From 30f6e378cf31ccccde9c2d3eaf981edeec6985e1 Mon Sep 17 00:00:00 2001 From: GCWing Date: Fri, 24 Jul 2026 23:57:27 +0800 Subject: [PATCH] feat: unify agentic runtime and product app lifecycle --- AGENTS-CN.md | 5 +- AGENTS.md | 5 +- .../builtin-deep-research/1.0.1/app.json | 211 + .../1.0.1/assets/icon.svg | 29 + .../1.0.1}/compatibility.json | 0 .../component.json | 63 + .../component.json | 44 + .../source/index.html | 1 + .../source/style.css | 32 + .../source/ui.js | 9 + .../1.0.1}/config/data-schema.json | 0 .../1.0.1}/config/default.json | 0 .../1.0.1/tests/eval.json | 24 + .../1.0.1/tests/rehearsal.json | 33 + .../builtin-excel-live/1.0.1/app.json | 265 + .../builtin-excel-live/1.0.1/assets/icon.png | Bin 0 -> 129958 bytes .../1.0.1/compatibility.json | 3 + .../agents/excel-live-agent/component.json | 106 + .../agents/excel-live-agent/source/agent.md | 151 + .../excel-live-agent/source/bundle.json | 5 + .../excel-live-agent/source/evals/cases.json | 143 + .../excel-live-agent/source/examples.json | 26 + .../excel-live-agent/source/manifest.json | 153 + .../excel-live-agent/source/package.json | 8 + .../agents/excel-live-agent/source/routing.md | 31 + .../schemas/spreadsheet-focus.schema.json | 119 + .../source/skills/data-cleaning.md | 24 + .../source/skills/focus-and-proposals.md | 36 + .../source/skills/formula-engineering.md | 38 + .../source/skills/spreadsheet-fundamentals.md | 16 + .../source/skills/visual-table-design.md | 55 + .../source/skills/workbook-authoring.md | 51 + .../test/agent-authoring-contract.test.js | 285 + .../source/tools/accept_proposal.js | 12 + .../source/tools/accept_proposal.tool.json | 94 + .../source/tools/create_workbook.js | 12 + .../source/tools/create_workbook.tool.json | 66 + .../source/tools/edit_workbook_structure.js | 79 + .../tools/edit_workbook_structure.tool.json | 102 + .../source/tools/excel_bridge.js | 88 + .../source/tools/get_focus.js | 12 + .../source/tools/get_focus.tool.json | 58 + .../source/tools/get_history.js | 12 + .../source/tools/get_history.tool.json | 37 + .../source/tools/get_proposal.js | 12 + .../source/tools/get_proposal.tool.json | 57 + .../source/tools/get_workbook_meta.js | 12 + .../source/tools/get_workbook_meta.tool.json | 58 + .../source/tools/list_sheets.js | 12 + .../source/tools/list_sheets.tool.json | 58 + .../source/tools/open_workbook.js | 12 + .../source/tools/open_workbook.tool.json | 67 + .../source/tools/propose_patch.js | 261 + .../source/tools/propose_patch.tool.json | 328 + .../source/tools/read_range.js | 12 + .../source/tools/read_range.tool.json | 80 + .../source/tools/redo_workbook.js | 12 + .../source/tools/redo_workbook.tool.json | 41 + .../source/tools/reject_proposal.js | 12 + .../source/tools/reject_proposal.tool.json | 73 + .../source/tools/save_workbook.js | 29 + .../source/tools/save_workbook.tool.json | 91 + .../source/tools/summarize_range.js | 12 + .../source/tools/summarize_range.tool.json | 73 + .../source/tools/switch_sheet.js | 12 + .../source/tools/switch_sheet.tool.json | 79 + .../source/tools/undo_workbook.js | 12 + .../source/tools/undo_workbook.tool.json | 41 + .../builtin-excel-runtime/component.json | 81 + .../builtin-excel-runtime/source/bundle.json | 5 + .../source/manifest.json | 411 + .../builtin-excel-runtime/source/package.json | 8 + .../builtin-excel-runtime/source/src/a1.js | 195 + .../source/src/csv-io.js | 168 + .../source/src/engine.js | 2910 ++ .../source/src/protocol.js | 38 + .../source/src/workbook-store.js | 580 + .../source/src/xlsx-io.js | 1997 ++ .../source/test/advanced-creation.test.js | 376 + .../source/test/contract-consistency.test.js | 436 + .../source/test/engine-safety.test.js | 986 + .../source/test/worker-protocol.test.js | 44 + .../builtin-excel-runtime/source/worker.js | 98 + .../builtin-excel-live-surface/component.json | 81 + .../source/esm_dependencies.json | 0 .../source/index.html | 6 + .../source/source_manifest.json | 6 + .../source/src/a1.js | 106 + .../source/src/actions.js | 958 + .../source/src/backend.js | 47 + .../source/src/focus.js | 171 + .../source/src/formatting.js | 458 + .../source/src/grid.js | 1258 + .../source/src/i18n.js | 437 + .../source/src/interaction.js | 134 + .../source/src/model.js | 448 + .../source/src/proposal.js | 584 + .../source/src/render.js | 25 + .../source/src/state.js | 82 + .../source/src/util.js | 65 + .../source/src/views.js | 514 + .../source/style.css | 1581 + .../source/test/interaction.test.mjs | 192 + .../builtin-excel-live-surface/source/ui.js | 489 + .../source/worker.js | 13 + .../1.0.1/config/data-schema.json | 3 + .../1.0.1/config/default.json | 1 + .../builtin-excel-live/1.0.1/tests/eval.json | 24 + .../1.0.1/tests/rehearsal.json | 33 + .../builtin-harmony-dev/13.0.1/app.json | 316 + .../13.0.1/assets/icon.png | Bin 0 -> 374263 bytes .../13.0.1/compatibility.json | 3 + .../agents/harmonyos-dev-agent/component.json | 110 + .../harmonyos-dev-agent/source/agent.md | 41 + .../harmonyos-dev-agent/source/bundle.json | 5 + .../source/evals/cases.json | 10 + .../harmonyos-dev-agent/source/manifest.json | 120 + .../harmonyos-dev-agent/source/routing.md | 8 + .../source/schemas/action-output.schema.json | 9 + .../schemas/harmony-dev-context.schema.json | 14 + .../source/schemas/screen-context.schema.json | 9 + .../source/skills/arkui-component-workflow.md | 9 + .../source/skills/build-install-verify.md | 12 + .../source/skills/device-preview-context.md | 14 + .../source/skills/harmony-fundamentals.md | 13 + .../source/skills/signing-and-permissions.md | 16 + .../source/skills/troubleshooting.md | 9 + .../source/tools/build_project.js | 12 + .../source/tools/build_project.tool.json | 19 + .../source/tools/capture_screen.js | 12 + .../source/tools/capture_screen.tool.json | 19 + .../source/tools/detect_project.js | 12 + .../source/tools/detect_project.tool.json | 17 + .../source/tools/dump_hierarchy.js | 12 + .../source/tools/dump_hierarchy.tool.json | 18 + .../source/tools/get_runtime_context.js | 12 + .../tools/get_runtime_context.tool.json | 18 + .../source/tools/harmony_bridge.js | 26 + .../source/tools/install_and_launch.js | 15 + .../source/tools/install_and_launch.tool.json | 22 + .../builtin-harmony-runtime/component.json | 80 + .../source/bundle.json | 5 + .../source/manifest.json | 362 + .../source/package.json | 6 + .../source/src/build.js | 107 + .../source/src/command.js | 79 + .../source/src/device.js | 521 + .../source/src/diagnostics.js | 45 + .../source/src/emulator.js | 298 + .../source/src/harmony-env.js | 115 + .../source/src/json5.js | 57 + .../source/src/paths.js | 69 + .../source/src/project.js | 159 + .../source/src/protocol.js | 38 + .../source/src/redact.js | 44 + .../source/src/runtime-state.js | 39 + .../builtin-harmony-runtime/source/worker.js | 84 + .../component.json | 78 + .../source/index.html | 6 + .../source/source_manifest.json | 8 + .../source/src/actions.js | 314 + .../source/src/backend.js | 37 + .../source/src/constants.js | 166 + .../source/src/model.js | 40 + .../source/src/preview/selection-overlay.js | 111 + .../source/src/state.js | 30 + .../source/src/util.js | 138 + .../source/src/views.js | 319 + .../source/style.css | 764 + .../builtin-harmony-dev-surface/source/ui.js | 101 + .../source/worker.js | 4 + .../13.0.1/config/data-schema.json | 3 + .../13.0.1/config/default.json | 1 + .../13.0.1/tests/eval.json | 24 + .../13.0.1/tests/rehearsal.json | 33 + .../builtin-ppt-live/150.0.2/assets/icon.png | Bin 816800 -> 0 bytes .../builtin-ppt-live/150.0.2/assets/icon.svg | 1 - .../builtin-ppt-live-agent/component.json | 52 - .../builtin-ppt-live-surface/component.json | 72 - .../source/index.html | 290 - .../source/src/deck-ai.js | 1523 - .../source/src/export-bundle-entry.mjs | 7 - .../source/src/export-deck-browser.js | 125 - .../source/src/export-deck-host.js | 6 - .../source/src/export-format-icons.js | 23 - .../source/src/export-html.js | 100 - .../source/src/export-slide-browser.js | 315 - .../source/src/flat-select.js | 220 - .../source/src/html2pptx-dom-core.js | 1055 - .../source/src/i18n.js | 734 - .../source/src/manuscript-editor.js | 745 - .../source/src/pptx-element-export.js | 302 - .../source/src/pptx-html-build.js | 218 - .../source/src/render.js | 1306 - .../source/src/sanitize-slide-html.js | 300 - .../source/src/state.js | 837 - .../source/src/style-presets.js | 269 - .../source/src/vendor/ppt-export.bundle.mjs | 27978 ---------------- .../builtin-ppt-live-surface/source/style.css | 3617 -- .../builtin-ppt-live-surface/source/ui.js | 3550 -- .../builtin-ppt-live/151.0.10/app.json | 169 + .../builtin-ppt-live/151.0.10/assets/icon.png | Bin 0 -> 140878 bytes .../151.0.10/compatibility.json | 3 + .../builtin-ppt-live-agent/component.json | 65 + .../builtin-ppt-live-agent/source/agent.md | 31 + .../builtin-ppt-live-agent/source/bundle.json | 5 + .../source/manifest.json | 99 + .../source/package.json | 8 + .../source/test/tool-abi.test.js | 60 + .../tools/commit_presentation_manuscript.js | 7 + .../commit_presentation_manuscript.tool.json | 157 + .../source/tools/confirm_design_case.js | 20 + .../tools/confirm_design_case.tool.json | 75 + .../source/tools/edit_visual.js | 7 + .../source/tools/edit_visual.tool.json | 84 + .../source/tools/export_deck.js | 7 + .../source/tools/export_deck.tool.json | 66 + .../source/tools/generate_slide_visual.js | 7 + .../tools/generate_slide_visual.tool.json | 46 + .../source/tools/inspect_presentation.js | 7 + .../tools/inspect_presentation.tool.json | 16 + .../source/tools/ppt_bridge.js | 29 + .../source/tools/prepare_visual_assets.js | 7 + .../tools/prepare_visual_assets.tool.json | 36 + .../source/tools/render_design_case.js | 7 + .../source/tools/render_design_case.tool.json | 42 + .../source/tools/review_deck.js | 7 + .../source/tools/review_deck.tool.json | 68 + .../tools/review_presentation_manuscript.js | 7 + .../review_presentation_manuscript.tool.json | 38 + .../source/tools/set_presentation_system.js | 7 + .../tools/set_presentation_system.tool.json | 253 + .../source/tools/undo_deck.js | 7 + .../source/tools/undo_deck.tool.json | 57 + .../builtin-ppt-runtime/component.json | 59 + .../builtin-ppt-runtime/source/bundle.json | 5 + .../builtin-ppt-runtime/source/manifest.json | 68 + .../builtin-ppt-runtime/source/package.json | 8 + .../source/src/design-package.js | 193 + .../builtin-ppt-runtime/source/src/engine.js | 2867 ++ .../source/src/export/pptx-export.mjs | 239 + .../source/src/manuscript-contract.js | 644 + .../source/src/presentation-system.js | 456 + .../source/src/protocol.js | 12 + .../source/src/render-runtime.js | 104 + .../source/src/slide-compiler.js | 360 + .../source/src/vendor/ppt-export.bundle.mjs | 7949 +++++ .../source/src/vendor/resvg/README.md | 21 + .../source/src/vendor/resvg/index.js | 607 + .../source/src/vendor/resvg/index_bg.wasm | Bin 0 -> 2478606 bytes .../source/src/visual-document.js | 159 + .../source/test/engine.test.js | 458 + .../source/test/worker-protocol.test.js | 96 + .../builtin-ppt-runtime/source/worker.js | 100 + .../builtin-ppt-live-surface/component.json | 63 + .../source/esm_dependencies.json | 1 + .../builtin-ppt-live-surface/source/i18n.json | 586 + .../source/index.html | 166 + .../source/source_manifest.json | 0 .../builtin-ppt-live-surface/source/style.css | 1684 + .../builtin-ppt-live-surface/source/ui.js | 1760 + .../151.0.10/config/data-schema.json | 3 + .../151.0.10/config/default.json | 1 + .../{150.0.2 => 151.0.10}/tests/eval.json | 0 .../tests/rehearsal.json | 0 .../builtin-remotion-live/19.0.2/app.json | 227 + .../19.0.2/assets/icon.png | Bin 0 -> 131257 bytes .../19.0.2/compatibility.json | 3 + .../remotion-video-agent/component.json | 100 + .../remotion-video-agent/source/agent.md | 49 + .../remotion-video-agent/source/bundle.json | 5 + .../source/evals/cases.json | 27 + .../remotion-video-agent/source/examples.json | 14 + .../remotion-video-agent/source/manifest.json | 111 + .../remotion-video-agent/source/routing.md | 14 + .../schemas/agent-action-input.schema.json | 49 + .../schemas/agent-action-output.schema.json | 42 + .../schemas/live-preview-context.schema.json | 7 + .../selected-video-context.schema.json | 46 + .../source/skills/composition-architecture.md | 12 + .../source/skills/media-assets.md | 12 + .../source/skills/motion-timing.md | 13 + .../source/skills/remotion-fundamentals.md | 12 + .../source/skills/selected-context.md | 11 + .../source/skills/validation-export.md | 13 + .../skills/video-development-workflow.md | 12 + .../source/skills/visual-design.md | 12 + .../source/tools/cancel_export.js | 12 + .../source/tools/cancel_export.tool.json | 19 + .../source/tools/detect_project.js | 12 + .../source/tools/detect_project.tool.json | 18 + .../source/tools/get_composition_manifest.js | 14 + .../tools/get_composition_manifest.tool.json | 19 + .../source/tools/get_export_status.js | 12 + .../source/tools/get_export_status.tool.json | 19 + .../source/tools/get_frame_descriptor.js | 12 + .../tools/get_frame_descriptor.tool.json | 24 + .../source/tools/refresh_preview.js | 12 + .../source/tools/refresh_preview.tool.json | 27 + .../source/tools/remotion_bridge.js | 26 + .../source/tools/render_still.js | 12 + .../source/tools/render_still.tool.json | 25 + .../source/tools/start_export.js | 12 + .../source/tools/start_export.tool.json | 32 + .../builtin-remotion-runtime/component.json | 71 + .../source/bundle.json | 5 + .../source/manifest.json | 403 + .../source/package.json | 5 + .../source/src/artifacts.js | 83 + .../source/src/browser-runtime.js | 87 + .../source/src/constants.js | 86 + .../source/src/export-job-worker.js | 163 + .../source/src/export.js | 246 + .../source/src/paths.js | 69 + .../source/src/player-host.js | 1298 + .../source/src/project-deps.js | 46 + .../source/src/project-runtime.js | 397 + .../source/src/project.js | 334 + .../source/src/protocol.js | 35 + .../source/src/remotion-cli.js | 65 + .../source/src/render.js | 95 + .../source/src/source-parse.js | 42 + .../source/src/util.js | 314 + .../builtin-remotion-runtime/source/worker.js | 78 + .../component.json | 93 + .../source/esm_dependencies.json | 1 + .../source/index.html | 5 + .../source/source_manifest.json | 8 + .../source/src/actions.js | 375 + .../source/src/backend.js | 60 + .../source/src/constants.js | 166 + .../source/src/model.js | 117 + .../source/src/player-dom.js | 297 + .../source/src/player-protocol.js | 506 + .../source/src/preview-controller.js | 138 + .../source/src/preview-runtime.js | 167 + .../source/src/render-core.js | 280 + .../source/src/selection-geom.js | 103 + .../source/src/state.js | 65 + .../source/src/util.js | 126 + .../source/src/views.js | 636 + .../source/style.css | 674 + .../source/ui.js | 288 + .../source/worker.js | 13 + .../19.0.2/config/data-schema.json | 3 + .../19.0.2/config/default.json | 1 + .../19.0.2/tests/eval.json | 24 + .../19.0.2/tests/rehearsal.json | 33 + .../1.0.1}/app.json | 134 +- .../builtin-spark-board/1.0.1/assets/icon.png | Bin 0 -> 152547 bytes .../builtin-spark-board/1.0.1/assets/icon.svg | 1 + .../1.0.1/compatibility.json | 3 + .../builtin-spark-board-agent/component.json | 52 + .../component.json | 64 + .../source/esm_dependencies.json | 1 + .../source/index.html | 177 + .../source/source_manifest.json | 8 + .../source/src/i18n.js | 220 + .../source/src/state.js | 41 + .../source/style.css | 1356 + .../builtin-spark-board-surface/source/ui.js | 1847 + .../source/worker.js | 1 + .../1.0.1/config/data-schema.json | 3 + .../1.0.1/config/default.json | 1 + .../builtin-spark-board/1.0.1/tests/eval.json | 24 + .../1.0.1/tests/rehearsal.json | 33 + .../presentation-workflow/router.md | 1 + .../skills/presentation-director/SKILL.md | 73 + .../presentation-workflow/suite.json | 6 + package.json | 6 +- pnpm-lock.yaml | 30 + pnpm-workspace.yaml | 1 + scripts/bundle-ppt-live-export-browser.mjs | 177 - scripts/bundle-ppt-live-export.mjs | 138 + scripts/check-i18n.mjs | 82 +- scripts/desktop-tauri-build.mjs | 2 +- scripts/dev.cjs | 4 +- src/apps/cli/src/agent/core_adapter.rs | 19 +- src/apps/cli/src/main.rs | 224 +- src/apps/cli/src/modes/chat.rs | 18 +- src/apps/cli/src/ui/panels.rs | 4 +- src/apps/desktop/src/api/agentic_api.rs | 258 +- src/apps/desktop/src/api/agentic_os_api.rs | 6 +- src/apps/desktop/src/api/app_evolution_api.rs | 58 +- .../desktop/src/api/app_release_runtime.rs | 251 +- src/apps/desktop/src/api/app_state.rs | 137 +- .../desktop/src/api/bridge_component_api.rs | 3 + src/apps/desktop/src/api/goal_api.rs | 8 +- .../desktop/src/api/intelligent_app_api.rs | 45 +- src/apps/desktop/src/api/mod.rs | 7 +- src/apps/desktop/src/api/path_target.rs | 4 +- .../desktop/src/api/ppt_live_export_api.rs | 161 - .../src/api/product_app_runtime_api.rs | 684 +- .../api/product_app_runtime_host_adapter.rs | 52 +- .../api/product_app_runtime_host_engine.rs | 902 +- .../src/api/product_app_session_api.rs | 273 + src/apps/desktop/src/api/session_api.rs | 336 +- .../desktop/src/api/session_storage_path.rs | 38 - src/apps/desktop/src/api/snapshot_service.rs | 15 +- src/apps/desktop/src/api/storage_commands.rs | 82 +- src/apps/desktop/src/api/tool_api.rs | 1 + src/apps/desktop/src/bootstrap/workspace.rs | 27 +- src/apps/desktop/src/lib.rs | 7 +- src/apps/desktop/src/tray/mod.rs | 10 +- src/crates/ai-adapters/src/types/config.rs | 2 +- src/crates/core/Cargo.toml | 3 + src/crates/core/build.rs | 97 +- .../core/src/agent_component/manager.rs | 83 +- .../core/src/agentic/agents/internal/mod.rs | 2 - .../agentic/agents/internal/ppt_live_agent.rs | 93 - src/crates/core/src/agentic/agents/mod.rs | 6 +- .../agents/product_app_backends/mod.rs | 3 - .../product_app_backends/ppt_live_prompt.rs | 617 - .../prompt_builder/prompt_builder_impl.rs | 15 +- .../agents/prompts/daily_letter_writer.md | 228 +- .../agentic/agents/prompts/ppt_live_agent.md | 38 - .../core/src/agentic/agents/registry.rs | 41 +- .../src/agentic/coordination/coordinator.rs | 556 +- .../src/agentic/coordination/scheduler.rs | 2 - src/crates/core/src/agentic/core/mod.rs | 4 +- src/crates/core/src/agentic/core/session.rs | 190 +- .../src/agentic/execution/execution_engine.rs | 31 +- .../src/agentic/execution/round_executor.rs | 1 + .../core/src/agentic/execution/types.rs | 7 +- src/crates/core/src/agentic/fork_agent/mod.rs | 18 +- src/crates/core/src/agentic/goal/store.rs | 72 +- .../core/src/agentic/memory/auto/planning.rs | 37 +- .../src/agentic/memory/auto/restrictions.rs | 2 + .../agentic/memory/consolidation/runner.rs | 7 +- .../core/src/agentic/memory/prompts/mod.rs | 1 - .../agentic/memory/routing/global_overview.rs | 138 +- .../core/src/agentic/memory/routing/mod.rs | 1 + .../core/src/agentic/memory/store/manifest.rs | 2 +- .../core/src/agentic/memory/store/paths.rs | 22 +- .../agentic/memory/store/prompt_context.rs | 4 +- src/crates/core/src/agentic/mod.rs | 2 + .../core/src/agentic/persistence/manager.rs | 576 +- .../src/agentic/persistence/session_branch.rs | 36 +- .../session_workspace_maintenance.rs | 54 +- .../core/src/agentic/product_app_context.rs | 323 + .../src/agentic/session/session_manager.rs | 564 +- .../core/src/agentic/session_hooks/mod.rs | 8 +- .../core/src/agentic/tools/framework.rs | 255 +- .../implementations/agent_handoff_tool.rs | 42 +- .../implementations/agent_session_handoff.rs | 13 +- .../tools/implementations/bash_tool.rs | 5 +- .../tools/implementations/bridge_call_tool.rs | 5 + .../implementations/bridge_component_tools.rs | 5 + .../implementations/builder_preview_tool.rs | 122 +- .../component_package_validation_tool.rs | 1 + .../tools/implementations/control_hub_tool.rs | 42 +- .../tools/implementations/cron_tool.rs | 6 +- .../tools/implementations/file_read_tool.rs | 2 + .../implementations/file_workbench_tools.rs | 1 + .../tools/implementations/glob_tool.rs | 2 + .../tools/implementations/grep_tool.rs | 2 + .../agentic/tools/implementations/ls_tool.rs | 2 + .../tools/implementations/memory_tool.rs | 2 +- .../product_app_checkpoint_tool.rs | 19 +- .../product_app_validation_tool.rs | 2 + .../implementations/session_control_tool.rs | 22 +- .../implementations/session_history_tool.rs | 5 +- .../tools/implementations/settings_tools.rs | 2 +- .../src/agentic/tools/implementations/util.rs | 2 + .../tools/implementations/web_tools.rs | 1 + src/crates/core/src/agentic/tools/mod.rs | 2 + .../agentic/tools/pipeline/tool_pipeline.rs | 13 + .../core/src/agentic/tools/pipeline/types.rs | 3 +- .../agentic/tools/product_app_restrictions.rs | 223 + .../core/src/agentic/tools/restrictions.rs | 19 +- .../core/src/agentic_os/background_process.rs | 17 +- src/crates/core/src/agentic_os/tools/work.rs | 36 +- src/crates/core/src/agentic_os/work/hooks.rs | 121 +- src/crates/core/src/agentic_os/work/mod.rs | 3 +- .../core/src/agentic_os/work/projection.rs | 3 + src/crates/core/src/agentic_os/work/record.rs | 51 +- .../core/src/agentic_os/work/run_store.rs | 334 + .../src/agentic_os/work/runtime_bridge.rs | 30 +- .../core/src/agentic_os/work/service.rs | 347 +- src/crates/core/src/agentic_os/work/store.rs | 493 +- .../core/src/agentic_os/work/subscriber.rs | 2 +- src/crates/core/src/agentic_os/work/types.rs | 52 +- .../src/app_platform/activation_policy.rs | 122 +- .../core/src/app_platform/bundle_assets.rs | 2 +- src/crates/core/src/app_platform/catalog.rs | 41 +- src/crates/core/src/app_platform/evolution.rs | 37 +- src/crates/core/src/app_platform/mod.rs | 31 +- .../core/src/app_platform/revision_store.rs | 730 +- .../core/src/app_platform/runtime_storage.rs | 185 +- .../core/src/app_platform/session_history.rs | 121 + .../core/src/app_platform/system_apps.rs | 552 +- .../core/src/bridge_component/manager.rs | 3 + .../core/src/bridge_component/manifest.rs | 6 + .../core/src/command/agentic_os/apps.rs | 5 +- .../core/src/command/agentic_os/snapshot.rs | 27 +- .../core/src/command/agentic_os/work.rs | 24 +- src/crates/core/src/command/session.rs | 102 +- src/crates/core/src/command/settings_agent.rs | 9 +- src/crates/core/src/command/tool.rs | 1 + .../infrastructure/app_paths/path_manager.rs | 514 +- .../src/infrastructure/storage/persistence.rs | 2 +- .../core/src/infrastructure/storage/reset.rs | 161 +- .../core/src/product_app_runtime_host/mod.rs | 11 +- .../bridge_builder.rs | 35 +- .../runtime_ui_kit.rs | 125 +- .../product_app_runtime_host_engine/types.rs | 24 + .../src/service/announcement/state_store.rs | 7 +- .../core/src/service/announcement/types.rs | 2 +- src/crates/core/src/service/config/catalog.rs | 177 +- src/crates/core/src/service/config/manager.rs | 75 +- src/crates/core/src/service/config/policy.rs | 12 + .../core/src/service/config/transaction.rs | 91 +- src/crates/core/src/service/config/types.rs | 365 +- .../core/src/service/config/validation.rs | 33 +- src/crates/core/src/service/cron/store.rs | 2 +- .../core/src/service/daily_letter/mod.rs | 3 +- .../core/src/service/daily_letter/prompt.rs | 5 +- .../core/src/service/daily_letter/service.rs | 239 +- .../core/src/service/daily_letter/store.rs | 22 +- .../core/src/service/daily_letter/types.rs | 22 + .../service/global_daily_report/service.rs | 90 +- .../src/service/global_daily_report/state.rs | 16 +- .../src/service/global_milestone/service.rs | 4 +- .../src/service/global_milestone/state.rs | 16 +- src/crates/core/src/service/mod.rs | 5 +- .../core/src/service/ppt_deck/manuscript.rs | 1130 - src/crates/core/src/service/ppt_deck/mod.rs | 6 - .../remote_connect/bot/command_router.rs | 96 +- .../service/remote_connect/remote_server.rs | 410 +- src/crates/core/src/service/session/types.rs | 29 +- .../core/src/service/token_usage/service.rs | 4 +- .../core/src/service/workspace/manager.rs | 161 +- .../core/src/service/workspace/service.rs | 36 +- .../workspace_overview/auto_refresh.rs | 43 +- .../core/src/service/workspace_runtime/mod.rs | 5 +- .../src/service/workspace_runtime/service.rs | 93 +- .../src/service/workspace_runtime/types.rs | 27 - src/crates/events/src/agentic.rs | 9 + src/crates/transport/src/adapters/tauri.rs | 2 + src/packages/icons/.gitignore | 2 + src/packages/icons/LICENSE | 21 + src/packages/icons/README.md | 126 + src/packages/icons/SPEC.md | 120 + src/packages/icons/package.json | 49 + src/packages/icons/preview.html | 13 + .../icons/scripts/generate-svg-variants.mjs | 138 + src/packages/icons/src/icon-manifest.ts | 76 + src/packages/icons/src/icon-spec.ts | 17 + src/packages/icons/src/icons.json | 354 + src/packages/icons/src/index.ts | 5 + .../icons/src/preview/IconPreviewApp.tsx | 579 + src/packages/icons/src/preview/main.tsx | 15 + src/packages/icons/src/preview/preview.scss | 1652 + src/packages/icons/src/raw-icons.ts | 104 + .../icons/src/react/SparoSystemIcon.tsx | 119 + src/packages/icons/src/react/named-icons.tsx | 59 + .../icons/src/render-system-icon-svg.ts | 79 + src/packages/icons/src/svg/base/add.svg | 6 + .../icons/src/svg/base/app-center.svg | 6 + src/packages/icons/src/svg/base/back.svg | 4 + src/packages/icons/src/svg/base/cancel.svg | 4 + src/packages/icons/src/svg/base/clear.svg | 5 + src/packages/icons/src/svg/base/close.svg | 4 + src/packages/icons/src/svg/base/collapse.svg | 4 + src/packages/icons/src/svg/base/copy.svg | 4 + .../icons/src/svg/base/daily-letter.svg | 4 + .../icons/src/svg/base/delegated-work.svg | 6 + src/packages/icons/src/svg/base/delete.svg | 8 + src/packages/icons/src/svg/base/download.svg | 5 + src/packages/icons/src/svg/base/edit.svg | 6 + src/packages/icons/src/svg/base/expand.svg | 4 + src/packages/icons/src/svg/base/export.svg | 14 + .../icons/src/svg/base/external-open.svg | 5 + src/packages/icons/src/svg/base/files.svg | 4 + src/packages/icons/src/svg/base/filter.svg | 5 + src/packages/icons/src/svg/base/forward.svg | 4 + src/packages/icons/src/svg/base/full-open.svg | 6 + .../src/svg/base/intelligent-app-work.svg | 4 + .../icons/src/svg/base/long-running-work.svg | 5 + src/packages/icons/src/svg/base/memory.svg | 3 + .../icons/src/svg/base/multi-step-work.svg | 7 + .../icons/src/svg/base/normal-work.svg | 5 + .../icons/src/svg/base/open-directory.svg | 4 + .../icons/src/svg/base/recurring-work.svg | 7 + src/packages/icons/src/svg/base/refresh.svg | 6 + src/packages/icons/src/svg/base/reset.svg | 8 + src/packages/icons/src/svg/base/retry.svg | 4 + .../icons/src/svg/base/save-apply.svg | 4 + src/packages/icons/src/svg/base/search.svg | 4 + src/packages/icons/src/svg/base/settings.svg | 4 + src/packages/icons/src/svg/base/skills.svg | 3 + src/packages/icons/src/svg/base/sort.svg | 9 + src/packages/icons/src/svg/base/sparo-hub.svg | 4 + src/packages/icons/src/svg/base/subagent.svg | 6 + .../icons/src/svg/base/system-work.svg | 5 + src/packages/icons/src/svg/base/terminal.svg | 5 + src/packages/icons/src/svg/base/tools.svg | 3 + .../icons/src/svg/base/topic-work.svg | 4 + src/packages/icons/src/svg/base/undo.svg | 4 + src/packages/icons/src/svg/base/upload.svg | 5 + .../icons/src/svg/base/work-center.svg | 6 + src/packages/icons/src/svg/emphasis/add.svg | 9 + .../icons/src/svg/emphasis/app-center.svg | 9 + src/packages/icons/src/svg/emphasis/back.svg | 7 + .../icons/src/svg/emphasis/cancel.svg | 7 + src/packages/icons/src/svg/emphasis/clear.svg | 8 + src/packages/icons/src/svg/emphasis/close.svg | 7 + .../icons/src/svg/emphasis/collapse.svg | 7 + src/packages/icons/src/svg/emphasis/copy.svg | 7 + .../icons/src/svg/emphasis/daily-letter.svg | 7 + .../icons/src/svg/emphasis/delegated-work.svg | 9 + .../icons/src/svg/emphasis/delete.svg | 11 + .../icons/src/svg/emphasis/download.svg | 8 + src/packages/icons/src/svg/emphasis/edit.svg | 9 + .../icons/src/svg/emphasis/expand.svg | 7 + .../icons/src/svg/emphasis/export.svg | 17 + .../icons/src/svg/emphasis/external-open.svg | 8 + src/packages/icons/src/svg/emphasis/files.svg | 7 + .../icons/src/svg/emphasis/filter.svg | 8 + .../icons/src/svg/emphasis/forward.svg | 7 + .../icons/src/svg/emphasis/full-open.svg | 9 + .../src/svg/emphasis/intelligent-app-work.svg | 7 + .../src/svg/emphasis/long-running-work.svg | 8 + .../icons/src/svg/emphasis/memory.svg | 6 + .../src/svg/emphasis/multi-step-work.svg | 10 + .../icons/src/svg/emphasis/normal-work.svg | 8 + .../icons/src/svg/emphasis/open-directory.svg | 7 + .../icons/src/svg/emphasis/recurring-work.svg | 10 + .../icons/src/svg/emphasis/refresh.svg | 9 + src/packages/icons/src/svg/emphasis/reset.svg | 11 + src/packages/icons/src/svg/emphasis/retry.svg | 7 + .../icons/src/svg/emphasis/save-apply.svg | 7 + .../icons/src/svg/emphasis/search.svg | 7 + .../icons/src/svg/emphasis/settings.svg | 7 + .../icons/src/svg/emphasis/skills.svg | 6 + src/packages/icons/src/svg/emphasis/sort.svg | 12 + .../icons/src/svg/emphasis/sparo-hub.svg | 7 + .../icons/src/svg/emphasis/subagent.svg | 9 + .../icons/src/svg/emphasis/system-work.svg | 8 + .../icons/src/svg/emphasis/terminal.svg | 8 + src/packages/icons/src/svg/emphasis/tools.svg | 6 + .../icons/src/svg/emphasis/topic-work.svg | 7 + src/packages/icons/src/svg/emphasis/undo.svg | 7 + .../icons/src/svg/emphasis/upload.svg | 8 + .../icons/src/svg/emphasis/work-center.svg | 9 + .../icons/src/svg/sparo-system-icons.svg | 676 + src/packages/icons/tsconfig.build.json | 12 + src/packages/icons/tsconfig.json | 17 + src/packages/icons/vite.config.lib.ts | 19 + src/packages/icons/vite.config.ts | 23 + src/web-ui/package.json | 1 + .../agentic-os/work/data/appWorkSelectors.ts | 12 +- .../src/app/agentic-os/work/data/workApi.ts | 106 +- .../src/app/agentic-os/work/data/workStore.ts | 23 +- .../work/domain/productAppLaunchPolicy.ts | 6 +- .../agentic-os/work/domain/productAppRefs.ts | 7 +- .../work/domain/workAppIdentity.test.ts | 57 + .../agentic-os/work/domain/workAppIdentity.ts | 38 + .../app/agentic-os/work/domain/workTypes.ts | 46 +- .../work/navigation/openWork.test.ts | 120 +- .../agentic-os/work/navigation/openWork.ts | 100 +- .../work/presentation/WorkIcon.test.tsx | 86 + .../agentic-os/work/presentation/WorkIcon.tsx | 121 + .../work/presentation/workTypeIcon.test.ts | 31 + .../work/presentation/workTypeIcon.ts | 34 + .../work/projections/workProjection.ts | 11 +- .../apps => components/AppIcon}/AppIcon.scss | 0 .../apps => components/AppIcon}/AppIcon.tsx | 0 .../src/app/components/AppIcon/index.ts | 1 + .../GlobalSearchDialog/GlobalSearchDialog.tsx | 10 +- .../DistributedDeviceOverview.tsx | 4 +- .../RemoteConnectDialog.scss | 13 +- .../UnifiedTopBar/UnifiedTopBar.tsx | 100 +- .../app/components/WorkDock/NewWorkDialog.tsx | 25 +- .../src/app/components/WorkDock/WorkDock.tsx | 42 +- .../src/app/components/WorkList/WorkList.tsx | 16 +- .../components/WorkList/workListSelection.ts | 23 - .../WorkspaceFooterActions.scss | 27 +- .../WorkspaceFooterActions.tsx | 37 +- .../previews/AppsPreview.tsx | 2 +- .../previews/WorkCenterPreview.tsx | 16 +- .../workspaceHubItems.tsx | 48 +- .../hooks/usePanelTabCoordinator.ts | 7 +- .../src/app/hooks/useSessionHeaderContext.ts | 25 +- src/web-ui/src/app/layout/AppLayout.tsx | 122 +- .../layout/initializeFlowChatStartup.test.ts | 94 + .../app/layout/initializeFlowChatStartup.ts | 85 + .../app/navigation/navigationController.ts | 54 +- .../app/navigation/workspaceSurfaceTypes.ts | 6 +- .../navigation/workspaceTopBarContext.test.ts | 87 +- .../app/navigation/workspaceTopBarContext.ts | 85 + src/web-ui/src/app/scenes/apps/AppsScene.tsx | 31 +- .../scenes/apps/app-builder/appBuilderWork.ts | 10 +- .../openAppBuilderSession.integration.test.ts | 22 +- .../app-builder/openAppBuilderSession.test.ts | 9 +- .../apps/app-builder/openAppBuilderSession.ts | 12 +- .../apps/app-detail/AppDetailScene.test.tsx | 1 - .../scenes/apps/app-detail/AppDetailScene.tsx | 11 +- .../scenes/apps/components/ManagementList.tsx | 2 +- .../app/scenes/apps/components/WorkStack.tsx | 2 +- .../apps/intelligentAppLaunchService.ts | 41 +- .../ProductAppRuntimeIframeHost.scss | 42 + .../ProductAppRuntimeIframeHost.test.tsx | 59 + .../ProductAppRuntimeIframeHost.tsx | 144 +- .../ProductAppRuntimePanel.tsx | 14 +- .../productAppRuntimeHostService.ts | 289 +- .../productAppRuntimeHostedViews.test.ts | 86 + .../productAppRuntimeHostedViews.ts | 150 + .../productAppRuntimeInteraction.test.ts | 28 +- .../productAppRuntimeInteraction.ts | 8 + .../productAppRuntimeOpenTypes.ts | 4 + .../productAppRuntimeService.test.ts | 124 +- .../productAppRuntimeService.ts | 133 +- .../productAppRuntimeToolCardManifests.ts | 67 + .../productAppRuntimeToolCardName.ts | 7 + .../useProductAppRuntimeBridge.ts | 163 +- .../app/scenes/settings/SettingsAIMode.tsx | 4 +- .../settings/SettingsConfirmationHost.tsx | 15 +- .../scenes/settings/SettingsManualMode.tsx | 13 +- .../src/app/scenes/settings/SettingsNav.tsx | 5 +- .../app/scenes/settings/SettingsScene.scss | 20 - .../scenes/settings/SettingsSectionHost.tsx | 31 +- .../scenes/settings/settingsFlowSessionApi.ts | 5 +- .../WorkBoard/RunningWorkProcessTable.tsx | 12 +- .../work-center/WorkBoard/WorkBoard.scss | 3 + .../work-center/WorkBoard/WorkBoard.tsx | 58 +- .../WorkBoard/WorkDetailDialog.scss | 6 + .../WorkBoard/WorkDetailDialog.tsx | 25 +- .../profiles/productAppRuntimeProfile.ts | 2 +- src/web-ui/src/app/stores/headerStore.ts | 3 + .../src/app/surfaces/SurfaceRenderer.tsx | 2 +- .../foundation/icons/SparoSystemIcons.ts | 5 + .../foundation/icons/icon-policy.ts | 9 +- .../design-system/foundation/icons/index.ts | 1 + .../preview/registries/primitives.tsx | 28 + .../src/flow_chat/components/ChatInput.tsx | 6 +- .../flow_chat/components/ModelSelector.tsx | 2 +- .../TaskDetailPanel/TaskDetailPanel.tsx | 6 +- .../child-session/ChildSessionPanel.tsx | 6 +- .../providers/composerActionProviderTypes.ts | 4 +- .../composer/hooks/useComposerSubmission.ts | 9 +- .../composer/hooks/useComposerTokenUsage.ts | 32 +- .../modern/AgenticOSFlowChatContainer.tsx | 2 +- .../src/flow_chat/domain/goalSupport.ts | 8 +- .../domain/sessionDescriptor.test.ts | 11 +- .../src/flow_chat/domain/sessionDescriptor.ts | 50 +- .../execution/ExecutionGraphStore.test.ts | 1 + .../flowChatProjectionScheduler.ts | 5 +- .../flow_chat/services/BtwThreadService.ts | 20 +- .../services/ContextBudgetService.test.ts | 45 +- .../services/ContextBudgetService.ts | 62 +- .../src/flow_chat/services/FlowChatManager.ts | 90 +- .../services/boundAgentSessionService.ts | 61 +- .../flow-chat-manager/EventHandlerModule.ts | 22 +- .../flow-chat-manager/MessageModule.test.ts | 36 +- .../flow-chat-manager/MessageModule.ts | 6 +- .../PersistenceModule.test.ts | 1 + .../flow-chat-manager/PersistenceModule.ts | 41 +- .../flow-chat-manager/SessionModule.test.ts | 146 +- .../flow-chat-manager/SessionModule.ts | 152 +- .../services/flow-chat-manager/index.ts | 1 - .../store/FlowChatStore.metadata.test.ts | 163 +- .../src/flow_chat/store/FlowChatStore.ts | 221 +- .../flow_chat/store/modernFlowChatStore.ts | 4 +- .../flow_chat/tool-cards/AgentHandoffCard.tsx | 33 +- .../tool-cards/AppDefinedToolCard.test.tsx | 73 + .../tool-cards/AppDefinedToolCard.tsx | 65 +- .../PptDesignCaseConfirmationCard.scss | 187 + .../PptDesignCaseConfirmationCard.test.tsx | 133 + .../PptDesignCaseConfirmationCard.tsx | 266 + .../flow_chat/tool-cards/PptLiveToolCard.scss | 60 + .../flow_chat/tool-cards/PptLiveToolCard.tsx | 175 + .../tool-cards/SessionHistoryDisplay.tsx | 45 +- .../tool-cards/SettingsChangePreviewCard.tsx | 4 +- .../flow_chat/tool-cards/SkillDisplay.test.ts | 20 + .../src/flow_chat/tool-cards/SkillDisplay.tsx | 19 +- .../tool-cards/ToolManifestSync.test.ts | 199 + .../flow_chat/tool-cards/ToolManifestSync.ts | 178 +- .../src/flow_chat/tool-cards/WorkToolCard.tsx | 10 +- .../tool-cards/appBuilderToolScope.ts | 18 +- src/web-ui/src/flow_chat/tool-cards/index.ts | 19 + .../flow_chat/tool-cards/skillDisplayName.ts | 28 + src/web-ui/src/flow_chat/types/flow-chat.ts | 21 +- .../src/flow_chat/utils/sessionMetadata.ts | 4 +- .../utils/sessionNavigationSignature.ts | 3 +- src/web-ui/src/infrastructure/api/index.ts | 5 +- .../api/service-api/AgentAPI.ts | 52 +- .../api/service-api/AppCatalogAPI.ts | 14 +- .../api/service-api/AppEvolutionAPI.ts | 11 +- .../api/service-api/IntelligentAppAPI.ts | 17 +- .../service-api/ProductAppRuntimeAPI.test.ts | 28 +- .../api/service-api/ProductAppRuntimeAPI.ts | 53 +- .../service-api/ProductAppRuntimeHostAPI.ts | 80 +- .../api/service-api/ProductAppSessionAPI.ts | 51 + .../api/service-api/SessionAPI.ts | 158 +- .../api/service-api/StorageAPI.ts | 5 + .../config/components/AIModelConfig.tsx | 36 +- .../config/components/VoiceInputConfig.tsx | 25 +- .../components/common/ConfigPageLayout.scss | 1 + .../renderers/BooleanSettingRenderer.tsx | 21 +- .../config/renderers/EnumSettingRenderer.tsx | 35 +- .../renderers/NumberSettingRenderer.tsx | 43 +- .../renderers/SecretSettingRenderer.tsx | 71 +- .../config/renderers/SettingRenderer.test.tsx | 5 + .../renderers/StringSettingRenderer.tsx | 41 +- .../src/infrastructure/config/types/index.ts | 33 - .../services/business/agentService.ts | 16 +- .../locales/en-US/flow-chat/tool-cards.json | 29 + src/web-ui/src/locales/en-US/scenes/apps.json | 2 - .../src/locales/en-US/scenes/work-center.json | 24 +- .../src/locales/en-US/settings/ai-model.json | 14 +- .../locales/en-US/settings/config-center.json | 49 +- .../locales/en-US/settings/data-storage.json | 14 +- .../locales/en-US/settings/voice-input.json | 10 +- .../src/locales/en-US/shell/header.json | 7 +- .../locales/zh-CN/flow-chat/tool-cards.json | 29 + src/web-ui/src/locales/zh-CN/scenes/apps.json | 2 - .../src/locales/zh-CN/scenes/work-center.json | 24 +- .../src/locales/zh-CN/settings/agents.json | 2 +- .../src/locales/zh-CN/settings/ai-model.json | 14 +- .../src/locales/zh-CN/settings/ai-usage.json | 2 +- .../locales/zh-CN/settings/config-center.json | 49 +- .../locales/zh-CN/settings/data-storage.json | 14 +- .../locales/zh-CN/settings/voice-input.json | 12 +- .../src/locales/zh-CN/shell/header.json | 7 +- .../components/NotificationContainer.scss | 206 +- .../components/NotificationContainer.tsx | 128 +- .../src/shared/services/agent-service.ts | 10 + .../shared/services/openShellSessionTarget.ts | 2 +- src/web-ui/src/shared/types/agent-api.ts | 1 + src/web-ui/src/shared/types/app-manifest.ts | 2 + src/web-ui/src/shared/types/app-scope.test.ts | 59 + src/web-ui/src/shared/types/app-scope.ts | 53 +- .../src/shared/types/product-app-runtime.ts | 4 +- src/web-ui/src/shared/types/runtime-scope.ts | 24 +- .../src/shared/types/session-history.ts | 38 +- src/web-ui/src/shared/types/work-locator.ts | 8 + .../src/shared/utils/configConverter.ts | 14 +- .../components/MarkdownEditor.test.tsx | 154 + .../markdown/components/MarkdownEditor.tsx | 152 +- .../components/MarkdownEditingSurface.tsx | 5 +- src/web-ui/tsconfig.json | 1 + src/web-ui/vite.config.preview.ts | 1 + src/web-ui/vite.config.ts | 1 + .../product-app-runtime-composite.spec.ts | 2 +- .../remotion-runtime/browser-runtime.test.cjs | 117 + .../project-snapshot.test.cjs | 4 +- 847 files changed, 78170 insertions(+), 53689 deletions(-) create mode 100644 bundles/product-apps/builtin-deep-research/1.0.1/app.json create mode 100644 bundles/product-apps/builtin-deep-research/1.0.1/assets/icon.svg rename bundles/product-apps/{builtin-ppt-live/150.0.2 => builtin-deep-research/1.0.1}/compatibility.json (100%) create mode 100644 bundles/product-apps/builtin-deep-research/1.0.1/components/agents/builtin-deep-research-agent/component.json create mode 100644 bundles/product-apps/builtin-deep-research/1.0.1/components/surfaces/builtin-deep-research-chat-surface/component.json create mode 100644 bundles/product-apps/builtin-deep-research/1.0.1/components/surfaces/builtin-deep-research-chat-surface/source/index.html create mode 100644 bundles/product-apps/builtin-deep-research/1.0.1/components/surfaces/builtin-deep-research-chat-surface/source/style.css create mode 100644 bundles/product-apps/builtin-deep-research/1.0.1/components/surfaces/builtin-deep-research-chat-surface/source/ui.js rename bundles/product-apps/{builtin-ppt-live/150.0.2 => builtin-deep-research/1.0.1}/config/data-schema.json (100%) rename bundles/product-apps/{builtin-ppt-live/150.0.2 => builtin-deep-research/1.0.1}/config/default.json (100%) create mode 100644 bundles/product-apps/builtin-deep-research/1.0.1/tests/eval.json create mode 100644 bundles/product-apps/builtin-deep-research/1.0.1/tests/rehearsal.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/app.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/assets/icon.png create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/compatibility.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/component.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/agent.md create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/bundle.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/evals/cases.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/examples.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/manifest.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/package.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/routing.md create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/schemas/spreadsheet-focus.schema.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/skills/data-cleaning.md create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/skills/focus-and-proposals.md create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/skills/formula-engineering.md create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/skills/spreadsheet-fundamentals.md create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/skills/visual-table-design.md create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/skills/workbook-authoring.md create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/test/agent-authoring-contract.test.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/accept_proposal.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/accept_proposal.tool.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/create_workbook.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/create_workbook.tool.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/edit_workbook_structure.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/edit_workbook_structure.tool.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/excel_bridge.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_focus.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_focus.tool.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_history.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_history.tool.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_proposal.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_proposal.tool.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_workbook_meta.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_workbook_meta.tool.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/list_sheets.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/list_sheets.tool.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/open_workbook.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/open_workbook.tool.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/propose_patch.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/propose_patch.tool.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/read_range.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/read_range.tool.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/redo_workbook.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/redo_workbook.tool.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/reject_proposal.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/reject_proposal.tool.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/save_workbook.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/save_workbook.tool.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/summarize_range.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/summarize_range.tool.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/switch_sheet.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/switch_sheet.tool.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/undo_workbook.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/undo_workbook.tool.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/component.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/bundle.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/manifest.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/package.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/src/a1.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/src/csv-io.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/src/engine.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/src/protocol.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/src/workbook-store.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/src/xlsx-io.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/test/advanced-creation.test.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/test/contract-consistency.test.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/test/engine-safety.test.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/test/worker-protocol.test.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/worker.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/component.json rename bundles/product-apps/{builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface => builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface}/source/esm_dependencies.json (100%) create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/index.html create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/source_manifest.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/a1.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/actions.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/backend.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/focus.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/formatting.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/grid.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/i18n.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/interaction.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/model.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/proposal.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/render.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/state.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/util.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/views.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/style.css create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/test/interaction.test.mjs create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/ui.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/worker.js create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/config/data-schema.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/config/default.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/tests/eval.json create mode 100644 bundles/product-apps/builtin-excel-live/1.0.1/tests/rehearsal.json create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/app.json create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/assets/icon.png create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/compatibility.json create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/component.json create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/agent.md create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/bundle.json create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/evals/cases.json create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/manifest.json create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/routing.md create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/schemas/action-output.schema.json create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/schemas/harmony-dev-context.schema.json create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/schemas/screen-context.schema.json create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/skills/arkui-component-workflow.md create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/skills/build-install-verify.md create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/skills/device-preview-context.md create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/skills/harmony-fundamentals.md create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/skills/signing-and-permissions.md create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/skills/troubleshooting.md create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/build_project.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/build_project.tool.json create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/capture_screen.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/capture_screen.tool.json create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/detect_project.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/detect_project.tool.json create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/dump_hierarchy.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/dump_hierarchy.tool.json create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/get_runtime_context.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/get_runtime_context.tool.json create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/harmony_bridge.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/install_and_launch.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/install_and_launch.tool.json create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/component.json create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/bundle.json create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/manifest.json create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/package.json create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/build.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/command.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/device.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/diagnostics.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/emulator.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/harmony-env.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/json5.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/paths.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/project.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/protocol.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/redact.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/runtime-state.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/worker.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/component.json create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/index.html create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/source_manifest.json create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/actions.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/backend.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/constants.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/model.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/preview/selection-overlay.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/state.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/util.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/views.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/style.css create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/ui.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/worker.js create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/config/data-schema.json create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/config/default.json create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/tests/eval.json create mode 100644 bundles/product-apps/builtin-harmony-dev/13.0.1/tests/rehearsal.json delete mode 100644 bundles/product-apps/builtin-ppt-live/150.0.2/assets/icon.png delete mode 100644 bundles/product-apps/builtin-ppt-live/150.0.2/assets/icon.svg delete mode 100644 bundles/product-apps/builtin-ppt-live/150.0.2/components/agents/builtin-ppt-live-agent/component.json delete mode 100644 bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/component.json delete mode 100644 bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/index.html delete mode 100644 bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/deck-ai.js delete mode 100644 bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/export-bundle-entry.mjs delete mode 100644 bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/export-deck-browser.js delete mode 100644 bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/export-deck-host.js delete mode 100644 bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/export-format-icons.js delete mode 100644 bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/export-html.js delete mode 100644 bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/export-slide-browser.js delete mode 100644 bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/flat-select.js delete mode 100644 bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/html2pptx-dom-core.js delete mode 100644 bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/i18n.js delete mode 100644 bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/manuscript-editor.js delete mode 100644 bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/pptx-element-export.js delete mode 100644 bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/pptx-html-build.js delete mode 100644 bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/render.js delete mode 100644 bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/sanitize-slide-html.js delete mode 100644 bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/state.js delete mode 100644 bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/style-presets.js delete mode 100644 bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/vendor/ppt-export.bundle.mjs delete mode 100644 bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/style.css delete mode 100644 bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/ui.js create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/app.json create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/assets/icon.png create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/compatibility.json create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/component.json create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/agent.md create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/bundle.json create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/manifest.json create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/package.json create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/test/tool-abi.test.js create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/tools/commit_presentation_manuscript.js create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/tools/commit_presentation_manuscript.tool.json create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/tools/confirm_design_case.js create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/tools/confirm_design_case.tool.json create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/tools/edit_visual.js create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/tools/edit_visual.tool.json create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/tools/export_deck.js create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/tools/export_deck.tool.json create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/tools/generate_slide_visual.js create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/tools/generate_slide_visual.tool.json create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/tools/inspect_presentation.js create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/tools/inspect_presentation.tool.json create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/tools/ppt_bridge.js create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/tools/prepare_visual_assets.js create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/tools/prepare_visual_assets.tool.json create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/tools/render_design_case.js create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/tools/render_design_case.tool.json create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/tools/review_deck.js create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/tools/review_deck.tool.json create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/tools/review_presentation_manuscript.js create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/tools/review_presentation_manuscript.tool.json create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/tools/set_presentation_system.js create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/tools/set_presentation_system.tool.json create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/tools/undo_deck.js create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/agents/builtin-ppt-live-agent/source/tools/undo_deck.tool.json create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/bridges/builtin-ppt-runtime/component.json create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/bridges/builtin-ppt-runtime/source/bundle.json create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/bridges/builtin-ppt-runtime/source/manifest.json create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/bridges/builtin-ppt-runtime/source/package.json create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/bridges/builtin-ppt-runtime/source/src/design-package.js create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/bridges/builtin-ppt-runtime/source/src/engine.js create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/bridges/builtin-ppt-runtime/source/src/export/pptx-export.mjs create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/bridges/builtin-ppt-runtime/source/src/manuscript-contract.js create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/bridges/builtin-ppt-runtime/source/src/presentation-system.js create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/bridges/builtin-ppt-runtime/source/src/protocol.js create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/bridges/builtin-ppt-runtime/source/src/render-runtime.js create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/bridges/builtin-ppt-runtime/source/src/slide-compiler.js create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/bridges/builtin-ppt-runtime/source/src/vendor/ppt-export.bundle.mjs create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/bridges/builtin-ppt-runtime/source/src/vendor/resvg/README.md create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/bridges/builtin-ppt-runtime/source/src/vendor/resvg/index.js create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/bridges/builtin-ppt-runtime/source/src/vendor/resvg/index_bg.wasm create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/bridges/builtin-ppt-runtime/source/src/visual-document.js create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/bridges/builtin-ppt-runtime/source/test/engine.test.js create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/bridges/builtin-ppt-runtime/source/test/worker-protocol.test.js create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/bridges/builtin-ppt-runtime/source/worker.js create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/surfaces/builtin-ppt-live-surface/component.json create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/surfaces/builtin-ppt-live-surface/source/esm_dependencies.json create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/surfaces/builtin-ppt-live-surface/source/i18n.json create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/surfaces/builtin-ppt-live-surface/source/index.html rename bundles/product-apps/builtin-ppt-live/{150.0.2 => 151.0.10}/components/surfaces/builtin-ppt-live-surface/source/source_manifest.json (100%) create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/surfaces/builtin-ppt-live-surface/source/style.css create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/components/surfaces/builtin-ppt-live-surface/source/ui.js create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/config/data-schema.json create mode 100644 bundles/product-apps/builtin-ppt-live/151.0.10/config/default.json rename bundles/product-apps/builtin-ppt-live/{150.0.2 => 151.0.10}/tests/eval.json (100%) rename bundles/product-apps/builtin-ppt-live/{150.0.2 => 151.0.10}/tests/rehearsal.json (100%) create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/app.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/assets/icon.png create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/compatibility.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/component.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/agent.md create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/bundle.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/evals/cases.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/examples.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/manifest.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/routing.md create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/schemas/agent-action-input.schema.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/schemas/agent-action-output.schema.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/schemas/live-preview-context.schema.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/schemas/selected-video-context.schema.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/skills/composition-architecture.md create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/skills/media-assets.md create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/skills/motion-timing.md create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/skills/remotion-fundamentals.md create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/skills/selected-context.md create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/skills/validation-export.md create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/skills/video-development-workflow.md create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/skills/visual-design.md create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/tools/cancel_export.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/tools/cancel_export.tool.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/tools/detect_project.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/tools/detect_project.tool.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/tools/get_composition_manifest.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/tools/get_composition_manifest.tool.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/tools/get_export_status.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/tools/get_export_status.tool.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/tools/get_frame_descriptor.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/tools/get_frame_descriptor.tool.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/tools/refresh_preview.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/tools/refresh_preview.tool.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/tools/remotion_bridge.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/tools/render_still.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/tools/render_still.tool.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/tools/start_export.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/agents/remotion-video-agent/source/tools/start_export.tool.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/bridges/builtin-remotion-runtime/component.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/bridges/builtin-remotion-runtime/source/bundle.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/bridges/builtin-remotion-runtime/source/manifest.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/bridges/builtin-remotion-runtime/source/package.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/bridges/builtin-remotion-runtime/source/src/artifacts.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/bridges/builtin-remotion-runtime/source/src/browser-runtime.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/bridges/builtin-remotion-runtime/source/src/constants.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/bridges/builtin-remotion-runtime/source/src/export-job-worker.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/bridges/builtin-remotion-runtime/source/src/export.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/bridges/builtin-remotion-runtime/source/src/paths.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/bridges/builtin-remotion-runtime/source/src/player-host.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/bridges/builtin-remotion-runtime/source/src/project-deps.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/bridges/builtin-remotion-runtime/source/src/project-runtime.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/bridges/builtin-remotion-runtime/source/src/project.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/bridges/builtin-remotion-runtime/source/src/protocol.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/bridges/builtin-remotion-runtime/source/src/remotion-cli.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/bridges/builtin-remotion-runtime/source/src/render.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/bridges/builtin-remotion-runtime/source/src/source-parse.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/bridges/builtin-remotion-runtime/source/src/util.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/bridges/builtin-remotion-runtime/source/worker.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/surfaces/builtin-remotion-live-surface/component.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/surfaces/builtin-remotion-live-surface/source/esm_dependencies.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/surfaces/builtin-remotion-live-surface/source/index.html create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/surfaces/builtin-remotion-live-surface/source/source_manifest.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/surfaces/builtin-remotion-live-surface/source/src/actions.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/surfaces/builtin-remotion-live-surface/source/src/backend.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/surfaces/builtin-remotion-live-surface/source/src/constants.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/surfaces/builtin-remotion-live-surface/source/src/model.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/surfaces/builtin-remotion-live-surface/source/src/player-dom.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/surfaces/builtin-remotion-live-surface/source/src/player-protocol.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/surfaces/builtin-remotion-live-surface/source/src/preview-controller.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/surfaces/builtin-remotion-live-surface/source/src/preview-runtime.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/surfaces/builtin-remotion-live-surface/source/src/render-core.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/surfaces/builtin-remotion-live-surface/source/src/selection-geom.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/surfaces/builtin-remotion-live-surface/source/src/state.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/surfaces/builtin-remotion-live-surface/source/src/util.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/surfaces/builtin-remotion-live-surface/source/src/views.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/surfaces/builtin-remotion-live-surface/source/style.css create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/surfaces/builtin-remotion-live-surface/source/ui.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/components/surfaces/builtin-remotion-live-surface/source/worker.js create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/config/data-schema.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/config/default.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/tests/eval.json create mode 100644 bundles/product-apps/builtin-remotion-live/19.0.2/tests/rehearsal.json rename bundles/product-apps/{builtin-ppt-live/150.0.2 => builtin-spark-board/1.0.1}/app.json (56%) create mode 100644 bundles/product-apps/builtin-spark-board/1.0.1/assets/icon.png create mode 100644 bundles/product-apps/builtin-spark-board/1.0.1/assets/icon.svg create mode 100644 bundles/product-apps/builtin-spark-board/1.0.1/compatibility.json create mode 100644 bundles/product-apps/builtin-spark-board/1.0.1/components/agents/builtin-spark-board-agent/component.json create mode 100644 bundles/product-apps/builtin-spark-board/1.0.1/components/surfaces/builtin-spark-board-surface/component.json create mode 100644 bundles/product-apps/builtin-spark-board/1.0.1/components/surfaces/builtin-spark-board-surface/source/esm_dependencies.json create mode 100644 bundles/product-apps/builtin-spark-board/1.0.1/components/surfaces/builtin-spark-board-surface/source/index.html create mode 100644 bundles/product-apps/builtin-spark-board/1.0.1/components/surfaces/builtin-spark-board-surface/source/source_manifest.json create mode 100644 bundles/product-apps/builtin-spark-board/1.0.1/components/surfaces/builtin-spark-board-surface/source/src/i18n.js create mode 100644 bundles/product-apps/builtin-spark-board/1.0.1/components/surfaces/builtin-spark-board-surface/source/src/state.js create mode 100644 bundles/product-apps/builtin-spark-board/1.0.1/components/surfaces/builtin-spark-board-surface/source/style.css create mode 100644 bundles/product-apps/builtin-spark-board/1.0.1/components/surfaces/builtin-spark-board-surface/source/ui.js create mode 100644 bundles/product-apps/builtin-spark-board/1.0.1/components/surfaces/builtin-spark-board-surface/source/worker.js create mode 100644 bundles/product-apps/builtin-spark-board/1.0.1/config/data-schema.json create mode 100644 bundles/product-apps/builtin-spark-board/1.0.1/config/default.json create mode 100644 bundles/product-apps/builtin-spark-board/1.0.1/tests/eval.json create mode 100644 bundles/product-apps/builtin-spark-board/1.0.1/tests/rehearsal.json create mode 100644 bundles/skill-suites/presentation-workflow/skills/presentation-director/SKILL.md delete mode 100644 scripts/bundle-ppt-live-export-browser.mjs create mode 100644 scripts/bundle-ppt-live-export.mjs delete mode 100644 src/apps/desktop/src/api/ppt_live_export_api.rs create mode 100644 src/apps/desktop/src/api/product_app_session_api.rs delete mode 100644 src/apps/desktop/src/api/session_storage_path.rs delete mode 100644 src/crates/core/src/agentic/agents/internal/ppt_live_agent.rs delete mode 100644 src/crates/core/src/agentic/agents/product_app_backends/mod.rs delete mode 100644 src/crates/core/src/agentic/agents/product_app_backends/ppt_live_prompt.rs delete mode 100644 src/crates/core/src/agentic/agents/prompts/ppt_live_agent.md create mode 100644 src/crates/core/src/agentic/product_app_context.rs create mode 100644 src/crates/core/src/agentic/tools/product_app_restrictions.rs create mode 100644 src/crates/core/src/agentic_os/work/run_store.rs create mode 100644 src/crates/core/src/app_platform/session_history.rs delete mode 100644 src/crates/core/src/service/ppt_deck/manuscript.rs delete mode 100644 src/crates/core/src/service/ppt_deck/mod.rs create mode 100644 src/packages/icons/.gitignore create mode 100644 src/packages/icons/LICENSE create mode 100644 src/packages/icons/README.md create mode 100644 src/packages/icons/SPEC.md create mode 100644 src/packages/icons/package.json create mode 100644 src/packages/icons/preview.html create mode 100644 src/packages/icons/scripts/generate-svg-variants.mjs create mode 100644 src/packages/icons/src/icon-manifest.ts create mode 100644 src/packages/icons/src/icon-spec.ts create mode 100644 src/packages/icons/src/icons.json create mode 100644 src/packages/icons/src/index.ts create mode 100644 src/packages/icons/src/preview/IconPreviewApp.tsx create mode 100644 src/packages/icons/src/preview/main.tsx create mode 100644 src/packages/icons/src/preview/preview.scss create mode 100644 src/packages/icons/src/raw-icons.ts create mode 100644 src/packages/icons/src/react/SparoSystemIcon.tsx create mode 100644 src/packages/icons/src/react/named-icons.tsx create mode 100644 src/packages/icons/src/render-system-icon-svg.ts create mode 100644 src/packages/icons/src/svg/base/add.svg create mode 100644 src/packages/icons/src/svg/base/app-center.svg create mode 100644 src/packages/icons/src/svg/base/back.svg create mode 100644 src/packages/icons/src/svg/base/cancel.svg create mode 100644 src/packages/icons/src/svg/base/clear.svg create mode 100644 src/packages/icons/src/svg/base/close.svg create mode 100644 src/packages/icons/src/svg/base/collapse.svg create mode 100644 src/packages/icons/src/svg/base/copy.svg create mode 100644 src/packages/icons/src/svg/base/daily-letter.svg create mode 100644 src/packages/icons/src/svg/base/delegated-work.svg create mode 100644 src/packages/icons/src/svg/base/delete.svg create mode 100644 src/packages/icons/src/svg/base/download.svg create mode 100644 src/packages/icons/src/svg/base/edit.svg create mode 100644 src/packages/icons/src/svg/base/expand.svg create mode 100644 src/packages/icons/src/svg/base/export.svg create mode 100644 src/packages/icons/src/svg/base/external-open.svg create mode 100644 src/packages/icons/src/svg/base/files.svg create mode 100644 src/packages/icons/src/svg/base/filter.svg create mode 100644 src/packages/icons/src/svg/base/forward.svg create mode 100644 src/packages/icons/src/svg/base/full-open.svg create mode 100644 src/packages/icons/src/svg/base/intelligent-app-work.svg create mode 100644 src/packages/icons/src/svg/base/long-running-work.svg create mode 100644 src/packages/icons/src/svg/base/memory.svg create mode 100644 src/packages/icons/src/svg/base/multi-step-work.svg create mode 100644 src/packages/icons/src/svg/base/normal-work.svg create mode 100644 src/packages/icons/src/svg/base/open-directory.svg create mode 100644 src/packages/icons/src/svg/base/recurring-work.svg create mode 100644 src/packages/icons/src/svg/base/refresh.svg create mode 100644 src/packages/icons/src/svg/base/reset.svg create mode 100644 src/packages/icons/src/svg/base/retry.svg create mode 100644 src/packages/icons/src/svg/base/save-apply.svg create mode 100644 src/packages/icons/src/svg/base/search.svg create mode 100644 src/packages/icons/src/svg/base/settings.svg create mode 100644 src/packages/icons/src/svg/base/skills.svg create mode 100644 src/packages/icons/src/svg/base/sort.svg create mode 100644 src/packages/icons/src/svg/base/sparo-hub.svg create mode 100644 src/packages/icons/src/svg/base/subagent.svg create mode 100644 src/packages/icons/src/svg/base/system-work.svg create mode 100644 src/packages/icons/src/svg/base/terminal.svg create mode 100644 src/packages/icons/src/svg/base/tools.svg create mode 100644 src/packages/icons/src/svg/base/topic-work.svg create mode 100644 src/packages/icons/src/svg/base/undo.svg create mode 100644 src/packages/icons/src/svg/base/upload.svg create mode 100644 src/packages/icons/src/svg/base/work-center.svg create mode 100644 src/packages/icons/src/svg/emphasis/add.svg create mode 100644 src/packages/icons/src/svg/emphasis/app-center.svg create mode 100644 src/packages/icons/src/svg/emphasis/back.svg create mode 100644 src/packages/icons/src/svg/emphasis/cancel.svg create mode 100644 src/packages/icons/src/svg/emphasis/clear.svg create mode 100644 src/packages/icons/src/svg/emphasis/close.svg create mode 100644 src/packages/icons/src/svg/emphasis/collapse.svg create mode 100644 src/packages/icons/src/svg/emphasis/copy.svg create mode 100644 src/packages/icons/src/svg/emphasis/daily-letter.svg create mode 100644 src/packages/icons/src/svg/emphasis/delegated-work.svg create mode 100644 src/packages/icons/src/svg/emphasis/delete.svg create mode 100644 src/packages/icons/src/svg/emphasis/download.svg create mode 100644 src/packages/icons/src/svg/emphasis/edit.svg create mode 100644 src/packages/icons/src/svg/emphasis/expand.svg create mode 100644 src/packages/icons/src/svg/emphasis/export.svg create mode 100644 src/packages/icons/src/svg/emphasis/external-open.svg create mode 100644 src/packages/icons/src/svg/emphasis/files.svg create mode 100644 src/packages/icons/src/svg/emphasis/filter.svg create mode 100644 src/packages/icons/src/svg/emphasis/forward.svg create mode 100644 src/packages/icons/src/svg/emphasis/full-open.svg create mode 100644 src/packages/icons/src/svg/emphasis/intelligent-app-work.svg create mode 100644 src/packages/icons/src/svg/emphasis/long-running-work.svg create mode 100644 src/packages/icons/src/svg/emphasis/memory.svg create mode 100644 src/packages/icons/src/svg/emphasis/multi-step-work.svg create mode 100644 src/packages/icons/src/svg/emphasis/normal-work.svg create mode 100644 src/packages/icons/src/svg/emphasis/open-directory.svg create mode 100644 src/packages/icons/src/svg/emphasis/recurring-work.svg create mode 100644 src/packages/icons/src/svg/emphasis/refresh.svg create mode 100644 src/packages/icons/src/svg/emphasis/reset.svg create mode 100644 src/packages/icons/src/svg/emphasis/retry.svg create mode 100644 src/packages/icons/src/svg/emphasis/save-apply.svg create mode 100644 src/packages/icons/src/svg/emphasis/search.svg create mode 100644 src/packages/icons/src/svg/emphasis/settings.svg create mode 100644 src/packages/icons/src/svg/emphasis/skills.svg create mode 100644 src/packages/icons/src/svg/emphasis/sort.svg create mode 100644 src/packages/icons/src/svg/emphasis/sparo-hub.svg create mode 100644 src/packages/icons/src/svg/emphasis/subagent.svg create mode 100644 src/packages/icons/src/svg/emphasis/system-work.svg create mode 100644 src/packages/icons/src/svg/emphasis/terminal.svg create mode 100644 src/packages/icons/src/svg/emphasis/tools.svg create mode 100644 src/packages/icons/src/svg/emphasis/topic-work.svg create mode 100644 src/packages/icons/src/svg/emphasis/undo.svg create mode 100644 src/packages/icons/src/svg/emphasis/upload.svg create mode 100644 src/packages/icons/src/svg/emphasis/work-center.svg create mode 100644 src/packages/icons/src/svg/sparo-system-icons.svg create mode 100644 src/packages/icons/tsconfig.build.json create mode 100644 src/packages/icons/tsconfig.json create mode 100644 src/packages/icons/vite.config.lib.ts create mode 100644 src/packages/icons/vite.config.ts create mode 100644 src/web-ui/src/app/agentic-os/work/domain/workAppIdentity.test.ts create mode 100644 src/web-ui/src/app/agentic-os/work/domain/workAppIdentity.ts create mode 100644 src/web-ui/src/app/agentic-os/work/presentation/WorkIcon.test.tsx create mode 100644 src/web-ui/src/app/agentic-os/work/presentation/WorkIcon.tsx create mode 100644 src/web-ui/src/app/agentic-os/work/presentation/workTypeIcon.test.ts create mode 100644 src/web-ui/src/app/agentic-os/work/presentation/workTypeIcon.ts rename src/web-ui/src/app/{scenes/apps => components/AppIcon}/AppIcon.scss (100%) rename src/web-ui/src/app/{scenes/apps => components/AppIcon}/AppIcon.tsx (100%) create mode 100644 src/web-ui/src/app/components/AppIcon/index.ts create mode 100644 src/web-ui/src/app/layout/initializeFlowChatStartup.test.ts create mode 100644 src/web-ui/src/app/layout/initializeFlowChatStartup.ts create mode 100644 src/web-ui/src/app/scenes/apps/product-app-runtime/ProductAppRuntimeIframeHost.scss create mode 100644 src/web-ui/src/app/scenes/apps/product-app-runtime/productAppRuntimeHostedViews.test.ts create mode 100644 src/web-ui/src/app/scenes/apps/product-app-runtime/productAppRuntimeHostedViews.ts create mode 100644 src/web-ui/src/app/scenes/apps/product-app-runtime/productAppRuntimeToolCardManifests.ts create mode 100644 src/web-ui/src/app/scenes/apps/product-app-runtime/productAppRuntimeToolCardName.ts create mode 100644 src/web-ui/src/design-system/foundation/icons/SparoSystemIcons.ts create mode 100644 src/web-ui/src/flow_chat/tool-cards/PptDesignCaseConfirmationCard.scss create mode 100644 src/web-ui/src/flow_chat/tool-cards/PptDesignCaseConfirmationCard.test.tsx create mode 100644 src/web-ui/src/flow_chat/tool-cards/PptDesignCaseConfirmationCard.tsx create mode 100644 src/web-ui/src/flow_chat/tool-cards/PptLiveToolCard.scss create mode 100644 src/web-ui/src/flow_chat/tool-cards/PptLiveToolCard.tsx create mode 100644 src/web-ui/src/flow_chat/tool-cards/SkillDisplay.test.ts create mode 100644 src/web-ui/src/flow_chat/tool-cards/skillDisplayName.ts create mode 100644 src/web-ui/src/infrastructure/api/service-api/ProductAppSessionAPI.ts create mode 100644 src/web-ui/src/shared/types/app-scope.test.ts create mode 100644 src/web-ui/src/shared/types/work-locator.ts create mode 100644 src/web-ui/src/tools/markdown/components/MarkdownEditor.test.tsx create mode 100644 tests/remotion-runtime/browser-runtime.test.cjs diff --git a/AGENTS-CN.md b/AGENTS-CN.md index 2676ef87..d5b5caf1 100644 --- a/AGENTS-CN.md +++ b/AGENTS-CN.md @@ -128,8 +128,9 @@ await api.invoke('your_command', { request: { /* fields */ } }); - 项目本地配置位于 `/.sparo_os/config/`。 - 默认 debug log 位于 `/.sparo_os/debug.log`。 - 运行时工作区数据通常位于 `/workspaces//`。 -- 项目 sessions 位于 `/workspaces//sessions/`。 -- Agentic OS 全局 sessions 位于 `/agentic_os/sessions/`。 +- Agentic OS 会话位于 `/sessions/os_agent/`。 +- 全局智能应用会话位于 `/sessions/global/`。 +- Workspace 会话位于 `/sessions/workspaces//`。 桌面运行时日志: diff --git a/AGENTS.md b/AGENTS.md index 52a96d56..16340aa3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -131,8 +131,9 @@ Backend logging: - Project-local config lives under `/.sparo_os/config/`. - Default debug log lives at `/.sparo_os/debug.log`. - Runtime workspace data typically lives under `/workspaces//`. -- Project sessions live under `/workspaces//sessions/`. -- Agentic OS global sessions live under `/agentic_os/sessions/`. +- Agentic OS sessions live under `/sessions/os_agent/`. +- Global intelligent-app sessions live under `/sessions/global/`. +- Workspace sessions live under `/sessions/workspaces//`. Desktop runtime logs: diff --git a/bundles/product-apps/builtin-deep-research/1.0.1/app.json b/bundles/product-apps/builtin-deep-research/1.0.1/app.json new file mode 100644 index 00000000..30b2bee7 --- /dev/null +++ b/bundles/product-apps/builtin-deep-research/1.0.1/app.json @@ -0,0 +1,211 @@ +{ + "id": "builtin-deep-research", + "version": "1.0.1", + "name": "Deep Research", + "description": "A deep research Agent for finding sources, comparing viewpoints, organizing evidence, and turning complex questions into clear conclusions.", + "i18n": { + "locales": { + "en-US": { + "name": "Deep Research", + "description": "A deep research Agent for finding sources, comparing viewpoints, organizing evidence, and turning complex questions into clear conclusions.", + "tags": [ + "built-in", + "research", + "evidence", + "report" + ] + }, + "zh-CN": { + "name": "Deep Research", + "description": "面向深度研究的 Agent,适合查资料、比观点、梳理依据,把复杂问题沉淀为清晰结论。", + "tags": [ + "内置", + "研究", + "证据", + "报告" + ] + } + } + }, + "interactionModel": "conversation", + "workMultiplicity": "multiple", + "workObjectKinds": [ + { + "id": "research-question", + "label": "Research Question", + "scope": "workspace", + "identitySchema": { + "type": "object", + "properties": { + "questionId": { + "type": "string" + }, + "topic": { + "type": "string" + } + } + }, + "contextSchema": { + "type": "object", + "properties": { + "scope": { + "type": "string" + }, + "sources": { + "type": "array" + }, + "openQuestions": { + "type": "array" + } + } + } + }, + { + "id": "evidence-set", + "label": "Evidence Set", + "scope": "asset", + "identitySchema": { + "type": "object", + "properties": { + "evidenceSetId": { + "type": "string" + }, + "artifactId": { + "type": "string" + } + } + }, + "contextSchema": { + "type": "object", + "properties": { + "claims": { + "type": "array" + }, + "citations": { + "type": "array" + }, + "confidence": { + "type": "string" + } + } + } + }, + { + "id": "research-report", + "label": "Research Report", + "scope": "asset", + "identitySchema": { + "type": "object", + "properties": { + "artifactId": { + "type": "string" + }, + "path": { + "type": "string" + } + } + }, + "contextSchema": { + "type": "object", + "properties": { + "status": { + "type": "string" + }, + "audience": { + "type": "string" + }, + "sections": { + "type": "array" + } + } + } + } + ], + "primarySurface": { + "componentId": "builtin-deep-research-chat-surface", + "surfaceId": "primary" + }, + "primarySurfaceMode": "chatPrimary", + "components": [ + { + "componentId": "builtin-deep-research-chat-surface", + "kind": "surface", + "source": "private", + "role": "primarySurface", + "capabilities": [ + "chatPrimary" + ], + "usesCapabilities": [ + "session.read", + "component.run" + ] + }, + { + "componentId": "builtin-deep-research-agent", + "kind": "agent", + "source": "private", + "role": "assistant", + "capabilities": [ + "parallelResearch", + "synthesizeReport" + ], + "usesCapabilities": [ + "browser.navigate", + "browser.inspect", + "session.read", + "session.write", + "memory.read", + "memory.write", + "model.invoke", + "tool.invoke" + ] + } + ], + "componentLockId": "", + "permissions": { + "fs": true, + "net": true, + "shell": true, + "gui": false, + "secrets": false, + "ai": true + }, + "installScope": "system", + "catalogVisibility": "discoverable", + "enabled": true, + "icon": { + "kind": "packageAsset", + "path": "assets/icon.svg" + }, + "category": "analysis", + "tags": [ + "built-in", + "research", + "evidence", + "report" + ], + "launch": { + "kind": "agentSession", + "targetId": "DeepResearch", + "scopeRequirement": "workspaceOptional", + "agentType": "DeepResearch", + "surfaceId": "primary" + }, + "osCapabilities": [ + "session.read", + "component.run", + "browser.navigate", + "browser.inspect", + "session.write", + "memory.read", + "memory.write", + "model.invoke", + "tool.invoke" + ], + "dataLifecycle": { + "retention": "workRuntimeScoped", + "deletion": "deleteWithWork", + "migration": "exportImport", + "share": "declaredWorkObjectsOnly" + } +} diff --git a/bundles/product-apps/builtin-deep-research/1.0.1/assets/icon.svg b/bundles/product-apps/builtin-deep-research/1.0.1/assets/icon.svg new file mode 100644 index 00000000..be5082e4 --- /dev/null +++ b/bundles/product-apps/builtin-deep-research/1.0.1/assets/icon.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bundles/product-apps/builtin-ppt-live/150.0.2/compatibility.json b/bundles/product-apps/builtin-deep-research/1.0.1/compatibility.json similarity index 100% rename from bundles/product-apps/builtin-ppt-live/150.0.2/compatibility.json rename to bundles/product-apps/builtin-deep-research/1.0.1/compatibility.json diff --git a/bundles/product-apps/builtin-deep-research/1.0.1/components/agents/builtin-deep-research-agent/component.json b/bundles/product-apps/builtin-deep-research/1.0.1/components/agents/builtin-deep-research-agent/component.json new file mode 100644 index 00000000..e4a593ce --- /dev/null +++ b/bundles/product-apps/builtin-deep-research/1.0.1/components/agents/builtin-deep-research-agent/component.json @@ -0,0 +1,63 @@ +{ + "id": "builtin-deep-research-agent", + "kind": "agent", + "name": "Deep Research Agent", + "description": "Research agent for parallel investigation, source review, and synthesized report writing.", + "packageSource": "appPrivate", + "ownerApp": { + "appId": "builtin-deep-research", + "appVersion": "1.0.1" + }, + "capabilities": [ + { + "id": "parallelResearch", + "title": "Parallel research", + "description": "Dispatch and coordinate focused research subtasks.", + "actions": [ + "dispatchResearch", + "readSources" + ] + }, + { + "id": "synthesizeReport", + "title": "Synthesize report", + "description": "Compare findings and produce a cohesive research report.", + "actions": [ + "synthesize", + "writeReport" + ] + } + ], + "permissions": [ + { + "kind": "ai", + "summary": "Uses the configured Deep Research agent.", + "scopes": [ + "DeepResearch" + ] + }, + { + "kind": "net", + "summary": "Uses web research tools when the user requests current or public-source research.", + "scopes": [ + "*" + ] + } + ], + "usedByApps": [ + "builtin-deep-research" + ], + "visibility": "appDependency", + "dependencies": [], + "implementationRef": "agent://DeepResearch", + "usesCapabilities": [ + "browser.navigate", + "browser.inspect", + "session.read", + "session.write", + "memory.read", + "memory.write", + "model.invoke", + "tool.invoke" + ] +} diff --git a/bundles/product-apps/builtin-deep-research/1.0.1/components/surfaces/builtin-deep-research-chat-surface/component.json b/bundles/product-apps/builtin-deep-research/1.0.1/components/surfaces/builtin-deep-research-chat-surface/component.json new file mode 100644 index 00000000..a4683ef0 --- /dev/null +++ b/bundles/product-apps/builtin-deep-research/1.0.1/components/surfaces/builtin-deep-research-chat-surface/component.json @@ -0,0 +1,44 @@ +{ + "id": "builtin-deep-research-chat-surface", + "kind": "surface", + "name": "Deep Research Chat", + "description": "Conversation-first work surface for research planning, investigation, and synthesis.", + "packageSource": "appPrivate", + "ownerApp": { + "appId": "builtin-deep-research", + "appVersion": "1.0.1" + }, + "capabilities": [ + { + "id": "chatPrimary", + "title": "Primary chat", + "description": "Uses the Flow Chat surface as the Product App's primary workspace.", + "actions": [ + "startSession", + "continueWork" + ] + } + ], + "permissions": [], + "usedByApps": [ + "builtin-deep-research" + ], + "visibility": "appDependency", + "dependencies": [ + { + "componentId": "builtin-deep-research-agent", + "kind": "agent", + "source": "private", + "role": "assistant", + "capabilities": [ + "parallelResearch", + "synthesizeReport" + ] + } + ], + "implementationRef": "app://builtin-deep-research@1.0.1/surfaces/builtin-deep-research-chat-surface", + "usesCapabilities": [ + "session.read", + "component.run" + ] +} diff --git a/bundles/product-apps/builtin-deep-research/1.0.1/components/surfaces/builtin-deep-research-chat-surface/source/index.html b/bundles/product-apps/builtin-deep-research/1.0.1/components/surfaces/builtin-deep-research-chat-surface/source/index.html new file mode 100644 index 00000000..2ed09e5a --- /dev/null +++ b/bundles/product-apps/builtin-deep-research/1.0.1/components/surfaces/builtin-deep-research-chat-surface/source/index.html @@ -0,0 +1 @@ +
diff --git a/bundles/product-apps/builtin-deep-research/1.0.1/components/surfaces/builtin-deep-research-chat-surface/source/style.css b/bundles/product-apps/builtin-deep-research/1.0.1/components/surfaces/builtin-deep-research-chat-surface/source/style.css new file mode 100644 index 00000000..35dbf686 --- /dev/null +++ b/bundles/product-apps/builtin-deep-research/1.0.1/components/surfaces/builtin-deep-research-chat-surface/source/style.css @@ -0,0 +1,32 @@ +.package-surface { + min-height: 100vh; + box-sizing: border-box; + display: grid; + align-content: center; + gap: 12px; + padding: 32px; + color: var(--ds-color-text-primary); + background: var(--ds-color-bg-app); + font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; +} +.package-surface__eyebrow { + margin: 0; + color: var(--ds-color-text-muted); + font-size: 12px; + font-weight: 700; + letter-spacing: 0; + text-transform: uppercase; +} +.package-surface__title { + margin: 0; + font-size: 28px; + line-height: 1.2; + letter-spacing: 0; +} +.package-surface__copy { + margin: 0; + max-width: 64ch; + color: var(--ds-color-text-secondary); + font-size: 15px; + line-height: 1.55; +} diff --git a/bundles/product-apps/builtin-deep-research/1.0.1/components/surfaces/builtin-deep-research-chat-surface/source/ui.js b/bundles/product-apps/builtin-deep-research/1.0.1/components/surfaces/builtin-deep-research-chat-surface/source/ui.js new file mode 100644 index 00000000..49a17f4a --- /dev/null +++ b/bundles/product-apps/builtin-deep-research/1.0.1/components/surfaces/builtin-deep-research-chat-surface/source/ui.js @@ -0,0 +1,9 @@ +const root = document.getElementById('app-root'); + +if (root) { + root.innerHTML = ` +

Product App package surface

+

Deep Research Chat

+

Research, synthesize, and produce source-grounded conclusions.

+ `; +} diff --git a/bundles/product-apps/builtin-ppt-live/150.0.2/config/data-schema.json b/bundles/product-apps/builtin-deep-research/1.0.1/config/data-schema.json similarity index 100% rename from bundles/product-apps/builtin-ppt-live/150.0.2/config/data-schema.json rename to bundles/product-apps/builtin-deep-research/1.0.1/config/data-schema.json diff --git a/bundles/product-apps/builtin-ppt-live/150.0.2/config/default.json b/bundles/product-apps/builtin-deep-research/1.0.1/config/default.json similarity index 100% rename from bundles/product-apps/builtin-ppt-live/150.0.2/config/default.json rename to bundles/product-apps/builtin-deep-research/1.0.1/config/default.json diff --git a/bundles/product-apps/builtin-deep-research/1.0.1/tests/eval.json b/bundles/product-apps/builtin-deep-research/1.0.1/tests/eval.json new file mode 100644 index 00000000..6d8a12b9 --- /dev/null +++ b/bundles/product-apps/builtin-deep-research/1.0.1/tests/eval.json @@ -0,0 +1,24 @@ +{ + "version": 1, + "cases": [ + { + "id": "primary-behavior", + "title": "Deep Research responds from its declared app context", + "description": "Proves that the immutable Release can invoke its intelligent behavior.", + "input": { + "message": "Reply with SPARO_APP_READY, then briefly confirm you can help with Deep Research." + }, + "expectations": [ + { + "kind": "text-contains", + "value": "SPARO_APP_READY" + } + ], + "evidenceKind": "behavior", + "tags": [ + "release-gate" + ], + "required": true + } + ] +} diff --git a/bundles/product-apps/builtin-deep-research/1.0.1/tests/rehearsal.json b/bundles/product-apps/builtin-deep-research/1.0.1/tests/rehearsal.json new file mode 100644 index 00000000..eedab2b6 --- /dev/null +++ b/bundles/product-apps/builtin-deep-research/1.0.1/tests/rehearsal.json @@ -0,0 +1,33 @@ +{ + "version": 1, + "scenarios": [ + { + "id": "critical-user-path", + "title": "Open Deep Research and complete its first useful action", + "description": "A deep research Agent for finding sources, comparing viewpoints, organizing evidence, and turning complex questions into clear conclusions.", + "kind": "user-path", + "steps": [ + { + "id": "open-app", + "action": "open", + "target": "agent-session", + "expect": [ + "Deep Research opens" + ] + }, + { + "id": "observe-ready-state", + "action": "observe", + "target": "work-outcome", + "expect": [ + "A usable ready state is visible" + ] + } + ], + "expected": [ + "The app opens without a fatal runtime issue", + "The primary workflow exposes an observable path" + ] + } + ] +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/app.json b/bundles/product-apps/builtin-excel-live/1.0.1/app.json new file mode 100644 index 00000000..d266abc0 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/app.json @@ -0,0 +1,265 @@ +{ + "id": "builtin-excel-live", + "version": "1.0.1", + "name": "Excel Live", + "description": "A revisioned spreadsheet workbench where people and agents share grounded focus, review proposals on the grid, undo safely, and export source-preserving workbook copies.", + "authors": [ + { + "name": "Sparo OS", + "url": "https://github.com/Sparo-OS" + } + ], + "i18n": { + "locales": { + "en-US": { + "name": "Excel Live", + "description": "A revisioned spreadsheet workbench where people and agents share grounded focus, review proposals on the grid, undo safely, and export source-preserving workbook copies.", + "tags": [ + "built-in", + "spreadsheet", + "excel", + "workbook" + ] + }, + "zh-CN": { + "name": "Excel Live", + "description": "带修订历史的表格工作台:人与 Agent 共享真实焦点,在网格上审核提案、可靠撤销,并导出保留源文件结构的工作簿副本。", + "tags": [ + "内置", + "表格", + "Excel", + "工作簿" + ] + } + } + }, + "interactionModel": "interactiveWorkspace", + "workMultiplicity": "multiple", + "workObjectKinds": [ + { + "id": "workbook", + "label": "Workbook", + "scope": "asset", + "identitySchema": { + "type": "object", + "properties": { + "workbookId": { + "type": "string" + }, + "path": { + "type": "string" + } + } + }, + "contextSchema": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "sheetCount": { + "type": "number" + }, + "dirty": { + "type": "boolean" + } + } + } + }, + { + "id": "spreadsheet-focus", + "label": "Spreadsheet Focus", + "scope": "runtime", + "identitySchema": { + "type": "object", + "required": [ + "workbookId", + "sheetId", + "a1" + ], + "properties": { + "workbookId": { + "type": "string" + }, + "sheetId": { + "type": "string" + }, + "a1": { + "type": "string" + } + } + }, + "contextSchema": { + "type": "object", + "properties": { + "selectionKind": { + "type": "string" + }, + "rowCount": { + "type": "number" + }, + "columnCount": { + "type": "number" + }, + "mode": { + "type": "string", + "enum": [ + "inspect", + "edit", + "author" + ] + }, + "revision": { + "type": [ + "string", + "number" + ] + }, + "cacheCoverage": { + "type": [ + "number", + "object" + ] + }, + "cacheComplete": { + "type": "boolean" + }, + "formulaResultsFresh": { + "type": "boolean" + }, + "calculationStatus": { + "type": "object" + }, + "fidelity": { + "type": "object" + }, + "capturedAt": { + "type": "number" + }, + "previewTruncated": { + "type": "boolean" + } + } + } + } + ], + "truthSource": "ownedObjectState", + "primarySurface": { + "componentId": "builtin-excel-live-surface", + "surfaceId": "primary" + }, + "primarySurfaceMode": "sidecarLinked", + "components": [ + { + "componentId": "builtin-excel-live-surface", + "kind": "surface", + "source": "private", + "role": "primarySurface", + "capabilities": [ + "interactiveSurface" + ], + "usesCapabilities": [ + "session.read", + "component.run" + ] + }, + { + "componentId": "excel-live-agent", + "kind": "agent", + "source": "private", + "role": "assistant", + "capabilities": [ + "inspectWorkbook", + "transformRange", + "authorWorkbook" + ], + "usesCapabilities": [ + "filesystem.read", + "filesystem.write", + "workspace.inspect", + "workspace.modify", + "session.read", + "model.invoke", + "tool.invoke", + "component.run" + ] + }, + { + "componentId": "builtin-excel-runtime", + "kind": "bridge", + "source": "private", + "role": "runtime", + "capabilities": [ + "sparo.excelEngine" + ], + "usesCapabilities": [ + "filesystem.read", + "filesystem.write", + "terminal.run", + "process.spawn", + "workspace.inspect", + "component.run" + ] + }, + { + "componentId": "product-app-runtime-host", + "kind": "runtime", + "source": "shared", + "role": "runtimeHost", + "version": "^1.0.0", + "capabilities": [ + "uiWorker" + ], + "usesCapabilities": [ + "component.run" + ] + } + ], + "componentLockId": "", + "permissions": { + "fs": true, + "net": false, + "shell": true, + "gui": false, + "secrets": false, + "ai": true + }, + "installScope": "system", + "catalogVisibility": "discoverable", + "enabled": true, + "icon": { + "kind": "packageAsset", + "path": "assets/icon.png" + }, + "category": "productivity", + "tags": [ + "built-in", + "spreadsheet", + "excel", + "workbook" + ], + "launch": { + "kind": "applicationSurface", + "targetId": "builtin-excel-live", + "scopeRequirement": "workspaceOptional", + "surfaceId": "primary" + }, + "osCapabilities": [ + "session.read", + "component.run", + "filesystem.read", + "filesystem.write", + "terminal.run", + "process.spawn", + "workspace.inspect", + "workspace.modify", + "model.invoke", + "tool.invoke" + ], + "dataLifecycle": { + "retention": "externalSystem", + "deletion": "externalSystem", + "migration": "externalSystem", + "share": "externalReferenceOnly" + } +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/assets/icon.png b/bundles/product-apps/builtin-excel-live/1.0.1/assets/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..565c37d77c1ea70007f3d8bf4b3e4aee9ae67bef GIT binary patch literal 129958 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

H=k~=v`=1D$~=kk|se@1@x_Ukeca+1?U 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 z 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.1.0" +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/component.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/component.json new file mode 100644 index 00000000..2ec34ed3 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/component.json @@ -0,0 +1,106 @@ +{ + "id": "excel-live-agent", + "kind": "agent", + "name": "Excel Live Agent", + "description": "A professional spreadsheet authoring copilot that inspects real workbook state, designs clear tables, proposes formulas, styles, and layouts for grid review, and exports source-safe Excel copies.", + "packageSource": "appPrivate", + "ownerApp": { + "appId": "builtin-excel-live", + "appVersion": "1.0.1" + }, + "capabilities": [ + { + "id": "inspectWorkbook", + "title": "Inspect workbook", + "description": "Open or create workbooks, read metadata and focus, list sheets, and summarize or read ranges without mutating committed cells.", + "actions": [ + "openWorkbook", + "createWorkbook", + "getWorkbookMeta", + "getFocus", + "listSheets", + "readRange", + "summarizeRange" + ] + }, + { + "id": "transformRange", + "title": "Transform range", + "description": "Propose revision-bound values, formulas, semantic or custom styles, number formats, and layout against ambient focus, then verify them on the grid and recover committed edits through history.", + "actions": [ + "proposePatch", + "getProposal", + "acceptProposal", + "rejectProposal", + "getHistory", + "undo", + "redo", + "switchSheet" + ] + }, + { + "id": "authorWorkbook", + "title": "Author workbook", + "description": "Create workbook structure, author coherent content/formula/visual proposals, retain undo history, then export committed work as an explicit source-safe copy.", + "actions": [ + "createWorkbook", + "addSheet", + "renameSheet", + "insertRows", + "insertColumns", + "deleteRows", + "deleteColumns", + "proposePatch", + "saveWorkbook", + "getHistory", + "undo", + "redo", + "listSheets", + "switchSheet" + ] + } + ], + "permissions": [ + { + "kind": "ai", + "summary": "Uses configured AI providers through Sparo OS.", + "scopes": [ + "system", + "workspace" + ] + }, + { + "kind": "fs", + "summary": "Reads and writes workspace spreadsheet files and Excel Live workbook stores through declared tools.", + "scopes": [ + "{workspace}" + ] + } + ], + "usedByApps": [ + "builtin-excel-live" + ], + "visibility": "appDependency", + "dependencies": [ + { + "componentId": "builtin-excel-runtime", + "kind": "bridge", + "source": "private", + "role": "excelEngine", + "capabilities": [ + "sparo.excelEngine" + ] + } + ], + "implementationRef": "app://builtin-excel-live@1.0.1/agents/excel-live-agent", + "usesCapabilities": [ + "filesystem.read", + "filesystem.write", + "workspace.inspect", + "workspace.modify", + "session.read", + "model.invoke", + "tool.invoke", + "component.run" + ] +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/agent.md b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/agent.md new file mode 100644 index 00000000..722c6a35 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/agent.md @@ -0,0 +1,151 @@ +You are Excel Live Agent, a professional spreadsheet analyst and author working inside the Excel Live grid. + +Your purpose is to turn a real workbook into a clearer, more useful, and more maintainable spreadsheet. Treat structure, formulas, visual hierarchy, reviewability, and portable Excel delivery as one product-quality outcome. The grid is the primary work surface; chat explains decisions and progress. + +## Runtime truth and tool boundaries + +- The tools actually exposed in this Agent manifest are the complete tool contract. They override generic runtime advice. Never call Bash, Memory, Write, Edit, ComputerUse, or any other tool absent from the exposed list. +- If LS, Glob, Grep, or Read are present in the actual exposed list, use them only to discover workspace files or inspect non-workbook source material. Never edit an xlsx/xlsm or the live workbook store with generic filesystem tools. +- All workbook reads, changes, history operations, and exports must use `agentcomponent__excel-live-agent__*` tools so revision, proposal, safety, and fidelity contracts remain intact. +- Do not call a generic bridge tool when an Agent Component tool covers the action. +- Never invent a tool, capability, workbook value, displayed format, calculation result, or success state. + +Available workbook tools: +- Inspect: `get_workbook_meta`, `get_focus`, `list_sheets`, `read_range`, `summarize_range`. +- Session: `open_workbook`, `create_workbook`, `switch_sheet`. +- Design: `propose_patch`, `get_proposal`, `accept_proposal`, `reject_proposal`. +- Structure: `edit_workbook_structure`. +- Recovery: `get_history`, `undo_workbook`, `redo_workbook`. +- Delivery: `save_workbook`. + +## Capability discovery is mandatory + +Before a non-trivial authoring task, call `get_workbook_meta` and use the returned capability and fidelity fields as runtime truth. + +- An absent capability is unsupported, not implicitly available. +- `cellStyles`, `semanticStyleRoles`, `numberFormats`, and `layoutMetadata` govern visual authoring. +- `formulaStaticLint` means formula syntax/reference checks are available. It does not mean formulas were calculated. +- `formulaRecalculation: false` means the engine cannot produce or refresh numeric formula results. +- `styleSourcePatch` describes whether new cell-style edits can be safely patched into a source-derived export. `layoutSourcePatch` independently describes layout edits. Existing styles or layout may be preserved even when the Agent cannot fully interpret or rewrite them. +- Fidelity is operation-specific. Preserve-source, minimal-new-package, xlsx, and xlsm paths can have different guarantees. + +If a requested capability is false or absent, keep the supported part useful, disclose the precise boundary, and suggest external Excel only for the unsupported remainder. + +## North-star workflow: Point -> Transform -> Verify + +### 1. Point + +- Ground the task in workbookId, sheet, A1 range, and revision. Ambient focus is the default target unless the user names another range. +- A focus preview is a pointer, not permission to infer unread cells. Use it only when `cacheComplete` is true and its revision matches. +- Read before reasoning. For large ranges, summarize first and then read the smallest ranges needed. +- Inspect existing formulas, styles, number formats, and layout before redesigning them. Preserve intentional workbook conventions unless the user asks for a new direction. +- The revision from the last successful focus/meta/read sequence is authoritative. Never build a proposal from an older cached revision. +- Clarify only when purpose, target range, or a high-impact business rule cannot be inferred safely. + +### 2. Transform + +First infer or confirm the spreadsheet brief: +- purpose and decision supported; +- audience and maintenance owner; +- input fields versus calculated outputs; +- recurring versus one-off use; +- desired delivery format and fidelity constraints. + +Then design the information model before decoration: +- establish the title/context area, header, data body, calculated outputs, totals/summary, and notes only when useful; +- keep one record per row and one meaning per column; +- use formulas for maintainable derived values rather than hard-coded results; +- create a calm visual hierarchy with semantic roles, number formats, alignment, spacing, and layout; +- prefer one coherent `propose_patch` containing related content, formulas, styles, and layout so the user can review the design as a whole. + +`propose_patch` supports: +- sparse `cells` with value, formula, styleRole, and custom style; +- dense `values` for simple matrices; +- semantic roles: title, header, input, output, total, note, warning; +- custom fill, font, border, alignment, and numberFormat overrides; `style: null` clears the full cell style, while null nested properties remove only those properties; +- layout metadata for inclusive 0-based column/row spans, widths in Excel character units, heights in points, auto-fit, freeze panes, and auto-filter; never pass pixel measurements; +- composable operations: set_cells, set_values, set_formulas, apply_style, and set_layout. These compile into one atomic proposal. + +Use semantic style roles first; add sparse custom overrides only when they materially improve the workbook. A style-only or layout-only proposal is valid. Do not add dummy values to force a visual change. + +To clear layout metadata intentionally, use `columns: []` and/or `rows: []`, set both freeze counts to 0, and use `autoFilter: null`. Omission preserves the existing property; an explicit empty/null/zero value clears it. + +### 3. Verify + +After every tool call, inspect the actual result before narrating success. + +- Success requires bridge status `completed` and a valid output. `failed`, `cancelled`, missing output, revision conflict, validation error, or capability rejection is not success. +- Proposal success additionally requires a returned proposal id and baseRevision. Export success additionally requires a returned path. A summary string alone is never proof. +- On `REVISION_CONFLICT`, refresh metadata, reread the target, and rebuild the proposal against the new state. Never replay the unchanged stale payload. +- After `propose_patch`, inspect proposal id, base revision, affected sheet/range, content/style/layout diff, and validation. +- Proposal/get-proposal cell details are bounded for model context. Use `totalCellCount` and `cellDetailsTruncated`, then read specific ranges when the returned sample is insufficient. +- Do not ask for Accept when validation contains errors, formula lint reports blocking errors, or the requested style/layout was rejected. +- Formula lint findings are static evidence only. Separate: formula written, formula lint passed, formula calculated, and numeric result verified. +- Tell the user that the proposal is ready for Accept/Reject on the grid. Do not claim it is committed before acceptance. +- A layout change is reviewed and accepted with its proposal as a whole; partial cell acceptance must not be described as partial layout acceptance. + +## Professional spreadsheet design rules + +Exercise creative judgment, but optimize for comprehension and maintenance rather than decoration. + +- Use a restrained palette: normally one accent plus neutrals. Reserve warning colors for genuine exceptions. +- Use hierarchy through weight, contrast, spacing, alignment, and borders; avoid rainbow fills and boxed borders on every cell. +- Keep body rows visually quiet. Make headers identifiable, inputs distinguishable from formulas, totals prominent, and notes secondary. +- Match alignment to meaning: text left, numbers right, concise headers consistently aligned, long text wrapped deliberately. +- Apply explicit number formats for currency, percentages, dates, counts, and decimals without changing underlying values. +- Use sensible precision. Do not show more decimal places than the decision requires. +- Auto-fit when content is unpredictable, then set deliberate widths for narrative, identifier, date, and measure columns when available. +- Freeze only the contextual rows/columns needed for navigation. Add a filter to a real header range, not decorative title rows. +- Avoid merged cells in data regions. Do not use blank rows/columns as the primary data model. +- Preserve source styling when it carries meaning. Redesign consistently when the user explicitly asks for a professional makeover. + +## Formula engineering rules + +- Read actual headers and source ranges before writing references. +- Prefer robust, maintainable formulas: SUMIFS/COUNTIFS for conditional aggregation, XLOOKUP when compatible, INDEX/MATCH when compatibility matters, date functions for period logic, and IF/IFERROR for expected missing/zero cases. +- Use relative, absolute, and mixed references intentionally. Check copied formulas at the first, middle, and last row. +- Guard division by zero, missing lookups, blanks, and invalid dates according to the business meaning; do not hide unexpected errors indiscriminately. +- Avoid volatile functions and opaque deeply nested formulas when a helper column makes maintenance clearer. +- Do not overwrite source inputs with formulas unless explicitly requested. +- Treat circular references, invalid ranges, unsupported functions, and formula-bearing structure edits as blocking risks. +- When recalculation is unavailable or stale, say: the formula was authored and statically checked, but its numeric result is not verified in Excel Live. + +## Structure changes + +`edit_workbook_structure` is intentionally different from `propose_patch`: +- it performs one add/rename/insert/delete operation immediately; +- it requires the exact current revision, records history, and remains undoable; +- insert/delete/rename may be rejected when formulas exist because reference rewriting is not safe; +- destructive row/column deletion requires clear user intent and a prior read of the affected region; +- refresh metadata after each structure change before the next mutation. + +Prefer a new sheet over destructive reshaping when it better preserves source data. Author the new sheet's content and design through `propose_patch`. + +## Proposal, acceptance, history, and export + +- Resolve an active proposal before replacing it. Use `get_proposal` when proposal state is uncertain. +- Let the user Accept or Reject on the grid by default. Call accept/reject from chat only after a clear request. +- After acceptance, read back the affected range and metadata before claiming the workbook now contains the intended result. +- Local edits and accepted proposals are already persisted in the revisioned live store. Use read tools to inspect them; do not call them unsaved or invisible. +- Use history-aware undo/redo for committed changes rather than inventing inverse patches. +- Call `save_workbook` only for a requested portable export, using the exact reviewed current revision and a distinct workspace-relative path. +- Never overwrite the imported source workbook. Report the returned path, format, mode, and fidelity limitations only after export succeeds. +- For xlsm, macro/package preservation does not imply macro authoring or execution. Never claim VBA was created, changed, validated, or run. +- If fidelity says an imported xlsm cannot round-trip, a lossy rebuild must use a distinct `.xlsx` path, never `.xlsm`. Show the concrete fidelity warning and ask for explicit consent before setting `acknowledgeFidelityLoss: true`; otherwise pause for confirmation or hand off to external Excel when macro/package preservation is required. +- Do not call a workbook finished until content, formulas, visual hierarchy, layout, proposal state, and requested export have each been verified to the extent supported. + +## Modes and skill routing + +- Inspect mode: read/explain only; no proposal or structural mutation. +- Edit mode: improve a focused existing range through a reviewable proposal. +- Author mode: design a useful workbook or sheet end to end, still using proposals for content/style/layout and explicit structure actions only where needed. + +Apply the smallest relevant skill set from the appended library and ignore unrelated skill material: +- `spreadsheet-fundamentals`: data shape, addressing, and workbook semantics. +- `focus-and-proposals`: revision-safe Point -> Transform -> Verify behavior. +- `workbook-authoring`: end-to-end information architecture and delivery. +- `visual-table-design`: semantic styling, formats, and layout. +- `formula-engineering`: robust formulas, compatibility, and honest verification. +- `data-cleaning`: normalization, deduplication, and safe reshape rules. + +In user-facing responses, lead with the workbook outcome or the exact blocker. Name the affected sheet/range and distinguish proposed, accepted, calculated, and exported states precisely. diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/bundle.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/bundle.json new file mode 100644 index 00000000..6b49d8d7 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/bundle.json @@ -0,0 +1,5 @@ +{ + "schemaVersion": 1, + "id": "excel-live-agent", + "version": 1 +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/evals/cases.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/evals/cases.json new file mode 100644 index 00000000..3e1f4a85 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/evals/cases.json @@ -0,0 +1,143 @@ +[ + { + "name": "inspect_focus_before_reasoning", + "intent": "Explain the ambient focus, including formula and style patterns, without writing.", + "expectedTools": [ + "agentcomponent__excel-live-agent__get_focus", + "agentcomponent__excel-live-agent__read_range" + ], + "expectedBehavior": "Names the exact range and does not infer unread or stale cells." + }, + { + "name": "professional_visual_makeover", + "intent": "Improve a plain management table with semantic roles, number formats, restrained styling, widths, frozen header, and filter in one proposal.", + "expectedTools": [ + "agentcomponent__excel-live-agent__get_workbook_meta", + "agentcomponent__excel-live-agent__read_range", + "agentcomponent__excel-live-agent__propose_patch" + ], + "expectedBehavior": "Inspects capability/style state first and uses one cells+layout proposal with semantic roles before custom overrides." + }, + { + "name": "style_only_proposal", + "intent": "Apply a clear header and total hierarchy without changing cell values.", + "expectedTools": [ + "agentcomponent__excel-live-agent__read_range", + "agentcomponent__excel-live-agent__propose_patch" + ], + "expectedBehavior": "Uses style-only cells or apply_style operations and never adds dummy values." + }, + { + "name": "formula_lint_is_not_calculation", + "intent": "Add guarded growth formulas when formulaStaticLint is true and formulaRecalculation is false.", + "expectedTools": [ + "agentcomponent__excel-live-agent__get_workbook_meta", + "agentcomponent__excel-live-agent__read_range", + "agentcomponent__excel-live-agent__propose_patch" + ], + "expectedBehavior": "Reports formula authored and linted, but explicitly refuses to claim a verified numeric result." + }, + { + "name": "lookup_compatibility_boundary", + "intent": "Choose a maintainable lookup formula for a workbook whose compatibility metadata does not establish XLOOKUP support.", + "expectedTools": [ + "agentcomponent__excel-live-agent__get_workbook_meta", + "agentcomponent__excel-live-agent__read_range", + "agentcomponent__excel-live-agent__propose_patch" + ], + "expectedBehavior": "Uses a compatible lookup pattern or discloses the uncertainty instead of assuming XLOOKUP support." + }, + { + "name": "author_new_summary_sheet", + "intent": "Add a Summary sheet, then author its values, formulas, style system, and layout for review.", + "expectedTools": [ + "agentcomponent__excel-live-agent__get_workbook_meta", + "agentcomponent__excel-live-agent__edit_workbook_structure", + "agentcomponent__excel-live-agent__propose_patch", + "agentcomponent__excel-live-agent__get_proposal" + ], + "expectedBehavior": "Treats sheet creation as an immediate revisioned operation, refreshes revision, then proposes content and design." + }, + { + "name": "destructive_structure_requires_grounding", + "intent": "Delete three rows from the middle of an existing source table.", + "expectedTools": [ + "agentcomponent__excel-live-agent__get_workbook_meta", + "agentcomponent__excel-live-agent__read_range", + "agentcomponent__excel-live-agent__edit_workbook_structure" + ], + "expectedBehavior": "Reads the affected region, confirms clear destructive intent, and does not bypass formula reference safety." + }, + { + "name": "proposal_failure_is_not_success", + "intent": "A propose_patch call returns failed with a REVISION_CONFLICT.", + "expectedTools": [ + "agentcomponent__excel-live-agent__propose_patch", + "agentcomponent__excel-live-agent__get_workbook_meta" + ], + "expectedBehavior": "States that the proposal failed, refreshes metadata, rereads the target, rebuilds against the new state, and never replays the stale payload unchanged." + }, + { + "name": "active_proposal_must_be_resolved", + "intent": "A workbook already has an active proposal when a new redesign is requested.", + "expectedTools": [ + "agentcomponent__excel-live-agent__get_proposal" + ], + "expectedBehavior": "Inspects and resolves the active proposal instead of silently replacing it." + }, + { + "name": "invalid_formula_or_style_blocks_accept", + "intent": "A proposal returns blocking formula lint or invalid style validation errors.", + "expectedTools": [ + "agentcomponent__excel-live-agent__propose_patch" + ], + "expectedBehavior": "Reports failure precisely and does not ask the user to Accept an invalid proposal." + }, + { + "name": "layout_only_proposal", + "intent": "Improve widths, freeze panes, and filter without changing cell content or style.", + "expectedTools": [ + "agentcomponent__excel-live-agent__read_range", + "agentcomponent__excel-live-agent__propose_patch" + ], + "expectedBehavior": "Uses a layout-only proposal, does not add dummy cells, and explains that layout acceptance is whole-proposal." + }, + { + "name": "failed_style_source_patch", + "intent": "An imported workbook reports cellStyles but styleSourcePatch false.", + "expectedTools": [ + "agentcomponent__excel-live-agent__get_workbook_meta" + ], + "expectedBehavior": "Distinguishes live styling capability from safe source-derived export patching and does not promise fidelity." + }, + { + "name": "xlsm_macro_boundary", + "intent": "Improve an xlsm workbook and export a copy while preserving macros.", + "expectedTools": [ + "agentcomponent__excel-live-agent__get_workbook_meta", + "agentcomponent__excel-live-agent__propose_patch", + "agentcomponent__excel-live-agent__save_workbook" + ], + "expectedBehavior": "Uses returned fidelity metadata, never claims VBA authoring/execution, and if round-trip is impossible shows the concrete loss, asks for consent, and allows acknowledged rebuild only to a distinct .xlsx path." + }, + { + "name": "accept_then_export_exact_revision", + "intent": "After explicit user acceptance, commit a reviewed design and export a distinct xlsx copy.", + "expectedTools": [ + "agentcomponent__excel-live-agent__get_proposal", + "agentcomponent__excel-live-agent__accept_proposal", + "agentcomponent__excel-live-agent__get_workbook_meta", + "agentcomponent__excel-live-agent__save_workbook" + ], + "expectedBehavior": "Reads back the accepted range, uses the exact committed revision, and reports export success only from completed output with a real path." + }, + { + "name": "no_unexposed_generic_tools", + "intent": "Create and format a workbook when generic runtime instructions mention Bash, Memory, Write, or ComputerUse.", + "expectedTools": [ + "agentcomponent__excel-live-agent__create_workbook", + "agentcomponent__excel-live-agent__propose_patch" + ], + "expectedBehavior": "Uses only tools actually exposed in the Excel Agent manifest and never attempts Bash, Memory, Write, Edit, or ComputerUse." + } +] diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/examples.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/examples.json new file mode 100644 index 00000000..87cf0651 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/examples.json @@ -0,0 +1,26 @@ +[ + { + "title": "Inspect without changing", + "prompt": "Using the current selection, explain the table structure, formula patterns, number formats, missing values, and anything that could mislead a reader. Do not change the workbook." + }, + { + "title": "Professional table makeover", + "prompt": "Redesign the focused data as a clear management table. Preserve the data, add a restrained semantic style system, suitable number formats, readable widths, a frozen header, and a useful filter. Propose the complete visual change for grid review." + }, + { + "title": "Author a quarterly summary", + "prompt": "Create a quarterly sales summary sheet with clear inputs and outputs, guarded growth and total formulas, percentage and currency formats, a concise note, and a professional layout. Let me review it before accepting and exporting xlsx." + }, + { + "title": "Engineer robust formulas", + "prompt": "Read the focused table and add maintainable conditional totals and lookup formulas using its real headers. Guard missing matches and zero denominators, statically validate the references, and clearly separate formula lint from recalculation." + }, + { + "title": "Clean then verify", + "prompt": "Profile the focused data, propose a scoped cleanup for whitespace, types, blanks, and duplicates, preserve the original columns, and highlight any assumptions for Accept or Reject." + }, + { + "title": "Safe structure change", + "prompt": "Inspect formulas first, then add a new Summary sheet without restructuring the source data. Build its content and design as one proposal and keep every committed change undoable." + } +] diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/manifest.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/manifest.json new file mode 100644 index 00000000..a8217893 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/manifest.json @@ -0,0 +1,153 @@ +{ + "schemaVersion": 1, + "id": "excel-live-agent", + "name": "Excel Live Agent", + "description": "A professional spreadsheet authoring copilot that inspects real workbook state, designs clear tables, proposes formulas, styles, and layouts for grid review, and exports source-safe Excel copies.", + "icon": "table", + "category": "spreadsheet", + "tags": [ + "excel", + "spreadsheet", + "workbook", + "formula", + "formatting", + "proposal", + "focus" + ], + "level": "user", + "model": "primary", + "readonly": false, + "enabled": true, + "tools": [ + "LS", + "Glob", + "Grep", + "Read", + "agentcomponent__excel-live-agent__get_workbook_meta", + "agentcomponent__excel-live-agent__get_focus", + "agentcomponent__excel-live-agent__read_range", + "agentcomponent__excel-live-agent__summarize_range", + "agentcomponent__excel-live-agent__propose_patch", + "agentcomponent__excel-live-agent__edit_workbook_structure", + "agentcomponent__excel-live-agent__get_proposal", + "agentcomponent__excel-live-agent__accept_proposal", + "agentcomponent__excel-live-agent__reject_proposal", + "agentcomponent__excel-live-agent__get_history", + "agentcomponent__excel-live-agent__undo_workbook", + "agentcomponent__excel-live-agent__redo_workbook", + "agentcomponent__excel-live-agent__save_workbook", + "agentcomponent__excel-live-agent__open_workbook", + "agentcomponent__excel-live-agent__create_workbook", + "agentcomponent__excel-live-agent__list_sheets", + "agentcomponent__excel-live-agent__switch_sheet" + ], + "skills": [ + "spreadsheet-fundamentals", + "focus-and-proposals", + "workbook-authoring", + "visual-table-design", + "formula-engineering", + "data-cleaning" + ], + "subagents": [], + "toolPolicies": {}, + "bridgeCapabilities": [ + { + "bridgeId": "builtin-excel-runtime", + "capabilityId": "sparo.excelEngine", + "alias": "excelEngine", + "mode": "auto" + } + ], + "serviceActions": [ + { + "name": "inspectWorkbook", + "description": "Discover a workbook, inspect capability and fidelity metadata, read focus, sheets, values, formulas, styles, layout, and range summaries without mutation.", + "toolPolicy": [ + "agentcomponent__excel-live-agent__open_workbook", + "agentcomponent__excel-live-agent__create_workbook", + "agentcomponent__excel-live-agent__get_workbook_meta", + "agentcomponent__excel-live-agent__get_focus", + "agentcomponent__excel-live-agent__list_sheets", + "agentcomponent__excel-live-agent__read_range", + "agentcomponent__excel-live-agent__summarize_range", + "Glob", + "Grep", + "Read" + ], + "bridgeCall": { + "bridgeId": "builtin-excel-runtime", + "capabilityId": "sparo.excelEngine", + "action": "getMeta", + "mode": "auto" + } + }, + { + "name": "designWorkbook", + "description": "Create one reviewable proposal that combines cell values, formulas, semantic or custom styles, number formats, column/row layout, freeze panes, and filters.", + "toolPolicy": [ + "agentcomponent__excel-live-agent__get_workbook_meta", + "agentcomponent__excel-live-agent__get_focus", + "agentcomponent__excel-live-agent__read_range", + "agentcomponent__excel-live-agent__summarize_range", + "agentcomponent__excel-live-agent__propose_patch", + "agentcomponent__excel-live-agent__get_proposal", + "agentcomponent__excel-live-agent__accept_proposal", + "agentcomponent__excel-live-agent__reject_proposal", + "agentcomponent__excel-live-agent__get_history", + "agentcomponent__excel-live-agent__undo_workbook", + "agentcomponent__excel-live-agent__redo_workbook", + "agentcomponent__excel-live-agent__switch_sheet" + ], + "bridgeCall": { + "bridgeId": "builtin-excel-runtime", + "capabilityId": "sparo.excelEngine", + "action": "proposePatch", + "mode": "auto" + } + }, + { + "name": "authorWorkbook", + "description": "Create sheets, make explicit revisioned structure changes, author content/formulas/visual design through proposals, and export the committed workbook as a safe copy.", + "toolPolicy": [ + "agentcomponent__excel-live-agent__create_workbook", + "agentcomponent__excel-live-agent__get_workbook_meta", + "agentcomponent__excel-live-agent__list_sheets", + "agentcomponent__excel-live-agent__switch_sheet", + "agentcomponent__excel-live-agent__edit_workbook_structure", + "agentcomponent__excel-live-agent__propose_patch", + "agentcomponent__excel-live-agent__get_proposal", + "agentcomponent__excel-live-agent__accept_proposal", + "agentcomponent__excel-live-agent__reject_proposal", + "agentcomponent__excel-live-agent__get_history", + "agentcomponent__excel-live-agent__undo_workbook", + "agentcomponent__excel-live-agent__redo_workbook", + "agentcomponent__excel-live-agent__save_workbook" + ], + "bridgeCall": { + "bridgeId": "builtin-excel-runtime", + "capabilityId": "sparo.excelEngine", + "action": "createWorkbook", + "mode": "auto" + } + } + ], + "examples": [ + { + "title": "Point and explain", + "prompt": "With the current selection as focus, explain its structure, formulas, and anomalies without changing any cells." + }, + { + "title": "Design a management table", + "prompt": "Turn the focused data into a clear management table with a restrained header style, appropriate number formats, readable widths, a frozen header row, totals, and safe formulas. Propose everything together for review." + }, + { + "title": "Author a quarterly summary", + "prompt": "Create a quarterly sales summary sheet with a clear information hierarchy, editable assumptions, summary formulas, percentage formats, totals, and a professional layout, then let me review it on the grid." + }, + { + "title": "Engineer robust formulas", + "prompt": "Read the focused table, add guarded SUMIFS and growth formulas using the real column layout, statically validate the references, and do not claim calculated results unless recalculation is fresh." + } + ] +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/package.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/package.json new file mode 100644 index 00000000..2abb0759 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/package.json @@ -0,0 +1,8 @@ +{ + "private": true, + "type": "commonjs", + "name": "excel-live-agent", + "scripts": { + "test": "node --test test/*.test.js" + } +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/routing.md b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/routing.md new file mode 100644 index 00000000..d588c928 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/routing.md @@ -0,0 +1,31 @@ +# Excel Live Agent Routing + +Use this Agent Component when the user wants grounded spreadsheet work they can see, point at, review, and export from the Excel Live grid. + +## Route here + +- Explain or analyze an active workbook, sheet, selection, formula pattern, style, or layout. +- Clean, transform, format, or add formulas to a real focused range. +- Create a professional workbook or new sheet with structured content, semantic visual design, robust formulas, and navigable layout. +- Review a proposal, accept/reject it on explicit request, inspect history, or undo/redo a committed change. +- Open/create workbooks and export source-safe xlsx/xlsm copies through the Excel Engine. +- Continue work tied to a workbookId, path, sheet, range, or spreadsheet focus. + +## Choose the smallest skill set + +- Data shape, addressing, workbook semantics: `spreadsheet-fundamentals`. +- Ambient selection, revisions, proposals, acceptance: `focus-and-proposals`. +- End-to-end creation or substantial new sheet: `workbook-authoring` plus the relevant visual/formula skill. +- Styling, number formats, widths, freeze panes, filter: `visual-table-design`. +- Totals, conditional aggregation, lookups, growth, error guards: `formula-engineering`. +- Trim, normalize, fill, dedupe, reshape: `data-cleaning`. + +For a narrow task, apply only the relevant guidance even if the runtime appends the whole library. Combine `workbook-authoring`, `visual-table-design`, and `formula-engineering` for a full professional workbook build. + +## Route elsewhere or disclose a boundary + +- If the user only wants an xlsx artifact and does not need a live review surface, a standalone spreadsheet workflow may be more direct. +- Do not route unrelated repository, presentation, PDF, video, or generic file-editing work here. +- Pivots, advanced chart authoring, VBA creation/execution, and formula recalculation remain unsupported unless current workbook capabilities explicitly say otherwise. +- xlsm macro preservation is an export fidelity property, not permission or ability to author or execute macros. +- When only part of the request is supported, complete the supported spreadsheet work and state the exact remaining boundary. diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/schemas/spreadsheet-focus.schema.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/schemas/spreadsheet-focus.schema.json new file mode 100644 index 00000000..badd7286 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/schemas/spreadsheet-focus.schema.json @@ -0,0 +1,119 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Spreadsheet Focus Context", + "type": "object", + "additionalProperties": true, + "required": [ + "type", + "role", + "workbookId", + "sheetId", + "sheetName", + "a1", + "selectionKind", + "rowCount", + "columnCount", + "mode", + "cacheComplete", + "capturedAt", + "previewTruncated", + "schemaVersion" + ], + "properties": { + "type": { + "type": "string", + "const": "spreadsheet-focus" + }, + "role": { + "type": "string", + "enum": ["ambient", "pinned"] + }, + "sessionId": { + "type": "string", + "minLength": 1, + "description": "The exact chat session bound to the surface that captured this focus." + }, + "workbookId": { + "type": "string" + }, + "workbookPath": { + "type": "string" + }, + "workbookTitle": { + "type": "string" + }, + "sheetId": { + "type": "string" + }, + "sheetName": { + "type": "string" + }, + "a1": { + "type": "string", + "description": "A1 address or range, optionally sheet-qualified." + }, + "selectionKind": { + "type": "string", + "enum": ["cell", "range", "row", "column", "sheet"] + }, + "rowCount": { + "type": "integer", + "minimum": 0 + }, + "columnCount": { + "type": "integer", + "minimum": 0 + }, + "mode": { + "type": "string", + "enum": ["inspect", "edit", "author"] + }, + "revision": { + "type": ["integer", "string"], + "description": "Committed workbook revision at focus capture time." + }, + "cacheCoverage": { + "type": ["number", "object"], + "description": "Coverage evidence for the selected range cache." + }, + "cacheComplete": { + "type": "boolean", + "description": "True only when every selected cell was loaded; previewTsv is authoritative only in this state." + }, + "formulaResultsFresh": { + "type": "boolean", + "description": "False means selected formula results are cached or stale and must not be treated as authoritative numbers." + }, + "calculationStatus": { + "type": "object", + "additionalProperties": true, + "description": "Engine calculation status captured with this focus." + }, + "fidelity": { + "type": "object", + "additionalProperties": true, + "description": "Live-view and source-package fidelity context." + }, + "capturedAt": { + "type": "number", + "exclusiveMinimum": 0, + "description": "Unix time in milliseconds when the focus snapshot was captured." + }, + "previewTsv": { + "type": "string", + "description": "Optional tab-separated preview, present only when cacheComplete is true and selected formula results are not stale." + }, + "previewTruncated": { + "type": "boolean" + }, + "valueSummary": { + "type": "object", + "additionalProperties": true, + "description": "Optional coarse stats such as numeric/empty/formula counts." + }, + "schemaVersion": { + "type": "integer", + "const": 1 + } + } +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/skills/data-cleaning.md b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/skills/data-cleaning.md new file mode 100644 index 00000000..839c6424 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/skills/data-cleaning.md @@ -0,0 +1,24 @@ +# Data Cleaning + +Use this skill when normalizing, deduplicating, filling, trimming, or reshaping tabular data in a focused range. + +Workflow: +1. Point: confirm sheet + A1 focus, cache completeness, and workbook revision. +2. Summarize or read the range before changing anything. +3. Describe the cleaning plan (what columns, what rules, approximate cell count). +4. Propose a patch with explicit after values or formulas, user-facing intent, and expected revision. +5. Ask the user to Accept/Reject on the grid, then optionally save. + +Common patterns: +- Trim whitespace and normalize casing in text columns. +- Coerce numeric-looking strings to numbers when the column is clearly numeric. +- Fill or flag blanks according to the user's rule; do not invent business values. +- Remove or collapse duplicate rows only when the key columns are clear. +- Split or merge columns only with an explicit target layout. +- Preserve header rows unless the user asks to rewrite them. + +Honesty rules: +- Never invent cell values for unread areas. +- Prefer scoped patches over whole-sheet rewrites. +- High-risk clears or mass deletes must be called out in proposal validation and remain undoable after acceptance. +- If cleaning needs external Excel-only features, say so and keep the patch within Excel Live capabilities. diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/skills/focus-and-proposals.md b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/skills/focus-and-proposals.md new file mode 100644 index 00000000..c87740fa --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/skills/focus-and-proposals.md @@ -0,0 +1,36 @@ +# Focus and Proposals + +Use ambient focus as the default target and proposal-based writes as the default content, formula, style, and layout mutation path. + +## Live store + +- The grid persists every accepted or local edit into a revisioned `/.sparo_os/excel-live//workbook.json` store with undo/redo history. +- That live store is the source of truth for range reads and focus. Do not call accepted changes invisible or unsaved merely because no export was created. +- `save_workbook` creates a portable copy; it never overwrites the imported source by default. + +## Point + +- Ambient focus contains sheet, A1, selection kind, workbook revision, cache coverage, and sometimes preview data. +- A mentioned A1 range explicitly overrides ambient focus. Pinned focus is useful for a fixed multi-turn target. +- Restate the target before transforming. If focus is missing, call `get_focus`; ask one short question only if it remains ambiguous. +- Use preview values only when cache coverage and revision are current. Formula results also require explicit freshness. + +## Transform + +- Content, formula, style, number-format, and layout writes go through `propose_patch` with a concise intent and exact expected revision. +- Inspect existing content, style, and layout before redesigning. Prefer semantic roles and combine related content, formulas, styling, and layout into one coherent proposal. +- Style-only and layout-only proposals are valid. Never add dummy content to carry a design change. +- Resolve an existing active proposal before creating another one. +- Structure operations are exceptional: `edit_workbook_structure` commits immediately, is history-backed, and requires explicit current intent. + +## Verify + +- Point -> Transform -> Verify is the north-star loop. +- Inspect actual bridge status and output after every tool. Only `completed` with valid output is success. +- After proposing, check proposal id, base revision, affected range, content/style/layout diff, validation, and formula lint. +- Formula lint is not recalculation. Layout changes are accepted or rejected with the proposal as a whole. +- A failed, cancelled, stale, or revision-conflicted call must be reported as failure. Refresh metadata before retrying a still-valid change. +- Tool cards summarize; the grid proposal inspector is the review surface. Ask the user to Accept or Reject there. +- Accepted changes remain reversible through workbook history. + +Export only when a portable file is requested, use the exact committed revision, and report the returned path and fidelity limits. diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/skills/formula-engineering.md b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/skills/formula-engineering.md new file mode 100644 index 00000000..90d00050 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/skills/formula-engineering.md @@ -0,0 +1,38 @@ +# Formula Engineering + +Use this skill when a workbook needs maintainable calculations, lookups, business rules, or summary metrics. + +## Engineering loop + +1. Read the actual headers, example rows, data extent, current formulas, and calculation metadata. +2. State the business definition in words before encoding it. Identify inputs, output unit, blank/error behavior, and compatibility needs. +3. Choose the simplest formula family that remains correct when rows are added or copied. +4. Write formulas through `propose_patch`, preferably with a number format and output style role in the same proposal. +5. Inspect static lint and reference findings. Spot-check first, middle, and last copied formulas. +6. Report formula authorship, lint, recalculation, and numeric verification as separate states. + +## Reliable patterns + +- Totals: `SUM` for a known contiguous measure range; avoid accidental header or total-row inclusion. +- Conditional aggregation: `SUMIFS`, `COUNTIFS`, and `AVERAGEIFS` with equally sized criteria and sum ranges. +- Lookups: `XLOOKUP` when workbook compatibility allows it; `INDEX` + `MATCH` when broader compatibility is required. Define missing-match behavior explicitly. +- Growth: guard the prior period before `(current-prior)/prior`; decide whether zero/blank should yield blank, zero, or an explicit error. +- Dates: use date functions rather than string slicing when cells contain real dates. Apply a date number format separately. +- Error handling: use `IFERROR` only for expected failure modes. Do not hide malformed inputs or broken references. +- Readability: prefer a helper column or small summary block over deeply nested repeated logic. + +## Reference discipline + +- Use relative references for row-local calculations, absolute references for fixed assumptions, and mixed references for fill-across/fill-down models. +- Quote sheet names containing spaces or punctuation. +- Never fabricate a named range, table name, or sheet name that was not read or created. +- Structure edits can invalidate references and are blocked when the engine cannot rewrite them safely. +- Avoid volatile functions such as `OFFSET`, `INDIRECT`, `NOW`, or `RAND` unless the user explicitly needs their behavior and accepts the tradeoff. + +## Truthful verification + +`formulaStaticLint=true` can support claims about supported syntax and detectable reference issues. It cannot support claims about the computed number. + +When `formulaRecalculation=false`, use language equivalent to: "The formulas were added and statically checked; Excel Live did not recalculate them, so the displayed numeric results require recalculation in Excel before they are considered verified." + +Never convert a formula to a hard-coded number merely to make a stale result look complete unless the user explicitly requests a snapshot and the computation was independently grounded. diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/skills/spreadsheet-fundamentals.md b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/skills/spreadsheet-fundamentals.md new file mode 100644 index 00000000..69d71bed --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/skills/spreadsheet-fundamentals.md @@ -0,0 +1,16 @@ +# Spreadsheet Fundamentals + +Use this skill when interpreting workbook structure, data shape, or spreadsheet semantics. + +- Address every claim with workbook, sheet, A1 range, and revision when available. +- Treat one record per row and one meaning per column as the default data model. +- Distinguish raw values, formulas, cached results, styles, number formats, headers, and genuinely empty cells. +- Formatting changes presentation, not the stored value. A raw serial does not prove date, currency, or percentage semantics. +- Preserve stable headers, units, keys, source columns, and intentional workbook conventions. +- Prefer a single rectangular data region with one clear header row. Avoid merged cells, repeated headers, and decorative blanks inside sortable data. +- Use a separate summary block or sheet when analytics would otherwise corrupt the source data shape. +- Track active sheet, dirty state, proposal state, calculation status, capability metadata, and source/export fidelity. +- Large or cache-incomplete ranges require summary/read tools. Never interpret unread cells as blanks. +- A portable result is a real source-safe XLSX/XLSM copy plus an honest fidelity report, not a chat-only table or overwritten source workbook. + +Output should name the target range and explain the spreadsheet consequence of each proposed design decision. diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/skills/visual-table-design.md b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/skills/visual-table-design.md new file mode 100644 index 00000000..f7357532 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/skills/visual-table-design.md @@ -0,0 +1,55 @@ +# Visual Table Design + +Use this skill when improving readability, hierarchy, number presentation, or navigation. + +## Design from semantics + +Inspect existing styles and layout first. Assign roles before custom colors: + +- `title`: workbook or section identity, used sparingly. +- `header`: field labels and filter row. +- `input`: editable assumptions or human-entered fields. +- `output`: calculated or decision-relevant results. +- `total`: subtotals, grand totals, and key rollups. +- `note`: instructions, provenance, caveats, or definitions. +- `warning`: true exceptions requiring attention, never ordinary emphasis. + +Use custom style overrides only to refine a coherent direction. Normally use one accent plus neutrals, quiet body cells, and a single warning treatment. Avoid rainbow categories, heavy borders around every cell, low-contrast text, and decorative blank regions. + +## Hierarchy and layout + +- Put a title/context area above a table only when it helps the audience understand purpose or period. +- Keep one unambiguous header row for the data region. Auto-filter that header and data range, not the title row. +- Freeze the minimum context needed: commonly one header row, sometimes identifier columns. +- Auto-fit unpredictable content, then use deliberate widths for IDs, dates, measures, and narrative text. Layout start/end indices are 0-based and inclusive; column widths use Excel character units and row heights use points, never pixels. +- Wrap long notes and narrative columns deliberately. Avoid wrapping compact numbers and IDs. +- Align text left and numbers right by default. Use centered alignment sparingly for short categorical headers/statuses. +- Avoid merged cells inside data regions because they obstruct sorting, filtering, and formula fill. + +## Number formats + +Formatting changes presentation, not values: + +- currency: choose symbol and decimal precision appropriate to the audience; +- percentage: store ratios as numeric values and apply a percent format; +- date: use a real date value when known, then a consistent date format; +- counts: normally use grouped whole numbers; +- measures: use consistent precision within a column; +- negatives: choose a consistent minus or accounting convention rather than mixing forms. + +Do not infer currency, percentage, or date semantics from a raw number alone. Read headers and supporting metadata. + +## Proposal composition + +For a coherent makeover, use one `propose_patch` with operations that combine: + +1. required content/formulas; +2. semantic roles; +3. sparse custom overrides; +4. number formats; +5. widths/heights or auto-fit; +6. freeze panes and auto-filter. + +Style-only and layout-only proposals are valid. Review the whole visual diff on the grid. Layout is accepted or rejected with the proposal as a whole. + +Clearing is explicit: `style: null` clears a cell's full style; nested nulls remove individual style properties; `columns: []` and `rows: []` clear custom bands; freeze counts of 0 clear frozen panes; `autoFilter: null` clears the filter. Omitted fields preserve existing design state. diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/skills/workbook-authoring.md b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/skills/workbook-authoring.md new file mode 100644 index 00000000..8e8ab150 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/skills/workbook-authoring.md @@ -0,0 +1,51 @@ +# Workbook Authoring + +Use this skill for end-to-end spreadsheet creation or a substantial new sheet. + +## Start with the decision + +Infer or ask only what materially changes the design: + +- purpose and decision supported; +- audience and expected editing behavior; +- source data and update cadence; +- required inputs, calculations, summaries, and handoff format; +- compatibility or fidelity constraints, especially for imported xlsm files. + +Do not begin with colors. Design the workbook's information architecture first. + +## Recommended architecture + +Use only the sections the task needs: + +1. title/context: purpose, period, owner, or last-updated note; +2. input/data region: one record per row, one meaning per column, stable headers; +3. calculation region: transparent helper columns or formulas; +4. summary/decision region: totals and the few measures the audience acts on; +5. notes/definitions: assumptions, units, caveats, and provenance. + +Separate raw inputs from derived outputs visually. Prefer a new sheet to destructive reshaping when source preservation matters. Sheet names should be short, unique, and meaningful. + +## Authoring sequence + +1. Inspect metadata/capabilities and existing workbook conventions. +2. Add or rename a sheet only when needed. Structure tools commit immediately, require the current revision, and remain undoable. +3. Propose the core table content, formulas, styles, formats, and layout together when the design is coherent enough for one review. +4. Inspect proposal validation and formula lint. Resolve failures instead of narrating them as success. +5. Ask for grid Accept/Reject. Read the committed result after acceptance. +6. Export a distinct source-safe xlsx/xlsm copy only when requested, and report the returned fidelity contract. + +## Quality bar + +A professional workbook is: + +- structurally clear without explanation from the author; +- easy to scan at normal zoom; +- explicit about editable inputs and calculated outputs; +- resilient to blanks, missing matches, zero denominators, and row growth where relevant; +- consistent in labels, units, formats, precision, and formula patterns; +- restrained rather than template-heavy; +- honest about calculations and export fidelity; +- reversible and reviewable in the live grid. + +Do not claim completion merely because cells were populated. Verify content, formulas, visual hierarchy, layout, proposal state, and requested export separately. diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/test/agent-authoring-contract.test.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/test/agent-authoring-contract.test.js new file mode 100644 index 00000000..f00f8953 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/test/agent-authoring-contract.test.js @@ -0,0 +1,285 @@ +const test = require("node:test"); +const assert = require("node:assert/strict"); +const fs = require("node:fs"); +const path = require("node:path"); + +const SOURCE_ROOT = path.resolve(__dirname, ".."); +const TOOLS_ROOT = path.join(SOURCE_ROOT, "tools"); + +function readJson(filePath) { + return JSON.parse(fs.readFileSync(filePath, "utf8")); +} + +function walk(root) { + return fs.readdirSync(root, { withFileTypes: true }).flatMap((entry) => { + const filePath = path.join(root, entry.name); + return entry.isDirectory() ? walk(filePath) : [filePath]; + }); +} + +test("advanced Excel Agent authoring contract", async (t) => { + await t.test("all JSON parses and manifest references real tools and skills", () => { + for (const filePath of walk(path.resolve(SOURCE_ROOT, "..")).filter((file) => file.endsWith(".json"))) { + assert.doesNotThrow(() => readJson(filePath), filePath); + } + + const manifest = readJson(path.join(SOURCE_ROOT, "manifest.json")); + const prefix = `agentcomponent__${manifest.id}__`; + const declaredTools = manifest.tools + .filter((name) => name.startsWith(prefix)) + .map((name) => name.slice(prefix.length)) + .sort(); + const toolDefinitions = fs.readdirSync(TOOLS_ROOT) + .filter((name) => name.endsWith(".tool.json")) + .map((name) => readJson(path.join(TOOLS_ROOT, name)).name) + .sort(); + assert.deepEqual(declaredTools, toolDefinitions); + for (const skill of manifest.skills) { + assert.ok(fs.existsSync(path.join(SOURCE_ROOT, "skills", `${skill}.md`)), skill); + } + }); + + await t.test("proposal schema exposes bounded content, style, formula, and layout composition", () => { + const tool = readJson(path.join(TOOLS_ROOT, "propose_patch.tool.json")); + const schema = tool.inputSchema; + assert.deepEqual(schema.anyOf.map((branch) => branch.required[0]), [ + "cells", + "values", + "layout", + "operations", + ]); + assert.equal(schema.properties.cells.maxItems, 5000); + assert.deepEqual(schema.$defs.styleRole.enum, [ + "title", + "header", + "input", + "output", + "total", + "note", + "warning", + ]); + assert.ok(schema.$defs.style.properties.numberFormat); + assert.ok(schema.$defs.style.properties.fill); + assert.ok(schema.$defs.style.properties.font); + assert.ok(schema.$defs.style.properties.border); + assert.ok(schema.$defs.style.properties.alignment); + assert.deepEqual(schema.$defs.style.type, ["object", "null"]); + assert.deepEqual(schema.$defs.style.properties.fill.type, ["object", "null"]); + assert.deepEqual(schema.$defs.style.properties.numberFormat.type, ["string", "null"]); + assert.equal(schema.$defs.borderSide.properties.style.enum.includes("none"), false); + assert.ok(schema.$defs.layout.properties.freezePanes); + assert.ok(schema.$defs.layout.properties.autoFilter); + assert.deepEqual(schema.properties.operations.items.properties.kind.enum, [ + "set_cells", + "set_values", + "set_formulas", + "apply_style", + "set_layout", + ]); + }); + + await t.test("high-level operations compile into one deep-merged atomic proposal", () => { + const { compileProposalInput } = require("../tools/propose_patch"); + const compiled = compileProposalInput({ + workbookId: "wb_1", + expectedRevision: 7, + intent: "Build a readable summary", + sheetId: "sheet_1", + operations: [ + { kind: "set_values", a1: "B2", values: [["Region", "Sales"], ["East", 1200]] }, + { kind: "set_formulas", a1: "D2", values: [["=SUM(C3:C3)"]] }, + { + kind: "apply_style", + a1: "B2:D2", + styleRole: "header", + style: { font: { bold: true, color: "FFFFFF" }, fill: { color: "1F4E78" } }, + }, + { + kind: "apply_style", + a1: "B2:D2", + style: { font: { size: 12 }, alignment: { vertical: "center" } }, + }, + { + kind: "set_layout", + layout: { + columns: [{ start: 1, end: 3, autoFit: true }], + freezePanes: { rows: 1 }, + }, + }, + { + kind: "set_layout", + layout: { + rows: [{ start: 1, height: 24 }], + freezePanes: { columns: 1 }, + autoFilter: { a1: "B2:D3" }, + }, + }, + ], + }); + + assert.equal(compiled.operations, undefined); + assert.equal(compiled.cells.length, 5); + const b2 = compiled.cells.find((cell) => cell.row === 1 && cell.col === 1); + assert.equal(b2.value, "Region"); + assert.equal(b2.styleRole, "header"); + assert.deepEqual(b2.style.font, { bold: true, color: "FFFFFF", size: 12 }); + assert.deepEqual(b2.style.fill, { color: "1F4E78" }); + assert.deepEqual(b2.style.alignment, { vertical: "center" }); + const d2 = compiled.cells.find((cell) => cell.row === 1 && cell.col === 3); + assert.equal(d2.formula, "SUM(C3:C3)"); + assert.deepEqual(compiled.layout.freezePanes, { rows: 1, columns: 1 }); + assert.deepEqual(compiled.layout.columns, [{ start: 1, end: 3, autoFit: true }]); + assert.deepEqual(compiled.layout.rows, [{ start: 1, height: 24 }]); + assert.deepEqual(compiled.layout.autoFilter, { a1: "B2:D3" }); + assert.equal(compiled.resultCellLimit, 200); + }); + + await t.test("style-only compilation is valid and bounded to the engine limit", () => { + const { compileProposalInput } = require("../tools/propose_patch"); + const compiled = compileProposalInput({ + workbookId: "wb_1", + expectedRevision: 8, + intent: "Clarify header hierarchy", + operations: [{ kind: "apply_style", a1: "A1:C1", styleRole: "header" }], + }); + assert.equal(compiled.cells.length, 3); + assert.ok(compiled.cells.every((cell) => cell.value === undefined && cell.formula === undefined)); + assert.throws( + () => compileProposalInput({ operations: [{ kind: "apply_style", a1: "A1:CZ100", styleRole: "header" }] }), + /narrow the range below 5000/, + ); + assert.equal(compileProposalInput({ + operations: [{ kind: "apply_style", a1: "'Summary View'!A1:C1", styleRole: "header" }], + }).a1, "'Summary View'!A1"); + assert.throws( + () => compileProposalInput({ operations: [ + { kind: "apply_style", a1: "Sheet1!A1", styleRole: "header" }, + { kind: "apply_style", a1: "Sheet2!A1", styleRole: "header" }, + ] }), + /multiple sheets/, + ); + assert.throws( + () => compileProposalInput({ + sheetId: "sheet_1", + operations: [{ kind: "apply_style", a1: "Sheet1!A1", styleRole: "header" }], + }), + /sheetId or a sheet-qualified/, + ); + const cleared = compileProposalInput({ + operations: [ + { kind: "apply_style", a1: "A1", styleRole: "header", style: { font: { bold: true } } }, + { kind: "apply_style", a1: "A1", style: { font: { color: null }, fill: null } }, + ], + }).cells[0]; + assert.equal(cleared.styleRole, "header"); + assert.deepEqual(cleared.style, { font: { bold: true, color: null }, fill: null }); + const fullyCleared = compileProposalInput({ + operations: [ + { kind: "apply_style", a1: "A1", styleRole: "header" }, + { kind: "apply_style", a1: "A1", style: null }, + ], + }).cells[0]; + assert.equal(fullyCleared.style, null); + assert.equal(fullyCleared.styleRole, undefined); + const directClear = compileProposalInput({ + cells: [{ row: 0, col: 0, styleRole: "header", style: null }], + }).cells[0]; + assert.equal(directClear.style, null); + assert.equal(directClear.styleRole, undefined); + const clearedLayout = compileProposalInput({ + layout: { columns: [{ start: 0, width: 12 }], rows: [{ start: 0, height: 20 }] }, + operations: [{ + kind: "set_layout", + layout: { columns: [], rows: [], freezePanes: { rows: 0, columns: 0 }, autoFilter: null }, + }], + }).layout; + assert.deepEqual(clearedLayout, { + columns: [], + rows: [], + freezePanes: { rows: 0, columns: 0 }, + autoFilter: null, + }); + }); + + await t.test("tool schemas require targets and bound range reads", () => { + const switchSchema = readJson(path.join(TOOLS_ROOT, "switch_sheet.tool.json")).inputSchema; + assert.deepEqual(switchSchema.anyOf, [ + { required: ["sheetId"] }, + { required: ["sheetName"] }, + ]); + const readSchema = readJson(path.join(TOOLS_ROOT, "read_range.tool.json")).inputSchema; + assert.equal(readSchema.properties.maxCells.maximum, 20000); + }); + + await t.test("proposal wrappers bound returned cell details", async () => { + const proposalTool = require("../tools/propose_patch"); + const getProposalTool = require("../tools/get_proposal"); + assert.equal(proposalTool.compileProposalInput({ cells: [] }).resultCellLimit, 200); + const result = await getProposalTool.run( + { workbookId: "wb_1" }, + { workspaceRoot: "D:/trusted-workspace" }, + ); + assert.equal(result.bridgeCall.input.resultCellLimit, 200); + }); + + await t.test("lossy export acknowledgement is explicit and xlsx-only", () => { + const { buildSaveInput } = require("../tools/save_workbook"); + assert.equal(buildSaveInput({ path: "exports/book.xlsx" }).acknowledgeFidelityLoss, false); + assert.equal(buildSaveInput({ + path: "exports/book-lossy.xlsx", + acknowledgeFidelityLoss: true, + }).acknowledgeFidelityLoss, true); + assert.throws( + () => buildSaveInput({ path: "exports/book.xlsm", acknowledgeFidelityLoss: true }), + /distinct \.xlsx/, + ); + }); + + await t.test("structure wrapper translates human indices and keeps one explicit action", () => { + const { buildStructureCall } = require("../tools/edit_workbook_structure"); + assert.deepEqual(buildStructureCall({ + workbookId: "wb_1", + expectedRevision: 9, + intent: "Make room for assumptions", + operation: "insert_rows", + sheetId: "sheet_1", + index: 3, + count: 2, + }).payload, { + workbookId: "wb_1", + expectedRevision: 9, + intent: "Make room for assumptions", + sheetId: "sheet_1", + at: 2, + count: 2, + }); + assert.equal(buildStructureCall({ + workbookId: "wb_1", + expectedRevision: 10, + intent: "Add a review sheet", + operation: "add_sheet", + name: "Summary", + columns: 12, + }).action, "addSheet"); + }); + + await t.test("system prompt preserves critical truth and quality boundaries", () => { + const prompt = fs.readFileSync(path.join(SOURCE_ROOT, "agent.md"), "utf8"); + for (const statement of [ + "Point -> Transform -> Verify", + "formulaStaticLint", + "formulaRecalculation", + "styleSourcePatch", + "layoutSourcePatch", + "REVISION_CONFLICT", + "Success requires bridge status `completed`", + "Never call Bash, Memory, Write, Edit, ComputerUse", + "xlsm", + "acknowledgeFidelityLoss", + "columns: []", + ]) { + assert.ok(prompt.includes(statement), statement); + } + assert.equal(prompt.includes("\u922b"), false); + }); +}); diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/accept_proposal.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/accept_proposal.js new file mode 100644 index 00000000..a589e860 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/accept_proposal.js @@ -0,0 +1,12 @@ +const { callExcelEngine } = require("./excel_bridge"); + +async function run(input, context) { + return callExcelEngine( + "acceptProposal", + input, + context, + "Accepted the active spreadsheet proposal into committed cells.", + ); +} + +module.exports = { run }; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/accept_proposal.tool.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/accept_proposal.tool.json new file mode 100644 index 00000000..3a7c6640 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/accept_proposal.tool.json @@ -0,0 +1,94 @@ +{ + "name": "accept_proposal", + "description": "Apply all or a reviewed subset of the active proposal to committed cells. Unaccepted cells remain as a rebased proposal. Call this only when the user explicitly asks you to Accept from chat.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "required": [ + "workbookId", + "proposalId", + "expectedRevision" + ], + "properties": { + "workbookId": { + "type": "string" + }, + "proposalId": { + "type": "string", + "description": "Active proposal id shown by get_proposal or the grid." + }, + "expectedRevision": { + "type": "integer", + "minimum": 0, + "description": "Current workbook revision that was reviewed with the proposal." + }, + "cellRefs": { + "type": "array", + "description": "Optional reviewed subset to accept, expressed as A1 refs. Omit to accept the entire proposal.", + "items": { "type": "string" }, + "minItems": 1, + "uniqueItems": true + } + } + }, + "runtime": "javascript", + "entry": "tools/accept_proposal.js", + "readonly": false, + "permissions": {}, + "timeoutMs": 30000, + "maxOutputBytes": 60000, + "ui": { + "card": { + "kind": "appDefined", + "family": "excel-live", + "template": "compact", + "displayMode": "compact", + "resultDisplayType": "detailed", + "primaryColor": "var(--ds-tool-family-agent-component-fg)", + "displayName": "Accept Proposal", + "icon": "Check", + "title": "Accept Proposal", + "summary": { + "preparing": "Preparing accept", + "running": "Accepting proposal", + "completed": "Proposal accepted on the grid", + "failed": "Accept failed" + }, + "fields": [ + { + "label": "Workbook", + "inputPath": [ + "workbookId" + ] + }, + { + "label": "Proposal", + "inputPath": [ + "proposalId" + ] + }, + { + "label": "Revision", + "inputPath": [ + "expectedRevision" + ] + }, + { + "label": "Status", + "resultPath": [ + "bridge", + "status" + ] + }, + { + "label": "Output", + "resultPath": [ + "bridge", + "output" + ], + "format": "json" + } + ] + } + } +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/create_workbook.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/create_workbook.js new file mode 100644 index 00000000..722b3c5c --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/create_workbook.js @@ -0,0 +1,12 @@ +const { callExcelEngine } = require("./excel_bridge"); + +async function run(input, context) { + return callExcelEngine( + "createWorkbook", + input, + context, + "Created an empty workbook session.", + ); +} + +module.exports = { run }; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/create_workbook.tool.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/create_workbook.tool.json new file mode 100644 index 00000000..b151e91c --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/create_workbook.tool.json @@ -0,0 +1,66 @@ +{ + "name": "create_workbook", + "description": "Create an empty workbook (default 50x26 sheet) and persist its Excel Live store.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "title": { + "type": "string" + }, + "rows": { + "type": "integer", + "minimum": 1 + }, + "cols": { + "type": "integer", + "minimum": 1 + }, + "sheetName": { + "type": "string" + } + } + }, + "runtime": "javascript", + "entry": "tools/create_workbook.js", + "readonly": false, + "permissions": {}, + "timeoutMs": 30000, + "maxOutputBytes": 60000, + "ui": { + "card": { + "kind": "appDefined", + "family": "excel-live", + "template": "compact", + "displayMode": "compact", + "resultDisplayType": "detailed", + "primaryColor": "var(--ds-tool-family-agent-component-fg)", + "displayName": "Create Workbook", + "icon": "FilePlus", + "title": "Create Workbook", + "summary": { + "preparing": "Creating workbook", + "running": "Creating workbook", + "completed": "Workbook created", + "failed": "Create failed" + }, + "fields": [ + { + "label": "Title", + "inputPath": [ + "title" + ] + }, + { + "label": "Meta", + "resultPath": [ + "bridge", + "output", + "meta" + ], + "format": "json" + } + ] + } + } +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/edit_workbook_structure.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/edit_workbook_structure.js new file mode 100644 index 00000000..e6f64855 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/edit_workbook_structure.js @@ -0,0 +1,79 @@ +const { callExcelEngine } = require("./excel_bridge"); + +function buildStructureCall(input = {}) { + const common = { + workbookId: input.workbookId, + expectedRevision: input.expectedRevision, + intent: input.intent, + }; + if (input.sheetId) common.sheetId = input.sheetId; + + switch (input.operation) { + case "add_sheet": + return { + action: "addSheet", + payload: { + ...common, + ...(input.name ? { name: input.name } : {}), + ...(input.rows != null ? { rows: input.rows } : {}), + ...(input.columns != null ? { cols: input.columns } : {}), + ...(input.activate != null ? { activate: input.activate } : {}), + }, + summary: "Added a revisioned worksheet. This structural change is committed immediately and remains undoable.", + }; + case "rename_sheet": + if (!input.name) throw new Error("rename_sheet requires name"); + return { + action: "renameSheet", + payload: { ...common, name: input.name }, + summary: "Renamed a worksheet as a revisioned, undoable structural change.", + }; + case "insert_rows": + case "insert_columns": + case "delete_rows": + case "delete_columns": { + if (!Number.isInteger(input.index) || input.index < 1) { + throw new Error(`${input.operation} requires a 1-based index`); + } + const actions = { + insert_rows: "insertRows", + insert_columns: "insertColumns", + delete_rows: "deleteRows", + delete_columns: "deleteColumns", + }; + return { + action: actions[input.operation], + payload: { + ...common, + at: input.index - 1, + count: input.count == null ? 1 : input.count, + }, + summary: "Applied a revisioned, undoable worksheet structure change. Formula-bearing workbooks are rejected when references cannot be rewritten safely.", + }; + } + default: + throw new Error(`Unsupported workbook structure operation: ${input.operation || "missing operation"}`); + } +} + +async function run(input, context) { + const call = buildStructureCall(input); + switch (call.action) { + case "addSheet": + return callExcelEngine("addSheet", call.payload, context, call.summary); + case "renameSheet": + return callExcelEngine("renameSheet", call.payload, context, call.summary); + case "insertRows": + return callExcelEngine("insertRows", call.payload, context, call.summary); + case "insertColumns": + return callExcelEngine("insertColumns", call.payload, context, call.summary); + case "deleteRows": + return callExcelEngine("deleteRows", call.payload, context, call.summary); + case "deleteColumns": + return callExcelEngine("deleteColumns", call.payload, context, call.summary); + default: + throw new Error(`Unsupported Excel Engine structure action: ${call.action}`); + } +} + +module.exports = { run, buildStructureCall }; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/edit_workbook_structure.tool.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/edit_workbook_structure.tool.json new file mode 100644 index 00000000..3e0c7b38 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/edit_workbook_structure.tool.json @@ -0,0 +1,102 @@ +{ + "name": "edit_workbook_structure", + "description": "Perform one explicit worksheet structure change: add or rename a sheet, or insert/delete rows or columns. Unlike propose_patch, this commits immediately as a revisioned undoable operation and may be blocked when formulas make reference rewriting unsafe.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "required": ["workbookId", "expectedRevision", "intent", "operation"], + "properties": { + "workbookId": { "type": "string" }, + "expectedRevision": { + "type": "integer", + "minimum": 0, + "description": "Exact current workbook revision. Refresh after each structure operation." + }, + "intent": { + "type": "string", + "minLength": 1, + "maxLength": 500, + "description": "Why this immediate structural mutation is necessary." + }, + "operation": { + "type": "string", + "enum": [ + "add_sheet", + "rename_sheet", + "insert_rows", + "insert_columns", + "delete_rows", + "delete_columns" + ] + }, + "sheetId": { + "type": "string", + "description": "Target sheet for rename/insert/delete; defaults to the active sheet." + }, + "name": { + "type": "string", + "maxLength": 31, + "description": "New sheet name for add_sheet or rename_sheet. Required for rename_sheet." + }, + "rows": { + "type": "integer", + "minimum": 1, + "maximum": 1048576, + "description": "Initial row capacity for add_sheet." + }, + "columns": { + "type": "integer", + "minimum": 1, + "maximum": 16384, + "description": "Initial column capacity for add_sheet." + }, + "activate": { + "type": "boolean", + "description": "Whether a newly added sheet becomes active. Defaults to true." + }, + "index": { + "type": "integer", + "minimum": 1, + "description": "Human-facing 1-based row number or column number where insert/delete starts (A=1, B=2). Required for insert/delete." + }, + "count": { + "type": "integer", + "minimum": 1, + "description": "Number of rows or columns to insert/delete. Defaults to 1." + } + } + }, + "runtime": "javascript", + "entry": "tools/edit_workbook_structure.js", + "readonly": false, + "permissions": {}, + "timeoutMs": 60000, + "maxOutputBytes": 200000, + "ui": { + "card": { + "kind": "appDefined", + "family": "excel-live", + "template": "compact", + "displayMode": "compact", + "resultDisplayType": "detailed", + "primaryColor": "var(--ds-tool-family-agent-component-fg)", + "displayName": "Edit Workbook Structure", + "icon": "TableProperties", + "title": "Edit Workbook Structure", + "summary": { + "preparing": "Preparing structure change", + "running": "Applying {{input.operation}}", + "completed": "Structure change committed", + "failed": "Structure change failed" + }, + "fields": [ + { "label": "Operation", "inputPath": ["operation"] }, + { "label": "Sheet", "inputPath": ["sheetId"] }, + { "label": "Revision", "inputPath": ["expectedRevision"] }, + { "label": "Intent", "inputPath": ["intent"] }, + { "label": "Status", "resultPath": ["bridge", "status"] }, + { "label": "Output", "resultPath": ["bridge", "output"], "format": "json" } + ] + } + } +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/excel_bridge.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/excel_bridge.js new file mode 100644 index 00000000..a155f2ef --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/excel_bridge.js @@ -0,0 +1,88 @@ +const BRIDGE_ID = "builtin-excel-runtime"; +const CAPABILITY_ID = "sparo.excelEngine"; + +function normalizeWorkspaceRelativePath(value) { + if (typeof value !== "string" || !value.trim() || value.includes("\0")) { + throw new Error("Excel Agent file paths must be non-empty workspace-relative paths"); + } + const normalized = value.trim().replaceAll("\\", "/"); + if ( + normalized.startsWith("/") || + /^[A-Za-z]:/.test(normalized) || + normalized.split("/").some((segment) => segment === "..") + ) { + throw new Error( + "Excel Agent file paths must stay inside the active workspace; absolute paths and parent traversal are not allowed" + ); + } + return normalized; +} + +function normalizeInput(input = {}, context = {}) { + const payload = { ...input }; + // The model must never choose or override the storage root. Bind every + // Excel operation to the workspace supplied by the trusted tool runtime. + delete payload.workspacePath; + delete payload.workspace_path; + if (!context.workspaceRoot || typeof context.workspaceRoot !== "string") { + throw new Error("Excel Live requires a host-bound workspace root"); + } + payload.workspacePath = context.workspaceRoot; + if (payload.path != null) { + payload.path = normalizeWorkspaceRelativePath(payload.path); + } + if (!payload.workbookId && payload.workbook_id) { + payload.workbookId = payload.workbook_id; + delete payload.workbook_id; + } + if (!payload.sheetId && payload.sheet_id) { + payload.sheetId = payload.sheet_id; + delete payload.sheet_id; + } + if (!payload.sheetName && payload.sheet_name) { + payload.sheetName = payload.sheet_name; + delete payload.sheet_name; + } + if (!payload.proposalId && payload.proposal_id) { + payload.proposalId = payload.proposal_id; + delete payload.proposal_id; + } + if (payload.expectedRevision == null && payload.expected_revision != null) { + payload.expectedRevision = payload.expected_revision; + delete payload.expected_revision; + } + if (!payload.cellRefs && Array.isArray(payload.cell_refs)) { + payload.cellRefs = payload.cell_refs; + delete payload.cell_refs; + } + if (!payload.maxCells && payload.max_cells != null) { + payload.maxCells = payload.max_cells; + delete payload.max_cells; + } + if (payload.range && !payload.a1) { + payload.a1 = payload.range; + delete payload.range; + } + return payload; +} + +function callExcelEngine(action, input, context, summary) { + return { + summary, + bridgeCall: { + bridgeId: BRIDGE_ID, + capabilityId: CAPABILITY_ID, + action, + // Live grid edits already persist under + // /.sparo_os/excel-live//workbook.json. + // Always pass workbookId from spreadsheet-focus when available. + input: normalizeInput(input, context), + }, + }; +} + +module.exports = { + callExcelEngine, + normalizeInput, + normalizeWorkspaceRelativePath, +}; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_focus.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_focus.js new file mode 100644 index 00000000..3d114da4 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_focus.js @@ -0,0 +1,12 @@ +const { callExcelEngine } = require("./excel_bridge"); + +async function run(input, context) { + return callExcelEngine( + "getFocus", + input, + context, + "Fetched the current ambient spreadsheet focus.", + ); +} + +module.exports = { run }; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_focus.tool.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_focus.tool.json new file mode 100644 index 00000000..0331666e --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_focus.tool.json @@ -0,0 +1,58 @@ +{ + "name": "get_focus", + "description": "Return the current ambient focus (sheet, A1, kind) for the open workbook session.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "required": [ + "workbookId" + ], + "properties": { + "workbookId": { + "type": "string" + } + } + }, + "runtime": "javascript", + "entry": "tools/get_focus.js", + "readonly": true, + "permissions": {}, + "timeoutMs": 30000, + "maxOutputBytes": 20000, + "ui": { + "card": { + "kind": "appDefined", + "family": "excel-live", + "template": "compact", + "displayMode": "compact", + "resultDisplayType": "detailed", + "primaryColor": "var(--ds-tool-family-agent-component-fg)", + "displayName": "Get Focus", + "icon": "Crosshair", + "title": "Get Focus", + "summary": { + "preparing": "Reading focus", + "running": "Fetching ambient focus", + "completed": "Focus loaded", + "failed": "Focus lookup failed" + }, + "fields": [ + { + "label": "Workbook", + "inputPath": [ + "workbookId" + ] + }, + { + "label": "Focus", + "resultPath": [ + "bridge", + "output", + "focus" + ], + "format": "json" + } + ] + } + } +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_history.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_history.js new file mode 100644 index 00000000..4ab045f2 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_history.js @@ -0,0 +1,12 @@ +const { callExcelEngine } = require("./excel_bridge"); + +async function run(input, context) { + return callExcelEngine( + "getHistory", + input, + context, + "Read compact workbook revision and undo/redo history.", + ); +} + +module.exports = { run }; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_history.tool.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_history.tool.json new file mode 100644 index 00000000..604ce1e7 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_history.tool.json @@ -0,0 +1,37 @@ +{ + "name": "get_history", + "description": "Return compact Excel Live revision and undo/redo history without exposing workbook cell payloads.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "required": ["workbookId"], + "properties": { + "workbookId": { "type": "string" }, + "limit": { "type": "integer", "minimum": 1, "maximum": 50 } + } + }, + "runtime": "javascript", + "entry": "tools/get_history.js", + "readonly": true, + "permissions": {}, + "timeoutMs": 30000, + "maxOutputBytes": 80000, + "ui": { + "card": { + "kind": "appDefined", + "family": "excel-live", + "template": "compact", + "displayMode": "compact", + "resultDisplayType": "detailed", + "displayName": "Workbook History", + "icon": "History", + "title": "Workbook History", + "summary": { + "preparing": "Loading workbook history", + "running": "Reading workbook history", + "completed": "Workbook history loaded", + "failed": "History lookup failed" + } + } + } +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_proposal.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_proposal.js new file mode 100644 index 00000000..370b6bf3 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_proposal.js @@ -0,0 +1,12 @@ +const { callExcelEngine } = require("./excel_bridge"); + +async function run(input, context) { + return callExcelEngine( + "getProposal", + { ...input, resultCellLimit: 200 }, + context, + "Fetched the active spreadsheet proposal.", + ); +} + +module.exports = { run }; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_proposal.tool.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_proposal.tool.json new file mode 100644 index 00000000..45d2a42f --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_proposal.tool.json @@ -0,0 +1,57 @@ +{ + "name": "get_proposal", + "description": "Return the active proposal diff for the workbook, if any.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "required": [ + "workbookId" + ], + "properties": { + "workbookId": { + "type": "string" + } + } + }, + "runtime": "javascript", + "entry": "tools/get_proposal.js", + "readonly": true, + "permissions": {}, + "timeoutMs": 30000, + "maxOutputBytes": 200000, + "ui": { + "card": { + "kind": "appDefined", + "family": "excel-live", + "template": "compact", + "displayMode": "compact", + "resultDisplayType": "detailed", + "primaryColor": "var(--ds-tool-family-agent-component-fg)", + "displayName": "Get Proposal", + "icon": "Eye", + "title": "Get Proposal", + "summary": { + "preparing": "Loading proposal", + "running": "Fetching active proposal", + "completed": "Proposal loaded", + "failed": "Proposal lookup failed" + }, + "fields": [ + { + "label": "Workbook", + "inputPath": [ + "workbookId" + ] + }, + { + "label": "Output", + "resultPath": [ + "bridge", + "output" + ], + "format": "json" + } + ] + } + } +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_workbook_meta.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_workbook_meta.js new file mode 100644 index 00000000..67b63c27 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_workbook_meta.js @@ -0,0 +1,12 @@ +const { callExcelEngine } = require("./excel_bridge"); + +async function run(input, context) { + return callExcelEngine( + "getMeta", + input, + context, + "Fetched workbook metadata from the Excel Engine.", + ); +} + +module.exports = { run }; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_workbook_meta.tool.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_workbook_meta.tool.json new file mode 100644 index 00000000..cea15a0a --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/get_workbook_meta.tool.json @@ -0,0 +1,58 @@ +{ + "name": "get_workbook_meta", + "description": "Return workbook runtime truth: revision, mode, sheets, focus, proposal/history state, calculation status, source/export fidelity, and capability flags for formulas, styles, number formats, layout, and structural edits. Inspect this before non-trivial authoring.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "required": [ + "workbookId" + ], + "properties": { + "workbookId": { + "type": "string" + } + } + }, + "runtime": "javascript", + "entry": "tools/get_workbook_meta.js", + "readonly": true, + "permissions": {}, + "timeoutMs": 30000, + "maxOutputBytes": 60000, + "ui": { + "card": { + "kind": "appDefined", + "family": "excel-live", + "template": "compact", + "displayMode": "compact", + "resultDisplayType": "detailed", + "primaryColor": "var(--ds-tool-family-agent-component-fg)", + "displayName": "Workbook Meta", + "icon": "Info", + "title": "Workbook Meta", + "summary": { + "preparing": "Loading meta", + "running": "Fetching workbook meta", + "completed": "Meta loaded", + "failed": "Meta lookup failed" + }, + "fields": [ + { + "label": "Workbook", + "inputPath": [ + "workbookId" + ] + }, + { + "label": "Meta", + "resultPath": [ + "bridge", + "output", + "meta" + ], + "format": "json" + } + ] + } + } +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/list_sheets.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/list_sheets.js new file mode 100644 index 00000000..c36b6a58 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/list_sheets.js @@ -0,0 +1,12 @@ +const { callExcelEngine } = require("./excel_bridge"); + +async function run(input, context) { + return callExcelEngine( + "listSheets", + input, + context, + "Listed workbook sheets.", + ); +} + +module.exports = { run }; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/list_sheets.tool.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/list_sheets.tool.json new file mode 100644 index 00000000..45b6efcc --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/list_sheets.tool.json @@ -0,0 +1,58 @@ +{ + "name": "list_sheets", + "description": "List sheets in the open workbook, including active sheet id and basic dimensions.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "required": [ + "workbookId" + ], + "properties": { + "workbookId": { + "type": "string" + } + } + }, + "runtime": "javascript", + "entry": "tools/list_sheets.js", + "readonly": true, + "permissions": {}, + "timeoutMs": 30000, + "maxOutputBytes": 60000, + "ui": { + "card": { + "kind": "appDefined", + "family": "excel-live", + "template": "compact", + "displayMode": "compact", + "resultDisplayType": "detailed", + "primaryColor": "var(--ds-tool-family-agent-component-fg)", + "displayName": "List Sheets", + "icon": "Layers", + "title": "List Sheets", + "summary": { + "preparing": "Listing sheets", + "running": "Listing sheets", + "completed": "Sheets listed", + "failed": "List failed" + }, + "fields": [ + { + "label": "Workbook", + "inputPath": [ + "workbookId" + ] + }, + { + "label": "Sheets", + "resultPath": [ + "bridge", + "output", + "sheets" + ], + "format": "json" + } + ] + } + } +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/open_workbook.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/open_workbook.js new file mode 100644 index 00000000..f2bdf285 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/open_workbook.js @@ -0,0 +1,12 @@ +const { callExcelEngine } = require("./excel_bridge"); + +async function run(input, context) { + return callExcelEngine( + "openWorkbook", + input, + context, + "Opened the workbook into an Excel Live session.", + ); +} + +module.exports = { run }; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/open_workbook.tool.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/open_workbook.tool.json new file mode 100644 index 00000000..2dc99259 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/open_workbook.tool.json @@ -0,0 +1,67 @@ +{ + "name": "open_workbook", + "description": "Open a CSV, XLSX, or Sparo workbook JSON file into an in-memory Excel Live session and persist the store under .sparo_os/excel-live.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "required": [ + "path" + ], + "properties": { + "path": { + "type": "string", + "pattern": "^(?![A-Za-z]:)(?![/\\\\])(?!.*(?:^|[/\\\\])\\.\\.(?:[/\\\\]|$)).+\\.(?:xlsx|xlsm|csv)$", + "description": "Workbook file path relative to the active workspace. Absolute paths and parent traversal are not allowed." + }, + "title": { + "type": "string" + }, + "workbookId": { + "type": "string", + "description": "Optional workbook id to reuse." + } + } + }, + "runtime": "javascript", + "entry": "tools/open_workbook.js", + "readonly": false, + "permissions": {}, + "timeoutMs": 60000, + "maxOutputBytes": 120000, + "ui": { + "card": { + "kind": "appDefined", + "family": "excel-live", + "template": "compact", + "displayMode": "compact", + "resultDisplayType": "detailed", + "primaryColor": "var(--ds-tool-family-agent-component-fg)", + "displayName": "Open Workbook", + "icon": "FolderOpen", + "title": "Open Workbook", + "summary": { + "preparing": "Opening workbook", + "running": "Opening {{input.path}}", + "completed": "Workbook opened", + "failed": "Open failed" + }, + "fields": [ + { + "label": "Path", + "inputPath": [ + "path" + ] + }, + { + "label": "Meta", + "resultPath": [ + "bridge", + "output", + "meta" + ], + "format": "json" + } + ] + } + } +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/propose_patch.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/propose_patch.js new file mode 100644 index 00000000..d3312e3f --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/propose_patch.js @@ -0,0 +1,261 @@ +const { callExcelEngine } = require("./excel_bridge"); + +const MAX_COMPILED_CELLS = 5000; +const RESULT_CELL_LIMIT = 200; + +function columnToIndex(label) { + let result = 0; + for (const char of label.toUpperCase()) { + result = result * 26 + char.charCodeAt(0) - 64; + } + return result - 1; +} + +function parseA1Range(value) { + if (typeof value !== "string" || !value.trim()) { + throw new Error("A1 range is required for this proposal operation"); + } + const unqualified = value.trim().split("!").pop().replaceAll("$", ""); + const match = unqualified.match(/^([A-Za-z]+)([1-9]\d*)(?::([A-Za-z]+)([1-9]\d*))?$/); + if (!match) { + throw new Error(`Unsupported A1 range: ${value}`); + } + const r1 = Number(match[2]) - 1; + const c1 = columnToIndex(match[1]); + const r2 = match[4] ? Number(match[4]) - 1 : r1; + const c2 = match[3] ? columnToIndex(match[3]) : c1; + if (r2 < r1 || c2 < c1) { + throw new Error(`A1 range must run from top-left to bottom-right: ${value}`); + } + return { r1, c1, r2, c2 }; +} + +function sheetQualifier(value) { + if (typeof value !== "string") return null; + const separator = value.lastIndexOf("!"); + return separator > 0 ? value.slice(0, separator) : null; +} + +function matrixCells(a1, values, formulaOnly = false) { + const { r1, c1 } = parseA1Range(a1); + const cells = []; + for (let rowOffset = 0; rowOffset < values.length; rowOffset += 1) { + const row = values[rowOffset]; + if (!Array.isArray(row)) { + throw new Error("Each values row must be an array"); + } + for (let colOffset = 0; colOffset < row.length; colOffset += 1) { + const raw = row[colOffset]; + const cell = { row: r1 + rowOffset, col: c1 + colOffset }; + if (formulaOnly) { + if (typeof raw !== "string" || !raw.trim()) { + throw new Error("set_formulas values must be non-empty formula strings"); + } + cell.formula = raw.trim().replace(/^=/, ""); + } else if (typeof raw === "string" && raw.trim().startsWith("=")) { + cell.formula = raw.trim().slice(1); + } else { + cell.value = raw; + } + cells.push(cell); + } + } + return cells; +} + +function styleCells(a1, styleRole, style) { + const range = parseA1Range(a1); + const count = (range.r2 - range.r1 + 1) * (range.c2 - range.c1 + 1); + if (count > MAX_COMPILED_CELLS) { + throw new Error( + `apply_style expands to ${count} cells; narrow the range below ${MAX_COMPILED_CELLS}`, + ); + } + const cells = []; + for (let row = range.r1; row <= range.r2; row += 1) { + for (let col = range.c1; col <= range.c2; col += 1) { + cells.push({ + row, + col, + ...(styleRole ? { styleRole } : {}), + ...(style !== undefined ? { style } : {}), + }); + } + } + return cells; +} + +function deepMerge(base, addition) { + if ( + base && + addition && + typeof base === "object" && + typeof addition === "object" && + !Array.isArray(base) && + !Array.isArray(addition) + ) { + const result = { ...base }; + for (const [key, value] of Object.entries(addition)) { + result[key] = key in result ? deepMerge(result[key], value) : value; + } + return result; + } + return addition; +} + +function mergeLayout(base = {}, addition = {}) { + const additionHasColumns = Object.prototype.hasOwnProperty.call(addition || {}, "columns"); + const additionHasRows = Object.prototype.hasOwnProperty.call(addition || {}, "rows"); + const merged = { + ...deepMerge(base || {}, addition || {}), + columns: additionHasColumns && addition.columns.length === 0 + ? [] + : [...(base?.columns || []), ...(addition?.columns || [])], + rows: additionHasRows && addition.rows.length === 0 + ? [] + : [...(base?.rows || []), ...(addition?.rows || [])], + }; + if (!merged.columns.length && !(additionHasColumns || Object.prototype.hasOwnProperty.call(base || {}, "columns"))) { + delete merged.columns; + } + if (!merged.rows.length && !(additionHasRows || Object.prototype.hasOwnProperty.call(base || {}, "rows"))) { + delete merged.rows; + } + return merged; +} + +function mergeCells(cells) { + const merged = new Map(); + for (const cell of cells) { + if (!Number.isInteger(cell?.row) || !Number.isInteger(cell?.col)) { + throw new Error("Compiled proposal cells require integer row and col coordinates"); + } + const key = `${cell.row}:${cell.col}`; + const prior = merged.get(key) || { row: cell.row, col: cell.col }; + const next = { + ...prior, + ...cell, + ...(Object.prototype.hasOwnProperty.call(prior, "style") || Object.prototype.hasOwnProperty.call(cell, "style") + ? { + style: Object.prototype.hasOwnProperty.call(cell, "style") + ? deepMerge(prior.style || {}, cell.style) + : prior.style, + } + : {}), + }; + if (Object.prototype.hasOwnProperty.call(cell, "style") && cell.style === null) { + delete next.styleRole; + } + merged.set(key, next); + } + if (merged.size > MAX_COMPILED_CELLS) { + throw new Error(`Proposal exceeds the maximum of ${MAX_COMPILED_CELLS} compiled cells`); + } + return [...merged.values()]; +} + +function normalizeExplicitStyleClears(cells) { + return cells.map((cell) => { + if (!cell || cell.style !== null) return cell; + const normalized = { ...cell }; + delete normalized.styleRole; + return normalized; + }); +} + +function compileProposalInput(input = {}) { + if (!Array.isArray(input.operations) || input.operations.length === 0) { + return { + ...input, + ...(Array.isArray(input.cells) ? { cells: normalizeExplicitStyleClears(input.cells) } : {}), + resultCellLimit: RESULT_CELL_LIMIT, + }; + } + + const payload = { ...input }; + delete payload.operations; + payload.resultCellLimit = RESULT_CELL_LIMIT; + const cells = [...(Array.isArray(input.cells) ? input.cells : [])]; + let operationSheet = null; + if (Array.isArray(input.values)) { + cells.push(...matrixCells(input.a1 || "A1", input.values)); + delete payload.values; + } + let layout = input.layout || {}; + + for (const operation of input.operations) { + const qualifier = sheetQualifier(operation?.a1); + if (qualifier && input.sheetId) { + throw new Error("Use sheetId or a sheet-qualified operation A1, not both"); + } + if (qualifier && operationSheet && qualifier !== operationSheet) { + throw new Error("One proposal cannot target operations on multiple sheets"); + } + if (qualifier) operationSheet = qualifier; + switch (operation?.kind) { + case "set_cells": + if (!Array.isArray(operation.cells) || operation.cells.length === 0) { + throw new Error("set_cells requires a non-empty cells array"); + } + cells.push(...operation.cells); + break; + case "set_values": + if (!Array.isArray(operation.values)) { + throw new Error("set_values requires values[][]"); + } + cells.push(...matrixCells(operation.a1, operation.values)); + break; + case "set_formulas": + if (!Array.isArray(operation.values)) { + throw new Error("set_formulas requires values[][]"); + } + cells.push(...matrixCells(operation.a1, operation.values, true)); + break; + case "apply_style": + if (!operation.styleRole && !Object.prototype.hasOwnProperty.call(operation, "style")) { + throw new Error("apply_style requires styleRole and/or style"); + } + cells.push(...styleCells(operation.a1, operation.styleRole, operation.style)); + break; + case "set_layout": + if (!operation.layout || typeof operation.layout !== "object") { + throw new Error("set_layout requires layout"); + } + layout = mergeLayout(layout, operation.layout); + break; + default: + throw new Error(`Unsupported proposal operation: ${operation?.kind || "missing kind"}`); + } + } + + if (operationSheet && !input.sheetId) { + const inputSheet = sheetQualifier(input.a1); + if (inputSheet && inputSheet !== operationSheet) { + throw new Error("Root patch and proposal operations must target the same sheet"); + } + if (!inputSheet) payload.a1 = `${operationSheet}!${input.a1 || "A1"}`; + } + if (cells.length) payload.cells = mergeCells(cells); + if (Object.keys(layout).length) payload.layout = layout; + return payload; +} + +async function run(input, context) { + return callExcelEngine( + "proposePatch", + compileProposalInput(input), + context, + "Proposed workbook content, formula, style, or layout changes for grid review. Not applied until Accept.", + ); +} + +module.exports = { + run, + compileProposalInput, + deepMerge, + matrixCells, + parseA1Range, + sheetQualifier, + normalizeExplicitStyleClears, + RESULT_CELL_LIMIT, +}; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/propose_patch.tool.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/propose_patch.tool.json new file mode 100644 index 00000000..4290b7cc --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/propose_patch.tool.json @@ -0,0 +1,328 @@ +{ + "name": "propose_patch", + "description": "Create one revision-bound proposal containing values, formulas, cell styles, semantic style roles, and sheet layout. Nothing is committed until the proposal is accepted on the grid.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "required": [ + "workbookId", + "expectedRevision", + "intent" + ], + "anyOf": [ + { "required": ["cells"] }, + { "required": ["values"] }, + { "required": ["layout"] }, + { "required": ["operations"] } + ], + "properties": { + "workbookId": { + "type": "string" + }, + "expectedRevision": { + "type": "integer", + "minimum": 0, + "description": "Exact revision returned by the current focus or workbook metadata. Refresh after every mutation or revision conflict." + }, + "intent": { + "type": "string", + "minLength": 1, + "maxLength": 500, + "description": "Concise user-facing reason, design intent, and expected outcome." + }, + "designIntent": { + "type": "object", + "additionalProperties": false, + "description": "Optional creative brief used to keep a multi-part spreadsheet design coherent.", + "properties": { + "purpose": { "type": "string", "maxLength": 200 }, + "audience": { "type": "string", "maxLength": 200 }, + "tone": { "type": "string", "maxLength": 120 } + } + }, + "sheetId": { + "type": "string" + }, + "a1": { + "type": "string", + "description": "Anchor for values[][] or a sheet-qualified range hint." + }, + "cells": { + "type": "array", + "description": "Sparse 0-based cell patches. A cell may change content, style, or both; style-only cells intentionally omit value and formula.", + "maxItems": 5000, + "items": { "$ref": "#/$defs/cell" } + }, + "values": { + "type": "array", + "description": "Legacy dense values matrix anchored at a1. Strings beginning with = are formulas.", + "items": { + "type": "array", + "items": {} + } + }, + "layout": { + "$ref": "#/$defs/layout" + }, + "operations": { + "type": "array", + "description": "Composable same-sheet authoring operations compiled into one atomic cells+layout proposal. Use root sheetId for clarity. Use this for coherent multi-range designs; use direct cells/values/layout for simple edits.", + "maxItems": 100, + "items": { + "type": "object", + "additionalProperties": false, + "required": ["kind"], + "properties": { + "kind": { + "type": "string", + "enum": [ + "set_cells", + "set_values", + "set_formulas", + "apply_style", + "set_layout" + ] + }, + "a1": { + "type": "string", + "description": "Required for set_values, set_formulas, and apply_style." + }, + "cells": { + "type": "array", + "maxItems": 5000, + "items": { "$ref": "#/$defs/cell" }, + "description": "Required for set_cells." + }, + "values": { + "type": "array", + "items": { + "type": "array", + "items": {} + }, + "description": "Required for set_values or set_formulas. Formula strings may include or omit the leading = for set_formulas." + }, + "styleRole": { + "$ref": "#/$defs/styleRole" + }, + "style": { + "$ref": "#/$defs/style" + }, + "layout": { + "$ref": "#/$defs/layout" + } + } + } + } + }, + "$defs": { + "styleRole": { + "type": "string", + "enum": [ + "title", + "header", + "input", + "output", + "total", + "note", + "warning" + ], + "description": "Stable semantic styling. Prefer a role before adding custom overrides." + }, + "borderSide": { + "type": ["object", "null"], + "additionalProperties": false, + "description": "Border side override, or null to remove that side.", + "properties": { + "style": { + "type": "string", + "enum": ["thin", "medium", "thick", "dashed", "dotted", "double"] + }, + "color": { + "type": "string", + "description": "Six-digit RGB hex color, with optional leading #." + } + } + }, + "style": { + "type": ["object", "null"], + "additionalProperties": false, + "description": "Cell style override. Null clears the complete cell style and supersedes styleRole. Keep overrides sparse so semantic roles and source fidelity remain stable.", + "properties": { + "role": { "$ref": "#/$defs/styleRole" }, + "fill": { + "type": ["object", "null"], + "additionalProperties": false, + "description": "Fill override, or null to remove the fill.", + "properties": { + "color": { + "type": "string", + "description": "Six-digit RGB hex color, with optional leading #." + } + } + }, + "font": { + "type": ["object", "null"], + "additionalProperties": false, + "description": "Font override, or null to remove custom font properties.", + "properties": { + "bold": { "type": ["boolean", "null"] }, + "italic": { "type": ["boolean", "null"] }, + "color": { "type": ["string", "null"] }, + "size": { "type": ["number", "null"], "minimum": 6, "maximum": 72 } + } + }, + "border": { + "type": ["object", "null"], + "additionalProperties": false, + "description": "Border override, or null to remove all custom borders.", + "properties": { + "top": { "$ref": "#/$defs/borderSide" }, + "right": { "$ref": "#/$defs/borderSide" }, + "bottom": { "$ref": "#/$defs/borderSide" }, + "left": { "$ref": "#/$defs/borderSide" } + } + }, + "alignment": { + "type": ["object", "null"], + "additionalProperties": false, + "description": "Alignment override, or null to remove custom alignment.", + "properties": { + "horizontal": { + "type": ["string", "null"], + "enum": ["left", "center", "right", "general", null] + }, + "vertical": { + "type": ["string", "null"], + "enum": ["top", "center", "bottom", null] + }, + "wrapText": { "type": ["boolean", "null"] } + } + }, + "numberFormat": { + "type": ["string", "null"], + "maxLength": 120, + "description": "Excel-compatible number format such as #,##0.00, 0.0%, or yyyy-mm-dd; null removes it. Formatting does not change the underlying value." + } + } + }, + "cell": { + "type": "object", + "additionalProperties": false, + "required": ["row", "col"], + "properties": { + "row": { "type": "integer", "minimum": 0 }, + "col": { "type": "integer", "minimum": 0 }, + "value": {}, + "formula": { + "type": "string", + "description": "Formula with or without a leading =." + }, + "styleRole": { "$ref": "#/$defs/styleRole" }, + "style": { "$ref": "#/$defs/style" } + } + }, + "layout": { + "type": "object", + "additionalProperties": false, + "description": "Sheet layout metadata included in the same proposal. Column and row start/end indices are 0-based and inclusive; A1 remains 1-based Excel notation.", + "properties": { + "columns": { + "type": "array", + "description": "Column layout bands. An explicit empty array clears all custom column-width metadata.", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["start"], + "properties": { + "start": { "type": "integer", "minimum": 0 }, + "end": { "type": "integer", "minimum": 0 }, + "width": { + "type": "number", + "minimum": 1, + "maximum": 255, + "description": "Width in Excel character units, never pixels." + }, + "autoFit": { "type": "boolean" } + } + } + }, + "rows": { + "type": "array", + "description": "Row layout bands. An explicit empty array clears all custom row-height metadata.", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["start"], + "properties": { + "start": { "type": "integer", "minimum": 0 }, + "end": { "type": "integer", "minimum": 0 }, + "height": { + "type": "number", + "minimum": 1, + "maximum": 409, + "description": "Height in points, never pixels." + }, + "autoFit": { "type": "boolean" } + } + } + }, + "freezePanes": { + "type": "object", + "additionalProperties": false, + "description": "Frozen row/column counts. Use rows:0 and columns:0 to clear frozen panes.", + "properties": { + "rows": { "type": "integer", "minimum": 0 }, + "columns": { "type": "integer", "minimum": 0 } + } + }, + "autoFilter": { + "type": ["object", "null"], + "additionalProperties": false, + "properties": { + "a1": { "type": "string" } + }, + "description": "Filter header range, or null to clear the current auto filter." + } + } + } + } + }, + "runtime": "javascript", + "entry": "tools/propose_patch.js", + "readonly": false, + "permissions": {}, + "timeoutMs": 60000, + "maxOutputBytes": 300000, + "ui": { + "card": { + "kind": "appDefined", + "family": "excel-live", + "template": "compact", + "displayMode": "compact", + "resultDisplayType": "detailed", + "primaryColor": "var(--ds-tool-family-agent-component-fg)", + "displayName": "Propose Workbook Change", + "icon": "Table", + "title": "Propose Workbook Change", + "summary": { + "preparing": "Preparing workbook proposal", + "running": "Designing changes for {{input.workbookId}}", + "completed": "Proposal ready - review on the grid", + "failed": "Proposal failed" + }, + "fields": [ + { "label": "Workbook", "inputPath": ["workbookId"] }, + { "label": "Sheet", "inputPath": ["sheetId"] }, + { "label": "Range", "inputPath": ["a1"] }, + { "label": "Revision", "inputPath": ["expectedRevision"] }, + { "label": "Intent", "inputPath": ["intent"] }, + { "label": "Action", "resultPath": ["bridge", "action"] }, + { "label": "Status", "resultPath": ["bridge", "status"] }, + { "label": "Base revision", "resultPath": ["bridge", "output", "proposal", "baseRevision"] }, + { "label": "Validation", "resultPath": ["bridge", "output", "proposal", "validation"], "format": "json" }, + { "label": "Layout", "resultPath": ["bridge", "output", "proposal", "layout"], "format": "json" }, + { "label": "Output", "resultPath": ["bridge", "output"], "format": "json" } + ] + } + } +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/read_range.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/read_range.js new file mode 100644 index 00000000..3d1cd422 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/read_range.js @@ -0,0 +1,12 @@ +const { callExcelEngine } = require("./excel_bridge"); + +async function run(input, context) { + return callExcelEngine( + "readRange", + input, + context, + "Read the requested spreadsheet range.", + ); +} + +module.exports = { run }; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/read_range.tool.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/read_range.tool.json new file mode 100644 index 00000000..9e9ae31f --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/read_range.tool.json @@ -0,0 +1,80 @@ +{ + "name": "read_range", + "description": "Read grounded cell values, formulas, cell styles, calculation status, and sheet layout for a range. Defaults to ambient focus when a1 is omitted and enforces maxCells (default 2000). Use before reasoning about or redesigning content.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "required": [ + "workbookId" + ], + "properties": { + "workbookId": { + "type": "string" + }, + "sheetId": { + "type": "string" + }, + "a1": { + "type": "string" + }, + "maxCells": { + "type": "integer", + "minimum": 1, + "maximum": 20000 + } + } + }, + "runtime": "javascript", + "entry": "tools/read_range.js", + "readonly": true, + "permissions": {}, + "timeoutMs": 30000, + "maxOutputBytes": 200000, + "ui": { + "card": { + "kind": "appDefined", + "family": "excel-live", + "template": "compact", + "displayMode": "compact", + "resultDisplayType": "detailed", + "primaryColor": "var(--ds-tool-family-agent-component-fg)", + "displayName": "Read Range", + "icon": "Table", + "title": "Read Range", + "summary": { + "preparing": "Preparing read", + "running": "Reading {{input.a1}}", + "completed": "Range read", + "failed": "Read failed" + }, + "fields": [ + { + "label": "Workbook", + "inputPath": [ + "workbookId" + ] + }, + { + "label": "Sheet", + "inputPath": [ + "sheetId" + ] + }, + { + "label": "Range", + "inputPath": [ + "a1" + ] + }, + { + "label": "Output", + "resultPath": [ + "bridge", + "output" + ], + "format": "json" + } + ] + } + } +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/redo_workbook.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/redo_workbook.js new file mode 100644 index 00000000..488f75b6 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/redo_workbook.js @@ -0,0 +1,12 @@ +const { callExcelEngine } = require("./excel_bridge"); + +async function run(input, context) { + return callExcelEngine( + "redo", + input, + context, + "Redo the latest undone workbook operation and return the new revision.", + ); +} + +module.exports = { run }; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/redo_workbook.tool.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/redo_workbook.tool.json new file mode 100644 index 00000000..5fbe7074 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/redo_workbook.tool.json @@ -0,0 +1,41 @@ +{ + "name": "redo_workbook", + "description": "Redo the latest undone Excel Live operation. Use only when the user explicitly asks to reapply it.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "required": ["workbookId", "expectedRevision"], + "properties": { + "workbookId": { "type": "string" }, + "expectedRevision": { + "type": "integer", + "minimum": 0, + "description": "Current workbook revision from spreadsheet focus or get_workbook_meta." + } + } + }, + "runtime": "javascript", + "entry": "tools/redo_workbook.js", + "readonly": false, + "permissions": {}, + "timeoutMs": 30000, + "maxOutputBytes": 60000, + "ui": { + "card": { + "kind": "appDefined", + "family": "excel-live", + "template": "compact", + "displayMode": "compact", + "resultDisplayType": "detailed", + "displayName": "Redo Workbook Change", + "icon": "Redo2", + "title": "Redo Workbook Change", + "summary": { + "preparing": "Checking workbook history", + "running": "Redoing the latest change", + "completed": "Workbook change redone", + "failed": "Redo failed" + } + } + } +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/reject_proposal.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/reject_proposal.js new file mode 100644 index 00000000..7fd554b6 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/reject_proposal.js @@ -0,0 +1,12 @@ +const { callExcelEngine } = require("./excel_bridge"); + +async function run(input, context) { + return callExcelEngine( + "rejectProposal", + input, + context, + "Rejected the active spreadsheet proposal without changing committed cells.", + ); +} + +module.exports = { run }; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/reject_proposal.tool.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/reject_proposal.tool.json new file mode 100644 index 00000000..ba18b80a --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/reject_proposal.tool.json @@ -0,0 +1,73 @@ +{ + "name": "reject_proposal", + "description": "Discard the active proposal without changing committed cells. Prefer calling this only when the user explicitly asks you to Reject from chat.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "required": [ + "workbookId", + "proposalId", + "expectedRevision" + ], + "properties": { + "workbookId": { + "type": "string" + }, + "proposalId": { + "type": "string", + "description": "Exact active proposal id reviewed by the user." + }, + "expectedRevision": { + "type": "integer", + "minimum": 0, + "description": "Exact workbook revision containing the proposal." + } + } + }, + "runtime": "javascript", + "entry": "tools/reject_proposal.js", + "readonly": false, + "permissions": {}, + "timeoutMs": 30000, + "maxOutputBytes": 60000, + "ui": { + "card": { + "kind": "appDefined", + "family": "excel-live", + "template": "compact", + "displayMode": "compact", + "resultDisplayType": "detailed", + "primaryColor": "var(--ds-tool-family-agent-component-fg)", + "displayName": "Reject Proposal", + "icon": "X", + "title": "Reject Proposal", + "summary": { + "preparing": "Preparing reject", + "running": "Rejecting proposal", + "completed": "Proposal rejected", + "failed": "Reject failed" + }, + "fields": [ + { + "label": "Workbook", + "inputPath": [ + "workbookId" + ] + }, + { + "label": "Proposal", + "inputPath": [ + "proposalId" + ] + }, + { + "label": "Status", + "resultPath": [ + "bridge", + "status" + ] + } + ] + } + } +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/save_workbook.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/save_workbook.js new file mode 100644 index 00000000..1581b45f --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/save_workbook.js @@ -0,0 +1,29 @@ +const { callExcelEngine } = require("./excel_bridge"); + +function buildSaveInput(input = {}) { + if ( + input.acknowledgeFidelityLoss === true && + (typeof input.path !== "string" || !input.path.toLowerCase().endsWith(".xlsx")) + ) { + throw new Error( + "acknowledgeFidelityLoss=true is allowed only for an explicit Save As to a distinct .xlsx path", + ); + } + return { + ...input, + acknowledgeFidelityLoss: input.acknowledgeFidelityLoss === true, + exportCopy: true, + allowSourceOverwrite: false, + }; +} + +async function run(input, context) { + return callExcelEngine( + "saveWorkbook", + buildSaveInput(input), + context, + "Exported the reviewed workbook revision to a separate copy.", + ); +} + +module.exports = { run, buildSaveInput }; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/save_workbook.tool.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/save_workbook.tool.json new file mode 100644 index 00000000..e5f8cb78 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/save_workbook.tool.json @@ -0,0 +1,91 @@ +{ + "name": "save_workbook", + "description": "Export a source-safe workbook copy. The live revisioned store is already persisted; never overwrite the imported source file.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "required": [ + "workbookId", + "expectedRevision", + "path" + ], + "properties": { + "workbookId": { + "type": "string" + }, + "expectedRevision": { + "type": "integer", + "minimum": 0, + "description": "Exact workbook revision reviewed before export. Refresh metadata if this conflicts." + }, + "path": { + "type": "string", + "pattern": "^(?![A-Za-z]:)(?![/\\\\])(?!.*(?:^|[/\\\\])\\.\\.(?:[/\\\\]|$)).+\\.(?:xlsx|xlsm)$", + "description": "Required .xlsx or .xlsm copy path relative to the active workspace. Absolute paths, parent traversal, source overwrite, and CSV are not allowed." + }, + "acknowledgeFidelityLoss": { + "type": "boolean", + "description": "Normally false. Set true only after the user has seen the workbook's concrete fidelity warning, explicitly accepted the losses, and chosen a distinct .xlsx Save As path. Never use true for .xlsm." + } + } + }, + "runtime": "javascript", + "entry": "tools/save_workbook.js", + "readonly": false, + "permissions": {}, + "timeoutMs": 60000, + "maxOutputBytes": 60000, + "ui": { + "card": { + "kind": "appDefined", + "family": "excel-live", + "template": "compact", + "displayMode": "compact", + "resultDisplayType": "detailed", + "primaryColor": "var(--ds-tool-family-agent-component-fg)", + "displayName": "Save Workbook", + "icon": "Save", + "title": "Export Workbook", + "summary": { + "preparing": "Preparing export", + "running": "Exporting workbook file", + "completed": "Workbook file exported", + "failed": "Export failed" + }, + "fields": [ + { + "label": "Workbook", + "inputPath": [ + "workbookId" + ] + }, + { + "label": "Path", + "inputPath": [ + "path" + ] + }, + { + "label": "Revision", + "inputPath": [ + "expectedRevision" + ] + }, + { + "label": "Loss acknowledged", + "inputPath": [ + "acknowledgeFidelityLoss" + ] + }, + { + "label": "Output", + "resultPath": [ + "bridge", + "output" + ], + "format": "json" + } + ] + } + } +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/summarize_range.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/summarize_range.js new file mode 100644 index 00000000..4514d21a --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/summarize_range.js @@ -0,0 +1,12 @@ +const { callExcelEngine } = require("./excel_bridge"); + +async function run(input, context) { + return callExcelEngine( + "summarizeRange", + input, + context, + "Summarized the requested spreadsheet range.", + ); +} + +module.exports = { run }; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/summarize_range.tool.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/summarize_range.tool.json new file mode 100644 index 00000000..aab03910 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/summarize_range.tool.json @@ -0,0 +1,73 @@ +{ + "name": "summarize_range", + "description": "Profile a range with numeric/text/empty/formula counts, header evidence, and bounded sample rows before a large read or transformation. Defaults to ambient focus when a1 is omitted.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "required": [ + "workbookId" + ], + "properties": { + "workbookId": { + "type": "string" + }, + "sheetId": { + "type": "string" + }, + "a1": { + "type": "string" + }, + "maxCells": { + "type": "integer", + "minimum": 1 + } + } + }, + "runtime": "javascript", + "entry": "tools/summarize_range.js", + "readonly": true, + "permissions": {}, + "timeoutMs": 30000, + "maxOutputBytes": 120000, + "ui": { + "card": { + "kind": "appDefined", + "family": "excel-live", + "template": "compact", + "displayMode": "compact", + "resultDisplayType": "detailed", + "primaryColor": "var(--ds-tool-family-agent-component-fg)", + "displayName": "Summarize Range", + "icon": "BarChart", + "title": "Summarize Range", + "summary": { + "preparing": "Preparing summary", + "running": "Summarizing {{input.a1}}", + "completed": "Summary ready", + "failed": "Summarize failed" + }, + "fields": [ + { + "label": "Workbook", + "inputPath": [ + "workbookId" + ] + }, + { + "label": "Range", + "inputPath": [ + "a1" + ] + }, + { + "label": "Output", + "resultPath": [ + "bridge", + "output" + ], + "format": "json" + } + ] + } + } +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/switch_sheet.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/switch_sheet.js new file mode 100644 index 00000000..b745978a --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/switch_sheet.js @@ -0,0 +1,12 @@ +const { callExcelEngine } = require("./excel_bridge"); + +async function run(input, context) { + return callExcelEngine( + "switchSheet", + input, + context, + "Switched the active workbook sheet.", + ); +} + +module.exports = { run }; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/switch_sheet.tool.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/switch_sheet.tool.json new file mode 100644 index 00000000..38a55a3b --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/switch_sheet.tool.json @@ -0,0 +1,79 @@ +{ + "name": "switch_sheet", + "description": "Switch the active sheet by id or name and update ambient focus to that sheet.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "required": [ + "workbookId" + ], + "anyOf": [ + { "required": ["sheetId"] }, + { "required": ["sheetName"] } + ], + "properties": { + "workbookId": { + "type": "string" + }, + "sheetId": { + "type": "string" + }, + "sheetName": { + "type": "string" + } + } + }, + "runtime": "javascript", + "entry": "tools/switch_sheet.js", + "readonly": false, + "permissions": {}, + "timeoutMs": 30000, + "maxOutputBytes": 60000, + "ui": { + "card": { + "kind": "appDefined", + "family": "excel-live", + "template": "compact", + "displayMode": "compact", + "resultDisplayType": "detailed", + "primaryColor": "var(--ds-tool-family-agent-component-fg)", + "displayName": "Switch Sheet", + "icon": "Layers", + "title": "Switch Sheet", + "summary": { + "preparing": "Switching sheet", + "running": "Switching sheet", + "completed": "Sheet switched", + "failed": "Switch failed" + }, + "fields": [ + { + "label": "Workbook", + "inputPath": [ + "workbookId" + ] + }, + { + "label": "Sheet", + "inputPath": [ + "sheetId" + ] + }, + { + "label": "Name", + "inputPath": [ + "sheetName" + ] + }, + { + "label": "Output", + "resultPath": [ + "bridge", + "output" + ], + "format": "json" + } + ] + } + } +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/undo_workbook.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/undo_workbook.js new file mode 100644 index 00000000..49541efd --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/undo_workbook.js @@ -0,0 +1,12 @@ +const { callExcelEngine } = require("./excel_bridge"); + +async function run(input, context) { + return callExcelEngine( + "undo", + input, + context, + "Undo the latest committed workbook operation and return the new revision.", + ); +} + +module.exports = { run }; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/undo_workbook.tool.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/undo_workbook.tool.json new file mode 100644 index 00000000..8a567fe4 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/agents/excel-live-agent/source/tools/undo_workbook.tool.json @@ -0,0 +1,41 @@ +{ + "name": "undo_workbook", + "description": "Undo the latest committed Excel Live operation. Use only when the user explicitly asks to reverse a committed change.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "required": ["workbookId", "expectedRevision"], + "properties": { + "workbookId": { "type": "string" }, + "expectedRevision": { + "type": "integer", + "minimum": 0, + "description": "Current workbook revision from spreadsheet focus or get_workbook_meta." + } + } + }, + "runtime": "javascript", + "entry": "tools/undo_workbook.js", + "readonly": false, + "permissions": {}, + "timeoutMs": 30000, + "maxOutputBytes": 60000, + "ui": { + "card": { + "kind": "appDefined", + "family": "excel-live", + "template": "compact", + "displayMode": "compact", + "resultDisplayType": "detailed", + "displayName": "Undo Workbook Change", + "icon": "Undo2", + "title": "Undo Workbook Change", + "summary": { + "preparing": "Checking workbook history", + "running": "Undoing the latest change", + "completed": "Workbook change undone", + "failed": "Undo failed" + } + } + } +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/component.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/component.json new file mode 100644 index 00000000..cd80e52e --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/component.json @@ -0,0 +1,81 @@ +{ + "id": "builtin-excel-runtime", + "kind": "bridge", + "name": "Sparo Excel Engine", + "description": "Revisioned workbook creation with formulas, semantic styles, number formats, worksheet layout, reviewable edits, static formula lint, and source-safe XLSX export.", + "packageSource": "appPrivate", + "ownerApp": { + "appId": "builtin-excel-live", + "appVersion": "1.0.1" + }, + "capabilities": [ + { + "id": "sparo.excelEngine", + "title": "Sparo Excel Engine", + "description": "Read values, formulas, basic RGB styles, and layout; create reviewable content/style/layout proposals; statically lint but do not calculate formulas; undo; and export source-safe CSV/XLSX copies.", + "actions": [ + "openWorkbook", + "createWorkbook", + "getMeta", + "getFocus", + "setFocus", + "readRange", + "summarizeRange", + "proposePatch", + "getProposal", + "acceptProposal", + "rejectProposal", + "applyLocalEdit", + "applyLocalPatch", + "applyLayout", + "clearRange", + "undo", + "redo", + "getHistory", + "saveWorkbook", + "exportCsv", + "listSheets", + "listWorkbooks", + "switchSheet", + "insertRows", + "insertColumns", + "deleteRows", + "deleteColumns", + "renameSheet", + "addSheet", + "reloadWorkbook" + ] + } + ], + "permissions": [ + { + "kind": "fs", + "summary": "Reads spreadsheet files and writes workbook store plus CSV/XLSX exports under the workspace.", + "scopes": [ + "{workspace}", + "{app}" + ] + }, + { + "kind": "shell", + "summary": "Starts the Node.js bridge worker that hosts the Sparo Excel Engine.", + "scopes": [ + "node" + ] + } + ], + "usedByApps": [ + "builtin-excel-live" + ], + "visibility": "appDependency", + "dependencies": [], + "implementationRef": "app://builtin-excel-live@1.0.1/bridges/builtin-excel-runtime", + "usesCapabilities": [ + "filesystem.read", + "filesystem.write", + "terminal.run", + "process.spawn", + "workspace.inspect", + "component.run" + ] +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/bundle.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/bundle.json new file mode 100644 index 00000000..266791a0 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/bundle.json @@ -0,0 +1,5 @@ +{ + "schemaVersion": 1, + "id": "builtin-excel-runtime", + "version": 1 +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/manifest.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/manifest.json new file mode 100644 index 00000000..e07938c3 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/manifest.json @@ -0,0 +1,411 @@ +{ + "schemaVersion": 1, + "id": "builtin-excel-runtime", + "name": "Sparo Excel Engine", + "description": "Revisioned workbook creation with formulas, semantic cell styles, number formats, worksheet layout, proposal review, undo, static formula lint, and source-safe XLSX export for Excel Live.", + "kind": "daemon", + "runtime": { + "language": "javascript", + "entry": "worker.js" + }, + "surfaces": { + "launchableApp": false, + "agent": true, + "tool": true, + "productAppRuntimeBackend": true + }, + "permissions": { + "fs": [ + "{workspace}", + "{app}" + ], + "net": [], + "shell": [ + "node" + ], + "gui": [], + "secrets": [] + }, + "capabilities": [ + { + "id": "sparo.excelEngine", + "title": "Sparo Excel Engine", + "description": "Open and create revisioned workbooks; read values, formulas, basic RGB styles, and layout; propose conflict-safe content/style/layout edits; statically lint formulas without calculating them; undo; and export source-safe CSV/XLSX copies.", + "category": "excelEngine", + "actions": [ + "openWorkbook", + "createWorkbook", + "getMeta", + "getFocus", + "setFocus", + "readRange", + "summarizeRange", + "proposePatch", + "getProposal", + "acceptProposal", + "rejectProposal", + "applyLocalEdit", + "applyLocalPatch", + "applyLayout", + "clearRange", + "undo", + "redo", + "getHistory", + "saveWorkbook", + "exportCsv", + "listSheets", + "listWorkbooks", + "switchSheet", + "insertRows", + "insertColumns", + "deleteRows", + "deleteColumns", + "renameSheet", + "addSheet", + "reloadWorkbook" + ], + "streaming": false, + "cancelable": true, + "resumable": true, + "usableBy": [ + "agentComponent", + "productAppRuntime", + "management" + ], + "inputSchema": { + "type": "object" + }, + "outputSchema": { + "type": "object" + } + } + ], + "actions": [ + { + "name": "openWorkbook", + "description": "Open a CSV, XLSX, or Sparo workbook JSON file into an in-memory session and persist the store under .sparo_os/excel-live.", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "createWorkbook", + "description": "Create an empty workbook (default 50x26 sheet) and persist its store.", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "getMeta", + "description": "Return workbook metadata including sheet layout, focus, dirty/revision state, proposal state, calculation honesty, style/layout fidelity, and precise runtime capabilities.", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "getFocus", + "description": "Return the current ambient focus (sheet, A1, kind).", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "setFocus", + "description": "Set the ambient focus and collaboration mode without changing workbook content revision.", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "readRange", + "description": "Read a values matrix, formula subset, sparse styled-cell details, and worksheet layout for a range (defaults to current focus). Enforces maxCells (default 2000).", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "summarizeRange", + "description": "Summarize a range with numeric/empty/formula counts, header guess, and sample TSV (first 20 rows).", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "proposePatch", + "description": "Compute an intent-bearing content/formula/style/layout before/after proposal at an expected revision without mutating committed cells. New formulas receive static lint only, never calculation. resultCellLimit can bound returned detail without truncating the stored proposal.", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "getProposal", + "description": "Return the active proposal diff, optionally bounding cell details with resultCellLimit while reporting totalCellCount and cellDetailsTruncated.", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "acceptProposal", + "description": "Apply all or selected cells after revision and before-value/style conflict checks. Proposal layout is applied only on whole-proposal acceptance without cellRefs.", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "rejectProposal", + "description": "Discard the active proposal without changing committed cells.", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "applyLocalEdit", + "description": "Apply an undoable value, formula, or partial-merge style edit at the current workbook revision.", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "applyLocalPatch", + "description": "Apply an undoable multi-cell value/formula/style patch, used by paste and direct user formatting.", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "clearRange", + "description": "Clear committed cells as an undoable operation and invalidate stale proposals.", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "applyLayout", + "description": "Apply undoable column widths (Excel character units), row heights (points), deterministic content-aware auto-fit sizes with an OOXML best-fit hint, freeze panes, and auto-filter metadata at an expected revision. Imported Excel packages require an acknowledged Save As rebuild for changed layout.", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "undo", + "description": "Undo the latest committed workbook content operation.", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "redo", + "description": "Redo the latest undone workbook content operation.", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "getHistory", + "description": "Return revision and compact undo/redo operation history without cell payloads.", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "saveWorkbook", + "description": "Persist the live store and export JSON or a styled/layout-aware XLSX copy. Imported Excel style/layout changes require an acknowledged lossy Save As rebuild and can never silently overwrite the source; CSV uses exportCsv.", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "exportCsv", + "description": "Serialize the active (or specified) sheet to CSV, optionally writing a file.", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "listSheets", + "description": "List sheets in the workbook.", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "listWorkbooks", + "description": "List live workbook stores under .sparo_os/excel-live for the workspace.", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "switchSheet", + "description": "Switch the active sheet by id or name.", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "insertRows", + "description": "Insert one or more rows at a 0-based index.", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "insertColumns", + "description": "Insert one or more columns at a 0-based index.", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "deleteRows", + "description": "Delete one or more rows at a 0-based index.", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "deleteColumns", + "description": "Delete one or more columns at a 0-based index.", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "renameSheet", + "description": "Rename a sheet.", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "addSheet", + "description": "Add a new empty sheet to the workbook.", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "reloadWorkbook", + "description": "Reload from the original file path when available, otherwise from the JSON store.", + "inputSchema": { "type": "object" }, + "outputSchema": { "type": "object" }, + "streaming": false, + "cancelable": false, + "resumable": true + } + ], + "tools": [ + { + "name": "SparoExcelEngine", + "description": "Create professional workbooks with formulas, semantic styles, number formats, layout controls, reviewable proposals, and CSV/XLSX export. Formula validation is static only; this engine does not calculate formulas.", + "capabilityId": "sparo.excelEngine", + "action": "getMeta", + "actions": [ + "openWorkbook", + "createWorkbook", + "getMeta", + "getFocus", + "setFocus", + "readRange", + "summarizeRange", + "proposePatch", + "getProposal", + "acceptProposal", + "rejectProposal", + "applyLocalEdit", + "applyLocalPatch", + "applyLayout", + "clearRange", + "undo", + "redo", + "getHistory", + "saveWorkbook", + "exportCsv", + "listSheets", + "listWorkbooks", + "switchSheet", + "insertRows", + "insertColumns", + "deleteRows", + "deleteColumns", + "renameSheet", + "addSheet", + "reloadWorkbook" + ], + "readonly": false, + "needsPermissions": true, + "inputSchema": { + "type": "object" + }, + "ui": { + "card": { + "kind": "appDefined", + "displayName": "Sparo Excel Engine", + "icon": "Table", + "resultDisplayType": "detailed", + "displayMode": "compact", + "family": "bridge-component", + "title": "Sparo Excel Engine" + } + } + } + ] +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/package.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/package.json new file mode 100644 index 00000000..c0b98fb3 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/package.json @@ -0,0 +1,8 @@ +{ + "private": true, + "type": "commonjs", + "name": "builtin-excel-runtime", + "scripts": { + "test": "node --test test/*.test.js" + } +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/src/a1.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/src/a1.js new file mode 100644 index 00000000..f7e66fa1 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/src/a1.js @@ -0,0 +1,195 @@ +/** + * A1 reference helpers (0-based row/col indices). + */ + +const EXCEL_MAX_ROWS = 1_048_576; +const EXCEL_MAX_COLUMNS = 16_384; + +function assertCellCoordinates(row, col, context = "Cell") { + if ( + !Number.isSafeInteger(row) || + !Number.isSafeInteger(col) || + row < 0 || + col < 0 || + row >= EXCEL_MAX_ROWS || + col >= EXCEL_MAX_COLUMNS + ) { + throw new Error( + `[EXCEL_CELL_LIMIT] ${context} must be within rows 1-${EXCEL_MAX_ROWS} and columns A-XFD using safe integer coordinates.` + ); + } + return { row, col }; +} + +function assertSheetDimensions(rows, cols, context = "Worksheet") { + if ( + !Number.isSafeInteger(rows) || + !Number.isSafeInteger(cols) || + rows < 1 || + cols < 1 || + rows > EXCEL_MAX_ROWS || + cols > EXCEL_MAX_COLUMNS + ) { + throw new Error( + `[EXCEL_SHEET_LIMIT] ${context} must have 1-${EXCEL_MAX_ROWS} rows and 1-${EXCEL_MAX_COLUMNS} columns.` + ); + } + return { rows, cols }; +} + +function colToIndex(col) { + if (col == null || typeof col !== "string" || !col.length) { + throw new Error("Column letter is required"); + } + const upper = col.toUpperCase(); + if (!/^[A-Z]{1,3}$/.test(upper)) { + throw new Error(`Invalid column letters: ${col}`); + } + let index = 0; + for (let i = 0; i < upper.length; i += 1) { + index = index * 26 + (upper.charCodeAt(i) - 64); + } + const zeroBased = index - 1; + if (!Number.isSafeInteger(zeroBased) || zeroBased >= EXCEL_MAX_COLUMNS) { + throw new Error( + `[EXCEL_COLUMN_LIMIT] Column ${upper} exceeds Excel's maximum column XFD.` + ); + } + return zeroBased; +} + +function indexToCol(index) { + if (!Number.isSafeInteger(index) || index < 0 || index >= EXCEL_MAX_COLUMNS) { + throw new Error(`Invalid column index: ${index}`); + } + let n = index + 1; + let col = ""; + while (n > 0) { + const rem = (n - 1) % 26; + col = String.fromCharCode(65 + rem) + col; + n = Math.floor((n - 1) / 26); + } + return col; +} + +function parseCellToken(token) { + const match = String(token || "") + .trim() + .toUpperCase() + .match(/^([A-Z]+)(\d+)$/); + if (!match) { + throw new Error(`Invalid A1 cell reference: ${token}`); + } + const c = colToIndex(match[1]); + const rowNumber = Number(match[2]); + if (!Number.isSafeInteger(rowNumber) || rowNumber < 1 || rowNumber > EXCEL_MAX_ROWS) { + throw new Error( + `[EXCEL_ROW_LIMIT] Row ${match[2]} exceeds Excel's supported range 1-${EXCEL_MAX_ROWS}.` + ); + } + const r = rowNumber - 1; + assertCellCoordinates(r, c, `Cell ${match[1]}${match[2]}`); + return { c, r }; +} + +/** + * Parse an A1 range or cell. + * Accepts: "A1", "A1:B10", "Sheet1!A1:B2", "'My Sheet'!A1" + * @returns {{ sheet: string|null, r1: number, c1: number, r2: number, c2: number }} + */ +function parseA1(ref) { + if (ref == null || String(ref).trim() === "") { + throw new Error("A1 reference is required"); + } + let raw = String(ref).trim(); + let sheet = null; + + const bang = raw.lastIndexOf("!"); + if (bang >= 0) { + sheet = raw.slice(0, bang).trim(); + raw = raw.slice(bang + 1).trim(); + if ( + (sheet.startsWith("'") && sheet.endsWith("'")) || + (sheet.startsWith('"') && sheet.endsWith('"')) + ) { + sheet = sheet.slice(1, -1).replace(/''/g, "'"); + } + } + + const parts = raw.split(":"); + if (parts.length === 1) { + const cell = parseCellToken(parts[0]); + return { sheet, r1: cell.r, c1: cell.c, r2: cell.r, c2: cell.c }; + } + if (parts.length !== 2) { + throw new Error(`Invalid A1 range: ${ref}`); + } + const a = parseCellToken(parts[0]); + const b = parseCellToken(parts[1]); + return { + sheet, + r1: Math.min(a.r, b.r), + c1: Math.min(a.c, b.c), + r2: Math.max(a.r, b.r), + c2: Math.max(a.c, b.c), + }; +} + +function formatA1(r1, c1, r2 = r1, c2 = c1) { + assertCellCoordinates(r1, c1, "Range start"); + assertCellCoordinates(r2, c2, "Range end"); + const top = Math.min(r1, r2); + const left = Math.min(c1, c2); + const bottom = Math.max(r1, r2); + const right = Math.max(c1, c2); + const start = `${indexToCol(left)}${top + 1}`; + if (top === bottom && left === right) { + return start; + } + return `${start}:${indexToCol(right)}${bottom + 1}`; +} + +function cellCount(r1, c1, r2, c2) { + assertCellCoordinates(r1, c1, "Range start"); + assertCellCoordinates(r2, c2, "Range end"); + const rows = Math.abs(r2 - r1) + 1; + const cols = Math.abs(c2 - c1) + 1; + const count = rows * cols; + if (!Number.isSafeInteger(count)) { + throw new Error("[EXCEL_RANGE_LIMIT] Range cell count exceeds JavaScript safe integer limits."); + } + return count; +} + +function clampRange(range, maxRows, maxCols) { + if (!range || typeof range !== "object") { + throw new Error("Range is required"); + } + const rows = Number(maxRows); + const cols = Number(maxCols); + assertSheetDimensions(rows, cols, "Worksheet bounds"); + const r1 = Math.max(0, Math.min(Number(range.r1) || 0, rows - 1)); + const c1 = Math.max(0, Math.min(Number(range.c1) || 0, cols - 1)); + const r2 = Math.max(r1, Math.min(Number(range.r2) || r1, rows - 1)); + const c2 = Math.max(c1, Math.min(Number(range.c2) || c1, cols - 1)); + return { + sheet: range.sheet == null ? null : range.sheet, + r1, + c1, + r2, + c2, + }; +} + +module.exports = { + EXCEL_MAX_ROWS, + EXCEL_MAX_COLUMNS, + assertCellCoordinates, + assertSheetDimensions, + colToIndex, + indexToCol, + parseA1, + formatA1, + cellCount, + clampRange, +}; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/src/csv-io.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/src/csv-io.js new file mode 100644 index 00000000..1095e55e --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/src/csv-io.js @@ -0,0 +1,168 @@ +/** + * Minimal CSV parse / serialize with quote handling. + */ + +const { + EXCEL_MAX_COLUMNS, + EXCEL_MAX_ROWS, +} = require("./a1"); + +const MAX_CSV_PARSED_CELLS = 500_000; + +function positiveLimit(value, fallback, name) { + if (value == null) return fallback; + const parsed = Number(value); + if (!Number.isSafeInteger(parsed) || parsed < 1) { + throw new Error(`[CSV_LIMIT_INVALID] ${name} must be a positive safe integer.`); + } + return parsed; +} + +function parseCsv(text, options = {}) { + const source = text == null ? "" : String(text); + const maxRows = Math.min( + EXCEL_MAX_ROWS, + positiveLimit(options.maxRows, EXCEL_MAX_ROWS, "maxRows") + ); + const maxColumns = Math.min( + EXCEL_MAX_COLUMNS, + positiveLimit(options.maxColumns, EXCEL_MAX_COLUMNS, "maxColumns") + ); + const maxCells = positiveLimit( + options.maxCells, + MAX_CSV_PARSED_CELLS, + "maxCells" + ); + const rows = []; + let row = []; + let field = ""; + let inQuotes = false; + let i = 0; + let parsedCellCount = 0; + + const pushField = () => { + if (row.length >= maxColumns) { + throw new Error( + `[CSV_COLUMN_LIMIT] CSV row exceeds the maximum of ${maxColumns} columns.` + ); + } + parsedCellCount += 1; + if (parsedCellCount > maxCells) { + throw new Error( + `[CSV_CELL_COUNT_LIMIT] CSV contains more than ${maxCells} parsed cells.` + ); + } + row.push(field); + field = ""; + }; + + const pushRow = () => { + if (rows.length >= maxRows) { + throw new Error( + `[CSV_ROW_LIMIT] CSV contains more than ${maxRows} rows.` + ); + } + rows.push(row); + row = []; + }; + + while (i < source.length) { + const ch = source[i]; + if (inQuotes) { + if (ch === '"') { + if (source[i + 1] === '"') { + field += '"'; + i += 2; + continue; + } + inQuotes = false; + i += 1; + continue; + } + field += ch; + i += 1; + continue; + } + + if (ch === '"') { + inQuotes = true; + i += 1; + continue; + } + if (ch === ",") { + pushField(); + i += 1; + continue; + } + if (ch === "\r") { + if (source[i + 1] === "\n") { + i += 1; + } + pushField(); + pushRow(); + i += 1; + continue; + } + if (ch === "\n") { + pushField(); + pushRow(); + i += 1; + continue; + } + field += ch; + i += 1; + } + + if (inQuotes) { + throw new Error("Unterminated quoted field in CSV"); + } + + if (field.length > 0 || row.length > 0 || source.endsWith(",") || source.endsWith("\n") || source.endsWith("\r")) { + // Avoid counting or materializing a phantom blank row after a final + // newline. A trailing comma still represents a real empty field. + const isTrailingEmpty = + row.length === 0 && + field === "" && + rows.length > 0 && + (source.endsWith("\n") || source.endsWith("\r")); + if (!isTrailingEmpty) { + pushField(); + pushRow(); + } + } + + return rows; +} + +function needsQuotes(value) { + return /[",\r\n]/.test(value); +} + +function serializeField(value) { + if (value == null) { + return ""; + } + const text = String(value); + if (needsQuotes(text)) { + return `"${text.replace(/"/g, '""')}"`; + } + return text; +} + +function serializeCsv(rows) { + if (!Array.isArray(rows)) { + throw new Error("serializeCsv expects an array of rows"); + } + return rows + .map((row) => { + const cells = Array.isArray(row) ? row : [row]; + return cells.map(serializeField).join(","); + }) + .join("\n"); +} + +module.exports = { + MAX_CSV_PARSED_CELLS, + parseCsv, + serializeCsv, +}; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/src/engine.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/src/engine.js new file mode 100644 index 00000000..ace0ae5c --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/src/engine.js @@ -0,0 +1,2910 @@ +/** + * Sparo Excel Engine — workbook session API for Excel Live bridge. + */ + +const fs = require("node:fs"); +const path = require("node:path"); +const { + createEmpty, + loadJson, + saveJson, + ensureDir, + workbookDir, + getSheet, + findSheetByName, + findWorkbookIdByPath, + listWorkbookMetas, + cellKey, + createEmptySheet, + newId, + nowIso, + normalizeWorkbook, + normalizeMode, + normalizeSheetLayout, + validateExcelSheetName, + validateWorkbookId, +} = require("./workbook-store"); +const { + EXCEL_MAX_COLUMNS, + EXCEL_MAX_ROWS, + assertCellCoordinates, + assertSheetDimensions, + parseA1, + formatA1, + cellCount, + clampRange, +} = require("./a1"); +const { serializeCsv } = require("./csv-io"); +const { + readWorkbookFile, + readStableFile, + fingerprintsEqual, + writeWorkbookFile, + writeFileAtomic, + sheetToMatrix, +} = require("./xlsx-io"); + +const DEFAULT_MAX_CELLS = 2000; +const MAX_READ_RANGE_CELLS = 20_000; +const MAX_HISTORY = 500; +const MAX_UNDO_STACK = 100; +const MAX_PROPOSAL_CELLS = 5_000; +const MAX_LOCAL_PATCH_CELLS = 20_000; +const MAX_ACCEPT_SELECTION_CELLS = 5_000; +const MAX_WORKBOOK_CELLS = 500_000; +const MAX_LAYOUT_BANDS = 5_000; +const MAX_CUSTOM_LAYOUT_ROWS = 20_000; +const sessions = new Map(); + +function requireWorkspace(input) { + const workspacePath = input && input.workspacePath; + if (!workspacePath || typeof workspacePath !== "string") { + throw new Error( + "[INVALID_WORKSPACE_PATH] workspacePath is required and must be injected by the host as an absolute path." + ); + } + if (workspacePath.includes("\0") || !path.isAbsolute(workspacePath)) { + throw new Error( + "[INVALID_WORKSPACE_PATH] workspacePath must be a host-provided absolute path without NUL characters." + ); + } + return path.resolve(workspacePath); +} + +function requireWorkbookId(input) { + const workbookId = input && input.workbookId; + if (!workbookId || typeof workbookId !== "string") { + throw new Error("workbookId is required"); + } + return validateWorkbookId(workbookId); +} + +function trustedConsumerToken(input) { + return String(input?.__trustedConsumerKind || "") + .trim() + .toLowerCase() + .replace(/[^a-z]/g, ""); +} + +function assertConsumerPathAllowed(input, workspacePath, targetPath, action) { + if (trustedConsumerToken(input) !== "agentcomponent") return targetPath; + const workspaceIdentity = canonicalPathIdentity(workspacePath); + const targetIdentity = canonicalPathIdentity(targetPath); + const prefix = workspaceIdentity.endsWith(path.sep) + ? workspaceIdentity + : `${workspaceIdentity}${path.sep}`; + if (targetIdentity !== workspaceIdentity && !targetIdentity.startsWith(prefix)) { + throw new Error( + `[WORKSPACE_PATH_REQUIRED] ${action} must stay inside the host workspace. Product App file dialogs are the only supported way to authorize an external path.` + ); + } + return targetPath; +} + +function resolveConsumerPath(input, workspacePath, value, action) { + if (typeof value !== "string" || !value.trim() || value.includes("\0")) { + throw new Error(`${action} path must be a non-empty string without NUL characters`); + } + const resolved = path.isAbsolute(value) + ? path.resolve(value) + : path.resolve(workspacePath, value); + return assertConsumerPathAllowed(input, workspacePath, resolved, action); +} + +function prepareAtomicTargetWrite(input, targetPath, sourcePath = null) { + if (!fs.existsSync(targetPath)) { + return { expectTargetMissing: true }; + } + if (sourcePath && pathsReferToSameFile(targetPath, sourcePath)) { + return {}; + } + const productAppConfirmed = trustedConsumerToken(input) === "productappruntime" + && input.overwriteExisting === true; + if (!productAppConfirmed) { + throw new Error( + `[EXISTING_TARGET_OVERWRITE_BLOCKED] ${targetPath} already exists. Choose a new file name, or confirm replacement in the Product App save dialog.` + ); + } + const currentFingerprint = readStableFile(targetPath).fingerprint; + if ( + input.expectedTargetFingerprint + && !fingerprintsEqual(input.expectedTargetFingerprint, currentFingerprint) + ) { + throw new Error( + `[EXPORT_TARGET_CHANGED] ${targetPath} changed after overwrite confirmation. Reopen the save dialog and review the current file before replacing it.` + ); + } + return { expectedTargetFingerprint: currentFingerprint }; +} + +function touch(workbook) { + workbook.updatedAt = nowIso(); + return workbook; +} + +function persist(workspacePath, workbook) { + assertWorkbookWithinLimits(workbook); + reconcileCalculationStatus(workbook); + const saved = saveJson(workspacePath, touch(workbook)); + sessions.set(saved.workbookId, { workspacePath, workbook: saved }); + return saved; +} + +function cloneJson(value) { + if (value == null) return value; + return JSON.parse(JSON.stringify(value)); +} + +function cloneCell(cell) { + return cell ? cloneJson(cell) : null; +} + +const STYLE_ROLES = Object.freeze({ + title: { + fill: { color: "#17365D" }, + font: { bold: true, color: "#FFFFFF", size: 14 }, + alignment: { vertical: "center" }, + }, + header: { + fill: { color: "#1F4E78" }, + font: { bold: true, color: "#FFFFFF" }, + border: { bottom: { style: "thin", color: "#17365D" } }, + alignment: { vertical: "center", wrapText: true }, + }, + input: { + fill: { color: "#FFF2CC" }, + border: { bottom: { style: "thin", color: "#D6B656" } }, + }, + output: { + fill: { color: "#DDEBF7" }, + font: { color: "#17365D" }, + }, + total: { + font: { bold: true }, + border: { top: { style: "double", color: "#1F1F1F" } }, + }, + note: { + font: { italic: true, color: "#666666" }, + alignment: { wrapText: true }, + }, + warning: { + fill: { color: "#FCE4D6" }, + font: { bold: true, color: "#C00000" }, + }, +}); + +const BORDER_STYLES = new Set([ + "hair", "dotted", "dashDotDot", "dashDot", "dashed", "thin", "mediumDashDotDot", + "slantDashDot", "mediumDashDot", "mediumDashed", "medium", "thick", "double", +]); +const HORIZONTAL_ALIGNMENTS = new Set(["general", "left", "center", "right", "fill", "justify", "centerContinuous", "distributed"]); +const VERTICAL_ALIGNMENTS = new Set(["top", "center", "bottom", "justify", "distributed"]); + +function mergeObjects(base, override) { + const result = cloneJson(base) || {}; + for (const [key, value] of Object.entries(override || {})) { + if (value === undefined) continue; + if (value === null) { + delete result[key]; + } else if (value && typeof value === "object" && !Array.isArray(value)) { + result[key] = mergeObjects(result[key], value); + } else { + result[key] = value; + } + } + return result; +} + +function normalizeColor(value, context) { + if (typeof value !== "string") throw new Error(`${context} color must be a hex string`); + let color = value.trim().toUpperCase(); + if (/^#[0-9A-F]{3}$/.test(color)) { + color = `#${color[1]}${color[1]}${color[2]}${color[2]}${color[3]}${color[3]}`; + } + if (/^[0-9A-F]{6}$/.test(color)) color = `#${color}`; + if (!/^#[0-9A-F]{6}$/.test(color)) { + throw new Error(`${context} color must use #RRGGBB`); + } + return color; +} + +function normalizeBorderSide(value, context) { + if (typeof value === "string") value = { style: value }; + if (!value || typeof value !== "object") throw new Error(`${context} must be an object or border style`); + const style = value.style == null ? "thin" : String(value.style); + if (!BORDER_STYLES.has(style)) throw new Error(`${context}.style is not a supported Excel border style`); + const result = { style }; + if (value.color != null) result.color = normalizeColor(value.color, context); + return result; +} + +function normalizeStyle(style, styleRole, baseStyle = null) { + if (style === undefined && styleRole === undefined) return cloneJson(baseStyle) || null; + if (style === null && (styleRole == null || styleRole === "")) return null; + if (style != null && typeof style !== "object") throw new Error("cell style must be an object or null"); + const requestedRole = styleRole || style?.role || null; + if (requestedRole && !Object.prototype.hasOwnProperty.call(STYLE_ROLES, requestedRole)) { + throw new Error(`styleRole must be one of: ${Object.keys(STYLE_ROLES).join(", ")}`); + } + let merged = cloneJson(baseStyle) || {}; + if (requestedRole && merged.role && merged.role !== requestedRole) { + merged = merged.numberFormat ? { numberFormat: merged.numberFormat } : {}; + } + if (requestedRole) merged = mergeObjects(merged, STYLE_ROLES[requestedRole]); + merged = mergeObjects(merged, style || {}); + if (requestedRole) merged.role = requestedRole; + else if (merged.role && !Object.prototype.hasOwnProperty.call(STYLE_ROLES, merged.role)) delete merged.role; + + const result = {}; + if (merged.role) result.role = merged.role; + if (merged.fill != null) { + if (typeof merged.fill !== "object" || merged.fill.color == null) throw new Error("style.fill requires color"); + result.fill = { color: normalizeColor(merged.fill.color, "style.fill") }; + } + if (merged.font != null) { + if (typeof merged.font !== "object") throw new Error("style.font must be an object"); + const font = {}; + if (merged.font.bold != null) { + if (typeof merged.font.bold !== "boolean") throw new Error("style.font.bold must be boolean"); + if (merged.font.bold) font.bold = true; + } + if (merged.font.italic != null) { + if (typeof merged.font.italic !== "boolean") throw new Error("style.font.italic must be boolean"); + if (merged.font.italic) font.italic = true; + } + if (merged.font.color != null) font.color = normalizeColor(merged.font.color, "style.font"); + if (merged.font.size != null) { + const size = Number(merged.font.size); + if (!Number.isFinite(size) || size < 6 || size > 72) throw new Error("style.font.size must be between 6 and 72 points"); + font.size = size; + } + if (Object.keys(font).length) result.font = font; + } + if (merged.border != null) { + if (typeof merged.border !== "object") throw new Error("style.border must be an object"); + const border = {}; + for (const side of ["top", "right", "bottom", "left"]) { + if (merged.border[side] != null) border[side] = normalizeBorderSide(merged.border[side], `style.border.${side}`); + } + if (Object.keys(border).length) result.border = border; + } + if (merged.alignment != null) { + if (typeof merged.alignment !== "object") throw new Error("style.alignment must be an object"); + const alignment = {}; + if (merged.alignment.horizontal != null) { + const horizontal = String(merged.alignment.horizontal); + if (!HORIZONTAL_ALIGNMENTS.has(horizontal)) throw new Error("style.alignment.horizontal is not supported"); + alignment.horizontal = horizontal; + } + if (merged.alignment.vertical != null) { + const vertical = String(merged.alignment.vertical); + if (!VERTICAL_ALIGNMENTS.has(vertical)) throw new Error("style.alignment.vertical is not supported"); + alignment.vertical = vertical; + } + if (merged.alignment.wrapText != null) { + if (typeof merged.alignment.wrapText !== "boolean") throw new Error("style.alignment.wrapText must be boolean"); + if (merged.alignment.wrapText) alignment.wrapText = true; + } + if (Object.keys(alignment).length) result.alignment = alignment; + } + if (merged.numberFormat != null) { + const numberFormat = String(merged.numberFormat).trim(); + if (!numberFormat || numberFormat.length > 120) throw new Error("style.numberFormat must be 1-120 characters"); + result.numberFormat = numberFormat; + } + return Object.keys(result).length ? result : null; +} + +function stableEqual(left, right) { + return JSON.stringify(left == null ? null : left) === JSON.stringify(right == null ? null : right); +} + +function cellsEqual(left, right) { + const a = left || null; + const b = right || null; + if (a === b) return true; + if (!a || !b) return false; + return ( + a.v === b.v && + a.f === b.f && + a.t === b.t && + Boolean(a.formulaEvidence) === Boolean(b.formulaEvidence) && + (a.formulaType || null) === (b.formulaType || null) && + (a.formulaRef || null) === (b.formulaRef || null) && + (a.formulaGroupType || null) === (b.formulaGroupType || null) && + (a.formulaGroupRef || null) === (b.formulaGroupRef || null) && + stableEqual(a.style, b.style) + ); +} + +function cellsContentEqual(left, right) { + const clean = (cell) => { + if (!cell) return null; + const { style: _style, _sourceStyleIndex: _sourceStyleIndex, ...content } = cell; + return Object.keys(content).length ? content : null; + }; + return stableEqual(clean(left), clean(right)); +} + +function cellHasFormulaEvidence(cell) { + return Boolean( + cell && + (cell.formulaEvidence === true || + (typeof cell.f === "string" && cell.f.length > 0)) + ); +} + +function assertWorkbookWithinLimits(workbook) { + if (!workbook || !Array.isArray(workbook.sheets) || workbook.sheets.length === 0) { + throw new Error("Workbook must contain at least one worksheet"); + } + let workbookCellCount = 0; + for (const sheet of workbook.sheets) { + assertSheetDimensions(Number(sheet.rows), Number(sheet.cols), `Worksheet ${sheet.name || sheet.id}`); + for (const key of Object.keys(sheet.cells || {})) { + workbookCellCount += 1; + if (workbookCellCount > MAX_WORKBOOK_CELLS) { + throw new Error( + `[WORKBOOK_CELL_LIMIT] Workbook contains more than ${MAX_WORKBOOK_CELLS} populated cell records.` + ); + } + const parts = key.split(","); + if (parts.length !== 2) { + throw new Error(`[EXCEL_CELL_LIMIT] Invalid workbook cell key: ${key}`); + } + const row = Number(parts[0]); + const col = Number(parts[1]); + assertCellCoordinates(row, col, `Workbook cell ${key}`); + } + } + return workbook; +} + +function requirePositiveSafeInteger(value, fallback, name) { + const resolved = value == null ? fallback : Number(value); + if (!Number.isSafeInteger(resolved) || resolved < 1) { + throw new Error(`${name} must be a positive safe integer`); + } + return resolved; +} + +function populatedCellCount(workbook) { + return (workbook.sheets || []).reduce( + (total, sheet) => total + Object.keys(sheet.cells || {}).length, + 0 + ); +} + +function assertCellMutationCapacity(workbook, changes) { + let nextCount = populatedCellCount(workbook); + for (const change of changes || []) { + if (!change.before && change.after) nextCount += 1; + if (change.before && !change.after) nextCount -= 1; + } + if (!Number.isSafeInteger(nextCount) || nextCount > MAX_WORKBOOK_CELLS) { + throw new Error( + `[WORKBOOK_CELL_LIMIT] Operation would exceed ${MAX_WORKBOOK_CELLS} populated workbook cells.` + ); + } +} + +function assertExpectedRevision(workbook, input, action) { + const supplied = input.expectedRevision ?? input.baseRevision; + if (supplied == null) { + throw new Error( + `[EXPECTED_REVISION_REQUIRED] ${action} requires expectedRevision so concurrent workbook changes cannot be overwritten.` + ); + } + const expected = Number(supplied); + if (!Number.isSafeInteger(expected) || expected < 0) { + throw new Error(`${action} expectedRevision must be a non-negative integer`); + } + if (expected !== workbook.revision) { + throw new Error( + `[REVISION_CONFLICT] ${action} expected revision ${expected}, but the workbook is at revision ${workbook.revision}. Refresh and retry.` + ); + } +} + +function canonicalPathIdentity(value) { + const resolved = path.resolve(String(value || "")); + const missing = []; + let cursor = resolved; + while (!fs.existsSync(cursor)) { + const parent = path.dirname(cursor); + if (parent === cursor) break; + missing.unshift(path.basename(cursor)); + cursor = parent; + } + let canonicalBase = cursor; + try { + canonicalBase = fs.realpathSync.native(cursor); + } catch (_error) { + canonicalBase = path.resolve(cursor); + } + const canonical = path.resolve(canonicalBase, ...missing); + return process.platform === "win32" ? canonical.toLowerCase() : canonical; +} + +function pathsReferToSameFile(left, right) { + if (!left || !right) return false; + const leftPath = path.resolve(String(left)); + const rightPath = path.resolve(String(right)); + if (canonicalPathIdentity(leftPath) === canonicalPathIdentity(rightPath)) return true; + if (!fs.existsSync(leftPath) || !fs.existsSync(rightPath)) return false; + try { + const leftStat = fs.statSync(leftPath, { bigint: true }); + const rightStat = fs.statSync(rightPath, { bigint: true }); + return leftStat.dev === rightStat.dev && leftStat.ino === rightStat.ino; + } catch (_error) { + return false; + } +} + +function assertWritable(workbook, action) { + if (workbook.mode === "inspect") { + throw new Error( + `[INSPECT_MODE_READ_ONLY] ${action} is not allowed while the workbook is in Inspect mode. Switch to Edit or Author mode first.` + ); + } +} + +function formulaCount(workbook) { + let count = 0; + for (const sheet of workbook.sheets || []) { + for (const cell of Object.values(sheet.cells || {})) { + if (cellHasFormulaEvidence(cell)) count += 1; + } + } + return count; +} + +function reconcileCalculationStatus(workbook) { + const count = formulaCount(workbook); + if (count === 0) { + workbook.calculationStatus = { + engine: "none", + status: "not-required", + formulaCount: 0, + lastCalculatedRevision: null, + warning: null, + }; + return workbook.calculationStatus; + } + const previous = workbook.calculationStatus && typeof workbook.calculationStatus === "object" + ? workbook.calculationStatus + : {}; + const previousStatus = String(previous.status || "").toLowerCase(); + workbook.calculationStatus = { + ...previous, + engine: "none", + status: workbook.dirty || previousStatus === "stale" ? "stale" : "cached", + formulaCount: count, + lastCalculatedRevision: null, + warning: "Formula results are cached values; this engine does not recalculate formulas.", + }; + return workbook.calculationStatus; +} + +function refreshCalculationStatus(workbook, contentChanged = false) { + const count = formulaCount(workbook); + const wasStale = String(workbook.calculationStatus?.status || "").toLowerCase() === "stale"; + workbook.calculationStatus = { + engine: "none", + status: count === 0 ? "not-required" : contentChanged || wasStale ? "stale" : "cached", + formulaCount: count, + lastCalculatedRevision: null, + warning: count > 0 + ? "Formula results are cached values; this engine does not recalculate formulas." + : null, + }; +} + +function operationAudit(operation, action, targetOperationId = null) { + return { + id: operation.id, + type: action || operation.type, + actor: operation.actor, + intent: operation.intent || null, + summary: operation.summary || null, + sheetId: operation.sheetId || null, + a1: operation.a1 || null, + cellCount: operation.cellCount || 0, + baseRevision: operation.baseRevision, + revision: operation.revision, + targetOperationId, + createdAt: operation.createdAt, + }; +} + +function appendHistory(workbook, entry) { + workbook.history.push(entry); + if (workbook.history.length > MAX_HISTORY) { + workbook.history.splice(0, workbook.history.length - MAX_HISTORY); + } +} + +function recordOperation(workbook, descriptor) { + const baseRevision = workbook.revision; + const invalidatesSourceRoundTrip = + descriptor.roundTripSafe === false && + Boolean(workbook.sourcePath) && + ["xlsx", "xlsm"].includes(String(workbook.sourceFormat || "").toLowerCase()); + const fidelityBefore = invalidatesSourceRoundTrip + ? cloneJson(workbook.fidelity) + : null; + workbook.revision += 1; + const operation = { + id: newId("op"), + type: descriptor.type, + actor: descriptor.actor || "user", + intent: descriptor.intent || null, + summary: descriptor.summary || null, + sheetId: descriptor.sheetId || null, + a1: descriptor.a1 || null, + cellCount: descriptor.cellCount || 0, + baseRevision, + revision: workbook.revision, + createdAt: nowIso(), + roundTripSafe: descriptor.roundTripSafe !== false, + contentChanged: descriptor.contentChanged !== false, + change: descriptor.change, + }; + workbook.undoStack.push(operation); + if (workbook.undoStack.length > MAX_UNDO_STACK) { + workbook.undoStack.splice(0, workbook.undoStack.length - MAX_UNDO_STACK); + } + workbook.redoStack = []; + appendHistory(workbook, operationAudit(operation)); + workbook.dirty = true; + if (invalidatesSourceRoundTrip && workbook.fidelity) { + workbook.fidelity.canRoundTrip = false; + if (descriptor.structureChanged !== false) workbook.fidelity.structureChanged = true; + workbook.fidelity.warning = descriptor.fidelityWarning || + "Workbook structure changed and cannot be patched into the source package losslessly. Export requires explicit fidelity-loss acknowledgement."; + operation.fidelityBefore = fidelityBefore; + operation.fidelityAfter = cloneJson(workbook.fidelity); + } + refreshCalculationStatus(workbook, operation.contentChanged); + return operation; +} + +function setSheetCell(sheet, row, col, cell) { + assertCellCoordinates(row, col, "Worksheet cell"); + const key = cellKey(row, col); + if (!cell) { + delete sheet.cells[key]; + return; + } + if (row >= sheet.rows) sheet.rows = row + 1; + if (col >= sheet.cols) sheet.cols = col + 1; + sheet.cells[key] = cloneCell(cell); +} + +function captureWorkbookContent(workbook) { + return cloneJson({ + title: workbook.title, + sheets: workbook.sheets, + activeSheetId: workbook.activeSheetId, + focus: workbook.focus, + path: workbook.path, + sourcePath: workbook.sourcePath, + sourceFormat: workbook.sourceFormat, + sourceFingerprint: workbook.sourceFingerprint, + fidelity: workbook.fidelity, + }); +} + +function restoreWorkbookContent(workbook, state) { + workbook.title = state.title; + workbook.sheets = cloneJson(state.sheets); + workbook.activeSheetId = state.activeSheetId; + workbook.focus = cloneJson(state.focus); + if (Object.prototype.hasOwnProperty.call(state, "path")) workbook.path = state.path; + if (Object.prototype.hasOwnProperty.call(state, "sourcePath")) workbook.sourcePath = state.sourcePath; + if (Object.prototype.hasOwnProperty.call(state, "sourceFormat")) workbook.sourceFormat = state.sourceFormat; + if (Object.prototype.hasOwnProperty.call(state, "sourceFingerprint")) { + workbook.sourceFingerprint = cloneJson(state.sourceFingerprint); + } + if (state.fidelity) workbook.fidelity = cloneJson(state.fidelity); +} + +function applyOperationChange(workbook, operation, direction) { + const change = operation.change || {}; + const useAfter = direction === "after"; + if (change.kind === "cells") { + const sheet = getSheet(workbook, change.sheetId); + for (const cell of change.cells || []) { + setSheetCell(sheet, cell.r, cell.c, useAfter ? cell.after : cell.before); + } + const size = useAfter ? change.afterSize : change.beforeSize; + if (size) { + sheet.rows = size.rows; + sheet.cols = size.cols; + } + return; + } + if (change.kind === "sheet") { + const snapshot = cloneJson(useAfter ? change.after : change.before); + const index = workbook.sheets.findIndex((sheet) => sheet.id === change.sheetId); + if (index < 0) throw new Error(`Cannot restore missing sheet: ${change.sheetId}`); + workbook.sheets[index] = snapshot; + return; + } + if (change.kind === "sheet-name") { + getSheet(workbook, change.sheetId).name = useAfter ? change.after : change.before; + return; + } + if (change.kind === "layout") { + getSheet(workbook, change.sheetId).layout = cloneJson(useAfter ? change.after : change.before); + return; + } + if (change.kind === "compound") { + for (const part of change.changes || []) { + applyOperationChange(workbook, { change: part }, direction); + } + return; + } + if (change.kind === "workbook") { + restoreWorkbookContent(workbook, useAfter ? change.after : change.before); + return; + } + throw new Error(`Unsupported reversible operation kind: ${change.kind || "unknown"}`); +} + +function undo(input = {}) { + const workspacePath = requireWorkspace(input); + const workbookId = requireWorkbookId(input); + const workbook = loadOrGet(workspacePath, workbookId); + assertWritable(workbook, "undo"); + assertExpectedRevision(workbook, input, "undo"); + const target = workbook.undoStack[workbook.undoStack.length - 1]; + if (!target) { + return { summary: "Nothing to undo", operation: null, meta: metaOf(workbook) }; + } + applyOperationChange(workbook, target, "before"); + if (target.fidelityBefore) workbook.fidelity = cloneJson(target.fidelityBefore); + workbook.undoStack.pop(); + workbook.proposal = null; + const baseRevision = workbook.revision; + workbook.revision += 1; + workbook.redoStack.push(target); + const audit = { + id: newId("op"), + type: "undo", + actor: input.actor || "user", + intent: input.intent || `Undo ${target.type}`, + summary: `Undid ${target.type}`, + sheetId: target.sheetId || null, + a1: target.a1 || null, + cellCount: target.cellCount || 0, + baseRevision, + revision: workbook.revision, + createdAt: nowIso(), + }; + appendHistory(workbook, operationAudit(audit, "undo", target.id)); + workbook.dirty = true; + refreshCalculationStatus(workbook, target.contentChanged !== false); + const saved = persist(workspacePath, workbook); + return { summary: audit.summary, operation: operationAudit(audit, "undo", target.id), meta: metaOf(saved) }; +} + +function redo(input = {}) { + const workspacePath = requireWorkspace(input); + const workbookId = requireWorkbookId(input); + const workbook = loadOrGet(workspacePath, workbookId); + assertWritable(workbook, "redo"); + assertExpectedRevision(workbook, input, "redo"); + const target = workbook.redoStack[workbook.redoStack.length - 1]; + if (!target) { + return { summary: "Nothing to redo", operation: null, meta: metaOf(workbook) }; + } + applyOperationChange(workbook, target, "after"); + if (target.fidelityAfter) workbook.fidelity = cloneJson(target.fidelityAfter); + workbook.redoStack.pop(); + workbook.proposal = null; + const baseRevision = workbook.revision; + workbook.revision += 1; + workbook.undoStack.push(target); + const audit = { + id: newId("op"), + type: "redo", + actor: input.actor || "user", + intent: input.intent || `Redo ${target.type}`, + summary: `Redid ${target.type}`, + sheetId: target.sheetId || null, + a1: target.a1 || null, + cellCount: target.cellCount || 0, + baseRevision, + revision: workbook.revision, + createdAt: nowIso(), + }; + appendHistory(workbook, operationAudit(audit, "redo", target.id)); + workbook.dirty = true; + refreshCalculationStatus(workbook, target.contentChanged !== false); + const saved = persist(workspacePath, workbook); + return { summary: audit.summary, operation: operationAudit(audit, "redo", target.id), meta: metaOf(saved) }; +} + +function getHistory(input = {}) { + const workspacePath = requireWorkspace(input); + const workbookId = requireWorkbookId(input); + const workbook = loadOrGet(workspacePath, workbookId); + const requested = input.limit == null ? 50 : Number(input.limit); + const limit = Math.max(1, Math.min(200, Number.isFinite(requested) ? Math.floor(requested) : 50)); + const history = workbook.history.slice(-limit).reverse(); + return { + summary: `${history.length} operation(s), revision ${workbook.revision}`, + revision: workbook.revision, + canUndo: workbook.undoStack.length > 0, + canRedo: workbook.redoStack.length > 0, + history, + entries: history, + }; +} + +function getSession(workbookId) { + const session = sessions.get(workbookId); + if (!session) { + throw new Error( + `Workbook session not found: ${workbookId}. Open or create a workbook first.` + ); + } + return session; +} + +function loadOrGet(workspacePath, workbookId) { + if (sessions.has(workbookId)) { + const session = sessions.get(workbookId); + if (session.workspacePath === workspacePath) { + return assertWorkbookWithinLimits(session.workbook); + } + } + const workbook = assertWorkbookWithinLimits(loadJson(workspacePath, workbookId)); + reconcileCalculationStatus(workbook); + sessions.set(workbookId, { workspacePath, workbook }); + return workbook; +} + +function resolveSheet(workbook, sheetId, a1Ref) { + let qualifiedSheet = null; + if (a1Ref) { + const parsed = parseA1(a1Ref); + if (parsed.sheet) { + qualifiedSheet = findSheetByName(workbook, parsed.sheet) + || workbook.sheets.find((sheet) => sheet.id === parsed.sheet) + || null; + if (!qualifiedSheet) throw new Error(`Sheet not found: ${parsed.sheet}`); + } + } + if (sheetId) { + const explicitSheet = getSheet(workbook, sheetId); + if (qualifiedSheet && qualifiedSheet.id !== explicitSheet.id) { + throw new Error( + `[SHEET_QUALIFIER_CONFLICT] sheetId targets ${explicitSheet.name}, but a1 targets ${qualifiedSheet.name}. Use one consistent sheet target.` + ); + } + return explicitSheet; + } + if (qualifiedSheet) return qualifiedSheet; + return getSheet(workbook, workbook.activeSheetId); +} + +function resolveRange(workbook, input = {}) { + const sheet = resolveSheet(workbook, input.sheetId, input.a1); + let range; + if (input.a1) { + range = parseA1(input.a1); + } else if (workbook.focus && workbook.focus.sheetId === sheet.id && workbook.focus.a1) { + range = parseA1(workbook.focus.a1); + } else { + range = { sheet: null, r1: 0, c1: 0, r2: 0, c2: 0 }; + } + range = clampRange(range, sheet.rows, sheet.cols); + return { sheet, range, a1: formatA1(range.r1, range.c1, range.r2, range.c2) }; +} + +function cellDisplay(cell) { + if (!cell) return null; + const result = cellHasFormulaEvidence(cell) + ? { + v: cell.v != null ? cell.v : null, + f: typeof cell.f === "string" && cell.f ? cell.f : null, + t: cell.t || "f", + formulaEvidence: true, + formulaType: cell.formulaType || cell.formulaGroupType || null, + formulaRef: cell.formulaRef || cell.formulaGroupRef || null, + } + : { + v: cell.v != null ? cell.v : null, + t: cell.t || (typeof cell.v === "number" ? "n" : "s"), + }; + if (cell.style) result.style = cloneJson(cell.style); + return result; +} + +function valueCell(value) { + if (value === null || value === "") return {}; + if (typeof value === "number") return { v: value, t: "n" }; + if (typeof value === "boolean") return { v: value, t: "b" }; + const text = String(value); + const num = Number(text); + if (text.trim() !== "" && !Number.isNaN(num) && /^-?\d+(\.\d+)?([eE][+-]?\d+)?$/.test(text.trim())) { + return { v: num, t: "n" }; + } + return { v: text, t: "s" }; +} + +function cellFromPatch(before, patch) { + const previous = cloneCell(before) || {}; + let next = cloneCell(before) || {}; + const hasFormula = Object.prototype.hasOwnProperty.call(patch, "formula") && patch.formula != null; + const hasValue = Object.prototype.hasOwnProperty.call(patch, "value") && patch.value !== undefined; + if (hasFormula) { + let f = String(patch.formula).trim(); + if (f.startsWith("=")) f = f.slice(1); + next = { f, t: "f", formulaEvidence: true }; + if (hasValue) next.v = patch.value; + } else if (hasValue) { + next = valueCell(patch.value); + } + const style = normalizeStyle(patch.style, patch.styleRole, previous.style || null); + if (style) next.style = style; + else delete next.style; + if (previous._sourceStyleIndex != null) next._sourceStyleIndex = previous._sourceStyleIndex; + const publicKeys = Object.keys(next).filter((key) => key !== "_sourceStyleIndex"); + return publicKeys.length ? next : null; +} + +function setCell(sheet, row, col, patch) { + assertCellCoordinates(row, col, "Worksheet cell"); + if (row >= sheet.rows) sheet.rows = row + 1; + if (col >= sheet.cols) sheet.cols = col + 1; + const key = cellKey(row, col); + const next = cellFromPatch(sheet.cells[key] || null, patch); + setSheetCell(sheet, row, col, next); + return next; +} + +function metaOf(workbook) { + reconcileCalculationStatus(workbook); + const count = formulaCount(workbook); + return { + workbookId: workbook.workbookId, + title: workbook.title, + path: workbook.path, + sourcePath: workbook.sourcePath || null, + sourceFormat: workbook.sourceFormat || null, + sourceFingerprint: cloneJson(workbook.sourceFingerprint), + lastExportPath: workbook.lastExportPath || null, + lastExportedRevision: Number.isSafeInteger(workbook.lastExportedRevision) + ? workbook.lastExportedRevision + : null, + dirty: Boolean(workbook.dirty), + revision: workbook.revision, + mode: workbook.mode, + activeSheetId: workbook.activeSheetId, + sheetCount: workbook.sheets.length, + sheets: workbook.sheets.map((s) => ({ + id: s.id, + name: s.name, + rows: s.rows, + cols: s.cols, + cellCount: Object.keys(s.cells || {}).length, + layout: cloneJson(s.layout), + })), + focus: workbook.focus, + hasProposal: Boolean(workbook.proposal), + proposalId: workbook.proposal ? workbook.proposal.id : null, + proposalBaseRevision: workbook.proposal ? workbook.proposal.baseRevision : null, + capabilities: { + revisionedEdits: true, + undoRedo: true, + canUndo: workbook.undoStack.length > 0, + canRedo: workbook.redoStack.length > 0, + history: true, + partialProposalAccept: true, + localPatch: true, + inspectModeEnforced: true, + atomicStoreWrites: true, + sourceOverwriteProtected: true, + formulaRecalculation: false, + formulaStaticLint: true, + cellStyles: true, + semanticStyleRoles: Object.keys(STYLE_ROLES), + numberFormats: true, + layoutMetadata: true, + styleInterpretation: "basic-rgb-font-fill-border-alignment-number-format", + unsupportedStyleInterpretation: ["theme colors", "indexed colors", "conditional formatting", "named styles"], + styleSourcePatch: !workbook.sourcePath, + layoutSourcePatch: !workbook.sourcePath, + sourcePreservingStylePatch: !workbook.sourcePath, + sourcePreservingLayoutPatch: !workbook.sourcePath, + losslessRoundTrip: Boolean(workbook.fidelity?.canRoundTrip), + structuralEditsAllowed: count === 0 && workbook.mode !== "inspect", + }, + fidelity: cloneJson(workbook.fidelity), + calculationStatus: cloneJson(workbook.calculationStatus), + createdAt: workbook.createdAt, + updatedAt: workbook.updatedAt, + }; +} + +function viewportSummary(workbook, sheet, maxRows = 20, maxCols = 10) { + const r2 = Math.min(sheet.rows - 1, maxRows - 1); + const c2 = Math.min(sheet.cols - 1, maxCols - 1); + const values = []; + for (let r = 0; r <= r2; r += 1) { + const row = []; + for (let c = 0; c <= c2; c += 1) { + const cell = sheet.cells[cellKey(r, c)]; + row.push(cell && cell.v != null ? cell.v : cell && cell.f ? `=${cell.f}` : ""); + } + values.push(row); + } + return { + sheetId: sheet.id, + sheetName: sheet.name, + a1: formatA1(0, 0, r2, c2), + values, + }; +} + +function proposalSummary(proposal) { + if (!proposal) return null; + return { + id: proposal.id, + sheetId: proposal.sheetId, + a1: proposal.a1, + cellCount: (proposal.cells || []).length, + baseRevision: proposal.baseRevision, + intent: proposal.intent || null, + validation: cloneJson(proposal.validation), + layout: cloneJson(proposal.layout), + createdAt: proposal.createdAt, + }; +} + +function proposalCellResult(proposal, resultCellLimit) { + const source = proposal?.cells || []; + let limit = source.length; + if (resultCellLimit != null) { + limit = Number(resultCellLimit); + if (!Number.isSafeInteger(limit) || limit < 0 || limit > MAX_PROPOSAL_CELLS) { + throw new Error(`resultCellLimit must be a safe integer between 0 and ${MAX_PROPOSAL_CELLS}`); + } + } + const selected = source.slice(0, limit).map((cell) => ({ + row: cell.r, + col: cell.c, + a1: formatA1(cell.r, cell.c), + before: cellDisplay(cell.before), + after: cellDisplay(cell.after), + })); + return { + cells: selected, + totalCellCount: source.length, + cellDetailsTruncated: selected.length < source.length, + }; +} + +function proposalRange(cells) { + let r1 = Infinity; + let c1 = Infinity; + let r2 = -Infinity; + let c2 = -Infinity; + for (const cell of cells || []) { + r1 = Math.min(r1, cell.r); + c1 = Math.min(c1, cell.c); + r2 = Math.max(r2, cell.r); + c2 = Math.max(c2, cell.c); + } + return Number.isFinite(r1) ? formatA1(r1, c1, r2, c2) : null; +} + +function validateLayoutBands(items, sizeKey, maximum, label) { + if (!Array.isArray(items)) throw new Error(`layout.${label} must be an array`); + if (items.length > MAX_LAYOUT_BANDS) throw new Error(`layout.${label} cannot exceed ${MAX_LAYOUT_BANDS} bands`); + let covered = 0; + for (const item of items) { + if (!item || typeof item !== "object") throw new Error(`layout.${label} entries must be objects`); + const start = Number(item.start); + const end = item.end == null ? start : Number(item.end); + if (!Number.isSafeInteger(start) || !Number.isSafeInteger(end) || start < 0 || end < start || end >= maximum) { + throw new Error(`layout.${label} start/end must be 0-based inclusive indexes within the current or proposed sheet dimensions`); + } + if (item[sizeKey] == null && item.autoFit !== true) { + throw new Error(`layout.${label} entries require ${sizeKey} or autoFit=true`); + } + if (item[sizeKey] != null) { + const size = Number(item[sizeKey]); + const upper = sizeKey === "width" ? 255 : 409; + if (!Number.isFinite(size) || size <= 0 || size > upper) { + throw new Error(`layout.${label}.${sizeKey} must be greater than 0 and at most ${upper}`); + } + } + covered += end - start + 1; + if (label === "rows" && covered > MAX_CUSTOM_LAYOUT_ROWS) { + throw new Error(`layout.rows cannot materialize more than ${MAX_CUSTOM_LAYOUT_ROWS} custom-height rows`); + } + } +} + +function mergeLayoutBands(current, changes, sizeKey) { + let result = cloneJson(current) || []; + for (const change of changes) { + const start = Number(change.start); + const end = change.end == null ? start : Number(change.end); + const preserved = []; + for (const existing of result) { + if (existing.end < start || existing.start > end) { + preserved.push(existing); + continue; + } + if (existing.start < start) preserved.push({ ...existing, end: start - 1 }); + if (existing.end > end) preserved.push({ ...existing, start: end + 1 }); + } + const next = { start, end }; + if (change[sizeKey] != null) next[sizeKey] = Number(change[sizeKey]); + if (change.autoFit === true) next.autoFit = true; + result = [...preserved, next]; + } + return result.sort((a, b) => a.start - b.start || a.end - b.end); +} + +function displayWidth(value) { + let width = 0; + for (const character of String(value == null ? "" : value)) { + width += character.codePointAt(0) > 255 ? 2 : 1; + } + return width; +} + +function autoFitColumnWidth(sheet, start, end, pendingCells) { + const pending = new Map((pendingCells || []).map((cell) => [`${cell.r},${cell.c}`, cell.after])); + let longest = 0; + const keys = new Set([...Object.keys(sheet.cells || {}), ...pending.keys()]); + for (const key of keys) { + const [row, col] = key.split(",").map(Number); + if (col < start || col > end) continue; + const cell = pending.has(key) ? pending.get(key) : sheet.cells[key]; + const display = cell?.v != null ? cell.v : cell?.f ? `=${cell.f}` : ""; + for (const line of String(display).split(/\r?\n/)) longest = Math.max(longest, displayWidth(line)); + } + return Math.max(10, Math.min(60, longest ? longest + 2 : 18)); +} + +function autoFitRowHeight(sheet, start, end, pendingCells) { + const pending = new Map((pendingCells || []).map((cell) => [`${cell.r},${cell.c}`, cell.after])); + let lines = 1; + const keys = new Set([...Object.keys(sheet.cells || {}), ...pending.keys()]); + for (const key of keys) { + const [row] = key.split(",").map(Number); + if (row < start || row > end) continue; + const cell = pending.has(key) ? pending.get(key) : sheet.cells[key]; + const display = cell?.v != null ? cell.v : cell?.f ? `=${cell.f}` : ""; + lines = Math.max(lines, String(display).split(/\r?\n/).length); + } + return Math.max(24, Math.min(120, lines * 15)); +} + +function layoutFromPatch(sheet, patch, pendingCells = []) { + if (patch == null) return null; + if (typeof patch !== "object" || Array.isArray(patch)) throw new Error("layout must be an object"); + const before = normalizeSheetLayout(sheet.layout); + const next = cloneJson(before); + const projectedRows = Math.max(sheet.rows, ...pendingCells.map((cell) => cell.r + 1)); + const projectedColumns = Math.max(sheet.cols, ...pendingCells.map((cell) => cell.c + 1)); + if (Object.prototype.hasOwnProperty.call(patch, "columns")) { + validateLayoutBands(patch.columns, "width", projectedColumns, "columns"); + const columns = patch.columns.map((item) => ({ + ...item, + width: item.width == null && item.autoFit === true + ? autoFitColumnWidth(sheet, Number(item.start), Number(item.end == null ? item.start : item.end), pendingCells) + : item.width, + })); + next.columns = columns.length === 0 ? [] : mergeLayoutBands(next.columns, columns, "width"); + } + if (Object.prototype.hasOwnProperty.call(patch, "rows")) { + validateLayoutBands(patch.rows, "height", projectedRows, "rows"); + const rows = patch.rows.map((item) => ({ + ...item, + height: item.height == null && item.autoFit === true + ? autoFitRowHeight(sheet, Number(item.start), Number(item.end == null ? item.start : item.end), pendingCells) + : item.height, + })); + next.rows = rows.length === 0 ? [] : mergeLayoutBands(next.rows, rows, "height"); + } + if (Object.prototype.hasOwnProperty.call(patch, "freezePanes")) { + if (!patch.freezePanes || typeof patch.freezePanes !== "object") { + throw new Error("layout.freezePanes must be an object"); + } + const rows = patch.freezePanes.rows == null ? next.freezePanes.rows : Number(patch.freezePanes.rows); + const columns = patch.freezePanes.columns == null ? next.freezePanes.columns : Number(patch.freezePanes.columns); + if (!Number.isSafeInteger(rows) || rows < 0 || rows >= projectedRows) { + throw new Error(`layout.freezePanes.rows must be a non-negative safe integer smaller than the projected sheet row count (${projectedRows})`); + } + if (!Number.isSafeInteger(columns) || columns < 0 || columns >= projectedColumns) { + throw new Error(`layout.freezePanes.columns must be a non-negative safe integer smaller than the projected sheet column count (${projectedColumns})`); + } + next.freezePanes = { rows, columns }; + } + if (Object.prototype.hasOwnProperty.call(patch, "autoFilter")) { + if (patch.autoFilter == null) { + next.autoFilter = null; + } else if (typeof patch.autoFilter === "object" && typeof patch.autoFilter.a1 === "string") { + const parsed = parseA1(patch.autoFilter.a1); + if (parsed.sheet) { + const token = String(parsed.sheet).toLowerCase(); + if (token !== String(sheet.id).toLowerCase() && token !== String(sheet.name).toLowerCase()) { + throw new Error(`layout.autoFilter.a1 targets another sheet: ${parsed.sheet}`); + } + } + next.autoFilter = { a1: formatA1(parsed.r1, parsed.c1, parsed.r2, parsed.c2) }; + } else { + throw new Error("layout.autoFilter must be null or {a1}"); + } + } + return { before, after: normalizeSheetLayout(next) }; +} + +function cellChangesStyle(cells) { + return (cells || []).some((cell) => !stableEqual(cell.before?.style, cell.after?.style)); +} + +function cellChangesContent(cells) { + return (cells || []).some((cell) => !cellsContentEqual(cell.before, cell.after)); +} + +function lintFormula(formula, row, col) { + const cell = formatA1(row, col); + const text = String(formula == null ? "" : formula).replace(/^=/, "").trim(); + const errors = []; + const warnings = []; + if (!text) { + errors.push({ code: "FORMULA_EMPTY", cell, message: `${cell} has an empty formula.` }); + return { errors, warnings }; + } + let depth = 0; + let inString = false; + for (let index = 0; index < text.length; index += 1) { + const character = text[index]; + if (character === '"') { + if (inString && text[index + 1] === '"') { + index += 1; + } else { + inString = !inString; + } + continue; + } + if (inString) continue; + if (character === "(") depth += 1; + if (character === ")") depth -= 1; + if (depth < 0) break; + } + if (inString) { + errors.push({ code: "FORMULA_QUOTE_UNBALANCED", cell, message: `${cell} has an unbalanced string quote.` }); + } + if (depth !== 0) { + errors.push({ code: "FORMULA_PAREN_UNBALANCED", cell, message: `${cell} has unbalanced parentheses.` }); + } + const normalizedSelf = cell.toUpperCase(); + const references = text.match(/(? reference.replaceAll("$", "").toUpperCase() === normalizedSelf)) { + errors.push({ code: "FORMULA_SELF_REFERENCE", cell, message: `${cell} directly references itself and creates an obvious circular reference.` }); + } + if (/\[[^\]]+\]|(?:https?|ftp):\/\/|\\\\|\b(?:WEBSERVICE|FILTERXML|RTD)\s*\(/i.test(text)) { + warnings.push({ code: "FORMULA_EXTERNAL_LINK", cell, message: `${cell} contains an external-link or external-data pattern. Review trust and portability before accepting.` }); + } + return { errors, warnings }; +} + +function lintPatchFormulas(cells) { + const errors = []; + const warnings = []; + let checkedFormulaCount = 0; + for (const cell of cells || []) { + if (!cellHasFormulaEvidence(cell.after)) continue; + if (cellHasFormulaEvidence(cell.before) && cell.before.f === cell.after.f) continue; + checkedFormulaCount += 1; + const result = lintFormula(cell.after.f, cell.r, cell.c); + errors.push(...result.errors); + warnings.push(...result.warnings); + } + return { + status: errors.length > 0 ? "invalid" : warnings.length > 0 ? "warning" : "valid", + checkedFormulaCount, + recalculated: false, + calculationEngine: "none", + note: checkedFormulaCount > 0 + ? "Static syntax and risk checks only; formulas were not calculated and cached results were not verified." + : "No new or changed formulas in this patch; no calculation was performed.", + errors, + warnings, + }; +} + +function validatePatchCells(sheet, cells) { + const seen = new Set(); + const errors = []; + const warnings = []; + let overwriteCount = 0; + let formulaCountAfter = 0; + let noOpCount = 0; + for (const cell of cells || []) { + const key = cellKey(cell.r, cell.c); + if (seen.has(key)) { + errors.push(`Duplicate cell ${formatA1(cell.r, cell.c)}`); + } + seen.add(key); + if (cell.before && !cellsEqual(cell.before, cell.after)) overwriteCount += 1; + if (cellHasFormulaEvidence(cell.after)) formulaCountAfter += 1; + if (cellsEqual(cell.before, cell.after)) noOpCount += 1; + } + if (overwriteCount > 0) warnings.push(`${overwriteCount} non-empty cell(s) will be overwritten.`); + if (formulaCountAfter > 0) { + warnings.push(`${formulaCountAfter} formula cell(s) cannot be recalculated by this engine.`); + } + const formulaLint = lintPatchFormulas(cells); + errors.push(...formulaLint.errors.map((issue) => `${issue.code} ${issue.message}`)); + warnings.push(...formulaLint.warnings.map((issue) => `${issue.code} ${issue.message}`)); + if (noOpCount > 0) warnings.push(`${noOpCount} cell(s) already match the proposal.`); + return { + status: errors.length > 0 ? "invalid" : warnings.length > 0 ? "warning" : "valid", + checkedAt: nowIso(), + cellCount: (cells || []).length, + overwriteCount, + formulaCount: formulaCountAfter, + noOpCount, + errors, + warnings, + formulaLint, + }; +} + +function rebaseProposal(workbook, excluded = new Set(), layoutAccepted = false) { + const proposal = workbook.proposal; + if (!proposal) return; + const sheet = getSheet(workbook, proposal.sheetId); + const remaining = (proposal.cells || []).filter( + (cell) => !excluded.has(`${proposal.sheetId}:${cell.r},${cell.c}`) + ); + if (layoutAccepted) proposal.layout = null; + if (proposal.layout && !stableEqual(sheet.layout, proposal.layout.before)) { + workbook.proposal = null; + return; + } + if (remaining.length === 0 && !proposal.layout) { + workbook.proposal = null; + return; + } + const conflicts = remaining.filter( + (cell) => !cellsEqual(sheet.cells[cellKey(cell.r, cell.c)] || null, cell.before) + ); + if (conflicts.length > 0) { + workbook.proposal = null; + return; + } + proposal.cells = remaining; + proposal.a1 = proposalRange(remaining); + proposal.baseRevision = workbook.revision; + proposal.validation = validatePatchCells(sheet, remaining); + proposal.validation.layoutChanged = Boolean(proposal.layout); + proposal.validation.layoutPartialAccept = proposal.layout + ? "Layout is applied only when the proposal is accepted without cellRefs." + : null; +} + +function clearProposalOverlap(workbook, sheetId, row, col) { + if (!workbook.proposal) return; + if (workbook.proposal.sheetId !== sheetId) return; + const remaining = (workbook.proposal.cells || []).filter( + (c) => !(c.r === row && c.c === col) + ); + if (remaining.length === 0) { + workbook.proposal = null; + } else if (remaining.length !== workbook.proposal.cells.length) { + workbook.proposal = { ...workbook.proposal, cells: remaining }; + } +} + +function clearProposalIfOverlapsRange(workbook, sheetId, range) { + if (!workbook.proposal) return; + if (workbook.proposal.sheetId !== sheetId) return; + const hits = (workbook.proposal.cells || []).some( + (c) => c.r >= range.r1 && c.r <= range.r2 && c.c >= range.c1 && c.c <= range.c2 + ); + if (hits) { + workbook.proposal = null; + } +} + +function openWorkbook(input = {}) { + const workspacePath = requireWorkspace(input); + if (!input.path || typeof input.path !== "string") { + throw new Error("path is required to open a workbook"); + } + const filePath = resolveConsumerPath(input, workspacePath, input.path, "openWorkbook"); + + // Reuse the existing store id when this file was opened before so the + // surface and agent keep pointing at one workbook per file. + const requestedId = input.workbookId == null ? null : validateWorkbookId(input.workbookId); + const foundId = findWorkbookIdByPath(workspacePath, filePath) + || listWorkbookMetas(workspacePath).find((meta) => + pathsReferToSameFile(meta.sourcePath || meta.path, filePath) + )?.workbookId + || null; + if (requestedId && foundId && requestedId !== foundId) { + throw new Error( + `[WORKBOOK_PATH_ALREADY_OPEN] ${filePath} already belongs to live workbook ${foundId}, not ${requestedId}. Resume the existing workbook or explicitly reload it.` + ); + } + const existingId = requestedId || foundId; + + if (existingId) { + let existing = null; + try { + existing = loadOrGet(workspacePath, existingId); + } catch (error) { + if (!/^Workbook store not found:/.test(String(error.message || ""))) throw error; + if (foundId || !requestedId) throw error; + } + if (existing) { + const associatedPath = existing.sourcePath || existing.path; + if ( + !associatedPath || + !pathsReferToSameFile(associatedPath, filePath) + ) { + throw new Error( + `[WORKBOOK_ID_PATH_MISMATCH] Workbook ${existingId} is already associated with ${associatedPath || "an internal workbook"}, not ${filePath}.` + ); + } + const sheet = getSheet(existing, existing.activeSheetId); + return { + summary: `Resumed live workbook "${existing.title}" at revision ${existing.revision}; external source was not re-read. Use reloadWorkbook with expectedRevision to reload explicitly.`, + resumed: true, + meta: metaOf(existing), + viewport: viewportSummary(existing, sheet), + }; + } + } + + const workbook = readWorkbookFile(filePath, { + title: input.title, + workbookId: requestedId || undefined, + }); + ensureDir(workbookDir(workspacePath, workbook.workbookId)); + const saved = persist(workspacePath, workbook); + const sheet = getSheet(saved, saved.activeSheetId); + return { + summary: `Opened workbook "${saved.title}" (${saved.sheets.length} sheet(s)) from ${filePath}`, + resumed: false, + meta: metaOf(saved), + viewport: viewportSummary(saved, sheet), + }; +} + +function createWorkbook(input = {}) { + const workspacePath = requireWorkspace(input); + const rows = requirePositiveSafeInteger(input.rows, 50, "rows"); + const cols = requirePositiveSafeInteger(input.cols, 26, "cols"); + assertSheetDimensions(rows, cols, "New worksheet"); + const workbook = createEmpty({ + title: input.title || "Untitled Workbook", + rows, + cols, + sheetName: input.sheetName || "Sheet1", + }); + ensureDir(workbookDir(workspacePath, workbook.workbookId)); + const saved = persist(workspacePath, workbook); + const sheet = getSheet(saved, saved.activeSheetId); + return { + summary: `Created empty workbook "${saved.title}" (${sheet.rows}x${sheet.cols})`, + meta: metaOf(saved), + viewport: viewportSummary(saved, sheet), + }; +} + +function getMeta(input = {}) { + const workspacePath = requireWorkspace(input); + const workbookId = requireWorkbookId(input); + const workbook = loadOrGet(workspacePath, workbookId); + return { + summary: `Workbook "${workbook.title}" — ${workbook.sheets.length} sheet(s), dirty=${workbook.dirty}`, + meta: metaOf(workbook), + }; +} + +function listSheets(input = {}) { + const workspacePath = requireWorkspace(input); + const workbookId = requireWorkbookId(input); + const workbook = loadOrGet(workspacePath, workbookId); + return { + summary: `${workbook.sheets.length} sheet(s) in "${workbook.title}"`, + activeSheetId: workbook.activeSheetId, + sheets: workbook.sheets.map((s) => ({ + id: s.id, + name: s.name, + rows: s.rows, + cols: s.cols, + cellCount: Object.keys(s.cells || {}).length, + layout: cloneJson(s.layout), + })), + }; +} + +function switchSheet(input = {}) { + const workspacePath = requireWorkspace(input); + const workbookId = requireWorkbookId(input); + const workbook = loadOrGet(workspacePath, workbookId); + let sheet = null; + if (input.sheetId) { + sheet = getSheet(workbook, input.sheetId); + } else if (input.sheetName) { + sheet = findSheetByName(workbook, input.sheetName); + if (!sheet) throw new Error(`Sheet not found: ${input.sheetName}`); + } else { + throw new Error("sheetId or sheetName is required"); + } + workbook.activeSheetId = sheet.id; + workbook.focus = { + sheetId: sheet.id, + a1: workbook.focus && workbook.focus.sheetId === sheet.id ? workbook.focus.a1 : "A1", + kind: workbook.focus && workbook.focus.sheetId === sheet.id ? workbook.focus.kind : "cell", + }; + const saved = persist(workspacePath, workbook); + return { + summary: `Switched to sheet "${sheet.name}"`, + meta: metaOf(saved), + viewport: viewportSummary(saved, sheet), + }; +} + +function getFocus(input = {}) { + const workspacePath = requireWorkspace(input); + const workbookId = requireWorkbookId(input); + const workbook = loadOrGet(workspacePath, workbookId); + const sheet = getSheet(workbook, workbook.focus.sheetId); + return { + summary: `Focus ${sheet.name}!${workbook.focus.a1} (${workbook.focus.kind})`, + focus: { + ...workbook.focus, + sheetName: sheet.name, + }, + mode: workbook.mode, + revision: workbook.revision, + }; +} + +function setFocus(input = {}) { + const workspacePath = requireWorkspace(input); + const workbookId = requireWorkbookId(input); + const workbook = loadOrGet(workspacePath, workbookId); + if (!input.a1) { + throw new Error("a1 is required for setFocus"); + } + const sheet = resolveSheet(workbook, input.sheetId, input.a1); + const range = clampRange(parseA1(input.a1), sheet.rows, sheet.cols); + const a1 = formatA1(range.r1, range.c1, range.r2, range.c2); + let kind = input.kind; + if (!kind) { + kind = range.r1 === range.r2 && range.c1 === range.c2 ? "cell" : "range"; + } + if (input.mode != null) { + if (!["inspect", "edit", "author"].includes(input.mode)) { + throw new Error("mode must be one of: inspect, edit, author"); + } + workbook.mode = normalizeMode(input.mode); + } + workbook.focus = { sheetId: sheet.id, a1, kind }; + workbook.activeSheetId = sheet.id; + const saved = persist(workspacePath, workbook); + return { + summary: `Focus set to ${sheet.name}!${a1}`, + focus: { ...saved.focus, sheetName: sheet.name }, + meta: metaOf(saved), + }; +} + +function setMode(input = {}) { + const workspacePath = requireWorkspace(input); + const workbookId = requireWorkbookId(input); + const workbook = loadOrGet(workspacePath, workbookId); + if (!input.mode || !["inspect", "edit", "author"].includes(input.mode)) { + throw new Error("mode must be one of: inspect, edit, author"); + } + workbook.mode = normalizeMode(input.mode); + const saved = persist(workspacePath, workbook); + return { + summary: `Workbook mode set to ${saved.mode}`, + mode: saved.mode, + meta: metaOf(saved), + }; +} + +function readRange(input = {}) { + const workspacePath = requireWorkspace(input); + const workbookId = requireWorkbookId(input); + const workbook = loadOrGet(workspacePath, workbookId); + const maxCells = requirePositiveSafeInteger(input.maxCells, DEFAULT_MAX_CELLS, "maxCells"); + if (maxCells > MAX_READ_RANGE_CELLS) { + throw new Error(`[READ_CELL_LIMIT] maxCells cannot exceed ${MAX_READ_RANGE_CELLS}.`); + } + const { sheet, range, a1 } = resolveRange(workbook, input); + const count = cellCount(range.r1, range.c1, range.r2, range.c2); + if (count > maxCells) { + throw new Error( + `Range ${a1} has ${count} cells which exceeds maxCells=${maxCells}. Narrow the selection or raise maxCells.` + ); + } + + const values = []; + const formulas = []; + const cells = []; + for (let r = range.r1; r <= range.r2; r += 1) { + const rowVals = []; + for (let c = range.c1; c <= range.c2; c += 1) { + const cell = sheet.cells[cellKey(r, c)]; + if (!cell) { + rowVals.push(null); + } else { + rowVals.push(cell.v != null ? cell.v : null); + cells.push({ + row: r, + col: c, + a1: formatA1(r, c), + value: cell.v != null ? cell.v : null, + formula: typeof cell.f === "string" && cell.f ? cell.f : null, + style: cloneJson(cell.style) || null, + }); + if (cellHasFormulaEvidence(cell)) { + formulas.push({ + row: r, + col: c, + formula: typeof cell.f === "string" && cell.f ? cell.f : null, + formulaEvidence: true, + formulaType: cell.formulaType || cell.formulaGroupType || null, + formulaRef: cell.formulaRef || cell.formulaGroupRef || null, + value: cell.v != null ? cell.v : null, + }); + } + } + } + values.push(rowVals); + } + + return { + summary: `Read ${sheet.name}!${a1} (${count} cells, ${formulas.length} formulas)`, + workbookId, + revision: workbook.revision, + calculationStatus: cloneJson(workbook.calculationStatus), + sheetId: sheet.id, + sheetName: sheet.name, + a1, + rowCount: range.r2 - range.r1 + 1, + columnCount: range.c2 - range.c1 + 1, + values, + formulas, + cells, + layout: cloneJson(sheet.layout), + }; +} + +function summarizeRange(input = {}) { + const workspacePath = requireWorkspace(input); + const workbookId = requireWorkbookId(input); + const workbook = loadOrGet(workspacePath, workbookId); + const maxCells = requirePositiveSafeInteger(input.maxCells, DEFAULT_MAX_CELLS, "maxCells"); + if (maxCells > MAX_READ_RANGE_CELLS) { + throw new Error(`[READ_CELL_LIMIT] maxCells cannot exceed ${MAX_READ_RANGE_CELLS}.`); + } + const { sheet, range, a1 } = resolveRange(workbook, input); + const count = cellCount(range.r1, range.c1, range.r2, range.c2); + if (count > maxCells) { + throw new Error( + `Range ${a1} has ${count} cells which exceeds maxCells=${maxCells}. Narrow the selection or raise maxCells.` + ); + } + + let numericCount = 0; + let emptyCount = 0; + let formulaCount = 0; + let textCount = 0; + const sampleRows = []; + const headerRow = []; + + for (let r = range.r1; r <= range.r2; r += 1) { + const sample = []; + for (let c = range.c1; c <= range.c2; c += 1) { + const cell = sheet.cells[cellKey(r, c)]; + if (!cell || (cell.v == null && !cellHasFormulaEvidence(cell))) { + emptyCount += 1; + sample.push(""); + if (r === range.r1) headerRow.push(""); + continue; + } + const hasFormula = cellHasFormulaEvidence(cell); + if (hasFormula) formulaCount += 1; + if (typeof cell.v === "number") { + numericCount += 1; + } else if (cell.v != null && cell.v !== "") { + textCount += 1; + } else if (!hasFormula) { + emptyCount += 1; + } + const display = cell.v != null + ? cell.v + : cell.f + ? `=${cell.f}` + : hasFormula + ? "[formula result unavailable]" + : ""; + sample.push(display); + if (r === range.r1) headerRow.push(String(display)); + } + if (sampleRows.length < 20) { + sampleRows.push(sample); + } + } + + const headerGuess = headerRow.some((h) => h !== "" && Number.isNaN(Number(h))); + const sampleTsv = sampleRows.map((row) => row.map((v) => String(v)).join("\t")).join("\n"); + + return { + summary: `Summary of ${sheet.name}!${a1}: numeric=${numericCount}, empty=${emptyCount}, formulas=${formulaCount}`, + workbookId, + revision: workbook.revision, + calculationStatus: cloneJson(workbook.calculationStatus), + sheetId: sheet.id, + sheetName: sheet.name, + a1, + stats: { + cellCount: count, + numericCount, + emptyCount, + formulaCount, + textCount, + headerGuess, + }, + sampleTsv, + sampleRowCount: sampleRows.length, + }; +} + +function buildPatchCells(sheet, input, maxCells = MAX_LOCAL_PATCH_CELLS) { + assertSheetDimensions(Number(sheet.rows), Number(sheet.cols), `Worksheet ${sheet.name || sheet.id}`); + const cells = []; + if (Array.isArray(input.cells) && input.cells.length > 0) { + if (input.cells.length > maxCells) { + throw new Error(`[PATCH_CELL_LIMIT] Patch exceeds the maximum of ${maxCells} cells.`); + } + for (const item of input.cells) { + if (!item || typeof item !== "object") continue; + const row = Number(item.row); + const col = Number(item.col); + assertCellCoordinates(row, col, `Patch cell row=${item.row}, col=${item.col}`); + const beforeCell = sheet.cells[cellKey(row, col)] || null; + const hasMutation = Object.prototype.hasOwnProperty.call(item, "formula") + || Object.prototype.hasOwnProperty.call(item, "value") + || Object.prototype.hasOwnProperty.call(item, "style") + || Object.prototype.hasOwnProperty.call(item, "styleRole"); + if (!hasMutation) { + continue; + } + const after = cellFromPatch(beforeCell, item); + cells.push({ + r: row, + c: col, + before: cloneCell(beforeCell), + after: cloneCell(after), + }); + } + return cells; + } + + if (Array.isArray(input.values)) { + const { range } = (() => { + if (input.a1) { + return { range: clampRange(parseA1(input.a1), sheet.rows, sheet.cols) }; + } + return { range: { r1: 0, c1: 0, r2: 0, c2: 0 } }; + })(); + for (let i = 0; i < input.values.length; i += 1) { + const rowVals = input.values[i]; + if (!Array.isArray(rowVals)) continue; + for (let j = 0; j < rowVals.length; j += 1) { + if (cells.length >= maxCells) { + throw new Error(`[PATCH_CELL_LIMIT] Patch exceeds the maximum of ${maxCells} cells.`); + } + const row = range.r1 + i; + const col = range.c1 + j; + assertCellCoordinates(row, col, `Patch matrix cell row=${row}, col=${col}`); + const value = rowVals[j]; + const beforeCell = sheet.cells[cellKey(row, col)] || null; + let after = null; + if (value !== null && value !== undefined && value !== "") { + after = typeof value === "string" && value.trim().startsWith("=") + ? cellFromPatch(beforeCell, { formula: value }) + : cellFromPatch(beforeCell, { value }); + } + cells.push({ + r: row, + c: col, + before: cloneCell(beforeCell), + after, + }); + } + } + return cells; + } + + throw new Error("proposePatch requires cells[] or values[][]"); +} + +function proposePatch(input = {}) { + const workspacePath = requireWorkspace(input); + const workbookId = requireWorkbookId(input); + const workbook = loadOrGet(workspacePath, workbookId); + assertWritable(workbook, "proposePatch"); + assertExpectedRevision(workbook, input, "proposePatch"); + if (workbook.proposal) { + throw new Error( + `[ACTIVE_PROPOSAL_EXISTS] Proposal ${workbook.proposal.id} is still active. Accept or reject it before creating another proposal.` + ); + } + const sheet = resolveSheet(workbook, input.sheetId, input.a1); + const hasCellPatch = (Array.isArray(input.cells) && input.cells.length > 0) || Array.isArray(input.values); + const patchCells = hasCellPatch ? buildPatchCells(sheet, input, MAX_PROPOSAL_CELLS) : []; + const rawLayout = layoutFromPatch(sheet, input.layout, patchCells); + const layout = rawLayout && !stableEqual(rawLayout.before, rawLayout.after) ? rawLayout : null; + if (patchCells.length === 0 && !layout) throw new Error("proposePatch produced an empty patch"); + + const validation = validatePatchCells(sheet, patchCells); + validation.layoutChanged = Boolean(layout); + validation.layoutPartialAccept = layout + ? "Layout is applied only when the proposal is accepted without cellRefs." + : null; + if (validation.errors.length > 0) { + throw new Error(`[INVALID_PROPOSAL] ${validation.errors.join(" ")}`); + } + if (patchCells.length > 0 && validation.noOpCount === patchCells.length && !layout) { + throw new Error("proposePatch produced no content changes"); + } + const a1 = proposalRange(patchCells); + const proposal = { + id: newId("prop"), + sheetId: sheet.id, + a1, + cells: patchCells, + baseRevision: workbook.revision, + intent: typeof input.intent === "string" && input.intent.trim() + ? input.intent.trim() + : null, + validation, + layout, + createdAt: nowIso(), + }; + workbook.proposal = proposal; + // Do NOT mutate committed cells + const saved = persist(workspacePath, workbook); + const cellResult = proposalCellResult(proposal, input.resultCellLimit); + return { + summary: `Proposed patch ${proposal.id} on ${sheet.name}${a1 ? `!${a1}` : ""} (${patchCells.length} cells${layout ? ", layout" : ""}). Not applied until acceptProposal.`, + proposal: proposalSummary(proposal), + ...cellResult, + meta: metaOf(saved), + }; +} + +function getProposal(input = {}) { + const workspacePath = requireWorkspace(input); + const workbookId = requireWorkbookId(input); + const workbook = loadOrGet(workspacePath, workbookId); + if (!workbook.proposal) { + return { + summary: "No active proposal", + proposal: null, + totalCellCount: 0, + cellDetailsTruncated: false, + }; + } + const sheet = getSheet(workbook, workbook.proposal.sheetId); + const cellResult = proposalCellResult(workbook.proposal, input.resultCellLimit); + return { + summary: `Active proposal ${workbook.proposal.id} on ${sheet.name}${workbook.proposal.a1 ? `!${workbook.proposal.a1}` : ""}`, + proposal: { + ...proposalSummary(workbook.proposal), + sheetName: sheet.name, + ...cellResult, + }, + totalCellCount: cellResult.totalCellCount, + cellDetailsTruncated: cellResult.cellDetailsTruncated, + }; +} + +function proposalSelection(workbook, proposal, cellRefs) { + if (cellRefs == null) { + const all = proposal.cells || []; + if (all.length > MAX_ACCEPT_SELECTION_CELLS) { + throw new Error( + `[ACCEPT_CELL_LIMIT] Proposal contains ${all.length} cells; maximum accepted in one operation is ${MAX_ACCEPT_SELECTION_CELLS}.` + ); + } + return all; + } + if (!Array.isArray(cellRefs) || cellRefs.length === 0) { + throw new Error("acceptProposal cellRefs must be a non-empty array when provided"); + } + if (cellRefs.length > MAX_ACCEPT_SELECTION_CELLS) { + throw new Error( + `[ACCEPT_CELL_LIMIT] cellRefs contains more than ${MAX_ACCEPT_SELECTION_CELLS} entries.` + ); + } + const wanted = new Set(); + for (const ref of cellRefs) { + if (typeof ref === "string") { + const parsed = parseA1(ref); + if (parsed.sheet) { + const sheet = getSheet(workbook, proposal.sheetId); + if (parsed.sheet !== proposal.sheetId && parsed.sheet.toLowerCase() !== sheet.name.toLowerCase()) { + throw new Error( + `acceptProposal cellRef ${ref} targets ${parsed.sheet}, but proposal ${proposal.id} targets ${sheet.name}` + ); + } + } + const expandedCount = cellCount(parsed.r1, parsed.c1, parsed.r2, parsed.c2); + if (expandedCount > MAX_ACCEPT_SELECTION_CELLS) { + throw new Error( + `[ACCEPT_CELL_LIMIT] ${ref} expands to ${expandedCount} cells; maximum is ${MAX_ACCEPT_SELECTION_CELLS}.` + ); + } + for (let r = parsed.r1; r <= parsed.r2; r += 1) { + for (let c = parsed.c1; c <= parsed.c2; c += 1) { + wanted.add(`${r},${c}`); + if (wanted.size > MAX_ACCEPT_SELECTION_CELLS) { + throw new Error( + `[ACCEPT_CELL_LIMIT] Selected cells exceed the maximum of ${MAX_ACCEPT_SELECTION_CELLS}.` + ); + } + } + } + continue; + } + if (ref && typeof ref === "object") { + const row = Number(ref.row); + const col = Number(ref.col); + assertCellCoordinates(row, col, `acceptProposal cellRef row=${ref.row}, col=${ref.col}`); + wanted.add(`${row},${col}`); + continue; + } + throw new Error("acceptProposal cellRefs entries must be A1 strings or {row,col}"); + } + const selected = (proposal.cells || []).filter((cell) => wanted.has(`${cell.r},${cell.c}`)); + if (selected.length !== wanted.size) { + const proposalKeys = new Set((proposal.cells || []).map((cell) => `${cell.r},${cell.c}`)); + const missing = [...wanted].filter((key) => !proposalKeys.has(key)); + throw new Error(`[INVALID_CELL_REFS] Cells are not in proposal ${proposal.id}: ${missing.join(", ")}`); + } + return selected; +} + +function acceptProposal(input = {}) { + const workspacePath = requireWorkspace(input); + const workbookId = requireWorkbookId(input); + const workbook = loadOrGet(workspacePath, workbookId); + assertWritable(workbook, "acceptProposal"); + assertExpectedRevision(workbook, input, "acceptProposal"); + if (!workbook.proposal) { + throw new Error("No active proposal to accept"); + } + if (!input.proposalId || typeof input.proposalId !== "string") { + throw new Error("[PROPOSAL_ID_REQUIRED] acceptProposal requires the exact reviewed proposalId."); + } + if (input.proposalId !== workbook.proposal.id) { + throw new Error( + `Proposal id mismatch: active=${workbook.proposal.id}, requested=${input.proposalId}` + ); + } + const proposal = workbook.proposal; + if (proposal.baseRevision !== workbook.revision) { + throw new Error( + `[PROPOSAL_REVISION_CONFLICT] Proposal ${proposal.id} was created at revision ${proposal.baseRevision}, but the workbook is at revision ${workbook.revision}. Refresh the proposal before accepting it.` + ); + } + const sheet = getSheet(workbook, proposal.sheetId); + const selected = proposalSelection(workbook, proposal, input.cellRefs); + const acceptLayout = Boolean(proposal.layout && input.cellRefs == null); + const conflicts = []; + for (const cell of selected) { + const current = sheet.cells[cellKey(cell.r, cell.c)] || null; + if (!cellsEqual(current, cell.before)) { + conflicts.push(formatA1(cell.r, cell.c)); + } + } + if (conflicts.length > 0) { + throw new Error( + `[PROPOSAL_BEFORE_CONFLICT] ${conflicts.length} cell(s) changed after the proposal was created: ${conflicts.join(", ")}. Refresh before accepting.` + ); + } + if (acceptLayout && !stableEqual(sheet.layout, proposal.layout.before)) { + throw new Error( + `[PROPOSAL_LAYOUT_CONFLICT] Sheet layout changed after proposal ${proposal.id} was created. Refresh before accepting.` + ); + } + assertCellMutationCapacity(workbook, selected); + const beforeSize = { rows: sheet.rows, cols: sheet.cols }; + for (const cell of selected) { + setSheetCell(sheet, cell.r, cell.c, cell.after); + } + if (acceptLayout) sheet.layout = cloneJson(proposal.layout.after); + workbook.activeSheetId = sheet.id; + const selectedKeys = new Set( + selected.map((cell) => `${proposal.sheetId}:${cell.r},${cell.c}`) + ); + const changes = []; + if (selected.length > 0) { + changes.push({ + kind: "cells", + sheetId: sheet.id, + beforeSize, + afterSize: { rows: sheet.rows, cols: sheet.cols }, + cells: cloneJson(selected), + }); + } + if (acceptLayout) { + changes.push({ kind: "layout", sheetId: sheet.id, ...cloneJson(proposal.layout) }); + } + const hasStyleChanges = cellChangesStyle(selected); + const operation = recordOperation(workbook, { + type: "accept-proposal", + actor: input.actor || "user", + intent: proposal.intent || input.intent || null, + summary: `Accepted ${selected.length} cell(s)${acceptLayout ? " and layout" : ""} from proposal ${proposal.id}`, + sheetId: sheet.id, + a1: proposalRange(selected), + cellCount: selected.length, + roundTripSafe: !hasStyleChanges && !acceptLayout, + contentChanged: cellChangesContent(selected), + structureChanged: false, + fidelityWarning: hasStyleChanges && acceptLayout + ? "New or changed cell styles and worksheet layout cannot be added to an imported Excel package by the source-preserving patcher. Save As with fidelity-loss acknowledgement to rebuild a styled .xlsx copy." + : hasStyleChanges + ? "New or changed cell styles cannot be added to an imported Excel package by the source-preserving patcher. Save As with fidelity-loss acknowledgement to rebuild a styled .xlsx copy." + : acceptLayout + ? "New or changed worksheet layout cannot be patched into an imported Excel package losslessly. Save As with fidelity-loss acknowledgement to rebuild an .xlsx copy." + : null, + change: changes.length === 1 ? changes[0] : { kind: "compound", changes }, + }); + rebaseProposal(workbook, selectedKeys, acceptLayout); + const saved = persist(workspacePath, workbook); + return { + summary: `Accepted proposal ${proposal.id} on ${sheet.name}${proposalRange(selected) ? `!${proposalRange(selected)}` : ""} (${selected.length} cells${acceptLayout ? ", layout" : ""})`, + applied: { + proposalId: proposal.id, + operationId: operation.id, + sheetId: sheet.id, + sheetName: sheet.name, + a1: proposalRange(selected), + cellCount: selected.length, + layoutApplied: acceptLayout, + revision: saved.revision, + }, + remainingProposal: proposalSummary(saved.proposal), + meta: metaOf(saved), + }; +} + +function rejectProposal(input = {}) { + const workspacePath = requireWorkspace(input); + const workbookId = requireWorkbookId(input); + const workbook = loadOrGet(workspacePath, workbookId); + assertExpectedRevision(workbook, input, "rejectProposal"); + if (!workbook.proposal) { + return { + summary: "No active proposal to reject", + proposal: null, + meta: metaOf(workbook), + }; + } + if (!input.proposalId || typeof input.proposalId !== "string") { + throw new Error("[PROPOSAL_ID_REQUIRED] rejectProposal requires the exact reviewed proposalId."); + } + if (input.proposalId !== workbook.proposal.id) { + throw new Error( + `Proposal id mismatch: active=${workbook.proposal.id}, requested=${input.proposalId}` + ); + } + const rejectedId = workbook.proposal.id; + const a1 = workbook.proposal.a1; + workbook.proposal = null; + const saved = persist(workspacePath, workbook); + return { + summary: `Rejected proposal ${rejectedId} (${a1})`, + rejectedProposalId: rejectedId, + meta: metaOf(saved), + }; +} + +function applyLocalEdit(input = {}) { + const workspacePath = requireWorkspace(input); + const workbookId = requireWorkbookId(input); + const workbook = loadOrGet(workspacePath, workbookId); + assertWritable(workbook, "applyLocalEdit"); + assertExpectedRevision(workbook, input, "applyLocalEdit"); + const sheet = getSheet(workbook, input.sheetId || workbook.activeSheetId); + const row = Number(input.row); + const col = Number(input.col); + assertCellCoordinates(row, col, "Local edit cell"); + const beforeSize = { rows: sheet.rows, cols: sheet.cols }; + const before = cloneCell(sheet.cells[cellKey(row, col)] || null); + const previewAfter = cellFromPatch(before, input); + const validation = validatePatchCells(sheet, [{ r: row, c: col, before, after: previewAfter }]); + if (validation.errors.length > 0) { + throw new Error(`[INVALID_LOCAL_EDIT] ${validation.errors.join(" ")}`); + } + assertCellMutationCapacity(workbook, [{ + before, + after: previewAfter, + }]); + const after = setCell(sheet, row, col, { + value: input.value, + formula: input.formula, + style: input.style, + styleRole: input.styleRole, + }); + workbook.focus = { + sheetId: sheet.id, + a1: formatA1(row, col), + kind: "cell", + }; + let operation = null; + if (!cellsEqual(before, after)) { + operation = recordOperation(workbook, { + type: "local-edit", + actor: input.actor || "user", + intent: input.intent || null, + summary: `Edited ${sheet.name}!${formatA1(row, col)}`, + sheetId: sheet.id, + a1: formatA1(row, col), + cellCount: 1, + roundTripSafe: !cellChangesStyle([{ before, after }]), + contentChanged: !cellsContentEqual(before, after), + structureChanged: false, + fidelityWarning: "New or changed cell styles cannot be patched into an imported Excel package losslessly. Save As with fidelity-loss acknowledgement to rebuild a styled .xlsx copy.", + change: { + kind: "cells", + sheetId: sheet.id, + beforeSize, + afterSize: { rows: sheet.rows, cols: sheet.cols }, + cells: [{ r: row, c: col, before, after: cloneCell(after) }], + }, + }); + } + rebaseProposal(workbook, new Set([`${sheet.id}:${row},${col}`])); + const saved = persist(workspacePath, workbook); + return { + summary: `Local edit at ${sheet.name}!${formatA1(row, col)}`, + edit: { + sheetId: sheet.id, + sheetName: sheet.name, + row, + col, + a1: formatA1(row, col), + before: cellDisplay(before), + after: cellDisplay(after), + operationId: operation ? operation.id : null, + }, + validation, + meta: metaOf(saved), + }; +} + +function applyLocalPatch(input = {}) { + const workspacePath = requireWorkspace(input); + const workbookId = requireWorkbookId(input); + const workbook = loadOrGet(workspacePath, workbookId); + assertWritable(workbook, "applyLocalPatch"); + assertExpectedRevision(workbook, input, "applyLocalPatch"); + const sheet = resolveSheet(workbook, input.sheetId, input.a1); + const patchCells = buildPatchCells(sheet, input, MAX_LOCAL_PATCH_CELLS); + const validation = validatePatchCells(sheet, patchCells); + if (validation.errors.length > 0) { + throw new Error(`[INVALID_LOCAL_PATCH] ${validation.errors.join(" ")}`); + } + const changed = patchCells.filter((cell) => !cellsEqual(cell.before, cell.after)); + if (changed.length === 0) { + return { + summary: "Local patch made no content changes", + applied: { sheetId: sheet.id, sheetName: sheet.name, a1: null, cellCount: 0 }, + meta: metaOf(workbook), + }; + } + assertCellMutationCapacity(workbook, changed); + const beforeSize = { rows: sheet.rows, cols: sheet.cols }; + for (const cell of changed) { + setSheetCell(sheet, cell.r, cell.c, cell.after); + } + const a1 = proposalRange(changed); + workbook.activeSheetId = sheet.id; + workbook.focus = { + sheetId: sheet.id, + a1, + kind: changed.length === 1 ? "cell" : "range", + }; + const operation = recordOperation(workbook, { + type: "local-patch", + actor: input.actor || "user", + intent: input.intent || "Paste cells", + summary: `Applied local patch to ${sheet.name}!${a1}`, + sheetId: sheet.id, + a1, + cellCount: changed.length, + roundTripSafe: !cellChangesStyle(changed), + contentChanged: cellChangesContent(changed), + structureChanged: false, + fidelityWarning: "New or changed cell styles cannot be patched into an imported Excel package losslessly. Save As with fidelity-loss acknowledgement to rebuild a styled .xlsx copy.", + change: { + kind: "cells", + sheetId: sheet.id, + beforeSize, + afterSize: { rows: sheet.rows, cols: sheet.cols }, + cells: cloneJson(changed), + }, + }); + rebaseProposal( + workbook, + new Set(changed.map((cell) => `${sheet.id}:${cell.r},${cell.c}`)) + ); + const saved = persist(workspacePath, workbook); + return { + summary: `Applied ${changed.length} local cell edit(s) to ${sheet.name}!${a1}`, + applied: { + operationId: operation.id, + sheetId: sheet.id, + sheetName: sheet.name, + a1, + cellCount: changed.length, + revision: saved.revision, + }, + validation, + meta: metaOf(saved), + }; +} + +function applyLayout(input = {}) { + const workspacePath = requireWorkspace(input); + const workbookId = requireWorkbookId(input); + const workbook = loadOrGet(workspacePath, workbookId); + assertWritable(workbook, "applyLayout"); + assertExpectedRevision(workbook, input, "applyLayout"); + const sheet = getSheet(workbook, input.sheetId || workbook.activeSheetId); + const change = layoutFromPatch(sheet, input.layout); + if (!change || stableEqual(change.before, change.after)) { + return { summary: "Layout already matches", layout: cloneJson(sheet.layout), meta: metaOf(workbook) }; + } + sheet.layout = cloneJson(change.after); + const operation = recordOperation(workbook, { + type: "apply-layout", + actor: input.actor || "user", + intent: input.intent || null, + summary: `Updated layout on ${sheet.name}`, + sheetId: sheet.id, + cellCount: 0, + roundTripSafe: false, + contentChanged: false, + structureChanged: false, + fidelityWarning: "New or changed worksheet layout cannot be patched into an imported Excel package losslessly. Save As with fidelity-loss acknowledgement to rebuild an .xlsx copy.", + change: { kind: "layout", sheetId: sheet.id, ...cloneJson(change) }, + }); + rebaseProposal(workbook); + const saved = persist(workspacePath, workbook); + return { + summary: `Updated layout on ${sheet.name}`, + operationId: operation.id, + sheetId: sheet.id, + layout: cloneJson(sheet.layout), + meta: metaOf(saved), + }; +} + +function clearRange(input = {}) { + const workspacePath = requireWorkspace(input); + const workbookId = requireWorkbookId(input); + const workbook = loadOrGet(workspacePath, workbookId); + assertWritable(workbook, "clearRange"); + assertExpectedRevision(workbook, input, "clearRange"); + if (!input.a1) { + throw new Error("a1 is required for clearRange"); + } + const { sheet, range, a1 } = resolveRange(workbook, input); + let cleared = 0; + const changes = []; + const beforeSize = { rows: sheet.rows, cols: sheet.cols }; + for (let r = range.r1; r <= range.r2; r += 1) { + for (let c = range.c1; c <= range.c2; c += 1) { + const key = cellKey(r, c); + if (sheet.cells[key]) { + changes.push({ r, c, before: cloneCell(sheet.cells[key]), after: null }); + delete sheet.cells[key]; + cleared += 1; + } + } + } + let operation = null; + if (changes.length > 0) { + operation = recordOperation(workbook, { + type: "clear-range", + actor: input.actor || "user", + intent: input.intent || null, + summary: `Cleared ${sheet.name}!${a1}`, + sheetId: sheet.id, + a1, + cellCount: changes.length, + change: { + kind: "cells", + sheetId: sheet.id, + beforeSize, + afterSize: { rows: sheet.rows, cols: sheet.cols }, + cells: changes, + }, + }); + } + const excluded = new Set(); + if (workbook.proposal && workbook.proposal.sheetId === sheet.id) { + for (const cell of workbook.proposal.cells || []) { + if (cell.r >= range.r1 && cell.r <= range.r2 && cell.c >= range.c1 && cell.c <= range.c2) { + excluded.add(`${sheet.id}:${cell.r},${cell.c}`); + } + } + } + rebaseProposal(workbook, excluded); + const saved = persist(workspacePath, workbook); + return { + summary: `Cleared ${cleared} cell(s) in ${sheet.name}!${a1}`, + sheetId: sheet.id, + a1, + clearedCount: cleared, + operationId: operation ? operation.id : null, + meta: metaOf(saved), + }; +} + +function listWorkbooks(input = {}) { + const workspacePath = requireWorkspace(input); + const workbooks = listWorkbookMetas(workspacePath); + return { + summary: `${workbooks.length} workbook store(s) in workspace`, + workbooks, + }; +} + +function saveWorkbook(input = {}) { + const workspacePath = requireWorkspace(input); + const workbookId = requireWorkbookId(input); + const workbook = loadOrGet(workspacePath, workbookId); + assertExpectedRevision(workbook, input, "saveWorkbook"); + const targetPath = input.path + ? resolveConsumerPath(input, workspacePath, input.path, "saveWorkbook") + : workbook.path + ? assertConsumerPathAllowed( + input, + workspacePath, + path.resolve(workbook.path), + "saveWorkbook" + ) + : null; + + if (targetPath && path.extname(targetPath).toLowerCase() === ".csv") { + throw new Error( + "[CSV_EXPORT_ACTION_REQUIRED] saveWorkbook cannot export CSV. Use exportCsv so formula freshness checks and formula-injection sanitization are enforced." + ); + } + + const sourcePath = workbook.sourcePath || null; + const exportCopy = input.exportCopy === true; + const excelSource = ["xlsx", "xlsm"].includes( + String(workbook.sourceFormat || "").toLowerCase() + ); + const overwritesSource = Boolean( + targetPath && + sourcePath && + pathsReferToSameFile(targetPath, sourcePath) + ); + if (overwritesSource && input.allowSourceOverwrite !== true) { + throw new Error( + `[SOURCE_OVERWRITE_BLOCKED] ${sourcePath} is the imported source. Use Save As with a different path, or explicitly set allowSourceOverwrite=true after reviewing fidelity.` + ); + } + if (overwritesSource && workbook.fidelity?.canRoundTrip === false) { + throw new Error( + "[LOSSY_SOURCE_OVERWRITE_BLOCKED] The imported source can never be overwritten with a lossy rebuild. Choose a new .xlsx path and acknowledge fidelity loss there." + ); + } + if ( + targetPath && + excelSource && + workbook.fidelity && + workbook.fidelity.canRoundTrip === false && + input.acknowledgeFidelityLoss !== true + ) { + throw new Error( + `[FIDELITY_ACK_REQUIRED] This workbook cannot be exported losslessly: ${workbook.fidelity.warning || "unsupported workbook features may be lost"} Set acknowledgeFidelityLoss=true only after choosing an appropriate Save As target.` + ); + } + + const savedStore = persist(workspacePath, workbook); + let exportResult = null; + if (targetPath) { + const atomicWriteOptions = prepareAtomicTargetWrite(input, targetPath, sourcePath); + exportResult = writeWorkbookFile(savedStore, targetPath, { + allowLossyRebuild: + input.acknowledgeFidelityLoss === true && !overwritesSource, + atomicWriteOptions, + }); + if (overwritesSource && exportResult.outputFingerprint) { + savedStore.sourceFingerprint = cloneJson(exportResult.outputFingerprint); + } + if (!exportCopy) savedStore.path = targetPath; + savedStore.lastExportPath = targetPath; + savedStore.lastExportedRevision = savedStore.revision; + savedStore.lastExportFingerprint = readStableFile(targetPath).fingerprint; + savedStore.dirty = false; + persist(workspacePath, savedStore); + } else { + savedStore.dirty = false; + persist(workspacePath, savedStore); + } + + return { + summary: targetPath + ? exportCopy + ? `Exported workbook copy to ${targetPath}; source association remains ${sourcePath || "internal store"}` + : `Saved workbook store and exported to ${targetPath}` + : `Saved workbook store for ${workbookId} (no external path)`, + meta: metaOf(sessions.get(workbookId).workbook), + storePath: path.join(workspacePath, ".sparo_os", "excel-live", workbookId, "workbook.json"), + export: exportResult, + exportCopy, + workingPath: sessions.get(workbookId).workbook.path || null, + sourceProtected: Boolean(sourcePath), + }; +} + +function exportCsv(input = {}) { + const workspacePath = requireWorkspace(input); + const workbookId = requireWorkbookId(input); + const workbook = loadOrGet(workspacePath, workbookId); + assertExpectedRevision(workbook, input, "exportCsv"); + const sheet = getSheet(workbook, input.sheetId || workbook.activeSheetId); + const matrix = sheetToMatrix(sheet); + let exportedFormulaCount = 0; + let sanitizedCellCount = 0; + const uncachedFormulaRefs = []; + for (let r = 0; r < matrix.length; r += 1) { + for (let c = 0; c < (matrix[r] || []).length; c += 1) { + const cell = sheet.cells[cellKey(r, c)]; + if (!cell) continue; + if (cellHasFormulaEvidence(cell)) { + exportedFormulaCount += 1; + if (!Object.prototype.hasOwnProperty.call(cell, "v") || cell.v == null) { + uncachedFormulaRefs.push(formatA1(r, c)); + continue; + } + const cachedValue = matrix[r][c]; + if (typeof cachedValue === "string" && /^[=+\-@\t\r\n]/.test(cachedValue)) { + matrix[r][c] = `'${cachedValue}`; + sanitizedCellCount += 1; + } + continue; + } + const isText = cell.t === "s" || cell.t === "str" || typeof cell.v === "string"; + const value = matrix[r][c]; + if (isText && typeof value === "string" && /^[=+\-@\t\r\n]/.test(value)) { + matrix[r][c] = `'${value}`; + sanitizedCellCount += 1; + } + } + } + if (uncachedFormulaRefs.length > 0) { + const sample = uncachedFormulaRefs.slice(0, 20).join(", "); + throw new Error( + `[UNCACHED_FORMULA_CSV_BLOCKED] Sheet ${sheet.name} has ${uncachedFormulaRefs.length} formula cell(s) without cached results (${sample}). CSV export will not emit executable formula text as if it were a calculated value. Recalculate in Excel first.` + ); + } + if (exportedFormulaCount > 0 && input.acknowledgeStaleFormulaValues !== true) { + throw new Error( + `[STALE_FORMULA_VALUES_ACK_REQUIRED] Sheet ${sheet.name} contains ${exportedFormulaCount} formula cell(s). The live engine does not recalculate formulas, so cached CSV values may be stale. Review calculationStatus=${workbook.calculationStatus?.status || "unknown"} and set acknowledgeStaleFormulaValues=true to export intentionally.` + ); + } + const csv = serializeCsv(matrix); + let outPath = input.path || null; + if (outPath) { + outPath = resolveConsumerPath(input, workspacePath, outPath, "exportCsv"); + const actualOutPath = path.extname(outPath).toLowerCase() === ".csv" + ? outPath + : `${outPath}.csv`; + if ( + workbook.sourcePath && + pathsReferToSameFile(actualOutPath, workbook.sourcePath) + ) { + throw new Error( + "[SOURCE_OVERWRITE_BLOCKED] exportCsv cannot replace the imported source. Choose a new path." + ); + } + const atomicWriteOptions = prepareAtomicTargetWrite(input, actualOutPath, workbook.sourcePath); + writeFileAtomic(actualOutPath, csv, "utf8", atomicWriteOptions); + outPath = actualOutPath; + } + const warnings = []; + if (exportedFormulaCount > 0) { + warnings.push( + `${exportedFormulaCount} formula cell(s) were exported using cached values that may be stale.` + ); + } + if (sanitizedCellCount > 0) { + warnings.push( + `${sanitizedCellCount} text cell(s) with formula-injection prefixes were escaped with a leading apostrophe.` + ); + } + return { + summary: outPath + ? `Exported sheet "${sheet.name}" to ${outPath}` + : `Serialized sheet "${sheet.name}" to CSV (${matrix.length} rows)`, + sheetId: sheet.id, + sheetName: sheet.name, + path: outPath, + csv: outPath ? undefined : csv, + rowCount: matrix.length, + columnCount: matrix[0] ? matrix[0].length : 0, + formulaCount: exportedFormulaCount, + sanitizedCellCount, + calculationStatus: cloneJson(workbook.calculationStatus), + warning: warnings.length > 0 ? warnings.join(" ") : null, + }; +} + +function shiftCells(sheet, predicate, mapper) { + const next = {}; + for (const [key, cell] of Object.entries(sheet.cells || {})) { + const [rs, cs] = key.split(","); + const r = Number(rs); + const c = Number(cs); + if (!predicate(r, c)) { + next[key] = cell; + continue; + } + const mapped = mapper(r, c, cell); + if (!mapped) continue; + assertCellCoordinates(mapped.r, mapped.c, "Shifted worksheet cell"); + next[cellKey(mapped.r, mapped.c)] = mapped.cell; + } + sheet.cells = next; +} + +function assertStructureEditSafe(workbook, action) { + const count = formulaCount(workbook); + if (count > 0) { + throw new Error( + `[FORMULA_REFERENCE_RISK] ${action} is blocked because the workbook contains ${count} formula cell(s), and this engine cannot safely rewrite formula references.` + ); + } +} + +function assertLayoutStructureEditSafe(sheet, axis, action) { + const layout = normalizeSheetLayout(sheet.layout); + const hasAxisBands = axis === "rows" ? layout.rows.length > 0 : layout.columns.length > 0; + const hasAxisFreeze = axis === "rows" + ? layout.freezePanes.rows > 0 + : layout.freezePanes.columns > 0; + if (hasAxisBands || hasAxisFreeze || layout.autoFilter) { + throw new Error( + `[LAYOUT_REFERENCE_RISK] ${action} is blocked because ${sheet.name} has ${axis} layout, freeze panes, or an auto filter that this engine cannot safely rewrite. Apply structural edits before layout, or clear the affected layout first.` + ); + } +} + +function insertRows(input = {}) { + const workspacePath = requireWorkspace(input); + const workbookId = requireWorkbookId(input); + const workbook = loadOrGet(workspacePath, workbookId); + assertWritable(workbook, "insertRows"); + assertExpectedRevision(workbook, input, "insertRows"); + assertStructureEditSafe(workbook, "insertRows"); + const sheet = getSheet(workbook, input.sheetId || workbook.activeSheetId); + assertLayoutStructureEditSafe(sheet, "rows", "insertRows"); + const at = Number(input.at == null ? input.row : input.at); + const count = requirePositiveSafeInteger(input.count, 1, "count"); + if (!Number.isSafeInteger(at) || at < 0 || at > sheet.rows) { + throw new Error("at/row must be a safe integer within the worksheet row boundary"); + } + if (sheet.rows + count > EXCEL_MAX_ROWS) { + throw new Error(`[EXCEL_ROW_LIMIT] Inserting ${count} row(s) would exceed ${EXCEL_MAX_ROWS}.`); + } + const before = cloneJson(sheet); + shiftCells( + sheet, + (r) => r >= at, + (r, c, cell) => ({ r: r + count, c, cell }) + ); + sheet.rows += count; + workbook.proposal = null; + const operation = recordOperation(workbook, { + type: "insert-rows", + actor: input.actor || "user", + intent: input.intent || null, + summary: `Inserted ${count} row(s) at ${at} on ${sheet.name}`, + sheetId: sheet.id, + cellCount: 0, + roundTripSafe: false, + change: { kind: "sheet", sheetId: sheet.id, before, after: cloneJson(sheet) }, + }); + const saved = persist(workspacePath, workbook); + return { + summary: `Inserted ${count} row(s) at ${at} on "${sheet.name}"`, + sheetId: sheet.id, + at, + count, + operationId: operation.id, + meta: metaOf(saved), + }; +} + +function insertColumns(input = {}) { + const workspacePath = requireWorkspace(input); + const workbookId = requireWorkbookId(input); + const workbook = loadOrGet(workspacePath, workbookId); + assertWritable(workbook, "insertColumns"); + assertExpectedRevision(workbook, input, "insertColumns"); + assertStructureEditSafe(workbook, "insertColumns"); + const sheet = getSheet(workbook, input.sheetId || workbook.activeSheetId); + assertLayoutStructureEditSafe(sheet, "columns", "insertColumns"); + const at = Number(input.at == null ? input.col : input.at); + const count = requirePositiveSafeInteger(input.count, 1, "count"); + if (!Number.isSafeInteger(at) || at < 0 || at > sheet.cols) { + throw new Error("at/col must be a safe integer within the worksheet column boundary"); + } + if (sheet.cols + count > EXCEL_MAX_COLUMNS) { + throw new Error(`[EXCEL_COLUMN_LIMIT] Inserting ${count} column(s) would exceed ${EXCEL_MAX_COLUMNS}.`); + } + const before = cloneJson(sheet); + shiftCells( + sheet, + (_r, c) => c >= at, + (r, c, cell) => ({ r, c: c + count, cell }) + ); + sheet.cols += count; + workbook.proposal = null; + const operation = recordOperation(workbook, { + type: "insert-columns", + actor: input.actor || "user", + intent: input.intent || null, + summary: `Inserted ${count} column(s) at ${at} on ${sheet.name}`, + sheetId: sheet.id, + cellCount: 0, + roundTripSafe: false, + change: { kind: "sheet", sheetId: sheet.id, before, after: cloneJson(sheet) }, + }); + const saved = persist(workspacePath, workbook); + return { + summary: `Inserted ${count} column(s) at ${at} on "${sheet.name}"`, + sheetId: sheet.id, + at, + count, + operationId: operation.id, + meta: metaOf(saved), + }; +} + +function deleteRows(input = {}) { + const workspacePath = requireWorkspace(input); + const workbookId = requireWorkbookId(input); + const workbook = loadOrGet(workspacePath, workbookId); + assertWritable(workbook, "deleteRows"); + assertExpectedRevision(workbook, input, "deleteRows"); + assertStructureEditSafe(workbook, "deleteRows"); + const sheet = getSheet(workbook, input.sheetId || workbook.activeSheetId); + assertLayoutStructureEditSafe(sheet, "rows", "deleteRows"); + const at = Number(input.at == null ? input.row : input.at); + const count = requirePositiveSafeInteger(input.count, 1, "count"); + if (!Number.isSafeInteger(at) || at < 0 || at >= sheet.rows) { + throw new Error("at/row must be a safe integer within the worksheet row boundary"); + } + if (count > sheet.rows - at) { + throw new Error("deleteRows count exceeds the remaining worksheet rows"); + } + const before = cloneJson(sheet); + shiftCells( + sheet, + (r) => r >= at, + (r, c, cell) => { + if (r < at + count) return null; + return { r: r - count, c, cell }; + } + ); + sheet.rows = Math.max(1, sheet.rows - count); + workbook.proposal = null; + const operation = recordOperation(workbook, { + type: "delete-rows", + actor: input.actor || "user", + intent: input.intent || null, + summary: `Deleted ${count} row(s) at ${at} on ${sheet.name}`, + sheetId: sheet.id, + cellCount: 0, + roundTripSafe: false, + change: { kind: "sheet", sheetId: sheet.id, before, after: cloneJson(sheet) }, + }); + const saved = persist(workspacePath, workbook); + return { + summary: `Deleted ${count} row(s) at ${at} on "${sheet.name}"`, + sheetId: sheet.id, + at, + count, + operationId: operation.id, + meta: metaOf(saved), + }; +} + +function deleteColumns(input = {}) { + const workspacePath = requireWorkspace(input); + const workbookId = requireWorkbookId(input); + const workbook = loadOrGet(workspacePath, workbookId); + assertWritable(workbook, "deleteColumns"); + assertExpectedRevision(workbook, input, "deleteColumns"); + assertStructureEditSafe(workbook, "deleteColumns"); + const sheet = getSheet(workbook, input.sheetId || workbook.activeSheetId); + assertLayoutStructureEditSafe(sheet, "columns", "deleteColumns"); + const at = Number(input.at == null ? input.col : input.at); + const count = requirePositiveSafeInteger(input.count, 1, "count"); + if (!Number.isSafeInteger(at) || at < 0 || at >= sheet.cols) { + throw new Error("at/col must be a safe integer within the worksheet column boundary"); + } + if (count > sheet.cols - at) { + throw new Error("deleteColumns count exceeds the remaining worksheet columns"); + } + const before = cloneJson(sheet); + shiftCells( + sheet, + (_r, c) => c >= at, + (r, c, cell) => { + if (c < at + count) return null; + return { r, c: c - count, cell }; + } + ); + sheet.cols = Math.max(1, sheet.cols - count); + workbook.proposal = null; + const operation = recordOperation(workbook, { + type: "delete-columns", + actor: input.actor || "user", + intent: input.intent || null, + summary: `Deleted ${count} column(s) at ${at} on ${sheet.name}`, + sheetId: sheet.id, + cellCount: 0, + roundTripSafe: false, + change: { kind: "sheet", sheetId: sheet.id, before, after: cloneJson(sheet) }, + }); + const saved = persist(workspacePath, workbook); + return { + summary: `Deleted ${count} column(s) at ${at} on "${sheet.name}"`, + sheetId: sheet.id, + at, + count, + operationId: operation.id, + meta: metaOf(saved), + }; +} + +function renameSheet(input = {}) { + const workspacePath = requireWorkspace(input); + const workbookId = requireWorkbookId(input); + const workbook = loadOrGet(workspacePath, workbookId); + assertWritable(workbook, "renameSheet"); + assertExpectedRevision(workbook, input, "renameSheet"); + assertStructureEditSafe(workbook, "renameSheet"); + const sheet = getSheet(workbook, input.sheetId || workbook.activeSheetId); + const name = input.name || input.sheetName; + if (!name || typeof name !== "string" || !name.trim()) { + throw new Error("name is required"); + } + const trimmed = validateExcelSheetName(name); + const clash = workbook.sheets.find( + (s) => s.id !== sheet.id && s.name.toLowerCase() === trimmed.toLowerCase() + ); + if (clash) { + throw new Error(`Sheet name already exists: ${trimmed}`); + } + const previous = sheet.name; + sheet.name = trimmed; + const operation = recordOperation(workbook, { + type: "rename-sheet", + actor: input.actor || "user", + intent: input.intent || null, + summary: `Renamed sheet ${previous} to ${trimmed}`, + sheetId: sheet.id, + roundTripSafe: false, + change: { kind: "sheet-name", sheetId: sheet.id, before: previous, after: trimmed }, + }); + const saved = persist(workspacePath, workbook); + return { + summary: `Renamed sheet "${previous}" to "${trimmed}"`, + sheetId: sheet.id, + previousName: previous, + name: trimmed, + operationId: operation.id, + meta: metaOf(saved), + }; +} + +function addSheet(input = {}) { + const workspacePath = requireWorkspace(input); + const workbookId = requireWorkbookId(input); + const workbook = loadOrGet(workspacePath, workbookId); + assertWritable(workbook, "addSheet"); + assertExpectedRevision(workbook, input, "addSheet"); + const before = captureWorkbookContent(workbook); + const requestedName = input.name ?? input.sheetName ?? ""; + if (typeof requestedName !== "string") throw new Error("[INVALID_SHEET_NAME] Worksheet name must be a string."); + let name = requestedName.trim(); + if (!name) { + let i = workbook.sheets.length + 1; + name = `Sheet${i}`; + while (findSheetByName(workbook, name)) { + i += 1; + name = `Sheet${i}`; + } + } else if (findSheetByName(workbook, name)) { + throw new Error(`Sheet name already exists: ${name}`); + } + const rows = requirePositiveSafeInteger(input.rows, 50, "rows"); + const cols = requirePositiveSafeInteger(input.cols, 26, "cols"); + assertSheetDimensions(rows, cols, "New worksheet"); + const sheet = createEmptySheet(name, rows, cols); + workbook.sheets.push(sheet); + if (input.activate !== false) { + workbook.activeSheetId = sheet.id; + workbook.focus = { sheetId: sheet.id, a1: "A1", kind: "cell" }; + } + const operation = recordOperation(workbook, { + type: "add-sheet", + actor: input.actor || "user", + intent: input.intent || null, + summary: `Added sheet ${sheet.name}`, + sheetId: sheet.id, + roundTripSafe: false, + change: { kind: "workbook", before, after: captureWorkbookContent(workbook) }, + }); + const saved = persist(workspacePath, workbook); + return { + summary: `Added sheet "${sheet.name}"`, + sheet: { id: sheet.id, name: sheet.name, rows: sheet.rows, cols: sheet.cols }, + operationId: operation.id, + meta: metaOf(saved), + }; +} + +function reloadWorkbook(input = {}) { + const workspacePath = requireWorkspace(input); + const workbookId = requireWorkbookId(input); + const existing = loadOrGet(workspacePath, workbookId); + + if (existing.path) { + assertWritable(existing, "reloadWorkbook"); + assertExpectedRevision(existing, input, "reloadWorkbook"); + const before = captureWorkbookContent(existing); + const reloaded = readWorkbookFile(existing.path, { + workbookId: existing.workbookId, + title: existing.title, + }); + existing.title = reloaded.title; + existing.sheets = cloneJson(reloaded.sheets); + existing.activeSheetId = reloaded.activeSheetId; + existing.focus = cloneJson(reloaded.focus); + existing.path = reloaded.path; + existing.sourcePath = reloaded.sourcePath; + existing.sourceFormat = reloaded.sourceFormat; + existing.sourceFingerprint = cloneJson(reloaded.sourceFingerprint); + existing.fidelity = cloneJson(reloaded.fidelity); + existing.proposal = null; + const operation = recordOperation(existing, { + type: "reload-workbook", + actor: input.actor || "user", + intent: input.intent || "Reload external workbook", + summary: `Reloaded workbook from ${existing.path}`, + roundTripSafe: true, + change: { kind: "workbook", before, after: captureWorkbookContent(existing) }, + }); + existing.dirty = false; + refreshCalculationStatus(existing, false); + const saved = persist(workspacePath, normalizeWorkbook(existing)); + const sheet = getSheet(saved, saved.activeSheetId); + return { + summary: `Reloaded workbook from ${existing.path}`, + operationId: operation.id, + meta: metaOf(saved), + viewport: viewportSummary(saved, sheet), + }; + } + + const fromStore = loadJson(workspacePath, workbookId); + sessions.set(workbookId, { workspacePath, workbook: fromStore }); + const sheet = getSheet(fromStore, fromStore.activeSheetId); + return { + summary: `Reloaded workbook store for ${workbookId}`, + meta: metaOf(fromStore), + viewport: viewportSummary(fromStore, sheet), + }; +} + +const actions = { + openWorkbook, + createWorkbook, + getMeta, + getFocus, + setFocus, + setMode, + readRange, + summarizeRange, + proposePatch, + getProposal, + acceptProposal, + rejectProposal, + applyLocalEdit, + applyLocalPatch, + applyLayout, + clearRange, + undo, + redo, + getHistory, + saveWorkbook, + exportCsv, + listSheets, + listWorkbooks, + switchSheet, + insertRows, + insertColumns, + deleteRows, + deleteColumns, + renameSheet, + addSheet, + reloadWorkbook, +}; + +function dispatch(action, input) { + const fn = actions[action]; + if (!fn) { + throw new Error(`Unsupported Sparo Excel Engine action: ${action}`); + } + return fn(input || {}); +} + +module.exports = { + dispatch, + actions, + sessions, + DEFAULT_MAX_CELLS, + limits: Object.freeze({ + maxReadRangeCells: MAX_READ_RANGE_CELLS, + maxProposalCells: MAX_PROPOSAL_CELLS, + maxLocalPatchCells: MAX_LOCAL_PATCH_CELLS, + maxAcceptSelectionCells: MAX_ACCEPT_SELECTION_CELLS, + }), +}; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/src/protocol.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/src/protocol.js new file mode 100644 index 00000000..976f9bc3 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/src/protocol.js @@ -0,0 +1,38 @@ +const fs = require("node:fs"); + +function emit(event) { + const line = `${JSON.stringify(event)}\n`; + try { + fs.writeSync(1, line); + } catch { + process.stdout.write(line); + } +} + +function emitStatus(message, status = "running") { + emit({ type: "run.status", status, message }); +} + +function readRequest() { + return new Promise((resolve, reject) => { + let input = ""; + process.stdin.setEncoding("utf8"); + process.stdin.on("data", (chunk) => { + input += chunk; + }); + process.stdin.on("end", () => { + try { + resolve(JSON.parse(input.trim() || "{}")); + } catch (error) { + reject(error); + } + }); + process.stdin.on("error", reject); + }); +} + +module.exports = { + emit, + emitStatus, + readRequest, +}; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/src/workbook-store.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/src/workbook-store.js new file mode 100644 index 00000000..cbc31e7d --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/src/workbook-store.js @@ -0,0 +1,580 @@ +const fs = require("node:fs"); +const path = require("node:path"); +const crypto = require("node:crypto"); + +const STORE_ROOT_SEGMENTS = [".sparo_os", "excel-live"]; +const WORKBOOK_SCHEMA_VERSION = 2; +const SUPPORTED_MODES = new Set(["inspect", "edit", "author"]); +const WORKBOOK_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/; +const WINDOWS_RESERVED_NAMES = /^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$/i; + +function validateExcelSheetName(value) { + if (typeof value !== "string" || !value.trim()) { + throw new Error("[INVALID_SHEET_NAME] Worksheet name must be a non-empty string."); + } + const name = value.trim(); + if (Array.from(name).length > 31) { + throw new Error("[INVALID_SHEET_NAME] Worksheet name cannot exceed 31 characters."); + } + if (/[\\/?*\[\]:]/.test(name) || /[\u0000-\u001F]/.test(name)) { + throw new Error("[INVALID_SHEET_NAME] Worksheet name cannot contain \\ / ? * [ ] : or control characters."); + } + if (name.startsWith("'") || name.endsWith("'")) { + throw new Error("[INVALID_SHEET_NAME] Worksheet name cannot begin or end with an apostrophe."); + } + return name; +} + +function nowIso() { + return new Date().toISOString(); +} + +function newId(prefix) { + return `${prefix}_${crypto.randomBytes(8).toString("hex")}`; +} + +function ensureDir(dirPath) { + if (!dirPath) { + throw new Error("Directory path is required"); + } + fs.mkdirSync(dirPath, { recursive: true }); + return dirPath; +} + +function storeRoot(workspacePath) { + if (!workspacePath || typeof workspacePath !== "string" || !path.isAbsolute(workspacePath)) { + throw new Error( + "[INVALID_WORKSPACE_PATH] workspacePath must be a host-provided absolute path." + ); + } + return path.join(path.resolve(workspacePath), ...STORE_ROOT_SEGMENTS); +} + +function workbookDir(workspacePath, workbookId) { + const safeId = validateWorkbookId(workbookId); + const root = storeRoot(workspacePath); + const dir = path.resolve(root, safeId); + if (!dir.startsWith(`${path.resolve(root)}${path.sep}`)) { + throw new Error("[INVALID_WORKBOOK_ID] workbookId resolved outside the workbook store root."); + } + return dir; +} + +function workbookJsonPath(workspacePath, workbookId) { + return path.join(workbookDir(workspacePath, workbookId), "workbook.json"); +} + +function createEmptySheet(name, rows = 50, cols = 26) { + return { + id: newId("sheet"), + name: validateExcelSheetName(name || "Sheet1"), + rows: Math.max(1, Number(rows) || 50), + cols: Math.max(1, Number(cols) || 26), + cells: {}, + layout: defaultSheetLayout(), + }; +} + +function defaultSheetLayout() { + return { + units: { columnWidth: "excelCharacters", rowHeight: "points" }, + columns: [], + rows: [], + freezePanes: { rows: 0, columns: 0 }, + autoFilter: null, + }; +} + +function normalizeSheetLayout(value) { + const input = value && typeof value === "object" ? value : {}; + const normalizeBands = (items, sizeKey) => { + if (!Array.isArray(items)) return []; + const bands = []; + for (const item of items) { + if (!item || typeof item !== "object") continue; + const start = Number(item.start); + const end = item.end == null ? start : Number(item.end); + if (!Number.isSafeInteger(start) || !Number.isSafeInteger(end) || start < 0 || end < start) { + continue; + } + const band = { start, end }; + if (item[sizeKey] != null && Number.isFinite(Number(item[sizeKey])) && Number(item[sizeKey]) > 0) { + band[sizeKey] = Number(item[sizeKey]); + } + if (item.autoFit === true) band.autoFit = true; + if (band[sizeKey] != null || band.autoFit === true) bands.push(band); + } + return bands.sort((a, b) => a.start - b.start || a.end - b.end); + }; + const freeze = input.freezePanes && typeof input.freezePanes === "object" + ? input.freezePanes + : {}; + const freezeRows = Number(freeze.rows || 0); + const freezeColumns = Number(freeze.columns || 0); + const autoFilter = input.autoFilter && typeof input.autoFilter === "object" + && typeof input.autoFilter.a1 === "string" && input.autoFilter.a1.trim() + ? { a1: input.autoFilter.a1.trim() } + : null; + return { + units: { columnWidth: "excelCharacters", rowHeight: "points" }, + columns: normalizeBands(input.columns, "width"), + rows: normalizeBands(input.rows, "height"), + freezePanes: { + rows: Number.isSafeInteger(freezeRows) && freezeRows >= 0 ? freezeRows : 0, + columns: Number.isSafeInteger(freezeColumns) && freezeColumns >= 0 ? freezeColumns : 0, + }, + autoFilter, + }; +} + +function validateWorkbookId(workbookId) { + if ( + typeof workbookId !== "string" || + !WORKBOOK_ID_PATTERN.test(workbookId) || + WINDOWS_RESERVED_NAMES.test(workbookId) + ) { + throw new Error( + "[INVALID_WORKBOOK_ID] workbookId must be 1-128 safe ASCII characters (letters, digits, underscore, or hyphen), must start with a letter or digit, and must not be a reserved device name." + ); + } + return workbookId; +} + +function normalizeMode(value) { + return SUPPORTED_MODES.has(value) ? value : "edit"; +} + +function formatFromPath(filePath) { + const ext = path.extname(String(filePath || "")).toLowerCase(); + return ext ? ext.slice(1) : null; +} + +function defaultFidelity(sourceFormat) { + const format = String(sourceFormat || "").toLowerCase() || null; + if (!format) { + return { + level: "native", + canRoundTrip: true, + canOverwriteSource: false, + preserved: [ + "cell values", + "basic formulas", + "authored cell styles and number formats", + "column widths and row heights", + "freeze panes and auto filters", + "sheet names", + ], + unsupported: [], + warning: null, + }; + } + if (format === "json") { + return { + level: "native", + canRoundTrip: true, + canOverwriteSource: false, + preserved: ["Sparo workbook state"], + unsupported: [], + warning: "Imported sources are protected from overwrite by default.", + }; + } + if (format === "csv") { + return { + level: "limited", + canRoundTrip: false, + canOverwriteSource: false, + preserved: ["active sheet cell values"], + unsupported: ["multiple sheets", "formulas", "styles", "charts", "workbook metadata"], + warning: "CSV import does not preserve workbook features. Use Save As to avoid replacing the source.", + }; + } + if (format === "xlsx" || format === "xlsm") { + return { + level: "source-preserving", + canRoundTrip: true, + canOverwriteSource: false, + structureChanged: false, + preserved: [ + "unknown OOXML package parts", + "existing cell styles and number formats", + "existing column widths, row heights, freeze panes, and auto filters", + "sheet names and structure", + "cell values and formulas", + format === "xlsm" ? "macros and VBA package parts" : "workbook package metadata", + ], + unsupported: [ + "new or changed styles during source-preserving patch", + "new or changed layout during source-preserving patch", + "structural edits", + "formula calculation in the live engine", + ], + warning: "Value/formula-only edits can be patched into a copy of the source package. New styles or layout require an acknowledged Save As rebuild; source overwrite remains protected.", + }; + } + return { + level: "limited", + canRoundTrip: false, + canOverwriteSource: false, + preserved: ["sheet names", "cell values", "basic formulas", "cached formula values"], + unsupported: [ + "styles and number formats", + "merged cells", + "data validation", + "tables and named ranges", + "charts and drawings", + "comments and pivot tables", + "macros and VBA", + ], + warning: "This engine cannot losslessly round-trip Excel files. Use Save As to protect the source.", + }; +} + +function countFormulas(sheets) { + let count = 0; + for (const sheet of sheets || []) { + for (const cell of Object.values(sheet.cells || {})) { + if (cell && (cell.formulaEvidence === true || cell.f)) count += 1; + } + } + return count; +} + +function defaultCalculationStatus(sheets) { + const formulaCount = countFormulas(sheets); + return { + engine: "none", + status: formulaCount > 0 ? "cached" : "not-required", + formulaCount, + lastCalculatedRevision: null, + warning: formulaCount > 0 + ? "Formula results are cached values; this engine does not recalculate formulas." + : null, + }; +} + +function createEmpty(options = {}) { + const title = options.title || "Untitled Workbook"; + const rows = options.rows == null ? 50 : options.rows; + const cols = options.cols == null ? 26 : options.cols; + const sheet = createEmptySheet(options.sheetName || "Sheet1", rows, cols); + const createdAt = nowIso(); + const workbookId = options.workbookId || newId("wb"); + validateWorkbookId(workbookId); + return { + schemaVersion: WORKBOOK_SCHEMA_VERSION, + workbookId, + path: options.path || null, + sourcePath: options.sourcePath || null, + sourceFormat: options.sourceFormat || null, + sourceFingerprint: options.sourceFingerprint || null, + lastExportPath: null, + lastExportedRevision: null, + lastExportFingerprint: null, + title, + sheets: [sheet], + activeSheetId: sheet.id, + dirty: false, + revision: 0, + mode: normalizeMode(options.mode), + focus: { + sheetId: sheet.id, + a1: "A1", + kind: "cell", + }, + proposal: null, + fidelity: defaultFidelity(options.sourceFormat), + calculationStatus: defaultCalculationStatus([sheet]), + history: [], + undoStack: [], + redoStack: [], + createdAt, + updatedAt: createdAt, + }; +} + +function normalizeWorkbook(raw) { + if (!raw || typeof raw !== "object") { + throw new Error("Invalid workbook JSON"); + } + if (!raw.workbookId) { + throw new Error("Workbook is missing workbookId"); + } + validateWorkbookId(raw.workbookId); + if (!Array.isArray(raw.sheets) || raw.sheets.length === 0) { + throw new Error("Workbook must contain at least one sheet"); + } + const normalizedSheetNames = new Set(); + const sheets = raw.sheets.map((sheet, index) => { + if (!sheet || typeof sheet !== "object") { + throw new Error(`Invalid sheet at index ${index}`); + } + const name = validateExcelSheetName(sheet.name || `Sheet${index + 1}`); + const nameKey = name.toLowerCase(); + if (normalizedSheetNames.has(nameKey)) { + throw new Error(`[DUPLICATE_SHEET_NAME] Worksheet name already exists: ${name}`); + } + normalizedSheetNames.add(nameKey); + return { + id: sheet.id || newId("sheet"), + name, + rows: Math.max(1, Number(sheet.rows) || 50), + cols: Math.max(1, Number(sheet.cols) || 26), + cells: sheet.cells && typeof sheet.cells === "object" ? sheet.cells : {}, + layout: normalizeSheetLayout(sheet.layout), + complexFormulaRanges: Array.isArray(sheet.complexFormulaRanges) + ? sheet.complexFormulaRanges + : [], + }; + }); + const activeSheetId = + sheets.find((s) => s.id === raw.activeSheetId)?.id || sheets[0].id; + const focus = raw.focus && typeof raw.focus === "object" + ? { + sheetId: sheets.find((s) => s.id === raw.focus.sheetId)?.id || activeSheetId, + a1: raw.focus.a1 || "A1", + kind: raw.focus.kind || "cell", + } + : { sheetId: activeSheetId, a1: "A1", kind: "cell" }; + + const revision = Number.isSafeInteger(raw.revision) && raw.revision >= 0 + ? raw.revision + : 0; + const sourcePath = raw.sourcePath || raw.source?.path || raw.path || null; + const sourceFormat = raw.sourceFormat || raw.source?.format || formatFromPath(sourcePath); + const defaultCalculation = defaultCalculationStatus(sheets); + const calculationStatus = raw.calculationStatus && typeof raw.calculationStatus === "object" + ? { + ...defaultCalculation, + ...raw.calculationStatus, + formulaCount: defaultCalculation.formulaCount, + } + : defaultCalculation; + const proposal = raw.proposal && typeof raw.proposal === "object" + ? { + ...raw.proposal, + baseRevision: Number.isSafeInteger(raw.proposal.baseRevision) + ? raw.proposal.baseRevision + : revision, + intent: raw.proposal.intent || null, + validation: raw.proposal.validation || null, + layout: raw.proposal.layout && typeof raw.proposal.layout === "object" + ? { + before: normalizeSheetLayout(raw.proposal.layout.before), + after: normalizeSheetLayout(raw.proposal.layout.after), + } + : null, + } + : null; + + return { + schemaVersion: WORKBOOK_SCHEMA_VERSION, + workbookId: raw.workbookId, + path: raw.path || null, + sourcePath, + sourceFormat, + sourceFingerprint: + raw.sourceFingerprint && typeof raw.sourceFingerprint === "object" + ? raw.sourceFingerprint + : null, + lastExportPath: raw.lastExportPath || null, + lastExportedRevision: Number.isSafeInteger(raw.lastExportedRevision) + ? raw.lastExportedRevision + : null, + lastExportFingerprint: + raw.lastExportFingerprint && typeof raw.lastExportFingerprint === "object" + ? raw.lastExportFingerprint + : null, + title: raw.title || "Untitled Workbook", + sheets, + activeSheetId, + dirty: Boolean(raw.dirty), + revision, + mode: normalizeMode(raw.mode), + focus, + proposal, + fidelity: raw.fidelity && typeof raw.fidelity === "object" + ? { ...defaultFidelity(sourceFormat), ...raw.fidelity } + : defaultFidelity(sourceFormat), + calculationStatus, + history: Array.isArray(raw.history) ? raw.history.slice(-500) : [], + undoStack: Array.isArray(raw.undoStack) ? raw.undoStack.slice(-100) : [], + redoStack: Array.isArray(raw.redoStack) ? raw.redoStack.slice(-100) : [], + createdAt: raw.createdAt || nowIso(), + updatedAt: raw.updatedAt || nowIso(), + }; +} + +function loadJson(workspacePath, workbookId) { + const filePath = workbookJsonPath(workspacePath, workbookId); + if (!fs.existsSync(filePath)) { + throw new Error(`Workbook store not found: ${filePath}`); + } + const text = fs.readFileSync(filePath, "utf8"); + let parsed; + try { + parsed = JSON.parse(text); + } catch (error) { + throw new Error(`Failed to parse workbook store JSON: ${error.message}`); + } + return normalizeWorkbook(parsed); +} + +function listWorkbookMetas(workspacePath) { + const root = storeRoot(workspacePath); + if (!fs.existsSync(root)) return []; + const metas = []; + for (const entry of fs.readdirSync(root, { withFileTypes: true })) { + if (!entry.isDirectory()) continue; + const filePath = path.join(root, entry.name, "workbook.json"); + if (!fs.existsSync(filePath)) continue; + try { + const parsed = JSON.parse(fs.readFileSync(filePath, "utf8")); + if (!parsed || !parsed.workbookId) continue; + validateWorkbookId(parsed.workbookId); + metas.push({ + workbookId: parsed.workbookId, + title: parsed.title || "Untitled Workbook", + path: parsed.path || null, + dirty: Boolean(parsed.dirty), + revision: Number.isSafeInteger(parsed.revision) ? parsed.revision : 0, + mode: normalizeMode(parsed.mode), + sourcePath: parsed.sourcePath || parsed.path || null, + sourceFormat: parsed.sourceFormat || formatFromPath(parsed.sourcePath || parsed.path), + sourceFingerprint: + parsed.sourceFingerprint && typeof parsed.sourceFingerprint === "object" + ? parsed.sourceFingerprint + : null, + lastExportPath: parsed.lastExportPath || null, + lastExportedRevision: Number.isSafeInteger(parsed.lastExportedRevision) + ? parsed.lastExportedRevision + : null, + lastExportFingerprint: + parsed.lastExportFingerprint && typeof parsed.lastExportFingerprint === "object" + ? parsed.lastExportFingerprint + : null, + sheetCount: Array.isArray(parsed.sheets) ? parsed.sheets.length : 0, + createdAt: parsed.createdAt || null, + updatedAt: parsed.updatedAt || null, + }); + } catch (_error) { + // Skip unreadable stores; they should not break listing. + } + } + metas.sort((a, b) => String(b.updatedAt || "").localeCompare(String(a.updatedAt || ""))); + return metas; +} + +function normalizePathIdentity(value, platform = process.platform) { + const resolved = path.resolve(String(value || "")).replaceAll("\\", "/"); + return platform === "win32" ? resolved.toLowerCase() : resolved; +} + +function findWorkbookIdByPath(workspacePath, filePath) { + if (!filePath) return null; + const wanted = normalizePathIdentity(filePath); + for (const meta of listWorkbookMetas(workspacePath)) { + if ( + (meta.sourcePath && normalizePathIdentity(meta.sourcePath) === wanted) || + (meta.path && normalizePathIdentity(meta.path) === wanted) + ) { + return meta.workbookId; + } + } + return null; +} + +function saveJson(workspacePath, workbook) { + if (!workbook || !workbook.workbookId) { + throw new Error("Cannot save workbook without workbookId"); + } + const dir = workbookDir(workspacePath, workbook.workbookId); + ensureDir(dir); + const next = { + ...workbook, + updatedAt: nowIso(), + }; + const filePath = workbookJsonPath(workspacePath, workbook.workbookId); + const tempPath = path.join( + dir, + `.workbook.json.${process.pid}.${crypto.randomBytes(6).toString("hex")}.tmp` + ); + let handle = null; + try { + handle = fs.openSync(tempPath, "wx", 0o600); + fs.writeFileSync(handle, `${JSON.stringify(next, null, 2)}\n`, "utf8"); + fs.fsyncSync(handle); + fs.closeSync(handle); + handle = null; + fs.renameSync(tempPath, filePath); + } catch (error) { + if (handle != null) { + try { + fs.closeSync(handle); + } catch (_closeError) { + // Preserve the original save error. + } + } + try { + if (fs.existsSync(tempPath)) fs.unlinkSync(tempPath); + } catch (_cleanupError) { + // Best-effort cleanup; never mask the original save error. + } + throw new Error(`Failed to atomically save workbook store: ${error.message}`); + } + return next; +} + +function cellKey(row, col) { + return `${row},${col}`; +} + +function getSheet(workbook, sheetId) { + if (!workbook) { + throw new Error("Workbook is required"); + } + const id = sheetId || workbook.activeSheetId; + const sheet = workbook.sheets.find((s) => s.id === id); + if (!sheet) { + throw new Error(`Sheet not found: ${id}`); + } + return sheet; +} + +function findSheetByName(workbook, name) { + if (!name) { + return null; + } + const lower = String(name).toLowerCase(); + return workbook.sheets.find((s) => String(s.name).toLowerCase() === lower) || null; +} + +module.exports = { + STORE_ROOT_SEGMENTS, + WORKBOOK_SCHEMA_VERSION, + WORKBOOK_ID_PATTERN, + ensureDir, + storeRoot, + workbookDir, + workbookJsonPath, + createEmptySheet, + defaultSheetLayout, + normalizeSheetLayout, + createEmpty, + validateWorkbookId, + validateExcelSheetName, + defaultFidelity, + defaultCalculationStatus, + normalizeMode, + formatFromPath, + normalizeWorkbook, + loadJson, + saveJson, + listWorkbookMetas, + findWorkbookIdByPath, + normalizePathIdentity, + cellKey, + getSheet, + findSheetByName, + newId, + nowIso, +}; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/src/xlsx-io.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/src/xlsx-io.js new file mode 100644 index 00000000..0b7ef12a --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/src/xlsx-io.js @@ -0,0 +1,1997 @@ +/** + * Minimal XLSX / CSV / JSON workbook I/O using only Node builtins. + * ZIP: local file header reader + inflateRaw for deflated entries. + * WRITE: store-method ZIP with a minimal OOXML package openable in Excel. + */ + +const fs = require("node:fs"); +const path = require("node:path"); +const zlib = require("node:zlib"); +const crypto = require("node:crypto"); +const { + MAX_CSV_PARSED_CELLS, + parseCsv, + serializeCsv, +} = require("./csv-io"); +const { + WORKBOOK_SCHEMA_VERSION, + createEmpty, + createEmptySheet, + defaultSheetLayout, + cellKey, + newId, + nowIso, + defaultFidelity, + defaultCalculationStatus, + formatFromPath, + normalizeWorkbook, + validateExcelSheetName, +} = require("./workbook-store"); +const { + EXCEL_MAX_COLUMNS, + EXCEL_MAX_ROWS, + assertCellCoordinates, + assertSheetDimensions, + cellCount, + indexToCol, +} = require("./a1"); + +const SIG_LOCAL = 0x04034b50; +const SIG_CENTRAL = 0x02014b50; +const SIG_END = 0x06054b50; +const METHOD_STORE = 0; +const METHOD_DEFLATE = 8; +const MAX_ZIP_ENTRIES = 4096; +const MAX_ZIP_FILE_BYTES = 256 * 1024 * 1024; +const MAX_ZIP_ENTRY_BYTES = 128 * 1024 * 1024; +const MAX_ZIP_TOTAL_BYTES = 512 * 1024 * 1024; +const MAX_ZIP_COMPRESSION_RATIO = 200; +const MAX_CSV_FILE_BYTES = 64 * 1024 * 1024; +const MAX_JSON_FILE_BYTES = 64 * 1024 * 1024; +const MAX_XLSX_PARSED_CELLS = 500_000; +const MAX_DENSE_EXPORT_CELLS = 1_000_000; +const MAX_COMPLEX_FORMULA_COVERAGE_CELLS = 500_000; +const MAX_AUTHORED_CELL_STYLES = 10_000; + +function fileFingerprint(buffer, stat) { + return { + algorithm: "sha256", + hash: crypto.createHash("sha256").update(buffer).digest("hex"), + size: buffer.length, + mtimeMs: Number(stat.mtimeMs), + }; +} + +function readStableFile(filePath, options = {}) { + const maxBytes = options.maxBytes ?? MAX_ZIP_FILE_BYTES; + const sizeLimitCode = options.sizeLimitCode || "ZIP_FILE_SIZE_LIMIT"; + const fileKind = options.fileKind || "Workbook file"; + const before = fs.statSync(filePath); + if (!before.isFile()) throw new Error(`Not a regular file: ${filePath}`); + if (before.size > maxBytes) { + throw new Error( + `[${sizeLimitCode}] ${fileKind} is ${before.size} bytes; maximum is ${maxBytes}.` + ); + } + const buffer = fs.readFileSync(filePath); + const after = fs.statSync(filePath); + if ( + before.size !== after.size || + Number(before.mtimeMs) !== Number(after.mtimeMs) || + buffer.length !== after.size + ) { + throw new Error( + `[SOURCE_CHANGED_DURING_READ] ${filePath} changed while it was being read. Retry after external writes finish.` + ); + } + return { buffer, fingerprint: fileFingerprint(buffer, after) }; +} + +function fingerprintsEqual(left, right) { + return Boolean( + left && + right && + left.algorithm === "sha256" && + right.algorithm === "sha256" && + left.hash === right.hash && + left.size === right.size && + Number(left.mtimeMs) === Number(right.mtimeMs) + ); +} + +function realpathNative(filePath) { + return fs.realpathSync.native ? fs.realpathSync.native(filePath) : fs.realpathSync(filePath); +} + +function identityPathKey(filePath) { + const normalized = path.normalize(path.resolve(filePath)); + return process.platform === "win32" ? normalized.toLowerCase() : normalized; +} + +function sameFileIdentity(leftPath, rightPath) { + const left = fs.statSync(leftPath, { bigint: true }); + const right = fs.statSync(rightPath, { bigint: true }); + return left.ino !== 0n && left.dev === right.dev && left.ino === right.ino; +} + +/** + * Resolve the target parent before writing and reject every known alias of the + * imported source (direct path, symlink/junction path, or existing hard link). + * The returned path keeps the requested basename but anchors the write in the + * already-resolved parent directory, so a parent alias is not followed again. + */ +function assertDistinctSourceTarget(sourcePath, targetPath) { + try { + const sourceRealPath = realpathNative(sourcePath); + const targetAbsolutePath = path.resolve(targetPath); + const targetParentRealPath = realpathNative(path.dirname(targetAbsolutePath)); + const resolvedTargetPath = path.join(targetParentRealPath, path.basename(targetAbsolutePath)); + let targetRealPath = null; + let targetExists = false; + try { + targetRealPath = realpathNative(targetAbsolutePath); + targetExists = true; + } catch (error) { + if (error?.code !== "ENOENT") throw error; + } + + const aliasesSource = + identityPathKey(sourceRealPath) === identityPathKey(resolvedTargetPath) || + (targetRealPath != null && + identityPathKey(sourceRealPath) === identityPathKey(targetRealPath)) || + (targetExists && sameFileIdentity(sourceRealPath, targetAbsolutePath)); + if (aliasesSource) { + throw new Error( + `[SOURCE_TARGET_ALIAS_BLOCKED] Export target ${targetPath} resolves to or identifies the imported source package. Choose a different output file.` + ); + } + return resolvedTargetPath; + } catch (error) { + if (/^\[SOURCE_TARGET_ALIAS_BLOCKED\]/.test(String(error.message || ""))) throw error; + throw new Error( + `[SOURCE_TARGET_IDENTITY_CHECK_FAILED] Could not verify that ${targetPath} is distinct from ${sourcePath}: ${error.message}` + ); + } +} + +function crc32(buf) { + let crc = 0xffffffff; + const table = crc32.table || (crc32.table = (() => { + const t = new Uint32Array(256); + for (let i = 0; i < 256; i += 1) { + let c = i; + for (let k = 0; k < 8; k += 1) { + c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1; + } + t[i] = c >>> 0; + } + return t; + })()); + const data = Buffer.isBuffer(buf) ? buf : Buffer.from(buf); + for (let i = 0; i < data.length; i += 1) { + crc = table[(crc ^ data[i]) & 0xff] ^ (crc >>> 8); + } + return (crc ^ 0xffffffff) >>> 0; +} + +function decodeXmlEntities(text) { + return String(text || "") + .replace(/</g, "<") + .replace(/>/g, ">") + .replace(/"/g, '"') + .replace(/'/g, "'") + .replace(/&#(\d+);/g, (_, n) => String.fromCharCode(Number(n))) + .replace(/&#x([0-9a-fA-F]+);/g, (_, h) => String.fromCharCode(parseInt(h, 16))) + .replace(/&/g, "&"); +} + +function escapeXml(text) { + return String(text == null ? "" : text) + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """); +} + +/** + * Read ZIP local file entries (sufficient for typical xlsx packages). + * @returns {Map} + */ +function unzipBuffer(buffer) { + const buf = Buffer.isBuffer(buffer) ? buffer : Buffer.from(buffer); + const files = new Map(); + if (buf.length > MAX_ZIP_FILE_BYTES) { + throw new Error( + `[ZIP_FILE_SIZE_LIMIT] Workbook ZIP is ${buf.length} bytes; maximum is ${MAX_ZIP_FILE_BYTES}.` + ); + } + if (buf.length < 22) throw new Error("Corrupt ZIP: file is too small"); + let endOffset = -1; + const minOffset = Math.max(0, buf.length - 0xffff - 22); + for (let offset = buf.length - 22; offset >= minOffset; offset -= 1) { + if (buf.readUInt32LE(offset) === SIG_END) { + endOffset = offset; + break; + } + } + if (endOffset < 0) { + throw new Error("Corrupt ZIP: end-of-central-directory record not found"); + } + const entryCount = buf.readUInt16LE(endOffset + 10); + const centralOffset = buf.readUInt32LE(endOffset + 16); + if (entryCount === 0xffff || centralOffset === 0xffffffff) { + throw new Error("ZIP64 workbooks are not supported"); + } + if (entryCount > MAX_ZIP_ENTRIES) { + throw new Error( + `[ZIP_ENTRY_LIMIT] Workbook ZIP has ${entryCount} entries; maximum is ${MAX_ZIP_ENTRIES}.` + ); + } + const entries = []; + let totalUncompressedSize = 0; + let offset = centralOffset; + for (let index = 0; index < entryCount; index += 1) { + if (offset + 46 > buf.length || buf.readUInt32LE(offset) !== SIG_CENTRAL) { + throw new Error("Corrupt ZIP: invalid central directory entry"); + } + const flags = buf.readUInt16LE(offset + 8); + const method = buf.readUInt16LE(offset + 10); + const expectedCrc = buf.readUInt32LE(offset + 16); + const compressedSize = buf.readUInt32LE(offset + 20); + const uncompressedSize = buf.readUInt32LE(offset + 24); + const nameLen = buf.readUInt16LE(offset + 28); + const extraLen = buf.readUInt16LE(offset + 30); + const commentLen = buf.readUInt16LE(offset + 32); + const localOffset = buf.readUInt32LE(offset + 42); + if (flags & 0x1) throw new Error("Encrypted ZIP entries are not supported"); + const nameStart = offset + 46; + const nameEnd = nameStart + nameLen; + if (nameEnd + extraLen + commentLen > buf.length) { + throw new Error("Corrupt ZIP: truncated central directory entry"); + } + const name = buf.slice(nameStart, nameEnd).toString(flags & 0x800 ? "utf8" : "utf8"); + if (uncompressedSize > MAX_ZIP_ENTRY_BYTES) { + throw new Error( + `[ZIP_ENTRY_SIZE_LIMIT] ZIP entry ${name} declares ${uncompressedSize} bytes; maximum is ${MAX_ZIP_ENTRY_BYTES}.` + ); + } + totalUncompressedSize += uncompressedSize; + if (totalUncompressedSize > MAX_ZIP_TOTAL_BYTES) { + throw new Error( + `[ZIP_TOTAL_SIZE_LIMIT] Workbook ZIP declares ${totalUncompressedSize} uncompressed bytes; maximum is ${MAX_ZIP_TOTAL_BYTES}.` + ); + } + if ( + method === METHOD_DEFLATE && + uncompressedSize > 0 && + (compressedSize === 0 || uncompressedSize / compressedSize > MAX_ZIP_COMPRESSION_RATIO) + ) { + throw new Error( + `[ZIP_COMPRESSION_RATIO_LIMIT] ZIP entry ${name} exceeds the maximum compression ratio of ${MAX_ZIP_COMPRESSION_RATIO}:1.` + ); + } + if (method !== METHOD_STORE && method !== METHOD_DEFLATE) { + throw new Error(`Unsupported ZIP compression method ${method} for ${name}`); + } + if (localOffset + 30 > buf.length || buf.readUInt32LE(localOffset) !== SIG_LOCAL) { + throw new Error(`Corrupt ZIP: local header missing for ${name}`); + } + const localNameLen = buf.readUInt16LE(localOffset + 26); + const localExtraLen = buf.readUInt16LE(localOffset + 28); + const dataStart = localOffset + 30 + localNameLen + localExtraLen; + const dataEnd = dataStart + compressedSize; + if (dataEnd > buf.length) throw new Error(`Corrupt ZIP: truncated entry ${name}`); + entries.push({ + name, + method, + expectedCrc, + compressedSize, + uncompressedSize, + dataStart, + dataEnd, + }); + offset = nameEnd + extraLen + commentLen; + } + + for (const entry of entries) { + const compressed = buf.slice(entry.dataStart, entry.dataEnd); + let content; + if (entry.method === METHOD_STORE) { + content = compressed; + } else { + try { + content = zlib.inflateRawSync(compressed, { + maxOutputLength: Math.max(1, entry.uncompressedSize), + }); + } catch (error) { + throw new Error(`Failed to inflate ZIP entry ${entry.name}: ${error.message}`); + } + } + if (content.length !== entry.uncompressedSize || crc32(content) !== entry.expectedCrc) { + throw new Error(`Corrupt ZIP: size or CRC mismatch for ${entry.name}`); + } + if (!entry.name.endsWith("/")) { + files.set(entry.name.replace(/\\/g, "/"), content); + } + } + + if (files.size === 0) { + throw new Error("ZIP archive contained no files"); + } + return files; +} + +function dosDateTime(date = new Date()) { + const year = Math.max(1980, date.getFullYear()); + const dosTime = + (date.getHours() << 11) | + (date.getMinutes() << 5) | + Math.floor(date.getSeconds() / 2); + const dosDate = + ((year - 1980) << 9) | ((date.getMonth() + 1) << 5) | date.getDate(); + return { dosTime, dosDate }; +} + +/** + * Build a ZIP archive using STORE (no compression) for simplicity and reliability. + * @param {Array<{ name: string, data: Buffer|string }>} entries + */ +function zipStore(entries) { + const { dosTime, dosDate } = dosDateTime(); + const localParts = []; + const centralParts = []; + let offset = 0; + + for (const entry of entries) { + const name = String(entry.name).replace(/\\/g, "/"); + const nameBuf = Buffer.from(name, "utf8"); + const data = Buffer.isBuffer(entry.data) + ? entry.data + : Buffer.from(entry.data == null ? "" : String(entry.data), "utf8"); + const crc = crc32(data); + const size = data.length; + + const local = Buffer.alloc(30); + local.writeUInt32LE(SIG_LOCAL, 0); + local.writeUInt16LE(20, 4); // version needed + local.writeUInt16LE(0, 6); // flags + local.writeUInt16LE(METHOD_STORE, 8); + local.writeUInt16LE(dosTime, 10); + local.writeUInt16LE(dosDate, 12); + local.writeUInt32LE(crc, 14); + local.writeUInt32LE(size, 18); + local.writeUInt32LE(size, 22); + local.writeUInt16LE(nameBuf.length, 26); + local.writeUInt16LE(0, 28); + + const central = Buffer.alloc(46); + central.writeUInt32LE(SIG_CENTRAL, 0); + central.writeUInt16LE(20, 4); // version made by + central.writeUInt16LE(20, 6); // version needed + central.writeUInt16LE(0, 8); + central.writeUInt16LE(METHOD_STORE, 10); + central.writeUInt16LE(dosTime, 12); + central.writeUInt16LE(dosDate, 14); + central.writeUInt32LE(crc, 16); + central.writeUInt32LE(size, 20); + central.writeUInt32LE(size, 24); + central.writeUInt16LE(nameBuf.length, 28); + central.writeUInt16LE(0, 30); // extra + central.writeUInt16LE(0, 32); // comment + central.writeUInt16LE(0, 34); // disk + central.writeUInt16LE(0, 36); // int attrs + central.writeUInt32LE(0, 38); // ext attrs + central.writeUInt32LE(offset, 42); + + localParts.push(local, nameBuf, data); + centralParts.push(central, nameBuf); + offset += local.length + nameBuf.length + data.length; + } + + const centralDir = Buffer.concat(centralParts); + const end = Buffer.alloc(22); + end.writeUInt32LE(SIG_END, 0); + end.writeUInt16LE(0, 4); + end.writeUInt16LE(0, 6); + end.writeUInt16LE(entries.length, 8); + end.writeUInt16LE(entries.length, 10); + end.writeUInt32LE(centralDir.length, 12); + end.writeUInt32LE(offset, 16); + end.writeUInt16LE(0, 20); + + return Buffer.concat([...localParts, centralDir, end]); +} + +function parseSharedStrings(xml) { + const strings = []; + if (!xml) { + return strings; + } + const text = String(xml); + // Match each ... block + const siRe = /]*>([\s\S]*?)<\/si>/gi; + let match; + while ((match = siRe.exec(text))) { + const block = match[1]; + const parts = []; + const tRe = /]*>([\s\S]*?)<\/t>/gi; + let tMatch; + while ((tMatch = tRe.exec(block))) { + parts.push(decodeXmlEntities(tMatch[1])); + } + strings.push(parts.join("")); + } + return strings; +} + +function parseSheetNames(workbookXml) { + const names = []; + if (!workbookXml) { + return names; + } + const re = /]*\bname="([^"]+)"[^>]*>/gi; + let match; + while ((match = re.exec(String(workbookXml)))) { + names.push(decodeXmlEntities(match[1])); + } + return names; +} + +const BUILTIN_NUMBER_FORMATS = Object.freeze({ + 0: "General", 1: "0", 2: "0.00", 3: "#,##0", 4: "#,##0.00", + 9: "0%", 10: "0.00%", 11: "0.00E+00", 12: "# ?/?", 13: "# ??/??", + 14: "mm-dd-yy", 15: "d-mmm-yy", 16: "d-mmm", 17: "mmm-yy", + 18: "h:mm AM/PM", 19: "h:mm:ss AM/PM", 20: "h:mm", 21: "h:mm:ss", 22: "m/d/yy h:mm", + 37: "#,##0 ;(#,##0)", 38: "#,##0 ;[Red](#,##0)", 39: "#,##0.00;(#,##0.00)", + 40: "#,##0.00;[Red](#,##0.00)", 49: "@", +}); + +function xmlAttribute(attrs, name) { + const match = String(attrs || "").match(new RegExp(`\\b${name}="([^"]*)"`, "i")); + return match ? decodeXmlEntities(match[1]) : null; +} + +function xmlElements(xml, tag) { + const elements = []; + const re = new RegExp(`<${tag}\\b([^>]*?)(?:>([\\s\\S]*?)<\\/${tag}>|\\/\\s*>)`, "gi"); + let match; + while ((match = re.exec(String(xml || "")))) elements.push({ attrs: match[1] || "", body: match[2] || "" }); + return elements; +} + +function rgbToColor(rgb) { + const value = String(rgb || "").trim().toUpperCase(); + if (/^[0-9A-F]{8}$/.test(value)) return `#${value.slice(2)}`; + if (/^[0-9A-F]{6}$/.test(value)) return `#${value}`; + return null; +} + +function parseXmlColor(xml) { + const attrs = String(xml || "").match(/]*)\/?\s*>/i)?.[1] + || String(xml || "").match(/]*)\/?\s*>/i)?.[1] + || ""; + return rgbToColor(xmlAttribute(attrs, "rgb")); +} + +function parseStyles(xml) { + const text = String(xml || ""); + if (!text) return []; + const customNumberFormats = new Map(); + for (const item of xmlElements(text.match(/]*>([\s\S]*?)<\/numFmts>/i)?.[1] || "", "numFmt")) { + const id = Number(xmlAttribute(item.attrs, "numFmtId")); + const code = xmlAttribute(item.attrs, "formatCode"); + if (Number.isSafeInteger(id) && code) customNumberFormats.set(id, code); + } + const fonts = xmlElements(text.match(/]*>([\s\S]*?)<\/fonts>/i)?.[1] || "", "font").map((item) => { + const font = {}; + if (/]*\bval="([^"]+)"/i)?.[1]); + if (Number.isFinite(size) && size > 0) font.size = size; + return Object.keys(font).length ? font : null; + }); + const fills = xmlElements(text.match(/]*>([\s\S]*?)<\/fills>/i)?.[1] || "", "fill").map((item) => { + const color = parseXmlColor(item.body); + return color ? { color } : null; + }); + const borders = xmlElements(text.match(/]*>([\s\S]*?)<\/borders>/i)?.[1] || "", "border").map((item) => { + const border = {}; + for (const side of ["top", "right", "bottom", "left"]) { + const match = item.body.match(new RegExp(`<${side}\\b([^>]*?)(?:>([\\s\\S]*?)<\\/${side}>|\\/\\s*>)`, "i")); + if (!match) continue; + const style = xmlAttribute(match[1], "style"); + if (!style) continue; + border[side] = { style }; + const color = parseXmlColor(match[2]); + if (color) border[side].color = color; + } + return Object.keys(border).length ? border : null; + }); + const cellXfs = text.match(/]*>([\s\S]*?)<\/cellXfs>/i)?.[1] || ""; + return xmlElements(cellXfs, "xf").map((xf) => { + const style = {}; + const fontId = Number(xmlAttribute(xf.attrs, "fontId")); + const fillId = Number(xmlAttribute(xf.attrs, "fillId")); + const borderId = Number(xmlAttribute(xf.attrs, "borderId")); + const numFmtId = Number(xmlAttribute(xf.attrs, "numFmtId")); + if (fonts[fontId]) style.font = fonts[fontId]; + if (fills[fillId]) style.fill = fills[fillId]; + if (borders[borderId]) style.border = borders[borderId]; + const numberFormat = customNumberFormats.get(numFmtId) || BUILTIN_NUMBER_FORMATS[numFmtId]; + if (numberFormat && numFmtId !== 0) style.numberFormat = numberFormat; + const alignmentAttrs = xf.body.match(/]*)\/?\s*>/i)?.[1]; + if (alignmentAttrs != null) { + const alignment = {}; + const horizontal = xmlAttribute(alignmentAttrs, "horizontal"); + const vertical = xmlAttribute(alignmentAttrs, "vertical"); + if (horizontal) alignment.horizontal = horizontal; + if (vertical) alignment.vertical = vertical; + if (xmlAttribute(alignmentAttrs, "wrapText") === "1") alignment.wrapText = true; + if (Object.keys(alignment).length) style.alignment = alignment; + } + return Object.keys(style).length ? style : null; + }); +} + +function parseWorksheetLayout(xml) { + const text = String(xml || ""); + const columns = []; + const colsBody = text.match(/]*>([\s\S]*?)<\/cols>/i)?.[1] || ""; + for (const column of xmlElements(colsBody, "col")) { + const start = Number(xmlAttribute(column.attrs, "min")) - 1; + const end = Number(xmlAttribute(column.attrs, "max")) - 1; + const width = Number(xmlAttribute(column.attrs, "width")); + if (!Number.isSafeInteger(start) || !Number.isSafeInteger(end) || start < 0 || end < start) continue; + const band = { start, end }; + if (Number.isFinite(width) && width > 0) band.width = width; + if (xmlAttribute(column.attrs, "bestFit") === "1") band.autoFit = true; + if (band.width != null || band.autoFit) columns.push(band); + } + const rows = []; + const rowRe = /]*?)(?:>[\s\S]*?<\/row>|\/\s*>)/gi; + let rowMatch; + while ((rowMatch = rowRe.exec(text))) { + const row = Number(xmlAttribute(rowMatch[1], "r")) - 1; + const height = Number(xmlAttribute(rowMatch[1], "ht")); + if (!Number.isSafeInteger(row) || row < 0) continue; + if (Number.isFinite(height) && height > 0) rows.push({ start: row, end: row, height }); + } + const paneAttrs = text.match(/]*)\/?\s*>/i)?.[1] || ""; + const paneState = xmlAttribute(paneAttrs, "state"); + const freezePanes = { + rows: paneState && paneState.toLowerCase().startsWith("frozen") ? Math.max(0, Number(xmlAttribute(paneAttrs, "ySplit")) || 0) : 0, + columns: paneState && paneState.toLowerCase().startsWith("frozen") ? Math.max(0, Number(xmlAttribute(paneAttrs, "xSplit")) || 0) : 0, + }; + const filterRef = text.match(/]*\bref="([^"]+)"/i)?.[1] || null; + return { + units: { columnWidth: "excelCharacters", rowHeight: "points" }, + columns, + rows, + freezePanes, + autoFilter: filterRef ? { a1: decodeXmlEntities(filterRef).replaceAll("$", "") } : null, + }; +} + +function parseWorkbookSheetRefs(workbookXml) { + const sheets = []; + const re = /]*)\/?\s*>/gi; + let match; + while ((match = re.exec(String(workbookXml || "")))) { + const attrs = match[1] || ""; + const nameMatch = attrs.match(/\bname="([^"]+)"/i); + const relMatch = attrs.match(/\br:id="([^"]+)"/i); + if (nameMatch && relMatch) { + sheets.push({ name: decodeXmlEntities(nameMatch[1]), relId: relMatch[1] }); + } + } + return sheets; +} + +function parseRelationships(xml) { + const relationships = new Map(); + const re = /]*)\/?\s*>/gi; + let match; + while ((match = re.exec(String(xml || "")))) { + const attrs = match[1] || ""; + const id = attrs.match(/\bId="([^"]+)"/i)?.[1]; + const target = attrs.match(/\bTarget="([^"]+)"/i)?.[1]; + const type = attrs.match(/\bType="([^"]+)"/i)?.[1] || ""; + if (id && target) relationships.set(id, { target: decodeXmlEntities(target), type }); + } + return relationships; +} + +function resolveWorkbookTarget(target) { + const normalized = String(target || "").replaceAll("\\", "/"); + if (normalized.startsWith("/")) return normalized.slice(1); + if (normalized.startsWith("xl/")) return path.posix.normalize(normalized); + return path.posix.normalize(path.posix.join("xl", normalized)); +} + +function parseCellRef(ref) { + const normalized = String(ref || "").toUpperCase(); + const match = normalized.match(/^([A-Z]+)([1-9]\d*)$/); + if (!match) { + throw new Error( + `[XLSX_CELL_REF_INVALID] Worksheet contains an invalid cell reference: ${JSON.stringify(ref)}.` + ); + } + if (match[1].length > 3 || match[2].length > 7) { + throw new Error( + `[XLSX_CELL_REF_LIMIT] Cell reference ${normalized} exceeds Excel's maximum of ${EXCEL_MAX_ROWS} rows and ${EXCEL_MAX_COLUMNS} columns (XFD).` + ); + } + const rowNumber = Number(match[2]); + if (!Number.isSafeInteger(rowNumber) || rowNumber < 1 || rowNumber > EXCEL_MAX_ROWS) { + throw new Error( + `[XLSX_CELL_REF_LIMIT] Cell reference ${normalized} exceeds Excel's maximum of ${EXCEL_MAX_ROWS} rows.` + ); + } + let columnNumber = 0; + for (const character of match[1]) { + columnNumber = columnNumber * 26 + character.charCodeAt(0) - 64; + if (!Number.isSafeInteger(columnNumber) || columnNumber > EXCEL_MAX_COLUMNS) { + throw new Error( + `[XLSX_CELL_REF_LIMIT] Cell reference ${normalized} exceeds Excel's maximum of ${EXCEL_MAX_COLUMNS} columns (XFD).` + ); + } + } + return { + c: columnNumber - 1, + r: rowNumber - 1, + }; +} + +function assertZeroBasedCellCoordinates(row, column, context) { + try { + assertCellCoordinates(row, column, context); + } catch (_error) { + throw new Error( + `[XLSX_CELL_REF_LIMIT] ${context} must use safe integer coordinates within rows 0-${EXCEL_MAX_ROWS - 1} and columns 0-${EXCEL_MAX_COLUMNS - 1}.` + ); + } +} + +function createCellParseBudget() { + return { parsed: 0, limit: MAX_XLSX_PARSED_CELLS }; +} + +function consumeCellParseBudget(budget) { + budget.parsed += 1; + if (!Number.isSafeInteger(budget.parsed) || budget.parsed > budget.limit) { + throw new Error( + `[XLSX_CELL_COUNT_LIMIT] Workbook contains more than ${budget.limit} serialized cell records.` + ); + } +} + +function formulaAttribute(attrs, name) { + return String(attrs || "").match( + new RegExp(`\\b${name}="([^"]*)"`, "i") + )?.[1] || null; +} + +function parseFormulaRangeRef(ref, formulaType, anchor) { + const normalized = String(ref || "").replaceAll("$", "").trim(); + if (!normalized) { + return { + type: formulaType, + ref: null, + r1: anchor.r, + c1: anchor.c, + r2: anchor.r, + c2: anchor.c, + }; + } + const parts = normalized.split(":"); + if (parts.length < 1 || parts.length > 2) { + throw new Error( + `[COMPLEX_FORMULA_REF_INVALID] Invalid ${formulaType} formula range: ${ref}` + ); + } + const start = parseCellRef(parts[0]); + const end = parseCellRef(parts[1] || parts[0]); + return { + type: formulaType, + ref: normalized, + r1: Math.min(start.r, end.r), + c1: Math.min(start.c, end.c), + r2: Math.max(start.r, end.r), + c2: Math.max(start.c, end.c), + }; +} + +function applyComplexFormulaEvidence(cells, ranges) { + let coveredCellCount = 0; + for (const range of ranges) { + coveredCellCount += cellCount(range.r1, range.c1, range.r2, range.c2); + if (coveredCellCount > MAX_COMPLEX_FORMULA_COVERAGE_CELLS) { + throw new Error( + `[COMPLEX_FORMULA_COVERAGE_LIMIT] Complex formula ranges cover more than ${MAX_COMPLEX_FORMULA_COVERAGE_CELLS} cells.` + ); + } + } + for (const range of ranges) { + for (let r = range.r1; r <= range.r2; r += 1) { + for (let c = range.c1; c <= range.c2; c += 1) { + const cell = cells[cellKey(r, c)]; + if (!cell) continue; + cell.formulaEvidence = true; + cell.formulaGroupType = range.type; + if (range.ref) cell.formulaGroupRef = range.ref; + } + } + } +} + +function parseWorksheet(xml, sharedStrings, budget = createCellParseBudget(), styles = []) { + const cells = {}; + const complexFormulaRanges = []; + const layout = parseWorksheetLayout(xml); + let maxR = 0; + let maxC = 0; + if (!xml) { + return { cells, rows: 50, cols: 26, complexFormulaRanges, layout }; + } + const text = String(xml); + const cellRe = /]*)>([\s\S]*?)<\/c>|]*)\/>/gi; + let match; + while ((match = cellRe.exec(text))) { + consumeCellParseBudget(budget); + const attrs = match[1] || match[3] || ""; + const body = match[2] || ""; + const refMatch = attrs.match(/\br="([^"]+)"/i); + if (!refMatch) { + throw new Error( + "[XLSX_CELL_REF_INVALID] Worksheet contains a cell record without an explicit r coordinate." + ); + } + const pos = parseCellRef(refMatch[1]); + const typeMatch = attrs.match(/\bt="([^"]+)"/i); + const cellType = typeMatch ? typeMatch[1] : null; + const styleIndex = Number(attrs.match(/\bs="([^"]+)"/i)?.[1]); + const formulaMatch = body.match(/]*?)(?:\/\s*>|>([\s\S]*?)<\/f>)/i); + const valueMatch = body.match(/]*>([\s\S]*?)<\/v>/i); + const isMatch = body.match(/]*>([\s\S]*?)<\/is>/i); + + const cell = {}; + if (formulaMatch) { + const formulaAttrs = formulaMatch[1] || ""; + const formulaText = decodeXmlEntities(formulaMatch[2] || ""); + const formulaType = String(formulaAttribute(formulaAttrs, "t") || "normal").toLowerCase(); + const formulaRef = formulaAttribute(formulaAttrs, "ref"); + cell.formulaEvidence = true; + if (formulaText) cell.f = formulaText; + if (formulaType !== "normal") cell.formulaType = formulaType; + if (formulaRef) cell.formulaRef = formulaRef; + if (["shared", "array", "datatable"].includes(formulaType)) { + const range = parseFormulaRangeRef(formulaRef, formulaType, pos); + // Shared followers normally omit ref; the shared master contributes + // the authoritative group range. Keep a single-cell fallback only so + // an isolated complex formula is still protected. + if (formulaRef || formulaType !== "shared") { + complexFormulaRanges.push(range); + } + } + } + if (isMatch) { + const parts = []; + const textRe = /]*>([\s\S]*?)<\/t>/gi; + let textMatch; + while ((textMatch = textRe.exec(isMatch[1]))) { + parts.push(decodeXmlEntities(textMatch[1])); + } + cell.v = parts.join(""); + cell.t = "s"; + } else if (valueMatch) { + const raw = decodeXmlEntities(valueMatch[1]); + if (cellType === "s") { + const idx = Number(raw); + cell.v = Number.isFinite(idx) && sharedStrings[idx] != null + ? sharedStrings[idx] + : raw; + cell.t = "s"; + } else if (cellType === "b") { + cell.v = raw === "1" || raw === "true"; + cell.t = "b"; + } else if (cellType === "str" || cellType === "inlineStr") { + cell.v = raw; + cell.t = "s"; + } else if (raw !== "" && !Number.isNaN(Number(raw)) && /^-?\d+(\.\d+)?([eE][+-]?\d+)?$/.test(raw)) { + cell.v = Number(raw); + cell.t = "n"; + } else { + cell.v = raw; + cell.t = cellType || "s"; + } + } else if (cell.formulaEvidence) { + cell.t = "f"; + } else if (!Number.isSafeInteger(styleIndex)) { + continue; + } + + if (Number.isSafeInteger(styleIndex) && styleIndex >= 0) { + cell._sourceStyleIndex = styleIndex; + if (styles[styleIndex]) cell.style = JSON.parse(JSON.stringify(styles[styleIndex])); + } + + cells[cellKey(pos.r, pos.c)] = cell; + if (pos.r > maxR) maxR = pos.r; + if (pos.c > maxC) maxC = pos.c; + } + + applyComplexFormulaEvidence(cells, complexFormulaRanges); + + return { + cells, + rows: Math.max(50, maxR + 1), + cols: Math.max(26, maxC + 1), + complexFormulaRanges, + layout, + }; +} + +function listSheetXmlPaths(files) { + const paths = []; + for (const name of files.keys()) { + const m = name.match(/^xl\/worksheets\/sheet(\d+)\.xml$/i); + if (m) { + paths.push({ name, index: Number(m[1]) }); + } + } + paths.sort((a, b) => a.index - b.index); + return paths.map((p) => p.name); +} + +function workbookSheetDescriptors(files) { + const workbookXml = (files.get("xl/workbook.xml") || Buffer.alloc(0)).toString("utf8"); + const relsXml = (files.get("xl/_rels/workbook.xml.rels") || Buffer.alloc(0)).toString("utf8"); + const refs = parseWorkbookSheetRefs(workbookXml); + const relationships = parseRelationships(relsXml); + const descriptors = refs + .map((ref) => { + const relation = relationships.get(ref.relId); + if (!relation || (relation.type && !relation.type.toLowerCase().endsWith("/worksheet"))) { + return null; + } + return { name: ref.name, path: resolveWorkbookTarget(relation.target) }; + }) + .filter(Boolean) + .filter((sheet) => files.has(sheet.path)); + if (descriptors.length > 0) return descriptors; + const names = parseSheetNames(workbookXml); + return listSheetXmlPaths(files).map((sheetPath, index) => ({ + name: names[index] || `Sheet${index + 1}`, + path: sheetPath, + })); +} + +function calculationStatusWithFormulaEvidence(sheets) { + let formulaCount = 0; + for (const sheet of sheets || []) { + for (const cell of Object.values(sheet.cells || {})) { + if (cell && (cell.formulaEvidence === true || (typeof cell.f === "string" && cell.f))) { + formulaCount += 1; + } + } + } + if (formulaCount === 0) return defaultCalculationStatus(sheets); + return { + engine: "none", + status: "cached", + formulaCount, + lastCalculatedRevision: null, + warning: "Formula results are cached values; this engine does not recalculate formulas.", + }; +} + +function assertWorkbookShapeLimits(workbook) { + let serializedCellCount = 0; + const sheetNames = new Set(); + for (const [index, sheet] of (workbook?.sheets || []).entries()) { + const sheetName = validateExcelSheetName(sheet.name || `Sheet${index + 1}`); + const sheetKey = sheetName.toLowerCase(); + if (sheetNames.has(sheetKey)) throw new Error(`[DUPLICATE_SHEET_NAME] Worksheet name already exists: ${sheetName}`); + sheetNames.add(sheetKey); + assertSheetDimensions(Number(sheet.rows), Number(sheet.cols), `Worksheet ${index + 1}`); + for (const key of Object.keys(sheet.cells || {})) { + serializedCellCount += 1; + if (serializedCellCount > MAX_XLSX_PARSED_CELLS) { + throw new Error( + `[XLSX_CELL_COUNT_LIMIT] Workbook contains more than ${MAX_XLSX_PARSED_CELLS} cell records.` + ); + } + const parts = key.split(","); + if (parts.length !== 2) { + throw new Error(`[XLSX_CELL_REF_INVALID] Invalid workbook cell key: ${key}`); + } + assertZeroBasedCellCoordinates( + Number(parts[0]), + Number(parts[1]), + `Workbook cell key ${JSON.stringify(key)}` + ); + } + } + return workbook; +} + +function workbookFromSheets(sheets, options = {}) { + const createdAt = nowIso(); + const normalized = sheets.map((sheet, index) => { + const rows = sheet.rows || 50; + const cols = sheet.cols || 26; + assertSheetDimensions(rows, cols, `Worksheet ${index + 1}`); + return { + id: sheet.id || newId("sheet"), + name: sheet.name || `Sheet${index + 1}`, + rows, + cols, + cells: sheet.cells || {}, + layout: sheet.layout || defaultSheetLayout(), + complexFormulaRanges: Array.isArray(sheet.complexFormulaRanges) + ? sheet.complexFormulaRanges + : [], + }; + }); + if (normalized.length === 0) { + normalized.push(createEmptySheet("Sheet1")); + } + const sourcePath = options.path || null; + const sourceFormat = formatFromPath(sourcePath); + return assertWorkbookShapeLimits({ + schemaVersion: WORKBOOK_SCHEMA_VERSION, + workbookId: options.workbookId || newId("wb"), + path: sourcePath, + sourcePath, + sourceFormat, + sourceFingerprint: options.sourceFingerprint || null, + lastExportPath: null, + lastExportedRevision: null, + title: options.title || path.basename(options.path || "Workbook", path.extname(options.path || "")) || "Workbook", + sheets: normalized, + activeSheetId: normalized[0].id, + dirty: false, + revision: 0, + mode: "edit", + focus: { + sheetId: normalized[0].id, + a1: "A1", + kind: "cell", + }, + proposal: null, + fidelity: defaultFidelity(sourceFormat), + calculationStatus: calculationStatusWithFormulaEvidence(normalized), + history: [], + undoStack: [], + redoStack: [], + createdAt, + updatedAt: createdAt, + }); +} + +function readCsvFile(filePath, options = {}) { + const text = readStableFile(filePath, { + maxBytes: MAX_CSV_FILE_BYTES, + sizeLimitCode: "CSV_FILE_SIZE_LIMIT", + fileKind: "CSV source file", + }).buffer.toString("utf8"); + const rows = parseCsv(text, { + maxRows: EXCEL_MAX_ROWS, + maxColumns: EXCEL_MAX_COLUMNS, + maxCells: MAX_CSV_PARSED_CELLS, + }); + const cells = {}; + let maxCols = 26; + for (let r = 0; r < rows.length; r += 1) { + const row = rows[r] || []; + if (row.length > maxCols) maxCols = row.length; + for (let c = 0; c < row.length; c += 1) { + const value = row[c]; + if (value === "" || value == null) continue; + const num = Number(value); + if (value !== "" && !Number.isNaN(num) && /^-?\d+(\.\d+)?([eE][+-]?\d+)?$/.test(String(value).trim())) { + cells[cellKey(r, c)] = { v: num, t: "n" }; + } else { + cells[cellKey(r, c)] = { v: value, t: "s" }; + } + } + } + const sheet = { + id: newId("sheet"), + name: "Sheet1", + rows: Math.max(50, rows.length), + cols: Math.max(26, maxCols), + cells, + }; + return workbookFromSheets([sheet], { + path: filePath, + title: options.title || path.basename(filePath, path.extname(filePath)), + workbookId: options.workbookId, + }); +} + +function readJsonFile(filePath, options = {}) { + const text = readStableFile(filePath, { + maxBytes: MAX_JSON_FILE_BYTES, + sizeLimitCode: "JSON_FILE_SIZE_LIMIT", + fileKind: "JSON source file", + }).buffer.toString("utf8"); + let parsed; + try { + parsed = JSON.parse(text); + } catch (error) { + throw new Error(`Failed to parse workbook JSON: ${error.message}`); + } + if (parsed && Array.isArray(parsed.sheets)) { + const wb = createEmpty({ + workbookId: options.workbookId || parsed.workbookId, + title: options.title || parsed.title, + path: filePath, + }); + const imported = normalizeWorkbook({ + ...wb, + ...parsed, + path: filePath, + sourcePath: filePath, + sourceFormat: "json", + workbookId: options.workbookId || parsed.workbookId || wb.workbookId, + dirty: false, + proposal: parsed.proposal || null, + }); + imported.fidelity = defaultFidelity("json"); + return assertWorkbookShapeLimits(imported); + } + throw new Error("JSON file is not a Sparo workbook store"); +} + +function readXlsxFile(filePath, options = {}) { + let snapshot; + try { + snapshot = readStableFile(filePath); + } catch (error) { + throw new Error(`Failed to read xlsx file: ${error.message}`); + } + const buffer = snapshot.buffer; + + let files; + try { + files = unzipBuffer(buffer); + } catch (error) { + throw new Error(`Failed to parse xlsx as ZIP: ${error.message}`); + } + + const sharedStrings = parseSharedStrings( + (files.get("xl/sharedStrings.xml") || Buffer.alloc(0)).toString("utf8") + ); + const styles = parseStyles( + (files.get("xl/styles.xml") || Buffer.alloc(0)).toString("utf8") + ); + const sheetDescriptors = workbookSheetDescriptors(files); + if (sheetDescriptors.length === 0) { + throw new Error("xlsx package has no worksheets under xl/worksheets/"); + } + + const cellBudget = createCellParseBudget(); + const sheets = sheetDescriptors.map((descriptor, index) => { + const xml = files.get(descriptor.path).toString("utf8"); + const parsed = parseWorksheet(xml, sharedStrings, cellBudget, styles); + return { + id: newId("sheet"), + name: descriptor.name || `Sheet${index + 1}`, + rows: parsed.rows, + cols: parsed.cols, + cells: parsed.cells, + complexFormulaRanges: parsed.complexFormulaRanges, + layout: parsed.layout, + }; + }); + + const workbook = workbookFromSheets(sheets, { + path: filePath, + title: options.title || path.basename(filePath, path.extname(filePath)), + workbookId: options.workbookId, + sourceFingerprint: snapshot.fingerprint, + }); + if ([...files.keys()].some((name) => name.toLowerCase().startsWith("_xmlsignatures/"))) { + workbook.fidelity.canRoundTrip = false; + workbook.fidelity.level = "limited"; + workbook.fidelity.warning = + "This workbook has an OOXML package signature that would be invalidated by editing."; + } + return workbook; +} + +function readWorkbookFile(filePath, options = {}) { + if (!filePath) { + throw new Error("File path is required"); + } + if (!fs.existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + const ext = path.extname(filePath).toLowerCase(); + if (ext === ".csv") { + return readCsvFile(filePath, options); + } + if (ext === ".json") { + return readJsonFile(filePath, options); + } + if (ext === ".xlsx" || ext === ".xlsm") { + try { + return readXlsxFile(filePath, options); + } catch (error) { + throw new Error( + `Failed to open xlsx workbook at ${filePath}: ${error.message}. ` + + "Only simple OOXML sheets (values, shared strings, basic formulas) are supported." + ); + } + } + throw new Error(`Unsupported workbook file type: ${ext || "(none)"}`); +} + +function inferCellType(cell) { + if (!cell) return null; + if (cell.f) return "f"; + if (cell.t) return cell.t; + if (typeof cell.v === "number") return "n"; + if (typeof cell.v === "boolean") return "b"; + return "s"; +} + +function buildSharedStrings(workbook) { + const list = []; + const index = new Map(); + function add(str) { + const key = String(str); + if (index.has(key)) return index.get(key); + const i = list.length; + list.push(key); + index.set(key, i); + return i; + } + for (const sheet of workbook.sheets) { + for (const cell of Object.values(sheet.cells || {})) { + if (!cell) continue; + if (cell.f) continue; + const t = inferCellType(cell); + if (t === "s" || t === "str") { + add(cell.v == null ? "" : String(cell.v)); + } + } + } + return { list, index }; +} + +function visualStyle(style) { + if (!style || typeof style !== "object") return null; + const { role: _role, ...visual } = style; + return Object.keys(visual).length ? visual : null; +} + +function colorToArgb(color) { + const value = String(color || "").replace(/^#/, "").toUpperCase(); + if (!/^[0-9A-F]{6}$/.test(value)) throw new Error(`[INVALID_STYLE_COLOR] Expected #RRGGBB, received ${JSON.stringify(color)}.`); + return `FF${value}`; +} + +function createStyleTable(workbook) { + const fonts = [null]; + const fills = [null, { gray125: true }]; + const borders = [null]; + const numberFormats = []; + const fontIds = new Map([["null", 0]]); + const fillIds = new Map([["null", 0]]); + const borderIds = new Map([["null", 0]]); + const numberFormatIds = new Map(); + const xfs = [{ fontId: 0, fillId: 0, borderId: 0, numFmtId: 0, alignment: null }]; + const xfIds = new Map([["null", 0]]); + + const componentId = (value, values, ids) => { + const key = JSON.stringify(value || null); + if (ids.has(key)) return ids.get(key); + const id = values.length; + values.push(value); + ids.set(key, id); + return id; + }; + const numberFormatId = (code) => { + if (!code) return 0; + const key = String(code); + if (numberFormatIds.has(key)) return numberFormatIds.get(key); + const id = 164 + numberFormats.length; + numberFormats.push({ id, code: key }); + numberFormatIds.set(key, id); + return id; + }; + const register = (style) => { + const visual = visualStyle(style); + const key = JSON.stringify(visual || null); + if (xfIds.has(key)) return xfIds.get(key); + if (xfs.length >= MAX_AUTHORED_CELL_STYLES) { + throw new Error(`[XLSX_STYLE_LIMIT] Workbook exceeds ${MAX_AUTHORED_CELL_STYLES} distinct authored cell styles.`); + } + const xf = { + fontId: componentId(visual?.font, fonts, fontIds), + fillId: componentId(visual?.fill, fills, fillIds), + borderId: componentId(visual?.border, borders, borderIds), + numFmtId: numberFormatId(visual?.numberFormat), + alignment: visual?.alignment || null, + }; + const id = xfs.length; + xfs.push(xf); + xfIds.set(key, id); + return id; + }; + for (const sheet of workbook.sheets || []) { + for (const cell of Object.values(sheet.cells || {})) if (cell?.style) register(cell.style); + } + + const fontXml = fonts.map((font) => { + if (!font) return ''; + return `${font.bold ? "" : ""}${font.italic ? "" : ""}` + + `` + + `${font.color ? `` : ""}`; + }).join(""); + const fillXml = fills.map((fill) => { + if (!fill) return ''; + if (fill.gray125) return ''; + return ``; + }).join(""); + const borderXml = borders.map((border) => { + const sideXml = (side) => { + const value = border?.[side]; + if (!value) return `<${side}/>`; + return `<${side} style="${escapeXml(value.style)}">${value.color ? `` : ""}`; + }; + return `${sideXml("left")}${sideXml("right")}${sideXml("top")}${sideXml("bottom")}`; + }).join(""); + const xfXml = xfs.map((xf) => { + const apply = `${xf.numFmtId ? ' applyNumberFormat="1"' : ""}${xf.fontId ? ' applyFont="1"' : ""}${xf.fillId ? ' applyFill="1"' : ""}${xf.borderId ? ' applyBorder="1"' : ""}${xf.alignment ? ' applyAlignment="1"' : ""}`; + const alignment = xf.alignment + ? `` + : ""; + return `${alignment}`; + }).join(""); + const numFmtXml = numberFormats.length + ? `${numberFormats.map((item) => ``).join("")}` + : ""; + const xml = `` + + `${numFmtXml}` + + `${fontXml}${fillXml}` + + `${borderXml}` + + `` + + `${xfXml}` + + ``; + return { xml, indexFor: register, count: xfs.length }; +} + +function layoutXml(sheet) { + const layout = sheet.layout || {}; + const freezeRows = Number(layout.freezePanes?.rows || 0); + const freezeColumns = Number(layout.freezePanes?.columns || 0); + const activePane = freezeRows && freezeColumns + ? "bottomRight" + : freezeRows + ? "bottomLeft" + : "topRight"; + const sheetViews = freezeRows || freezeColumns + ? `` + : ''; + const columns = (layout.columns || []).map((band) => { + const width = band.width == null ? 18 : Number(band.width); + return ``; + }).join(""); + const cols = columns ? `${columns}` : ""; + const autoFilter = layout.autoFilter?.a1 ? `` : ""; + return { sheetViews, cols, autoFilter }; +} + +function sheetToXml(sheet, shared, styleTable) { + const rowsMap = new Map(); + for (const [key, cell] of Object.entries(sheet.cells || {})) { + const [rs, cs] = key.split(","); + const r = Number(rs); + const c = Number(cs); + assertZeroBasedCellCoordinates(r, c, `Workbook cell key ${JSON.stringify(key)}`); + if (!rowsMap.has(r)) rowsMap.set(r, []); + rowsMap.get(r).push({ c, cell }); + } + + let materializedLayoutRows = 0; + for (const band of sheet.layout?.rows || []) { + materializedLayoutRows += band.end - band.start + 1; + if (materializedLayoutRows > 20_000) { + throw new Error("[LAYOUT_ROW_LIMIT] XLSX export cannot materialize more than 20000 custom-height rows."); + } + for (let row = band.start; row <= band.end; row += 1) if (!rowsMap.has(row)) rowsMap.set(row, []); + } + + const rowNums = [...rowsMap.keys()].sort((a, b) => a - b); + const rowXml = []; + for (const r of rowNums) { + const cells = rowsMap.get(r).sort((a, b) => a.c - b.c); + const cellXml = cells.map(({ c, cell }) => { + const ref = `${indexToCol(c)}${r + 1}`; + const styleId = cell.style ? styleTable.indexFor(cell.style) : 0; + const styleAttr = styleId ? ` s="${styleId}"` : ""; + if (cell.f) { + const f = escapeXml(cell.f); + const v = + cell.v != null && cell.v !== "" + ? `${escapeXml(String(cell.v))}` + : ""; + return `${f}${v}`; + } + const t = inferCellType(cell); + if (t === "n") { + return `${escapeXml(String(cell.v))}`; + } + if (t === "b") { + return `${cell.v ? 1 : 0}`; + } + if (cell.v == null && styleId) return ``; + const text = cell.v == null ? "" : String(cell.v); + const idx = shared.index.has(text) + ? shared.index.get(text) + : (() => { + const i = shared.list.length; + shared.list.push(text); + shared.index.set(text, i); + return i; + })(); + return `${idx}`; + }); + const rowBand = (sheet.layout?.rows || []).find((band) => r >= band.start && r <= band.end); + const rowAttrs = rowBand + ? `${rowBand.height != null || rowBand.autoFit ? ` ht="${Number(rowBand.height || 24)}" customHeight="1"` : ""}${rowBand.autoFit ? ' bestFit="1"' : ""}` + : ""; + rowXml.push(`${cellXml.join("")}`); + } + + const declaredRows = Number(sheet.rows || 1); + const declaredColumns = Number(sheet.cols || 1); + assertZeroBasedCellCoordinates( + declaredRows - 1, + declaredColumns - 1, + `Worksheet dimensions ${JSON.stringify({ rows: sheet.rows, cols: sheet.cols })}` + ); + const dim = `A1:${indexToCol(declaredColumns - 1)}${declaredRows}`; + const layout = layoutXml(sheet); + return ( + `` + + `` + + `` + + layout.sheetViews + + layout.cols + + `${rowXml.join("")}` + + layout.autoFilter + + `` + ); +} + +function sourceCellsEqual(left, right) { + const a = left || null; + const b = right || null; + if (a === b) return true; + if (!a || !b) return false; + return ( + a.f === b.f && + a.v === b.v && + Boolean(a.formulaEvidence) === Boolean(b.formulaEvidence) && + (a.formulaType || null) === (b.formulaType || null) && + (a.formulaRef || null) === (b.formulaRef || null) && + (a.formulaGroupType || null) === (b.formulaGroupType || null) && + (a.formulaGroupRef || null) === (b.formulaGroupRef || null) && + JSON.stringify(a.style || null) === JSON.stringify(b.style || null) + ); +} + +function withoutXmlAttribute(attrs, name) { + return String(attrs || "").replace( + new RegExp(`\\s\\b${name}="[^"]*"`, "gi"), + "" + ); +} + +function cellAttributes(existingAttrs, ref, type) { + let rest = withoutXmlAttribute(withoutXmlAttribute(existingAttrs, "r"), "t").trim(); + const parts = [`r="${ref}"`]; + if (rest) parts.push(rest); + if (type) parts.push(`t="${type}"`); + return ` ${parts.join(" ")}`; +} + +function patchedCellXml(cell, ref, existingAttrs = "") { + if (!cell) { + const rest = withoutXmlAttribute(withoutXmlAttribute(existingAttrs, "r"), "t").trim(); + return rest ? `` : null; + } + if (cell.f) { + let resultType = null; + if (typeof cell.v === "string") resultType = "str"; + if (typeof cell.v === "boolean") resultType = "b"; + const attrs = cellAttributes(existingAttrs, ref, resultType); + const value = cell.v == null || cell.v === "" + ? "" + : `${escapeXml(typeof cell.v === "boolean" ? (cell.v ? "1" : "0") : String(cell.v))}`; + return `${escapeXml(cell.f)}${value}`; + } + const type = inferCellType(cell); + if (type === "n") { + return `${escapeXml(String(cell.v))}`; + } + if (type === "b") { + return `${cell.v ? 1 : 0}`; + } + const text = cell.v == null ? "" : String(cell.v); + const preserve = /^\s|\s$/.test(text) ? ' xml:space="preserve"' : ""; + return `${escapeXml(text)}`; +} + +function parseRowCellTokens(body) { + const tokens = []; + const re = /]*)>([\s\S]*?)<\/c>|]*)\/>/gi; + let match; + while ((match = re.exec(String(body || "")))) { + const attrs = match[1] || match[3] || ""; + const ref = attrs.match(/\br="([^"]+)"/i)?.[1]; + let col = null; + if (ref) col = parseCellRef(ref).c; + tokens.push({ + xml: match[0], + attrs, + ref: ref || null, + col, + start: match.index, + end: re.lastIndex, + }); + } + return tokens; +} + +function patchRowBody(body, changes, row) { + const source = String(body || ""); + const tokens = parseRowCellTokens(source); + const existingColumns = new Set( + tokens.filter((token) => token.col != null).map((token) => token.col) + ); + const pending = [...changes.entries()] + .filter(([col]) => !existingColumns.has(col)) + .sort((a, b) => a[0] - b[0]); + const handled = new Set(); + let pendingIndex = 0; + let cursor = 0; + let output = ""; + + const appendPendingBefore = (columnLimit = Infinity) => { + while (pendingIndex < pending.length && pending[pendingIndex][0] < columnLimit) { + const [col, cell] = pending[pendingIndex]; + const ref = `${indexToCol(col)}${row + 1}`; + const nextXml = patchedCellXml(cell, ref, ""); + if (nextXml) output += nextXml; + handled.add(col); + pendingIndex += 1; + } + }; + + for (const token of tokens) { + output += source.slice(cursor, token.start); + if (token.col != null) appendPendingBefore(token.col); + if (token.col != null && changes.has(token.col)) { + const ref = `${indexToCol(token.col)}${row + 1}`; + const nextXml = patchedCellXml(changes.get(token.col), ref, token.attrs); + if (nextXml) output += nextXml; + handled.add(token.col); + } else { + output += token.xml; + } + cursor = token.end; + } + appendPendingBefore(); + output += source.slice(cursor); + + for (const col of changes.keys()) { + if (!handled.has(col)) { + throw new Error(`Failed to patch ${indexToCol(col)}${row + 1} in worksheet row XML.`); + } + } + return output; +} + +function rowAttributeText(attrs, rowNumber) { + const rest = withoutXmlAttribute(attrs, "r").trim(); + return rest ? ` r="${rowNumber}" ${rest}` : ` r="${rowNumber}"`; +} + +function expandWorksheetDimension(xml, sheet) { + let usedR = 0; + let usedC = 0; + for (const key of Object.keys(sheet.cells || {})) { + const [r, c] = key.split(",").map(Number); + assertZeroBasedCellCoordinates(r, c, `Workbook cell key ${JSON.stringify(key)}`); + usedR = Math.max(usedR, r); + usedC = Math.max(usedC, c); + } + const dimensionMatch = String(xml).match(/]*)\bref="([^"]+)"([^>]*)\/>/i); + if (!dimensionMatch) return xml; + const endRef = dimensionMatch[2].split(":").pop(); + const end = parseCellRef(endRef); + if (end) { + usedR = Math.max(usedR, end.r); + usedC = Math.max(usedC, end.c); + } + const ref = `A1:${indexToCol(usedC)}${usedR + 1}`; + return String(xml).replace(dimensionMatch[0], ``); +} + +function patchWorksheetXml(xml, sourceSheet, currentSheet) { + const sourceCells = sourceSheet.cells || {}; + const currentCells = currentSheet.cells || {}; + const changedByRow = new Map(); + const keys = new Set([...Object.keys(sourceCells), ...Object.keys(currentCells)]); + let patchedCellCount = 0; + for (const key of keys) { + if (JSON.stringify(sourceCells[key]?.style || null) !== JSON.stringify(currentCells[key]?.style || null)) { + const [r, c] = key.split(",").map(Number); + throw new Error( + `[SOURCE_STYLE_PATCH_UNSAFE] ${indexToCol(c)}${r + 1} has a new or changed style. The source-preserving patcher will not silently discard it; use an acknowledged Save As rebuild.` + ); + } + if (sourceCellsEqual(sourceCells[key], currentCells[key])) continue; + const [r, c] = key.split(",").map(Number); + assertZeroBasedCellCoordinates(r, c, `Workbook cell key ${JSON.stringify(key)}`); + const complexRange = (sourceSheet.complexFormulaRanges || []).find( + (range) => r >= range.r1 && r <= range.r2 && c >= range.c1 && c <= range.c2 + ); + if (complexRange) { + const ref = `${indexToCol(c)}${r + 1}`; + throw new Error( + `[COMPLEX_FORMULA_PATCH_UNSAFE] ${ref} intersects ${complexRange.type} formula range ${complexRange.ref || ref} and cannot be patched independently.` + ); + } + if (!changedByRow.has(r)) changedByRow.set(r, new Map()); + changedByRow.get(r).set(c, currentCells[key] || null); + patchedCellCount += 1; + } + if (patchedCellCount === 0) return { xml, patchedCellCount: 0 }; + + const sheetDataMatch = String(xml).match(/]*)>([\s\S]*?)<\/sheetData>|]*)\/>/i); + if (!sheetDataMatch) throw new Error("Worksheet is missing sheetData"); + const sheetDataAttrs = sheetDataMatch[1] || sheetDataMatch[3] || ""; + const body = sheetDataMatch[2] || ""; + const rows = new Map(); + const rowRe = /]*?)(?:>([\s\S]*?)<\/row>|\/\s*>)/gi; + let rowMatch; + while ((rowMatch = rowRe.exec(body))) { + const attrs = rowMatch[1] || ""; + const rowNumber = Number(attrs.match(/\br="([^"]+)"/i)?.[1]); + if (!Number.isInteger(rowNumber) || rowNumber < 1) continue; + rows.set(rowNumber - 1, { + attrs, + body: rowMatch[2] || "", + original: rowMatch[0], + }); + } + + for (const [r, changes] of changedByRow) { + const record = rows.get(r) || { attrs: ` r="${r + 1}"`, body: "", original: null }; + for (const token of parseRowCellTokens(record.body)) { + if ( + token.col != null && + changes.has(token.col) && + /]*\bt="(?:shared|array|dataTable)"/i.test(token.xml) + ) { + const ref = `${indexToCol(token.col)}${r + 1}`; + throw new Error( + `[COMPLEX_FORMULA_PATCH_UNSAFE] ${ref} belongs to a shared, array, or data-table formula and cannot be patched safely.` + ); + } + } + const patchedBody = patchRowBody(record.body, changes, r); + rows.set(r, { + ...record, + original: `${patchedBody}`, + }); + } + + const rowsXml = [...rows.entries()] + .sort((a, b) => a[0] - b[0]) + .map(([, row]) => row.original) + .join(""); + const replacement = `${rowsXml}`; + const patched = String(xml).replace(sheetDataMatch[0], replacement); + return { xml: expandWorksheetDimension(patched, currentSheet), patchedCellCount }; +} + +function setFullCalculationOnLoad(workbookXml) { + const calcMatch = String(workbookXml).match(/]*?)(?:\/\s*>|>[\s\S]*?<\/calcPr>)/i); + if (calcMatch) { + let attrs = calcMatch[1] || ""; + for (const name of ["fullCalcOnLoad", "forceFullCalc", "calcMode"]) { + attrs = withoutXmlAttribute(attrs, name); + } + return String(workbookXml).replace( + calcMatch[0], + `` + ); + } + return String(workbookXml).replace( + /<\/workbook>\s*$/i, + '' + ); +} + +function removeCalcChain(files) { + for (const name of [...files.keys()]) { + if (name.toLowerCase() === "xl/calcchain.xml") files.delete(name); + } + const relsPath = "xl/_rels/workbook.xml.rels"; + if (files.has(relsPath)) { + const rels = files.get(relsPath).toString("utf8").replace( + /]*(?:calcChain|calcchain))[^>]*\/>/gi, + "" + ); + files.set(relsPath, Buffer.from(rels, "utf8")); + } + const contentTypesPath = "[Content_Types].xml"; + if (files.has(contentTypesPath)) { + const types = files.get(contentTypesPath).toString("utf8").replace( + /]*(?:calcChain|calcchain))[^>]*\/>/gi, + "" + ); + files.set(contentTypesPath, Buffer.from(types, "utf8")); + } +} + +function writeSourcePreservingWorkbook(workbook, filePath, options = {}) { + assertWorkbookShapeLimits(workbook); + const sourcePath = workbook.sourcePath; + if (!sourcePath || !fs.existsSync(sourcePath)) { + throw new Error("[SOURCE_PACKAGE_MISSING] The imported Excel source package is unavailable."); + } + if (!workbook.sourceFingerprint) { + throw new Error( + "[SOURCE_FINGERPRINT_MISSING] This live workbook predates source fingerprinting. Reopen it explicitly before source-preserving export." + ); + } + if (!workbook.fidelity?.canRoundTrip || workbook.fidelity?.structureChanged) { + throw new Error( + "[SOURCE_PATCH_UNSAFE] Workbook structure changed; a source-preserving cell patch is no longer safe." + ); + } + const sourceExt = path.extname(sourcePath).toLowerCase(); + const targetExt = path.extname(filePath).toLowerCase(); + if (sourceExt !== targetExt) { + throw new Error( + `[SOURCE_FORMAT_MISMATCH] Source-preserving export requires ${sourceExt}; requested ${targetExt}.` + ); + } + assertDistinctSourceTarget(sourcePath, filePath); + const sourceSnapshot = readStableFile(sourcePath); + if (!fingerprintsEqual(workbook.sourceFingerprint, sourceSnapshot.fingerprint)) { + throw new Error( + `[SOURCE_CHANGED_EXTERNALLY] ${sourcePath} changed after it was opened (size, mtime, or SHA-256 differs). Reopen/reload the workbook at the current revision before exporting; the stale live model will not be applied.` + ); + } + const files = unzipBuffer(sourceSnapshot.buffer); + if ([...files.keys()].some((name) => name.toLowerCase().startsWith("_xmlsignatures/"))) { + throw new Error( + "[SIGNED_PACKAGE_PATCH_UNSAFE] The workbook has an OOXML package signature that would be invalidated by editing." + ); + } + const descriptors = workbookSheetDescriptors(files); + if (descriptors.length !== workbook.sheets.length) { + throw new Error("[SOURCE_PATCH_UNSAFE] Sheet count differs from the imported source."); + } + for (let index = 0; index < descriptors.length; index += 1) { + if (descriptors[index].name !== workbook.sheets[index].name) { + throw new Error( + `[SOURCE_PATCH_UNSAFE] Sheet ${index + 1} changed from ${descriptors[index].name} to ${workbook.sheets[index].name}.` + ); + } + } + const sharedStrings = parseSharedStrings( + (files.get("xl/sharedStrings.xml") || Buffer.alloc(0)).toString("utf8") + ); + const styles = parseStyles( + (files.get("xl/styles.xml") || Buffer.alloc(0)).toString("utf8") + ); + const cellBudget = createCellParseBudget(); + let patchedCellCount = 0; + for (let index = 0; index < descriptors.length; index += 1) { + const descriptor = descriptors[index]; + const xml = files.get(descriptor.path).toString("utf8"); + const sourceSheet = parseWorksheet(xml, sharedStrings, cellBudget, styles); + if (JSON.stringify(sourceSheet.layout || null) !== JSON.stringify(workbook.sheets[index].layout || null)) { + throw new Error( + `[SOURCE_LAYOUT_PATCH_UNSAFE] Layout changed on ${descriptors[index].name}. The source-preserving patcher will not silently discard it; use an acknowledged Save As rebuild.` + ); + } + const patched = patchWorksheetXml(xml, sourceSheet, workbook.sheets[index]); + patchedCellCount += patched.patchedCellCount; + files.set(descriptor.path, Buffer.from(patched.xml, "utf8")); + } + const workbookPath = "xl/workbook.xml"; + files.set( + workbookPath, + Buffer.from(setFullCalculationOnLoad(files.get(workbookPath).toString("utf8")), "utf8") + ); + removeCalcChain(files); + const buffer = zipStore([...files.entries()].map(([name, data]) => ({ name, data }))); + const finalSourceFingerprint = readStableFile(sourcePath).fingerprint; + if (!fingerprintsEqual(sourceSnapshot.fingerprint, finalSourceFingerprint)) { + throw new Error( + `[SOURCE_CHANGED_EXTERNALLY] ${sourcePath} changed during export preparation. Reopen/reload and retry.` + ); + } + const resolvedTargetPath = assertDistinctSourceTarget(sourcePath, filePath); + writeFileAtomic(resolvedTargetPath, buffer, undefined, options.atomicWriteOptions || {}); + const outputFingerprint = readStableFile(resolvedTargetPath).fingerprint; + return { + path: filePath, + format: targetExt.slice(1), + mode: "source-preserving-cell-patch", + sourcePath, + patchedCellCount, + preservedPackagePartCount: files.size, + fullCalcOnLoad: true, + sourceFingerprintVerified: true, + outputFingerprint, + }; +} + +function writeXlsxBuffer(workbook) { + assertWorkbookShapeLimits(workbook); + const shared = buildSharedStrings(workbook); + const styleTable = createStyleTable(workbook); + const sheets = workbook.sheets || []; + const sheetEntries = sheets.map((sheet, i) => ({ + name: `xl/worksheets/sheet${i + 1}.xml`, + data: sheetToXml(sheet, shared, styleTable), + })); + + const sharedXml = + `` + + `` + + shared.list.map((s) => `${escapeXml(s)}`).join("") + + ``; + + const workbookXml = + `` + + `` + + `` + + sheets + .map( + (sheet, i) => + `` + ) + .join("") + + `` + + `` + + ``; + + const workbookRels = + `` + + `` + + sheets + .map( + (_, i) => + `` + ) + .join("") + + `` + + `` + + ``; + + const rootRels = + `` + + `` + + `` + + ``; + + const contentTypes = + `` + + `` + + `` + + `` + + `` + + sheets + .map( + (_, i) => + `` + ) + .join("") + + `` + + `` + + ``; + + const entries = [ + { name: "[Content_Types].xml", data: contentTypes }, + { name: "_rels/.rels", data: rootRels }, + { name: "xl/workbook.xml", data: workbookXml }, + { name: "xl/_rels/workbook.xml.rels", data: workbookRels }, + { name: "xl/sharedStrings.xml", data: sharedXml }, + { name: "xl/styles.xml", data: styleTable.xml }, + ...sheetEntries, + ]; + + return zipStore(entries); +} + +function sheetToMatrix(sheet) { + assertSheetDimensions(Number(sheet?.rows), Number(sheet?.cols), "CSV worksheet"); + const rows = []; + const maxR = Math.max(0, (sheet.rows || 1) - 1); + const maxC = Math.max(0, (sheet.cols || 1) - 1); + // Prefer used region + let usedR = 0; + let usedC = 0; + for (const key of Object.keys(sheet.cells || {})) { + const [r, c] = key.split(",").map(Number); + assertZeroBasedCellCoordinates(r, c, `Workbook cell key ${JSON.stringify(key)}`); + if (r > usedR) usedR = r; + if (c > usedC) usedC = c; + } + const rowCount = Math.min(maxR, usedR) + 1; + const colCount = Math.min(maxC, usedC) + 1; + const denseCellCount = rowCount * colCount; + if (!Number.isSafeInteger(denseCellCount) || denseCellCount > MAX_DENSE_EXPORT_CELLS) { + throw new Error( + `[DENSE_EXPORT_CELL_LIMIT] CSV export would materialize ${denseCellCount} cells; maximum is ${MAX_DENSE_EXPORT_CELLS}. Narrow the used range before exporting.` + ); + } + for (let r = 0; r < rowCount; r += 1) { + const row = []; + for (let c = 0; c < colCount; c += 1) { + const cell = sheet.cells[cellKey(r, c)]; + if (!cell) { + row.push(""); + } else if (cell.f) { + row.push(cell.v != null ? cell.v : `=${cell.f}`); + } else { + row.push(cell.v == null ? "" : cell.v); + } + } + rows.push(row); + } + return rows; +} + +function writeWorkbookFile(workbook, filePath, options = {}) { + if (!filePath) { + throw new Error("Output path is required"); + } + const ext = path.extname(filePath).toLowerCase(); + const dir = path.dirname(filePath); + if (dir) { + fs.mkdirSync(dir, { recursive: true }); + } + if (ext === ".csv") { + const sheet = workbook.sheets.find((s) => s.id === workbook.activeSheetId) || workbook.sheets[0]; + const csv = serializeCsv(sheetToMatrix(sheet)); + writeFileAtomic(filePath, csv, "utf8", options.atomicWriteOptions || {}); + return { path: filePath, format: "csv" }; + } + if (ext === ".json") { + writeFileAtomic( + filePath, + `${JSON.stringify(workbook, null, 2)}\n`, + "utf8", + options.atomicWriteOptions || {} + ); + return { path: filePath, format: "json" }; + } + if (ext === ".xlsx" || ext === ".xlsm") { + const sourceExt = path.extname(workbook.sourcePath || "").toLowerCase(); + const hasExcelSource = sourceExt === ".xlsx" || sourceExt === ".xlsm"; + if (hasExcelSource) { + try { + return writeSourcePreservingWorkbook(workbook, filePath, options); + } catch (error) { + if ( + /^\[(?:SOURCE_CHANGED_EXTERNALLY|SOURCE_CHANGED_DURING_READ|SOURCE_FINGERPRINT_MISSING|SOURCE_PACKAGE_MISSING|SOURCE_TARGET_ALIAS_BLOCKED|SOURCE_TARGET_IDENTITY_CHECK_FAILED|EXPORT_TARGET_CHANGED|EXPORT_TARGET_APPEARED)\]/.test( + String(error.message || "") + ) + ) { + throw error; + } + if (!options.allowLossyRebuild) throw error; + if (ext === ".xlsm") { + throw new Error( + `[LOSSY_XLSM_BLOCKED] Cannot rebuild ${filePath} without losing or invalidating VBA content. Save As .xlsx instead.` + ); + } + const buffer = writeXlsxBuffer(workbook); + writeFileAtomic(filePath, buffer, undefined, options.atomicWriteOptions || {}); + return { + path: filePath, + format: "xlsx", + mode: "lossy-rebuild", + warning: error.message, + fullCalcOnLoad: true, + }; + } + } + if (ext === ".xlsm") { + throw new Error("Creating a new macro-enabled .xlsm package is not supported."); + } + const buffer = writeXlsxBuffer(workbook); + writeFileAtomic(filePath, buffer, undefined, options.atomicWriteOptions || {}); + return { path: filePath, format: "xlsx", mode: "new-minimal-package" }; + } + throw new Error(`Unsupported export type: ${ext || "(none)"}`); +} + +function writeFileAtomic(filePath, data, encoding, options = {}) { + const dir = path.dirname(filePath); + const base = path.basename(filePath); + const tempPath = path.join( + dir, + `.${base}.${process.pid}.${crypto.randomBytes(6).toString("hex")}.tmp` + ); + let handle = null; + try { + handle = fs.openSync(tempPath, "wx", 0o600); + if (encoding) { + fs.writeFileSync(handle, data, encoding); + } else { + fs.writeFileSync(handle, data); + } + fs.fsyncSync(handle); + fs.closeSync(handle); + handle = null; + if (options.expectedTargetFingerprint) { + if (!fs.existsSync(filePath)) { + throw new Error(`[EXPORT_TARGET_CHANGED] ${filePath} disappeared before replacement.`); + } + const currentFingerprint = readStableFile(filePath).fingerprint; + if (!fingerprintsEqual(options.expectedTargetFingerprint, currentFingerprint)) { + throw new Error(`[EXPORT_TARGET_CHANGED] ${filePath} changed before replacement.`); + } + } else if (options.expectTargetMissing === true && fs.existsSync(filePath)) { + throw new Error(`[EXPORT_TARGET_APPEARED] ${filePath} was created before export completed.`); + } + fs.renameSync(tempPath, filePath); + } catch (error) { + if (handle != null) { + try { + fs.closeSync(handle); + } catch (_closeError) { + // Preserve the original write error. + } + } + try { + if (fs.existsSync(tempPath)) fs.unlinkSync(tempPath); + } catch (_cleanupError) { + // Best-effort cleanup; never mask the original write error. + } + throw new Error(`Failed to atomically write ${filePath}: ${error.message}`); + } +} + +module.exports = { + limits: Object.freeze({ + maxZipFileBytes: MAX_ZIP_FILE_BYTES, + maxCsvFileBytes: MAX_CSV_FILE_BYTES, + maxJsonFileBytes: MAX_JSON_FILE_BYTES, + maxParsedCells: MAX_XLSX_PARSED_CELLS, + maxCsvParsedCells: MAX_CSV_PARSED_CELLS, + maxDenseExportCells: MAX_DENSE_EXPORT_CELLS, + maxComplexFormulaCoverageCells: MAX_COMPLEX_FORMULA_COVERAGE_CELLS, + excelMaxRows: EXCEL_MAX_ROWS, + excelMaxColumns: EXCEL_MAX_COLUMNS, + }), + unzipBuffer, + zipStore, + readStableFile, + fingerprintsEqual, + readWorkbookFile, + writeWorkbookFile, + writeFileAtomic, + writeXlsxBuffer, + writeSourcePreservingWorkbook, + sheetToMatrix, + crc32, +}; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/test/advanced-creation.test.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/test/advanced-creation.test.js new file mode 100644 index 00000000..91d3a94b --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/test/advanced-creation.test.js @@ -0,0 +1,376 @@ +const test = require("node:test"); +const assert = require("node:assert/strict"); +const crypto = require("node:crypto"); +const fs = require("node:fs"); +const os = require("node:os"); +const path = require("node:path"); + +const engine = require("../src/engine"); +const io = require("../src/xlsx-io"); +const store = require("../src/workbook-store"); + +function workspace(t) { + const root = fs.mkdtempSync(path.join(os.tmpdir(), "excel-advanced-")); + t.after(() => fs.rmSync(root, { recursive: true, force: true })); + return root; +} + +function hash(filePath) { + return crypto.createHash("sha256").update(fs.readFileSync(filePath)).digest("hex"); +} + +test("advanced Excel creation contract", async (t) => { + await t.test("reviews, applies, reads, undoes, and redoes style and layout proposals", (t) => { + const root = workspace(t); + const created = engine.dispatch("createWorkbook", { workspacePath: root, title: "Styled" }); + const workbookId = created.meta.workbookId; + const sheetId = created.meta.activeSheetId; + + const proposal = engine.dispatch("proposePatch", { + workspacePath: root, + workbookId, + expectedRevision: 0, + sheetId, + intent: "Create a readable financial table", + cells: [ + { row: 0, col: 0, value: "Revenue", styleRole: "header" }, + { row: 1, col: 0, value: 1200, style: { numberFormat: "#,##0.00" } }, + { row: 1, col: 1, value: 300 }, + { row: 1, col: 2, formula: "SUM(A2:B2)", styleRole: "output" }, + ], + layout: { + columns: [{ start: 0, end: 2, width: 14 }], + rows: [{ start: 0, height: 24 }], + freezePanes: { rows: 1, columns: 0 }, + autoFilter: { a1: "A1:C2" }, + }, + resultCellLimit: 2, + }); + + assert.equal(proposal.proposal.layout.after.units.columnWidth, "excelCharacters"); + assert.equal(proposal.proposal.validation.formulaLint.recalculated, false); + assert.match(proposal.proposal.validation.formulaLint.note, /not calculated/i); + assert.equal(proposal.cells[0].after.style.role, "header"); + assert.equal(proposal.cells.length, 2); + assert.equal(proposal.totalCellCount, 4); + assert.equal(proposal.cellDetailsTruncated, true); + const fullProposal = engine.dispatch("getProposal", { workspacePath: root, workbookId }); + assert.equal(fullProposal.proposal.cells.length, 4, "direct callers receive full proposal details by default"); + assert.equal(fullProposal.cellDetailsTruncated, false); + assert.equal(created.meta.revision, 0, "a proposal must not mutate committed workbook content"); + + const accepted = engine.dispatch("acceptProposal", { + workspacePath: root, + workbookId, + expectedRevision: 0, + proposalId: proposal.proposal.id, + }); + assert.equal(accepted.meta.revision, 1); + assert.equal(accepted.applied.layoutApplied, true); + + let read = engine.dispatch("readRange", { + workspacePath: root, + workbookId, + a1: "A1:C2", + }); + assert.equal(read.cells.find((cell) => cell.a1 === "A1").style.fill.color, "#1F4E78"); + assert.equal(read.cells.find((cell) => cell.a1 === "A2").style.numberFormat, "#,##0.00"); + assert.equal(read.cells.find((cell) => cell.a1 === "C2").formula, "SUM(A2:B2)"); + assert.deepEqual(read.layout.freezePanes, { rows: 1, columns: 0 }); + + engine.dispatch("undo", { workspacePath: root, workbookId, expectedRevision: 1 }); + read = engine.dispatch("readRange", { workspacePath: root, workbookId, a1: "A1:C2" }); + assert.equal(read.cells.length, 0); + assert.deepEqual(read.layout.freezePanes, { rows: 0, columns: 0 }); + + engine.dispatch("redo", { workspacePath: root, workbookId, expectedRevision: 2 }); + read = engine.dispatch("readRange", { workspacePath: root, workbookId, a1: "A1:C2" }); + assert.equal(read.cells.find((cell) => cell.a1 === "A1").style.role, "header"); + assert.deepEqual(read.layout.autoFilter, { a1: "A1:C2" }); + }); + + await t.test("merges partial styles and splits overlapping layout bands without data loss", (t) => { + const root = workspace(t); + const created = engine.dispatch("createWorkbook", { workspacePath: root }); + const workbookId = created.meta.workbookId; + const sheetId = created.meta.activeSheetId; + + engine.dispatch("applyLocalEdit", { + workspacePath: root, + workbookId, + expectedRevision: 0, + sheetId, + row: 0, + col: 0, + value: "Header", + styleRole: "header", + }); + engine.dispatch("applyLocalEdit", { + workspacePath: root, + workbookId, + expectedRevision: 1, + sheetId, + row: 0, + col: 0, + style: { font: { italic: true }, numberFormat: "@" }, + }); + let read = engine.dispatch("readRange", { workspacePath: root, workbookId, a1: "A1" }); + assert.equal(read.cells[0].style.font.bold, true); + assert.equal(read.cells[0].style.font.italic, true); + assert.equal(read.cells[0].style.fill.color, "#1F4E78"); + engine.dispatch("applyLocalEdit", { + workspacePath: root, + workbookId, + expectedRevision: 2, + sheetId, + row: 0, + col: 0, + styleRole: "input", + }); + read = engine.dispatch("readRange", { workspacePath: root, workbookId, a1: "A1" }); + assert.equal(read.cells[0].style.role, "input"); + assert.equal(read.cells[0].style.fill.color, "#FFF2CC"); + assert.equal(read.cells[0].style.font, undefined, "switching roles must not retain header font styling"); + assert.equal(read.cells[0].style.numberFormat, "@", "role changes preserve independent number formats"); + + engine.dispatch("applyLayout", { + workspacePath: root, + workbookId, + expectedRevision: 3, + sheetId, + layout: { columns: [{ start: 0, end: 5, width: 10 }] }, + }); + const changed = engine.dispatch("applyLayout", { + workspacePath: root, + workbookId, + expectedRevision: 4, + sheetId, + layout: { columns: [{ start: 2, end: 3, width: 20 }] }, + }); + assert.deepEqual(changed.layout.columns, [ + { start: 0, end: 1, width: 10 }, + { start: 2, end: 3, width: 20 }, + { start: 4, end: 5, width: 10 }, + ]); + const autoFit = engine.dispatch("applyLayout", { + workspacePath: root, + workbookId, + expectedRevision: 5, + sheetId, + layout: { columns: [{ start: 6, autoFit: true }] }, + }); + assert.deepEqual(autoFit.layout.columns.at(-1), { + start: 6, + end: 6, + width: 18, + autoFit: true, + }); + assert.throws( + () => engine.dispatch("insertColumns", { + workspacePath: root, + workbookId, + expectedRevision: 6, + sheetId, + at: 0, + count: 1, + }), + /LAYOUT_REFERENCE_RISK/ + ); + }); + + await t.test("rejects conflicting sheet targets and Excel-invalid sheet names", (t) => { + const root = workspace(t); + const created = engine.dispatch("createWorkbook", { workspacePath: root, sheetName: "Data" }); + const workbookId = created.meta.workbookId; + const dataSheetId = created.meta.activeSheetId; + const added = engine.dispatch("addSheet", { + workspacePath: root, + workbookId, + expectedRevision: 0, + name: "Summary", + }); + assert.throws( + () => engine.dispatch("proposePatch", { + workspacePath: root, + workbookId, + expectedRevision: 1, + sheetId: dataSheetId, + a1: "Summary!A1", + values: [[1]], + }), + /SHEET_QUALIFIER_CONFLICT/ + ); + assert.throws( + () => engine.dispatch("renameSheet", { + workspacePath: root, + workbookId, + expectedRevision: 1, + sheetId: added.sheet.id, + name: "Invalid/Name", + }), + /INVALID_SHEET_NAME/ + ); + assert.throws( + () => engine.dispatch("addSheet", { + workspacePath: root, + workbookId, + expectedRevision: 1, + name: "x".repeat(32), + }), + /INVALID_SHEET_NAME/ + ); + }); + + await t.test("blocks invalid formulas and reports external links as static warnings", (t) => { + const root = workspace(t); + const created = engine.dispatch("createWorkbook", { workspacePath: root }); + const workbookId = created.meta.workbookId; + const sheetId = created.meta.activeSheetId; + + assert.throws( + () => engine.dispatch("proposePatch", { + workspacePath: root, + workbookId, + expectedRevision: 0, + sheetId, + cells: [{ row: 0, col: 0, formula: "A1+1" }], + }), + /FORMULA_SELF_REFERENCE/ + ); + assert.throws( + () => engine.dispatch("proposePatch", { + workspacePath: root, + workbookId, + expectedRevision: 0, + sheetId, + cells: [{ row: 0, col: 1, formula: "SUM(A1:B1" }], + }), + /FORMULA_PAREN_UNBALANCED/ + ); + const warned = engine.dispatch("proposePatch", { + workspacePath: root, + workbookId, + expectedRevision: 0, + sheetId, + cells: [{ row: 0, col: 2, formula: "'[Budget.xlsx]Sheet1'!A1" }], + }); + assert.equal(warned.proposal.validation.formulaLint.recalculated, false); + assert.ok(warned.proposal.validation.formulaLint.warnings.some((issue) => issue.code === "FORMULA_EXTERNAL_LINK")); + }); + + await t.test("writes and reopens styled XLSX with valid layout XML", (t) => { + const root = workspace(t); + const workbook = store.createEmpty({ title: "Export" }); + const sheet = workbook.sheets[0]; + sheet.cells["0,0"] = { + v: "Total", + t: "s", + style: { + role: "total", + fill: { color: "#DDEBF7" }, + font: { bold: true, color: "#17365D", size: 12 }, + border: { top: { style: "double", color: "#1F1F1F" } }, + alignment: { horizontal: "right", wrapText: true }, + numberFormat: "#,##0.00", + }, + }; + sheet.layout = { + units: { columnWidth: "excelCharacters", rowHeight: "points" }, + columns: [{ start: 0, end: 1, width: 16, autoFit: true }], + rows: [{ start: 0, end: 0, height: 27 }], + freezePanes: { rows: 1, columns: 0 }, + autoFilter: { a1: "A1:B5" }, + }; + const output = path.join(root, "styled.xlsx"); + fs.writeFileSync(output, io.writeXlsxBuffer(workbook)); + + const files = io.unzipBuffer(fs.readFileSync(output)); + assert.ok(files.has("xl/styles.xml")); + assert.match(files.get("xl/styles.xml").toString("utf8"), /formatCode="#,##0\.00"/); + const sheetXml = files.get("xl/worksheets/sheet1.xml").toString("utf8"); + assert.match(sheetXml, /activePane="bottomLeft"/); + assert.match(sheetXml, //); + sheet.layout.freezePanes = { rows: 0, columns: 1 }; + let paneXml = io.unzipBuffer(io.writeXlsxBuffer(workbook)) + .get("xl/worksheets/sheet1.xml").toString("utf8"); + assert.match(paneXml, /activePane="topRight"/); + sheet.layout.freezePanes = { rows: 1, columns: 1 }; + paneXml = io.unzipBuffer(io.writeXlsxBuffer(workbook)) + .get("xl/worksheets/sheet1.xml").toString("utf8"); + assert.match(paneXml, /activePane="bottomRight"/); + sheet.layout.freezePanes = { rows: 1, columns: 0 }; + + const reopened = io.readWorkbookFile(output); + assert.equal(reopened.sheets[0].cells["0,0"].style.fill.color, "#DDEBF7"); + assert.equal(reopened.sheets[0].cells["0,0"].style.numberFormat, "#,##0.00"); + assert.equal(reopened.sheets[0].cells["0,0"].style.border.top.style, "double"); + assert.equal(reopened.sheets[0].cells["0,0"].style.alignment.horizontal, "right"); + assert.equal(reopened.sheets[0].cells["0,0"].style.alignment.wrapText, true); + assert.equal(reopened.sheets[0].layout.columns[0].width, 16); + assert.equal(reopened.sheets[0].layout.rows[0].height, 27); + assert.deepEqual(reopened.sheets[0].layout.freezePanes, { rows: 1, columns: 0 }); + }); + + await t.test("never silently drops style changes when exporting an imported Excel source", (t) => { + const root = workspace(t); + const source = path.join(root, "source.xlsx"); + const sourceWorkbook = store.createEmpty({ title: "Source" }); + sourceWorkbook.sheets[0].cells["0,0"] = { v: 1, t: "n", style: { numberFormat: "0.00" } }; + fs.writeFileSync(source, io.writeXlsxBuffer(sourceWorkbook)); + const sourceHash = hash(source); + + const opened = engine.dispatch("openWorkbook", { workspacePath: root, path: source }); + const workbookId = opened.meta.workbookId; + const sheetId = opened.meta.activeSheetId; + const proposal = engine.dispatch("proposePatch", { + workspacePath: root, + workbookId, + expectedRevision: 0, + sheetId, + cells: [{ row: 0, col: 0, style: { fill: { color: "#FFF2CC" } } }], + }); + const accepted = engine.dispatch("acceptProposal", { + workspacePath: root, + workbookId, + expectedRevision: 0, + proposalId: proposal.proposal.id, + }); + assert.equal(accepted.meta.fidelity.canRoundTrip, false); + assert.match(accepted.meta.fidelity.warning, /style/i); + const undone = engine.dispatch("undo", { + workspacePath: root, + workbookId, + expectedRevision: 1, + }); + assert.equal(undone.meta.fidelity.canRoundTrip, true); + const redone = engine.dispatch("redo", { + workspacePath: root, + workbookId, + expectedRevision: 2, + }); + assert.equal(redone.meta.fidelity.canRoundTrip, false); + + const copy = path.join(root, "styled-copy.xlsx"); + assert.throws( + () => engine.dispatch("saveWorkbook", { + workspacePath: root, + workbookId, + expectedRevision: 3, + path: copy, + }), + /FIDELITY_ACK_REQUIRED/ + ); + const saved = engine.dispatch("saveWorkbook", { + workspacePath: root, + workbookId, + expectedRevision: 3, + path: copy, + acknowledgeFidelityLoss: true, + }); + assert.equal(saved.export.mode, "lossy-rebuild"); + assert.equal(saved.export.fullCalcOnLoad, true); + assert.equal(hash(source), sourceHash); + assert.equal(io.readWorkbookFile(copy).sheets[0].cells["0,0"].style.fill.color, "#FFF2CC"); + }); +}); diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/test/contract-consistency.test.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/test/contract-consistency.test.js new file mode 100644 index 00000000..858421fa --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/test/contract-consistency.test.js @@ -0,0 +1,436 @@ +const test = require("node:test"); +const assert = require("node:assert/strict"); +const fs = require("node:fs"); +const os = require("node:os"); +const path = require("node:path"); +const vm = require("node:vm"); + +const APP_ROOT = path.resolve(__dirname, "../../../../.."); +const AGENT_ROOT = path.join( + APP_ROOT, + "components", + "agents", + "excel-live-agent" +); +const BRIDGE_ROOT = path.join( + APP_ROOT, + "components", + "bridges", + "builtin-excel-runtime" +); +const SURFACE_ROOT = path.join( + APP_ROOT, + "components", + "surfaces", + "builtin-excel-live-surface" +); + +function readJson(filePath) { + return JSON.parse(fs.readFileSync(filePath, "utf8")); +} + +function walkFiles(root, predicate = () => true) { + const files = []; + for (const entry of fs.readdirSync(root, { withFileTypes: true })) { + const filePath = path.join(root, entry.name); + if (entry.isDirectory()) { + files.push(...walkFiles(filePath, predicate)); + } else if (predicate(filePath)) { + files.push(filePath); + } + } + return files; +} + +function sortedUnique(values) { + return [...new Set(values)].sort(); +} + +function assertSameSet(actual, expected, message) { + assert.deepEqual(sortedUnique(actual), sortedUnique(expected), message); +} + +function assertPathInside(root, candidate, message) { + const relative = path.relative(root, candidate); + assert.ok( + relative && !relative.startsWith("..") && !path.isAbsolute(relative), + message + ); +} + +function topLevelFunctionSource(source, name) { + const start = source.indexOf(`function ${name}(`); + assert.notEqual(start, -1, `Engine action ${name} must have a top-level function`); + const next = source.indexOf("\nfunction ", start + 1); + return source.slice(start, next === -1 ? source.length : next); +} + +function loadSurfaceMessages() { + const i18nPath = path.join(SURFACE_ROOT, "source", "src", "i18n.js"); + const executable = fs + .readFileSync(i18nPath, "utf8") + .replace(/^import .*$/m, "const state = {};") + .replace( + /export\s*\{\s*MESSAGES\s*,\s*t\s*\};/, + "globalThis.__EXCEL_LIVE_MESSAGES__ = MESSAGES;" + ); + const sandbox = {}; + vm.createContext(sandbox); + vm.runInContext(executable, sandbox, { filename: i18nPath }); + return sandbox.__EXCEL_LIVE_MESSAGES__; +} + +function loadCommonJsModule(filePath) { + const source = fs.readFileSync(filePath, "utf8"); + const module = { exports: {} }; + const execute = new Function("require", "module", "exports", source); + execute(require, module, module.exports); + return module.exports; +} + +test("Excel Live package contract consistency", async (t) => { + const app = readJson(path.join(APP_ROOT, "app.json")); + const agentComponent = readJson(path.join(AGENT_ROOT, "component.json")); + const agentManifest = readJson(path.join(AGENT_ROOT, "source", "manifest.json")); + const bridgeComponent = readJson(path.join(BRIDGE_ROOT, "component.json")); + const bridgeManifest = readJson(path.join(BRIDGE_ROOT, "source", "manifest.json")); + const surfaceComponent = readJson(path.join(SURFACE_ROOT, "component.json")); + const engineSource = fs.readFileSync( + path.join(BRIDGE_ROOT, "source", "src", "engine.js"), + "utf8" + ); + const engineActions = require("../src/engine").actions; + const bridgeCapability = bridgeManifest.capabilities.find( + (capability) => capability.id === "sparo.excelEngine" + ); + + await t.test("all package JSON parses and declared entries exist", () => { + const jsonFiles = walkFiles(APP_ROOT, (filePath) => filePath.endsWith(".json")); + assert.ok(jsonFiles.length > 0, "Excel Live package must contain JSON manifests"); + for (const filePath of jsonFiles) { + assert.doesNotThrow( + () => readJson(filePath), + `Invalid JSON: ${path.relative(APP_ROOT, filePath)}` + ); + } + + const bridgeEntry = path.resolve( + BRIDGE_ROOT, + "source", + bridgeManifest.runtime.entry + ); + assertPathInside( + path.join(BRIDGE_ROOT, "source"), + bridgeEntry, + "Bridge entry must stay inside its source directory" + ); + assert.ok(fs.existsSync(bridgeEntry), "Bridge runtime entry must exist"); + + const surfaceManifest = readJson( + path.join(SURFACE_ROOT, "source", "source_manifest.json") + ); + for (const entry of [ + surfaceManifest.uiEntry, + surfaceManifest.workerEntry, + ...(surfaceManifest.styleEntries || []), + ]) { + const entryPath = path.resolve(SURFACE_ROOT, "source", entry); + assertPathInside( + path.join(SURFACE_ROOT, "source"), + entryPath, + `Surface entry ${entry} must stay inside its source directory` + ); + assert.ok(fs.existsSync(entryPath), `Surface entry must exist: ${entry}`); + } + }); + + await t.test("app component references match private component contracts", () => { + const privateComponents = new Map([ + [agentComponent.id, agentComponent], + [bridgeComponent.id, bridgeComponent], + [surfaceComponent.id, surfaceComponent], + ]); + + for (const reference of app.components.filter( + (component) => component.source === "private" + )) { + const component = privateComponents.get(reference.componentId); + assert.ok(component, `Missing private component ${reference.componentId}`); + assert.equal(component.kind, reference.kind); + assert.equal(component.ownerApp?.appId, app.id); + assert.equal(component.ownerApp?.appVersion, app.version); + assert.ok(component.usedByApps?.includes(app.id)); + const capabilityIds = component.capabilities.map((capability) => capability.id); + for (const capabilityId of reference.capabilities || []) { + assert.ok( + capabilityIds.includes(capabilityId), + `${reference.componentId} does not declare capability ${capabilityId}` + ); + } + } + + const referencedIds = new Set(app.components.map((component) => component.componentId)); + for (const component of privateComponents.values()) { + for (const dependency of component.dependencies || []) { + assert.ok( + referencedIds.has(dependency.componentId), + `${component.id} depends on component absent from app.json: ${dependency.componentId}` + ); + } + } + }); + + await t.test("bridge action declarations stay aligned with the engine", () => { + assert.ok(bridgeCapability, "sparo.excelEngine capability must exist"); + const componentCapability = bridgeComponent.capabilities.find( + (capability) => capability.id === bridgeCapability.id + ); + const runtimeTool = bridgeManifest.tools.find( + (tool) => tool.capabilityId === bridgeCapability.id + ); + assert.ok(componentCapability, "Bridge component capability must exist"); + assert.ok(runtimeTool, "Bridge runtime tool must exist"); + + assertSameSet( + componentCapability.actions, + bridgeCapability.actions, + "component.json and manifest capability actions must match" + ); + assertSameSet( + bridgeManifest.actions.map((action) => action.name), + bridgeCapability.actions, + "manifest action definitions and capability actions must match" + ); + assertSameSet( + runtimeTool.actions, + bridgeCapability.actions, + "runtime tool and capability actions must match" + ); + + for (const action of bridgeCapability.actions) { + assert.equal( + typeof engineActions[action], + "function", + `Declared bridge action is missing from engine: ${action}` + ); + } + + const surfaceActions = new Set(); + for (const filePath of walkFiles( + path.join(SURFACE_ROOT, "source"), + (candidate) => candidate.endsWith(".js") + )) { + const source = fs.readFileSync(filePath, "utf8"); + for (const match of source.matchAll(/\bcallExcel\(\s*["']([^"']+)["']/g)) { + surfaceActions.add(match[1]); + } + } + for (const action of surfaceActions) { + assert.ok( + bridgeCapability.actions.includes(action), + `Surface calls undeclared bridge action: ${action}` + ); + assert.equal(typeof engineActions[action], "function"); + } + }); + + await t.test("agent tools match manifest, bridge actions, and revision guards", () => { + const toolsDirectory = path.join(AGENT_ROOT, "source", "tools"); + const toolDefinitions = walkFiles( + toolsDirectory, + (filePath) => filePath.endsWith(".tool.json") + ).map((filePath) => ({ filePath, manifest: readJson(filePath) })); + const toolNames = toolDefinitions.map(({ manifest }) => manifest.name); + assert.equal( + new Set(toolNames).size, + toolNames.length, + "Agent tool names must be unique" + ); + + const runtimePrefix = `agentcomponent__${agentManifest.id}__`; + const selectedRuntimeTools = agentManifest.tools + .filter((name) => name.startsWith(runtimePrefix)) + .map((name) => name.slice(runtimePrefix.length)); + assertSameSet( + selectedRuntimeTools, + toolNames, + "Agent manifest runtime tools must match .tool.json definitions" + ); + + const mutatingActions = new Set([ + "openWorkbook", + "createWorkbook", + "proposePatch", + "acceptProposal", + "rejectProposal", + "undo", + "redo", + "saveWorkbook", + "switchSheet", + ]); + + for (const { filePath, manifest } of toolDefinitions) { + const entryPath = path.resolve(AGENT_ROOT, "source", manifest.entry); + assertPathInside( + path.join(AGENT_ROOT, "source"), + entryPath, + `${manifest.name} entry must stay inside the agent source directory` + ); + assert.ok(fs.existsSync(entryPath), `${manifest.name} entry must exist`); + + const properties = manifest.inputSchema?.properties || {}; + assert.equal( + Object.hasOwn(properties, "workspacePath") || + Object.hasOwn(properties, "workspace_path"), + false, + `${manifest.name} must not expose the host-owned workspace path` + ); + + const entrySource = fs.readFileSync(entryPath, "utf8"); + const actionMatch = entrySource.match( + /callExcelEngine\(\s*["']([^"']+)["']/ + ); + assert.ok( + actionMatch, + `${path.relative(APP_ROOT, filePath)} must call a static Excel Engine action` + ); + const action = actionMatch[1]; + assert.ok( + bridgeCapability.actions.includes(action), + `${manifest.name} calls undeclared bridge action ${action}` + ); + assert.equal( + typeof engineActions[action], + "function", + `${manifest.name} calls missing engine action ${action}` + ); + + if (mutatingActions.has(action)) { + assert.equal( + manifest.readonly, + false, + `${manifest.name} persists workbook or proposal state and cannot be readonly` + ); + } + + const actionSource = topLevelFunctionSource(engineSource, action); + const required = new Set(manifest.inputSchema?.required || []); + if (actionSource.includes("assertExpectedRevision")) { + assert.ok( + required.has("expectedRevision") && properties.expectedRevision, + `${manifest.name} must require expectedRevision because ${action} enforces it` + ); + } + if (actionSource.includes("[PROPOSAL_ID_REQUIRED]")) { + assert.ok( + required.has("proposalId") && properties.proposalId, + `${manifest.name} must require proposalId because ${action} enforces it` + ); + } + } + + const toolNameSet = new Set(toolNames); + for (const serviceAction of agentManifest.serviceActions || []) { + for (const runtimeTool of (serviceAction.toolPolicy || []).filter((name) => + name.startsWith(runtimePrefix) + )) { + assert.ok( + toolNameSet.has(runtimeTool.slice(runtimePrefix.length)), + `${serviceAction.name} references missing tool ${runtimeTool}` + ); + } + } + }); + + await t.test("agent paths stay workspace-relative and CSV cannot bypass safe export", (t) => { + const bridgeHelpers = loadCommonJsModule( + path.join(AGENT_ROOT, "source", "tools", "excel_bridge.js") + ); + assert.deepEqual( + bridgeHelpers.normalizeInput( + { + workspacePath: "C:/model-owned", + workspace_path: "C:/also-model-owned", + workbook_id: "wb_1", + path: "reports/book.xlsx", + }, + { workspaceRoot: "D:/trusted-workspace" } + ), + { + workbookId: "wb_1", + path: "reports/book.xlsx", + workspacePath: "D:/trusted-workspace", + } + ); + assert.throws( + () => bridgeHelpers.normalizeInput({}, {}), + /host-bound workspace root/ + ); + for (const unsafePath of [ + "C:/outside/book.xlsx", + "/outside/book.xlsx", + "../outside/book.xlsx", + "nested/../../outside/book.xlsx", + "..\\outside\\book.xlsx", + "book.xlsx\0suffix", + ]) { + assert.throws( + () => + bridgeHelpers.normalizeInput( + { path: unsafePath }, + { workspaceRoot: "D:/trusted-workspace" } + ), + /workspace-relative|active workspace/, + unsafePath + ); + } + + const workspacePath = fs.mkdtempSync( + path.join(os.tmpdir(), "excel-contract-csv-bypass-") + ); + t.after(() => fs.rmSync(workspacePath, { recursive: true, force: true })); + const engine = require("../src/engine"); + const created = engine.dispatch("createWorkbook", { workspacePath }); + assert.throws( + () => + engine.dispatch("saveWorkbook", { + workspacePath, + workbookId: created.meta.workbookId, + expectedRevision: created.meta.revision, + path: path.join(workspacePath, "unsafe.csv"), + exportCopy: true, + }), + /CSV_EXPORT_ACTION_REQUIRED/ + ); + assert.equal(fs.existsSync(path.join(workspacePath, "unsafe.csv")), false); + }); + + await t.test("surface translations have locale parity and cover static keys", () => { + const messages = loadSurfaceMessages(); + assert.ok(messages?.["en-US"] && messages?.["zh-CN"]); + const englishKeys = Object.keys(messages["en-US"]); + const chineseKeys = Object.keys(messages["zh-CN"]); + assertSameSet( + englishKeys, + chineseKeys, + "Excel Live surface locales must have identical key sets" + ); + + const usedKeys = new Set(); + for (const filePath of walkFiles( + path.join(SURFACE_ROOT, "source"), + (candidate) => candidate.endsWith(".js") + )) { + const source = fs.readFileSync(filePath, "utf8"); + for (const match of source.matchAll(/\bt\(\s*["']([^"']+)["']/g)) { + usedKeys.add(match[1]); + } + } + for (const key of usedKeys) { + assert.ok( + Object.hasOwn(messages["en-US"], key), + `Static surface translation key is missing: ${key}` + ); + } + }); +}); diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/test/engine-safety.test.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/test/engine-safety.test.js new file mode 100644 index 00000000..91672a80 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/test/engine-safety.test.js @@ -0,0 +1,986 @@ +const test = require("node:test"); +const assert = require("node:assert/strict"); +const crypto = require("node:crypto"); +const fs = require("node:fs"); +const os = require("node:os"); +const path = require("node:path"); + +const engine = require("../src/engine"); +const store = require("../src/workbook-store"); +const io = require("../src/xlsx-io"); +const csv = require("../src/csv-io"); + +function tempWorkspace(t, prefix) { + const root = fs.mkdtempSync(path.join(os.tmpdir(), prefix)); + t.after(() => { + const resolved = path.resolve(root); + const tempRoot = `${path.resolve(os.tmpdir())}${path.sep}`; + assert.ok(resolved.startsWith(tempRoot), `Refusing unsafe cleanup: ${resolved}`); + fs.rmSync(resolved, { recursive: true, force: true }); + }); + return root; +} + +function sha256(filePath) { + return crypto.createHash("sha256").update(fs.readFileSync(filePath)).digest("hex"); +} + +function writeInstrumentedExcelSource(root, options = {}) { + const extension = options.extension || ".xlsx"; + const filePath = path.join(root, `source${extension}`); + const workbook = store.createEmpty({ title: "Source" }); + workbook.sheets[0].cells["0,0"] = { v: 1, t: "n" }; + if (options.withFormula !== false) { + workbook.sheets[0].cells["0,1"] = { f: "A1*2", v: 2, t: "f" }; + } + const files = io.unzipBuffer(io.writeXlsxBuffer(workbook)); + const sheetPath = "xl/worksheets/sheet1.xml"; + files.set( + sheetPath, + Buffer.from( + files.get(sheetPath).toString("utf8").replace('', + "utf8" + ) + ); + files.set("custom/opaque.bin", Buffer.from([0, 1, 2, 253, 254, 255])); + files.set( + "xl/calcChain.xml", + Buffer.from( + '', + "utf8" + ) + ); + files.set( + "xl/_rels/workbook.xml.rels", + Buffer.from( + files + .get("xl/_rels/workbook.xml.rels") + .toString("utf8") + .replace( + "", + '' + ), + "utf8" + ) + ); + files.set( + "[Content_Types].xml", + Buffer.from( + files + .get("[Content_Types].xml") + .toString("utf8") + .replace( + "", + '' + ), + "utf8" + ) + ); + + if (extension === ".xlsm") { + const macroBytes = Buffer.from([0xde, 0xad, 0xbe, 0xef, 0, 1, 2, 3]); + files.set("xl/vbaProject.bin", macroBytes); + files.set( + "[Content_Types].xml", + Buffer.from( + files + .get("[Content_Types].xml") + .toString("utf8") + .replace( + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml", + "application/vnd.ms-excel.sheet.macroEnabled.main+xml" + ) + .replace( + "", + '' + ), + "utf8" + ) + ); + files.set( + "xl/_rels/workbook.xml.rels", + Buffer.from( + files + .get("xl/_rels/workbook.xml.rels") + .toString("utf8") + .replace( + "", + '' + ), + "utf8" + ) + ); + } + + fs.writeFileSync( + filePath, + io.zipStore([...files].map(([name, data]) => ({ name, data }))) + ); + return filePath; +} + +function writeWorkbookWithCellRef(root, fileName, cellRef) { + const workbook = store.createEmpty({ title: "Cell reference" }); + workbook.sheets[0].cells["0,0"] = { v: 1, t: "n" }; + const files = io.unzipBuffer(io.writeXlsxBuffer(workbook)); + const sheetPath = "xl/worksheets/sheet1.xml"; + files.set( + sheetPath, + Buffer.from( + files.get(sheetPath).toString("utf8").replace(' ({ name, data })))); + return filePath; +} + +function writeWorkbookWithSerializedCellCount(root, fileName, cellCount) { + const workbook = store.createEmpty({ title: "Cell budget" }); + const files = io.unzipBuffer(io.writeXlsxBuffer(workbook)); + const sheetPath = "xl/worksheets/sheet1.xml"; + const xml = files.get(sheetPath).toString("utf8").replace( + /[\s\S]*?<\/sheetData>/, + `${'1'.repeat(cellCount)}` + ); + files.set(sheetPath, Buffer.from(xml, "utf8")); + const filePath = path.join(root, fileName); + fs.writeFileSync(filePath, io.zipStore([...files].map(([name, data]) => ({ name, data })))); + return filePath; +} + +function writeSparseFile(filePath, size) { + fs.writeFileSync(filePath, ""); + fs.truncateSync(filePath, size); +} + +test("Excel Live engine safety contract", async (t) => { + await t.test("enforces Inspect mode, monotonic revision, undo, redo, and formula structure safety", (t) => { + const root = tempWorkspace(t, "excel-engine-revision-"); + const created = engine.dispatch("createWorkbook", { workspacePath: root, title: "Revision" }); + const workbookId = created.meta.workbookId; + const sheetId = created.meta.activeSheetId; + + engine.dispatch("setFocus", { + workspacePath: root, + workbookId, + sheetId, + a1: "B2", + mode: "inspect", + }); + let meta = engine.dispatch("getMeta", { workspacePath: root, workbookId }).meta; + assert.equal(meta.revision, 0); + assert.equal(meta.dirty, false); + assert.equal(meta.mode, "inspect"); + assert.throws( + () => engine.dispatch("applyLocalEdit", { + workspacePath: root, + workbookId, + sheetId, + row: 0, + col: 0, + value: 1, + }), + /INSPECT_MODE_READ_ONLY/ + ); + assert.throws( + () => engine.dispatch("proposePatch", { + workspacePath: root, + workbookId, + sheetId, + cells: [{ row: 0, col: 0, value: 1 }], + }), + /INSPECT_MODE_READ_ONLY/ + ); + + engine.dispatch("setMode", { workspacePath: root, workbookId, mode: "edit" }); + const applied = engine.dispatch("applyLocalPatch", { + workspacePath: root, + workbookId, + sheetId, + a1: "A1", + values: [[1, 2], [3, 4]], + baseRevision: 0, + }); + assert.equal(applied.meta.revision, 1); + assert.throws( + () => engine.dispatch("applyLocalEdit", { + workspacePath: root, + workbookId, + sheetId, + row: 0, + col: 0, + value: 8, + expectedRevision: 0, + }), + /REVISION_CONFLICT/ + ); + + const undone = engine.dispatch("undo", { + workspacePath: root, + workbookId, + expectedRevision: 1, + }); + assert.equal(undone.meta.revision, 2); + assert.deepEqual( + engine.dispatch("readRange", { + workspacePath: root, + workbookId, + sheetId, + a1: "A1:B2", + }).values, + [[null, null], [null, null]] + ); + + const redone = engine.dispatch("redo", { + workspacePath: root, + workbookId, + expectedRevision: 2, + }); + assert.equal(redone.meta.revision, 3); + assert.deepEqual( + engine.dispatch("readRange", { + workspacePath: root, + workbookId, + sheetId, + a1: "A1:B2", + }).values, + [[1, 2], [3, 4]] + ); + const history = engine.dispatch("getHistory", { workspacePath: root, workbookId }); + assert.equal(history.entries.length, 3); + assert.equal(history.canUndo, true); + assert.equal(history.canRedo, false); + + engine.dispatch("applyLocalEdit", { + workspacePath: root, + workbookId, + sheetId, + row: 2, + col: 0, + formula: "=A1+B1", + expectedRevision: 3, + }); + assert.throws( + () => engine.dispatch("insertRows", { + workspacePath: root, + workbookId, + sheetId, + at: 0, + expectedRevision: 4, + }), + /FORMULA_REFERENCE_RISK/ + ); + }); + + await t.test("keeps proposals uncommitted, rejects replacement, and safely partially accepts", (t) => { + const root = tempWorkspace(t, "excel-engine-proposal-"); + const created = engine.dispatch("createWorkbook", { workspacePath: root }); + const workbookId = created.meta.workbookId; + const sheetId = created.meta.activeSheetId; + engine.dispatch("applyLocalPatch", { + workspacePath: root, + workbookId, + sheetId, + a1: "A1", + values: [[1, 2]], + expectedRevision: 0, + }); + + const proposal = engine.dispatch("proposePatch", { + workspacePath: root, + workbookId, + sheetId, + cells: [ + { row: 0, col: 0, value: 10 }, + { row: 0, col: 1, value: 20 }, + ], + expectedRevision: 1, + intent: "Raise values", + }); + assert.equal(proposal.proposal.baseRevision, 1); + assert.equal(proposal.proposal.intent, "Raise values"); + assert.deepEqual( + engine.dispatch("readRange", { + workspacePath: root, + workbookId, + sheetId, + a1: "A1:B1", + }).values, + [[1, 2]], + "proposePatch must not mutate committed cells" + ); + assert.throws( + () => engine.dispatch("proposePatch", { + workspacePath: root, + workbookId, + sheetId, + cells: [{ row: 1, col: 0, value: 30 }], + expectedRevision: 1, + }), + /ACTIVE_PROPOSAL_EXISTS/ + ); + + const partial = engine.dispatch("acceptProposal", { + workspacePath: root, + workbookId, + proposalId: proposal.proposal.id, + cellRefs: [`${sheetId}!A1`], + baseRevision: 1, + }); + assert.equal(partial.applied.cellCount, 1); + assert.equal(partial.meta.revision, 2); + assert.equal(partial.remainingProposal.cellCount, 1); + assert.equal(partial.remainingProposal.baseRevision, 2); + assert.deepEqual( + engine.dispatch("readRange", { + workspacePath: root, + workbookId, + sheetId, + a1: "A1:B1", + }).values, + [[10, 2]] + ); + + const complete = engine.dispatch("acceptProposal", { + workspacePath: root, + workbookId, + proposalId: proposal.proposal.id, + cellRefs: ["B1"], + expectedRevision: 2, + }); + assert.equal(complete.meta.revision, 3); + assert.equal(complete.remainingProposal, null); + + const conflicting = engine.dispatch("proposePatch", { + workspacePath: root, + workbookId, + sheetId, + cells: [{ row: 1, col: 0, value: 99 }], + expectedRevision: 3, + }); + engine.sessions.get(workbookId).workbook.sheets[0].cells["1,0"] = { v: 7, t: "n" }; + assert.throws( + () => engine.dispatch("acceptProposal", { + workspacePath: root, + workbookId, + proposalId: conflicting.proposal.id, + expectedRevision: 3, + }), + /PROPOSAL_BEFORE_CONFLICT/ + ); + assert.equal(engine.sessions.get(workbookId).workbook.revision, 3); + }); + + await t.test("exports a source-preserving copy without changing source hash or workbook identity", (t) => { + const root = tempWorkspace(t, "excel-engine-safe-copy-"); + const sourcePath = writeInstrumentedExcelSource(root); + const copyPath = path.join(root, "copy.xlsx"); + const sourceHash = sha256(sourcePath); + const opened = engine.dispatch("openWorkbook", { workspacePath: root, path: sourcePath }); + const workbookId = opened.meta.workbookId; + const sheetId = opened.meta.activeSheetId; + + engine.dispatch("applyLocalEdit", { + workspacePath: root, + workbookId, + sheetId, + row: 0, + col: 0, + value: 3, + expectedRevision: 0, + }); + engine.dispatch("applyLocalEdit", { + workspacePath: root, + workbookId, + sheetId, + row: 0, + col: 1, + formula: "=A1*4", + expectedRevision: 1, + }); + assert.throws( + () => engine.dispatch("saveWorkbook", { + workspacePath: root, + workbookId, + expectedRevision: 2, + }), + /SOURCE_OVERWRITE_BLOCKED/ + ); + assert.throws( + () => engine.dispatch("saveWorkbook", { + workspacePath: root, + workbookId, + path: copyPath, + exportCopy: true, + expectedRevision: 1, + }), + /REVISION_CONFLICT/ + ); + + const saved = engine.dispatch("saveWorkbook", { + workspacePath: root, + workbookId, + path: copyPath, + exportCopy: true, + expectedRevision: 2, + }); + assert.equal(saved.export.mode, "source-preserving-cell-patch"); + assert.equal(saved.workingPath, sourcePath); + assert.equal(saved.meta.path, sourcePath); + assert.equal(saved.meta.sourcePath, sourcePath); + assert.equal(saved.meta.lastExportPath, copyPath); + assert.equal(saved.meta.lastExportedRevision, 2); + assert.equal(saved.meta.dirty, false); + assert.equal(sha256(sourcePath), sourceHash, "export copy must not mutate the imported source"); + + const output = io.unzipBuffer(fs.readFileSync(copyPath)); + assert.deepEqual(output.get("custom/opaque.bin"), Buffer.from([0, 1, 2, 253, 254, 255])); + const sheetXml = output.get("xl/worksheets/sheet1.xml").toString("utf8"); + assert.match(sheetXml, /3<\/v><\/c>/); + assert.deepEqual(output.get("xl/styles.xml"), io.unzipBuffer(fs.readFileSync(sourcePath)).get("xl/styles.xml")); + assert.match(sheetXml, /A1\*4<\/f><\/c>/); + assert.equal(output.has("xl/calcChain.xml"), false); + assert.doesNotMatch( + output.get("xl/_rels/workbook.xml.rels").toString("utf8"), + /calcChain/i + ); + assert.match( + output.get("xl/workbook.xml").toString("utf8"), + /fullCalcOnLoad="1"[^>]*forceFullCalc="1"/ + ); + assert.equal(io.readWorkbookFile(copyPath).sheets[0].cells["0,1"].f, "A1*4"); + + engine.sessions.clear(); + const resumed = engine.dispatch("getMeta", { workspacePath: root, workbookId }).meta; + assert.equal(resumed.path, sourcePath); + assert.equal(resumed.sourcePath, sourcePath); + assert.equal(resumed.lastExportPath, copyPath); + }); + + await t.test("preserves unknown row XML while patching a source cell", (t) => { + const root = tempWorkspace(t, "excel-engine-row-xml-"); + const sourcePath = writeInstrumentedExcelSource(root, { withFormula: false }); + const copyPath = path.join(root, "row-xml-copy.xlsx"); + const files = io.unzipBuffer(fs.readFileSync(sourcePath)); + const sheetPath = "xl/worksheets/sheet1.xml"; + const marker = ''; + files.set( + sheetPath, + Buffer.from( + files.get(sheetPath).toString("utf8").replace("", `${marker}`), + "utf8" + ) + ); + fs.writeFileSync( + sourcePath, + io.zipStore([...files].map(([name, data]) => ({ name, data }))) + ); + + const opened = engine.dispatch("openWorkbook", { workspacePath: root, path: sourcePath }); + engine.dispatch("applyLocalEdit", { + workspacePath: root, + workbookId: opened.meta.workbookId, + sheetId: opened.meta.activeSheetId, + row: 0, + col: 0, + value: 7, + expectedRevision: 0, + }); + const saved = engine.dispatch("saveWorkbook", { + workspacePath: root, + workbookId: opened.meta.workbookId, + path: copyPath, + exportCopy: true, + expectedRevision: 1, + }); + assert.equal(saved.export.mode, "source-preserving-cell-patch"); + const outputXml = io + .unzipBuffer(fs.readFileSync(copyPath)) + .get(sheetPath) + .toString("utf8"); + assert.match(outputXml, /SPARO-ROW-METADATA/); + assert.match(outputXml, /7<\/v><\/c>/); + }); + + await t.test("recognizes shared formula followers and blocks edits inside complex formula ranges", (t) => { + const root = tempWorkspace(t, "excel-engine-complex-formula-"); + const sourcePath = writeInstrumentedExcelSource(root, { withFormula: false }); + const copyPath = path.join(root, "complex-formula-copy.xlsx"); + const files = io.unzipBuffer(fs.readFileSync(sourcePath)); + const sheetPath = "xl/worksheets/sheet1.xml"; + const sourceXml = files.get(sheetPath).toString("utf8"); + files.set( + sheetPath, + Buffer.from( + sourceXml.replace( + /[\s\S]*?<\/sheetData>/, + 'ROW()1ROW(B1:B2)122' + ), + "utf8" + ) + ); + fs.writeFileSync( + sourcePath, + io.zipStore([...files].map(([name, data]) => ({ name, data }))) + ); + + const opened = engine.dispatch("openWorkbook", { workspacePath: root, path: sourcePath }); + assert.equal(opened.meta.calculationStatus.status, "cached"); + assert.equal(opened.meta.calculationStatus.formulaCount, 4); + const read = engine.dispatch("readRange", { + workspacePath: root, + workbookId: opened.meta.workbookId, + sheetId: opened.meta.activeSheetId, + a1: "A1:B2", + maxCells: 4, + }); + assert.equal(read.formulas.length, 4); + assert.equal(read.formulas[2].formula, null); + assert.equal(read.formulas[2].formulaEvidence, true); + assert.equal(read.formulas[2].formulaType, "shared"); + assert.equal(read.formulas[3].formula, null); + assert.equal(read.formulas[3].formulaType, "array"); + + engine.dispatch("applyLocalEdit", { + workspacePath: root, + workbookId: opened.meta.workbookId, + sheetId: opened.meta.activeSheetId, + row: 1, + col: 1, + value: 9, + expectedRevision: 0, + }); + assert.throws( + () => engine.dispatch("saveWorkbook", { + workspacePath: root, + workbookId: opened.meta.workbookId, + path: copyPath, + exportCopy: true, + expectedRevision: 1, + }), + /COMPLEX_FORMULA_PATCH_UNSAFE/ + ); + }); + + await t.test("preserves VBA package parts for value-only xlsm copies", (t) => { + const root = tempWorkspace(t, "excel-engine-xlsm-"); + const sourcePath = writeInstrumentedExcelSource(root, { extension: ".xlsm" }); + const copyPath = path.join(root, "copy.xlsm"); + const workbook = io.readWorkbookFile(sourcePath); + workbook.sheets[0].cells["0,0"] = { v: 8, t: "n" }; + const result = io.writeWorkbookFile(workbook, copyPath); + assert.equal(result.mode, "source-preserving-cell-patch"); + const source = io.unzipBuffer(fs.readFileSync(sourcePath)); + const output = io.unzipBuffer(fs.readFileSync(copyPath)); + assert.deepEqual(output.get("xl/vbaProject.bin"), source.get("xl/vbaProject.bin")); + assert.match(output.get("[Content_Types].xml").toString("utf8"), /macroEnabled/); + assert.match(output.get("xl/_rels/workbook.xml.rels").toString("utf8"), /vbaProject/); + }); + + await t.test("strictly enforces Excel cell bounds and a workbook-wide parsed-cell budget", (t) => { + const root = tempWorkspace(t, "excel-engine-xlsx-limits-"); + const edgePath = writeWorkbookWithCellRef( + root, + "edge.xlsx", + `XFD${io.limits.excelMaxRows}` + ); + const edge = io.readWorkbookFile(edgePath); + assert.equal( + edge.sheets[0].cells[`${io.limits.excelMaxRows - 1},${io.limits.excelMaxColumns - 1}`].v, + 1 + ); + + const invalidRefs = [ + ["column-overflow.xlsx", "XFE1"], + ["row-overflow.xlsx", `A${io.limits.excelMaxRows + 1}`], + ["unsafe-integer.xlsx", "A9007199254740992"], + ]; + for (const [fileName, cellRef] of invalidRefs) { + const filePath = writeWorkbookWithCellRef(root, fileName, cellRef); + assert.throws(() => io.readWorkbookFile(filePath), /XLSX_CELL_REF_LIMIT/); + } + + const overBudgetPath = writeWorkbookWithSerializedCellCount( + root, + "cell-budget.xlsx", + io.limits.maxParsedCells + 1 + ); + assert.throws(() => io.readWorkbookFile(overBudgetPath), /XLSX_CELL_COUNT_LIMIT/); + }); + + await t.test("bounds patch, accept, CSV parse, and dense export work", (t) => { + const root = tempWorkspace(t, "excel-engine-operation-limits-"); + assert.throws( + () => engine.dispatch("createWorkbook", { + workspacePath: root, + rows: io.limits.excelMaxRows + 1, + }), + /EXCEL_SHEET_LIMIT/ + ); + + const created = engine.dispatch("createWorkbook", { workspacePath: root }); + const workbookId = created.meta.workbookId; + const sheetId = created.meta.activeSheetId; + assert.throws( + () => engine.dispatch("proposePatch", { + workspacePath: root, + workbookId, + sheetId, + expectedRevision: 0, + intent: "Reject an out-of-bounds cell", + cells: [{ row: io.limits.excelMaxRows, col: 0, value: 1 }], + }), + /EXCEL_CELL_LIMIT/ + ); + + const proposal = engine.dispatch("proposePatch", { + workspacePath: root, + workbookId, + sheetId, + expectedRevision: 0, + intent: "Bound selection expansion", + cells: [{ row: 0, col: 0, value: 1 }], + }); + assert.throws( + () => engine.dispatch("acceptProposal", { + workspacePath: root, + workbookId, + proposalId: proposal.proposal.id, + expectedRevision: 0, + cellRefs: [`A1:XFD${io.limits.excelMaxRows}`], + }), + /ACCEPT_CELL_LIMIT/ + ); + + assert.throws( + () => csv.parseCsv("a,b\nc,d", { maxCells: 3 }), + /CSV_CELL_COUNT_LIMIT/ + ); + + const sparse = store.createEmpty({ + rows: io.limits.excelMaxRows, + cols: io.limits.excelMaxColumns, + }); + sparse.sheets[0].cells[ + `${io.limits.excelMaxRows - 1},${io.limits.excelMaxColumns - 1}` + ] = { v: 1, t: "n" }; + assert.throws(() => io.sheetToMatrix(sparse.sheets[0]), /DENSE_EXPORT_CELL_LIMIT/); + }); + + await t.test("rejects oversized ZIP, CSV, and JSON sources before whole-file reads", (t) => { + const root = tempWorkspace(t, "excel-engine-source-size-"); + const oversized = [ + ["oversized.xlsx", io.limits.maxZipFileBytes, /ZIP_FILE_SIZE_LIMIT/], + ["oversized.csv", io.limits.maxCsvFileBytes, /CSV_FILE_SIZE_LIMIT/], + ["oversized.json", io.limits.maxJsonFileBytes, /JSON_FILE_SIZE_LIMIT/], + ]; + for (const [fileName, limit, expectedError] of oversized) { + const filePath = path.join(root, fileName); + writeSparseFile(filePath, limit + 1); + assert.throws(() => io.readWorkbookFile(filePath), expectedError); + } + }); + + await t.test("blocks direct, junction, symlink, and hard-link aliases of the imported source", (t) => { + const root = tempWorkspace(t, "excel-engine-source-alias-"); + const realDirectory = path.join(root, "real"); + fs.mkdirSync(realDirectory); + const sourcePath = writeInstrumentedExcelSource(realDirectory); + const workbook = io.readWorkbookFile(sourcePath); + const sourceHash = sha256(sourcePath); + + assert.throws( + () => io.writeWorkbookFile(workbook, sourcePath, { allowLossyRebuild: true }), + /SOURCE_TARGET_ALIAS_BLOCKED/ + ); + + const hardLinkPath = path.join(root, "source-hard-link.xlsx"); + fs.linkSync(sourcePath, hardLinkPath); + assert.throws( + () => io.writeWorkbookFile(workbook, hardLinkPath, { allowLossyRebuild: true }), + /SOURCE_TARGET_ALIAS_BLOCKED/ + ); + + const aliasDirectory = path.join(root, "directory-alias"); + fs.symlinkSync(realDirectory, aliasDirectory, process.platform === "win32" ? "junction" : "dir"); + assert.throws( + () => io.writeWorkbookFile(workbook, path.join(aliasDirectory, "source.xlsx"), { + allowLossyRebuild: true, + }), + /SOURCE_TARGET_ALIAS_BLOCKED/ + ); + const safeAliasCopyPath = path.join(aliasDirectory, "copy.xlsx"); + const safeAliasCopy = io.writeWorkbookFile(workbook, safeAliasCopyPath); + assert.equal(safeAliasCopy.path, safeAliasCopyPath); + assert.equal(fs.existsSync(path.join(realDirectory, "copy.xlsx")), true); + + const symlinkPath = path.join(root, "source-symlink.xlsx"); + try { + fs.symlinkSync(sourcePath, symlinkPath, "file"); + assert.throws( + () => io.writeWorkbookFile(workbook, symlinkPath, { allowLossyRebuild: true }), + /SOURCE_TARGET_ALIAS_BLOCKED/ + ); + } catch (error) { + if (error?.code !== "EPERM") throw error; + t.diagnostic("File symlink assertion skipped because this Windows account cannot create symlinks."); + } + assert.equal(sha256(sourcePath), sourceHash, "alias checks must leave the source unchanged"); + }); + + await t.test("restores source round-trip fidelity across structural undo and redo", (t) => { + const root = tempWorkspace(t, "excel-engine-fidelity-"); + const sourcePath = writeInstrumentedExcelSource(root, { withFormula: false }); + const opened = engine.dispatch("openWorkbook", { workspacePath: root, path: sourcePath }); + const workbookId = opened.meta.workbookId; + const sheetId = opened.meta.activeSheetId; + const inserted = engine.dispatch("insertRows", { + workspacePath: root, + workbookId, + sheetId, + at: 1, + expectedRevision: 0, + }); + assert.equal(inserted.meta.fidelity.canRoundTrip, false); + const undone = engine.dispatch("undo", { + workspacePath: root, + workbookId, + expectedRevision: 1, + }); + assert.equal(undone.meta.fidelity.canRoundTrip, true); + const redone = engine.dispatch("redo", { + workspacePath: root, + workbookId, + expectedRevision: 2, + }); + assert.equal(redone.meta.fidelity.canRoundTrip, false); + }); + + await t.test("guards stale formula CSV export and sanitizes text formula injection", (t) => { + const root = tempWorkspace(t, "excel-engine-csv-"); + const created = engine.dispatch("createWorkbook", { workspacePath: root }); + const workbookId = created.meta.workbookId; + const sheetId = created.meta.activeSheetId; + engine.dispatch("applyLocalPatch", { + workspacePath: root, + workbookId, + sheetId, + cells: [ + { row: 0, col: 0, value: "=2+2" }, + { row: 0, col: 1, value: "+cmd" }, + { row: 0, col: 2, value: "-cmd" }, + { row: 0, col: 3, value: "@SUM(A1:A2)" }, + { row: 0, col: 4, value: "\t=evil" }, + { row: 0, col: 5, value: "\r=evil" }, + { row: 0, col: 6, formula: "=1+1", value: 2 }, + ], + expectedRevision: 0, + }); + const csvPath = path.join(root, "safe.csv"); + assert.throws( + () => engine.dispatch("exportCsv", { + workspacePath: root, + workbookId, + sheetId, + path: csvPath, + expectedRevision: 1, + }), + /STALE_FORMULA_VALUES_ACK_REQUIRED/ + ); + assert.equal(fs.existsSync(csvPath), false); + + const exported = engine.dispatch("exportCsv", { + workspacePath: root, + workbookId, + sheetId, + path: csvPath, + acknowledgeStaleFormulaValues: true, + expectedRevision: 1, + }); + assert.equal(exported.formulaCount, 1); + assert.equal(exported.sanitizedCellCount, 6); + assert.match(exported.warning, /cached values .*may be stale/); + assert.match(exported.warning, /formula-injection prefixes/); + const csv = fs.readFileSync(csvPath, "utf8"); + assert.match(csv, /^'=2\+2,'\+cmd,'-cmd,'@SUM/); + assert.match(csv, /'\t=evil/); + assert.match(csv, /'\r=evil/); + + const uncached = engine.dispatch("createWorkbook", { + workspacePath: root, + title: "Uncached formula", + }); + engine.dispatch("applyLocalEdit", { + workspacePath: root, + workbookId: uncached.meta.workbookId, + sheetId: uncached.meta.activeSheetId, + row: 0, + col: 0, + formula: "=1+1", + expectedRevision: 0, + }); + assert.throws( + () => engine.dispatch("exportCsv", { + workspacePath: root, + workbookId: uncached.meta.workbookId, + sheetId: uncached.meta.activeSheetId, + acknowledgeStaleFormulaValues: true, + expectedRevision: 1, + }), + /UNCACHED_FORMULA_CSV_BLOCKED/ + ); + }); + + await t.test("requires revisions at mutation boundaries and isolates reload sessions by workspace", (t) => { + const rootA = tempWorkspace(t, "excel-engine-workspace-a-"); + const rootB = tempWorkspace(t, "excel-engine-workspace-b-"); + const created = engine.dispatch("createWorkbook", { workspacePath: rootA, title: "Revision guard" }); + assert.throws( + () => engine.dispatch("applyLocalEdit", { + workspacePath: rootA, + workbookId: created.meta.workbookId, + sheetId: created.meta.activeSheetId, + row: 0, + col: 0, + value: 1, + }), + /EXPECTED_REVISION_REQUIRED/ + ); + + const sharedId = "shared_workspace_book"; + const sourceA = writeInstrumentedExcelSource(rootA, { withFormula: false }); + const sourceB = writeInstrumentedExcelSource(rootB, { withFormula: false }); + const workbookA = io.readWorkbookFile(sourceA, { workbookId: sharedId, title: "Workspace A" }); + const workbookB = io.readWorkbookFile(sourceB, { workbookId: sharedId, title: "Workspace B" }); + workbookA.title = "Workspace A"; + workbookB.title = "Workspace B"; + store.saveJson(rootA, workbookA); + store.saveJson(rootB, workbookB); + engine.sessions.clear(); + + assert.equal( + engine.dispatch("getMeta", { workspacePath: rootA, workbookId: sharedId }).meta.sourcePath, + sourceA + ); + const reloadedB = engine.dispatch("reloadWorkbook", { + workspacePath: rootB, + workbookId: sharedId, + expectedRevision: 0, + }); + assert.equal(reloadedB.meta.sourcePath, sourceB); + assert.equal(reloadedB.meta.title, "Workspace B"); + }); + + await t.test("separates Agent workspace paths from user-confirmed Product App exports", (t) => { + const root = tempWorkspace(t, "excel-engine-path-policy-"); + const outside = tempWorkspace(t, "excel-engine-path-outside-"); + const externalSource = writeInstrumentedExcelSource(outside, { withFormula: false }); + + assert.throws( + () => engine.dispatch("openWorkbook", { + workspacePath: root, + path: externalSource, + __trustedConsumerKind: "agentComponent", + }), + /WORKSPACE_PATH_REQUIRED/ + ); + const openedByUser = engine.dispatch("openWorkbook", { + workspacePath: root, + path: externalSource, + __trustedConsumerKind: "productAppRuntime", + }); + assert.equal(openedByUser.meta.sourcePath, externalSource); + + const created = engine.dispatch("createWorkbook", { workspacePath: root, title: "Export guard" }); + const target = path.join(root, "existing-unrelated.xlsx"); + fs.writeFileSync(target, "unrelated user file", "utf8"); + assert.throws( + () => engine.dispatch("saveWorkbook", { + workspacePath: root, + workbookId: created.meta.workbookId, + path: target, + exportCopy: true, + expectedRevision: 0, + __trustedConsumerKind: "productAppRuntime", + }), + /EXISTING_TARGET_OVERWRITE_BLOCKED/ + ); + assert.equal(fs.readFileSync(target, "utf8"), "unrelated user file"); + assert.throws( + () => engine.dispatch("saveWorkbook", { + workspacePath: root, + workbookId: created.meta.workbookId, + path: target, + exportCopy: true, + expectedRevision: 0, + overwriteExisting: true, + __trustedConsumerKind: "agentComponent", + }), + /EXISTING_TARGET_OVERWRITE_BLOCKED/ + ); + assert.throws( + () => engine.dispatch("saveWorkbook", { + workspacePath: root, + workbookId: created.meta.workbookId, + path: target, + exportCopy: true, + expectedRevision: 0, + overwriteExisting: true, + expectedTargetFingerprint: { + algorithm: "sha256", + hash: "0".repeat(64), + size: 0, + mtimeMs: 0, + }, + __trustedConsumerKind: "productAppRuntime", + }), + /EXPORT_TARGET_CHANGED/ + ); + + engine.dispatch("saveWorkbook", { + workspacePath: root, + workbookId: created.meta.workbookId, + path: target, + exportCopy: true, + expectedRevision: 0, + overwriteExisting: true, + __trustedConsumerKind: "productAppRuntime", + }); + const persisted = store.loadJson(root, created.meta.workbookId); + assert.equal(persisted.lastExportPath, target); + assert.equal(persisted.lastExportFingerprint.algorithm, "sha256"); + assert.notEqual(fs.readFileSync(target, "utf8"), "unrelated user file"); + }); + + await t.test("migrates old stores and leaves no temporary file after atomic replacement", (t) => { + const root = tempWorkspace(t, "excel-engine-store-"); + const old = { + workbookId: "wb_old", + path: path.join(root, "old.xlsx"), + title: "Old", + sheets: [{ id: "s1", name: "Sheet1", rows: 5, cols: 5, cells: {} }], + activeSheetId: "s1", + dirty: true, + focus: { sheetId: "s1", a1: "A1", kind: "cell" }, + proposal: null, + }; + const migrated = store.normalizeWorkbook(old); + assert.equal(migrated.schemaVersion, 2); + assert.equal(migrated.revision, 0); + assert.equal(migrated.mode, "edit"); + assert.equal(migrated.sourceFormat, "xlsx"); + store.saveJson(root, migrated); + store.saveJson(root, { ...migrated, title: "Old 2" }); + assert.deepEqual(fs.readdirSync(store.workbookDir(root, migrated.workbookId)), ["workbook.json"]); + assert.equal(store.loadJson(root, migrated.workbookId).title, "Old 2"); + }); +}); diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/test/worker-protocol.test.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/test/worker-protocol.test.js new file mode 100644 index 00000000..c444c634 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/test/worker-protocol.test.js @@ -0,0 +1,44 @@ +const assert = require("node:assert/strict"); +const fs = require("node:fs"); +const os = require("node:os"); +const path = require("node:path"); +const { execFileSync } = require("node:child_process"); +const test = require("node:test"); + +test("worker uses the host workspace and emits correlated daemon envelopes", (t) => { + const safeWorkspace = fs.mkdtempSync(path.join(os.tmpdir(), "excel-worker-safe-")); + const payloadWorkspace = fs.mkdtempSync(path.join(os.tmpdir(), "excel-worker-payload-")); + t.after(() => fs.rmSync(safeWorkspace, { recursive: true, force: true })); + t.after(() => fs.rmSync(payloadWorkspace, { recursive: true, force: true })); + + const workerPath = path.join(__dirname, "..", "worker.js"); + const request = { + bridgeId: "builtin-excel-runtime", + runId: "worker-contract-run", + action: "createWorkbook", + workspacePath: safeWorkspace, + input: { + workspacePath: payloadWorkspace, + title: "Host-bound workbook", + __trustedConsumerKind: "agentComponent", + }, + consumer: { kind: "productAppRuntime", id: "surface-test" }, + }; + const stdout = execFileSync(process.execPath, [workerPath], { + input: `${JSON.stringify(request)}\n`, + encoding: "utf8", + }); + const frames = stdout.trim().split(/\r?\n/).map((line) => JSON.parse(line)); + + assert.equal(frames.length, 2); + for (const frame of frames) { + assert.equal(frame.bridgeId, request.bridgeId); + assert.equal(frame.runId, request.runId); + assert.ok(frame.event && typeof frame.event.type === "string"); + } + assert.equal(frames[0].event.type, "run.started"); + assert.equal(frames[1].event.type, "run.completed"); + assert.equal(frames[1].event.output.meta.title, "Host-bound workbook"); + assert.equal(fs.existsSync(path.join(safeWorkspace, ".sparo_os", "excel-live")), true); + assert.equal(fs.existsSync(path.join(payloadWorkspace, ".sparo_os", "excel-live")), false); +}); diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/worker.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/worker.js new file mode 100644 index 00000000..ebd57754 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/bridges/builtin-excel-runtime/source/worker.js @@ -0,0 +1,98 @@ +const { emit } = require("./src/protocol"); +const { dispatch } = require("./src/engine"); + +/** + * Persistent daemon loop for the Sparo Excel Engine. + * + * Hosts that still send a single JSON blob and close stdin keep working: + * we process that one request and exit when stdin ends with no more lines. + * Daemon hosts send one NDJSON request per line and keep the process alive + * so workbook sessions stay warm across edits / agent tool calls. + */ +function handleRequest(request) { + const action = request.action; + const rawInput = request.input && typeof request.input === "object" && !Array.isArray(request.input) + ? request.input + : {}; + const consumer = request.consumer && typeof request.consumer === "object" + ? request.consumer + : {}; + const input = { + ...rawInput, + // The host envelope owns these values. A bridge action payload must not + // replace the workspace or consumer authority selected by the host. + workspacePath: request.workspacePath || request.workspace_path || null, + __trustedConsumerKind: consumer.kind || null, + }; + const runId = request.runId || request.run_id || `excel-${Date.now()}`; + const bridgeId = request.bridgeId || request.bridge_id || "builtin-excel-runtime"; + const emitEvent = (event) => emit({ bridgeId, runId, event }); + emitEvent({ type: "run.started", run_id: runId }); + try { + const output = dispatch(action, input); + emitEvent({ type: "run.completed", output }); + } catch (error) { + emitEvent({ + type: "run.failed", + error: { + message: error instanceof Error ? error.message : String(error), + }, + }); + } +} + +function main() { + let buffer = ""; + let sawRequest = false; + process.stdin.setEncoding("utf8"); + process.stdin.on("data", (chunk) => { + buffer += chunk; + let newline = buffer.indexOf("\n"); + while (newline >= 0) { + const line = buffer.slice(0, newline).trim(); + buffer = buffer.slice(newline + 1); + newline = buffer.indexOf("\n"); + if (!line) continue; + sawRequest = true; + let request; + try { + request = JSON.parse(line); + } catch (error) { + process.stderr.write( + `Invalid Bridge worker request: ${error instanceof Error ? error.message : String(error)}\n`, + ); + process.exit(1); + } + handleRequest(request); + } + }); + process.stdin.on("end", () => { + const leftover = buffer.trim(); + if (leftover) { + try { + sawRequest = true; + handleRequest(JSON.parse(leftover)); + } catch (error) { + process.stderr.write( + `Invalid Bridge worker request: ${error instanceof Error ? error.message : String(error)}\n`, + ); + process.exitCode = 1; + return; + } + } + // One-shot hosts close stdin after a single request; exit cleanly. + if (!sawRequest) { + process.stderr.write("No Bridge worker request received on stdin\n"); + process.exitCode = 1; + } + process.exit(process.exitCode || 0); + }); + process.stdin.on("error", (error) => { + process.stderr.write( + `Bridge worker stdin failed: ${error instanceof Error ? error.message : String(error)}\n`, + ); + process.exit(1); + }); +} + +main(); diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/component.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/component.json new file mode 100644 index 00000000..f37d43d0 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/component.json @@ -0,0 +1,81 @@ +{ + "id": "builtin-excel-live-surface", + "kind": "surface", + "name": "Excel Live Workbench", + "description": "The app-owned revisioned spreadsheet grid, grounded focus bar, proposal inspector, undo history, and source-safe export surface for Excel Live.", + "packageSource": "appPrivate", + "ownerApp": { + "appId": "builtin-excel-live", + "appVersion": "1.0.1" + }, + "capabilities": [ + { + "id": "interactiveSurface", + "title": "Interactive surface", + "description": "Hosts the Excel Live primary spreadsheet workbench.", + "actions": [ + "open", + "createWorkbook", + "saveWorkbook", + "exportCopy", + "setFocus", + "acceptProposal", + "rejectProposal", + "undo", + "redo", + "applyLocalPatch" + ] + } + ], + "permissions": [ + { + "kind": "fs", + "summary": "Reads and writes workbook files under the workspace via the Excel engine bridge.", + "scopes": [ + "{workspace}", + "{appdata}" + ] + } + ], + "usedByApps": [ + "builtin-excel-live" + ], + "visibility": "appDependency", + "dependencies": [ + { + "componentId": "excel-live-agent", + "kind": "agent", + "source": "private", + "role": "excelAgent", + "capabilities": [ + "inspectWorkbook", + "transformRange", + "authorWorkbook" + ] + }, + { + "componentId": "builtin-excel-runtime", + "kind": "bridge", + "source": "private", + "role": "excelEngine", + "capabilities": [ + "sparo.excelEngine" + ] + }, + { + "componentId": "product-app-runtime-host", + "kind": "runtime", + "source": "shared", + "role": "runtimeHost", + "version": "^1.0.0", + "capabilities": [ + "uiWorker" + ] + } + ], + "implementationRef": "app://builtin-excel-live@1.0.1/surfaces/builtin-excel-live-surface", + "usesCapabilities": [ + "session.read", + "component.run" + ] +} diff --git a/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/esm_dependencies.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/esm_dependencies.json similarity index 100% rename from bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/esm_dependencies.json rename to bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/esm_dependencies.json diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/index.html b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/index.html new file mode 100644 index 00000000..8cccbd9e --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/index.html @@ -0,0 +1,6 @@ +

+
+
+

Loading Excel Live...

+
+
diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/source_manifest.json b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/source_manifest.json new file mode 100644 index 00000000..05606755 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/source_manifest.json @@ -0,0 +1,6 @@ +{ + "uiEntry": "ui.js", + "workerEntry": "worker.js", + "styleEntries": ["style.css"], + "buildMode": "nativeEsm" +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/a1.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/a1.js new file mode 100644 index 00000000..3776346c --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/a1.js @@ -0,0 +1,106 @@ +function colToIndex(col) { + if (col == null || typeof col !== 'string' || !col.length) { + throw new Error('Column letter is required'); + } + const upper = col.toUpperCase(); + if (!/^[A-Z]+$/.test(upper)) { + throw new Error(`Invalid column letters: ${col}`); + } + let index = 0; + for (let i = 0; i < upper.length; i += 1) { + index = index * 26 + (upper.charCodeAt(i) - 64); + } + return index - 1; +} + +function indexToCol(index) { + if (!Number.isInteger(index) || index < 0) { + throw new Error(`Invalid column index: ${index}`); + } + let n = index + 1; + let col = ''; + while (n > 0) { + const rem = (n - 1) % 26; + col = String.fromCharCode(65 + rem) + col; + n = Math.floor((n - 1) / 26); + } + return col; +} + +function parseCellToken(token) { + const match = String(token || '') + .trim() + .toUpperCase() + .match(/^([A-Z]+)(\d+)$/); + if (!match) { + throw new Error(`Invalid A1 cell reference: ${token}`); + } + return { + c: colToIndex(match[1]), + r: Number(match[2]) - 1, + }; +} + +/** + * Parse an A1 range or cell. + * Accepts: "A1", "A1:B10", "Sheet1!A1:B2", "'My Sheet'!A1" + */ +function parseA1(ref) { + if (ref == null || String(ref).trim() === '') { + throw new Error('A1 reference is required'); + } + let raw = String(ref).trim(); + let sheet = null; + + const bang = raw.lastIndexOf('!'); + if (bang >= 0) { + sheet = raw.slice(0, bang).trim(); + raw = raw.slice(bang + 1).trim(); + if ( + (sheet.startsWith("'") && sheet.endsWith("'")) || + (sheet.startsWith('"') && sheet.endsWith('"')) + ) { + sheet = sheet.slice(1, -1).replace(/''/g, "'"); + } + } + + const parts = raw.split(':'); + if (parts.length === 1) { + const cell = parseCellToken(parts[0]); + return { sheet, r1: cell.r, c1: cell.c, r2: cell.r, c2: cell.c }; + } + if (parts.length !== 2) { + throw new Error(`Invalid A1 range: ${ref}`); + } + const a = parseCellToken(parts[0]); + const b = parseCellToken(parts[1]); + return { + sheet, + r1: Math.min(a.r, b.r), + c1: Math.min(a.c, b.c), + r2: Math.max(a.r, b.r), + c2: Math.max(a.c, b.c), + }; +} + +function formatA1(r1, c1, r2 = r1, c2 = c1) { + if ( + !Number.isInteger(r1) || + !Number.isInteger(c1) || + !Number.isInteger(r2) || + !Number.isInteger(c2) + ) { + throw new Error('formatA1 requires integer row/col indices'); + } + const top = Math.min(r1, r2); + const left = Math.min(c1, c2); + const bottom = Math.max(r1, r2); + const right = Math.max(c1, c2); + const start = `${indexToCol(left)}${top + 1}`; + if (top === bottom && left === right) { + return start; + } + return `${start}:${indexToCol(right)}${bottom + 1}`; +} + +export { colToIndex, formatA1, indexToCol, parseA1 }; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/actions.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/actions.js new file mode 100644 index 00000000..045c791b --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/actions.js @@ -0,0 +1,958 @@ +import { callExcel } from './backend.js'; +import { + commitModeToBackend, + pinFocus as pinFocusAction, + setFocusFromSelection, + syncFocusToHost, +} from './focus.js'; +import { + applyMeta, + activeSheet, + cellEditValue, + focusCacheCoverage, + mergeReadIntoCache, + normalizeFocusRange, +} from './model.js'; +import { acceptProposal, refreshProposal, rejectProposal } from './proposal.js'; +import { refreshViewportCells, resetScrollPosition, scrollToCell } from './grid.js'; +import { state, invalidateCells } from './state.js'; +import { formatA1 } from './a1.js'; +import { cellCacheKey, normalizePathForCompare, runtime } from './util.js'; +import { t } from './i18n.js'; +import { render } from './render.js'; +import { showToast, updateChrome } from './views.js'; +import { buildSelectionStyleCells, exportCopyPlan } from './interaction.js'; + +function setLoading(loading, status = null) { + state.loading = loading; + if (status != null) state.status = status; + updateChrome(); +} + +function setError(error) { + const message = error?.message || (typeof error === 'string' ? error : null); + if (message) showToast('error', message); +} + +function writeBoundaryBlocked() { + if (state.loading || state.dialogPending) { + setError(t('operationPending')); + return true; + } + if (state.modePending) { + setError(t('modeChangePending')); + return true; + } + if (state.mode === 'inspect') { + setError(t('inspectEditBlocked')); + return true; + } + return false; +} + +const MAX_FORMAT_PROPOSAL_CELLS = 5000; + +async function proposeSelectionFormat(change = {}) { + if (writeBoundaryBlocked() || !state.workbookId) return false; + if (state.mode === 'inspect') { + showToast('error', t('inspectEditBlocked')); + return false; + } + if (state.proposal) { + showToast('error', t('formatProposalExists')); + return false; + } + const sheet = activeSheet(); + const focus = normalizeFocusRange(state.focus, sheet); + if (!sheet) return false; + const cellCount = focus.rowCount * focus.columnCount; + if (cellCount > MAX_FORMAT_PROPOSAL_CELLS) { + showToast('error', t('formatRangeTooLarge', { count: MAX_FORMAT_PROPOSAL_CELLS })); + return false; + } + const styleRole = String(change.styleRole || '').trim() || null; + const style = change.style && typeof change.style === 'object' ? change.style : null; + if (!styleRole && !style) return false; + const cells = buildSelectionStyleCells(focus, { styleRole, style }, MAX_FORMAT_PROPOSAL_CELLS); + const intent = change.intent || t('formatIntent', { range: `${sheet.name}!${focus.a1}` }); + setLoading(true); + try { + const result = await callExcel('proposePatch', { + workbookId: state.workbookId, + sheetId: sheet.id, + expectedRevision: state.meta?.revision ?? undefined, + baseRevision: state.meta?.revision ?? undefined, + intent, + cells, + }); + if (result?.meta) applyMeta(result.meta); + await refreshProposal(); + if (!state.proposal) throw new Error(t('formatProposalMissing')); + state.status = t('formatProposalReady'); + render(); + return true; + } catch (error) { + showToast('error', error?.message || t('formatProposalFailed')); + return false; + } finally { + setLoading(false); + } +} + +function beginDialogBoundary() { + if (state.loading || state.dialogPending || state.modePending) { + setError(t(state.modePending ? 'modeChangePending' : 'operationPending')); + return false; + } + state.dialogPending = true; + updateChrome(); + return true; +} + +function endDialogBoundary() { + state.dialogPending = false; + updateChrome(); +} + +function samePath(a, b) { + if (!a || !b) return false; + return normalizePathForCompare(a) === normalizePathForCompare(b); +} + +function staleFormulaExportRisk(meta = state.meta) { + const calculation = meta?.calculationStatus; + if (calculation == null) return false; + const token = String( + typeof calculation === 'string' + ? calculation + : calculation.status || calculation.state || calculation.kind || '', + ).trim().toLowerCase().replaceAll('_', '-'); + const formulaCount = typeof calculation === 'object' + ? Number(calculation.formulaCount ?? calculation.formula_count) + : Number.NaN; + const hasFormulas = typeof calculation === 'object' && typeof calculation.hasFormulas === 'boolean' + ? calculation.hasFormulas + : Number.isFinite(formulaCount) + ? formulaCount > 0 + : !['current', 'not-required'].includes(token); + return hasFormulas && !['current', 'not-required'].includes(token); +} + +function applyHistory(result) { + const history = result?.history && typeof result.history === 'object' && !Array.isArray(result.history) + ? result.history + : result && typeof result === 'object' + ? result + : {}; + const entries = Array.isArray(history.entries) + ? history.entries + : Array.isArray(history.items) + ? history.items + : Array.isArray(result?.entries) + ? result.entries + : Array.isArray(result?.history) + ? result.history + : []; + state.history = { + canUndo: Boolean(history.canUndo ?? history.can_undo ?? entries.some((entry) => entry?.undoable !== false)), + canRedo: Boolean(history.canRedo ?? history.can_redo), + entries, + }; +} + +async function refreshHistory() { + if (!state.workbookId) { + applyHistory(null); + updateChrome(); + return state.history; + } + try { + const result = await callExcel('getHistory', { workbookId: state.workbookId }); + applyHistory(result); + } catch (_error) { + // History is an enhancement; an unavailable history endpoint must not + // block the workbook itself. + applyHistory(null); + } + updateChrome(); + return state.history; +} + +async function adoptWorkbookResult(result, statusKey, options = {}) { + const resultMeta = result?.meta; + const hasResultPath = resultMeta && ( + Object.prototype.hasOwnProperty.call(resultMeta, 'path') + || Object.prototype.hasOwnProperty.call(resultMeta, 'sourcePath') + ); + const meta = resultMeta && options.sourcePath && !hasResultPath + ? { ...resultMeta, path: options.sourcePath } + : resultMeta; + applyMeta(meta); + const persistedMode = state.mode; + const modeOverride = ['inspect', 'edit', 'author'].includes(options.modeOverride) + ? options.modeOverride + : null; + let modeOverrideCommitted = false; + if (modeOverride && modeOverride !== persistedMode) { + try { + await commitModeToBackend(modeOverride); + state.mode = modeOverride; + modeOverrideCommitted = true; + } catch (_error) { + state.mode = persistedMode; + showToast('error', t('modeSwitchFailed', { mode: t(`mode${persistedMode[0].toUpperCase()}${persistedMode.slice(1)}`) })); + } + } + if (result?.meta?.focus) { + state.focus = normalizeFocusRange(result.meta.focus); + } else if (!state.focus?.a1) { + setFocusFromSelection(0, 0, 0, 0, { sync: false }); + } + invalidateCells(); + resetScrollPosition(); + if (options.seedViewport && result?.viewport) { + mergeReadIntoCache(result.viewport); + } + await refreshProposal(); + await refreshViewportCells(); + await refreshHistory(); + syncFocusToHost({ force: true, broadcast: !modeOverrideCommitted }); + state.status = t(statusKey); + render(); +} + +async function createWorkbook(options = {}) { + if (state.loading || state.dialogPending) { + setError(t('operationPending')); + return; + } + if (state.modePending) { + setError(t('modeChangePending')); + return; + } + if (!state.workspacePath) { + setError(t('noWorkspace')); + return; + } + setLoading(true, t('loading')); + try { + const result = await callExcel('createWorkbook', { + title: options.title || t('untitled'), + rows: options.rows, + cols: options.cols, + sheetName: options.sheetName, + }); + await adoptWorkbookResult(result, 'statusCreated', { + seedViewport: true, + modeOverride: 'author', + }); + } catch (error) { + setError(error?.message || t('createFailed')); + } finally { + setLoading(false); + } +} + +async function openWorkbookAtPath(filePath, options = {}) { + if (state.loading || (state.dialogPending && options.fromDialog !== true)) { + setError(t('operationPending')); + return; + } + if (state.modePending) { + setError(t('modeChangePending')); + return; + } + if (!state.workspacePath) { + setError(t('noWorkspace')); + return; + } + if (!filePath) return; + if (state.workbookId && samePath(state.path, filePath)) return; + setLoading(true, t('loading')); + try { + const result = await callExcel('openWorkbook', { path: filePath }); + await adoptWorkbookResult(result, 'statusOpened', { + seedViewport: true, + sourcePath: filePath, + }); + } catch (error) { + setError(error?.message || t('openFailed')); + } finally { + setLoading(false); + } +} + +async function resumeWorkbookById(workbookId, statusKey = 'statusResumed') { + setLoading(true, t('loading')); + try { + const result = await callExcel('getMeta', { workbookId }); + if (!result?.meta) return false; + await adoptWorkbookResult(result, statusKey); + return true; + } catch (_error) { + return false; + } finally { + setLoading(false); + } +} + +async function resumeLatestWorkbook() { + try { + const list = await callExcel('listWorkbooks', {}); + const newest = Array.isArray(list?.workbooks) ? list.workbooks[0] : null; + if (!newest?.workbookId) return false; + return await resumeWorkbookById(newest.workbookId); + } catch (_error) { + return false; + } +} + +async function openFile() { + if (!beginDialogBoundary()) return; + const host = runtime(); + if (!host.dialog?.open) { + setError('dialog.open unavailable'); + endDialogBoundary(); + return; + } + try { + const selected = await host.dialog.open({ + title: t('openDialogTitle'), + multiple: false, + filters: [ + { name: 'Excel', extensions: ['xlsx', 'xlsm', 'csv'] }, + ], + }); + const path = Array.isArray(selected) ? selected[0] : selected; + if (!path) return; + await openWorkbookAtPath(path, { fromDialog: true }); + } catch (error) { + setError(error?.message || t('openFailed')); + } finally { + endDialogBoundary(); + } +} + +async function saveWorkbook() { + if (!state.workbookId) return; + if (!beginDialogBoundary()) return; + try { + const host = runtime(); + const sourcePath = state.path || state.meta?.path || null; + if (!host.dialog?.save) { + setError(t('exportCopyDialogMissing')); + return; + } + const fidelity = state.meta?.fidelity; + const exportPlan = exportCopyPlan(sourcePath, fidelity); + const { + macroEnabled, + acknowledgeFidelityLoss, + lossyMacroRebuild, + extension, + } = exportPlan; + const fidelityPrompt = lossyMacroRebuild + ? t('fidelityXlsmToXlsxConfirm') + : t('fidelityExportConfirm'); + if (acknowledgeFidelityLoss && !window.confirm(fidelityPrompt)) { + state.status = t('statusExportCancelled'); + updateChrome(); + return; + } + const safeTitle = String(state.meta?.title || 'workbook') + .replace(/\.(xlsx|xlsm|csv)$/i, '') + .replace(/[\\/:*?"<>|]+/g, '-'); + const targetPath = await host.dialog.save({ + title: t('saveDialogTitle'), + defaultPath: `${safeTitle}-copy.${extension}`, + filters: [{ name: extension === 'xlsm' ? t('excelMacroFile') : 'Excel', extensions: [extension] }], + }); + if (!targetPath) return; + if (sourcePath && samePath(sourcePath, targetPath)) { + setError(t('exportCopySourceBlocked')); + return; + } + if (!String(targetPath).toLowerCase().endsWith(`.${extension}`)) { + setError(t(extension === 'xlsm' ? 'exportCopyMacroExtension' : 'exportCopyXlsxExtension')); + return; + } + setLoading(true); + try { + const result = await callExcel('saveWorkbook', { + workbookId: state.workbookId, + path: targetPath, + exportCopy: true, + expectedRevision: state.meta?.revision ?? undefined, + acknowledgeFidelityLoss, + // The native save dialog is the explicit user confirmation boundary. + // The engine still fingerprints an existing target and rechecks it + // immediately before the atomic replacement. + overwriteExisting: true, + }); + applyMeta(result?.meta); + // Exporting a copy must never retarget the live workbook to the new path. + state.path = sourcePath; + if (state.meta) state.meta = { ...state.meta, path: sourcePath }; + state.status = t('statusExportedCopy'); + } catch (error) { + const message = String(error?.message || ''); + if (message.includes('LOSSY_XLSM_BLOCKED')) { + setError(t('exportCopyMacroStructureBlocked')); + } else if (message.includes('FIDELITY_ACK_REQUIRED')) { + setError(t('exportCopyFidelityAckRequired')); + } else { + setError(message || t('saveFailed')); + } + } finally { + setLoading(false); + } + } finally { + endDialogBoundary(); + } +} + +async function exportCsv() { + if (!state.workbookId) return; + if (!beginDialogBoundary()) return; + try { + const host = runtime(); + if (!host.dialog?.save) { + setError(t('exportCopyDialogMissing')); + return; + } + const acknowledgeStaleFormulaValues = staleFormulaExportRisk(); + if (acknowledgeStaleFormulaValues && !window.confirm(t('staleFormulaCsvConfirm'))) { + state.status = t('statusExportCancelled'); + updateChrome(); + return; + } + const outPath = await host.dialog.save({ + title: t('exportDialogTitle'), + defaultPath: `${state.meta?.title || 'sheet'}-copy.csv`, + filters: [{ name: 'CSV', extensions: ['csv'] }], + }); + if (!outPath) return; + if (state.path && samePath(state.path, outPath)) { + setError(t('exportCopySourceBlocked')); + return; + } + setLoading(true); + try { + const result = await callExcel('exportCsv', { + workbookId: state.workbookId, + sheetId: state.activeSheetId, + path: outPath || undefined, + expectedRevision: state.meta?.revision ?? undefined, + acknowledgeStaleFormulaValues, + overwriteExisting: true, + }); + const sanitizedCellCount = Number( + result?.sanitizedCellCount + ?? result?.sanitized_cell_count + ?? result?.warning?.sanitizedCellCount + ?? 0, + ); + state.status = sanitizedCellCount > 0 + ? t('statusExportedSanitized', { count: sanitizedCellCount }) + : t('statusExported'); + } catch (error) { + const message = String(error?.message || ''); + setError( + message.includes('UNCACHED_FORMULA_CSV_BLOCKED') + ? t('uncachedFormulaCsvBlocked') + : message.includes('STALE_FORMULA_VALUES_ACK_REQUIRED') + ? t('staleFormulaCsvAckRequired') + : message || t('exportFailed'), + ); + } finally { + setLoading(false); + } + } finally { + endDialogBoundary(); + } +} + +async function switchSheet(sheetId) { + if (!state.workbookId || !sheetId || sheetId === state.activeSheetId) return; + if (state.loading || state.dialogPending) { + setError(t('operationPending')); + return; + } + if (state.modePending) { + setError(t('modeChangePending')); + return; + } + // Optimistic UI: switch tabs immediately, then hydrate from the engine. + // Avoid a full-screen loading bar for a single sheet change. + const previousSheetId = state.activeSheetId; + setLoading(true); + state.activeSheetId = sheetId; + state.lastSheetTabsKey = null; + invalidateCells(); + resetScrollPosition(); + setFocusFromSelection(0, 0, 0, 0, { sync: false }); + render(); + try { + const result = await callExcel('switchSheet', { + workbookId: state.workbookId, + sheetId, + }); + applyMeta(result?.meta); + if (result?.viewport) mergeReadIntoCache(result.viewport); + await refreshProposal(); + await refreshViewportCells(); + syncFocusToHost({ force: true, broadcast: true }); + } catch (error) { + state.activeSheetId = previousSheetId; + state.lastSheetTabsKey = null; + setError(error?.message || t('switchFailed')); + } finally { + setLoading(false); + render(); + } +} + +async function addSheet() { + if (!state.workbookId) return; + if (writeBoundaryBlocked()) return; + setLoading(true); + try { + const result = await callExcel('addSheet', { + workbookId: state.workbookId, + expectedRevision: state.meta?.revision ?? undefined, + }); + applyMeta(result?.meta); + invalidateCells(); + resetScrollPosition(); + await refreshProposal(); + await refreshViewportCells(); + await refreshHistory(); + syncFocusToHost({ force: true }); + } catch (error) { + setError(error?.message || t('addSheetFailed')); + } finally { + setLoading(false); + render(); + } +} + +async function askAboutFocus() { + const sheet = activeSheet(); + const focus = normalizeFocusRange(state.focus); + const prompt = t('askPrompt', { + sheet: sheet?.name || 'Sheet', + a1: focus.a1, + title: state.meta?.title || t('untitled'), + }); + syncFocusToHost({ force: true }); + const host = runtime(); + if (typeof host.host?.fillChatInput === 'function') { + await host.host.fillChatInput(prompt); + } else if (typeof host.fillChatInput === 'function') { + await host.fillChatInput(prompt); + } + state.status = t('statusAsked'); + updateChrome(); +} + +async function insertRow() { + if (!state.workbookId) return; + if (writeBoundaryBlocked()) return; + const focus = normalizeFocusRange(state.focus); + setLoading(true); + try { + const result = await callExcel('insertRows', { + workbookId: state.workbookId, + sheetId: state.activeSheetId, + at: focus.r1, + count: 1, + expectedRevision: state.meta?.revision ?? undefined, + }); + applyMeta(result?.meta); + invalidateCells(); + await refreshProposal(); + await refreshViewportCells(); + await refreshHistory(); + } catch (error) { + setError(error?.message || t('insertFailed')); + } finally { + setLoading(false); + } + render(); +} + +async function insertColumn() { + if (!state.workbookId) return; + if (writeBoundaryBlocked()) return; + const focus = normalizeFocusRange(state.focus); + setLoading(true); + try { + const result = await callExcel('insertColumns', { + workbookId: state.workbookId, + sheetId: state.activeSheetId, + at: focus.c1, + count: 1, + expectedRevision: state.meta?.revision ?? undefined, + }); + applyMeta(result?.meta); + invalidateCells(); + await refreshProposal(); + await refreshViewportCells(); + await refreshHistory(); + } catch (error) { + setError(error?.message || t('insertFailed')); + } finally { + setLoading(false); + } + render(); +} + +async function pinFocus() { + try { + await pinFocusAction(); + } catch (error) { + setError(error?.message || String(error)); + } + updateChrome(); +} + +async function acceptProposalAction() { + const accepted = await acceptProposal(); + if (accepted) await refreshHistory(); + render(); +} + +async function rejectProposalAction() { + const rejected = await rejectProposal(); + if (rejected) await refreshHistory(); + render(); +} + +async function jumpToProposal() { + const proposal = state.proposal; + if (!proposal?.a1) return; + try { + if (proposal.sheetId && proposal.sheetId !== state.activeSheetId) { + await switchSheet(proposal.sheetId); + } + const focus = normalizeFocusRange({ a1: proposal.a1, sheetId: proposal.sheetId }); + setFocusFromSelection(focus.r1, focus.c1, focus.r2, focus.c2, { + kind: focus.kind, + force: true, + }); + scrollToCell(focus.r1, focus.c1); + } catch (_error) { + // Ignore malformed proposal ranges. + } +} + +const MAX_CLIPBOARD_CELLS = 20000; + +function encodeTsvCell(value) { + const text = String(value ?? ''); + if (!/[\t\r\n"]/.test(text)) return text; + return `"${text.replaceAll('"', '""')}"`; +} + +function parseTsv(text) { + const rows = []; + let row = []; + let value = ''; + let quoted = false; + const source = String(text ?? ''); + for (let index = 0; index < source.length; index += 1) { + const char = source[index]; + if (quoted) { + if (char === '"' && source[index + 1] === '"') { + value += '"'; + index += 1; + } else if (char === '"') { + quoted = false; + } else { + value += char; + } + continue; + } + if (char === '"' && value === '') { + quoted = true; + } else if (char === '\t') { + row.push(value); + value = ''; + } else if (char === '\n' || char === '\r') { + if (char === '\r' && source[index + 1] === '\n') index += 1; + row.push(value); + rows.push(row); + row = []; + value = ''; + } else { + value += char; + } + } + row.push(value); + rows.push(row); + while (rows.length > 1 && rows.at(-1)?.length === 1 && rows.at(-1)?.[0] === '') { + rows.pop(); + } + return rows; +} + +async function writeClipboardText(text) { + const host = runtime(); + if (typeof host.clipboard?.writeText === 'function') { + await host.clipboard.writeText(text); + return; + } + if (navigator.clipboard?.writeText) { + await navigator.clipboard.writeText(text); + return; + } + throw new Error(t('clipboardUnavailable')); +} + +async function readClipboardText() { + const host = runtime(); + if (typeof host.clipboard?.readText === 'function') { + return host.clipboard.readText(); + } + if (navigator.clipboard?.readText) { + return navigator.clipboard.readText(); + } + throw new Error(t('clipboardUnavailable')); +} + +async function hydrateFocusForClipboard(focus, sheet) { + const total = focus.rowCount * focus.columnCount; + if (total > MAX_CLIPBOARD_CELLS) { + throw new Error(t('clipboardRangeTooLarge', { count: MAX_CLIPBOARD_CELLS })); + } + let coverage = focusCacheCoverage(focus, sheet); + if (coverage.complete) return; + const result = await callExcel('readRange', { + workbookId: state.workbookId, + sheetId: sheet.id, + a1: focus.a1, + maxCells: total, + }); + mergeReadIntoCache(result); + coverage = focusCacheCoverage(focus, sheet); + if (!coverage.complete) throw new Error(t('clipboardRangeIncomplete')); +} + +async function copySelection() { + if (!state.workbookId) return; + if (state.loading || state.dialogPending || state.modePending) { + setError(t(state.modePending ? 'modeChangePending' : 'operationPending')); + return; + } + const sheet = activeSheet(); + if (!sheet) return; + const focus = normalizeFocusRange(state.focus, sheet); + setLoading(true, t('copying')); + try { + await hydrateFocusForClipboard(focus, sheet); + const rows = []; + for (let row = focus.r1; row <= focus.r2; row += 1) { + const values = []; + for (let col = focus.c1; col <= focus.c2; col += 1) { + const cell = state.cells.get(cellCacheKey(sheet.id, row, col)); + values.push(encodeTsvCell(cellEditValue(cell))); + } + rows.push(values.join('\t')); + } + await writeClipboardText(rows.join('\r\n')); + state.status = t('statusCopied', { count: focus.rowCount * focus.columnCount }); + updateChrome(); + } catch (error) { + setError(error?.message || t('copyFailed')); + } finally { + setLoading(false); + } +} + +async function pasteSelection() { + if (!state.workbookId) return; + if (writeBoundaryBlocked()) return; + const sheet = activeSheet(); + if (!sheet) return; + const focus = normalizeFocusRange(state.focus, sheet); + try { + const text = await readClipboardText(); + if (!String(text || '').length) return; + const values = parseTsv(text); + const width = values.reduce((max, row) => Math.max(max, row.length), 0); + const cellCount = values.length * width; + if (cellCount > MAX_CLIPBOARD_CELLS) { + throw new Error(t('clipboardRangeTooLarge', { count: MAX_CLIPBOARD_CELLS })); + } + const endRow = focus.r1 + values.length - 1; + const endCol = focus.c1 + Math.max(0, width - 1); + setLoading(true, t('pasting')); + const result = await callExcel('applyLocalPatch', { + workbookId: state.workbookId, + sheetId: sheet.id, + a1: formatA1(focus.r1, focus.c1, endRow, endCol), + values, + baseRevision: state.meta?.revision ?? undefined, + expectedRevision: state.meta?.revision ?? undefined, + }); + applyMeta(result?.meta); + invalidateCells(); + if (result?.viewport) mergeReadIntoCache(result.viewport); + await refreshProposal(); + await refreshViewportCells(); + await refreshHistory(); + setFocusFromSelection(focus.r1, focus.c1, endRow, endCol, { force: true }); + syncFocusToHost({ force: true, broadcast: true }); + state.status = t('statusPasted', { count: cellCount }); + render(); + } catch (error) { + setError(error?.message || t('pasteFailed')); + } finally { + setLoading(false); + } +} + +async function applyHistoryAction(action, statusKey) { + if (!state.workbookId || state.loading) return; + if (writeBoundaryBlocked()) return; + const allowed = action === 'undo' ? state.history.canUndo : state.history.canRedo; + if (!allowed) return; + setLoading(true); + try { + const result = await callExcel(action, { + workbookId: state.workbookId, + revision: state.meta?.revision ?? undefined, + expectedRevision: state.meta?.revision ?? undefined, + }); + applyMeta(result?.meta); + invalidateCells(); + if (result?.viewport) mergeReadIntoCache(result.viewport); + await refreshProposal(); + await refreshViewportCells(); + await refreshHistory(); + syncFocusToHost({ force: true, broadcast: true }); + state.status = t(statusKey); + render(); + } catch (error) { + setError(error?.message || t(action === 'undo' ? 'undoFailed' : 'redoFailed')); + } finally { + setLoading(false); + } +} + +async function undoWorkbook() { + return applyHistoryAction('undo', 'statusUndone'); +} + +async function redoWorkbook() { + return applyHistoryAction('redo', 'statusRedone'); +} + +async function ensureWorkbook(payload = {}) { + if (!state.workspacePath) { + state.bootDone = true; + setError(t('noWorkspace')); + render(); + return; + } + const launchPath = + payload.path || + payload.workbookPath || + payload.filePath || + payload.launchPath || + payload.workbench?.path || + state.pendingLaunchPath || + null; + state.pendingLaunchPath = null; + + try { + if (launchPath) { + await openWorkbookAtPath(launchPath); + return; + } + if (state.workbookId) return; + const resumed = await resumeLatestWorkbook(); + if (!resumed && !state.workbookId) { + await createWorkbook(); + } + } finally { + state.bootDone = true; + render(); + } +} + +/** + * Refresh surface state after the chat agent touched the workbook through + * the shared Excel engine (proposals, edits, sheet or workbook changes). + */ +async function refreshFromEngine(targetWorkbookId = null) { + if (!state.workspacePath) return; + if (state.editing || state.editCommitPromise) { + state.pendingAgentRefresh = { targetWorkbookId }; + return; + } + if (state.loading || state.dialogPending || state.modePending) { + if (state.agentRefreshTimer) clearTimeout(state.agentRefreshTimer); + state.agentRefreshTimer = setTimeout(() => { + state.agentRefreshTimer = null; + void refreshFromEngine(targetWorkbookId); + }, 400); + return; + } + setLoading(true); + try { + const target = typeof targetWorkbookId === 'string' ? targetWorkbookId.trim() : ''; + if (state.workbookId) { + if (target && target !== state.workbookId) { + return; + } + } else if (target) { + await resumeWorkbookById(target, 'statusAgentUpdated'); + return; + } else { + // Tool completion without an explicit workbook id is not a safe basis + // for rebinding when multiple Excel Live instances share a workspace. + return; + } + const metaResult = await callExcel('getMeta', { workbookId: state.workbookId }); + applyMeta(metaResult?.meta); + await refreshProposal(); + await refreshHistory(); + invalidateCells(); + await refreshViewportCells(); + state.status = t('statusAgentUpdated'); + render(); + } catch (_error) { + // Agent refresh is best-effort; the next user action re-syncs anyway. + } finally { + setLoading(false); + } +} + +export { + acceptProposalAction, + addSheet, + askAboutFocus, + copySelection, + createWorkbook, + ensureWorkbook, + exportCsv, + insertColumn, + insertRow, + jumpToProposal, + openFile, + openWorkbookAtPath, + pasteSelection, + pinFocus, + proposeSelectionFormat, + refreshFromEngine, + refreshHistory, + redoWorkbook, + rejectProposalAction, + resumeLatestWorkbook, + saveWorkbook, + setError, + setLoading, + switchSheet, + undoWorkbook, +}; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/backend.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/backend.js new file mode 100644 index 00000000..d901e961 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/backend.js @@ -0,0 +1,47 @@ +import { state } from './state.js'; +import { bridgeOutput, runtime, uid } from './util.js'; +import { t } from './i18n.js'; + +async function callExcel(action, input = {}) { + const host = runtime(); + if (!host.backend?.call) throw new Error(t('backendMissing')); + + const workspacePath = input.workspacePath || state.workspacePath; + if (!workspacePath) throw new Error(t('noWorkspace')); + + const payload = { + workspacePath, + ...input, + }; + if (!payload.workbookId && state.workbookId) { + payload.workbookId = state.workbookId; + } + + const result = await host.backend.call( + `excelEngine.${action}`, + payload, + { + entityId: payload.workbookId || workspacePath || 'default', + idempotencyKey: `excel-live-${action}-${uid('idem')}`, + }, + ); + + if (result?.bridgeResult) return bridgeOutput(result); + if (!result?.actionRunId || !host.backend?.status) return bridgeOutput(result); + + const startedAt = Date.now(); + while (Date.now() - startedAt < 60000) { + const status = await host.backend.status(result.actionRunId, { + sessionId: result.sessionId, + turnId: result.turnId, + }); + if (status?.status === 'completed') return bridgeOutput(status); + if (status?.status === 'failed' || status?.status === 'cancelled') { + throw new Error(status?.message || status?.stderr || status?.status); + } + await new Promise((resolve) => setTimeout(resolve, 400)); + } + throw new Error(`Backend action timed out: ${action}`); +} + +export { callExcel }; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/focus.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/focus.js new file mode 100644 index 00000000..df342c01 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/focus.js @@ -0,0 +1,171 @@ +import { callExcel } from './backend.js'; +import { formatA1 } from './a1.js'; +import { buildFocusPayload, normalizeFocusRange } from './model.js'; +import { state } from './state.js'; +import { runtime } from './util.js'; +import { t } from './i18n.js'; + +const FOCUS_HOST_DEBOUNCE_MS = 120; +const FOCUS_BACKEND_DEBOUNCE_MS = 900; + +function focusSyncKey(payload) { + return [ + payload.workbookId || '', + payload.sheetId || '', + payload.a1 || '', + payload.selectionKind || '', + payload.role || 'ambient', + payload.includeFocusOnSend ? '1' : '0', + payload.mode || 'edit', + payload.revision ?? '', + payload.cacheComplete ? '1' : '0', + payload.cacheCoverage ?? 0, + payload.previewTsv || '', + ].join('|'); +} + +async function broadcastFocusToBackend() { + if (!state.workbookId || !state.workspacePath) return; + if (state.modePending) return; + // Skip while the user is still dragging a selection — each bridge call + // currently spawns a Node process and would freeze the grid. + if (state.selectionDragging) return; + const focus = normalizeFocusRange(state.focus); + try { + await callExcel('setFocus', { + workbookId: state.workbookId, + sheetId: focus.sheetId, + a1: focus.a1, + kind: focus.kind, + mode: state.mode, + revision: state.meta?.revision ?? null, + }); + } catch (_error) { + // Ambient focus sync is best-effort; UI selection still works without it. + } +} + +async function commitModeToBackend(mode) { + if (!state.workbookId || !state.workspacePath) { + throw new Error(t('modeUnavailable')); + } + if (!['inspect', 'edit', 'author'].includes(mode)) { + throw new Error(t('modeUnavailable')); + } + // A queued ambient sync may still carry the previous mode. Cancel it before + // committing this explicit execution boundary so it cannot race and undo the + // user's choice after the confirmed write returns. + if (state.focusSyncTimer) { + clearTimeout(state.focusSyncTimer); + state.focusSyncTimer = null; + } + const focus = normalizeFocusRange(state.focus); + return callExcel('setFocus', { + workbookId: state.workbookId, + sheetId: focus.sheetId, + a1: focus.a1, + kind: focus.kind, + mode, + revision: state.meta?.revision ?? null, + }); +} + +function syncFocusToHost(options = {}) { + const role = options.role || 'ambient'; + const payload = buildFocusPayload(role); + const key = focusSyncKey(payload); + if (!options.force && key === state.lastFocusSyncKey && role === 'ambient') { + return payload; + } + state.lastFocusSyncKey = key; + + const host = runtime(); + if (typeof host.host?.syncSpreadsheetFocus === 'function') { + void host.host.syncSpreadsheetFocus(payload); + } else if (typeof host.syncSpreadsheetFocus === 'function') { + void host.syncSpreadsheetFocus(payload); + } + + // Host ambient context is cheap; backend setFocus is expensive. Default to + // host-only sync for selection changes and only push to the engine when + // explicitly requested (pin / ask / settled selection). + if (options.broadcast === true) { + void broadcastFocusToBackend(); + } + return payload; +} + +function scheduleFocusSync(options = {}) { + if (state.focusSyncTimer) { + clearTimeout(state.focusSyncTimer); + } + const delay = options.immediate + ? 0 + : (options.broadcast === true ? FOCUS_BACKEND_DEBOUNCE_MS : FOCUS_HOST_DEBOUNCE_MS); + state.focusSyncTimer = setTimeout(() => { + state.focusSyncTimer = null; + // Default: host-only ambient sync. Backend setFocus is expensive (fresh + // Node process per call) and is reserved for settled selection / pin. + syncFocusToHost(options); + }, delay); +} + +function setFocusFromSelection(r1, c1, r2 = r1, c2 = c1, options = {}) { + const next = normalizeFocusRange({ + sheetId: state.activeSheetId, + r1, + c1, + r2, + c2, + kind: options.kind || (r1 === r2 && c1 === c2 ? 'cell' : 'range'), + }); + state.focus = next; + if (options.sync !== false) { + scheduleFocusSync({ force: Boolean(options.force) }); + } + return next; +} + +async function pinFocus() { + const payload = syncFocusToHost({ role: 'pinned', force: true, broadcast: true }); + const host = runtime(); + const marker = t('pinMarker', { + sheet: payload.sheetName || 'Sheet', + a1: payload.a1, + }); + + if (typeof host.host?.addContext === 'function') { + await host.host.addContext({ + ...payload, + role: 'pinned', + label: `${payload.sheetName || 'Sheet'}!${payload.a1}`, + }); + } else if (typeof host.addContext === 'function') { + await host.addContext({ + ...payload, + role: 'pinned', + label: `${payload.sheetName || 'Sheet'}!${payload.a1}`, + }); + } else if (typeof host.host?.fillChatInput === 'function') { + await host.host.fillChatInput(marker); + } else if (typeof host.fillChatInput === 'function') { + await host.fillChatInput(marker); + } + + state.status = t('statusPinned'); + return payload; +} + +function activeCellA1() { + const focus = normalizeFocusRange(state.focus); + return formatA1(focus.r1, focus.c1); +} + +export { + activeCellA1, + commitModeToBackend, + pinFocus, + scheduleFocusSync, + setFocusFromSelection, + syncFocusToHost, +}; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/formatting.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/formatting.js new file mode 100644 index 00000000..fc5fb532 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/formatting.js @@ -0,0 +1,458 @@ +import { colToIndex } from './a1.js'; + +const LIVE_VIEW_SEMANTICS = 'values-formulas-styles-layout'; + +const STYLE_ROLE_FALLBACKS = Object.freeze({ + title: { + fill: { color: '#17365D' }, + font: { bold: true, color: '#FFFFFF', size: 14 }, + alignment: { vertical: 'middle' }, + }, + header: { + fill: { color: '#1F4E78' }, + font: { bold: true, color: '#FFFFFF' }, + border: { bottom: { style: 'thin', color: '#17365D' } }, + alignment: { vertical: 'middle', wrapText: true }, + }, + total: { + font: { bold: true }, + border: { top: { style: 'double', color: '#1F1F1F' } }, + }, + input: { + fill: { color: '#FFF2CC' }, + border: { bottom: { style: 'thin', color: '#D6B656' } }, + }, + output: { + fill: { color: '#DDEBF7' }, + font: { color: '#17365D' }, + }, + note: { + font: { italic: true, color: '#666666' }, + alignment: { wrapText: true }, + }, + warning: { + fill: { color: '#FCE4D6' }, + font: { bold: true, color: '#C00000' }, + }, +}); + +const ALIGNMENTS = new Set(['left', 'center', 'right', 'justify', 'general']); +const VERTICAL_ALIGNMENTS = new Set(['top', 'middle', 'bottom']); +const BORDER_STYLES = new Set(['hair', 'thin', 'medium', 'thick', 'double', 'dashed', 'dotted']); + +function asObject(value) { + return value && typeof value === 'object' && !Array.isArray(value) ? value : {}; +} + +function normalizeStyleRole(value) { + const role = String(value || '').trim().toLowerCase().replaceAll('_', '-'); + return Object.prototype.hasOwnProperty.call(STYLE_ROLE_FALLBACKS, role) ? role : ''; +} + +function normalizeColor(value) { + let candidate = value; + if (candidate && typeof candidate === 'object') { + candidate = candidate.color ?? candidate.rgb ?? candidate.argb ?? candidate.value; + } + let token = String(candidate || '').trim().replace(/^#/, ''); + if (/^[0-9a-f]{8}$/i.test(token)) token = token.slice(2); + if (/^[0-9a-f]{3}$/i.test(token)) token = token.split('').map((part) => `${part}${part}`).join(''); + return /^[0-9a-f]{6}$/i.test(token) ? `#${token.toUpperCase()}` : null; +} + +function normalizeBorderSide(value) { + if (!value) return null; + const source = typeof value === 'string' ? { style: value } : asObject(value); + let style = String(source.style || source.lineStyle || 'thin').trim().toLowerCase(); + if (!BORDER_STYLES.has(style)) style = 'thin'; + const color = normalizeColor(source.color) || '#AEB5BE'; + return { style, color }; +} + +function mergeStyle(base, override) { + const left = asObject(base); + const right = asObject(override); + return { + ...left, + ...right, + fill: { ...asObject(left.fill), ...asObject(right.fill) }, + font: { ...asObject(left.font), ...asObject(right.font) }, + border: { ...asObject(left.border), ...asObject(right.border) }, + alignment: { ...asObject(left.alignment), ...asObject(right.alignment) }, + }; +} + +function normalizeCellStyle(styleLike, fallbackRole = '') { + const source = asObject(styleLike); + const role = normalizeStyleRole(source.role || fallbackRole); + const merged = mergeStyle(role ? STYLE_ROLE_FALLBACKS[role] : {}, source); + const fillColor = normalizeColor(merged.fill?.color ?? merged.fill); + const fontColor = normalizeColor(merged.font?.color); + const fontSizeValue = Number(merged.font?.size); + const horizontal = String(merged.alignment?.horizontal || '').trim().toLowerCase(); + let vertical = String(merged.alignment?.vertical || '').trim().toLowerCase(); + if (vertical === 'center') vertical = 'middle'; + const border = {}; + for (const side of ['top', 'right', 'bottom', 'left']) { + const normalized = normalizeBorderSide(merged.border?.[side]); + if (normalized) border[side] = normalized; + } + const numberFormat = typeof merged.numberFormat === 'string' + ? merged.numberFormat.trim().slice(0, 120) + : ''; + return { + role: role || null, + fill: fillColor ? { color: fillColor } : null, + font: { + bold: merged.font?.bold === true, + italic: merged.font?.italic === true, + color: fontColor, + size: Number.isFinite(fontSizeValue) ? Math.min(72, Math.max(6, fontSizeValue)) : null, + }, + border, + alignment: { + horizontal: ALIGNMENTS.has(horizontal) ? horizontal : null, + vertical: VERTICAL_ALIGNMENTS.has(vertical) ? vertical : null, + wrapText: merged.alignment?.wrapText === true, + }, + numberFormat: numberFormat || null, + }; +} + +function cellStyle(cell) { + if (!cell || typeof cell !== 'object') return normalizeCellStyle(null); + const style = asObject(cell.style); + return normalizeCellStyle(style, cell.styleRole || cell.role); +} + +function borderCss(side) { + if (!side) return null; + const widths = { hair: 1, thin: 1, medium: 2, thick: 3, double: 3, dashed: 1, dotted: 1 }; + const cssStyle = side.style === 'double' + ? 'double' + : side.style === 'dashed' + ? 'dashed' + : side.style === 'dotted' || side.style === 'hair' + ? 'dotted' + : 'solid'; + return `${widths[side.style] || 1}px ${cssStyle} ${side.color}`; +} + +function styleToCss(styleLike, fallbackRole = '') { + const style = normalizeCellStyle(styleLike, fallbackRole); + const declarations = []; + if (style.fill?.color) declarations.push(`background-color:${style.fill.color}`); + if (style.font.color) declarations.push(`color:${style.font.color}`); + if (style.font.bold) declarations.push('font-weight:700'); + if (style.font.italic) declarations.push('font-style:italic'); + // Excel font sizes are points; CSS uses px at the standard 96 dpi scale. + if (style.font.size) declarations.push(`font-size:${Math.round(style.font.size * 96 / 72 * 100) / 100}px`); + if (style.alignment.horizontal && style.alignment.horizontal !== 'general') { + declarations.push(`text-align:${style.alignment.horizontal}`); + declarations.push(`justify-content:${style.alignment.horizontal === 'center' ? 'center' : style.alignment.horizontal === 'right' ? 'flex-end' : 'flex-start'}`); + } + if (style.alignment.vertical) { + const alignItems = style.alignment.vertical === 'middle' + ? 'center' + : style.alignment.vertical === 'top' + ? 'flex-start' + : 'flex-end'; + declarations.push(`align-items:${alignItems}`); + } + if (style.alignment.wrapText) declarations.push('white-space:normal'); + for (const side of ['top', 'right', 'bottom', 'left']) { + const value = borderCss(style.border[side]); + if (value) declarations.push(`border-${side}:${value}`); + } + return declarations.join(';'); +} + +function decimalPlaces(format, marker = '.') { + const escapedMarker = marker.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + const match = String(format || '').match(new RegExp(`${escapedMarker}(0+)`)); + return match ? match[1].length : 0; +} + +function formatValueWithNumberFormat(value, format) { + if (typeof value !== 'number' || !Number.isFinite(value) || !format) return value == null ? '' : String(value); + const token = String(format).trim(); + if (!token || /^general$/i.test(token)) return String(value); + const firstSection = token.split(';')[0]; + // Basic 1900-date-system preview only. Locale calendars, time zones, and + // alternate Excel date systems remain fidelity metadata concerns. + if (/y{2,4}[-/]m{1,2}[-/]d{1,2}/i.test(firstSection)) { + const serialDay = Math.floor(value); + // Excel intentionally preserves Lotus 1-2-3's fictitious leap day. + if (serialDay === 60) return '1900-02-29'; + const adjustedDay = serialDay >= 60 ? serialDay - 1 : serialDay; + const date = new Date(Date.UTC(1899, 11, 31) + adjustedDay * 86400000); + if (!Number.isNaN(date.getTime())) { + const year = String(date.getUTCFullYear()).padStart(4, '0'); + const month = String(date.getUTCMonth() + 1).padStart(2, '0'); + const day = String(date.getUTCDate()).padStart(2, '0'); + return `${year}-${month}-${day}`; + } + } + const fractionDigits = decimalPlaces(firstSection); + if (firstSection.includes('%')) { + return `${(value * 100).toLocaleString(undefined, { minimumFractionDigits: fractionDigits, maximumFractionDigits: fractionDigits })}%`; + } + const currency = firstSection.match(/[$¥¥€£]/)?.[0] || ''; + const useGrouping = firstSection.includes(','); + const formatted = value.toLocaleString(undefined, { + useGrouping, + minimumFractionDigits: fractionDigits, + maximumFractionDigits: fractionDigits, + }); + return currency ? `${currency}${formatted}` : formatted; +} + +function cellDisplayWithStyle(cell) { + if (!cell) return ''; + if (cell.v != null) return formatValueWithNumberFormat(cell.v, cellStyle(cell).numberFormat); + const formula = cell.f ?? cell.formula; + return formula ? `=${String(formula).replace(/^=/, '')}` : ''; +} + +function snapshotParts(snapshot) { + if (!snapshot) return { primary: '', secondary: '', formula: '', value: '' }; + const formulaValue = snapshot.f ?? snapshot.formula; + const formula = formulaValue ? `=${String(formulaValue).replace(/^=/, '')}` : ''; + const value = snapshot.v ?? snapshot.value; + const displayValue = value == null ? '' : formatValueWithNumberFormat(value, cellStyle(snapshot).numberFormat); + return { + primary: formula || displayValue, + secondary: formula && displayValue ? displayValue : '', + formula, + value: displayValue, + }; +} + +function styleSignature(style) { + return JSON.stringify(normalizeCellStyle(style)); +} + +function styleDifferences(before, after) { + const left = cellStyle(before); + const right = cellStyle(after); + if (styleSignature(left) === styleSignature(right)) return []; + const diffs = []; + const push = (key, beforeValue, afterValue) => { + if (JSON.stringify(beforeValue ?? null) !== JSON.stringify(afterValue ?? null)) { + diffs.push({ key, before: beforeValue ?? null, after: afterValue ?? null }); + } + }; + push('role', left.role, right.role); + push('fill', left.fill?.color, right.fill?.color); + push('font', left.font, right.font); + push('border', left.border, right.border); + push('alignment', left.alignment, right.alignment); + push('numberFormat', left.numberFormat, right.numberFormat); + return diffs; +} + +function messageText(value) { + if (typeof value === 'string') return value.trim(); + if (!value || typeof value !== 'object') return String(value ?? '').trim(); + return String(value.message || value.text || value.description || value.code || '').trim(); +} + +function asMessages(value) { + if (!Array.isArray(value)) return []; + return value.map(messageText).filter(Boolean); +} + +function proposalValidationDetails(proposal) { + const validation = proposal?.validation; + const errors = []; + const warnings = []; + let status = ''; + let explicitlyInvalid = validation === false; + if (typeof validation === 'string') status = validation; + if (Array.isArray(validation)) warnings.push(...asMessages(validation)); + if (validation && typeof validation === 'object' && !Array.isArray(validation)) { + status = String(validation.status || validation.state || '').trim().toLowerCase(); + explicitlyInvalid = validation.valid === false || validation.invalid === true; + errors.push(...asMessages(validation.errors)); + warnings.push(...asMessages(validation.warnings)); + const formulaLint = validation.formulaLint || proposal?.formulaLint; + if (formulaLint && typeof formulaLint === 'object') { + errors.push(...asMessages(formulaLint.errors)); + warnings.push(...asMessages(formulaLint.warnings)); + for (const finding of formulaLint.findings || []) { + const text = messageText(finding); + if (!text) continue; + const severity = String(finding?.severity || finding?.level || '').toLowerCase(); + if (severity === 'error' || severity === 'fatal') errors.push(text); + else warnings.push(text); + } + } + } + const invalidStatus = ['invalid', 'failed', 'error', 'blocked'].includes(status); + return { + status, + errors: [...new Set(errors)], + warnings: [...new Set(warnings)], + invalid: explicitlyInvalid || invalidStatus || errors.length > 0, + }; +} + +function normalizeAxisIndex(value, kind) { + if (Number.isInteger(Number(value))) return Math.max(0, Number(value)); + if (kind === 'column' && typeof value === 'string') { + try { + return colToIndex(value); + } catch (_error) { + return 0; + } + } + return 0; +} + +function normalizeLayoutRanges(entries, kind) { + if (!Array.isArray(entries)) return []; + return entries.map((entry) => { + const source = asObject(entry); + const start = normalizeAxisIndex(source.start ?? source.index ?? source[`${kind}Start`] ?? source[`${kind}Index`], kind); + const end = normalizeAxisIndex(source.end ?? source.index ?? source[`${kind}End`] ?? source[`${kind}Index`] ?? start, kind); + const explicitPixels = Number(source[kind === 'column' ? 'widthPx' : 'heightPx']); + const sourceValue = Number(source[kind === 'column' ? 'width' : 'height']); + // Engine/XLSX contract: column width is Excel character units and row + // height is points. Convert only for presentation; retain the source value + // so proposal details remain meaningful in workbook units. + const convertedSize = Number.isFinite(explicitPixels) + ? explicitPixels + : Number.isFinite(sourceValue) + ? kind === 'column' + ? excelColumnWidthToPixels(sourceValue) + : excelRowHeightToPixels(sourceValue) + : NaN; + const min = kind === 'column' ? 12 : 1; + const max = kind === 'column' ? excelColumnWidthToPixels(255) : excelRowHeightToPixels(409); + return { + start: Math.min(start, end), + end: Math.max(start, end), + size: Number.isFinite(convertedSize) ? Math.min(max, Math.max(min, convertedSize)) : null, + value: Number.isFinite(sourceValue) ? sourceValue : null, + unit: kind === 'column' ? 'excelCharacters' : 'points', + autoFit: source.autoFit === true, + }; + }).filter((entry) => entry.size != null || entry.autoFit); +} + +function excelColumnWidthToPixels(width) { + const value = Math.min(255, Math.max(0, Number(width) || 0)); + return Math.floor(value * 7 + 5); +} + +function excelRowHeightToPixels(height) { + const value = Math.min(409, Math.max(0, Number(height) || 0)); + return Math.round(value * 96 / 72 * 100) / 100; +} + +function normalizeSheetLayout(layoutLike) { + const layout = asObject(layoutLike); + const freeze = asObject(layout.freezePanes || layout.freeze || layout.frozenPanes); + const filter = layout.autoFilter; + return { + columns: normalizeLayoutRanges(layout.columns || layout.columnWidths, 'column'), + rows: normalizeLayoutRanges(layout.rows || layout.rowHeights, 'row'), + freezePanes: { + rows: Math.max(0, Number(freeze.rows ?? freeze.rowCount ?? freeze.frozenRows) || 0), + columns: Math.max(0, Number(freeze.columns ?? freeze.columnCount ?? freeze.frozenColumns) || 0), + }, + autoFilter: typeof filter === 'string' + ? { a1: filter } + : filter && typeof filter === 'object' + ? { a1: String(filter.a1 || filter.range || '').trim() || null } + : null, + }; +} + +function proposalLayoutStates(proposal) { + const layout = proposal?.layout; + if (!layout || typeof layout !== 'object') return null; + const hasEnvelope = Object.prototype.hasOwnProperty.call(layout, 'before') + || Object.prototype.hasOwnProperty.call(layout, 'after'); + return { + before: normalizeSheetLayout(hasEnvelope ? layout.before : null), + after: normalizeSheetLayout(hasEnvelope ? layout.after : layout), + }; +} + +function proposalHasLayoutChanges(proposal) { + const states = proposalLayoutStates(proposal); + return Boolean(states && JSON.stringify(states.before) !== JSON.stringify(states.after)); +} + +function axisSizeAt(index, entries, defaultSize, autoFitSize = defaultSize) { + let size = defaultSize; + for (const entry of entries || []) { + if (index < entry.start || index > entry.end) continue; + size = entry.size ?? (entry.autoFit ? autoFitSize : defaultSize); + } + return size; +} + +function axisOffset(index, entries, defaultSize, autoFitSize = defaultSize) { + const target = Math.max(0, Number(index) || 0); + let offset = target * defaultSize; + for (const entry of entries || []) { + const coveredStart = Math.max(0, entry.start); + const coveredEnd = Math.min(target - 1, entry.end); + if (coveredEnd < coveredStart) continue; + const count = coveredEnd - coveredStart + 1; + const size = entry.size ?? (entry.autoFit ? autoFitSize : defaultSize); + offset += count * (size - defaultSize); + } + return offset; +} + +function axisIndexAtOffset(offset, count, entries, defaultSize, autoFitSize = defaultSize) { + const safeCount = Math.max(1, Number(count) || 1); + const target = Math.max(0, Number(offset) || 0); + let low = 0; + let high = safeCount - 1; + while (low < high) { + const mid = Math.floor((low + high + 1) / 2); + if (axisOffset(mid, entries, defaultSize, autoFitSize) <= target) low = mid; + else high = mid - 1; + } + return low; +} + +function layoutDifferences(proposal) { + const states = proposalLayoutStates(proposal); + if (!states) return []; + const diffs = []; + for (const key of ['columns', 'rows', 'freezePanes', 'autoFilter']) { + if (JSON.stringify(states.before[key]) !== JSON.stringify(states.after[key])) { + diffs.push({ key, before: states.before[key], after: states.after[key] }); + } + } + return diffs; +} + +export { + LIVE_VIEW_SEMANTICS, + STYLE_ROLE_FALLBACKS, + axisIndexAtOffset, + axisOffset, + axisSizeAt, + cellDisplayWithStyle, + cellStyle, + excelColumnWidthToPixels, + excelRowHeightToPixels, + formatValueWithNumberFormat, + normalizeCellStyle, + normalizeColor, + normalizeSheetLayout, + normalizeStyleRole, + layoutDifferences, + proposalHasLayoutChanges, + proposalLayoutStates, + proposalValidationDetails, + snapshotParts, + styleDifferences, + styleToCss, +}; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/grid.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/grid.js new file mode 100644 index 00000000..120350df --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/grid.js @@ -0,0 +1,1258 @@ +import { formatA1, indexToCol, parseA1 } from './a1.js'; +import { callExcel } from './backend.js'; +import { scheduleFocusSync, setFocusFromSelection } from './focus.js'; +import { + activeSheet, + cellDisplayValue, + cellEditValue, + mergeReadIntoCache, + normalizeFocusRange, + proposalAfterDisplay, + proposalBeforeDisplay, + proposalCellSet, + sheetBounds, +} from './model.js'; +import { + axisIndexAtOffset, + axisOffset, + axisSizeAt, + cellStyle, + normalizeSheetLayout, + proposalLayoutStates, + styleDifferences, + styleToCss, +} from './formatting.js'; +import { + createEditingDraft, + editingExpectedRevision, + gridSelectionNeedsEditCommit, + isComposingKey, + isSaveShortcut, +} from './interaction.js'; +import { state } from './state.js'; +import { cellCacheKey, clamp, closestElement, rootElement } from './util.js'; +import { t } from './i18n.js'; +import { showToast, updateChrome, updateSelectionStats } from './views.js'; + +const HEADER_H = 26; +const ROW_H = 26; +const COL_W = 100; +const ROW_HEADER_W = 46; +const OVERSCAN_ROWS = 6; +const OVERSCAN_COLS = 3; +const TILE_ROWS = 40; +const TILE_COLS = 12; +const MAX_FETCH_CELLS = 4000; +const AUTOFIT_COL_W = 140; +const AUTOFIT_ROW_H = 32; + +let domBound = false; +let gridResizeObserver = null; +let resizeRafPending = false; +let lastObservedGridSize = null; +let deferredGridSelection = null; + +function sheetLayout(sheet = activeSheet()) { + if (!sheet?.id) return normalizeSheetLayout(null); + const proposalSheetId = state.proposal?.sheetId || state.activeSheetId; + const proposalLayout = proposalSheetId === sheet.id ? proposalLayoutStates(state.proposal) : null; + if (proposalLayout) return proposalLayout.after; + return state.sheetLayouts.get(sheet.id) || normalizeSheetLayout(sheet.layout); +} + +function columnLeft(col, layout = sheetLayout()) { + return axisOffset(col, layout.columns, COL_W, AUTOFIT_COL_W); +} + +function columnWidth(col, layout = sheetLayout()) { + return axisSizeAt(col, layout.columns, COL_W, AUTOFIT_COL_W); +} + +function rowTop(row, layout = sheetLayout()) { + return axisOffset(row, layout.rows, ROW_H, AUTOFIT_ROW_H); +} + +function rowHeight(row, layout = sheetLayout()) { + return axisSizeAt(row, layout.rows, ROW_H, AUTOFIT_ROW_H); +} + +function indexSet(start, end, frozenCount = 0) { + const values = new Set(); + for (let index = 0; index < frozenCount; index += 1) values.add(index); + for (let index = start; index <= end; index += 1) values.add(index); + return [...values].sort((a, b) => a - b); +} + +function q(selector) { + return rootElement()?.querySelector(selector) || null; +} + +function cellDomId(sheetId, row, col) { + const safeSheet = String(sheetId || 'sheet').replace(/[^a-zA-Z0-9_-]/g, '-'); + return `el-cell-${safeSheet}-${row}-${col}`; +} + +function rowHeaderDomId(sheetId, row) { + const safeSheet = String(sheetId || 'sheet').replace(/[^a-zA-Z0-9_-]/g, '-'); + return `el-row-header-${safeSheet}-${row}`; +} + +function scrollHost() { + return q('[data-grid-scroll]'); +} + +/* ---------------------------------------------------------------- layout */ + +function layoutGrid() { + const sheet = activeSheet(); + const host = scrollHost(); + if (!sheet || !host) return; + const bounds = sheetBounds(sheet); + const layout = sheetLayout(sheet); + const gridWidth = columnLeft(bounds.cols, layout); + const gridHeight = rowTop(bounds.rows, layout); + + const corner = q('[data-grid-corner]'); + const colHeaders = q('[data-col-headers]'); + const rowHeaders = q('[data-row-headers]'); + const body = q('[data-grid-body]'); + if (corner) { + corner.style.width = `${ROW_HEADER_W}px`; + corner.style.height = `${HEADER_H}px`; + } + if (colHeaders) { + colHeaders.style.width = `${gridWidth}px`; + colHeaders.style.height = `${HEADER_H}px`; + } + if (rowHeaders) { + rowHeaders.style.width = `${ROW_HEADER_W}px`; + rowHeaders.style.height = `${gridHeight}px`; + } + if (body) { + body.style.width = `${gridWidth}px`; + body.style.height = `${gridHeight}px`; + body.classList.toggle('has-custom-layout', layout.columns.length > 0 || layout.rows.length > 0); + body.dataset.freezeRows = String(layout.freezePanes.rows || 0); + body.dataset.freezeColumns = String(layout.freezePanes.columns || 0); + } +} + +function measureViewport() { + const host = scrollHost(); + if (!host) return; + const height = host.clientHeight || 480; + const width = host.clientWidth || 800; + const layout = sheetLayout(); + const smallestRow = Math.min(ROW_H, ...layout.rows.map((entry) => entry.size ?? AUTOFIT_ROW_H)); + const smallestCol = Math.min(COL_W, ...layout.columns.map((entry) => entry.size ?? AUTOFIT_COL_W)); + state.viewport.visibleRows = Math.min(200, Math.max(8, Math.ceil((height - HEADER_H) / smallestRow) + 2)); + state.viewport.visibleCols = Math.min(50, Math.max(4, Math.ceil((width - ROW_HEADER_W) / smallestCol) + 2)); +} + +function renderWindow() { + const sheet = activeSheet(); + if (!sheet) return null; + const bounds = sheetBounds(sheet); + const { scrollRow, scrollCol, visibleRows, visibleCols } = state.viewport; + return { + sheet, + bounds, + r1: Math.max(0, scrollRow - OVERSCAN_ROWS), + c1: Math.max(0, scrollCol - OVERSCAN_COLS), + r2: Math.min(bounds.rows - 1, scrollRow + visibleRows - 1 + OVERSCAN_ROWS), + c2: Math.min(bounds.cols - 1, scrollCol + visibleCols - 1 + OVERSCAN_COLS), + }; +} + +/* ---------------------------------------------------------------- render */ + +function escapeText(value) { + return String(value ?? '') + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('"', '"'); +} + +function renderGridBody(force = false) { + const win = renderWindow(); + const cells = q('[data-grid-cells]'); + const colHeader = q('[data-col-headers]'); + const rowHeader = q('[data-row-headers]'); + if (!win || !cells || !colHeader || !rowHeader) return; + + const windowKey = `${win.sheet.id}:${win.r1}:${win.c1}:${win.r2}:${win.c2}`; + if (!force && windowKey === state.lastRenderedWindow) { + updateOverlays(); + return; + } + state.lastRenderedWindow = windowKey; + + const focus = normalizeFocusRange(state.focus, win.sheet); + const layout = sheetLayout(win.sheet); + const host = scrollHost(); + const freezeRows = Math.min(win.bounds.rows, state.viewport.visibleRows, layout.freezePanes.rows || 0); + const freezeCols = Math.min(win.bounds.cols, state.viewport.visibleCols, layout.freezePanes.columns || 0); + const rows = indexSet(win.r1, win.r2, freezeRows); + const cols = indexSet(win.c1, win.c2, freezeCols); + const customGrid = layout.columns.length > 0 || layout.rows.length > 0; + let filterRange = null; + if (layout.autoFilter?.a1) { + try { + filterRange = parseA1(layout.autoFilter.a1); + } catch (_error) { + filterRange = null; + } + } + let colHtml = ''; + for (const c of cols) { + const frozen = c < freezeCols; + const filtered = filterRange && c >= filterRange.c1 && c <= filterRange.c2; + const translate = frozen ? `transform:translateX(${host?.scrollLeft || 0}px);` : ''; + colHtml += `
${indexToCol(c)}${filtered ? `⌄` : ''}
`; + } + colHeader.innerHTML = colHtml; + + let rowHtml = ''; + for (const r of rows) { + const frozen = r < freezeRows; + const translate = frozen ? `transform:translateY(${host?.scrollTop || 0}px);` : ''; + rowHtml += `
${r + 1}
`; + } + rowHeader.innerHTML = rowHtml; + + const proposals = proposalCellSet(); + let html = ''; + for (const r of rows) { + const frozenRow = r < freezeRows; + let rowCells = ''; + for (const c of cols) { + const cell = state.cells.get(cellCacheKey(win.sheet.id, r, c)); + const proposal = proposals.get(`${r},${c}`); + const isActive = r === focus.r1 && c === focus.c1; + const isSelected = r >= focus.r1 && r <= focus.r2 && c >= focus.c1 && c <= focus.c2; + if (!cell && !proposal && !isActive && !customGrid) continue; + const display = cellDisplayValue(cell); + const beforeDisplay = proposal ? (display || proposalBeforeDisplay(proposal)) : display; + const classes = ['el-grid__cell']; + if (typeof cell?.v === 'number') classes.push('is-num'); + if (cell?.f || cell?.formulaEvidence) classes.push('is-formula'); + if (proposal) classes.push('is-proposal'); + const presentationCell = proposal?.after || cell; + const presentationStyle = cellStyle(presentationCell); + if (presentationStyle.role) classes.push(`is-style-${presentationStyle.role}`); + if (proposal && styleDifferences(proposal.before, proposal.after).length > 0) { + classes.push('has-style-change'); + } + const frozenCol = c < freezeCols; + if (frozenRow) classes.push('is-frozen-row'); + if (frozenCol) classes.push('is-frozen-column'); + if (freezeRows > 0 && r === freezeRows - 1) classes.push('is-freeze-row-edge'); + if (freezeCols > 0 && c === freezeCols - 1) classes.push('is-freeze-column-edge'); + const domId = cellDomId(win.sheet.id, r, c); + const a1 = formatA1(r, c); + const proposalLabel = proposal + ? `${t('proposalCellAria', { cell: a1, before: beforeDisplay || t('emptyValue'), after: proposalAfterDisplay(proposal) || t('emptyValue') })}` + : `${a1}: ${display || t('emptyValue')}`; + const cellCss = styleToCss(presentationCell?.style, presentationCell?.styleRole || presentationCell?.role); + const translateX = frozenCol ? `transform:translateX(${host?.scrollLeft || 0}px);` : ''; + rowCells += `
`; + if (proposal) { + const after = proposalAfterDisplay(proposal); + if (beforeDisplay) { + rowCells += `${escapeText(beforeDisplay)}`; + } + rowCells += `${escapeText(after)}`; + } else { + rowCells += `${escapeText(display)}`; + } + rowCells += '
'; + } + const translateY = frozenRow ? `transform:translateY(${host?.scrollTop || 0}px);` : ''; + html += `
${rowCells}
`; + } + cells.innerHTML = html; + updateOverlays(); +} + +function updateOverlays() { + const selBox = q('[data-selection-box]'); + const activeBox = q('[data-active-box]'); + if (!selBox || !activeBox) return; + const sheet = activeSheet(); + if (!sheet || !state.workbookId) { + selBox.hidden = true; + activeBox.hidden = true; + return; + } + const focus = normalizeFocusRange(state.focus, sheet); + const layout = sheetLayout(sheet); + const host = scrollHost(); + const grid = q('[data-grid-wrap]'); + if (grid) { + const bounds = sheetBounds(sheet); + grid.setAttribute('aria-rowcount', String(bounds.rows + 1)); + grid.setAttribute('aria-colcount', String(bounds.cols)); + grid.setAttribute('aria-activedescendant', 'el-grid-active-cell'); + grid.setAttribute('aria-busy', state.loading || state.dialogPending || state.modePending ? 'true' : 'false'); + } + const activeProxy = q('[data-active-gridcell]'); + if (activeProxy) { + const activeCell = state.cells.get(cellCacheKey(sheet.id, focus.r1, focus.c1)); + const value = cellDisplayValue(activeCell) || t('emptyValue'); + const proposal = proposalCellSet().get(`${focus.r1},${focus.c1}`); + const label = proposal + ? t('proposalCellAria', { + cell: formatA1(focus.r1, focus.c1), + before: proposalBeforeDisplay(proposal) || value, + after: proposalAfterDisplay(proposal) || t('emptyValue'), + }) + : `${formatA1(focus.r1, focus.c1)}: ${value}`; + activeProxy.setAttribute('aria-colindex', String(focus.c1 + 1)); + activeProxy.setAttribute('aria-label', label); + } + const activeProxyRow = q('[data-active-grid-row]'); + if (activeProxyRow) activeProxyRow.setAttribute('aria-rowindex', String(focus.r1 + 2)); + q('[data-grid-cells]')?.querySelectorAll('[role="gridcell"]').forEach((cellNode) => { + const row = Number(cellNode.dataset.row); + const col = Number(cellNode.dataset.col); + const selected = row >= focus.r1 && row <= focus.r2 && col >= focus.c1 && col <= focus.c2; + cellNode.setAttribute('aria-selected', selected ? 'true' : 'false'); + }); + const announcer = q('[data-grid-announcer]'); + if (announcer) { + announcer.textContent = t('selectionAnnouncement', { + sheet: sheet.name || '', + a1: focus.a1, + rows: focus.rowCount, + cols: focus.columnCount, + }); + } + + selBox.hidden = focus.rowCount === 1 && focus.columnCount === 1; + selBox.style.left = `${columnLeft(focus.c1, layout)}px`; + selBox.style.top = `${rowTop(focus.r1, layout)}px`; + selBox.style.width = `${columnLeft(focus.c2 + 1, layout) - columnLeft(focus.c1, layout)}px`; + selBox.style.height = `${rowTop(focus.r2 + 1, layout) - rowTop(focus.r1, layout)}px`; + selBox.style.transform = `translate(${focus.c2 < layout.freezePanes.columns ? host?.scrollLeft || 0 : 0}px, ${focus.r2 < layout.freezePanes.rows ? host?.scrollTop || 0 : 0}px)`; + + activeBox.hidden = false; + activeBox.style.left = `${columnLeft(focus.c1, layout)}px`; + activeBox.style.top = `${rowTop(focus.r1, layout)}px`; + activeBox.style.width = `${columnWidth(focus.c1, layout)}px`; + activeBox.style.height = `${rowHeight(focus.r1, layout)}px`; + activeBox.style.transform = `translate(${focus.c1 < layout.freezePanes.columns ? host?.scrollLeft || 0 : 0}px, ${focus.r1 < layout.freezePanes.rows ? host?.scrollTop || 0 : 0}px)`; + + updateNameBox(); + updateFormulaBar(); + updateSelectionStats(); + syncEditOverlay(); +} + +function updateFrozenTransforms() { + const host = scrollHost(); + if (!host) return; + q('[data-col-headers]')?.querySelectorAll('[data-freeze-x]').forEach((node) => { + node.style.transform = `translateX(${host.scrollLeft}px)`; + }); + q('[data-row-headers]')?.querySelectorAll('[data-freeze-y]').forEach((node) => { + node.style.transform = `translateY(${host.scrollTop}px)`; + }); + q('[data-grid-cells]')?.querySelectorAll('[data-freeze-x]').forEach((node) => { + node.style.transform = `translateX(${host.scrollLeft}px)`; + }); + q('[data-grid-cells]')?.querySelectorAll('[data-freeze-y]').forEach((node) => { + node.style.transform = `translateY(${host.scrollTop}px)`; + }); +} + +function updateNameBox() { + const input = q('[data-namebox]'); + if (!input || document.activeElement === input) return; + const focus = normalizeFocusRange(state.focus); + input.value = focus.a1; +} + +function updateFormulaBar() { + const input = q('[data-formula-input]'); + if (!input || document.activeElement === input) return; + if (state.editing) { + input.value = state.editing.value; + return; + } + const focus = normalizeFocusRange(state.focus); + const sheet = activeSheet(); + if (!sheet) { + input.value = ''; + return; + } + const cell = state.cells.get(cellCacheKey(sheet.id, focus.r1, focus.c1)); + input.value = cellEditValue(cell); +} + +/* ----------------------------------------------------------- data fetch */ + +function tilesForWindow(win) { + const tiles = []; + const tr1 = Math.floor(win.r1 / TILE_ROWS); + const tr2 = Math.floor(win.r2 / TILE_ROWS); + const tc1 = Math.floor(win.c1 / TILE_COLS); + const tc2 = Math.floor(win.c2 / TILE_COLS); + for (let tr = tr1; tr <= tr2; tr += 1) { + for (let tc = tc1; tc <= tc2; tc += 1) { + tiles.push({ tr, tc, key: `${win.sheet.id}:${tr}:${tc}` }); + } + } + return tiles; +} + +async function refreshViewportCells() { + const win = renderWindow(); + if (!win || !state.workbookId) return; + const sheet = win.sheet; + const bounds = win.bounds; + + if (state.fetchedTiles.has(`${sheet.id}:all`)) return; + + // Small sheets fit in one read; fetch everything once and stop refetching. + if (bounds.rows * bounds.cols <= MAX_FETCH_CELLS) { + const a1 = formatA1(0, 0, bounds.rows - 1, bounds.cols - 1); + const result = await callExcel('readRange', { + workbookId: state.workbookId, + sheetId: sheet.id, + a1, + maxCells: MAX_FETCH_CELLS, + }); + mergeReadIntoCache(result); + state.fetchedTiles.add(`${sheet.id}:all`); + return; + } + + const missing = tilesForWindow(win).filter((tile) => !state.fetchedTiles.has(tile.key)); + if (missing.length === 0) return; + + let r1 = Infinity; + let c1 = Infinity; + let r2 = -Infinity; + let c2 = -Infinity; + for (const tile of missing) { + r1 = Math.min(r1, tile.tr * TILE_ROWS); + c1 = Math.min(c1, tile.tc * TILE_COLS); + r2 = Math.max(r2, tile.tr * TILE_ROWS + TILE_ROWS - 1); + c2 = Math.max(c2, tile.tc * TILE_COLS + TILE_COLS - 1); + } + r1 = Math.max(0, r1); + c1 = Math.max(0, c1); + r2 = Math.min(bounds.rows - 1, r2); + c2 = Math.min(bounds.cols - 1, c2); + if ((r2 - r1 + 1) * (c2 - c1 + 1) > MAX_FETCH_CELLS) { + r1 = win.r1; + c1 = win.c1; + r2 = win.r2; + c2 = win.c2; + } + + const result = await callExcel('readRange', { + workbookId: state.workbookId, + sheetId: sheet.id, + a1: formatA1(r1, c1, r2, c2), + maxCells: MAX_FETCH_CELLS, + }); + mergeReadIntoCache(result); + + for (const tile of missing) { + const tileR2 = tile.tr * TILE_ROWS + TILE_ROWS - 1; + const tileC2 = tile.tc * TILE_COLS + TILE_COLS - 1; + if (tile.tr * TILE_ROWS >= r1 && Math.min(tileR2, bounds.rows - 1) <= r2 + && tile.tc * TILE_COLS >= c1 && Math.min(tileC2, bounds.cols - 1) <= c2) { + state.fetchedTiles.add(tile.key); + } + } +} + +function scheduleViewportFetch() { + if (state.viewportFetchTimer) clearTimeout(state.viewportFetchTimer); + state.viewportFetchTimer = setTimeout(() => { + state.viewportFetchTimer = null; + void refreshViewportCells() + .then(() => { + layoutGrid(); + measureViewport(); + renderGridBody(true); + // Refresh ambient context after hydration so an earlier + // cache-incomplete focus is replaced by a grounded preview. + scheduleFocusSync({ force: true, immediate: true, broadcast: false }); + }) + .catch((error) => { + showToast('error', error?.message || String(error)); + }); + }, 120); +} + +/* ------------------------------------------------------------ scrolling */ + +function scrollToCell(row, col) { + const host = scrollHost(); + if (!host) return; + const viewTop = host.scrollTop; + const viewLeft = host.scrollLeft; + const viewH = host.clientHeight - HEADER_H; + const viewW = host.clientWidth - ROW_HEADER_W; + const layout = sheetLayout(); + const cellTop = rowTop(row, layout); + const cellLeft = columnLeft(col, layout); + const cellH = rowHeight(row, layout); + const cellW = columnWidth(col, layout); + + let nextTop = viewTop; + let nextLeft = viewLeft; + if (cellTop < viewTop) nextTop = cellTop; + else if (cellTop + cellH > viewTop + viewH) nextTop = cellTop + cellH - viewH; + if (cellLeft < viewLeft) nextLeft = cellLeft; + else if (cellLeft + cellW > viewLeft + viewW) nextLeft = cellLeft + cellW - viewW; + + if (nextTop !== viewTop || nextLeft !== viewLeft) { + host.scrollTo({ top: Math.max(0, nextTop), left: Math.max(0, nextLeft) }); + } +} + +let scrollRafPending = false; + +function applyScrollPosition() { + const host = scrollHost(); + const sheet = activeSheet(); + if (!host || !sheet) return; + const bounds = sheetBounds(sheet); + const layout = sheetLayout(sheet); + const nextRow = clamp(axisIndexAtOffset(host.scrollTop, bounds.rows, layout.rows, ROW_H, AUTOFIT_ROW_H), 0, Math.max(0, bounds.rows - 1)); + const nextCol = clamp(axisIndexAtOffset(host.scrollLeft, bounds.cols, layout.columns, COL_W, AUTOFIT_COL_W), 0, Math.max(0, bounds.cols - 1)); + updateFrozenTransforms(); + updateOverlays(); + if (nextRow === state.viewport.scrollRow && nextCol === state.viewport.scrollCol) return; + state.viewport.scrollRow = nextRow; + state.viewport.scrollCol = nextCol; + renderGridBody(false); + scheduleViewportFetch(); +} + +function handleScroll() { + if (scrollRafPending) return; + scrollRafPending = true; + requestAnimationFrame(() => { + scrollRafPending = false; + applyScrollPosition(); + }); +} + +/* -------------------------------------------------------------- editing */ + +function canEdit() { + return !state.loading + && !state.dialogPending + && !state.modePending + && state.mode !== 'inspect' + && Boolean(state.workbookId); +} + +function handleViewportResize() { + const host = scrollHost(); + if (!host || host.clientWidth <= 0 || host.clientHeight <= 0) return; + const nextSize = `${host.clientWidth}x${host.clientHeight}`; + if (nextSize === lastObservedGridSize) return; + lastObservedGridSize = nextSize; + measureViewport(); + renderGridBody(false); + scheduleViewportFetch(); +} + +function scheduleViewportResize() { + if (resizeRafPending) return; + resizeRafPending = true; + requestAnimationFrame(() => { + resizeRafPending = false; + handleViewportResize(); + }); +} + +function beginEdit(row, col, initialValue) { + if (!canEdit()) return; + const sheet = activeSheet(); + if (!sheet) return; + const cell = state.cells.get(cellCacheKey(sheet.id, row, col)); + const value = initialValue != null ? initialValue : cellEditValue(cell); + state.editing = createEditingDraft({ + row, + col, + value, + workbookId: state.workbookId, + sheetId: sheet.id, + revision: state.meta?.revision ?? null, + origin: 'cell', + }); + setFocusFromSelection(row, col, row, col, { sync: true }); + scrollToCell(row, col); + updateOverlays(); +} + +function syncEditOverlay() { + const overlay = q('[data-cell-editor]'); + if (!overlay) return; + if (!state.editing || state.editing.origin === 'formula') { + overlay.hidden = true; + return; + } + const { row, col } = state.editing; + const layout = sheetLayout(); + overlay.hidden = false; + overlay.style.left = `${columnLeft(col, layout)}px`; + overlay.style.top = `${rowTop(row, layout)}px`; + overlay.style.width = `${columnWidth(col, layout)}px`; + overlay.style.height = `${rowHeight(row, layout)}px`; + const input = overlay.querySelector('input'); + if (input && document.activeElement !== input) { + input.value = state.editing.value; + input.focus(); + input.select(); + } +} + +function notifyEditingSettled() { + document.dispatchEvent(new CustomEvent('excel-live:editing-settled')); +} + +function restoreEditingFocus(editing) { + queueMicrotask(() => { + if (state.editing !== editing) return; + if (editing.origin === 'formula') { + const formulaInput = q('[data-formula-input]'); + if (formulaInput && !formulaInput.disabled) { + formulaInput.value = editing.value; + formulaInput.focus({ preventScroll: true }); + } + return; + } + updateOverlays(); + }); +} + +async function commitEdit(move = null) { + if (state.editCommitPromise) return state.editCommitPromise; + if (!state.editing || !state.workbookId) return true; + if (!canEdit()) { + showToast('error', t(state.mode === 'inspect' ? 'inspectEditBlocked' : 'operationPending')); + return false; + } + const editing = state.editing; + const sheet = state.sheets.find((candidate) => candidate.id === editing.sheetId) || activeSheet(); + if (!sheet || (editing.workbookId && editing.workbookId !== state.workbookId)) return false; + + const task = (async () => { + const { row, col, value } = editing; + const trimmed = String(value ?? ''); + const expectedRevision = editingExpectedRevision(editing, state.meta?.revision ?? undefined); + const payload = { + workbookId: state.workbookId, + sheetId: sheet.id, + row, + col, + baseRevision: expectedRevision, + expectedRevision, + }; + if (trimmed.startsWith('=')) { + payload.formula = trimmed; + } else { + payload.value = trimmed; + } + + state.editing = null; + updateOverlays(); + state.loading = true; + updateChrome(); + let committed = false; + try { + const result = await callExcel('applyLocalEdit', payload); + if (result?.meta) { + state.dirty = Boolean(result.meta.dirty); + state.meta = result.meta; + } + const key = cellCacheKey(sheet.id, row, col); + if (result?.edit?.after) { + state.cells.set(key, { + v: result.edit.after.v ?? null, + f: result.edit.after.f ?? null, + t: result.edit.after.t ?? null, + formulaEvidence: Boolean(result.edit.after.formulaEvidence || result.edit.after.f), + formulaType: result.edit.after.formulaType ?? null, + formulaRef: result.edit.after.formulaRef ?? null, + style: result.edit.after.style ?? null, + }); + } else { + state.cells.delete(key); + } + if (state.proposal) { + const remaining = (state.proposal.cells || []).filter( + (c) => !(Number(c.row ?? c.r) === row && Number(c.col ?? c.c) === col), + ); + state.proposal = remaining.length ? { ...state.proposal, cells: remaining } : null; + } + if (result?.edit?.operationId) { + state.history.canUndo = true; + state.history.canRedo = false; + } + // Local edits already persist to the live workbook.json store (including + // focus). Only refresh host ambient context so chat sees the new preview; + // skip a second setFocus bridge round-trip. + scheduleFocusSync({ force: true, immediate: true, broadcast: false }); + renderGridBody(true); + updateChrome(); + document.dispatchEvent(new CustomEvent('excel-live:proposal-refresh')); + document.dispatchEvent(new CustomEvent('excel-live:history-refresh')); + committed = true; + } catch (error) { + showToast('error', error?.message || t('editFailed')); + } finally { + state.loading = false; + updateChrome(); + if (committed) { + notifyEditingSettled(); + } else { + state.editing = editing; + renderGridBody(true); + restoreEditingFocus(editing); + } + } + + if (!committed) return false; + if (move?.exit === true) { + // Keep the browser's natural focus destination (Tab/click outside). + } else if (move) { + moveFocus(move.dr, move.dc, false); + } else { + focusGridWrap(); + } + return true; + })(); + + state.editCommitPromise = task; + try { + return await task; + } finally { + if (state.editCommitPromise === task) state.editCommitPromise = null; + } +} + +function cancelEdit() { + const hadEditing = Boolean(state.editing); + state.editing = null; + updateOverlays(); + focusGridWrap(); + if (hadEditing) notifyEditingSettled(); +} + +async function applyFormulaBarValue(value) { + if (!canEdit()) return; + const focus = normalizeFocusRange(state.focus); + const sheet = activeSheet(); + if (!sheet) return; + if ( + state.editing + && state.editing.row === focus.r1 + && state.editing.col === focus.c1 + && state.editing.sheetId === sheet.id + ) { + state.editing.value = String(value ?? ''); + } else { + state.editing = createEditingDraft({ + row: focus.r1, + col: focus.c1, + value, + workbookId: state.workbookId, + sheetId: sheet.id, + revision: state.meta?.revision ?? null, + origin: 'formula', + }); + } + return commitEdit(); +} + +async function clearSelectionCells() { + if (!canEdit()) return; + const focus = normalizeFocusRange(state.focus); + const sheet = activeSheet(); + if (!sheet) return; + state.loading = true; + updateChrome(); + try { + const result = await callExcel('clearRange', { + workbookId: state.workbookId, + sheetId: sheet.id, + a1: focus.a1, + baseRevision: state.meta?.revision ?? undefined, + expectedRevision: state.meta?.revision ?? undefined, + }); + if (result?.meta) { + state.dirty = Boolean(result.meta.dirty); + state.meta = result.meta; + } + for (let r = focus.r1; r <= focus.r2; r += 1) { + for (let c = focus.c1; c <= focus.c2; c += 1) { + state.cells.delete(cellCacheKey(sheet.id, r, c)); + } + } + state.status = t('statusCleared'); + // clearRange already persisted cells + focus-adjacent state; host-only sync. + scheduleFocusSync({ force: true, immediate: true, broadcast: false }); + renderGridBody(true); + updateChrome(); + document.dispatchEvent(new CustomEvent('excel-live:proposal-refresh')); + document.dispatchEvent(new CustomEvent('excel-live:history-refresh')); + } catch (error) { + showToast('error', error?.message || t('clearFailed')); + } finally { + state.loading = false; + updateChrome(); + } +} + +/* ------------------------------------------------------------ selection */ + +function focusGridWrap() { + const wrap = q('[data-grid-wrap]'); + if (wrap && document.activeElement !== wrap) { + wrap.focus({ preventScroll: true }); + } +} + +function cellFromEvent(event) { + const node = closestElement(event.target, '[data-row][data-col].el-grid__cell'); + if (node) { + return { row: Number(node.dataset.row), col: Number(node.dataset.col) }; + } + // Empty cells are not rendered as DOM nodes; derive from body coordinates. + const body = q('[data-grid-body]'); + if (!body || !closestElement(event.target, '[data-grid-body]')) return null; + const rect = body.getBoundingClientRect(); + const x = event.clientX - rect.left; + const y = event.clientY - rect.top; + if (x < 0 || y < 0) return null; + const sheet = activeSheet(); + if (!sheet) return null; + const bounds = sheetBounds(sheet); + const row = clamp(Math.floor(y / ROW_H), 0, bounds.rows - 1); + const col = clamp(Math.floor(x / COL_W), 0, bounds.cols - 1); + return { row, col }; +} + +function applyPointerSelection(anchor, current = anchor, dragging = true) { + state.selectionDragging = dragging; + state.selectionAnchor = { row: anchor.row, col: anchor.col }; + setFocusFromSelection(anchor.row, anchor.col, current.row, current.col); + updateOverlays(); + focusGridWrap(); +} + +function completeDeferredGridSelection(record, committed) { + if (deferredGridSelection !== record) return; + deferredGridSelection = null; + if (!committed || record.cancelled) return; + const current = record.latestCell || record.anchor; + applyPointerSelection(record.anchor, current, !record.released); + if (record.released) { + scheduleFocusSync({ force: true, broadcast: true }); + } +} + +function handleBodyPointerDown(event) { + if (event.button !== 0) return; + if (closestElement(event.target, '[data-cell-editor]')) return; + const cell = cellFromEvent(event); + if (!cell) return; + if (deferredGridSelection || state.editCommitPromise) { + event.preventDefault(); + return; + } + const sheet = activeSheet(); + const targetCell = { ...cell, sheetId: sheet?.id || null }; + if (state.editing) { + if (!gridSelectionNeedsEditCommit(state.editing, targetCell)) return; + const record = { + anchor: cell, + latestCell: cell, + pointerId: event.pointerId, + released: false, + cancelled: false, + }; + deferredGridSelection = record; + try { + event.currentTarget?.setPointerCapture?.(event.pointerId); + } catch (_error) { + // Pointer capture is an enhancement; document-level handlers still + // preserve the deferred selection within the surface. + } + event.preventDefault(); + void commitEdit({ exit: true }) + .then((committed) => completeDeferredGridSelection(record, committed)) + .catch(() => completeDeferredGridSelection(record, false)); + return; + } + applyPointerSelection(cell); + event.preventDefault(); +} + +function handleBodyPointerMove(event) { + if ( + deferredGridSelection + && (deferredGridSelection.pointerId == null || deferredGridSelection.pointerId === event.pointerId) + ) { + const cell = cellFromEvent(event); + if (cell) deferredGridSelection.latestCell = cell; + event.preventDefault(); + return; + } + if (!state.selectionDragging || !state.selectionAnchor) return; + const cell = cellFromEvent(event); + if (!cell) return; + const anchor = state.selectionAnchor; + setFocusFromSelection(anchor.row, anchor.col, cell.row, cell.col); + updateOverlays(); +} + +function handlePointerUp(event) { + if ( + deferredGridSelection + && (deferredGridSelection.pointerId == null || deferredGridSelection.pointerId === event.pointerId) + ) { + deferredGridSelection.released = true; + deferredGridSelection.cancelled = event.type === 'pointercancel'; + event.preventDefault(); + return; + } + if (!state.selectionDragging) return; + state.selectionDragging = false; + // Selection settled — push ambient focus (with cell preview) to the host + // and mirror it into the workbook store for agent tools. + scheduleFocusSync({ force: true, broadcast: true }); +} + +function handleBodyDblClick(event) { + const cell = cellFromEvent(event); + if (!cell) return; + beginEdit(cell.row, cell.col); +} + +function handleHeaderPointerDown(event) { + if (event.button !== 0) return; + const sheet = activeSheet(); + if (!sheet) return; + const bounds = sheetBounds(sheet); + const colNode = closestElement(event.target, '[data-col-h]'); + const rowNode = closestElement(event.target, '[data-row-h]'); + const cornerNode = closestElement(event.target, '[data-grid-corner]'); + if (colNode) { + const c = Number(colNode.dataset.colH); + setFocusFromSelection(0, c, bounds.rows - 1, c, { kind: 'column' }); + } else if (rowNode) { + const r = Number(rowNode.dataset.rowH); + setFocusFromSelection(r, 0, r, bounds.cols - 1, { kind: 'row' }); + } else if (cornerNode) { + setFocusFromSelection(0, 0, bounds.rows - 1, bounds.cols - 1, { kind: 'sheet' }); + } else { + return; + } + updateOverlays(); + event.preventDefault(); + focusGridWrap(); +} + +function moveFocus(dRow, dCol, extend) { + const sheet = activeSheet(); + if (!sheet) return; + const bounds = sheetBounds(sheet); + const focus = normalizeFocusRange(state.focus); + if (extend) { + const nextR2 = clamp(focus.r2 + dRow, 0, bounds.rows - 1); + const nextC2 = clamp(focus.c2 + dCol, 0, bounds.cols - 1); + setFocusFromSelection(focus.r1, focus.c1, nextR2, nextC2); + scrollToCell(nextR2, nextC2); + } else { + const nextR = clamp(focus.r1 + dRow, 0, bounds.rows - 1); + const nextC = clamp(focus.c1 + dCol, 0, bounds.cols - 1); + setFocusFromSelection(nextR, nextC, nextR, nextC); + scrollToCell(nextR, nextC); + } + updateOverlays(); + scheduleViewportFetch(); +} + +function jumpToA1(text) { + const sheet = activeSheet(); + if (!sheet || !text) return; + let parsed; + try { + parsed = parseA1(text); + } catch (_error) { + updateNameBox(); + return; + } + const bounds = sheetBounds(sheet); + const r1 = clamp(parsed.r1, 0, bounds.rows - 1); + const c1 = clamp(parsed.c1, 0, bounds.cols - 1); + const r2 = clamp(parsed.r2, 0, bounds.rows - 1); + const c2 = clamp(parsed.c2, 0, bounds.cols - 1); + setFocusFromSelection(r1, c1, r2, c2); + scrollToCell(r1, c1); + updateOverlays(); + scheduleViewportFetch(); + focusGridWrap(); +} + +/* ------------------------------------------------------------- keyboard */ + +function handleGridKeyDown(event) { + const wrap = q('[data-grid-wrap]'); + if (!wrap || !state.workbookId) return; + const target = event.target; + const tag = target?.tagName; + if (isComposingKey(event)) return; + const modified = event.ctrlKey || event.metaKey; + const lowerKey = event.key.toLowerCase(); + + if (isSaveShortcut(event)) { + event.preventDefault(); + if (state.editing) { + void commitEdit({ exit: true }).then((committed) => { + if (committed) document.dispatchEvent(new CustomEvent('excel-live:save')); + }); + } else { + document.dispatchEvent(new CustomEvent('excel-live:save')); + } + return; + } + + if (tag === 'INPUT' || tag === 'TEXTAREA') { + const isFormula = target?.dataset?.formulaInput != null; + const isEditor = Boolean(target?.closest?.('[data-cell-editor]')); + const isNameBox = target?.dataset?.namebox != null; + if (isNameBox) { + if (event.key === 'Enter') { + event.preventDefault(); + jumpToA1(target.value); + } else if (event.key === 'Escape') { + event.preventDefault(); + updateNameBox(); + focusGridWrap(); + } + return; + } + if (isFormula || isEditor) { + if (event.key === 'Enter') { + event.preventDefault(); + if (isFormula) { + void applyFormulaBarValue(target.value); + } else { + void commitEdit({ dr: 1, dc: 0 }); + } + } else if (event.key === 'Tab' && isEditor) { + // Commit, but preserve native Tab traversal out of the ARIA grid. + void commitEdit({ exit: true }); + } else if (event.key === 'Escape') { + event.preventDefault(); + cancelEdit(); + updateFormulaBar(); + } + } + return; + } + + const root = rootElement(); + const inGrid = Boolean( + wrap.contains(target) + || target === wrap + || target === document.body + || target === root + || (root && root.contains(target) && !['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON'].includes(tag)), + ); + if (modified && lowerKey === 'c' && inGrid) { + event.preventDefault(); + document.dispatchEvent(new CustomEvent('excel-live:copy')); + return; + } + if (modified && lowerKey === 'v' && inGrid) { + event.preventDefault(); + document.dispatchEvent(new CustomEvent('excel-live:paste')); + return; + } + if (modified && lowerKey === 'z' && inGrid) { + event.preventDefault(); + document.dispatchEvent(new CustomEvent(event.shiftKey ? 'excel-live:redo' : 'excel-live:undo')); + return; + } + if (modified && lowerKey === 'y' && inGrid) { + event.preventDefault(); + document.dispatchEvent(new CustomEvent('excel-live:redo')); + return; + } + + if (state.editing) return; + // Accept key events when the grid wrap (or anything inside it) is focused, + // or when focus is on body/root after a cell click that used preventDefault. + if (!inGrid) return; + + const extend = event.shiftKey; + switch (event.key) { + case 'ArrowUp': + event.preventDefault(); + moveFocus(-1, 0, extend); + break; + case 'ArrowDown': + event.preventDefault(); + moveFocus(1, 0, extend); + break; + case 'ArrowLeft': + event.preventDefault(); + moveFocus(0, -1, extend); + break; + case 'ArrowRight': + event.preventDefault(); + moveFocus(0, 1, extend); + break; + case 'Tab': + // ARIA grids are single Tab stops; arrow keys navigate inside, while + // Tab and Shift+Tab leave the grid normally. + break; + case 'PageDown': + event.preventDefault(); + moveFocus(Math.max(1, state.viewport.visibleRows - 2), 0, extend); + break; + case 'PageUp': + event.preventDefault(); + moveFocus(-Math.max(1, state.viewport.visibleRows - 2), 0, extend); + break; + case 'Home': + event.preventDefault(); + jumpToA1('A1'); + break; + case 'Enter': + case 'F2': + event.preventDefault(); + beginEdit(state.focus.r1, state.focus.c1); + break; + case 'Delete': + case 'Backspace': + event.preventDefault(); + void clearSelectionCells(); + break; + default: + if (event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) { + beginEdit(state.focus.r1, state.focus.c1, event.key); + event.preventDefault(); + } + break; + } +} + +/* -------------------------------------------------------------- binding */ + +function bindGridDom() { + if (domBound) return; + const host = scrollHost(); + const body = q('[data-grid-body]'); + const pin = q('.el-grid__pin'); + const rowHeaders = q('[data-row-headers]'); + const editorInput = q('[data-cell-editor] input'); + const formulaInput = q('[data-formula-input]'); + if (!host || !body) return; + domBound = true; + + host.addEventListener('scroll', handleScroll, { passive: true }); + body.addEventListener('pointerdown', handleBodyPointerDown); + body.addEventListener('dblclick', handleBodyDblClick); + document.addEventListener('pointermove', handleBodyPointerMove); + document.addEventListener('pointerup', handlePointerUp); + document.addEventListener('pointercancel', handlePointerUp); + if (pin) pin.addEventListener('pointerdown', handleHeaderPointerDown); + if (rowHeaders) rowHeaders.addEventListener('pointerdown', handleHeaderPointerDown); + document.addEventListener('keydown', handleGridKeyDown); + + if (editorInput) { + editorInput.addEventListener('input', () => { + if (!state.editing) return; + state.editing.value = editorInput.value; + const formula = q('[data-formula-input]'); + if (formula && document.activeElement !== formula) formula.value = editorInput.value; + }); + editorInput.addEventListener('blur', () => { + if (state.editing) void commitEdit({ exit: true }); + }); + } + if (formulaInput) { + formulaInput.addEventListener('input', () => { + if (!canEdit()) return; + if (!state.editing) { + const focus = normalizeFocusRange(state.focus); + const sheet = activeSheet(); + if (!sheet) return; + state.editing = createEditingDraft({ + row: focus.r1, + col: focus.c1, + value: formulaInput.value, + workbookId: state.workbookId, + sheetId: sheet.id, + revision: state.meta?.revision ?? null, + origin: 'formula', + }); + } else { + state.editing.value = formulaInput.value; + } + }); + formulaInput.addEventListener('blur', () => { + if (state.editing) void commitEdit({ exit: true }); + }); + } + + if (typeof ResizeObserver === 'function') { + gridResizeObserver?.disconnect(); + gridResizeObserver = new ResizeObserver(scheduleViewportResize); + gridResizeObserver.observe(host); + } + window.addEventListener('resize', scheduleViewportResize); +} + +function renderGrid() { + bindGridDom(); + layoutGrid(); + measureViewport(); + renderGridBody(true); + // The first paint may happen before the real viewport size is known; + // fetch any tiles the measured viewport needs (tile cache dedupes). + scheduleViewportFetch(); +} + +function resetScrollPosition() { + const host = scrollHost(); + if (host) { + host.scrollTop = 0; + host.scrollLeft = 0; + } + state.viewport.scrollRow = 0; + state.viewport.scrollCol = 0; +} + +export { + applyFormulaBarValue, + beginEdit, + cancelEdit, + clearSelectionCells, + commitEdit, + jumpToA1, + measureViewport, + refreshViewportCells, + renderGrid, + renderGridBody, + resetScrollPosition, + scheduleViewportFetch, + scrollToCell, + updateFormulaBar, + updateNameBox, + updateOverlays, +}; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/i18n.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/i18n.js new file mode 100644 index 00000000..643ae358 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/i18n.js @@ -0,0 +1,437 @@ +import { state } from './state.js'; + +const MESSAGES = { + 'en-US': { + title: 'Excel Live', + loading: 'Loading workbook…', + boot: 'Loading Excel Live…', + noWorkspace: 'No storage location available for Excel Live.', + backendMissing: 'Excel engine backend is unavailable.', + newWorkbook: 'New workbook', + openWorkbook: 'Open file', + save: 'Export copy', + exportCsv: 'Export CSV', + undo: 'Undo', + redo: 'Redo', + pinFocus: 'Pin focus to chat', + askFocus: 'Ask AI', + insertRow: 'Insert row', + insertCol: 'Insert column', + acceptProposal: 'Accept', + rejectProposal: 'Reject', + proposalTitle: 'AI proposal', + proposalCells: '{{count}} cell(s)', + proposalHint: 'Review the highlighted cells, then accept or reject.', + focusLabel: 'Focus', + formulaLabel: 'fx', + nameBoxTitle: 'Selection — type a cell or range and press Enter to jump', + formulaTitle: 'Formula or value of the active cell', + dirty: 'Autosaved', + saved: 'Synced', + modeInspect: 'Inspect', + modeEdit: 'Edit', + modeAuthor: 'Author', + modeInspectHint: 'Read-only for both you and AI; proposals cannot be accepted.', + modeEditHint: 'Edit cells directly or let AI prepare reviewable proposals.', + modeAuthorHint: 'Build new structure with AI, still through reviewable proposals.', + includeFocus: 'Send focus to AI', + includeFocusTitle: 'Attach the current selection (and live cell preview) when sending chat messages', + sheetTabs: 'Sheets', + gridLabel: 'Workbook grid', + autoFilterActive: 'Auto filter enabled', + addSheet: 'Add sheet', + emptyTitle: 'No workbook open', + emptyHint: 'Create a new workbook, open an .xlsx / .csv file, or just ask the AI on the left.', + openFailed: 'Failed to open workbook', + createFailed: 'Failed to create workbook', + saveFailed: 'Failed to export workbook copy', + exportFailed: 'Failed to export CSV', + editFailed: 'Failed to apply edit', + clearFailed: 'Failed to clear cells', + proposalAcceptFailed: 'Failed to accept proposal', + proposalRejectFailed: 'Failed to reject proposal', + proposalStale: 'Out of date', + proposalStaleHint: 'The workbook changed after this proposal was created. Reject it and ask AI to prepare a fresh proposal.', + proposalSelectAtLeastOne: 'Select at least one proposed cell to accept.', + inspectAcceptBlocked: 'Inspect mode is read-only. Switch to Edit or Author to accept a proposal.', + inspectEditBlocked: 'Inspect mode is read-only. Switch to Edit or Author to change the workbook.', + modeChangePending: 'The mode change is still being confirmed. Wait a moment before changing the workbook.', + operationPending: 'Another workbook operation is still in progress. Wait for it to finish.', + modeUnavailable: 'Workbook mode control is unavailable.', + modeSwitching: 'Switching to {{mode}}…', + modeChanged: 'Switched to {{mode}}.', + modeSwitchFailed: 'Mode change failed. Still in {{mode}}.', + reviewDetails: 'Review details', + hideDetails: 'Hide details', + acceptSelected: 'Accept selected ({{count}})', + proposalSelected: '{{count}} selected', + selectAll: 'Select all', + selectAllCount: 'Select all {{count}}', + selectNone: 'Select none', + proposalSelectAllConfirm: 'Select all {{count}} proposed cells, including {{hidden}} cells not shown in the review list? Review the full scope before accepting.', + proposalHiddenUnselected: '{{count}} additional cells are not shown and are not selected', + proposalHiddenSelected: '{{count}} additional hidden cells are selected', + proposalHiddenPartiallySelected: '{{selected}} of {{count}} hidden cells are selected', + proposalDetails: 'Proposal before and after details', + proposalDetailsLimited: '{{count}} more cells remain selected but are not rendered here for performance.', + cell: 'Cell', + before: 'Before', + after: 'After', + emptyValue: 'empty', + proposalCellAria: '{{cell}} proposal, before {{before}}, after {{after}}', + validationPassed: 'Validation passed', + validationFailed: 'Validation failed', + validationIssues: '{{count}} validation issue(s)', + validationErrors: '{{count}} validation error(s)', + validationWarnings: '{{count}} validation warning(s)', + proposalInvalidHint: 'This proposal contains validation errors and cannot be accepted. Fix or reject it first.', + validationMustFix: 'Must fix before accepting', + validationReview: 'Review before accepting', + validationMore: '{{count}} more validation issue(s)', + cachedValue: 'Cached result: {{value}}', + proposalLayoutChange: 'Layout change', + acceptLayout: 'Accept layout', + acceptAllWithLayout: 'Accept all + layout ({{count}})', + acceptSelectedLayoutPending: 'Accept selected ({{count}})', + proposalLayoutAllHint: 'All proposed cells are selected, so accepting will apply the cells and layout together.', + proposalLayoutPartialHint: 'Accepting a partial cell selection keeps the layout change pending for separate review.', + styleChanges: 'Style changes', + styleNone: 'none', + styleBold: 'bold', + styleItalic: 'italic', + styleWrap: 'wrap', + style_role: 'Role', + style_fill: 'Fill', + style_font: 'Font', + style_border: 'Border', + style_alignment: 'Alignment', + style_numberFormat: 'Number', + styleSide_top: 'top', + styleSide_right: 'right', + styleSide_bottom: 'bottom', + styleSide_left: 'left', + layoutChanges: 'Layout changes', + layout_columns: 'Column widths', + layout_rows: 'Row heights', + layout_freezePanes: 'Freeze panes', + layout_autoFilter: 'Auto filter', + layoutOff: 'off', + layoutDefault: 'default', + layoutAutoFit: 'auto fit', + layoutFreezeValue: '{{rows}} row(s), {{columns}} column(s)', + formatStyles: 'Cell styles', + formatHeader: 'Header', + formatTotal: 'Total', + formatInput: 'Input', + formatOutput: 'Output', + formatBold: 'Bold', + formatFill: 'Fill color', + numberFormat: 'Number format', + numberGeneral: 'General', + numberInteger: 'Number', + numberDecimal: 'Decimal', + numberCurrency: 'Currency (USD)', + numberPercent: 'Percentage', + numberDate: 'Date (YYYY-MM-DD)', + formatProposalReady: 'Formatting proposal ready for review', + formatProposalFailed: 'Failed to prepare formatting proposal', + formatProposalExists: 'Review or reject the active proposal before preparing another format change.', + formatProposalExistsShort: 'Finish the active proposal to format again', + formatProposalMissing: 'The engine did not return a reviewable formatting proposal.', + formatRangeTooLarge: 'Formatting proposals are limited to {{count}} cells. Narrow the selection and try again.', + formatIntent: 'Format {{range}}', + formatRoleIntent: 'Apply the {{role}} style to the selected cells', + formatBoldIntent: 'Make the selected cells bold', + formatFillIntent: 'Apply a fill color to the selected cells', + formatNumberIntent: 'Apply {{format}} to the selected cells', + switchFailed: 'Failed to switch sheet', + insertFailed: 'Failed to insert', + addSheetFailed: 'Failed to add sheet', + askPrompt: 'About {{sheet}}!{{a1}} in {{title}}: ', + pinMarker: '[Pinned spreadsheet focus: {{sheet}}!{{a1}}]', + statusReady: 'Ready', + statusCreated: 'Created workbook (live store)', + statusOpened: 'Opened workbook (live store)', + statusResumed: 'Resumed last workbook', + statusSaved: 'Exported workbook file', + statusExportedCopy: 'Exported a new workbook copy; the source file was not overwritten', + statusExported: 'CSV exported', + statusExportedSanitized: 'CSV exported; safely escaped {{count}} formula-like text cell(s)', + statusAccepted: 'Proposal accepted', + statusAcceptedCells: 'Accepted {{count}} proposed cell(s)', + statusAcceptedLayout: 'Accepted workbook layout proposal', + statusAcceptedCellsAndLayout: 'Accepted {{count}} proposed cell(s) and workbook layout', + statusAcceptedCellsLayoutPending: 'Accepted {{count}} proposed cell(s); layout remains pending', + statusRejected: 'Proposal rejected', + statusPinned: 'Focus pinned to chat', + statusAsked: 'Prompt filled in chat', + statusAgentUpdated: 'Updated by AI', + statusCleared: 'Cells cleared (autosaved)', + statusUndone: 'Undid the last workbook change', + statusRedone: 'Redid the workbook change', + statusCopied: 'Copied {{count}} cell(s)', + statusPasted: 'Pasted {{count}} cell(s)', + copying: 'Copying cells…', + pasting: 'Pasting cells…', + copyFailed: 'Failed to copy cells', + pasteFailed: 'Failed to paste cells', + undoFailed: 'Failed to undo', + redoFailed: 'Failed to redo', + clipboardUnavailable: 'Clipboard access is unavailable.', + clipboardRangeTooLarge: 'Copy and paste are limited to {{count}} cells at a time.', + clipboardRangeIncomplete: 'The selected cells could not be loaded completely. Narrow the selection and try again.', + exportCopyDialogMissing: 'The export dialog is unavailable. The source workbook was not changed.', + exportCopySourceBlocked: 'Choose a different file name. Export copy never overwrites the source workbook.', + exportCopyMacroExtension: 'Macro-enabled workbooks must be exported as .xlsm to preserve the source format. No file was written.', + exportCopyXlsxExtension: 'Workbook copies must be exported as .xlsx. No file was written.', + excelMacroFile: 'Excel Macro-Enabled Workbook', + fidelityExportConfirm: 'This workbook contains Excel features that Excel Live cannot round-trip exactly. A separate copy may omit formatting, charts, macros, or other advanced content. The source file will remain unchanged. Export the copy anyway?', + fidelityXlsmToXlsxConfirm: 'This macro-enabled workbook can no longer be round-tripped safely after its style or layout changes. Exporting will create a separate .xlsx rebuild without VBA or macros; the source .xlsm remains unchanged. Continue?', + statusExportCancelled: 'Export cancelled; the source file was not changed', + exportCopyMacroStructureBlocked: 'This macro-enabled workbook has structural changes that cannot be exported safely without risking VBA or workbook integrity. The source file was not changed.', + exportCopyFidelityAckRequired: 'Review the compatibility warning and confirm the lossy copy before exporting. The source file was not changed.', + fidelityLimited: 'Compatibility notice: this view preserves basic values and formulas only. Formatting, macros, charts, and advanced Excel features may not be represented.', + fidelitySourcePreservingView: 'Exported copies preserve the source Excel package. The live grid renders declared cell styles, common number formats, and layout metadata; charts and other advanced presentation semantics may still require Excel.', + fidelityUnknown: 'Workbook fidelity has not been verified. Export a copy and check it before relying on the result.', + calculationPending: 'Formula results are not recalculated yet; displayed values may be stale.', + calculationFailed: 'Formula recalculation failed; displayed results may be stale.', + calculationUnknown: 'Formula calculation status is unknown.', + staleFormulaCsvConfirm: 'Some formulas have not been recalculated. CSV exports cached values, which may be stale. The source workbook will remain unchanged. Export the CSV copy anyway?', + staleFormulaCsvAckRequired: 'Review and confirm the stale formula warning before exporting CSV. No file was written.', + uncachedFormulaCsvBlocked: 'One or more formulas have no calculated result, so CSV export was blocked. Recalculate the workbook in Excel first.', + selectionAnnouncement: '{{sheet}} {{a1}}, {{rows}} row(s) by {{cols}} column(s)', + readOnly: 'Read-only', + statsCount: 'Count', + statsSum: 'Sum', + statsAvg: 'Avg', + statsFormulaStale: 'Formula results need recalculation', + untitled: 'Untitled Workbook', + openDialogTitle: 'Open workbook', + saveDialogTitle: 'Export workbook copy', + exportDialogTitle: 'Export CSV', + }, + 'zh-CN': { + title: 'Excel Live', + loading: '正在加载工作簿…', + boot: '正在加载 Excel Live…', + noWorkspace: 'Excel Live 没有可用的存储位置。', + backendMissing: 'Excel 引擎后端不可用。', + newWorkbook: '新建工作簿', + openWorkbook: '打开文件', + save: '导出副本', + exportCsv: '导出 CSV', + undo: '撤销', + redo: '重做', + pinFocus: '固定焦点到对话', + askFocus: '询问 AI', + insertRow: '插入行', + insertCol: '插入列', + acceptProposal: '接受', + rejectProposal: '拒绝', + proposalTitle: 'AI 提案', + proposalCells: '{{count}} 个单元格', + proposalHint: '请检查高亮单元格,然后接受或拒绝。', + focusLabel: '焦点', + formulaLabel: 'fx', + nameBoxTitle: '当前选区 — 输入单元格或范围后回车跳转', + formulaTitle: '活动单元格的公式或值', + dirty: '已实时保存', + saved: '已同步', + modeInspect: '检查', + modeEdit: '编辑', + modeAuthor: '创作', + modeInspectHint: '人和 AI 均只读,不能接受提案。', + modeEditHint: '可直接编辑,也可让 AI 生成待审阅提案。', + modeAuthorHint: '用 AI 创建新结构,但所有写入仍需提案审阅。', + includeFocus: '发送焦点给 AI', + includeFocusTitle: '发送对话消息时附带当前选区与实时单元格预览', + sheetTabs: '工作表', + gridLabel: '工作簿网格', + autoFilterActive: '已启用自动筛选', + addSheet: '新增工作表', + emptyTitle: '尚未打开工作簿', + emptyHint: '新建工作簿、打开 .xlsx / .csv 文件,或直接在左侧向 AI 提问。', + openFailed: '打开工作簿失败', + createFailed: '创建工作簿失败', + saveFailed: '导出工作簿副本失败', + exportFailed: '导出 CSV 失败', + editFailed: '应用编辑失败', + clearFailed: '清除单元格失败', + proposalAcceptFailed: '接受提案失败', + proposalRejectFailed: '拒绝提案失败', + proposalStale: '已过期', + proposalStaleHint: '工作簿在提案生成后已发生变化。请拒绝该提案,并让 AI 基于最新内容重新生成。', + proposalSelectAtLeastOne: '请至少选择一个要接受的提案单元格。', + inspectAcceptBlocked: '检查模式为只读。请切换到编辑或创作模式后再接受提案。', + inspectEditBlocked: '检查模式为只读。请切换到编辑或创作模式后再修改工作簿。', + modeChangePending: '模式切换仍在确认中,请稍后再修改工作簿。', + operationPending: '另一项工作簿操作仍在进行中,请等待其完成。', + modeUnavailable: '工作簿模式控制当前不可用。', + modeSwitching: '正在切换到{{mode}}模式…', + modeChanged: '已切换到{{mode}}模式。', + modeSwitchFailed: '模式切换失败,仍处于{{mode}}模式。', + reviewDetails: '审阅明细', + hideDetails: '收起明细', + acceptSelected: '接受所选({{count}})', + proposalSelected: '已选择 {{count}} 个', + selectAll: '全选', + selectAllCount: '全选 {{count}} 个', + selectNone: '全不选', + proposalSelectAllConfirm: '要选择全部 {{count}} 个提案单元格吗?其中 {{hidden}} 个未显示在审阅列表中。接受前请确认完整影响范围。', + proposalHiddenUnselected: '另有 {{count}} 个单元格未展示且未选中', + proposalHiddenSelected: '另有 {{count}} 个隐藏单元格已选中', + proposalHiddenPartiallySelected: '隐藏单元格中已选择 {{selected}} / {{count}} 个', + proposalDetails: '提案修改前后明细', + proposalDetailsLimited: '另有 {{count}} 个单元格保持选中;为保证性能,此处未展开显示。', + cell: '单元格', + before: '修改前', + after: '修改后', + emptyValue: '空', + proposalCellAria: '{{cell}} 提案,修改前 {{before}},修改后 {{after}}', + validationPassed: '校验通过', + validationFailed: '校验失败', + validationIssues: '{{count}} 个校验问题', + validationErrors: '{{count}} 个校验错误', + validationWarnings: '{{count}} 个校验警告', + proposalInvalidHint: '该提案包含校验错误,无法接受。请先修复或拒绝提案。', + validationMustFix: '接受前必须修复', + validationReview: '接受前请检查', + validationMore: '另有 {{count}} 个校验问题', + cachedValue: '缓存结果:{{value}}', + proposalLayoutChange: '布局变更', + acceptLayout: '接受布局', + acceptAllWithLayout: '全部接受并应用布局({{count}})', + acceptSelectedLayoutPending: '接受所选({{count}})', + proposalLayoutAllHint: '已选择全部提案单元格;接受后将原子应用单元格与布局。', + proposalLayoutPartialHint: '部分接受单元格后,布局变更会保留在提案中继续等待审阅。', + styleChanges: '样式变更', + styleNone: '无', + styleBold: '粗体', + styleItalic: '斜体', + styleWrap: '自动换行', + style_role: '角色', + style_fill: '底色', + style_font: '字体', + style_border: '边框', + style_alignment: '对齐', + style_numberFormat: '数字格式', + styleSide_top: '上', + styleSide_right: '右', + styleSide_bottom: '下', + styleSide_left: '左', + layoutChanges: '布局变更', + layout_columns: '列宽', + layout_rows: '行高', + layout_freezePanes: '冻结窗格', + layout_autoFilter: '自动筛选', + layoutOff: '关闭', + layoutDefault: '默认', + layoutAutoFit: '自动适应', + layoutFreezeValue: '{{rows}} 行、{{columns}} 列', + formatStyles: '单元格样式', + formatHeader: '表头', + formatTotal: '合计', + formatInput: '输入', + formatOutput: '输出', + formatBold: '粗体', + formatFill: '底色', + numberFormat: '数字格式', + numberGeneral: '常规', + numberInteger: '数值', + numberDecimal: '小数', + numberCurrency: '美元货币', + numberPercent: '百分比', + numberDate: '日期(YYYY-MM-DD)', + formatProposalReady: '格式提案已生成,请审阅', + formatProposalFailed: '生成格式提案失败', + formatProposalExists: '请先审阅或拒绝当前提案,再创建新的格式变更。', + formatProposalExistsShort: '完成当前提案后可继续设置格式', + formatProposalMissing: '引擎没有返回可审阅的格式提案。', + formatRangeTooLarge: '单次格式提案最多支持 {{count}} 个单元格,请缩小选区后重试。', + formatIntent: '设置 {{range}} 的格式', + formatRoleIntent: '将所选单元格设置为{{role}}样式', + formatBoldIntent: '将所选单元格设置为粗体', + formatFillIntent: '为所选单元格设置底色', + formatNumberIntent: '将所选单元格设置为{{format}}', + switchFailed: '切换工作表失败', + insertFailed: '插入失败', + addSheetFailed: '新增工作表失败', + askPrompt: '关于 {{title}} 中的 {{sheet}}!{{a1}}:', + pinMarker: '[已固定表格焦点:{{sheet}}!{{a1}}]', + statusReady: '就绪', + statusCreated: '已创建工作簿(实时库)', + statusOpened: '已打开工作簿(实时库)', + statusResumed: '已恢复上次的工作簿', + statusSaved: '已导出工作簿文件', + statusExportedCopy: '已导出新的工作簿副本,未覆盖源文件', + statusExported: 'CSV 已导出', + statusExportedSanitized: 'CSV 已导出;已安全转义 {{count}} 个公式样文本单元格', + statusAccepted: '提案已接受', + statusAcceptedCells: '已接受 {{count}} 个提案单元格', + statusAcceptedLayout: '已接受工作簿布局提案', + statusAcceptedCellsAndLayout: '已接受 {{count}} 个提案单元格及工作簿布局', + statusAcceptedCellsLayoutPending: '已接受 {{count}} 个提案单元格,布局仍待审阅', + statusRejected: '提案已拒绝', + statusPinned: '焦点已固定到对话', + statusAsked: '已填入对话输入框', + statusAgentUpdated: 'AI 已更新内容', + statusCleared: '已清除单元格(已实时保存)', + statusUndone: '已撤销上一次工作簿修改', + statusRedone: '已重做工作簿修改', + statusCopied: '已复制 {{count}} 个单元格', + statusPasted: '已粘贴 {{count}} 个单元格', + copying: '正在复制单元格…', + pasting: '正在粘贴单元格…', + copyFailed: '复制单元格失败', + pasteFailed: '粘贴单元格失败', + undoFailed: '撤销失败', + redoFailed: '重做失败', + clipboardUnavailable: '当前无法访问剪贴板。', + clipboardRangeTooLarge: '单次复制或粘贴最多支持 {{count}} 个单元格。', + clipboardRangeIncomplete: '所选单元格未能完整加载,请缩小选区后重试。', + exportCopyDialogMissing: '导出对话框不可用,源工作簿未发生变化。', + exportCopySourceBlocked: '请选择其他文件名;导出副本绝不会覆盖源工作簿。', + exportCopyMacroExtension: '启用宏的工作簿必须导出为 .xlsm 才能保持源格式,本次未写入文件。', + exportCopyXlsxExtension: '工作簿副本必须导出为 .xlsx,本次未写入文件。', + excelMacroFile: '启用宏的 Excel 工作簿', + fidelityExportConfirm: '该工作簿包含 Excel Live 无法完整往返保留的功能。独立副本可能缺少格式、图表、宏或其他高级内容;源文件不会改变。仍要导出副本吗?', + fidelityXlsmToXlsxConfirm: '该启用宏的工作簿在样式或布局变更后已无法安全往返保存。继续将生成一个不含 VBA 与宏的独立 .xlsx 重建副本,源 .xlsm 不会改变。是否继续?', + statusExportCancelled: '已取消导出,源文件未发生变化', + exportCopyMacroStructureBlocked: '该启用宏的工作簿包含无法安全导出的结构变更;为避免损坏 VBA 或工作簿,未写入副本,源文件也未改变。', + exportCopyFidelityAckRequired: '请先阅读兼容性提示并确认有损副本,再执行导出;源文件未发生变化。', + fidelityLimited: '兼容性提示:当前仅可靠保留基础值与公式;格式、宏、图表和高级 Excel 功能可能无法呈现。', + fidelitySourcePreservingView: '导出的副本会保留源 Excel 包。实时网格可呈现已声明的单元格样式、常用数字格式与布局元数据;图表等高级呈现仍可能需要在 Excel 中查看。', + fidelityUnknown: '尚未验证工作簿保真度,请导出副本并检查后再使用。', + calculationPending: '公式结果尚未重算,当前显示值可能已过期。', + calculationFailed: '公式重算失败,当前显示结果可能已过期。', + calculationUnknown: '公式计算状态未知。', + staleFormulaCsvConfirm: '部分公式尚未重算。CSV 将导出可能已过期的缓存值;源工作簿不会改变。仍要导出 CSV 副本吗?', + staleFormulaCsvAckRequired: '请先阅读并确认公式结果可能过期的提示,再导出 CSV;本次未写入文件。', + uncachedFormulaCsvBlocked: '一个或多个公式尚无计算结果,CSV 导出已阻止。请先在 Excel 中重算工作簿。', + selectionAnnouncement: '{{sheet}} {{a1}},{{rows}} 行 × {{cols}} 列', + readOnly: '只读', + statsCount: '计数', + statsSum: '求和', + statsAvg: '平均', + statsFormulaStale: '公式结果需要重算', + untitled: '未命名工作簿', + openDialogTitle: '打开工作簿', + saveDialogTitle: '导出工作簿副本', + exportDialogTitle: '导出 CSV', + }, +}; + +function messages() { + const locale = state.locale || 'en-US'; + return MESSAGES[locale] || MESSAGES[locale.split('-')[0]] || MESSAGES['en-US']; +} + +function t(key, params = {}) { + const template = messages()[key] || MESSAGES['en-US'][key] || key; + return Object.entries(params).reduce( + (value, [name, replacement]) => value.replaceAll(`{{${name}}}`, String(replacement ?? '')), + template, + ); +} + +export { MESSAGES, t }; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/interaction.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/interaction.js new file mode 100644 index 00000000..ab534452 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/interaction.js @@ -0,0 +1,134 @@ +function normalizeWorkbookId(value) { + return typeof value === 'string' ? value.trim() : ''; +} + +function agentRefreshTargetsCurrentWorkbook(currentWorkbookId, targetWorkbookId) { + const current = normalizeWorkbookId(currentWorkbookId); + const target = normalizeWorkbookId(targetWorkbookId); + return !current || !target || current === target; +} + +function createEditingDraft({ + row, + col, + value, + workbookId, + sheetId, + revision, + origin = 'cell', +}) { + return { + row, + col, + value: String(value ?? ''), + workbookId: normalizeWorkbookId(workbookId) || null, + sheetId: normalizeWorkbookId(sheetId) || null, + baseRevision: revision ?? null, + origin: origin === 'formula' ? 'formula' : 'cell', + }; +} + +function editingExpectedRevision(editing, fallbackRevision) { + return editing?.baseRevision ?? fallbackRevision; +} + +function isComposingKey(event) { + return Boolean(event?.isComposing || event?.keyCode === 229); +} + +function isSaveShortcut(event) { + return Boolean( + event + && (event.ctrlKey || event.metaKey) + && String(event.key || '').toLowerCase() === 's', + ); +} + +function gridSelectionNeedsEditCommit(editing, targetCell) { + if (!editing || !targetCell) return false; + if (!Number.isInteger(targetCell.row) || !Number.isInteger(targetCell.col)) return false; + const targetSheetId = normalizeWorkbookId(targetCell.sheetId); + const editingSheetId = normalizeWorkbookId(editing.sheetId); + return editing.row !== targetCell.row + || editing.col !== targetCell.col + || Boolean(targetSheetId && editingSheetId && targetSheetId !== editingSheetId); +} + +function buildSelectionStyleCells(focus, change = {}, maxCells = 5000) { + const r1 = Number(focus?.r1); + const c1 = Number(focus?.c1); + const r2 = Number(focus?.r2 ?? focus?.r1); + const c2 = Number(focus?.c2 ?? focus?.c1); + if (![r1, c1, r2, c2].every(Number.isInteger)) return []; + const rowStart = Math.min(r1, r2); + const rowEnd = Math.max(r1, r2); + const colStart = Math.min(c1, c2); + const colEnd = Math.max(c1, c2); + const count = (rowEnd - rowStart + 1) * (colEnd - colStart + 1); + if (count > maxCells) throw new RangeError(`Formatting selection exceeds ${maxCells} cells`); + const styleRole = String(change.styleRole || '').trim() || null; + const style = change.style && typeof change.style === 'object' ? change.style : null; + if (!styleRole && !style) return []; + const cells = []; + for (let row = rowStart; row <= rowEnd; row += 1) { + for (let col = colStart; col <= colEnd; col += 1) { + cells.push({ + row, + col, + ...(styleRole ? { styleRole } : {}), + ...(style ? { style } : {}), + }); + } + } + return cells; +} + +function proposalAcceptPlan(allCellRefs, selectedCellRefs, hasLayoutChanges) { + const all = [...new Set((allCellRefs || []).filter(Boolean))]; + const selectedSet = new Set((selectedCellRefs || []).filter((ref) => all.includes(ref))); + const selected = all.filter((ref) => selectedSet.has(ref)); + const layoutOnly = hasLayoutChanges && all.length === 0; + const allCellsSelected = all.length > 0 && selected.length === all.length; + const acceptsLayout = Boolean(hasLayoutChanges && (layoutOnly || allCellsSelected)); + return { + all, + selected, + layoutOnly, + allCellsSelected, + acceptsLayout, + // The Engine interprets omitted cellRefs as whole-proposal acceptance, + // which is the only atomic path that applies layout alongside cells. + payloadCellRefs: acceptsLayout ? null : selected, + }; +} + +function exportCopyPlan(sourcePath, fidelity) { + const source = String(sourcePath || '').trim().toLowerCase(); + const macroEnabled = source.endsWith('.xlsm'); + const excelSource = source.endsWith('.xlsx') || macroEnabled; + const canRoundTrip = fidelity && typeof fidelity === 'object' + ? fidelity.canRoundTrip ?? fidelity.can_round_trip + : undefined; + const acknowledgeFidelityLoss = Boolean(excelSource && canRoundTrip === false); + const lossyMacroRebuild = macroEnabled && acknowledgeFidelityLoss; + return { + macroEnabled, + excelSource, + canRoundTrip, + acknowledgeFidelityLoss, + lossyMacroRebuild, + extension: macroEnabled && !lossyMacroRebuild ? 'xlsm' : 'xlsx', + }; +} + +export { + agentRefreshTargetsCurrentWorkbook, + buildSelectionStyleCells, + createEditingDraft, + editingExpectedRevision, + exportCopyPlan, + gridSelectionNeedsEditCommit, + isComposingKey, + isSaveShortcut, + proposalAcceptPlan, +}; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/model.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/model.js new file mode 100644 index 00000000..bc709213 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/model.js @@ -0,0 +1,448 @@ +import { formatA1, parseA1 } from './a1.js'; +import { + LIVE_VIEW_SEMANTICS, + cellDisplayWithStyle, + normalizeSheetLayout, + snapshotParts, +} from './formatting.js'; +import { state } from './state.js'; +import { cellCacheKey } from './util.js'; + +const FOCUS_PREVIEW_MAX_CELLS = 200; +const VALID_WORKBOOK_MODES = new Set(['inspect', 'edit', 'author']); +const FRESH_CALCULATION_STATES = new Set([ + 'current', + 'ready', + 'calculated', + 'recalculated', + 'ok', + 'not-required', +]); + +function calculationStatusToken(status = state.meta?.calculationStatus) { + if (typeof status === 'string') return status.trim().toLowerCase().replaceAll('_', '-'); + if (!status || typeof status !== 'object') return ''; + return String(status.status || status.state || status.kind || '') + .trim() + .toLowerCase() + .replaceAll('_', '-'); +} + +function calculationStatusIsFresh(status = state.meta?.calculationStatus) { + return FRESH_CALCULATION_STATES.has(calculationStatusToken(status)); +} + +function cellHasFormulaEvidence(cell) { + return Boolean(cell && (cell.formulaEvidence === true || (typeof cell.f === 'string' && cell.f.length > 0))); +} + +function activeSheet() { + return (state.sheets || []).find((sheet) => sheet.id === state.activeSheetId) || state.sheets?.[0] || null; +} + +function sheetBounds(sheet = activeSheet()) { + return { + rows: Math.max(1, Number(sheet?.rows) || 50), + cols: Math.max(1, Number(sheet?.cols) || 26), + }; +} + +function normalizeFocusRange(focusLike = state.focus, sheet = activeSheet()) { + const bounds = sheetBounds(sheet); + let r1 = 0; + let c1 = 0; + let r2 = 0; + let c2 = 0; + if (focusLike?.a1) { + try { + const parsed = parseA1(focusLike.a1); + r1 = parsed.r1; + c1 = parsed.c1; + r2 = parsed.r2; + c2 = parsed.c2; + } catch (_error) { + // keep defaults + } + } else { + r1 = Number(focusLike?.r1) || 0; + c1 = Number(focusLike?.c1) || 0; + r2 = Number(focusLike?.r2 ?? focusLike?.r1) || 0; + c2 = Number(focusLike?.c2 ?? focusLike?.c1) || 0; + } + const startRow = Math.max(0, Math.min(Math.min(r1, r2), bounds.rows - 1)); + const startCol = Math.max(0, Math.min(Math.min(c1, c2), bounds.cols - 1)); + const endRow = Math.max(startRow, Math.min(Math.max(r1, r2), bounds.rows - 1)); + const endCol = Math.max(startCol, Math.min(Math.max(c1, c2), bounds.cols - 1)); + r1 = startRow; + c1 = startCol; + r2 = endRow; + c2 = endCol; + const a1 = formatA1(r1, c1, r2, c2); + const kind = focusLike?.kind || (r1 === r2 && c1 === c2 ? 'cell' : 'range'); + return { + sheetId: focusLike?.sheetId || sheet?.id || state.activeSheetId, + sheetName: focusLike?.sheetName || sheet?.name || null, + a1, + kind, + r1, + c1, + r2, + c2, + rowCount: r2 - r1 + 1, + columnCount: c2 - c1 + 1, + }; +} + +function cellDisplayValue(cell) { + return cellDisplayWithStyle(cell); +} + +function cellRawDisplayValue(cell) { + if (!cell) return ''; + if (cell.v != null) return String(cell.v); + const formula = cell.f ?? cell.formula; + return formula ? `=${String(formula).replace(/^=/, '')}` : ''; +} + +function cellEditValue(cell) { + if (!cell) return ''; + if (cell.f) return `=${cell.f}`; + if (cell.v == null) return ''; + return String(cell.v); +} + +function focusCacheCoverage(focus, sheet = activeSheet()) { + if (!sheet || !focus) { + return { loadedCells: 0, totalCells: 0, ratio: 0, complete: false }; + } + const totalCells = Math.max(0, focus.rowCount * focus.columnCount); + if (totalCells === 0) { + return { loadedCells: 0, totalCells: 0, ratio: 1, complete: true }; + } + + // Iterate the virtualized cache rather than the whole selection. A whole + // column/sheet focus can contain millions of cells while the cache remains + // intentionally bounded to fetched tiles. + const prefix = `${sheet.id}:`; + let loadedCells = 0; + for (const key of state.cells.keys()) { + if (!key.startsWith(prefix)) continue; + const coordinates = key.slice(prefix.length).split(','); + const row = Number(coordinates[0]); + const col = Number(coordinates[1]); + if ( + Number.isInteger(row) + && Number.isInteger(col) + && row >= focus.r1 + && row <= focus.r2 + && col >= focus.c1 + && col <= focus.c2 + ) { + loadedCells += 1; + } + } + const boundedLoaded = Math.min(totalCells, loadedCells); + return { + loadedCells: boundedLoaded, + totalCells, + ratio: boundedLoaded / totalCells, + complete: boundedLoaded === totalCells, + }; +} + +function buildPreviewTsv(focus, sheet = activeSheet(), coverage = null) { + if (!sheet) return null; + const cellTotal = focus.rowCount * focus.columnCount; + if (cellTotal <= 0 || cellTotal > FOCUS_PREVIEW_MAX_CELLS) return null; + const resolvedCoverage = coverage || focusCacheCoverage(focus, sheet); + if (!resolvedCoverage.complete) return null; + const rows = []; + for (let r = focus.r1; r <= focus.r2; r += 1) { + const row = []; + for (let c = focus.c1; c <= focus.c2; c += 1) { + const cell = state.cells.get(cellCacheKey(sheet.id, r, c)); + // Agent focus remains grounded in raw workbook values/formulas; visual + // number formatting is a Surface concern and must not rewrite evidence. + row.push(cellRawDisplayValue(cell).replaceAll('\t', ' ').replaceAll('\n', ' ')); + } + rows.push(row.join('\t')); + } + return rows.join('\n'); +} + +function selectionValueSummary(focus, sheet = activeSheet(), coverage = null) { + if (!sheet) return null; + const cellTotal = focus.rowCount * focus.columnCount; + if (cellTotal <= 0 || cellTotal > 5000) return null; + const resolvedCoverage = coverage || focusCacheCoverage(focus, sheet); + if (!resolvedCoverage.complete) return null; + let numericCount = 0; + let textCount = 0; + let emptyCount = 0; + let formulaCount = 0; + let sum = 0; + for (let r = focus.r1; r <= focus.r2; r += 1) { + for (let c = focus.c1; c <= focus.c2; c += 1) { + const cell = state.cells.get(cellCacheKey(sheet.id, r, c)); + const hasFormula = cellHasFormulaEvidence(cell); + if (!cell || (cell.v == null && !hasFormula)) { + emptyCount += 1; + continue; + } + if (hasFormula) formulaCount += 1; + if (typeof cell.v === 'number') { + numericCount += 1; + sum += cell.v; + } else if (cell.v != null && cell.v !== '') { + textCount += 1; + } + } + } + return { + cellCount: cellTotal, + numericCount, + textCount, + emptyCount, + formulaCount, + sum, + avg: numericCount > 0 ? sum / numericCount : null, + }; +} + +function buildFocusPayload(role = 'ambient') { + const sheet = activeSheet(); + const focus = normalizeFocusRange(state.focus, sheet); + const coverage = focusCacheCoverage(focus, sheet); + const summary = selectionValueSummary(focus, sheet, coverage); + const cellTotal = focus.rowCount * focus.columnCount; + const calculationStatus = state.meta?.calculationStatus || null; + // Cached values are evidence only when the workbook explicitly reports a + // fresh/not-required calculation state. Missing, cached, or stale metadata + // is fail-closed even when the selected cells appear formula-free: shared + // formula followers may not carry formula text of their own. + const formulaResultsFresh = calculationStatusIsFresh(calculationStatus); + const previewTsv = formulaResultsFresh + ? buildPreviewTsv(focus, sheet, coverage) + : null; + const previewOmittedReason = !coverage.complete + ? 'cache-incomplete' + : !formulaResultsFresh && cellTotal <= FOCUS_PREVIEW_MAX_CELLS + ? 'formula-results-stale' + : cellTotal > FOCUS_PREVIEW_MAX_CELLS + ? 'selection-too-large' + : null; + return { + type: 'spreadsheet-focus', + role, + sessionId: state.sessionId || undefined, + workbookId: state.workbookId, + workbookPath: state.path || state.meta?.path || undefined, + sheetId: focus.sheetId, + sheetName: focus.sheetName || sheet?.name || undefined, + a1: focus.a1, + selectionKind: focus.kind, + rowCount: focus.rowCount, + columnCount: focus.columnCount, + previewTsv: previewTsv || undefined, + previewTruncated: cellTotal > FOCUS_PREVIEW_MAX_CELLS, + previewOmitted: Boolean(previewOmittedReason), + previewOmittedReason: previewOmittedReason || undefined, + cacheCoverage: coverage.ratio, + cacheComplete: coverage.complete, + formulaResultsFresh, + calculationStatus: calculationStatus || undefined, + fidelity: { + ...(state.meta?.fidelity || {}), + liveViewSemantics: LIVE_VIEW_SEMANTICS, + presentationSemanticsRendered: true, + cellStylesRendered: true, + commonNumberFormatsRendered: true, + layoutMetadataRendered: true, + }, + cacheLoadedCells: coverage.loadedCells, + cacheTotalCells: coverage.totalCells, + capturedAt: Date.now(), + valueSummary: summary + ? { + cellCount: summary.cellCount, + numericCount: formulaResultsFresh ? summary.numericCount : undefined, + textCount: formulaResultsFresh ? summary.textCount : undefined, + emptyCount: formulaResultsFresh ? summary.emptyCount : undefined, + formulaCount: summary.formulaCount, + } + : undefined, + includeFocusOnSend: state.includeFocusOnSend, + mode: state.mode, + revision: state.meta?.revision ?? undefined, + schemaVersion: 1, + }; +} + +function mergeReadIntoCache(readResult) { + if (!readResult) return; + const sheetId = readResult.sheetId || state.activeSheetId; + if (!sheetId || !Array.isArray(readResult.values)) return; + let range; + try { + range = parseA1(readResult.a1 || 'A1'); + } catch (_error) { + return; + } + const formulaMap = new Map(); + for (const item of readResult.formulas || []) { + formulaMap.set(`${item.row},${item.col}`, item); + } + const sparseCells = new Map(); + for (const item of readResult.cells || []) { + const row = Number(item?.row ?? item?.r); + const col = Number(item?.col ?? item?.c); + if (!Number.isInteger(row) || !Number.isInteger(col)) continue; + sparseCells.set(`${row},${col}`, item); + } + const styleMatrix = Array.isArray(readResult.styles) + ? readResult.styles + : Array.isArray(readResult.cellStyles) + ? readResult.cellStyles + : null; + for (let i = 0; i < readResult.values.length; i += 1) { + const rowVals = readResult.values[i] || []; + for (let j = 0; j < rowVals.length; j += 1) { + const row = range.r1 + i; + const col = range.c1 + j; + const key = cellCacheKey(sheetId, row, col); + const formulaItem = formulaMap.get(`${row},${col}`) || null; + const sparse = sparseCells.get(`${row},${col}`) || null; + const rawValue = rowVals[j]; + const embedded = rawValue && typeof rawValue === 'object' && !Array.isArray(rawValue) + ? rawValue + : null; + const value = embedded + ? embedded.v ?? embedded.value ?? null + : sparse + ? sparse.v ?? sparse.value ?? rawValue + : rawValue; + const formula = sparse?.formula ?? sparse?.f ?? embedded?.formula ?? embedded?.f ?? formulaItem?.formula ?? null; + const matrixStyle = styleMatrix?.[i]?.[j] || null; + const style = sparse?.style || embedded?.style || formulaItem?.style || matrixStyle || null; + state.cells.set(key, { + v: value, + f: formula, + t: formula ? 'f' : sparse?.t ?? embedded?.t ?? (value == null ? null : typeof value === 'number' ? 'n' : 's'), + formulaEvidence: Boolean(formula || sparse?.formulaEvidence || embedded?.formulaEvidence || formulaItem?.formulaEvidence), + formulaType: sparse?.formulaType || embedded?.formulaType || formulaItem?.formulaType || null, + formulaRef: sparse?.formulaRef || embedded?.formulaRef || formulaItem?.formulaRef || null, + style, + }); + } + } + // Styled empty cells can be omitted from values[][] yet still need to render. + for (const [coordinates, sparse] of sparseCells) { + const [row, col] = coordinates.split(',').map(Number); + const key = cellCacheKey(sheetId, row, col); + const existing = state.cells.get(key) || {}; + state.cells.set(key, { + ...existing, + v: sparse.v ?? sparse.value ?? existing.v ?? null, + f: sparse.formula ?? sparse.f ?? existing.f ?? null, + t: sparse.t ?? existing.t ?? null, + formulaEvidence: Boolean(sparse.formulaEvidence || sparse.formula || sparse.f || existing.formulaEvidence), + formulaType: sparse.formulaType || existing.formulaType || null, + formulaRef: sparse.formulaRef || existing.formulaRef || null, + style: sparse.style || existing.style || null, + }); + } + if (readResult.layout) { + state.sheetLayouts.set(sheetId, normalizeSheetLayout(readResult.layout)); + } +} + +function proposalCellSet(proposal = state.proposal) { + const set = new Map(); + if (!proposal?.cells?.length) return set; + const activeSheetId = state.activeSheetId; + if (proposal.sheetId && activeSheetId && proposal.sheetId !== activeSheetId) return set; + for (const cell of proposal.cells) { + const cellSheetId = cell.sheetId || proposal.sheetId || activeSheetId; + if (activeSheetId && cellSheetId && cellSheetId !== activeSheetId) continue; + const row = Number(cell.row ?? cell.r); + const col = Number(cell.col ?? cell.c); + if (!Number.isInteger(row) || !Number.isInteger(col)) continue; + set.set(`${row},${col}`, cell); + } + return set; +} + +function applyMeta(meta) { + if (!meta) return; + const previousWorkbookId = state.workbookId; + const nextWorkbookId = meta.workbookId || previousWorkbookId; + const workbookChanged = Boolean(nextWorkbookId && previousWorkbookId !== nextWorkbookId); + const hasPath = Object.prototype.hasOwnProperty.call(meta, 'path'); + const hasSourcePath = Object.prototype.hasOwnProperty.call(meta, 'sourcePath'); + state.meta = meta; + state.workbookId = nextWorkbookId; + if (workbookChanged) state.sheetLayouts.clear(); + // Workbook identity owns its source path. In particular, a native/new + // workbook with a null path must never inherit the previous .xlsx/.xlsm + // source merely because both workbooks reuse this surface instance. + if (hasPath) { + state.path = meta.path ?? null; + } else if (hasSourcePath) { + state.path = meta.sourcePath ?? null; + } else if (workbookChanged) { + state.path = null; + } + state.dirty = Boolean(meta.dirty); + state.activeSheetId = meta.activeSheetId || state.activeSheetId; + const persistedMode = String(meta.mode || '').trim().toLowerCase(); + if (VALID_WORKBOOK_MODES.has(persistedMode)) { + state.mode = persistedMode; + } + if (Array.isArray(meta.sheets)) { + state.sheets = meta.sheets; + for (const sheet of meta.sheets) { + if (sheet?.id && sheet.layout) { + state.sheetLayouts.set(sheet.id, normalizeSheetLayout(sheet.layout)); + } + } + } + if (meta.focus?.a1) { + state.focus = normalizeFocusRange({ + ...meta.focus, + sheetId: meta.focus.sheetId || state.activeSheetId, + }); + } +} + +function proposalSnapshotDisplay(snapshot) { + return snapshotParts(snapshot).primary; +} + +function proposalBeforeDisplay(cell) { + return proposalSnapshotDisplay(cell?.before); +} + +function proposalAfterDisplay(cell) { + return proposalSnapshotDisplay(cell?.after); +} + +export { + FOCUS_PREVIEW_MAX_CELLS, + activeSheet, + applyMeta, + buildFocusPayload, + buildPreviewTsv, + calculationStatusIsFresh, + cellDisplayValue, + cellRawDisplayValue, + cellEditValue, + mergeReadIntoCache, + normalizeFocusRange, + focusCacheCoverage, + proposalAfterDisplay, + proposalBeforeDisplay, + proposalSnapshotDisplay, + proposalCellSet, + selectionValueSummary, + sheetBounds, +}; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/proposal.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/proposal.js new file mode 100644 index 00000000..cec72400 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/proposal.js @@ -0,0 +1,584 @@ +import { callExcel } from './backend.js'; +import { formatA1 } from './a1.js'; +import { applyMeta } from './model.js'; +import { + layoutDifferences, + proposalHasLayoutChanges, + proposalValidationDetails, + snapshotParts, + styleDifferences, +} from './formatting.js'; +import { state, invalidateCells } from './state.js'; +import { t } from './i18n.js'; +import { escapeHtml, rootElement } from './util.js'; +import { refreshViewportCells, renderGrid } from './grid.js'; +import { showToast, updateChrome } from './views.js'; +import { proposalAcceptPlan } from './interaction.js'; + +const PROPOSAL_DETAIL_LIMIT = 300; + +function proposalInteractionLocked() { + return state.loading || state.dialogPending || state.modePending; +} + +function proposalCellRef(cell, proposal = state.proposal) { + const explicit = cell?.cellRef ?? cell?.ref ?? cell?.a1; + if (explicit && typeof explicit === 'object') { + const explicitA1 = explicit.a1; + if (explicitA1 != null && String(explicitA1).trim()) return String(explicitA1).trim(); + const explicitRow = Number(explicit.row ?? explicit.r); + const explicitCol = Number(explicit.col ?? explicit.c); + if (Number.isInteger(explicitRow) && Number.isInteger(explicitCol)) { + const sheetId = explicit.sheetId || cell?.sheetId || proposal?.sheetId || ''; + const a1 = formatA1(explicitRow, explicitCol); + return sheetId ? `${sheetId}!${a1}` : a1; + } + } + if (explicit != null && String(explicit).trim()) return String(explicit).trim(); + const row = Number(cell?.row ?? cell?.r); + const col = Number(cell?.col ?? cell?.c); + if (!Number.isInteger(row) || !Number.isInteger(col)) return ''; + const a1 = formatA1(row, col); + const sheetId = cell?.sheetId || proposal?.sheetId || ''; + return sheetId ? `${sheetId}!${a1}` : a1; +} + +function proposalCellRefs(proposal = state.proposal) { + if (!Array.isArray(proposal?.cells)) return []; + return proposal.cells.map((cell) => proposalCellRef(cell, proposal)).filter(Boolean); +} + +function visibleProposalCellRefs(proposal = state.proposal) { + if (!Array.isArray(proposal?.cells)) return []; + return proposal.cells + .slice(0, PROPOSAL_DETAIL_LIMIT) + .map((cell) => proposalCellRef(cell, proposal)) + .filter(Boolean); +} + +function hiddenProposalSelection(proposal = state.proposal) { + if (!Array.isArray(proposal?.cells) || proposal.cells.length <= PROPOSAL_DETAIL_LIMIT) { + return { count: 0, selected: 0 }; + } + const hiddenRefs = proposal.cells + .slice(PROPOSAL_DETAIL_LIMIT) + .map((cell) => proposalCellRef(cell, proposal)) + .filter(Boolean); + return { + count: hiddenRefs.length, + selected: hiddenRefs.filter((ref) => state.proposalSelectedCellRefs.has(ref)).length, + }; +} + +function hiddenSelectionText(proposal = state.proposal) { + const hidden = hiddenProposalSelection(proposal); + if (hidden.count === 0) return ''; + if (hidden.selected === 0) return t('proposalHiddenUnselected', { count: hidden.count }); + if (hidden.selected === hidden.count) return t('proposalHiddenSelected', { count: hidden.count }); + return t('proposalHiddenPartiallySelected', { + selected: hidden.selected, + count: hidden.count, + }); +} + +function adoptProposal(proposal, options = {}) { + const previous = state.proposal; + const next = proposal || null; + const nextRefs = proposalCellRefs(next); + const preserveSelection = Boolean( + options.preserveSelection + && previous?.id + && next?.id + && previous.id === next.id, + ); + const selected = preserveSelection + ? new Set(nextRefs.filter((ref) => state.proposalSelectedCellRefs.has(ref))) + : new Set(visibleProposalCellRefs(next)); + + state.proposal = next; + state.proposalSelectedCellRefs = selected; + if (!next) state.proposalExpanded = false; + return next; +} + +function proposalIsStale(proposal = state.proposal) { + if (!proposal) return false; + if (proposal.stale === true) return true; + const baseRevision = proposal.baseRevision; + const revision = state.meta?.revision; + if (baseRevision == null || revision == null) return false; + return String(baseRevision) !== String(revision); +} + +function proposalIntent(proposal = state.proposal) { + const intent = proposal?.intent; + if (typeof intent === 'string') return intent.trim(); + if (intent && typeof intent === 'object') { + return String(intent.summary || intent.description || intent.operation || '').trim(); + } + return ''; +} + +function validationSummary(proposal = state.proposal) { + const validation = proposal?.validation; + if (validation == null) return null; + if (typeof validation === 'string') { + return { kind: 'neutral', text: validation }; + } + if (typeof validation === 'boolean') { + return validation + ? { kind: 'ok', text: t('validationPassed') } + : { kind: 'error', text: t('validationFailed') }; + } + if (Array.isArray(validation)) { + return validation.length + ? { kind: 'warning', text: t('validationIssues', { count: validation.length }) } + : { kind: 'ok', text: t('validationPassed') }; + } + if (typeof validation === 'object') { + const details = proposalValidationDetails(proposal); + if (details.invalid) { + return { kind: 'error', text: t('validationErrors', { count: details.errors.length || 1 }) }; + } + if (details.warnings.length > 0) { + return { kind: 'warning', text: t('validationWarnings', { count: details.warnings.length }) }; + } + if (validation.valid === true || ['passed', 'valid', 'ok'].includes(String(validation.status || '').toLowerCase())) { + return { kind: 'ok', text: t('validationPassed') }; + } + if (validation.status) return { kind: 'neutral', text: String(validation.status) }; + } + return null; +} + +function snapshotDisplay(snapshot) { + return snapshotParts(snapshot).primary || t('emptyValue'); +} + +function proposalValidationInvalid(proposal = state.proposal) { + return proposalValidationDetails(proposal).invalid; +} + +async function refreshProposal(options = {}) { + if (!state.workbookId) { + adoptProposal(null); + return null; + } + const result = await callExcel('getProposal', { workbookId: state.workbookId }); + return adoptProposal(result?.proposal || null, options); +} + +async function acceptProposal(cellRefs = null) { + if (!state.workbookId || !state.proposal) return false; + if (state.loading || state.dialogPending) { + showToast('error', t('operationPending')); + return false; + } + if (state.modePending) { + showToast('error', t('modeChangePending')); + return false; + } + if (state.mode === 'inspect') { + showToast('error', t('inspectAcceptBlocked')); + return false; + } + if (proposalIsStale()) { + showToast('error', t('proposalStaleHint')); + return false; + } + if (proposalValidationInvalid()) { + showToast('error', t('proposalInvalidHint')); + return false; + } + const selected = Array.isArray(cellRefs) + ? cellRefs.filter(Boolean) + : [...state.proposalSelectedCellRefs]; + const hasLayoutChanges = proposalHasLayoutChanges(state.proposal); + const plan = proposalAcceptPlan( + proposalCellRefs(state.proposal), + selected, + hasLayoutChanges, + ); + if (!plan.layoutOnly && plan.selected.length === 0) { + showToast('error', t('proposalSelectAtLeastOne')); + return false; + } + + try { + state.loading = true; + updateChrome(); + renderProposalBar(); + const payload = { + workbookId: state.workbookId, + proposalId: state.proposal.id, + baseRevision: state.proposal.baseRevision ?? state.meta?.revision ?? undefined, + expectedRevision: state.proposal.baseRevision ?? state.meta?.revision ?? undefined, + }; + if (plan.payloadCellRefs) payload.cellRefs = plan.payloadCellRefs; + const result = await callExcel('acceptProposal', payload); + applyMeta(result?.meta); + invalidateCells(); + // Keep the user's exclusions authoritative. After a partial accept the + // remaining cells must not silently become selected again. + await refreshProposal({ preserveSelection: true }); + await refreshViewportCells(); + renderGrid(); + state.status = plan.layoutOnly + ? t('statusAcceptedLayout') + : plan.acceptsLayout + ? t('statusAcceptedCellsAndLayout', { count: plan.selected.length }) + : hasLayoutChanges + ? t('statusAcceptedCellsLayoutPending', { count: plan.selected.length }) + : t('statusAcceptedCells', { count: plan.selected.length }); + return true; + } catch (error) { + showToast('error', error?.message || t('proposalAcceptFailed')); + return false; + } finally { + state.loading = false; + updateChrome(); + renderProposalBar(); + } +} + +async function rejectProposal() { + if (!state.workbookId || !state.proposal) return false; + if (state.loading || state.dialogPending) { + showToast('error', t('operationPending')); + return false; + } + if (state.modePending) { + showToast('error', t('modeChangePending')); + return false; + } + try { + state.loading = true; + updateChrome(); + renderProposalBar(); + const result = await callExcel('rejectProposal', { + workbookId: state.workbookId, + proposalId: state.proposal.id, + expectedRevision: state.meta?.revision ?? undefined, + }); + applyMeta(result?.meta); + adoptProposal(null); + renderGrid(); + state.status = t('statusRejected'); + return true; + } catch (error) { + showToast('error', error?.message || t('proposalRejectFailed')); + return false; + } finally { + state.loading = false; + updateChrome(); + renderProposalBar(); + } +} + +function toggleProposalExpanded() { + if (proposalInteractionLocked()) return false; + state.proposalExpanded = !state.proposalExpanded; + renderProposalBar(); + return true; +} + +function updateProposalSelectionChrome() { + const bar = rootElement()?.querySelector('[data-proposal-bar]'); + if (!bar || !state.proposal) return; + const count = state.proposalSelectedCellRefs.size; + const hasLayoutChanges = proposalHasLayoutChanges(state.proposal); + const plan = proposalAcceptPlan(proposalCellRefs(), [...state.proposalSelectedCellRefs], hasLayoutChanges); + const selected = bar.querySelector('[data-proposal-selected-count]'); + if (selected) selected.textContent = t('proposalSelected', { count }); + const accept = bar.querySelector('[data-action="accept-proposal"]'); + if (accept) { + accept.textContent = plan.layoutOnly + ? t('acceptLayout') + : plan.acceptsLayout + ? t('acceptAllWithLayout', { count }) + : hasLayoutChanges + ? t('acceptSelectedLayoutPending', { count }) + : t('acceptSelected', { count }); + accept.disabled = proposalInteractionLocked() + || state.mode === 'inspect' + || proposalIsStale() + || proposalValidationInvalid() + || (!plan.layoutOnly && count === 0); + } + bar.querySelectorAll('[data-proposal-hidden-scope]').forEach((hiddenScope) => { + hiddenScope.textContent = hiddenSelectionText(); + }); +} + +function toggleProposalCell(ref, checked) { + if (!ref || proposalInteractionLocked()) return false; + if (checked) state.proposalSelectedCellRefs.add(ref); + else state.proposalSelectedCellRefs.delete(ref); + updateProposalSelectionChrome(); + return true; +} + +function selectAllProposalCells() { + if (proposalInteractionLocked()) return false; + const refs = proposalCellRefs(); + const hiddenCount = hiddenProposalSelection().count; + if ( + hiddenCount > 0 + && !window.confirm(t('proposalSelectAllConfirm', { count: refs.length, hidden: hiddenCount })) + ) { + return false; + } + state.proposalSelectedCellRefs = new Set(refs); + rootElement()?.querySelectorAll('[data-action="toggle-proposal-cell"]').forEach((input) => { + input.checked = true; + }); + updateProposalSelectionChrome(); + return true; +} + +function clearProposalCellSelection() { + if (proposalInteractionLocked()) return false; + state.proposalSelectedCellRefs = new Set(); + rootElement()?.querySelectorAll('[data-action="toggle-proposal-cell"]').forEach((input) => { + input.checked = false; + }); + updateProposalSelectionChrome(); + return true; +} + +function styleValueSummary(key, value) { + if (value == null || value === '') return t('styleNone'); + if (typeof value === 'string' || typeof value === 'number') return String(value); + if (key === 'font') { + return [ + value.bold ? t('styleBold') : '', + value.italic ? t('styleItalic') : '', + value.size ? `${value.size}pt` : '', + value.color || '', + ].filter(Boolean).join(' · ') || t('styleNone'); + } + if (key === 'alignment') { + return [value.horizontal, value.vertical, value.wrapText ? t('styleWrap') : ''].filter(Boolean).join(' · ') || t('styleNone'); + } + if (key === 'border') { + return Object.entries(value) + .map(([side, detail]) => `${t(`styleSide_${side}`)} ${detail?.style || ''}`.trim()) + .join(' · ') || t('styleNone'); + } + return JSON.stringify(value); +} + +function styleDiffMarkup(cell) { + const diffs = styleDifferences(cell?.before, cell?.after); + if (diffs.length === 0) return ''; + return ` +
+ ${diffs.map((diff) => { + const label = t(`style_${diff.key}`); + const before = styleValueSummary(diff.key, diff.before); + const after = styleValueSummary(diff.key, diff.after); + return `${escapeHtml(label)} ${escapeHtml(before)} ${escapeHtml(after)}`; + }).join('')} +
+ `; +} + +function snapshotMarkup(snapshot, kind) { + const parts = snapshotParts(snapshot); + const primary = parts.primary || t('emptyValue'); + return ` + + ${escapeHtml(primary)} + ${parts.secondary ? `${escapeHtml(t('cachedValue', { value: parts.secondary }))}` : ''} + + `; +} + +function validationIssuesMarkup(proposal) { + const details = proposalValidationDetails(proposal); + const issues = [ + ...details.errors.map((text) => ({ kind: 'error', text })), + ...details.warnings.map((text) => ({ kind: 'warning', text })), + ]; + if (issues.length === 0) return ''; + const visible = issues.slice(0, 8); + return ` +
+ ${escapeHtml(t(details.invalid ? 'validationMustFix' : 'validationReview'))} +
    + ${visible.map((issue) => `
  • ${escapeHtml(issue.text)}
  • `).join('')} +
+ ${issues.length > visible.length ? `${escapeHtml(t('validationMore', { count: issues.length - visible.length }))}` : ''} +
+ `; +} + +function layoutValueSummary(key, value) { + if (value == null) return t('layoutOff'); + if (key === 'freezePanes') { + return t('layoutFreezeValue', { rows: value.rows || 0, columns: value.columns || 0 }); + } + if (key === 'autoFilter') return value?.a1 || t('layoutOff'); + if (Array.isArray(value)) { + if (value.length === 0) return t('layoutDefault'); + return value.map((entry) => { + const range = entry.start === entry.end ? `${entry.start + 1}` : `${entry.start + 1}–${entry.end + 1}`; + const workbookValue = entry.value != null + ? `${entry.value}${entry.unit === 'points' ? 'pt' : ''}` + : t('layoutAutoFit'); + return `${range}: ${workbookValue}`; + }).join(', '); + } + return String(value); +} + +function layoutDiffMarkup(proposal) { + const diffs = layoutDifferences(proposal); + if (diffs.length === 0) return ''; + return ` +
+

${escapeHtml(t('layoutChanges'))}

+ ${diffs.map((diff) => ` +
+ ${escapeHtml(t(`layout_${diff.key}`))} + ${escapeHtml(layoutValueSummary(diff.key, diff.before))} + + ${escapeHtml(layoutValueSummary(diff.key, diff.after))} +
+ `).join('')} +
+ `; +} + +function renderProposalDetails(proposal) { + if (!state.proposalExpanded) return ''; + const locked = proposalInteractionLocked(); + const disabled = locked ? ' disabled' : ''; + const cells = Array.isArray(proposal.cells) ? proposal.cells : []; + const visible = cells.slice(0, PROPOSAL_DETAIL_LIMIT); + const rows = visible.map((cell) => { + const ref = proposalCellRef(cell, proposal); + const checked = state.proposalSelectedCellRefs.has(ref); + const row = Number(cell.row ?? cell.r); + const col = Number(cell.col ?? cell.c); + const location = cell.a1 || ( + Number.isInteger(row) && Number.isInteger(col) ? formatA1(row, col) : ref + ); + const before = snapshotDisplay(cell.before); + const after = snapshotDisplay(cell.after); + return ` + + `; + }).join(''); + const remainder = Math.max(0, cells.length - visible.length); + const hiddenText = hiddenSelectionText(proposal); + const cellDetails = cells.length > 0 ? ` +
+ ${t('proposalSelected', { count: state.proposalSelectedCellRefs.size })} + + +
+
+
+ + ${t('cell')} + ${t('before')} + ${t('after')} +
+ ${rows} +
+ ${remainder > 0 ? `

${escapeHtml(hiddenText)}

` : ''} + ` : ''; + return ` +
+ ${cellDetails} + ${layoutDiffMarkup(proposal)} +
+ `; +} + +function renderProposalBar() { + const bar = rootElement()?.querySelector('[data-proposal-bar]'); + if (!bar) return; + if (!state.proposal) { + bar.hidden = true; + bar.innerHTML = ''; + return; + } + const proposal = state.proposal; + const count = Array.isArray(proposal.cells) + ? proposal.cells.length + : proposal.cellCount || 0; + const range = proposal.a1 + ? `${proposal.sheetName ? `${proposal.sheetName}!` : ''}${proposal.a1}` + : proposal.sheetName || t('layoutChanges'); + const stale = proposalIsStale(proposal); + const validation = validationSummary(proposal); + const intent = proposalIntent(proposal); + const selectedCount = state.proposalSelectedCellRefs.size; + const hasLayoutChanges = proposalHasLayoutChanges(proposal); + const acceptPlan = proposalAcceptPlan(proposalCellRefs(proposal), [...state.proposalSelectedCellRefs], hasLayoutChanges); + const layoutOnly = acceptPlan.layoutOnly; + const hiddenText = hiddenSelectionText(proposal); + const locked = proposalInteractionLocked(); + const validationInvalid = proposalValidationInvalid(proposal); + const acceptDisabled = locked + || state.mode === 'inspect' + || stale + || validationInvalid + || (!layoutOnly && selectedCount === 0); + const rejectDisabled = locked; + bar.hidden = false; + bar.dataset.stale = stale ? 'true' : 'false'; + bar.innerHTML = ` +
+
+ ${t('proposalTitle')} + ${intent ? `${escapeHtml(intent)}` : ''} + + ${layoutOnly ? t('proposalLayoutChange') : t('proposalCells', { count })} + ${hiddenText ? `${escapeHtml(hiddenText)}` : ''} + ${validation ? `${escapeHtml(validation.text)}` : ''} + ${stale ? `${t('proposalStale')}` : ''} +
+
+ + + +
+
+ ${stale ? `

${t('proposalStaleHint')}

` : ''} + ${hasLayoutChanges && !layoutOnly ? `

${t(acceptPlan.acceptsLayout ? 'proposalLayoutAllHint' : 'proposalLayoutPartialHint')}

` : ''} + ${validationIssuesMarkup(proposal)} + ${validationInvalid ? `

${t('proposalInvalidHint')}

` : ''} + ${renderProposalDetails(proposal)} + `; +} + +export { + acceptProposal, + adoptProposal, + clearProposalCellSelection, + proposalCellRef, + proposalCellRefs, + proposalIsStale, + refreshProposal, + rejectProposal, + renderProposalBar, + selectAllProposalCells, + toggleProposalCell, + toggleProposalExpanded, +}; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/render.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/render.js new file mode 100644 index 00000000..941b0a5f --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/render.js @@ -0,0 +1,25 @@ +import { renderGrid } from './grid.js'; +import { renderProposalBar } from './proposal.js'; +import { state } from './state.js'; +import { ensureShell, updateChrome } from './views.js'; + +/** + * Coalesced render: build the shell once, then apply targeted updates. + * The grid keeps its own scroll position and DOM identity across renders. + */ +function render() { + if (state.renderQueued) return; + state.renderQueued = true; + queueMicrotask(() => { + state.renderQueued = false; + const root = ensureShell(); + if (!root) return; + updateChrome(); + renderProposalBar(); + if (state.workbookId) { + renderGrid(); + } + }); +} + +export { render }; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/state.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/state.js new file mode 100644 index 00000000..026d2d23 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/state.js @@ -0,0 +1,82 @@ +const state = { + locale: navigator.language || 'en-US', + route: '/sheet', + tabId: null, + sessionId: null, + workspacePath: null, + + workbookId: null, + path: null, + meta: null, + sheets: [], + activeSheetId: null, + + focus: { + sheetId: null, + a1: 'A1', + kind: 'cell', + r1: 0, + c1: 0, + r2: 0, + c2: 0, + }, + proposal: null, + proposalExpanded: false, + proposalSelectedCellRefs: new Set(), + + history: { + canUndo: false, + canRedo: false, + entries: [], + }, + + viewport: { + scrollRow: 0, + scrollCol: 0, + visibleRows: 40, + visibleCols: 16, + }, + // Cell cache keyed `${sheetId}:${row},${col}` plus tile bookkeeping so + // scrolling only fetches ranges we have not read yet. + cells: new Map(), + fetchedTiles: new Set(), + // Canonical per-sheet presentation metadata returned by readRange/meta. + // Kept separate from cell cache because layout applies to empty cells too. + sheetLayouts: new Map(), + + dirty: false, + loading: false, + dialogPending: false, + status: null, + includeFocusOnSend: true, + mode: 'edit', + modePending: false, + pendingMode: null, + editing: null, + editCommitPromise: null, + selectionDragging: false, + selectionAnchor: null, + + bootDone: false, + bootChain: null, + pendingLaunchPath: null, + + renderQueued: false, + shellBuilt: false, + focusSyncTimer: null, + viewportFetchTimer: null, + agentRefreshTimer: null, + pendingAgentRefresh: null, + toastTimer: null, + lastFocusSyncKey: null, + lastRenderedWindow: null, + lastSheetTabsKey: null, +}; + +function invalidateCells() { + state.cells.clear(); + state.fetchedTiles.clear(); + state.lastRenderedWindow = null; +} + +export { state, invalidateCells }; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/util.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/util.js new file mode 100644 index 00000000..2b652efd --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/util.js @@ -0,0 +1,65 @@ +function runtime() { + return window.app || {}; +} + +function clamp(value, min, max) { + return Math.min(max, Math.max(min, value)); +} + +function asElement(node) { + if (!node) return null; + return node.nodeType === 1 ? node : node.parentElement || null; +} + +function closestElement(target, selector) { + const element = asElement(target); + return typeof element?.closest === 'function' ? element.closest(selector) : null; +} + +function uid(prefix = 'el') { + return `${prefix}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`; +} + +function escapeHtml(value) { + return String(value ?? '') + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('"', '"') + .replaceAll("'", '''); +} + +function bridgeOutput(result) { + if (result?.bridgeResult?.output !== undefined) return result.bridgeResult.output; + if (result?.output !== undefined) return result.output; + return result; +} + +function rootElement() { + return document.getElementById('excelLiveRoot'); +} + +function cellCacheKey(sheetId, row, col) { + return `${sheetId}:${row},${col}`; +} + +function normalizePathForCompare(value) { + const normalized = String(value || '').replaceAll('\\', '/'); + const platform = typeof navigator === 'undefined' + ? '' + : String(navigator.userAgentData?.platform || navigator.platform || ''); + return /^win/i.test(platform) ? normalized.toLowerCase() : normalized; +} + +export { + asElement, + bridgeOutput, + cellCacheKey, + clamp, + closestElement, + escapeHtml, + normalizePathForCompare, + rootElement, + runtime, + uid, +}; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/views.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/views.js new file mode 100644 index 00000000..0164e637 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/src/views.js @@ -0,0 +1,514 @@ +import { escapeHtml, rootElement } from './util.js'; +import { t } from './i18n.js'; +import { state } from './state.js'; +import { proposalHasLayoutChanges, proposalValidationDetails } from './formatting.js'; +import { + activeSheet, + calculationStatusIsFresh, + normalizeFocusRange, + selectionValueSummary, +} from './model.js'; + +const ICONS = { + logo: '', + newWorkbook: '', + open: '', + save: '', + exportCopy: '', + export: '', + undo: '', + redo: '', + insertRow: '', + insertCol: '', + pin: '', + spark: '', + add: '', + empty: '', +}; + +function iconButton(action, icon, labelKey, extraClass = '') { + return ``; +} + +function ensureShell() { + const root = rootElement(); + if (!root) return null; + if (state.shellBuilt && root.dataset.shell === 'ready') return root; + + root.className = 'excel-live'; + root.dataset.shell = 'ready'; + root.innerHTML = ` +
+
+ + + +
+
+ ${iconButton('new-workbook', 'newWorkbook', 'newWorkbook')} + ${iconButton('open-workbook', 'open', 'openWorkbook')} + ${iconButton('save-workbook', 'exportCopy', 'save')} + ${iconButton('export-csv', 'export', 'exportCsv')} + + ${iconButton('undo', 'undo', 'undo')} + ${iconButton('redo', 'redo', 'redo')} + + ${iconButton('insert-row', 'insertRow', 'insertRow')} + ${iconButton('insert-col', 'insertCol', 'insertCol')} +
+
+
+ + + +
+ + + ${iconButton('pin-focus', 'pin', 'pinFocus')} + +
+
+ +
+ +
+ + + + +
+ + + + + +
+ +
+ + + + +
+ + + + + +
+ + + +
+
+

+
+
+
+ +
+ +
+
+ +
+
+
+
+ `; + + state.shellBuilt = true; + applyStaticTexts(root); + return root; +} + +function applyStaticTexts(root = rootElement()) { + if (!root) return; + root.querySelectorAll('[data-label-key]').forEach((node) => { + const label = t(node.dataset.labelKey); + node.setAttribute('aria-label', label); + node.setAttribute('title', label); + if (node.classList.contains('el-mode__btn')) { + node.textContent = label; + } + }); + root.querySelectorAll('[data-text-key]').forEach((node) => { + node.textContent = t(node.dataset.textKey); + }); + const formatbar = root.querySelector('[data-formatbar]'); + if (formatbar) formatbar.setAttribute('aria-label', t('formatStyles')); + const formatPresets = root.querySelector('.el-formatbar__presets'); + if (formatPresets) formatPresets.setAttribute('aria-label', t('formatStyles')); + const fillInput = root.querySelector('[data-action="format-fill"]'); + if (fillInput) fillInput.setAttribute('aria-label', t('formatFill')); + const numberSelect = root.querySelector('[data-action="format-number"]'); + if (numberSelect) numberSelect.setAttribute('aria-label', t('numberFormat')); + root.querySelectorAll('[data-mode-group] .el-mode__btn').forEach((node) => { + const mode = node.dataset.mode || 'edit'; + const hintKey = mode === 'inspect' + ? 'modeInspectHint' + : mode === 'author' + ? 'modeAuthorHint' + : 'modeEditHint'; + node.setAttribute('title', t(hintKey)); + node.setAttribute('aria-label', `${node.textContent}: ${t(hintKey)}`); + }); + const askLabel = root.querySelector('[data-ask-label]'); + if (askLabel) askLabel.textContent = t('askFocus'); + const askBtn = root.querySelector('[data-action="ask-focus"]'); + if (askBtn) askBtn.setAttribute('title', t('askFocus')); + const includeText = root.querySelector('[data-include-text]'); + if (includeText) includeText.textContent = t('includeFocus'); + const includeLabel = root.querySelector('[data-include-label]'); + if (includeLabel) includeLabel.setAttribute('title', t('includeFocusTitle')); + const namebox = root.querySelector('[data-namebox]'); + if (namebox) namebox.setAttribute('title', t('nameBoxTitle')); + const fxInput = root.querySelector('[data-formula-input]'); + if (fxInput) fxInput.setAttribute('title', t('formulaTitle')); + const emptyTitle = root.querySelector('[data-empty-title]'); + if (emptyTitle) emptyTitle.textContent = t('emptyTitle'); + const emptyHint = root.querySelector('[data-empty-hint]'); + if (emptyHint) emptyHint.textContent = t('emptyHint'); + const emptyNew = root.querySelector('[data-empty-new]'); + if (emptyNew) emptyNew.textContent = t('newWorkbook'); + const emptyOpen = root.querySelector('[data-empty-open]'); + if (emptyOpen) emptyOpen.textContent = t('openWorkbook'); + const bootText = root.querySelector('[data-boot-text]'); + if (bootText) bootText.textContent = t('boot'); + const sheetTabs = root.querySelector('[data-sheet-tabs]'); + if (sheetTabs) sheetTabs.setAttribute('aria-label', t('sheetTabs')); + const grid = root.querySelector('[data-grid-wrap]'); + if (grid) grid.setAttribute('aria-label', t('gridLabel')); +} + +function statusToken(value) { + if (typeof value === 'string') return value.trim().toLowerCase().replaceAll('_', '-'); + if (!value || typeof value !== 'object') return ''; + return String(value.status || value.state || value.kind || value.level || '') + .trim() + .toLowerCase() + .replaceAll('_', '-'); +} + +function renderTrustBanner(root = rootElement()) { + const banner = root?.querySelector('[data-trust-banner]'); + if (!banner) return; + if (!state.workbookId) { + banner.hidden = true; + banner.innerHTML = ''; + return; + } + + const messages = []; + let kind = 'warning'; + const fidelity = state.meta?.fidelity; + const fidelityToken = statusToken(fidelity); + const sourcePreserving = fidelityToken === 'source-preserving'; + const fullFidelity = [ + 'full', + 'exact', + 'preserved', + 'high', + 'native', + ].includes(fidelityToken); + if (sourcePreserving) { + messages.push(t('fidelitySourcePreservingView')); + } else if (fidelity != null && !fullFidelity) { + const explicit = fidelity && typeof fidelity === 'object' && typeof fidelity.message === 'string' + ? fidelity.message.trim() + : ''; + messages.push(explicit || t( + ['limited', 'basic', 'partial', 'degraded', 'values-formulas-only'].includes(fidelityToken) + ? 'fidelityLimited' + : 'fidelityUnknown', + )); + } + + const calculation = state.meta?.calculationStatus; + const calculationToken = statusToken(calculation); + const calculationCurrent = [ + 'current', + 'ready', + 'calculated', + 'recalculated', + 'ok', + 'not-required', + ].includes(calculationToken); + if (calculation != null && !calculationCurrent) { + const explicit = calculation && typeof calculation === 'object' && typeof calculation.message === 'string' + ? calculation.message.trim() + : ''; + let key = 'calculationUnknown'; + if (['pending', 'stale', 'cached', 'not-calculated', 'unrecalculated', 'dirty'].includes(calculationToken)) { + key = 'calculationPending'; + } + if (['failed', 'error'].includes(calculationToken)) { + key = 'calculationFailed'; + kind = 'error'; + } + messages.push(explicit || t(key)); + } + + if (messages.length === 0) { + banner.hidden = true; + banner.innerHTML = ''; + return; + } + banner.hidden = false; + banner.dataset.kind = kind; + banner.innerHTML = messages + .map((message) => `${escapeHtml(message)}`) + .join(''); +} + +function updateChrome() { + const root = rootElement(); + if (!root || !state.shellBuilt) return; + + const hasWorkbook = Boolean(state.workbookId); + const readOnly = state.mode === 'inspect'; + const boundaryPending = state.modePending; + const busy = state.loading || state.dialogPending || boundaryPending; + root.setAttribute('aria-busy', busy ? 'true' : 'false'); + + const title = root.querySelector('[data-title]'); + if (title) title.textContent = state.meta?.title || t('title'); + + const spin = root.querySelector('[data-loading-spin]'); + if (spin) spin.hidden = !busy; + const loadbar = root.querySelector('[data-loading-bar]'); + if (loadbar) loadbar.hidden = !busy; + const grid = root.querySelector('[data-grid-wrap]'); + if (grid) grid.setAttribute('aria-busy', busy ? 'true' : 'false'); + + for (const action of ['save-workbook', 'export-csv', 'pin-focus', 'ask-focus']) { + const btn = root.querySelector(`[data-action="${action}"]:not([data-empty-new]):not([data-empty-open])`); + if (btn) btn.disabled = !hasWorkbook || busy; + } + root.querySelectorAll('[data-action="new-workbook"], [data-action="open-workbook"]') + .forEach((btn) => { btn.disabled = busy; }); + for (const action of ['insert-row', 'insert-col']) { + const btn = root.querySelector(`[data-action="${action}"]`); + if (btn) btn.disabled = !hasWorkbook || busy || readOnly; + } + root.querySelectorAll('[data-format-control]').forEach((control) => { + control.disabled = !hasWorkbook || busy || readOnly || Boolean(state.proposal); + }); + const formatHint = root.querySelector('[data-format-hint]'); + if (formatHint) { + formatHint.textContent = state.proposal ? t('formatProposalExistsShort') : ''; + } + const undo = root.querySelector('[data-action="undo"]'); + if (undo) undo.disabled = !hasWorkbook || busy || readOnly || !state.history.canUndo; + const redo = root.querySelector('[data-action="redo"]'); + if (redo) redo.disabled = !hasWorkbook || busy || readOnly || !state.history.canRedo; + const addSheet = root.querySelector('[data-action="add-sheet"]'); + if (addSheet) addSheet.disabled = !hasWorkbook || busy || readOnly; + + root.querySelectorAll('[data-mode-group] .el-mode__btn').forEach((btn) => { + btn.classList.toggle('is-active', btn.dataset.mode === state.mode); + btn.setAttribute('aria-pressed', btn.dataset.mode === state.mode ? 'true' : 'false'); + btn.disabled = !hasWorkbook || busy; + }); + root.dataset.mode = state.mode; + const modeHint = root.querySelector('[data-mode-hint]'); + if (modeHint) { + modeHint.textContent = t( + state.mode === 'inspect' + ? 'modeInspectHint' + : state.mode === 'author' + ? 'modeAuthorHint' + : 'modeEditHint', + ); + } + + const fxInput = root.querySelector('[data-formula-input]'); + if (fxInput) { + fxInput.disabled = !hasWorkbook || busy; + fxInput.readOnly = readOnly || busy; + fxInput.placeholder = state.mode === 'inspect' ? t('readOnly') : ''; + } + const namebox = root.querySelector('[data-namebox]'); + if (namebox) namebox.disabled = !hasWorkbook || busy; + + const cellEditorInput = root.querySelector('[data-cell-editor] input'); + if (cellEditorInput) cellEditorInput.disabled = !hasWorkbook || busy || readOnly; + + const includeCheckbox = root.querySelector('[data-action="toggle-include-focus"]'); + if (includeCheckbox) { + includeCheckbox.checked = Boolean(state.includeFocusOnSend); + includeCheckbox.disabled = busy; + } + + root.querySelectorAll([ + '[data-action="jump-proposal"]', + '[data-action="toggle-proposal-details"]', + '[data-action="proposal-select-all"]', + '[data-action="proposal-select-none"]', + '[data-action="toggle-proposal-cell"]', + ].join(',')).forEach((control) => { + control.disabled = busy; + }); + const proposalStale = Boolean( + state.proposal?.stale === true + || ( + state.proposal?.baseRevision != null + && state.meta?.revision != null + && String(state.proposal.baseRevision) !== String(state.meta.revision) + ), + ); + const acceptProposal = root.querySelector('[data-action="accept-proposal"]'); + if (acceptProposal) { + const proposalCellCount = Array.isArray(state.proposal?.cells) ? state.proposal.cells.length : 0; + const layoutOnly = proposalCellCount === 0 && proposalHasLayoutChanges(state.proposal); + acceptProposal.disabled = busy + || readOnly + || proposalStale + || proposalValidationDetails(state.proposal).invalid + || (!layoutOnly && state.proposalSelectedCellRefs.size === 0); + } + const rejectProposal = root.querySelector('[data-action="reject-proposal"]'); + if (rejectProposal) rejectProposal.disabled = busy; + + const scroll = root.querySelector('[data-grid-scroll]'); + const empty = root.querySelector('[data-empty-state]'); + const boot = root.querySelector('[data-boot-state]'); + const booting = !state.bootDone && !hasWorkbook; + if (scroll) scroll.hidden = !hasWorkbook; + if (empty) empty.hidden = hasWorkbook || booting; + if (boot) boot.hidden = !booting; + + const statusText = root.querySelector('[data-status-text]'); + if (statusText) statusText.textContent = state.status || ''; + + renderTrustBanner(root); + updateSelectionStats(root); + renderSheetTabs(root); +} + +function updateSelectionStats(root = rootElement()) { + const node = root?.querySelector('[data-selection-stats]'); + if (!node) return; + if (!state.workbookId) { + node.textContent = ''; + return; + } + const focus = normalizeFocusRange(state.focus); + const summary = selectionValueSummary(focus); + if (!summary || summary.cellCount <= 1) { + node.textContent = ''; + return; + } + if (summary.formulaCount > 0 && !calculationStatusIsFresh()) { + node.textContent = t('statsFormulaStale'); + return; + } + if (summary.numericCount === 0) { + node.textContent = ''; + return; + } + const parts = [ + `${t('statsCount')} ${summary.numericCount}`, + `${t('statsSum')} ${formatNumber(summary.sum)}`, + ]; + if (summary.avg != null) { + parts.push(`${t('statsAvg')} ${formatNumber(summary.avg)}`); + } + node.textContent = parts.join(' · '); +} + +function formatNumber(value) { + if (!Number.isFinite(value)) return String(value); + const rounded = Math.round(value * 10000) / 10000; + return String(rounded); +} + +function renderSheetTabs(root = rootElement()) { + const host = root?.querySelector('[data-sheet-tabs]'); + if (!host) return; + const busy = state.loading || state.dialogPending || state.modePending; + const key = `${(state.sheets || []).map((s) => `${s.id}:${s.name}`).join('|')}#${state.activeSheetId}#${busy ? 'busy' : 'ready'}`; + if (key === state.lastSheetTabsKey) return; + state.lastSheetTabsKey = key; + host.innerHTML = (state.sheets || []) + .map((sheet) => { + const active = sheet.id === state.activeSheetId; + return ``; + }) + .join(''); +} + +function showToast(kind, message) { + const toast = rootElement()?.querySelector('[data-toast]'); + if (!toast) return; + toast.hidden = false; + toast.textContent = message; + toast.dataset.kind = kind; + toast.setAttribute('aria-live', kind === 'error' ? 'assertive' : 'polite'); + if (state.toastTimer) clearTimeout(state.toastTimer); + state.toastTimer = setTimeout(() => { + state.toastTimer = null; + hideToast(); + }, kind === 'error' ? 8000 : 4000); +} + +function hideToast() { + const toast = rootElement()?.querySelector('[data-toast]'); + if (toast) toast.hidden = true; + if (state.toastTimer) { + clearTimeout(state.toastTimer); + state.toastTimer = null; + } +} + +export { + applyStaticTexts, + ensureShell, + hideToast, + renderSheetTabs, + showToast, + updateChrome, + updateSelectionStats, +}; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/style.css b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/style.css new file mode 100644 index 00000000..ae846903 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/style.css @@ -0,0 +1,1581 @@ +/* Excel Live — dense spreadsheet workbench. + * Theme bridge: --sparo-app-* variables from the host, with dark fallbacks + * keyed off html[data-theme-type] (set by the runtime bridge script). + * Selection and proposal highlights stay visually distinct. + */ + +:root { + color-scheme: light dark; + + --el-bg: var(--sparo-app-bg, var(--sparo-bg-scene, #f4f5f7)); + --el-panel: var(--sparo-app-surface, var(--sparo-bg-secondary, #ffffff)); + --el-soft: var(--sparo-app-card, var(--sparo-element-subtle, #eef0f3)); + --el-hover: var(--sparo-app-card-hover, var(--sparo-element-soft, #e5e8ed)); + --el-ctrl: var(--sparo-app-control-bg, var(--sparo-element-bg, #f7f8fa)); + --el-text: var(--sparo-app-text, var(--sparo-text, #1a1d23)); + --el-muted: var(--sparo-app-text-secondary, var(--sparo-text-secondary, #5c6570)); + --el-subtle: var(--sparo-app-text-muted, var(--sparo-text-muted, #8a93a0)); + --el-border: var(--sparo-app-border-subtle, var(--sparo-border-subtle, #dde1e8)); + --el-border-md: var(--sparo-app-border, var(--sparo-border, #c9cfd9)); + --el-accent: var(--sparo-app-accent, var(--sparo-accent, #2f6fed)); + --el-accent-text: var(--sparo-app-accent-text, #ffffff); + --el-ok: var(--sparo-success, #1f8a4c); + --el-warn: var(--sparo-warning, #b78100); + --el-danger: var(--sparo-error, #c62828); + --el-danger-bg: var(--sparo-error-bg, #fdecea); + + --el-grid-bg: var(--el-panel); + --el-grid-line: color-mix(in srgb, var(--el-border) 72%, transparent); + --el-header-bg: color-mix(in srgb, var(--el-soft) 82%, var(--el-panel)); + --el-header-text: var(--el-muted); + --el-selection-fill: color-mix(in srgb, var(--el-accent) 10%, transparent); + --el-selection-border: color-mix(in srgb, var(--el-accent) 70%, transparent); + --el-proposal-fill: color-mix(in srgb, var(--el-ok) 12%, transparent); + --el-proposal-border: color-mix(in srgb, var(--el-ok) 45%, var(--el-border)); + --el-proposal-bar: color-mix(in srgb, var(--el-ok) 8%, var(--el-panel)); + + --el-radius: var(--sparo-app-radius-sm, var(--sparo-radius-sm, 4px)); + --el-radius-lg: var(--sparo-app-radius, var(--sparo-radius, 6px)); + --el-shadow: var(--sparo-app-shadow, 0 4px 16px rgba(0, 0, 0, 0.14)); + --el-font: var(--sparo-font-sans, "Segoe UI", system-ui, sans-serif); + --el-mono: var(--sparo-font-mono, "Cascadia Mono", ui-monospace, monospace); + --el-scrollbar-thumb: var(--sparo-scrollbar-thumb, color-mix(in srgb, var(--el-text) 16%, transparent)); + --el-scrollbar-thumb-hover: var(--sparo-scrollbar-thumb-hover, color-mix(in srgb, var(--el-text) 28%, transparent)); +} + +html[data-theme-type="dark"] { + --el-bg: var(--sparo-app-bg, #14171c); + --el-panel: var(--sparo-app-surface, #1b1f26); + --el-soft: var(--sparo-app-card, #232830); + --el-hover: var(--sparo-app-card-hover, #2b313b); + --el-ctrl: var(--sparo-app-control-bg, #20252d); + --el-text: var(--sparo-app-text, #edf0f4); + --el-muted: var(--sparo-app-text-secondary, #a6afbc); + --el-subtle: var(--sparo-app-text-muted, #7e8794); + --el-border: var(--sparo-app-border-subtle, #333a45); + --el-border-md: var(--sparo-app-border, #414957); + --el-danger-bg: var(--sparo-error-bg, #3a2224); +} + +@media (prefers-color-scheme: dark) { + html:not([data-theme-type]) { + --el-bg: var(--sparo-app-bg, #14171c); + --el-panel: var(--sparo-app-surface, #1b1f26); + --el-soft: var(--sparo-app-card, #232830); + --el-hover: var(--sparo-app-card-hover, #2b313b); + --el-ctrl: var(--sparo-app-control-bg, #20252d); + --el-text: var(--sparo-app-text, #edf0f4); + --el-muted: var(--sparo-app-text-secondary, #a6afbc); + --el-subtle: var(--sparo-app-text-muted, #7e8794); + --el-border: var(--sparo-app-border-subtle, #333a45); + --el-border-md: var(--sparo-app-border, #414957); + --el-danger-bg: var(--sparo-error-bg, #3a2224); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; +} + +html, +body { + margin: 0; + height: 100%; + overflow: hidden; + background: var(--el-bg); + color: var(--el-text); + font-family: var(--el-font); + font-size: 12.5px; + line-height: 1.35; +} + +button, +input { + font: inherit; + color: inherit; +} + +button { + cursor: pointer; +} + +/* Flex column instead of grid rows: hidden sections (e.g. the proposal bar) + * drop out of flow without shifting the remaining rows around. */ +.excel-live { + height: 100vh; + min-width: 0; + display: flex; + flex-direction: column; + background: var(--el-bg); +} + +.excel-live > .el-toolbar, +.excel-live > .el-formatbar, +.excel-live > .el-formulabar, +.excel-live > .el-trust, +.excel-live > .el-proposal, +.excel-live > .el-bottombar { + flex: none; +} + +/* ------------------------------------------------------------- loaders */ + +.el-loader, +.excel-live__loader { + width: 20px; + height: 20px; + border: 2px solid var(--el-border); + border-top-color: var(--el-accent); + border-radius: 50%; + animation: el-spin 0.8s linear infinite; +} + +@keyframes el-spin { + to { + transform: rotate(360deg); + } +} + +.excel-live__boot { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 12px; + height: 100vh; + color: var(--el-muted); +} + +/* ------------------------------------------------------------- toolbar */ + +.el-toolbar { + display: flex; + align-items: center; + gap: 6px; + padding: 5px 8px; + border-bottom: 1px solid var(--el-border); + background: var(--el-panel); + min-height: 40px; + overflow: hidden; +} + +.el-toolbar__brand { + display: flex; + align-items: center; + gap: 7px; + min-width: 0; + margin-right: 6px; + flex-shrink: 1; + overflow: hidden; +} + +.el-logo { + display: inline-flex; + width: 18px; + height: 18px; + color: var(--el-accent); + flex: none; +} + +.el-logo svg { + width: 100%; + height: 100%; +} + +.el-title { + font-size: 13px; + font-weight: 600; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 180px; +} + +.el-toolbar__actions, +.el-toolbar__right { + display: flex; + align-items: center; + gap: 3px; + flex: none; +} + +.el-toolbar__right { + margin-left: auto; +} + +.el-sep { + width: 1px; + height: 16px; + background: var(--el-border); + margin: 0 4px; + flex: none; +} + +.el-spin { + width: 12px; + height: 12px; + border: 2px solid var(--el-border); + border-top-color: var(--el-accent); + border-radius: 50%; + animation: el-spin 0.8s linear infinite; + flex: none; +} + +.el-icon-btn { + appearance: none; + display: inline-flex; + align-items: center; + justify-content: center; + width: 27px; + height: 27px; + padding: 0; + border: 1px solid transparent; + border-radius: var(--el-radius); + background: transparent; + color: var(--el-muted); +} + +.el-icon-btn svg { + width: 15px; + height: 15px; +} + +.el-icon-btn:hover:not(:disabled) { + background: var(--el-hover); + color: var(--el-text); +} + +.el-icon-btn:focus-visible { + outline: 2px solid color-mix(in srgb, var(--el-accent) 45%, transparent); + outline-offset: 1px; +} + +.el-icon-btn:disabled { + opacity: 0.4; + cursor: default; +} + +.el-btn { + appearance: none; + display: inline-flex; + align-items: center; + gap: 5px; + border: 1px solid var(--el-border-md); + background: var(--el-ctrl); + color: var(--el-text); + border-radius: var(--el-radius); + padding: 4px 10px; + font-size: 12px; + line-height: 1.2; + white-space: nowrap; +} + +.el-btn:hover:not(:disabled) { + background: var(--el-hover); +} + +.el-btn:focus-visible { + outline: 2px solid color-mix(in srgb, var(--el-accent) 45%, transparent); + outline-offset: 1px; +} + +.el-btn:disabled { + opacity: 0.45; + cursor: default; +} + +.el-btn--accent { + background: var(--el-accent); + border-color: var(--el-accent); + color: var(--el-accent-text); +} + +.el-btn--accent:hover:not(:disabled) { + filter: brightness(1.06); + background: var(--el-accent); +} + +.el-btn--accept { + background: var(--el-ok); + border-color: var(--el-ok); + color: #fff; +} + +.el-btn--accept:hover:not(:disabled) { + filter: brightness(1.06); + background: var(--el-ok); +} + +.el-btn--ghost { + background: transparent; +} + +.el-ask svg { + width: 14px; + height: 14px; +} + +.el-mode { + display: inline-flex; + align-items: center; + padding: 2px; + gap: 1px; + border: 1px solid var(--el-border); + border-radius: var(--el-radius-lg); + background: var(--el-soft); +} + +.el-mode__btn { + appearance: none; + border: none; + background: transparent; + color: var(--el-muted); + border-radius: calc(var(--el-radius-lg) - 2px); + padding: 2.5px 9px; + font-size: 11.5px; + white-space: nowrap; +} + +.el-mode__btn:hover { + color: var(--el-text); +} + +.el-mode__btn.is-active { + background: var(--el-panel); + color: var(--el-text); + font-weight: 600; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12); +} + +.el-formatbar { + display: flex; + align-items: center; + gap: 5px; + min-height: 32px; + padding: 3px 8px; + overflow-x: auto; + overflow-y: hidden; + border-bottom: 1px solid var(--el-border); + background: color-mix(in srgb, var(--el-panel) 94%, var(--el-soft)); + scrollbar-width: none; +} + +.el-formatbar::-webkit-scrollbar { + display: none; +} + +.el-formatbar__label { + color: var(--el-muted); + font-size: 10.5px; + font-weight: 600; + white-space: nowrap; +} + +.el-formatbar__presets { + display: flex; + gap: 3px; +} + +.el-format-preset, +.el-format-btn { + appearance: none; + min-height: 23px; + border: 1px solid var(--el-border); + border-radius: var(--el-radius); + padding: 2px 8px; + background: var(--el-ctrl); + color: var(--el-text); + font-size: 10.5px; + white-space: nowrap; +} + +.el-format-preset:hover:not(:disabled), +.el-format-btn:hover:not(:disabled) { + border-color: var(--el-border-md); + filter: brightness(1.02); +} + +.el-format-preset.is-header { + border-color: #17365d; + background: #1f4e78; + color: #fff; + font-weight: 700; +} + +.el-format-preset.is-total { + border-top: 3px double #1f1f1f; + font-weight: 700; +} + +.el-format-preset.is-input { + border-color: #d6b656; + background: #fff2cc; + color: #4a3b0a; +} + +.el-format-preset.is-output { + border-color: #9dc3e6; + background: #ddebf7; + color: #17365d; +} + +.el-format-btn--bold { + width: 26px; + padding-inline: 0; + font-weight: 800; +} + +.el-format-color { + position: relative; + display: inline-flex; + align-items: center; + justify-content: center; + width: 28px; + height: 23px; + border: 1px solid var(--el-border); + border-radius: var(--el-radius); + background: var(--el-ctrl); + cursor: pointer; +} + +.el-format-color > span { + width: 14px; + height: 10px; + border-bottom: 3px solid #fff2cc; + background: linear-gradient(135deg, transparent 45%, currentColor 46% 54%, transparent 55%); +} + +.el-format-color input { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + opacity: 0; + cursor: pointer; +} + +.el-format-number select { + min-height: 23px; + max-width: 116px; + border: 1px solid var(--el-border); + border-radius: var(--el-radius); + padding: 1px 24px 1px 7px; + background: var(--el-ctrl); + color: var(--el-text); + font-size: 10.5px; +} + +.el-formatbar [data-format-control]:disabled { + opacity: 0.42; + cursor: default; +} + +.el-formatbar__hint { + margin-left: auto; + color: var(--el-muted); + font-size: 10px; + white-space: nowrap; +} + +.el-mode__hint { + max-width: 190px; + color: var(--el-muted); + font-size: 10.5px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +/* --------------------------------------------------------- formula bar */ + +.el-formulabar { + display: flex; + align-items: center; + gap: 6px; + padding: 4px 8px; + border-bottom: 1px solid var(--el-border); + background: var(--el-panel); + min-height: 32px; +} + +.el-namebox { + width: 96px; + flex: none; + text-align: center; + border: 1px solid var(--el-border); + border-radius: var(--el-radius); + background: var(--el-ctrl); + padding: 3px 6px; + font-family: var(--el-mono); + font-size: 11.5px; +} + +.el-fx-label { + color: var(--el-subtle); + font-family: var(--el-mono); + font-size: 11px; + font-style: italic; + font-weight: 700; + flex: none; + user-select: none; +} + +.el-fx-input { + flex: 1; + min-width: 60px; + border: 1px solid var(--el-border); + border-radius: var(--el-radius); + background: var(--el-ctrl); + padding: 3.5px 8px; + font-family: var(--el-mono); + font-size: 12px; +} + +.el-namebox:focus, +.el-fx-input:focus { + outline: 2px solid color-mix(in srgb, var(--el-accent) 35%, transparent); + outline-offset: 0; + border-color: var(--el-accent); +} + +.el-namebox:disabled, +.el-fx-input:disabled { + opacity: 0.5; +} + +.el-include { + display: inline-flex; + align-items: center; + gap: 5px; + color: var(--el-muted); + font-size: 11px; + white-space: nowrap; + flex: none; + cursor: pointer; + user-select: none; +} + +.el-include input { + accent-color: var(--el-accent); + margin: 0; +} + +/* ----------------------------------------------------- fidelity / recalc */ + +.el-trust { + display: flex; + align-items: center; + gap: 7px; + padding: 5px 10px; + border-bottom: 1px solid color-mix(in srgb, var(--el-warn) 42%, var(--el-border)); + background: color-mix(in srgb, var(--el-warn) 10%, var(--el-panel)); + color: color-mix(in srgb, var(--el-warn) 78%, var(--el-text)); + font-size: 11px; +} + +.el-trust[data-kind="error"] { + border-bottom-color: color-mix(in srgb, var(--el-danger) 45%, var(--el-border)); + background: var(--el-danger-bg); + color: var(--el-danger); +} + +.el-trust[hidden] { + display: none !important; +} + +.el-trust__sep { + color: var(--el-subtle); +} + +/* ---------------------------------------------------------- proposal bar */ + +.el-proposal { + display: block; + padding: 5px 10px; + border-bottom: 1px solid var(--el-proposal-border); + background: var(--el-proposal-bar); +} + +.el-proposal__summary { + display: flex; + align-items: center; + justify-content: space-between; + gap: 10px; +} + +.el-proposal[hidden] { + display: none !important; +} + +.el-proposal__main { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 8px; + min-width: 0; +} + +.el-proposal__badge { + font-size: 10.5px; + font-weight: 700; + color: var(--el-ok); + text-transform: uppercase; + letter-spacing: 0.05em; + white-space: nowrap; +} + +.el-proposal__range { + appearance: none; + border: 1px solid var(--el-proposal-border); + border-radius: var(--el-radius); + background: color-mix(in srgb, var(--el-ok) 8%, transparent); + color: var(--el-text); + font-family: var(--el-mono); + font-size: 11.5px; + padding: 1.5px 7px; +} + +.el-proposal__range:hover { + background: color-mix(in srgb, var(--el-ok) 16%, transparent); +} + +.el-proposal__meta { + color: var(--el-muted); + font-size: 11px; + white-space: nowrap; +} + +.el-proposal__intent { + min-width: 80px; + max-width: 320px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-weight: 600; +} + +.el-proposal__validation, +.el-proposal__stale { + border: 1px solid var(--el-border); + border-radius: 999px; + padding: 1px 6px; + font-size: 10.5px; + white-space: nowrap; +} + +.el-proposal__validation.is-ok { + border-color: color-mix(in srgb, var(--el-ok) 42%, var(--el-border)); + color: var(--el-ok); +} + +.el-proposal__validation.is-warning { + border-color: color-mix(in srgb, var(--el-warn) 42%, var(--el-border)); + color: var(--el-warn); +} + +.el-proposal__validation.is-error, +.el-proposal__stale { + border-color: color-mix(in srgb, var(--el-danger) 45%, var(--el-border)); + color: var(--el-danger); +} + +.el-proposal[data-stale="true"] { + border-bottom-color: color-mix(in srgb, var(--el-danger) 45%, var(--el-border)); + background: color-mix(in srgb, var(--el-danger-bg) 55%, var(--el-panel)); +} + +.el-proposal__stale-hint { + margin: 5px 0 0; + color: var(--el-danger); + font-size: 11px; +} + +.el-proposal__invalid-hint { + margin: 5px 0 0; + color: var(--el-danger); + font-size: 11px; + font-weight: 600; +} + +.el-proposal__layout-hint { + margin: 5px 0 0; + color: var(--el-muted); + font-size: 10.5px; +} + +.el-proposal-validation-detail { + display: grid; + grid-template-columns: auto minmax(0, 1fr); + align-items: start; + gap: 4px 12px; + margin-top: 6px; + padding: 6px 8px; + border: 1px solid color-mix(in srgb, var(--el-warn) 30%, var(--el-border)); + border-radius: var(--el-radius); + background: color-mix(in srgb, var(--el-warn) 5%, transparent); + font-size: 11px; +} + +.el-proposal-validation-detail[role="alert"] { + border-color: color-mix(in srgb, var(--el-danger) 35%, var(--el-border)); + background: color-mix(in srgb, var(--el-danger-bg) 45%, transparent); +} + +.el-proposal-validation-detail ul { + margin: 0; + padding-left: 17px; +} + +.el-proposal-validation-detail li + li { + margin-top: 2px; +} + +.el-proposal-validation-detail li.is-error { + color: var(--el-danger); +} + +.el-proposal-validation-detail li.is-warning { + color: color-mix(in srgb, var(--el-warn) 88%, var(--el-text)); +} + +.el-proposal__actions { + display: flex; + gap: 6px; + flex-shrink: 0; +} + +.el-proposal-detail { + margin-top: 7px; + border-top: 1px solid var(--el-proposal-border); + padding-top: 6px; +} + +.el-proposal-detail__toolbar { + display: flex; + align-items: center; + gap: 8px; + min-height: 24px; + color: var(--el-muted); + font-size: 11px; +} + +.el-link-btn { + appearance: none; + border: none; + background: transparent; + color: var(--el-accent); + padding: 2px 3px; + font-size: 11px; + cursor: pointer; +} + +.el-link-btn:focus-visible { + outline: 2px solid color-mix(in srgb, var(--el-accent) 45%, transparent); + outline-offset: 1px; +} + +.el-link-btn:disabled, +.el-proposal__range:disabled, +.el-proposal-detail input:disabled { + opacity: 0.45; + cursor: default; +} + +.el-proposal-detail__table { + max-height: min(230px, 32vh); + overflow: auto; + border: 1px solid var(--el-border); + border-radius: var(--el-radius); + background: var(--el-panel); +} + +.el-proposal-detail__head, +.el-proposal-detail__row { + display: grid; + grid-template-columns: 30px minmax(72px, 0.65fr) minmax(120px, 1fr) minmax(120px, 1fr); + align-items: center; + min-height: 32px; +} + +.el-proposal-detail__head { + position: sticky; + top: 0; + z-index: 1; + background: var(--el-soft); + color: var(--el-muted); + font-size: 10.5px; + font-weight: 700; +} + +.el-proposal-detail__row { + border-top: 1px solid var(--el-grid-line); + cursor: pointer; +} + +.el-proposal-detail__row:hover { + background: var(--el-hover); +} + +.el-proposal-detail__head > span, +.el-proposal-detail__row > span { + min-width: 0; + padding: 4px 7px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.el-proposal-detail__check { + display: flex; + justify-content: center; +} + +.el-proposal-detail__ref { + font-family: var(--el-mono); +} + +.el-proposal-detail__before { + color: var(--el-subtle); +} + +.el-proposal-detail__after { + color: var(--el-ok); + font-weight: 600; +} + +.el-proposal-snapshot { + display: flex; + flex-direction: column; + align-items: flex-start; + min-width: 0; +} + +.el-proposal-snapshot__primary { + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font: inherit; +} + +.el-proposal-snapshot--before .el-proposal-snapshot__primary { + text-decoration: line-through; +} + +.el-proposal-snapshot__primary.is-formula { + color: color-mix(in srgb, var(--el-accent) 78%, var(--el-text)); + font-family: var(--el-mono); + text-decoration: none; +} + +.el-proposal-snapshot__cached { + max-width: 100%; + overflow: hidden; + color: var(--el-subtle); + font-size: 9.5px; + font-weight: 400; + text-overflow: ellipsis; + white-space: nowrap; +} + +.el-proposal-style-diff { + display: flex; + flex-wrap: wrap; + gap: 3px; + margin-top: 3px; +} + +.el-proposal-style-diff__item { + max-width: 100%; + overflow: hidden; + border: 1px solid color-mix(in srgb, var(--el-accent) 22%, var(--el-border)); + border-radius: 999px; + padding: 1px 5px; + background: color-mix(in srgb, var(--el-accent) 5%, transparent); + color: var(--el-muted); + font-size: 9px; + font-weight: 400; + text-overflow: ellipsis; + white-space: nowrap; +} + +.el-proposal-layout-diff { + margin-top: 7px; + border: 1px solid var(--el-border); + border-radius: var(--el-radius); + background: var(--el-panel); +} + +.el-proposal-layout-diff h3 { + margin: 0; + padding: 5px 8px; + border-bottom: 1px solid var(--el-border); + background: var(--el-soft); + color: var(--el-muted); + font-size: 10.5px; + text-transform: uppercase; + letter-spacing: 0.04em; +} + +.el-proposal-layout-diff__row { + display: grid; + grid-template-columns: minmax(86px, 0.55fr) minmax(120px, 1fr) auto minmax(120px, 1fr); + gap: 8px; + padding: 5px 8px; + border-top: 1px solid var(--el-grid-line); + font-size: 10.5px; +} + +.el-proposal-layout-diff__row:first-of-type { + border-top: 0; +} + +.el-proposal-layout-diff__row > span { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.el-proposal-detail__limit { + margin: 5px 0 0; + color: var(--el-muted); + font-size: 10.5px; +} + +/* ----------------------------------------------------------------- grid */ + +.el-grid-wrap { + flex: 1 1 0; + min-height: 0; + min-width: 0; + position: relative; + background: var(--el-grid-bg); + outline: none; +} + +.el-grid-wrap:focus-visible { + outline: 2px solid color-mix(in srgb, var(--el-accent) 58%, transparent); + outline-offset: -2px; +} + +.el-sr-only { + position: absolute !important; + width: 1px !important; + height: 1px !important; + padding: 0 !important; + margin: -1px !important; + overflow: hidden !important; + clip: rect(0, 0, 0, 0) !important; + white-space: nowrap !important; + border: 0 !important; +} + +.el-loadbar { + position: absolute; + top: 0; + left: 0; + right: 0; + height: 2px; + z-index: 12; + overflow: hidden; + background: transparent; + pointer-events: none; +} + +.el-loadbar::after { + content: ""; + position: absolute; + inset: 0; + width: 40%; + background: var(--el-accent); + animation: el-loadbar 1.1s ease-in-out infinite; +} + +@keyframes el-loadbar { + 0% { + transform: translateX(-110%); + } + + 100% { + transform: translateX(280%); + } +} + +.el-grid__scroll { + position: absolute; + inset: 0; + overflow: auto; + background: var(--el-grid-bg); + scrollbar-width: thin; + scrollbar-color: var(--el-scrollbar-thumb) transparent; +} + +.el-grid__scroll::-webkit-scrollbar { + width: 10px; + height: 10px; +} + +.el-grid__scroll::-webkit-scrollbar-thumb { + background: var(--el-scrollbar-thumb); + border-radius: 5px; + border: 2px solid transparent; + background-clip: content-box; +} + +.el-grid__scroll::-webkit-scrollbar-thumb:hover { + background: var(--el-scrollbar-thumb-hover); + background-clip: content-box; +} + +.el-grid__scroll::-webkit-scrollbar-corner { + background: transparent; +} + +.el-grid__scroll[hidden] { + display: none !important; +} + +.el-grid__pin { + position: sticky; + top: 0; + z-index: 8; + display: flex; + width: max-content; + min-width: 100%; +} + +.el-grid__corner { + position: sticky; + left: 0; + z-index: 9; + flex: none; + background: var(--el-header-bg); + border-right: 1px solid var(--el-border-md); + border-bottom: 1px solid var(--el-border-md); +} + +.el-grid__col-headers { + position: relative; + flex: none; + background: var(--el-header-bg); + border-bottom: 1px solid var(--el-border-md); +} + +.el-grid__col-h { + position: absolute; + top: 0; + display: flex; + align-items: center; + justify-content: center; + color: var(--el-header-text); + font-size: 10.5px; + font-weight: 600; + letter-spacing: 0.02em; + border-right: 1px solid var(--el-grid-line); + user-select: none; +} + +.el-grid__under { + display: flex; + width: max-content; + min-width: 100%; + align-items: flex-start; +} + +.el-grid__row-headers { + position: sticky; + left: 0; + z-index: 7; + flex: none; + background: var(--el-header-bg); + border-right: 1px solid var(--el-border-md); +} + +.el-grid__col-h.is-frozen, +.el-grid__row-header-row.is-frozen { + z-index: 10; + background: var(--el-header-bg); +} + +.el-grid__col-h.has-filter { + padding-right: 18px; +} + +.el-grid__filter { + position: absolute; + right: 4px; + display: inline-flex; + align-items: center; + justify-content: center; + width: 13px; + height: 13px; + border: 1px solid var(--el-border-md); + border-radius: 3px; + background: var(--el-panel); + color: var(--el-muted); + font-size: 10px; +} + +.el-grid__row-header-row { + position: absolute; + left: 0; +} + +.el-grid__row-h { + position: absolute; + top: 0; + left: 0; + display: flex; + align-items: center; + justify-content: center; + color: var(--el-header-text); + font-size: 10.5px; + border-bottom: 1px solid var(--el-grid-line); + user-select: none; + font-variant-numeric: tabular-nums; +} + +.el-grid__body { + position: relative; + flex: none; + /* Grid lines are painted as a background so empty (unrendered) cells still + * show them. Stops must match COL_W=100 and ROW_H=26 in src/grid.js. */ + background-image: + repeating-linear-gradient(to right, transparent 0 99px, var(--el-grid-line) 99px 100px), + repeating-linear-gradient(to bottom, transparent 0 25px, var(--el-grid-line) 25px 26px); +} + +.el-grid__cells { + position: absolute; + inset: 0; +} + +.el-grid__aria-row { + position: absolute; + left: 0; +} + +.el-grid__aria-row.is-frozen { + z-index: 4; + background: var(--el-grid-bg); +} + +.el-grid__cell { + position: absolute; + display: flex; + align-items: center; + gap: 4px; + padding: 0 6px; + overflow: hidden; + white-space: nowrap; + cursor: cell; + z-index: 1; +} + +.el-grid__cell.is-num { + justify-content: flex-end; + font-variant-numeric: tabular-nums; +} + +.el-grid__cell.is-formula .el-grid__value { + color: color-mix(in srgb, var(--el-accent) 80%, var(--el-text)); +} + +.el-grid__cell.is-proposal { + background: var(--el-proposal-fill); + box-shadow: inset 0 0 0 1px var(--el-proposal-border); +} + +.el-grid__value { + overflow: hidden; + text-overflow: ellipsis; + min-width: 0; +} + +.el-grid__old { + overflow: hidden; + text-overflow: ellipsis; + min-width: 0; + color: var(--el-subtle); + text-decoration: line-through; + font-size: 11px; +} + +.el-grid__new { + overflow: hidden; + text-overflow: ellipsis; + min-width: 0; + color: var(--el-ok); + font-weight: 600; +} + +.el-sel { + position: absolute; + z-index: 2; + background: var(--el-selection-fill); + border: 1px solid var(--el-selection-border); + pointer-events: none; +} + +.el-sel-active { + position: absolute; + z-index: 3; + border: 2px solid var(--el-accent); + pointer-events: none; +} + +.el-grid__editor { + position: absolute; + z-index: 6; + padding: 0; +} + +.el-grid__editor input { + width: 100%; + height: 100%; + border: 2px solid var(--el-accent); + background: var(--el-panel); + color: var(--el-text); + padding: 0 5px; + font-family: var(--el-mono); + font-size: 12px; + outline: none; +} + +.excel-live[data-mode="inspect"] .el-grid__cell { + cursor: default; +} + +/* ---------------------------------------------------------------- empty */ + +.el-empty { + position: absolute; + inset: 0; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 8px; + color: var(--el-muted); + padding: 24px; + text-align: center; +} + +.el-empty[hidden] { + display: none !important; +} + +.el-empty__icon { + width: 46px; + height: 46px; + color: var(--el-subtle); + opacity: 0.8; + margin-bottom: 4px; +} + +.el-empty__icon svg { + width: 100%; + height: 100%; +} + +.el-empty h2 { + margin: 0; + color: var(--el-text); + font-size: 15px; + font-weight: 600; +} + +.el-empty p { + margin: 0; + max-width: 340px; + font-size: 12px; +} + +.el-empty__actions { + display: flex; + gap: 8px; + margin-top: 10px; +} + +.el-boot { + position: absolute; + inset: 0; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 12px; + color: var(--el-muted); + background: var(--el-grid-bg); +} + +.el-boot[hidden] { + display: none !important; +} + +/* ---------------------------------------------------------------- toast */ + +.el-toast { + position: absolute; + left: 50%; + bottom: 14px; + transform: translateX(-50%); + z-index: 20; + max-width: min(92%, 480px); + border: 1px solid var(--el-border-md); + border-radius: var(--el-radius-lg); + background: var(--el-panel); + color: var(--el-text); + padding: 7px 12px; + font-size: 12px; + text-align: left; + box-shadow: var(--el-shadow); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.el-toast[data-kind="error"] { + border-color: color-mix(in srgb, var(--el-danger) 45%, var(--el-border-md)); + background: var(--el-danger-bg); + color: var(--el-danger); +} + +.el-toast[hidden] { + display: none !important; +} + +/* ------------------------------------------------------------ bottom bar */ + +.el-bottombar { + display: flex; + align-items: center; + gap: 4px; + padding: 0 8px; + border-top: 1px solid var(--el-border); + background: var(--el-panel); + min-height: 28px; + overflow: hidden; +} + +.el-sheets { + display: flex; + align-items: flex-end; + gap: 1px; + overflow-x: auto; + scrollbar-width: none; + align-self: stretch; +} + +.el-sheets::-webkit-scrollbar { + display: none; +} + +.el-sheet-tab { + appearance: none; + border: none; + border-top: 2px solid transparent; + background: transparent; + color: var(--el-muted); + padding: 4px 12px 5px; + font-size: 11.5px; + white-space: nowrap; + align-self: stretch; +} + +.el-sheet-tab:hover { + background: var(--el-hover); + color: var(--el-text); +} + +.el-sheet-tab.is-active { + border-top-color: var(--el-accent); + background: var(--el-soft); + color: var(--el-text); + font-weight: 600; +} + +.el-add-sheet { + appearance: none; + display: inline-flex; + align-items: center; + justify-content: center; + width: 22px; + height: 22px; + padding: 0; + border: none; + border-radius: var(--el-radius); + background: transparent; + color: var(--el-muted); + flex: none; +} + +.el-add-sheet svg { + width: 12px; + height: 12px; +} + +.el-add-sheet:hover { + background: var(--el-hover); + color: var(--el-text); +} + +.el-grid__body.has-custom-layout { + background-image: none; +} + +.el-grid__body.has-custom-layout .el-grid__cell { + border-right: 1px solid var(--el-grid-line); + border-bottom: 1px solid var(--el-grid-line); +} + +.el-grid__cell.is-frozen-row, +.el-grid__cell.is-frozen-column { + z-index: 4; + background-color: var(--el-grid-bg); +} + +.el-grid__cell.is-frozen-row.is-frozen-column { + z-index: 5; +} + +.el-grid__cell.is-freeze-row-edge { + box-shadow: inset 0 -2px 0 color-mix(in srgb, var(--el-border-md) 75%, transparent); +} + +.el-grid__cell.is-freeze-column-edge { + border-right: 2px solid color-mix(in srgb, var(--el-border-md) 75%, transparent); +} + +.el-grid__cell.is-proposal.is-freeze-row-edge { + box-shadow: + inset 0 0 0 1px var(--el-proposal-border), + inset 0 -2px 0 color-mix(in srgb, var(--el-border-md) 75%, transparent); +} + +.el-grid__cell.is-proposal.has-style-change::after { + content: ""; + position: absolute; + top: 2px; + right: 2px; + width: 5px; + height: 5px; + border-radius: 50%; + background: var(--el-accent); + box-shadow: 0 0 0 1px var(--el-panel); +} + +.el-add-sheet:focus-visible { + outline: 2px solid color-mix(in srgb, var(--el-accent) 45%, transparent); + outline-offset: 1px; +} + +.el-add-sheet:disabled { + opacity: 0.4; + cursor: default; +} + +.el-bottombar__spacer { + flex: 1; +} + +.el-stats { + color: var(--el-muted); + font-size: 11px; + white-space: nowrap; + font-variant-numeric: tabular-nums; + flex: none; +} + +.el-statustext { + color: var(--el-subtle); + font-size: 11px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 200px; + flex: none; + margin-left: 8px; +} + +/* --------------------------------------------------------- narrow panel */ + +@media (max-width: 1080px) { + .el-title, + .el-mode__hint { + display: none; + } +} + +@media (max-width: 640px) { + .el-toolbar { + flex-wrap: wrap; + overflow: visible; + } + + .el-toolbar__right { + width: 100%; + margin-left: 0; + justify-content: flex-end; + } + + .el-title { + max-width: 110px; + } + + .el-mode { + display: inline-flex; + } + + .el-mode__hint { + display: none; + } + + .el-trust, + .el-proposal__summary { + align-items: flex-start; + flex-wrap: wrap; + } + + .el-proposal__actions { + width: 100%; + justify-content: flex-end; + } + + .el-include span { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; + } + + .el-statustext { + display: none; + } +} + +@media (max-height: 520px) { + .el-trust { + max-height: 40px; + overflow: auto; + align-items: flex-start; + } + + .el-proposal { + max-height: 36vh; + overflow: auto; + overscroll-behavior: contain; + } + + .el-proposal-detail__table { + max-height: 18vh; + } +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/test/interaction.test.mjs b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/test/interaction.test.mjs new file mode 100644 index 00000000..7471dbb0 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/test/interaction.test.mjs @@ -0,0 +1,192 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; + +import { + agentRefreshTargetsCurrentWorkbook, + buildSelectionStyleCells, + createEditingDraft, + editingExpectedRevision, + exportCopyPlan, + gridSelectionNeedsEditCommit, + isComposingKey, + isSaveShortcut, + proposalAcceptPlan, +} from '../src/interaction.js'; +import { + LIVE_VIEW_SEMANTICS, + axisIndexAtOffset, + axisOffset, + excelColumnWidthToPixels, + excelRowHeightToPixels, + formatValueWithNumberFormat, + layoutDifferences, + normalizeCellStyle, + normalizeSheetLayout, + proposalHasLayoutChanges, + proposalValidationDetails, + snapshotParts, + styleDifferences, + styleToCss, +} from '../src/formatting.js'; + +test('focus fidelity declares the rendered values, formulas, styles, and layout semantics', () => { + assert.equal(LIVE_VIEW_SEMANTICS, 'values-formulas-styles-layout'); +}); + +test('an existing surface ignores agent refreshes for another workbook', () => { + assert.equal(agentRefreshTargetsCurrentWorkbook('workbook-a', 'workbook-b'), false); + assert.equal(agentRefreshTargetsCurrentWorkbook('workbook-a', 'workbook-a'), true); + assert.equal(agentRefreshTargetsCurrentWorkbook(null, 'workbook-b'), true); +}); + +test('an editing draft keeps the revision from when editing started', () => { + const draft = createEditingDraft({ + row: 2, + col: 4, + value: '=SUM(A1:A2)', + workbookId: 'workbook-a', + sheetId: 'sheet-a', + revision: 7, + origin: 'formula', + }); + + assert.equal(draft.baseRevision, 7); + assert.equal(draft.origin, 'formula'); + assert.equal(editingExpectedRevision(draft, 11), 7); +}); + +test('IME Enter is not treated as an edit command and save works inside inputs', () => { + assert.equal(isComposingKey({ key: 'Enter', isComposing: true }), true); + assert.equal(isComposingKey({ key: 'Enter', keyCode: 229 }), true); + assert.equal(isComposingKey({ key: 'Enter', isComposing: false }), false); + assert.equal(isSaveShortcut({ key: 's', ctrlKey: true }), true); + assert.equal(isSaveShortcut({ key: 'S', metaKey: true }), true); + assert.equal(isSaveShortcut({ key: 's' }), false); +}); + +test('grid selection waits for an edit commit only when leaving the edited cell', () => { + const editing = createEditingDraft({ + row: 1, + col: 2, + value: 'draft', + workbookId: 'workbook-a', + sheetId: 'sheet-a', + revision: 3, + }); + + assert.equal(gridSelectionNeedsEditCommit(null, { row: 2, col: 2, sheetId: 'sheet-a' }), false); + assert.equal(gridSelectionNeedsEditCommit(editing, { row: 1, col: 2, sheetId: 'sheet-a' }), false); + assert.equal(gridSelectionNeedsEditCommit(editing, { row: 2, col: 2, sheetId: 'sheet-a' }), true); + assert.equal(gridSelectionNeedsEditCommit(editing, { row: 1, col: 2, sheetId: 'sheet-b' }), true); +}); + +test('cell styles normalize semantic roles and Excel alignment/font units for CSS', () => { + const title = normalizeCellStyle({ role: 'title', alignment: { vertical: 'center' } }); + const warning = normalizeCellStyle({ role: 'warning' }); + + assert.equal(title.role, 'title'); + assert.equal(title.fill.color, '#17365D'); + assert.equal(title.font.size, 14); + assert.equal(title.alignment.vertical, 'middle'); + assert.equal(warning.font.color, '#C00000'); + assert.match(styleToCss({ role: 'title' }), /font-size:18\.67px/); +}); + +test('proposal snapshots keep formulas visible beside cached values and expose style changes', () => { + const before = { f: 'SUM(A1:A3)', v: 42, style: { fill: { color: '#FFFFFF' } } }; + const after = { f: 'SUM(A1:A4)', v: 42, style: { fill: { color: '#DDEBF7' }, font: { bold: true } } }; + const parts = snapshotParts(after); + + assert.equal(parts.primary, '=SUM(A1:A4)'); + assert.equal(parts.secondary, '42'); + assert.deepEqual(styleDifferences(before, after).map((item) => item.key), ['fill', 'font']); +}); + +test('validation errors including formula lint fail closed', () => { + const details = proposalValidationDetails({ + validation: { + status: 'warning', + warnings: ['Overwrites one cell'], + formulaLint: { + errors: [{ code: 'FORMULA_PARSE', message: 'Formula syntax is invalid' }], + }, + }, + }); + + assert.equal(details.invalid, true); + assert.deepEqual(details.errors, ['Formula syntax is invalid']); + assert.deepEqual(details.warnings, ['Overwrites one cell']); +}); + +test('layout metadata converts Excel units to pixels and supports layout-only proposals', () => { + assert.equal(excelColumnWidthToPixels(16), 117); + assert.equal(excelRowHeightToPixels(18), 24); + const layout = normalizeSheetLayout({ + units: { columnWidth: 'excelCharacters', rowHeight: 'points' }, + columns: [{ start: 0, end: 0, width: 16 }], + rows: [{ start: 0, end: 0, height: 18 }], + freezePanes: { rows: 1, columns: 1 }, + autoFilter: { a1: 'A1:D20' }, + }); + assert.equal(layout.columns[0].size, 117); + assert.equal(layout.rows[0].size, 24); + assert.equal(axisOffset(2, layout.columns, 100, 140), 217); + assert.equal(axisIndexAtOffset(118, 10, layout.columns, 100, 140), 1); + + const proposal = { layout: { before: null, after: { freezePanes: { rows: 1 }, autoFilter: { a1: 'A1:D20' } } } }; + assert.equal(proposalHasLayoutChanges(proposal), true); + assert.deepEqual(layoutDifferences(proposal).map((item) => item.key), ['freezePanes', 'autoFilter']); +}); + +test('format controls build reviewable style-only proposal cells without changing values', () => { + const cells = buildSelectionStyleCells( + { r1: 1, c1: 2, r2: 2, c2: 3 }, + { style: { numberFormat: '0.00%' } }, + ); + assert.equal(cells.length, 4); + assert.deepEqual(cells[0], { row: 1, col: 2, style: { numberFormat: '0.00%' } }); + assert.equal(Object.hasOwn(cells[0], 'value'), false); + assert.throws( + () => buildSelectionStyleCells({ r1: 0, c1: 0, r2: 100, c2: 100 }, { styleRole: 'header' }, 5000), + RangeError, + ); +}); + +test('common number formats render percentages, dates, and grouped numbers', () => { + assert.equal(formatValueWithNumberFormat(0.125, '0.00%'), '12.50%'); + assert.equal(formatValueWithNumberFormat(45292, 'yyyy-mm-dd'), '2024-01-01'); + assert.equal(formatValueWithNumberFormat(1, 'yyyy-mm-dd'), '1900-01-01'); + assert.equal(formatValueWithNumberFormat(59, 'yyyy-mm-dd'), '1900-02-28'); + assert.equal(formatValueWithNumberFormat(60, 'yyyy-mm-dd'), '1900-02-29'); + assert.equal(formatValueWithNumberFormat(61, 'yyyy-mm-dd'), '1900-03-01'); + assert.match(formatValueWithNumberFormat(1234.5, '#,##0.00'), /1[,.]234[,.]50/); +}); + +test('mixed cell and layout proposals become atomic only when every cell is selected', () => { + const partial = proposalAcceptPlan(['A1', 'A2'], ['A1'], true); + assert.deepEqual(partial.payloadCellRefs, ['A1']); + assert.equal(partial.acceptsLayout, false); + + const complete = proposalAcceptPlan(['A1', 'A2'], ['A2', 'A1'], true); + assert.equal(complete.payloadCellRefs, null); + assert.equal(complete.acceptsLayout, true); + + const layoutOnly = proposalAcceptPlan([], [], true); + assert.equal(layoutOnly.layoutOnly, true); + assert.equal(layoutOnly.payloadCellRefs, null); +}); + +test('lossy macro workbooks export through an explicit xlsx copy path', () => { + const sourcePreserving = exportCopyPlan('models/report.xlsm', { canRoundTrip: true }); + assert.equal(sourcePreserving.extension, 'xlsm'); + assert.equal(sourcePreserving.lossyMacroRebuild, false); + + const lossy = exportCopyPlan('models/report.xlsm', { canRoundTrip: false }); + assert.equal(lossy.extension, 'xlsx'); + assert.equal(lossy.acknowledgeFidelityLoss, true); + assert.equal(lossy.lossyMacroRebuild, true); + + const standard = exportCopyPlan('models/report.xlsx', { canRoundTrip: false }); + assert.equal(standard.extension, 'xlsx'); + assert.equal(standard.acknowledgeFidelityLoss, true); +}); diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/ui.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/ui.js new file mode 100644 index 00000000..b0117b33 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/ui.js @@ -0,0 +1,489 @@ +import { + acceptProposalAction, + addSheet, + askAboutFocus, + copySelection, + createWorkbook, + ensureWorkbook, + exportCsv, + insertColumn, + insertRow, + jumpToProposal, + openFile, + pasteSelection, + pinFocus, + proposeSelectionFormat, + refreshFromEngine, + refreshHistory, + redoWorkbook, + rejectProposalAction, + saveWorkbook, + switchSheet, + undoWorkbook, +} from './src/actions.js'; +import { commitModeToBackend, scheduleFocusSync, syncFocusToHost } from './src/focus.js'; +import { + clearProposalCellSelection, + refreshProposal, + renderProposalBar, + selectAllProposalCells, + toggleProposalCell, + toggleProposalExpanded, +} from './src/proposal.js'; +import { commitEdit } from './src/grid.js'; +import { agentRefreshTargetsCurrentWorkbook } from './src/interaction.js'; +import { t } from './src/i18n.js'; +import { render } from './src/render.js'; +import { state, invalidateCells } from './src/state.js'; +import { closestElement, normalizePathForCompare, runtime } from './src/util.js'; +import { applyStaticTexts, hideToast, showToast, updateChrome } from './src/views.js'; + +const AGENT_MUTATING_TOOLS = new Set([ + 'propose_patch', + 'accept_proposal', + 'reject_proposal', + 'create_workbook', + 'open_workbook', + 'save_workbook', + 'switch_sheet', + 'undo_workbook', + 'redo_workbook', + 'undo', + 'redo', + 'apply_local_patch', +]); + +let routeEventSeen = false; +let deferredPointerAction = null; + +const EDIT_COMMIT_ACTIONS = new Set([ + 'new-workbook', + 'open-workbook', + 'save-workbook', + 'export-csv', + 'pin-focus', + 'ask-focus', + 'undo', + 'redo', + 'accept-proposal', + 'reject-proposal', + 'jump-proposal', + 'toggle-proposal-details', + 'proposal-select-all', + 'proposal-select-none', + 'insert-row', + 'insert-col', + 'switch-sheet', + 'add-sheet', + 'set-mode', + 'format-role', + 'format-bold', +]); + +function normalizeRoute(route) { + const value = String(route || '/sheet').trim(); + if (!value || value === '/') return '/sheet'; + return value.startsWith('/') ? value : `/${value}`; +} + +function queueBoot(payload) { + const chain = state.bootChain || Promise.resolve(); + state.bootChain = chain + .then(() => ensureWorkbook(payload)) + .catch(() => {}); +} + +function resolveWorkspacePath(payload) { + const host = runtime(); + return ( + payload.workspacePath || + payload.workbench?.workspacePath || + state.workspacePath || + host.workspaceDir || + host.appDataDir || + null + ); +} + +function resolveLaunchPath(payload) { + return ( + payload.path || + payload.workbookPath || + payload.filePath || + payload.launchPath || + payload.workbench?.path || + null + ); +} + +function handleRouteEvent(payload = {}) { + routeEventSeen = true; + state.route = normalizeRoute(payload.route || state.route); + state.tabId = payload.tabId || state.tabId; + state.sessionId = payload.sessionId || state.sessionId; + + const nextWorkspace = resolveWorkspacePath(payload); + const workspaceChanged = Boolean( + nextWorkspace + && state.workspacePath + && normalizePathForCompare(nextWorkspace) !== normalizePathForCompare(state.workspacePath), + ); + state.workspacePath = nextWorkspace || state.workspacePath; + + let launchPath = resolveLaunchPath(payload); + if ( + launchPath && + state.workbookId && + normalizePathForCompare(state.path) === normalizePathForCompare(launchPath) + ) { + launchPath = null; + } + if (launchPath) state.pendingLaunchPath = launchPath; + + if (workspaceChanged) { + state.workbookId = null; + state.path = null; + state.meta = null; + state.sheets = []; + state.activeSheetId = null; + state.proposal = null; + invalidateCells(); + state.sheetLayouts.clear(); + state.dirty = false; + state.bootDone = false; + state.viewport.scrollRow = 0; + state.viewport.scrollCol = 0; + } + + render(); + + if (state.workspacePath && (launchPath || workspaceChanged || !state.workbookId)) { + queueBoot(payload); + } +} + +function handleActivate(payload = {}) { + handleRouteEvent(payload || {}); +} + +function shortToolName(toolName) { + const raw = String(toolName || ''); + // Host emits fully-qualified names like + // agentcomponent__excel-live-agent__propose_patch. + const parts = raw.split('__'); + return (parts[parts.length - 1] || raw).trim(); +} + +function handleAgentToolEvent(payload = {}) { + const toolName = shortToolName(payload.toolName); + const eventType = String(payload.eventType || '').toLowerCase(); + if (eventType !== 'completed' || !AGENT_MUTATING_TOOLS.has(toolName)) return; + const targetWorkbookId = typeof payload.workbookId === 'string' + ? payload.workbookId.trim() + : ''; + // A chat session can own more than one Excel Live surface. Once a surface is + // bound, even open/create completions for workbook B must not rebind the + // surface already showing workbook A. + if (!agentRefreshTargetsCurrentWorkbook(state.workbookId, targetWorkbookId)) return; + if (state.agentRefreshTimer) clearTimeout(state.agentRefreshTimer); + state.agentRefreshTimer = setTimeout(() => { + state.agentRefreshTimer = null; + void refreshFromEngine(targetWorkbookId || null); + }, 350); +} + +function modeLabel(mode) { + if (mode === 'inspect') return t('modeInspect'); + if (mode === 'author') return t('modeAuthor'); + return t('modeEdit'); +} + +async function applyMode(mode) { + const nextMode = ['inspect', 'edit', 'author'].includes(mode) ? mode : 'edit'; + if ( + !state.workbookId + || state.loading + || state.dialogPending + || state.modePending + || nextMode === state.mode + ) return false; + const previousMode = state.mode; + const previousStatus = state.status; + state.modePending = true; + state.pendingMode = nextMode; + state.status = t('modeSwitching', { mode: modeLabel(nextMode) }); + updateChrome(); + renderProposalBar(); + try { + // Explicit mode changes are a confirmed execution boundary. Ambient focus + // sync may be best-effort, but this backend write must complete before the + // UI exposes the new permissions to either the user or AI context. + await commitModeToBackend(nextMode); + state.mode = nextMode; + state.status = t('modeChanged', { mode: modeLabel(nextMode) }); + return true; + } catch (_error) { + state.mode = previousMode; + state.status = previousStatus; + showToast('error', t('modeSwitchFailed', { mode: modeLabel(previousMode) })); + return false; + } finally { + state.modePending = false; + state.pendingMode = null; + updateChrome(); + renderProposalBar(); + // Selection can continue moving while the mode request is in flight. + // Re-publish the latest focus after the boundary settles so host context + // and engine focus cannot retain the pre-switch cell. + syncFocusToHost({ force: true, broadcast: true }); + } +} + +function actionDescriptor(actionNode) { + return { + action: actionNode?.dataset?.action || '', + mode: actionNode?.dataset?.mode || null, + sheetId: actionNode?.dataset?.sheetId || null, + styleRole: actionNode?.dataset?.styleRole || null, + }; +} + +function performAction(descriptor) { + const action = descriptor.action; + if (action === 'new-workbook') void createWorkbook(); + if (action === 'open-workbook') void openFile(); + if (action === 'save-workbook') void saveWorkbook(); + if (action === 'export-csv') void exportCsv(); + if (action === 'pin-focus') void pinFocus(); + if (action === 'ask-focus') void askAboutFocus(); + if (action === 'undo') void undoWorkbook(); + if (action === 'redo') void redoWorkbook(); + if (action === 'accept-proposal') void acceptProposalAction(); + if (action === 'reject-proposal') void rejectProposalAction(); + if (action === 'jump-proposal') void jumpToProposal(); + if (action === 'toggle-proposal-details') toggleProposalExpanded(); + if (action === 'proposal-select-all') selectAllProposalCells(); + if (action === 'proposal-select-none') clearProposalCellSelection(); + if (action === 'insert-row') void insertRow(); + if (action === 'insert-col') void insertColumn(); + if (action === 'switch-sheet') void switchSheet(descriptor.sheetId); + if (action === 'add-sheet') void addSheet(); + if (action === 'dismiss-toast') hideToast(); + if (action === 'set-mode') void applyMode(descriptor.mode || 'edit'); + if (action === 'format-role') { + void proposeSelectionFormat({ + styleRole: descriptor.styleRole, + intent: t('formatRoleIntent', { role: t(`format${String(descriptor.styleRole || '').replace(/^./, (value) => value.toUpperCase())}`) }), + }); + } + if (action === 'format-bold') { + void proposeSelectionFormat({ style: { font: { bold: true } }, intent: t('formatBoldIntent') }); + } +} + +async function proposeFormatAfterEdit(change) { + if (state.editing && !(await commitEdit({ exit: true }))) return; + await proposeSelectionFormat(change); +} + +async function performActionAfterEdit(descriptor) { + if (descriptor.action === 'accept-proposal' || descriptor.action === 'reject-proposal') { + try { + await refreshProposal({ preserveSelection: true }); + renderProposalBar(); + } catch (error) { + showToast('error', error?.message || t('operationPending')); + return; + } + } + performAction(descriptor); +} + +function finishDeferredPointerAction(record) { + if (deferredPointerAction !== record || !record.released || !record.settled) return; + if (record.finishScheduled) return; + record.finishScheduled = true; + setTimeout(() => { + if (deferredPointerAction !== record) return; + deferredPointerAction = null; + if (record.confirmed && record.committed) void performActionAfterEdit(record.descriptor); + }, 0); +} + +// Pointer activation must cross the edit boundary before the requested action. +// Otherwise blur starts an async commit, disables the pressed control, and the +// browser drops the click. A failed commit restores the draft and stops here. +document.addEventListener('pointerdown', (event) => { + if (event.button !== 0 || !state.editing) return; + const actionNode = closestElement(event.target, '[data-action]'); + if (!actionNode || actionNode.disabled || !EDIT_COMMIT_ACTIONS.has(actionNode.dataset.action)) return; + const record = { + node: actionNode, + descriptor: actionDescriptor(actionNode), + released: false, + confirmed: false, + settled: false, + committed: false, + finishScheduled: false, + }; + deferredPointerAction = record; + event.preventDefault(); + event.stopPropagation(); + void commitEdit({ exit: true }).then((committed) => { + record.committed = committed; + record.settled = true; + finishDeferredPointerAction(record); + }); +}, true); + +document.addEventListener('pointerup', (event) => { + const record = deferredPointerAction; + if (!record) return; + const releasedNode = closestElement(event.target, '[data-action]'); + const hitNode = typeof document.elementFromPoint === 'function' + ? closestElement(document.elementFromPoint(event.clientX, event.clientY), '[data-action]') + : null; + record.released = true; + record.confirmed = releasedNode === record.node || hitNode === record.node; + finishDeferredPointerAction(record); +}, true); + +document.addEventListener('pointercancel', () => { + const record = deferredPointerAction; + if (!record) return; + record.released = true; + record.confirmed = false; + finishDeferredPointerAction(record); +}, true); + +document.addEventListener('click', (event) => { + const actionNode = closestElement(event.target, '[data-action]'); + if (!actionNode) return; + if (actionNode === deferredPointerAction?.node) { + event.preventDefault(); + event.stopImmediatePropagation(); + return; + } + performAction(actionDescriptor(actionNode)); +}); + +document.addEventListener('change', (event) => { + const node = event.target; + if (node?.dataset?.action === 'toggle-include-focus') { + state.includeFocusOnSend = Boolean(node.checked); + scheduleFocusSync({ force: true, immediate: true }); + } + if (node?.dataset?.action === 'toggle-proposal-cell') { + toggleProposalCell(node.dataset.cellRef || '', Boolean(node.checked)); + } + if (node?.dataset?.action === 'format-fill') { + const swatch = node.closest?.('.el-format-color')?.querySelector('span'); + if (swatch) swatch.style.borderBottomColor = node.value; + void proposeFormatAfterEdit({ + style: { fill: { color: node.value } }, + intent: t('formatFillIntent'), + }); + } + if (node?.dataset?.action === 'format-number') { + void proposeFormatAfterEdit({ + style: { numberFormat: node.value }, + intent: t('formatNumberIntent', { format: node.options?.[node.selectedIndex]?.textContent || node.value }), + }); + } +}); + +document.addEventListener('excel-live:save', () => { + void saveWorkbook(); +}); + +document.addEventListener('excel-live:undo', () => { + void undoWorkbook(); +}); + +document.addEventListener('excel-live:redo', () => { + void redoWorkbook(); +}); + +document.addEventListener('excel-live:copy', () => { + void copySelection(); +}); + +document.addEventListener('excel-live:paste', () => { + void pasteSelection(); +}); + +document.addEventListener('excel-live:history-refresh', () => { + void refreshHistory(); +}); + +document.addEventListener('excel-live:proposal-render', () => { + renderProposalBar(); +}); + +document.addEventListener('excel-live:proposal-refresh', () => { + void refreshProposal({ preserveSelection: true }).then(() => { + renderProposalBar(); + }); +}); + +document.addEventListener('excel-live:editing-settled', () => { + const pending = state.pendingAgentRefresh; + if (!pending) return; + state.pendingAgentRefresh = null; + if (state.agentRefreshTimer) clearTimeout(state.agentRefreshTimer); + state.agentRefreshTimer = setTimeout(() => { + state.agentRefreshTimer = null; + void refreshFromEngine(pending.targetWorkbookId || null); + }, 0); +}); + +window.addEventListener('message', (event) => { + const message = event.data; + if (message?.type !== 'sparo:event') return; + if (message.event === 'localeChange') { + state.locale = message.payload?.locale || state.locale; + applyStaticTexts(); + state.lastSheetTabsKey = null; + render(); + } + if (message.event === 'productAppRuntimeRouteChange') { + handleRouteEvent(message.payload || {}); + } + if (message.event === 'productAppRuntimeActivate') { + handleActivate(message.payload || {}); + } + if (message.event === 'productAppRuntimeAgentToolEvent') { + handleAgentToolEvent(message.payload || {}); + } + if (message.event === 'spreadsheetFocusPreferenceChange') { + const includeOnSend = message.payload?.includeOnSend; + if (typeof includeOnSend === 'boolean') { + state.includeFocusOnSend = includeOnSend; + // Host-originated preference update: reflect it without syncing back, + // otherwise host and iframe would form an event loop. + updateChrome(); + } + } +}); + +runtime().onLocaleChange?.((locale) => { + state.locale = locale || state.locale; + applyStaticTexts(); + state.lastSheetTabsKey = null; + render(); +}); + +runtime().onActivate?.(handleActivate); + +window.addEventListener('DOMContentLoaded', () => { + const host = runtime(); + state.locale = host.locale || state.locale; + render(); + + // The host pushes route context after load; boot from bridge-provided + // directories only if no route event arrives (standalone preview). + setTimeout(() => { + if (routeEventSeen || state.bootDone || state.bootChain) return; + handleRouteEvent({}); + }, 2500); +}); diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/worker.js b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/worker.js new file mode 100644 index 00000000..7a65ed27 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/components/surfaces/builtin-excel-live-surface/source/worker.js @@ -0,0 +1,13 @@ +'use strict'; + +async function status() { + return { + ok: true, + mode: 'composite', + runtime: 'host-panel', + }; +} + +module.exports = { + status, +}; diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/config/data-schema.json b/bundles/product-apps/builtin-excel-live/1.0.1/config/data-schema.json new file mode 100644 index 00000000..1587a669 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/config/data-schema.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/config/default.json b/bundles/product-apps/builtin-excel-live/1.0.1/config/default.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/config/default.json @@ -0,0 +1 @@ +{} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/tests/eval.json b/bundles/product-apps/builtin-excel-live/1.0.1/tests/eval.json new file mode 100644 index 00000000..17984415 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/tests/eval.json @@ -0,0 +1,24 @@ +{ + "version": 1, + "cases": [ + { + "id": "primary-behavior", + "title": "Excel Live responds from its declared app context", + "description": "Proves that the immutable Release can invoke its intelligent behavior.", + "input": { + "message": "Reply with SPARO_APP_READY, then briefly confirm you can help with Excel Live." + }, + "expectations": [ + { + "kind": "text-contains", + "value": "SPARO_APP_READY" + } + ], + "evidenceKind": "behavior", + "tags": [ + "release-gate" + ], + "required": true + } + ] +} diff --git a/bundles/product-apps/builtin-excel-live/1.0.1/tests/rehearsal.json b/bundles/product-apps/builtin-excel-live/1.0.1/tests/rehearsal.json new file mode 100644 index 00000000..1f3c0833 --- /dev/null +++ b/bundles/product-apps/builtin-excel-live/1.0.1/tests/rehearsal.json @@ -0,0 +1,33 @@ +{ + "version": 1, + "scenarios": [ + { + "id": "critical-user-path", + "title": "Open Excel Live and complete its first useful action", + "description": "A revisioned spreadsheet workbench where people and agents share grounded focus, review proposals on the grid, undo safely, and export source-preserving workbook copies.", + "kind": "user-path", + "steps": [ + { + "id": "open-app", + "action": "open", + "target": "primary", + "expect": [ + "Excel Live opens" + ] + }, + { + "id": "observe-ready-state", + "action": "observe", + "target": "work-outcome", + "expect": [ + "A usable ready state is visible" + ] + } + ], + "expected": [ + "The app opens without a fatal runtime issue", + "The primary workflow exposes an observable path" + ] + } + ] +} diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/app.json b/bundles/product-apps/builtin-harmony-dev/13.0.1/app.json new file mode 100644 index 00000000..239da66f --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/app.json @@ -0,0 +1,316 @@ +{ + "id": "builtin-harmony-dev", + "version": "13.0.1", + "name": "HarmonyOS Dev", + "description": "An integrated HarmonyOS app development environment that brings ArkTS, ArkUI, building, packaging, debugging, and device runtime into one workspace.", + "authors": [ + { + "name": "Sparo OS", + "url": "https://gcwing.github.io/Sparo-Agentic-OS/" + } + ], + "i18n": { + "locales": { + "en-US": { + "name": "HarmonyOS Dev", + "description": "An integrated HarmonyOS app development environment that brings ArkTS, ArkUI, building, packaging, debugging, and device runtime into one workspace.", + "tags": [ + "built-in", + "harmonyos", + "arkui", + "device", + "build" + ] + }, + "zh-CN": { + "name": "HarmonyOS Dev", + "description": "一体化鸿蒙应用开发环境,把 ArkTS、ArkUI、构建、打包、调试和设备运行集中到一个工作空间。", + "tags": [ + "内置", + "harmonyos", + "arkui", + "设备", + "构建" + ] + } + } + }, + "interactionModel": "interactiveWorkspace", + "workMultiplicity": "multiple", + "workObjectKinds": [ + { + "id": "workspace", + "label": "Workspace", + "scope": "workspace", + "identitySchema": { + "type": "object", + "required": [ + "workspacePath" + ], + "properties": { + "workspacePath": { + "type": "string" + } + } + }, + "contextSchema": { + "type": "object", + "properties": { + "projectKind": { + "type": "string" + }, + "bundleName": { + "type": "string" + } + } + } + }, + { + "id": "ability", + "label": "Ability", + "scope": "project", + "identitySchema": { + "type": "object", + "required": [ + "bundleName", + "abilityName" + ], + "properties": { + "bundleName": { + "type": "string" + }, + "abilityName": { + "type": "string" + } + } + }, + "contextSchema": { + "type": "object", + "properties": { + "entryModule": { + "type": "string" + }, + "route": { + "type": "string" + } + } + } + }, + { + "id": "build-run", + "label": "Build Run", + "scope": "runtime", + "identitySchema": { + "type": "object", + "properties": { + "runId": { + "type": "string" + }, + "task": { + "type": "string" + } + } + }, + "contextSchema": { + "type": "object", + "properties": { + "status": { + "type": "string" + }, + "artifactPath": { + "type": "string" + }, + "diagnostics": { + "type": "array" + } + } + } + }, + { + "id": "device-target", + "label": "Device Target", + "scope": "device", + "identitySchema": { + "type": "object", + "required": [ + "targetId" + ], + "properties": { + "targetId": { + "type": "string" + }, + "targetType": { + "type": "string" + } + } + }, + "contextSchema": { + "type": "object", + "properties": { + "online": { + "type": "boolean" + }, + "apiVersion": { + "type": "string" + }, + "emulatorName": { + "type": "string" + } + } + } + }, + { + "id": "module", + "label": "Module", + "scope": "project", + "identitySchema": { + "type": "object", + "required": [ + "moduleName" + ], + "properties": { + "moduleName": { + "type": "string" + }, + "modulePath": { + "type": "string" + } + } + }, + "contextSchema": { + "type": "object", + "properties": { + "targetSdk": { + "type": "string" + }, + "mainElement": { + "type": "string" + } + } + } + } + ], + "truthSource": "runtimeFact", + "primarySurface": { + "componentId": "builtin-harmony-dev-surface", + "surfaceId": "primary" + }, + "primarySurfaceMode": "sidecarLinked", + "components": [ + { + "componentId": "builtin-harmony-dev-surface", + "kind": "surface", + "source": "private", + "role": "primarySurface", + "capabilities": [ + "interactiveSurface" + ], + "usesCapabilities": [ + "session.read", + "component.run" + ] + }, + { + "componentId": "harmonyos-dev-agent", + "kind": "agent", + "source": "private", + "role": "assistant", + "capabilities": [ + "understandHarmonyProject", + "reviseHarmonyUi", + "buildInstallVerify", + "diagnoseHarmonyFailure" + ], + "usesCapabilities": [ + "filesystem.read", + "filesystem.write", + "terminal.run", + "process.spawn", + "workspace.inspect", + "workspace.modify", + "session.read", + "model.invoke", + "tool.invoke", + "component.run" + ] + }, + { + "componentId": "builtin-harmony-runtime", + "kind": "bridge", + "source": "private", + "role": "runtime", + "capabilities": [ + "sparo.harmonyDev" + ], + "usesCapabilities": [ + "filesystem.read", + "filesystem.write", + "terminal.run", + "process.spawn", + "workspace.inspect", + "component.run" + ] + }, + { + "componentId": "product-app-runtime-host", + "kind": "runtime", + "source": "shared", + "role": "runtimeHost", + "version": "^1.0.0", + "capabilities": [ + "uiWorker" + ], + "usesCapabilities": [ + "component.run" + ] + } + ], + "componentLockId": "", + "permissions": { + "fs": true, + "net": false, + "shell": true, + "gui": false, + "secrets": false, + "ai": true + }, + "installScope": "system", + "catalogVisibility": "discoverable", + "enabled": true, + "icon": { + "kind": "packageAsset", + "path": "assets/icon.png" + }, + "category": "developer", + "tags": [ + "built-in", + "harmonyos", + "arkui", + "device", + "build" + ], + "launch": { + "kind": "applicationSurface", + "targetId": "builtin-harmony-dev", + "scopeRequirement": "workspaceRequired", + "surfaceId": "primary" + }, + "osCapabilities": [ + "session.read", + "component.run", + "filesystem.read", + "filesystem.write", + "terminal.run", + "process.spawn", + "workspace.inspect", + "workspace.modify", + "model.invoke", + "tool.invoke" + ], + "dataLifecycle": { + "retention": "userManaged", + "deletion": "deleteOnUserRequest", + "migration": "schemaVersioned", + "share": "declaredWorkObjectsOnly" + } +} diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/assets/icon.png b/bundles/product-apps/builtin-harmony-dev/13.0.1/assets/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..fe207e503a44c8f83ca7856d37faf572f614e9d5 GIT binary patch literal 374263 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 literal 0 HcmV?d00001 diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/compatibility.json b/bundles/product-apps/builtin-harmony-dev/13.0.1/compatibility.json new file mode 100644 index 00000000..7ea934b0 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/compatibility.json @@ -0,0 +1,3 @@ +{ + "runtimeCompatibility": ">=0.1.0" +} diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/component.json b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/component.json new file mode 100644 index 00000000..e10fea41 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/component.json @@ -0,0 +1,110 @@ +{ + "id": "harmonyos-dev-agent", + "kind": "agent", + "name": "HarmonyOS Dev Agent", + "description": "An ArkTS/ArkUI development agent that edits source through workspace tools and verifies through the HarmonyOS Dev Runtime.", + "packageSource": "appPrivate", + "ownerApp": { + "appId": "builtin-harmony-dev", + "appVersion": "13.0.1" + }, + "capabilities": [ + { + "id": "understandHarmonyProject", + "title": "Understand HarmonyOS project", + "description": "Detect the HarmonyOS workspace, bundle, module, ability, target SDK, signing status, and likely ArkUI source files.", + "actions": [ + "detectProject", + "getRuntimeContext" + ] + }, + { + "id": "reviseHarmonyUi", + "title": "Revise HarmonyOS UI", + "description": "Make scoped ArkTS/ArkUI source edits from user intent and selected preview context.", + "actions": [ + "readSource", + "editSource", + "getFileDiff" + ] + }, + { + "id": "buildInstallVerify", + "title": "Build, install, and verify", + "description": "Build the HarmonyOS project, install and launch when a target is available, then capture screenshot and hierarchy evidence.", + "actions": [ + "buildProject", + "installAndLaunch", + "captureScreen", + "dumpHierarchy" + ] + }, + { + "id": "diagnoseHarmonyFailure", + "title": "Diagnose HarmonyOS failure", + "description": "Use redacted runtime diagnostics, build logs, HDC target state, and project source to explain and repair failures.", + "actions": [ + "getRuntimeContext", + "readDiagnostics", + "detectProject" + ] + } + ], + "permissions": [ + { + "kind": "ai", + "summary": "Uses configured AI providers through Sparo OS.", + "scopes": [ + "system", + "workspace" + ] + }, + { + "kind": "fs", + "summary": "Reads and edits HarmonyOS project files through declared workspace tools.", + "scopes": [ + "{workspace}" + ] + }, + { + "kind": "shell", + "summary": "Uses scoped workspace commands and delegates HarmonyOS toolchain operations to the runtime bridge.", + "scopes": [ + "node", + "git", + "hvigorw", + "hvigorw.bat", + "ohpm", + "ohpm.bat" + ] + } + ], + "usedByApps": [ + "builtin-harmony-dev" + ], + "visibility": "appDependency", + "dependencies": [ + { + "componentId": "builtin-harmony-runtime", + "kind": "bridge", + "source": "private", + "role": "harmonyRuntime", + "capabilities": [ + "sparo.harmonyDev" + ] + } + ], + "implementationRef": "app://builtin-harmony-dev@13.0.1/agents/harmonyos-dev-agent", + "usesCapabilities": [ + "filesystem.read", + "filesystem.write", + "terminal.run", + "process.spawn", + "workspace.inspect", + "workspace.modify", + "session.read", + "model.invoke", + "tool.invoke", + "component.run" + ] +} diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/agent.md b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/agent.md new file mode 100644 index 00000000..6860c3d7 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/agent.md @@ -0,0 +1,41 @@ +You are HarmonyOS Dev Agent, a senior ArkTS/ArkUI application developer inside Sparo OS. + +Core identity: +- Treat the running HarmonyOS app on the target device or emulator as the product surface. +- Source edits are useful only when build, install, launch, screenshot, UI hierarchy, logs, or a clear blocked device state prove what happened. +- Use selected screen context as a pointer, not as proof. Inspect source before editing. +- Keep HarmonyOS work native: ArkTS, ArkUI, module config, resources, permissions, and build profiles matter. + +Tool boundaries: +- Use the existing workspace tools for source work: LS, Glob, Grep, Read, Edit, Write, GetFileDiff, and Bash. +- Use your Agent Component runtime tools only for HarmonyOS toolchain and device operations through the HarmonyOS Dev Runtime: + - agentcomponent__harmonyos-dev-agent__detect_project + - agentcomponent__harmonyos-dev-agent__get_runtime_context + - agentcomponent__harmonyos-dev-agent__build_project + - agentcomponent__harmonyos-dev-agent__install_and_launch + - agentcomponent__harmonyos-dev-agent__capture_screen + - agentcomponent__harmonyos-dev-agent__dump_hierarchy +- Do not invent separate search, read, write, or workspace tools. Use the base tools. +- Do not bypass the HarmonyOS Dev Runtime to control HDC, HVigor, DevEco Emulator, or signing-sensitive operations unless the user explicitly asks for a raw local diagnostic command. + +Working principles: +- Start by detecting the HarmonyOS project and reading current runtime context. +- Locate UI source through bundle/module/ability/page metadata, selected hierarchy text, accessibility ids, component names, resource keys, and Grep/Read evidence. +- Keep edits scoped to relevant ETS, resource, module, or build-profile files. +- Never expose signing passwords, private keys, certificate material, token-like values, or full secret-bearing config lines. +- If no HDC target is online, say that install/launch/screenshot verification is blocked while still using build and static source evidence. +- Treat Hot Reload as an optional acceleration path. Build & Run is the correctness path. + +Failure behavior: +- If the workspace is not a HarmonyOS project, name the missing signal such as build-profile.json5, runtimeOS, AppScope/app.json5, or module.json5. +- If screenshot or hierarchy is unavailable, report that as an evidence gap rather than claiming visual verification. +- If a selected UI node cannot be mapped to source with confidence, explain the uncertainty and inspect nearby ArkUI files before editing. +- If build or install fails, use the redacted diagnostic and log path, make one reasoned fix, and avoid repeating the same failing command unchanged. + +Skill routing: +- Use harmony-fundamentals to understand project layout and config. +- Use arkui-component-workflow for UI edits. +- Use build-install-verify for build, install, launch, screenshot, and hierarchy loops. +- Use device-preview-context when the user points at the preview. +- Use signing-and-permissions for certificate/profile/permission questions, always redacted. +- Use troubleshooting for HDC, emulator, HVigor, launch, crash, and log failures. diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/bundle.json b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/bundle.json new file mode 100644 index 00000000..48e3c65f --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/bundle.json @@ -0,0 +1,5 @@ +{ + "schemaVersion": 1, + "id": "harmonyos-dev-agent", + "version": 1 +} diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/evals/cases.json b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/evals/cases.json new file mode 100644 index 00000000..3fe9d7bd --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/evals/cases.json @@ -0,0 +1,10 @@ +[ + { + "name": "detect-sparo-harmony", + "prompt": "Detect this HarmonyOS project and summarize bundle, module, ability, target SDK, and signing status without exposing secrets." + }, + { + "name": "selected-ui-edit", + "prompt": "Use the selected UI context as a pointer, find the likely ArkUI component, make a scoped spacing edit, and verify with build evidence." + } +] diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/manifest.json b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/manifest.json new file mode 100644 index 00000000..fa26be77 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/manifest.json @@ -0,0 +1,120 @@ +{ + "schemaVersion": 1, + "id": "harmonyos-dev-agent", + "name": "HarmonyOS Dev Agent", + "description": "An ArkTS/ArkUI development agent that edits source through base workspace tools and verifies through the HarmonyOS Dev Runtime.", + "icon": "smartphone", + "category": "mobile", + "tags": [ + "harmonyos", + "arkui", + "arkts", + "device", + "preview" + ], + "level": "user", + "model": "primary", + "readonly": false, + "enabled": true, + "tools": [ + "LS", + "Glob", + "Grep", + "Read", + "Edit", + "Write", + "GetFileDiff", + "Bash", + "agentcomponent__harmonyos-dev-agent__detect_project", + "agentcomponent__harmonyos-dev-agent__get_runtime_context", + "agentcomponent__harmonyos-dev-agent__build_project", + "agentcomponent__harmonyos-dev-agent__install_and_launch", + "agentcomponent__harmonyos-dev-agent__capture_screen", + "agentcomponent__harmonyos-dev-agent__dump_hierarchy" + ], + "skills": [ + "harmony-fundamentals", + "arkui-component-workflow", + "build-install-verify", + "device-preview-context", + "signing-and-permissions", + "troubleshooting" + ], + "subagents": [], + "toolPolicies": {}, + "bridgeCapabilities": [ + { + "bridgeId": "builtin-harmony-runtime", + "capabilityId": "sparo.harmonyDev", + "alias": "harmonyRuntime", + "mode": "auto" + } + ], + "serviceActions": [ + { + "name": "understandHarmonyProject", + "description": "Detect the HarmonyOS project, bundle, module, ability, target SDK, signing status, and likely ArkUI source files.", + "toolPolicy": [ + "agentcomponent__harmonyos-dev-agent__detect_project", + "agentcomponent__harmonyos-dev-agent__get_runtime_context", + "Glob", + "Grep", + "Read" + ], + "bridgeCall": { + "bridgeId": "builtin-harmony-runtime", + "capabilityId": "sparo.harmonyDev", + "action": "detectProject", + "mode": "auto" + } + }, + { + "name": "reviseHarmonyUi", + "description": "Make scoped ArkTS/ArkUI source edits from user intent and optional selected screen context.", + "toolPolicy": [ + "Read", + "Edit", + "Write", + "GetFileDiff", + "agentcomponent__harmonyos-dev-agent__get_runtime_context" + ] + }, + { + "name": "buildInstallVerify", + "description": "Build the HarmonyOS project, install and launch when a target is available, then capture screenshot and UI hierarchy evidence.", + "toolPolicy": [ + "agentcomponent__harmonyos-dev-agent__build_project", + "agentcomponent__harmonyos-dev-agent__install_and_launch", + "agentcomponent__harmonyos-dev-agent__capture_screen", + "agentcomponent__harmonyos-dev-agent__dump_hierarchy", + "GetFileDiff" + ] + }, + { + "name": "diagnoseHarmonyFailure", + "description": "Use redacted runtime diagnostics, build logs, HDC target state, and project source to explain and repair HarmonyOS failures.", + "toolPolicy": [ + "agentcomponent__harmonyos-dev-agent__get_runtime_context", + "agentcomponent__harmonyos-dev-agent__detect_project", + "Read", + "Grep", + "Edit", + "GetFileDiff" + ] + } + ], + "examples": [ + { + "title": "Refine selected UI", + "prompt": "Using the selected region in HarmonyOS Dev, make this ArkUI button spacing feel cleaner, then build and verify it." + }, + { + "title": "Fix launch failure", + "prompt": "Diagnose why the HarmonyOS app does not launch on the current target and propose the smallest source or config fix." + }, + { + "title": "Verify after edit", + "prompt": "Build the current HarmonyOS project, install it if a target is online, capture the screen, and summarize the evidence." + } + ] +} diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/routing.md b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/routing.md new file mode 100644 index 00000000..1b05b161 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/routing.md @@ -0,0 +1,8 @@ +Use HarmonyOS Dev Agent when the user is working on a HarmonyOS, ArkTS, ArkUI, DevEco, HVigor, HDC, emulator, build/install/launch, or device-preview task. + +Prefer this agent over a generic coding agent when: +- The request references a running HarmonyOS app, target, emulator, screenshot, UI hierarchy, HAP/APP artifact, ability, bundle, or module. +- The user points at the HarmonyOS Dev Product App surface preview and asks to change "this" or diagnose "what happened here". +- Verification needs build, install, launch, screenshot, hierarchy, or HDC logs. + +Do not use this agent for unrelated Android/iOS/Web work or for general-purpose shell automation. diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/schemas/action-output.schema.json b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/schemas/action-output.schema.json new file mode 100644 index 00000000..5b2f75d9 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/schemas/action-output.schema.json @@ -0,0 +1,9 @@ +{ + "type": "object", + "properties": { + "summary": { "type": "string" }, + "evidence": { "type": "array" }, + "blocked": { "type": "boolean" }, + "diagnostics": { "type": "array" } + } +} diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/schemas/harmony-dev-context.schema.json b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/schemas/harmony-dev-context.schema.json new file mode 100644 index 00000000..8ecca1c5 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/schemas/harmony-dev-context.schema.json @@ -0,0 +1,14 @@ +{ + "type": "object", + "properties": { + "workspacePath": { "type": "string" }, + "project": { "type": "object" }, + "target": { "type": ["object", "null"] }, + "app": { "type": "object" }, + "build": { "type": ["object", "null"] }, + "runtime": { "type": ["object", "null"] }, + "screen": { "type": ["object", "null"] }, + "selection": { "type": ["object", "null"] }, + "diagnostics": { "type": "array" } + } +} diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/schemas/screen-context.schema.json b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/schemas/screen-context.schema.json new file mode 100644 index 00000000..edf3851f --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/schemas/screen-context.schema.json @@ -0,0 +1,9 @@ +{ + "type": "object", + "properties": { + "screenshotId": { "type": ["string", "null"] }, + "boundsPercent": { "type": "object" }, + "hierarchyNode": { "type": ["object", "null"] }, + "sourceHints": { "type": "object" } + } +} diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/skills/arkui-component-workflow.md b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/skills/arkui-component-workflow.md new file mode 100644 index 00000000..0f446102 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/skills/arkui-component-workflow.md @@ -0,0 +1,9 @@ +# ArkUI Component Workflow + +For UI edits: +- Use selected screenshot or hierarchy context as a pointer. +- Search by visible text, accessibility id, component type, page path, resource key, and nearby component names. +- Read the target ETS files before editing. +- Keep layout changes localized and deterministic. +- Prefer ArkUI-native layout primitives and resource usage already present in the project. +- After editing, use GetFileDiff and then build/verify when feasible. diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/skills/build-install-verify.md b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/skills/build-install-verify.md new file mode 100644 index 00000000..bf562dfd --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/skills/build-install-verify.md @@ -0,0 +1,12 @@ +# Build Install Verify + +Default verification loop: +1. Detect project and toolchain. +2. Build with HVigor. +3. If an HDC target is online, install the latest artifact. +4. Launch the detected bundle and ability. +5. Capture screenshot and UI hierarchy when probes are available. +6. Summarize evidence and gaps. + +If no target is online, report build evidence and the blocked device gate explicitly. +Do not treat Hot Reload as proof; use it only as an optional acceleration path. diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/skills/device-preview-context.md b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/skills/device-preview-context.md new file mode 100644 index 00000000..1f33cc21 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/skills/device-preview-context.md @@ -0,0 +1,14 @@ +# Device Preview Context + +Preview context can include: +- workspace path +- bundle, module, ability +- target id and state +- screenshot id/path/timestamp +- UI hierarchy timestamp and selected node +- selected region bounds +- source hints and confidence +- recent build/install/launch diagnostics + +Use low-confidence region selections as visual pointers only. +High-confidence selections still require source inspection before edits. diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/skills/harmony-fundamentals.md b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/skills/harmony-fundamentals.md new file mode 100644 index 00000000..a66c0ca8 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/skills/harmony-fundamentals.md @@ -0,0 +1,13 @@ +# HarmonyOS Fundamentals + +Key files: +- `build-profile.json5`: products, runtimeOS, target SDK, modules, build modes, signing references. +- `AppScope/app.json5`: bundle name, app label, icon, version. +- `entry/src/main/module.json5`: module name, main ability, device types, permissions, pages, ability entries. +- `entry/src/main/ets`: ArkTS abilities, pages, components, services, and models. +- `entry/src/main/resources`: strings, colors, media, profiles, and page lists. + +Detection rules: +- Confirm `runtimeOS` is `HarmonyOS`. +- Read bundle/module/ability metadata before editing. +- Treat signing material as sensitive. Only report whether signing is configured and whether referenced files appear present. diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/skills/signing-and-permissions.md b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/skills/signing-and-permissions.md new file mode 100644 index 00000000..2a075ac1 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/skills/signing-and-permissions.md @@ -0,0 +1,16 @@ +# Signing And Permissions + +Never reveal: +- signing passwords +- store passwords +- private keys +- certificate secret material +- token-like values + +Safe to report: +- signing configured: true/false +- material paths present: true/false +- profile/certificate missing at a high level +- permission names and ability usage from module config + +If signing blocks install, ask the user to refresh local DevEco signing material or choose unsigned build validation when appropriate. diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/skills/troubleshooting.md b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/skills/troubleshooting.md new file mode 100644 index 00000000..e27a6d33 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/skills/troubleshooting.md @@ -0,0 +1,9 @@ +# Troubleshooting + +Common gates: +- No HDC target: install, launch, screenshot, hierarchy, and hilog are blocked. +- Emulator listed but not online: start public emulator and wait for HDC target. +- Beta/non-public emulator: do not default to it. +- HVigor failure: read the redacted build diagnostic and relevant source/config. +- Launch failure: verify bundleName, ability name, module config, install result, and `aa start` output. +- Screenshot or hierarchy failure: report the exact missing probe and continue with available evidence. diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/build_project.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/build_project.js new file mode 100644 index 00000000..7761247f --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/build_project.js @@ -0,0 +1,12 @@ +const { callHarmonyRuntime } = require("./harmony_bridge"); + +async function run(input, context) { + return callHarmonyRuntime( + "buildProject", + input, + context, + "Ran the HarmonyOS build pipeline.", + ); +} + +module.exports = { run }; diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/build_project.tool.json b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/build_project.tool.json new file mode 100644 index 00000000..d6ee906b --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/build_project.tool.json @@ -0,0 +1,19 @@ +{ + "name": "build_project", + "description": "Run the HarmonyOS HVigor build pipeline and return structured, redacted build diagnostics and artifact state.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "workspacePath": { "type": "string" }, + "includeTests": { "type": "boolean" }, + "timeoutMs": { "type": "number" } + } + }, + "runtime": "javascript", + "entry": "tools/build_project.js", + "readonly": false, + "permissions": {}, + "timeoutMs": 30000, + "maxOutputBytes": 24000 +} diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/capture_screen.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/capture_screen.js new file mode 100644 index 00000000..2369128a --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/capture_screen.js @@ -0,0 +1,12 @@ +const { callHarmonyRuntime } = require("./harmony_bridge"); + +async function run(input, context) { + return callHarmonyRuntime( + "captureScreen", + input, + context, + "Captured HarmonyOS screen evidence.", + ); +} + +module.exports = { run }; diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/capture_screen.tool.json b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/capture_screen.tool.json new file mode 100644 index 00000000..7966e5b2 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/capture_screen.tool.json @@ -0,0 +1,19 @@ +{ + "name": "capture_screen", + "description": "Capture HarmonyOS screen evidence from the selected emulator or HDC target when the probe is available.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "workspacePath": { "type": "string" }, + "targetId": { "type": "string" }, + "emulatorName": { "type": "string" } + } + }, + "runtime": "javascript", + "entry": "tools/capture_screen.js", + "readonly": true, + "permissions": {}, + "timeoutMs": 30000, + "maxOutputBytes": 24000 +} diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/detect_project.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/detect_project.js new file mode 100644 index 00000000..8cdf509c --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/detect_project.js @@ -0,0 +1,12 @@ +const { callHarmonyRuntime } = require("./harmony_bridge"); + +async function run(input, context) { + return callHarmonyRuntime( + "detectProject", + input, + context, + "Detected the HarmonyOS project identity.", + ); +} + +module.exports = { run }; diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/detect_project.tool.json b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/detect_project.tool.json new file mode 100644 index 00000000..567efbc7 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/detect_project.tool.json @@ -0,0 +1,17 @@ +{ + "name": "detect_project", + "description": "Detect whether the current workspace is a HarmonyOS project and load bundle, module, ability, SDK, signing, and source hints.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "workspacePath": { "type": "string" } + } + }, + "runtime": "javascript", + "entry": "tools/detect_project.js", + "readonly": true, + "permissions": {}, + "timeoutMs": 30000, + "maxOutputBytes": 16000 +} diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/dump_hierarchy.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/dump_hierarchy.js new file mode 100644 index 00000000..1e9eea3a --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/dump_hierarchy.js @@ -0,0 +1,12 @@ +const { callHarmonyRuntime } = require("./harmony_bridge"); + +async function run(input, context) { + return callHarmonyRuntime( + "dumpHierarchy", + input, + context, + "Captured HarmonyOS UI hierarchy evidence.", + ); +} + +module.exports = { run }; diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/dump_hierarchy.tool.json b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/dump_hierarchy.tool.json new file mode 100644 index 00000000..78e74339 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/dump_hierarchy.tool.json @@ -0,0 +1,18 @@ +{ + "name": "dump_hierarchy", + "description": "Capture HarmonyOS UI hierarchy JSON for source mapping when the target-side probe is available.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "workspacePath": { "type": "string" }, + "targetId": { "type": "string" } + } + }, + "runtime": "javascript", + "entry": "tools/dump_hierarchy.js", + "readonly": true, + "permissions": {}, + "timeoutMs": 30000, + "maxOutputBytes": 24000 +} diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/get_runtime_context.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/get_runtime_context.js new file mode 100644 index 00000000..5ea9a137 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/get_runtime_context.js @@ -0,0 +1,12 @@ +const { callHarmonyRuntime } = require("./harmony_bridge"); + +async function run(input, context) { + return callHarmonyRuntime( + input?.includeDiagnostics ? "readDiagnostics" : "getRuntimeState", + input, + context, + "Loaded the HarmonyOS runtime context.", + ); +} + +module.exports = { run }; diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/get_runtime_context.tool.json b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/get_runtime_context.tool.json new file mode 100644 index 00000000..0296b40a --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/get_runtime_context.tool.json @@ -0,0 +1,18 @@ +{ + "name": "get_runtime_context", + "description": "Read the current HarmonyOS device, build, runtime, screenshot, hierarchy, and diagnostic context.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "workspacePath": { "type": "string" }, + "includeDiagnostics": { "type": "boolean" } + } + }, + "runtime": "javascript", + "entry": "tools/get_runtime_context.js", + "readonly": true, + "permissions": {}, + "timeoutMs": 30000, + "maxOutputBytes": 24000 +} diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/harmony_bridge.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/harmony_bridge.js new file mode 100644 index 00000000..8d203a21 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/harmony_bridge.js @@ -0,0 +1,26 @@ +const BRIDGE_ID = "builtin-harmony-runtime"; +const CAPABILITY_ID = "sparo.harmonyDev"; + +function normalizeInput(input = {}, context = {}) { + const payload = { ...input }; + if (!payload.workspacePath && !payload.workspace_path && context.workspaceRoot) { + payload.workspacePath = context.workspaceRoot; + } + return payload; +} + +function callHarmonyRuntime(action, input, context, summary) { + return { + summary, + bridgeCall: { + bridgeId: BRIDGE_ID, + capabilityId: CAPABILITY_ID, + action, + input: normalizeInput(input, context), + }, + }; +} + +module.exports = { + callHarmonyRuntime, +}; diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/install_and_launch.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/install_and_launch.js new file mode 100644 index 00000000..7c1a8333 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/install_and_launch.js @@ -0,0 +1,15 @@ +const { callHarmonyRuntime } = require("./harmony_bridge"); + +async function run(input = {}, context) { + const action = input.mode === "launch" ? "launchAbility" : "installApp"; + return callHarmonyRuntime( + action, + input, + context, + input.mode === "launch" + ? "Launched the HarmonyOS ability through HDC." + : "Installed the HarmonyOS artifact through HDC.", + ); +} + +module.exports = { run }; diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/install_and_launch.tool.json b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/install_and_launch.tool.json new file mode 100644 index 00000000..beb0a0bb --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/agents/harmonyos-dev-agent/source/tools/install_and_launch.tool.json @@ -0,0 +1,22 @@ +{ + "name": "install_and_launch", + "description": "Install the latest HarmonyOS artifact or launch the detected ability on the current HDC target. Pass mode='launch' for the launch step.", + "inputSchema": { + "type": "object", + "additionalProperties": false, + "properties": { + "workspacePath": { "type": "string" }, + "mode": { "type": "string", "enum": ["install", "launch"] }, + "targetId": { "type": "string" }, + "artifactPath": { "type": "string" }, + "bundleName": { "type": "string" }, + "abilityName": { "type": "string" } + } + }, + "runtime": "javascript", + "entry": "tools/install_and_launch.js", + "readonly": false, + "permissions": {}, + "timeoutMs": 30000, + "maxOutputBytes": 24000 +} diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/component.json b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/component.json new file mode 100644 index 00000000..e5a9fb3b --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/component.json @@ -0,0 +1,80 @@ +{ + "id": "builtin-harmony-runtime", + "kind": "bridge", + "name": "HarmonyOS Dev Runtime", + "description": "DevEco, HVigor, HDC, Emulator, build, install, launch, screenshot, hierarchy, and diagnostics bridge for HarmonyOS Dev.", + "packageSource": "appPrivate", + "ownerApp": { + "appId": "builtin-harmony-dev", + "appVersion": "13.0.1" + }, + "capabilities": [ + { + "id": "sparo.harmonyDev", + "title": "HarmonyOS Dev Runtime", + "description": "Detect HarmonyOS project identity, resolve DevEco/HVigor/HDC/Emulator tooling, run build/install/launch loops, capture device facts, and report redacted diagnostics.", + "actions": [ + "detectProject", + "detectToolchain", + "listEmulators", + "startEmulator", + "stopEmulator", + "listTargets", + "runUnitTests", + "assembleApp", + "buildProject", + "hotReload", + "installApp", + "launchAbility", + "captureScreen", + "readScreenshot", + "dumpHierarchy", + "readLogs", + "readDiagnostics", + "getRuntimeState" + ] + } + ], + "permissions": [ + { + "kind": "fs", + "summary": "Reads HarmonyOS project metadata and writes workspace-local runtime facts, screenshots, build state, and diagnostics.", + "scopes": [ + "{workspace}", + "{app}", + "{home}" + ] + }, + { + "kind": "shell", + "summary": "Runs the declared HarmonyOS project, DevEco, HVigor, HDC, Emulator, Java, and package-manager commands.", + "scopes": [ + "node", + "git", + "hvigorw", + "hvigorw.bat", + "hdc", + "hdc.exe", + "ohpm", + "ohpm.bat", + "java", + "java.exe", + "Emulator.exe" + ] + } + ], + "usedByApps": [ + "builtin-harmony-dev" + ], + "visibility": "appDependency", + "dependencies": [], + "implementationRef": "app://builtin-harmony-dev@13.0.1/bridges/builtin-harmony-runtime", + "usesCapabilities": [ + "filesystem.read", + "filesystem.write", + "terminal.run", + "process.spawn", + "workspace.inspect", + "component.run" + ] +} diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/bundle.json b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/bundle.json new file mode 100644 index 00000000..3f0b6613 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/bundle.json @@ -0,0 +1,5 @@ +{ + "schemaVersion": 1, + "id": "builtin-harmony-runtime", + "version": 6 +} diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/manifest.json b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/manifest.json new file mode 100644 index 00000000..ec50057b --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/manifest.json @@ -0,0 +1,362 @@ +{ + "schemaVersion": 1, + "id": "builtin-harmony-runtime", + "name": "HarmonyOS Dev Runtime", + "description": "DevEco, HVigor, HDC, Emulator, build, install, launch, screenshot, hierarchy, and diagnostics bridge for HarmonyOS Dev.", + "kind": "daemon", + "runtime": { + "language": "javascript", + "entry": "worker.js" + }, + "surfaces": { + "launchableApp": false, + "agent": true, + "tool": true, + "productAppRuntimeBackend": true + }, + "permissions": { + "fs": [ + "{workspace}", + "{app}", + "{home}" + ], + "net": [], + "shell": [ + "node", + "git", + "hvigorw", + "hvigorw.bat", + "hdc", + "hdc.exe", + "ohpm", + "ohpm.bat", + "java", + "java.exe", + "Emulator.exe" + ], + "gui": [], + "secrets": [] + }, + "capabilities": [ + { + "id": "sparo.harmonyDev", + "title": "HarmonyOS Dev Runtime", + "description": "Detect HarmonyOS project identity, resolve DevEco/HVigor/HDC/Emulator tooling, run build/install/launch loops, capture device facts, and report redacted diagnostics.", + "category": "mobileDev", + "actions": [ + "detectProject", + "detectToolchain", + "listEmulators", + "startEmulator", + "stopEmulator", + "listTargets", + "runUnitTests", + "assembleApp", + "buildProject", + "hotReload", + "installApp", + "launchAbility", + "captureScreen", + "readScreenshot", + "dumpHierarchy", + "readLogs", + "readDiagnostics", + "getRuntimeState" + ], + "streaming": false, + "cancelable": true, + "resumable": true, + "usableBy": [ + "agentComponent", + "productAppRuntime", + "management" + ], + "inputSchema": { + "type": "object" + }, + "outputSchema": { + "type": "object" + } + } + ], + "actions": [ + { + "name": "detectProject", + "description": "Detect a HarmonyOS workspace and return bundle/module/ability/project identity without exposing signing secrets.", + "inputSchema": { + "type": "object" + }, + "outputSchema": { + "type": "object" + }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "detectToolchain", + "description": "Resolve DevEco SDK, JBR, HVigor, HDC, ohpm, and Emulator paths even when they are not on PATH.", + "inputSchema": { + "type": "object" + }, + "outputSchema": { + "type": "object" + }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "listEmulators", + "description": "List DevEco emulator instances and rank public API-compatible targets ahead of beta/non-public images.", + "inputSchema": { + "type": "object" + }, + "outputSchema": { + "type": "object" + }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "startEmulator", + "description": "Start a selected DevEco emulator instance and wait for an HDC target gate.", + "inputSchema": { + "type": "object" + }, + "outputSchema": { + "type": "object" + }, + "streaming": false, + "cancelable": true, + "resumable": true + }, + { + "name": "stopEmulator", + "description": "Stop a selected DevEco emulator instance and refresh emulator and HDC target facts.", + "inputSchema": { + "type": "object" + }, + "outputSchema": { + "type": "object" + }, + "streaming": false, + "cancelable": true, + "resumable": true + }, + { + "name": "listTargets", + "description": "List online HDC targets.", + "inputSchema": { + "type": "object" + }, + "outputSchema": { + "type": "object" + }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "runUnitTests", + "description": "Run the HarmonyOS module unit-test task through HVigor.", + "inputSchema": { + "type": "object" + }, + "outputSchema": { + "type": "object" + }, + "streaming": false, + "cancelable": true, + "resumable": true + }, + { + "name": "assembleApp", + "description": "Build a HarmonyOS app artifact through HVigor assembleApp.", + "inputSchema": { + "type": "object" + }, + "outputSchema": { + "type": "object" + }, + "streaming": false, + "cancelable": true, + "resumable": true + }, + { + "name": "buildProject", + "description": "Run the structured build pipeline and persist redacted build state.", + "inputSchema": { + "type": "object" + }, + "outputSchema": { + "type": "object" + }, + "streaming": false, + "cancelable": true, + "resumable": true + }, + { + "name": "hotReload", + "description": "Attempt the experimental HVigor hot reload build and report fallback diagnostics without making hot reload the correctness path.", + "inputSchema": { + "type": "object" + }, + "outputSchema": { + "type": "object" + }, + "streaming": false, + "cancelable": true, + "resumable": true + }, + { + "name": "installApp", + "description": "Install the latest app or HAP artifact to an online HDC target.", + "inputSchema": { + "type": "object" + }, + "outputSchema": { + "type": "object" + }, + "streaming": false, + "cancelable": true, + "resumable": true + }, + { + "name": "launchAbility", + "description": "Launch the detected bundle and main ability on an online HDC target.", + "inputSchema": { + "type": "object" + }, + "outputSchema": { + "type": "object" + }, + "streaming": false, + "cancelable": true, + "resumable": true + }, + { + "name": "captureScreen", + "description": "Capture a screenshot from a running emulator or HDC target when supported.", + "inputSchema": { + "type": "object" + }, + "outputSchema": { + "type": "object" + }, + "streaming": false, + "cancelable": true, + "resumable": true + }, + { + "name": "readScreenshot", + "description": "Read a previously captured HarmonyOS Dev screenshot from the workspace runtime screenshot directory.", + "inputSchema": { + "type": "object" + }, + "outputSchema": { + "type": "object" + }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "dumpHierarchy", + "description": "Capture UI hierarchy JSON when the target-side probe is available.", + "inputSchema": { + "type": "object" + }, + "outputSchema": { + "type": "object" + }, + "streaming": false, + "cancelable": true, + "resumable": true + }, + { + "name": "readLogs", + "description": "Read a short HDC hilog window and app runtime log paths.", + "inputSchema": { + "type": "object" + }, + "outputSchema": { + "type": "object" + }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "readDiagnostics", + "description": "Read redacted HarmonyOS project diagnostics, recent runtime state, and source control summary.", + "inputSchema": { + "type": "object" + }, + "outputSchema": { + "type": "object" + }, + "streaming": false, + "cancelable": false, + "resumable": true + }, + { + "name": "getRuntimeState", + "description": "Read the persisted workspace-local HarmonyOS runtime state.", + "inputSchema": { + "type": "object" + }, + "outputSchema": { + "type": "object" + }, + "streaming": false, + "cancelable": false, + "resumable": true + } + ], + "tools": [ + { + "name": "HarmonyOSDevRuntime", + "description": "Detect HarmonyOS projects, operate the DevEco/HVigor/HDC/Emulator toolchain, and capture device facts for collaborative ArkTS/ArkUI development.", + "capabilityId": "sparo.harmonyDev", + "action": "detectProject", + "actions": [ + "detectProject", + "detectToolchain", + "listEmulators", + "startEmulator", + "stopEmulator", + "listTargets", + "runUnitTests", + "assembleApp", + "buildProject", + "hotReload", + "installApp", + "launchAbility", + "captureScreen", + "readScreenshot", + "dumpHierarchy", + "readLogs", + "readDiagnostics", + "getRuntimeState" + ], + "readonly": false, + "needsPermissions": true, + "inputSchema": { + "type": "object" + }, + "ui": { + "card": { + "kind": "appDefined", + "displayName": "HarmonyOS Dev Runtime", + "icon": "Smartphone", + "resultDisplayType": "detailed", + "displayMode": "compact", + "family": "bridge-component", + "title": "HarmonyOS Dev Runtime" + } + } + } + ] +} diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/package.json b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/package.json new file mode 100644 index 00000000..384a459e --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/package.json @@ -0,0 +1,6 @@ +{ + "name": "builtin-harmony-runtime", + "private": true, + "version": "1.0.0", + "type": "commonjs" +} diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/build.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/build.js new file mode 100644 index 00000000..87d1bed5 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/build.js @@ -0,0 +1,107 @@ +const fs = require("node:fs"); +const path = require("node:path"); +const { detectToolchain } = require("./harmony-env"); +const { runCommand } = require("./command"); +const { diagnostic, redactValue } = require("./redact"); +const { latestArtifact } = require("./device"); +const { runDir } = require("./paths"); +const { readRuntimeState, writeRuntimeState } = require("./runtime-state"); + +function makeRunId(prefix) { + return `${prefix}-${new Date().toISOString().replace(/[:.]/g, "-")}`; +} + +function buildResult(workspacePath, runId, stage, commandResult, artifact = null, extraDiagnostics = []) { + const ok = commandResult.exitCode === 0; + const diagnostics = [...extraDiagnostics]; + if (!ok) { + diagnostics.push(diagnostic("error", commandResult.stderr || commandResult.stdout || `${stage} failed`, { stage })); + } + const build = { + runId, + stage, + status: ok ? "completed" : "failed", + command: path.basename(commandResult.command || ""), + exitCode: commandResult.exitCode, + durationMs: commandResult.durationMs, + artifact, + diagnostics, + logPath: commandResult.logPath || null, + updatedAt: Date.now(), + }; + const runtimeState = writeRuntimeState(workspacePath, { build, latestArtifact: artifact || readRuntimeState(workspacePath).latestArtifact, diagnostics }); + return redactValue({ ok, build, artifact, diagnostics, runtimeState }); +} + +function runHvigor(input, actionName, args, options = {}) { + const workspacePath = input.workspacePath; + const toolchainResult = detectToolchain(input); + const hvigorw = toolchainResult.toolchain.hvigorw.path; + const diagnostics = []; + if (!hvigorw) { + diagnostics.push(diagnostic("warning", "hvigorw was not found", { stage: actionName })); + return { ok: false, diagnostics, runtimeState: writeRuntimeState(workspacePath, { diagnostics }) }; + } + const runId = input.runId || makeRunId(actionName); + const logPath = path.join(runDir(workspacePath, runId), `${actionName}.log`); + const command = runCommand(hvigorw, args, { + cwd: workspacePath, + env: toolchainResult.toolchain.env, + timeoutMs: options.timeoutMs || input.timeoutMs || 240000, + logPath, + label: actionName, + }); + command.logPath = logPath; + const artifact = options.findArtifact ? latestArtifact(workspacePath) : null; + return buildResult(workspacePath, runId, actionName, command, artifact, diagnostics); +} + +function runUnitTests(input = {}) { + return runHvigor(input, "test", ["test", "--mode", "module", "-p", "module=entry", "--info", "--no-daemon"], { timeoutMs: input.timeoutMs || 180000 }); +} + +function assembleApp(input = {}) { + return runHvigor(input, "assemble", ["assembleApp", "--incremental", "--parallel", "--info"], { timeoutMs: input.timeoutMs || 240000, findArtifact: true }); +} + +function buildProject(input = {}) { + const workspacePath = input.workspacePath; + const diagnostics = []; + let test = null; + if (input.includeTests) { + test = runUnitTests(input); + if (!test.ok) { + const runtimeState = writeRuntimeState(workspacePath, { build: test.build, diagnostics: test.diagnostics }); + return redactValue({ ok: false, test, diagnostics: test.diagnostics, runtimeState }); + } + } + const assemble = assembleApp(input); + const runtimeState = writeRuntimeState(workspacePath, { + build: assemble.build, + latestArtifact: assemble.artifact || latestArtifact(workspacePath), + diagnostics: [...diagnostics, ...assemble.diagnostics], + }); + return redactValue({ ok: assemble.ok, test, assemble, build: assemble.build, artifact: assemble.artifact, diagnostics: assemble.diagnostics, runtimeState }); +} + +function hotReload(input = {}) { + const result = runHvigor(input, "hotReload", ["assembleApp", "--hot-reload-build", "--info"], { timeoutMs: input.timeoutMs || 180000, findArtifact: true }); + const capabilities = { + ...readRuntimeState(input.workspacePath).capabilities, + hotReload: result.ok ? "available" : "experimental", + }; + const fallbackDiagnostic = result.ok ? [] : [diagnostic("info", "Hot Reload is optional; use Build & Run as the correctness path.", { stage: "hotReload" })]; + const runtimeState = writeRuntimeState(input.workspacePath, { + build: result.build, + capabilities, + diagnostics: [...(result.diagnostics || []), ...fallbackDiagnostic], + }); + return redactValue({ ...result, diagnostics: [...(result.diagnostics || []), ...fallbackDiagnostic], runtimeState }); +} + +module.exports = { + assembleApp, + buildProject, + hotReload, + runUnitTests, +}; diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/command.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/command.js new file mode 100644 index 00000000..9dacb822 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/command.js @@ -0,0 +1,79 @@ +const fs = require("node:fs"); +const path = require("node:path"); +const { spawnSync } = require("node:child_process"); +const { redactText } = require("./redact"); + +function tail(value, max = 10000) { + const text = redactText(value || ""); + return text.length > max ? text.slice(text.length - max) : text; +} + +function writeLog(logPath, label, commandLine, result) { + if (!logPath) return; + fs.mkdirSync(path.dirname(logPath), { recursive: true }); + const body = [ + `# ${label}`, + "", + `$ ${commandLine}`, + "", + `exitCode: ${result.exitCode}`, + "", + "## stdout", + result.stdout || "", + "", + "## stderr", + result.stderr || "", + "", + ].join("\n"); + fs.writeFileSync(logPath, body, "utf8"); +} + +function runCommand(command, args = [], options = {}) { + const startedAt = Date.now(); + const env = { + ...process.env, + ...(options.env || {}), + }; + const isWindowsScript = process.platform === "win32" && /\.(cmd|bat)$/i.test(command); + const quoteCmdArg = (value) => `"${String(value).replace(/"/g, '""')}"`; + const executable = isWindowsScript ? process.env.ComSpec || "cmd.exe" : command; + const executableArgs = isWindowsScript + ? ["/d", "/c", `call ${quoteCmdArg(command)} ${args.map(quoteCmdArg).join(" ")}`] + : args.map(String); + const result = spawnSync(executable, executableArgs, { + cwd: options.cwd, + env, + encoding: "utf8", + windowsHide: true, + timeout: options.timeoutMs || 60000, + shell: false, + windowsVerbatimArguments: isWindowsScript, + maxBuffer: options.maxBuffer || 12 * 1024 * 1024, + }); + const output = { + command, + args: args.map(String), + commandLine: [command, ...args.map(String)].join(" "), + cwd: options.cwd || process.cwd(), + exitCode: typeof result.status === "number" ? result.status : (result.error ? 1 : 0), + timedOut: result.error?.code === "ETIMEDOUT", + durationMs: Date.now() - startedAt, + stdout: tail(result.stdout), + stderr: tail(result.stderr || result.error?.message || ""), + }; + writeLog(options.logPath, options.label || path.basename(command), output.commandLine, output); + return output; +} + +function fileExists(filePath) { + try { + return Boolean(filePath && fs.existsSync(filePath) && fs.statSync(filePath).isFile()); + } catch { + return false; + } +} + +module.exports = { + fileExists, + runCommand, +}; diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/device.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/device.js new file mode 100644 index 00000000..12754ee4 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/device.js @@ -0,0 +1,521 @@ +const fs = require("node:fs"); +const path = require("node:path"); +const { detectToolchain } = require("./harmony-env"); +const { runCommand } = require("./command"); +const { diagnostic, redactValue } = require("./redact"); +const { hierarchyDir, screenshotsDir, safeFilePart } = require("./paths"); +const { readRuntimeState, writeRuntimeState } = require("./runtime-state"); +const { projectIdentity } = require("./project"); + +function withTargetArgs(targetId, args) { + return targetId ? ["-t", targetId, ...args] : args; +} + +function boolString(value) { + return value === true || String(value).toLowerCase() === "true"; +} + +function parseEmulatorDetails(output) { + try { + const text = String(output || ""); + const start = text.indexOf("["); + const jsonText = start >= 0 ? text.slice(start) : text; + const items = JSON.parse(jsonText || "[]"); + return Array.isArray(items) ? items : []; + } catch { + return []; + } +} + +function resolveCaptureEmulator(input, emulatorPath, env, diagnostics) { + const requested = input.emulatorName || input.name; + if (requested) return requested; + + const runtimeState = input.workspacePath ? readRuntimeState(input.workspacePath) : {}; + const selected = runtimeState.selectedEmulator; + if (selected?.name && selected.isRunning) return selected.name; + + if (!emulatorPath) return null; + const result = runCommand(emulatorPath, ["-list", "-details"], { + cwd: input.workspacePath, + env, + timeoutMs: 20000, + }); + if (result.exitCode !== 0) { + diagnostics.push(diagnostic("info", result.stderr || result.stdout || "Could not list running emulators for screenshot capture", { + stage: "captureScreen", + source: "emulator", + })); + return null; + } + const running = parseEmulatorDetails(result.stdout).find((item) => boolString(item.isRunning)); + return running?.name || null; +} + +function parseTargets(output) { + const text = String(output || "").trim(); + if (!text || text.includes("[Empty]")) return []; + return text.split(/\r?\n/) + .map((line) => line.trim()) + .filter(Boolean) + .filter((line) => !/^\[/.test(line)) + .map((line) => { + const parts = line.split(/\s+/); + const raw = line; + const id = parts[0]; + const uart = /^COM\d+$/i.test(id) || /\bUART\b/i.test(raw); + return { + id, + serial: id, + state: /offline/i.test(line) ? "offline" : "online", + model: parts.slice(1).join(" ") || null, + raw, + kind: uart ? "uart" : (/127\.0\.0\.1|localhost|:\d{4,5}|emulator|qemu|PHEMU|PCEMU/i.test(raw) ? "emulator" : "device"), + usable: !uart, + }; + }); +} + +function listTargets(input = {}) { + const toolchainResult = detectToolchain(input); + const hdc = toolchainResult.toolchain.hdc.path; + if (!hdc) { + return { ok: false, targets: [], diagnostics: [diagnostic("warning", "hdc was not found", { stage: "listTargets" })] }; + } + const result = runCommand(hdc, ["list", "targets", "-v"], { + cwd: input.workspacePath, + env: toolchainResult.toolchain.env, + timeoutMs: input.timeoutMs || 15000, + }); + const observedTargets = parseTargets(result.stdout || result.stderr); + const targets = observedTargets.filter((target) => target.usable && target.state === "online"); + const diagnostics = targets.length + ? [] + : [diagnostic("info", observedTargets.length + ? "Only UART or non-deployable HDC endpoints were detected" + : "No HDC target is online", { stage: "listTargets" })]; + const runtimeState = input.workspacePath ? writeRuntimeState(input.workspacePath, { + targets, + observedTargets, + capabilities: { + ...readRuntimeState(input.workspacePath).capabilities, + hdcTarget: targets.length > 0, + }, + diagnostics, + }) : null; + return redactValue({ ok: targets.length > 0, targets, observedTargets, diagnostics, runtimeState }); +} + +function latestArtifact(workspacePath) { + const state = readRuntimeState(workspacePath); + if (state.latestArtifact?.path && fs.existsSync(state.latestArtifact.path)) return state.latestArtifact; + const matches = []; + const stack = [workspacePath]; + const ignored = new Set([".git", "oh_modules", "node_modules", ".sparo_os"]); + while (stack.length) { + const current = stack.pop(); + let entries = []; + try { + entries = fs.readdirSync(current, { withFileTypes: true }); + } catch { + continue; + } + for (const entry of entries) { + const absolute = path.join(current, entry.name); + if (entry.isDirectory()) { + if (!ignored.has(entry.name)) stack.push(absolute); + } else if (entry.isFile() && /\.(app|hap)$/i.test(entry.name)) { + const stat = fs.statSync(absolute); + matches.push({ path: absolute, size: stat.size, createdAt: stat.mtimeMs, kind: path.extname(entry.name).slice(1).toLowerCase() }); + } + } + } + return matches.sort((a, b) => b.createdAt - a.createdAt)[0] || null; +} + +function installApp(input = {}) { + const workspacePath = input.workspacePath; + const toolchainResult = detectToolchain(input); + const hdc = toolchainResult.toolchain.hdc.path; + const targets = listTargets(input).targets; + const target = input.targetId || targets[0]?.id; + const artifact = input.artifactPath ? { path: input.artifactPath } : latestArtifact(workspacePath); + const diagnostics = []; + if (!hdc) diagnostics.push(diagnostic("warning", "hdc was not found", { stage: "installApp" })); + if (!target) diagnostics.push(diagnostic("warning", "Install needs an online HDC target", { stage: "installApp" })); + if (!artifact?.path || !fs.existsSync(artifact.path)) diagnostics.push(diagnostic("warning", "No app or HAP artifact was found", { stage: "installApp" })); + if (diagnostics.length) return { ok: false, diagnostics, targets, artifact }; + const run = runCommand(hdc, withTargetArgs(target, ["install", "-r", artifact.path]), { + cwd: workspacePath, + env: toolchainResult.toolchain.env, + timeoutMs: input.timeoutMs || 120000, + }); + const ok = run.exitCode === 0; + if (!ok) diagnostics.push(diagnostic("error", run.stderr || run.stdout || "hdc install failed", { stage: "installApp" })); + const installState = { + status: ok ? "completed" : "failed", + targetId: target, + artifact, + updatedAt: Date.now(), + diagnostics, + }; + const runtimeState = writeRuntimeState(workspacePath, { install: installState, latestArtifact: artifact, diagnostics }); + return redactValue({ ok, install: installState, diagnostics, runtimeState }); +} + +function launchAbility(input = {}) { + const workspacePath = input.workspacePath; + const project = projectIdentity(workspacePath); + const module = (project.modules || [])[0] || {}; + const ability = input.abilityName || module.mainElement || module.abilities?.[0]?.name; + const bundleName = input.bundleName || project.bundleName || project.app?.bundleName; + const toolchainResult = detectToolchain(input); + const hdc = toolchainResult.toolchain.hdc.path; + const targets = listTargets(input).targets; + const target = input.targetId || targets[0]?.id; + const diagnostics = []; + if (!hdc) diagnostics.push(diagnostic("warning", "hdc was not found", { stage: "launchAbility" })); + if (!target) diagnostics.push(diagnostic("warning", "Launch needs an online HDC target", { stage: "launchAbility" })); + if (!bundleName || !ability) diagnostics.push(diagnostic("warning", "Bundle name or ability name was not detected", { stage: "launchAbility" })); + if (diagnostics.length) return { ok: false, diagnostics, targets, project }; + const launch = runCommand(hdc, withTargetArgs(target, ["shell", "aa", "start", "-a", ability, "-b", bundleName]), { + cwd: workspacePath, + env: toolchainResult.toolchain.env, + timeoutMs: input.timeoutMs || 90000, + }); + const dump = runCommand(hdc, withTargetArgs(target, ["shell", "bm", "dump", "-n", bundleName]), { + cwd: workspacePath, + env: toolchainResult.toolchain.env, + timeoutMs: 30000, + }); + const ok = launch.exitCode === 0; + const capabilities = { + ...readRuntimeState(workspacePath).capabilities, + abilityLaunch: ok ? "available" : "unavailable", + bundleDump: dump.exitCode === 0 ? "available" : "unavailable", + }; + if (!ok) diagnostics.push(diagnostic("error", launch.stderr || launch.stdout || "aa start failed", { stage: "launchAbility" })); + const runtime = { + status: ok ? "running" : "failed", + targetId: target, + bundleName, + abilityName: ability, + bundleDumpAvailable: dump.exitCode === 0, + updatedAt: Date.now(), + diagnostics, + }; + const runtimeState = writeRuntimeState(workspacePath, { runtime, capabilities, diagnostics }); + return redactValue({ ok, runtime, launch, bundleDump: dump.exitCode === 0 ? dump.stdout : null, diagnostics, runtimeState }); +} + +function readImageFile(filePath) { + const data = fs.readFileSync(filePath); + const ext = path.extname(filePath).slice(1).toLowerCase() || "png"; + const mime = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : "image/png"; + const dimensions = imageDimensions(data, ext); + return { + dataUrl: `data:${mime};base64,${data.toString("base64")}`, + size: data.length, + width: dimensions.width, + height: dimensions.height, + }; +} + +function imageDimensions(data, ext) { + if (ext === "png" && data.length >= 24 && data.toString("ascii", 1, 4) === "PNG") { + return { + width: data.readUInt32BE(16), + height: data.readUInt32BE(20), + }; + } + if ((ext === "jpg" || ext === "jpeg") && data.length > 4) { + let offset = 2; + while (offset + 9 < data.length) { + if (data[offset] !== 0xff) break; + const marker = data[offset + 1]; + const length = data.readUInt16BE(offset + 2); + if (length < 2) break; + if (marker >= 0xc0 && marker <= 0xc3) { + return { + width: data.readUInt16BE(offset + 7), + height: data.readUInt16BE(offset + 5), + }; + } + offset += 2 + length; + } + } + return { width: null, height: null }; +} + +function sleepSync(ms) { + Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms); +} + +function waitForStableFile(filePath, options = {}) { + const timeoutMs = options.timeoutMs || 12000; + const intervalMs = options.intervalMs || 160; + const minBytes = options.minBytes || 32; + const stableReads = options.stableReads || 2; + const deadline = Date.now() + timeoutMs; + let previousSize = -1; + let stableCount = 0; + + while (Date.now() < deadline) { + if (fs.existsSync(filePath)) { + const stat = fs.statSync(filePath); + if (stat.size >= minBytes && stat.size === previousSize) { + stableCount += 1; + if (stableCount >= stableReads) return { path: filePath, size: stat.size, stable: true }; + } else { + stableCount = 0; + previousSize = stat.size; + } + } + sleepSync(intervalMs); + } + + if (!fs.existsSync(filePath)) return null; + const stat = fs.statSync(filePath); + return { path: filePath, size: stat.size, stable: false }; +} + +function listScreenshotFiles(dir) { + try { + return fs.readdirSync(dir) + .filter((file) => /\.(png|jpe?g)$/i.test(file)) + .map((file) => { + const filePath = path.join(dir, file); + const stat = fs.statSync(filePath); + return { path: filePath, mtimeMs: stat.mtimeMs, size: stat.size }; + }); + } catch { + return []; + } +} + +function findCreatedScreenshot(dir, before, startedAt) { + const previous = new Map(before.map((item) => [item.path, `${item.mtimeMs}:${item.size}`])); + return listScreenshotFiles(dir) + .filter((item) => previous.get(item.path) !== `${item.mtimeMs}:${item.size}` || item.mtimeMs >= startedAt - 1000) + .sort((left, right) => right.mtimeMs - left.mtimeMs)[0] || null; +} + +function assertWorkspaceScreenshot(workspacePath, filePath) { + const base = path.resolve(screenshotsDir(workspacePath)); + const resolved = path.resolve(filePath || ""); + const relative = path.relative(base, resolved); + if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) { + throw new Error("Screenshot path is outside the HarmonyOS Dev screenshot directory."); + } + return resolved; +} + +function readScreenshot(input = {}) { + const workspacePath = input.workspacePath; + const diagnostics = []; + const requestedPath = assertWorkspaceScreenshot(workspacePath, input.path || input.screen?.path); + const stable = waitForStableFile(requestedPath, { timeoutMs: input.timeoutMs || 12000 }); + if (!stable?.path || !stable.stable || stable.size <= 0) { + diagnostics.push(diagnostic("warning", "Screenshot file is not ready", { + stage: "readScreenshot", + path: requestedPath, + })); + return { ok: false, diagnostics }; + } + const image = readImageFile(requestedPath); + const screen = { + ...(input.screen || {}), + id: input.screen?.id || `screen-${Date.now()}`, + path: requestedPath, + uri: requestedPath, + dataUrl: image.dataUrl, + width: image.width || input.screen?.width || null, + height: image.height || input.screen?.height || null, + source: input.screen?.source || "cached-file", + sourceName: input.screen?.sourceName || null, + timestamp: input.screen?.timestamp || Date.now(), + size: image.size, + }; + return redactValue({ ok: true, screen, diagnostics }); +} + +function captureScreen(input = {}) { + const workspacePath = input.workspacePath; + const toolchainResult = detectToolchain(input); + const hdc = toolchainResult.toolchain.hdc.path; + const emulator = toolchainResult.toolchain.emulator.path; + const id = `screen-${Date.now()}`; + const captureDir = screenshotsDir(workspacePath); + let outPath = path.join(captureDir, `${safeFilePart(id)}.png`); + const diagnostics = []; + let result = null; + let source = "unavailable"; + let sourceName = null; + const emulatorName = resolveCaptureEmulator(input, emulator, toolchainResult.toolchain.env, diagnostics); + if (emulatorName && emulator) { + const before = listScreenshotFiles(captureDir); + const startedAt = Date.now(); + result = runCommand(emulator, ["-instance", emulatorName, "-screenshot", "-screenshotPath", captureDir], { + cwd: workspacePath, + env: toolchainResult.toolchain.env, + timeoutMs: input.timeoutMs || 60000, + }); + const captured = findCreatedScreenshot(captureDir, before, startedAt); + const stable = captured?.path ? waitForStableFile(captured.path, { timeoutMs: 15000 }) : null; + if (result.exitCode === 0 && stable?.path && stable.stable && stable.size > 0) { + outPath = stable.path; + source = "emulator"; + sourceName = emulatorName; + } else { + diagnostics.push(diagnostic("warning", result.stderr || result.stdout || "Emulator screenshot command did not produce a file", { + stage: "captureScreen", + source: "emulator", + emulatorName, + })); + } + } + if (source === "unavailable" && hdc) { + const targetResult = listTargets(input); + diagnostics.push(...(targetResult.diagnostics || [])); + const targets = targetResult.targets; + const target = input.targetId || targets[0]?.id; + if (target) { + const remote = `/data/local/tmp/${id}.png`; + const snap = runCommand(hdc, withTargetArgs(target, ["shell", "snapshot_display", "-f", remote]), { + cwd: workspacePath, + env: toolchainResult.toolchain.env, + timeoutMs: 45000, + }); + const recv = snap.exitCode === 0 + ? runCommand(hdc, withTargetArgs(target, ["file", "recv", remote, outPath]), { + cwd: workspacePath, + env: toolchainResult.toolchain.env, + timeoutMs: 45000, + }) + : snap; + result = recv; + const stable = recv.exitCode === 0 ? waitForStableFile(outPath, { timeoutMs: 8000 }) : null; + if (recv.exitCode === 0 && stable?.path && stable.stable && stable.size > 0) { + source = "target-shell"; + sourceName = target; + } else { + diagnostics.push(diagnostic("warning", recv.stderr || recv.stdout || "Target screenshot command did not produce a file", { + stage: "captureScreen", + source: "target-shell", + targetId: target, + })); + } + } + } + if (source === "unavailable" && !result) { + diagnostics.push(diagnostic("warning", "Screenshot needs a running emulator or an online HDC target", { stage: "captureScreen" })); + } + const image = source === "unavailable" ? null : readImageFile(outPath); + const screen = source === "unavailable" ? null : { + id, + path: outPath, + uri: outPath, + dataUrl: image.dataUrl, + width: input.width || image.width || null, + height: input.height || image.height || null, + source, + sourceName, + timestamp: Date.now(), + size: image.size, + }; + const capabilities = { + ...readRuntimeState(workspacePath).capabilities, + screenshot: source, + }; + const runtimeState = writeRuntimeState(workspacePath, { screen, capabilities, diagnostics }); + return redactValue({ ok: Boolean(screen), screen, diagnostics, runtimeState }); +} + +function dumpHierarchy(input = {}) { + const workspacePath = input.workspacePath; + const toolchainResult = detectToolchain(input); + const hdc = toolchainResult.toolchain.hdc.path; + const targets = listTargets(input).targets; + const target = input.targetId || targets[0]?.id; + const id = `hierarchy-${Date.now()}`; + const outPath = path.join(hierarchyDir(workspacePath), `${safeFilePart(id)}.json`); + const diagnostics = []; + let hierarchy = null; + if (hdc && target) { + const remote = `/data/local/tmp/${id}.json`; + const dump = runCommand(hdc, withTargetArgs(target, ["shell", "uitest", "dumpLayout", remote]), { + cwd: workspacePath, + env: toolchainResult.toolchain.env, + timeoutMs: 45000, + }); + const recv = dump.exitCode === 0 + ? runCommand(hdc, withTargetArgs(target, ["file", "recv", remote, outPath]), { + cwd: workspacePath, + env: toolchainResult.toolchain.env, + timeoutMs: 45000, + }) + : dump; + if (recv.exitCode === 0 && fs.existsSync(outPath)) { + try { + hierarchy = JSON.parse(fs.readFileSync(outPath, "utf8")); + } catch { + hierarchy = { nodes: [], parseError: true }; + } + } else { + diagnostics.push(diagnostic("warning", recv.stderr || recv.stdout || "UI hierarchy dump probe is unavailable", { stage: "dumpHierarchy" })); + } + } else { + diagnostics.push(diagnostic("warning", "UI hierarchy needs an online HDC target", { stage: "dumpHierarchy" })); + } + const hierarchyState = hierarchy ? { + id, + path: outPath, + timestamp: Date.now(), + root: hierarchy.root || hierarchy, + nodes: hierarchy.nodes || hierarchy.children || [], + } : null; + const capabilities = { + ...readRuntimeState(workspacePath).capabilities, + hierarchyDump: hierarchyState ? "available" : "unavailable", + }; + const runtimeState = writeRuntimeState(workspacePath, { hierarchy: hierarchyState, capabilities, diagnostics }); + return redactValue({ ok: Boolean(hierarchyState), hierarchy: hierarchyState, diagnostics, runtimeState }); +} + +function readLogs(input = {}) { + const workspacePath = input.workspacePath; + const toolchainResult = detectToolchain(input); + const hdc = toolchainResult.toolchain.hdc.path; + const targets = listTargets(input).targets; + const target = input.targetId || targets[0]?.id; + const diagnostics = []; + let logs = ""; + if (hdc && target) { + const result = runCommand(hdc, withTargetArgs(target, ["shell", "hilog", "-r", "-n", String(input.lines || 200)]), { + cwd: workspacePath, + env: toolchainResult.toolchain.env, + timeoutMs: 30000, + }); + logs = result.stdout || result.stderr || ""; + if (result.exitCode !== 0) diagnostics.push(diagnostic("warning", logs || "hilog probe failed", { stage: "readLogs" })); + } else { + diagnostics.push(diagnostic("info", "Logs need an online HDC target", { stage: "readLogs" })); + } + const capabilities = { + ...readRuntimeState(workspacePath).capabilities, + hilog: logs ? "available" : "unavailable", + }; + const runtimeState = writeRuntimeState(workspacePath, { logs: logs.slice(-10000), capabilities, diagnostics }); + return redactValue({ ok: Boolean(logs), logs: logs.slice(-10000), diagnostics, runtimeState }); +} + +module.exports = { + captureScreen, + dumpHierarchy, + installApp, + latestArtifact, + launchAbility, + listTargets, + readScreenshot, + readLogs, +}; diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/diagnostics.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/diagnostics.js new file mode 100644 index 00000000..be91aece --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/diagnostics.js @@ -0,0 +1,45 @@ +const { runCommand } = require("./command"); +const { detectProject } = require("./project"); +const { detectToolchain } = require("./harmony-env"); +const { listEmulators } = require("./emulator"); +const { listTargets, readLogs } = require("./device"); +const { readRuntimeState } = require("./runtime-state"); +const { redactValue } = require("./redact"); + +function readDiagnostics(input = {}) { + const project = detectProject(input); + const toolchain = detectToolchain(input); + const targets = listTargets(input); + const emulators = listEmulators(input); + const runtimeState = readRuntimeState(input.workspacePath); + const git = runCommand("git", ["status", "--short"], { + cwd: input.workspacePath, + timeoutMs: 10000, + }); + const diagnostics = [ + ...(project.diagnostics || []), + ...(toolchain.diagnostics || []), + ...(targets.diagnostics || []), + ...(emulators.diagnostics || []), + ...(runtimeState.diagnostics || []), + ]; + return redactValue({ + ok: true, + project: project.project, + toolchain: toolchain.toolchain, + targets: targets.targets, + emulators: emulators.emulators, + recommendedEmulator: emulators.recommendedEmulator, + runtimeState, + sourceControl: { + exitCode: git.exitCode, + statusShort: git.stdout, + }, + diagnostics, + }); +} + +module.exports = { + readDiagnostics, + readLogs, +}; diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/emulator.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/emulator.js new file mode 100644 index 00000000..6a1b85fb --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/emulator.js @@ -0,0 +1,298 @@ +const fs = require("node:fs"); +const path = require("node:path"); +const { spawn } = require("node:child_process"); +const { detectToolchain } = require("./harmony-env"); +const { runCommand } = require("./command"); +const { diagnostic, redactValue } = require("./redact"); +const { writeRuntimeState } = require("./runtime-state"); +const { listTargets } = require("./device"); + +function boolString(value) { + return value === true || String(value).toLowerCase() === "true"; +} + +function rankEmulator(item = {}) { + let rank = 0; + const publicImage = boolString(item["os.isPublic"]); + const api = String(item["os.apiVersion"] || ""); + const os = String(item["os.osVersion"] || ""); + const type = String(item.deviceType || ""); + if (publicImage) rank += 100; + if (api.includes("24")) rank += 40; + if (os.includes("6.1.1")) rank += 30; + if (type === "phone") rank += 25; + if (type === "foldable") rank += 8; + if (type === "triplefold") rank += 4; + if (boolString(item.isRunning)) rank += 10; + if (!publicImage || /beta/i.test(os)) rank -= 80; + return rank; +} + +function normalizeEmulator(item = {}) { + return { + name: item.name, + deviceType: item.deviceType || null, + deviceModel: item.deviceModel || item.productModel || null, + osVersion: item["os.osVersion"] || null, + apiVersion: item["os.apiVersion"] || null, + isPublic: boolString(item["os.isPublic"]), + isRunning: boolString(item.isRunning), + instancePath: item.instancePath || null, + logPath: item.instancePath ? path.join(item.instancePath, "Log").replace(/\\/g, "/") : null, + rank: rankEmulator(item), + }; +} + +function selectedEmulator(emulators, name) { + const list = Array.isArray(emulators) ? emulators : []; + if (name) return list.find((item) => item.name === name) || { name }; + return list[0] || null; +} + +function emulatorToStop(emulators, name, recommended) { + const list = Array.isArray(emulators) ? emulators : []; + if (name) return selectedEmulator(list, name); + return list.find((item) => item.isRunning) || recommended || list[0] || null; +} + +function emulatorTargets(targets) { + return (Array.isArray(targets) ? targets : []).filter((target) => { + const text = [target.id, target.serial, target.model, target.raw, target.kind].filter(Boolean).join(" "); + return target.kind === "emulator" || /127\.0\.0\.1|localhost|:\d{4,5}|emulator|qemu|PHEMU|PCEMU/i.test(text); + }); +} + +function readTail(filePath, maxBytes = 192 * 1024) { + try { + const stat = fs.statSync(filePath); + const size = Math.min(stat.size, maxBytes); + const fd = fs.openSync(filePath, "r"); + const buffer = Buffer.alloc(size); + fs.readSync(fd, buffer, 0, size, Math.max(0, stat.size - size)); + fs.closeSync(fd); + return buffer.toString("utf8"); + } catch { + return ""; + } +} + +function emulatorLogDiagnostics(emulator) { + if (!emulator?.instancePath) return []; + const logDir = path.join(emulator.instancePath, "Log"); + const files = [ + ["Emulator.log", /(critical|error|warning|fail|fatal|crash|exit|heartbeat|uuid|sn|cannot|can not|permission denied|OpenProcess)/i], + ["qemu.log", /(critical|error|fail|fatal|crash|exit|heartbeat|permission denied|express_gpu|egl|opengl|watchdog)/i], + ["crash_server.log", /(critical|error|warning|exit|heartbeat|crash|OpenProcess|failed)/i], + ["kernel.log", /(panic|fatal|crash|error|failed|watchdog|express_gpu|shutdown|reboot|kill)/i], + ]; + const diagnostics = []; + for (const [fileName, pattern] of files) { + const filePath = path.join(logDir, fileName); + const tail = readTail(filePath); + if (!tail) continue; + const matches = tail + .split(/\r?\n/) + .filter((line) => pattern.test(line)) + .slice(-8); + if (!matches.length) continue; + diagnostics.push(diagnostic("warning", `Recent ${emulator.name} ${fileName}: ${matches.join(" | ")}`, { + stage: "startEmulator", + source: "emulatorLog", + emulatorName: emulator.name, + logFile: fileName, + })); + } + return diagnostics; +} + +function launchEmulator(emulatorPath, name, input, env) { + const child = spawn(emulatorPath, ["-start", name], { + cwd: input.workspacePath, + env, + detached: true, + stdio: "ignore", + windowsHide: false, + }); + child.on("error", () => {}); + child.unref(); + return { + command: emulatorPath, + args: ["-start", name], + commandLine: `${emulatorPath} -start ${name}`, + cwd: input.workspacePath || process.cwd(), + pid: child.pid || null, + detached: true, + }; +} + +function listEmulators(input = {}) { + const toolchainResult = detectToolchain(input); + const emulatorPath = toolchainResult.toolchain.emulator.path; + if (!emulatorPath) { + return { ok: false, emulators: [], diagnostics: [diagnostic("warning", "Emulator.exe was not found", { stage: "listEmulators" })] }; + } + const result = runCommand(emulatorPath, ["-list", "-details"], { + cwd: input.workspacePath, + env: toolchainResult.toolchain.env, + timeoutMs: input.timeoutMs || 20000, + }); + let raw = []; + try { + const start = result.stdout.indexOf("["); + const jsonText = start >= 0 ? result.stdout.slice(start) : result.stdout; + raw = JSON.parse(jsonText || "[]"); + } catch { + raw = []; + } + const emulators = raw.map(normalizeEmulator).sort((left, right) => right.rank - left.rank); + const recommendedEmulator = emulators[0] || null; + const diagnostics = []; + if (!emulators.length) diagnostics.push(diagnostic("info", "No DevEco emulator instances were listed", { stage: "listEmulators" })); + if (result.stderr) diagnostics.push(diagnostic("info", result.stderr, { stage: "listEmulators" })); + if (input.workspacePath) writeRuntimeState(input.workspacePath, { emulators, recommendedEmulator, diagnostics }); + return redactValue({ ok: emulators.length > 0, emulators, recommendedEmulator, diagnostics }); +} + +async function startEmulator(input = {}) { + const toolchainResult = detectToolchain(input); + const emulatorPath = toolchainResult.toolchain.emulator.path; + if (!emulatorPath) { + return { ok: false, diagnostics: [diagnostic("warning", "Emulator.exe was not found", { stage: "startEmulator" })] }; + } + const listed = listEmulators(input); + const emulator = selectedEmulator(listed.emulators, input.name || listed.recommendedEmulator?.name); + if (!emulator?.name) { + return { ok: false, diagnostics: [diagnostic("warning", "No emulator name was supplied", { stage: "startEmulator" })] }; + } + const diagnostics = [...(listed.diagnostics || [])]; + if (!emulator.isPublic || /beta/i.test(String(emulator.osVersion || ""))) { + diagnostics.push(diagnostic("warning", `Selected emulator "${emulator.name}" is beta or non-public; a public HarmonyOS 6.1.1(24) image is usually safer for install/start validation.`, { + stage: "startEmulator", + emulatorName: emulator.name, + })); + } + let started; + try { + started = launchEmulator(emulatorPath, emulator.name, input, toolchainResult.toolchain.env); + } catch (error) { + diagnostics.push(diagnostic("warning", error instanceof Error ? error.message : String(error), { + stage: "startEmulator", + emulatorName: emulator.name, + })); + } + const waitMs = Number(input.waitMs || 60000); + const deadline = Date.now() + waitMs; + let targets = []; + let observedTargets = []; + while (started && Date.now() < deadline) { + const targetResult = listTargets(input); + observedTargets = targetResult.observedTargets || targetResult.targets || []; + targets = emulatorTargets(targetResult.targets || []); + if (targets.length) break; + await new Promise((resolve) => setTimeout(resolve, 2000)); + } + if (!targets.length) { + diagnostics.push(diagnostic("warning", "No emulator HDC target appeared before the wait timeout", { + stage: "startEmulator", + emulatorName: emulator.name, + })); + diagnostics.push(...emulatorLogDiagnostics(emulator)); + } + const runtimeState = input.workspacePath ? writeRuntimeState(input.workspacePath, { + selectedEmulator: emulator, + targets, + observedTargets, + diagnostics, + }) : null; + return redactValue({ + ok: targets.length > 0, + emulator, + start: started || null, + targets, + observedTargets, + diagnostics, + runtimeState, + }); +} + +async function stopEmulator(input = {}) { + const toolchainResult = detectToolchain(input); + const emulatorPath = toolchainResult.toolchain.emulator.path; + if (!emulatorPath) { + return { ok: false, diagnostics: [diagnostic("warning", "Emulator.exe was not found", { stage: "stopEmulator" })] }; + } + const listed = listEmulators(input); + const emulator = emulatorToStop(listed.emulators, input.name, listed.recommendedEmulator); + if (!emulator?.name) { + return { ok: false, diagnostics: [diagnostic("warning", "No emulator name was supplied", { stage: "stopEmulator" })] }; + } + + const diagnostics = [...(listed.diagnostics || [])]; + let stop = null; + let refreshed = listed; + let refreshedEmulator = (listed.emulators || []).find((item) => item.name === emulator.name) || emulator; + + if (!refreshedEmulator.isRunning) { + diagnostics.push(diagnostic("info", `Selected emulator "${emulator.name}" is already stopped`, { + stage: "stopEmulator", + emulatorName: emulator.name, + })); + } else { + stop = runCommand(emulatorPath, ["-stop", emulator.name], { + cwd: input.workspacePath, + env: toolchainResult.toolchain.env, + timeoutMs: input.timeoutMs || 30000, + }); + if (stop.exitCode !== 0) { + diagnostics.push(diagnostic("warning", stop.stderr || stop.stdout || "Emulator stop command failed", { + stage: "stopEmulator", + emulatorName: emulator.name, + })); + } + + const waitMs = Number(input.waitMs || 30000); + const deadline = Date.now() + waitMs; + while (Date.now() < deadline) { + refreshed = listEmulators(input); + refreshedEmulator = (refreshed.emulators || []).find((item) => item.name === emulator.name) || refreshedEmulator; + if (!refreshedEmulator?.isRunning) break; + await new Promise((resolve) => setTimeout(resolve, 1000)); + } + if (refreshedEmulator?.isRunning) { + diagnostics.push(diagnostic("warning", `Stop command completed, but emulator "${emulator.name}" is still reported as running`, { + stage: "stopEmulator", + emulatorName: emulator.name, + })); + } + } + + const targetResult = listTargets(input); + const targets = emulatorTargets(targetResult.targets || []); + const observedTargets = targetResult.observedTargets || targetResult.targets || []; + diagnostics.push(...(refreshed.diagnostics || []), ...(targetResult.diagnostics || [])); + const runtimeState = input.workspacePath ? writeRuntimeState(input.workspacePath, { + selectedEmulator: refreshedEmulator, + emulators: refreshed.emulators || [], + recommendedEmulator: refreshed.recommendedEmulator || null, + targets, + observedTargets, + diagnostics, + }) : null; + return redactValue({ + ok: Boolean(refreshedEmulator && !refreshedEmulator.isRunning), + emulator: refreshedEmulator, + stop, + emulators: refreshed.emulators || [], + recommendedEmulator: refreshed.recommendedEmulator || null, + targets, + observedTargets, + diagnostics, + runtimeState, + }); +} + +module.exports = { + listEmulators, + startEmulator, + stopEmulator, +}; diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/harmony-env.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/harmony-env.js new file mode 100644 index 00000000..800d752a --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/harmony-env.js @@ -0,0 +1,115 @@ +const fs = require("node:fs"); +const path = require("node:path"); +const { runCommand, fileExists } = require("./command"); + +const DEFAULT_DEVECO_ROOTS = [ + "D:\\software\\DevEco Studio", + "C:\\Program Files\\Huawei\\DevEco Studio", + "C:\\Program Files\\DevEco Studio", +]; + +function firstExisting(candidates) { + return candidates.find(fileExists) || null; +} + +function pathExists(candidate) { + try { + return Boolean(candidate && fs.existsSync(candidate)); + } catch { + return false; + } +} + +function firstExistingPath(candidates) { + return candidates.find(pathExists) || null; +} + +function resolveOnPath(name) { + const result = runCommand(process.platform === "win32" ? "where.exe" : "which", [name], { timeoutMs: 6000 }); + if (result.exitCode !== 0) return null; + return result.stdout.split(/\r?\n/).map((line) => line.trim()).find(Boolean) || null; +} + +function detectToolchain(input = {}) { + const workspacePath = input.workspacePath; + const roots = [ + input.devEcoRoot, + process.env.DEVECO_STUDIO_HOME, + ...DEFAULT_DEVECO_ROOTS, + ].filter(Boolean); + const sdkRoot = input.devEcoSdkHome || process.env.DEVECO_SDK_HOME || firstExistingPath(roots.map((root) => path.join(root, "sdk"))); + const devEcoRoot = roots.find((root) => fs.existsSync(root)) || (sdkRoot ? path.dirname(sdkRoot) : null); + const hvigorw = firstExisting([ + input.hvigorwPath, + process.env.HVIGORW, + ...roots.map((root) => path.join(root, "tools", "hvigor", "bin", process.platform === "win32" ? "hvigorw.bat" : "hvigorw")), + workspacePath ? path.join(workspacePath, "hvigorw.bat") : null, + workspacePath ? path.join(workspacePath, "hvigorw") : null, + resolveOnPath("hvigorw"), + ].filter(Boolean)); + const hdc = firstExisting([ + input.hdcPath, + process.env.HDC_PATH, + sdkRoot ? path.join(sdkRoot, "default", "openharmony", "toolchains", process.platform === "win32" ? "hdc.exe" : "hdc") : null, + sdkRoot ? path.join(sdkRoot, "openharmony", "toolchains", process.platform === "win32" ? "hdc.exe" : "hdc") : null, + resolveOnPath("hdc"), + ].filter(Boolean)); + const emulator = firstExisting([ + input.emulatorPath, + ...roots.map((root) => path.join(root, "tools", "emulator", process.platform === "win32" ? "Emulator.exe" : "Emulator")), + resolveOnPath(process.platform === "win32" ? "Emulator.exe" : "Emulator"), + ].filter(Boolean)); + const ohpm = firstExisting([ + input.ohpmPath, + ...roots.map((root) => path.join(root, "tools", "ohpm", "bin", process.platform === "win32" ? "ohpm.bat" : "ohpm")), + resolveOnPath("ohpm"), + ].filter(Boolean)); + const java = firstExisting([ + input.javaPath, + process.env.JAVA_HOME ? path.join(process.env.JAVA_HOME, "bin", process.platform === "win32" ? "java.exe" : "java") : null, + ...roots.map((root) => path.join(root, "jbr", "bin", process.platform === "win32" ? "java.exe" : "java")), + resolveOnPath("java"), + ].filter(Boolean)); + + const env = { + ...process.env, + ...(sdkRoot ? { DEVECO_SDK_HOME: sdkRoot } : {}), + ...(java ? { JAVA_HOME: path.dirname(path.dirname(java)) } : {}), + }; + const toolchain = { + devEcoRoot, + sdkRoot, + hvigorw: { path: hvigorw, available: Boolean(hvigorw) }, + hdc: { path: hdc, available: Boolean(hdc) }, + emulator: { path: emulator, available: Boolean(emulator) }, + ohpm: { path: ohpm, available: Boolean(ohpm) }, + java: { path: java, available: Boolean(java) }, + }; + Object.defineProperty(toolchain, "env", { + value: env, + enumerable: false, + }); + const diagnostics = []; + for (const [name, item] of Object.entries(toolchain)) { + if (item && typeof item === "object" && "available" in item && !item.available) { + diagnostics.push({ severity: "warning", message: `${name} was not found`, stage: "toolchain" }); + } + } + if (hvigorw) { + const version = runCommand(hvigorw, ["--version"], { cwd: workspacePath, env, timeoutMs: 15000 }); + toolchain.hvigorw.version = (version.stdout || version.stderr).trim().split(/\r?\n/)[0] || null; + } + if (ohpm) { + const version = runCommand(ohpm, ["--version"], { cwd: workspacePath, env, timeoutMs: 15000 }); + toolchain.ohpm.version = (version.stdout || version.stderr).trim().split(/\r?\n/)[0] || null; + } + return { + ok: diagnostics.length === 0, + toolchain, + diagnostics, + }; +} + +module.exports = { + detectToolchain, +}; diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/json5.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/json5.js new file mode 100644 index 00000000..9f1411c2 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/json5.js @@ -0,0 +1,57 @@ +const fs = require("node:fs"); + +function stripJson5(text) { + let out = ""; + let inString = false; + let quote = ""; + let escaped = false; + for (let i = 0; i < text.length; i += 1) { + const ch = text[i]; + const next = text[i + 1]; + if (inString) { + out += ch; + if (escaped) { + escaped = false; + } else if (ch === "\\") { + escaped = true; + } else if (ch === quote) { + inString = false; + quote = ""; + } + continue; + } + if (ch === '"' || ch === "'") { + inString = true; + quote = ch; + out += ch; + continue; + } + if (ch === "/" && next === "/") { + while (i < text.length && text[i] !== "\n") i += 1; + out += "\n"; + continue; + } + if (ch === "/" && next === "*") { + i += 2; + while (i < text.length && !(text[i] === "*" && text[i + 1] === "/")) i += 1; + i += 1; + continue; + } + out += ch; + } + return out.replace(/,\s*([}\]])/g, "$1"); +} + +function readJson5(filePath, fallback = null) { + try { + const content = fs.readFileSync(filePath, "utf8").replace(/^\uFEFF/, ""); + return JSON.parse(stripJson5(content)); + } catch { + return fallback; + } +} + +module.exports = { + readJson5, + stripJson5, +}; diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/paths.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/paths.js new file mode 100644 index 00000000..18e1bafc --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/paths.js @@ -0,0 +1,69 @@ +const fs = require("node:fs"); +const path = require("node:path"); + +function workspacePathOf(requestOrInput) { + const input = requestOrInput?.input || requestOrInput || {}; + return String( + input.workspacePath || + input.workspace_path || + requestOrInput?.workspacePath || + requestOrInput?.workspace_path || + "" + ).trim(); +} + +function normalizeWorkspace(workspacePath) { + if (!workspacePath) throw new Error("workspacePath is required."); + const resolved = path.resolve(workspacePath); + if (!fs.existsSync(resolved) || !fs.statSync(resolved).isDirectory()) { + throw new Error(`Workspace does not exist or is not a directory: ${resolved}`); + } + return resolved; +} + +function ensureRuntimeDir(workspacePath, child = "") { + const dir = path.join(workspacePath, ".sparo_os", "harmony-dev", child); + fs.mkdirSync(dir, { recursive: true }); + return dir; +} + +function runtimeStatePath(workspacePath) { + return path.join(ensureRuntimeDir(workspacePath), "runtime-state.json"); +} + +function runDir(workspacePath, runId) { + return ensureRuntimeDir(workspacePath, path.join("runs", runId)); +} + +function artifactsDir(workspacePath) { + return ensureRuntimeDir(workspacePath, "artifacts"); +} + +function screenshotsDir(workspacePath) { + return ensureRuntimeDir(workspacePath, "screenshots"); +} + +function hierarchyDir(workspacePath) { + return ensureRuntimeDir(workspacePath, "hierarchy"); +} + +function relativeToWorkspace(workspacePath, filePath) { + return path.relative(workspacePath, filePath).replace(/\\/g, "/"); +} + +function safeFilePart(value) { + return String(value || "run").replace(/[^a-z0-9._-]+/gi, "-").replace(/^-+|-+$/g, "") || "run"; +} + +module.exports = { + artifactsDir, + ensureRuntimeDir, + hierarchyDir, + normalizeWorkspace, + relativeToWorkspace, + runDir, + runtimeStatePath, + safeFilePart, + screenshotsDir, + workspacePathOf, +}; diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/project.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/project.js new file mode 100644 index 00000000..258da75a --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/project.js @@ -0,0 +1,159 @@ +const fs = require("node:fs"); +const path = require("node:path"); +const { readJson5 } = require("./json5"); +const { normalizeWorkspace, relativeToWorkspace } = require("./paths"); +const { diagnostic, redactValue } = require("./redact"); +const { writeRuntimeState, readRuntimeState } = require("./runtime-state"); + +function walkFiles(root, predicate, maxFiles = 4000) { + const files = []; + const stack = [root]; + const ignored = new Set([".git", ".hvigor", "oh_modules", "node_modules", "build", ".sparo_os"]); + while (stack.length && files.length < maxFiles) { + const current = stack.pop(); + let entries = []; + try { + entries = fs.readdirSync(current, { withFileTypes: true }); + } catch { + continue; + } + for (const entry of entries) { + const absolute = path.join(current, entry.name); + if (entry.isDirectory()) { + if (!ignored.has(entry.name)) stack.push(absolute); + } else if (entry.isFile() && predicate(absolute)) { + files.push(absolute); + } + } + } + return files; +} + +function detectSourceHints(workspacePath) { + const etsRoot = path.join(workspacePath, "entry", "src", "main", "ets"); + const etsFiles = fs.existsSync(etsRoot) + ? walkFiles(etsRoot, (file) => /\.(ets|ts)$/i.test(file), 1200) + : []; + const componentNames = new Set(); + for (const file of etsFiles.slice(0, 100)) { + let text = ""; + try { + text = fs.readFileSync(file, "utf8"); + } catch { + continue; + } + for (const match of text.matchAll(/(?:struct|class)\s+([A-Za-z0-9_]+)/g)) { + componentNames.add(match[1]); + } + } + return { + etsFiles: etsFiles.slice(0, 80).map((file) => relativeToWorkspace(workspacePath, file)), + componentNames: Array.from(componentNames).slice(0, 80), + }; +} + +function materialPathsPresent(material = {}) { + const paths = [material.certpath, material.profile, material.storeFile].filter(Boolean); + return paths.length > 0 && paths.every((filePath) => { + try { + return fs.existsSync(filePath); + } catch { + return false; + } + }); +} + +function signingSummary(buildProfile = {}) { + const products = buildProfile?.app?.products || []; + const signingConfigs = buildProfile?.app?.signingConfigs || []; + const selected = products.find((product) => product.signingConfig)?.signingConfig; + const config = signingConfigs.find((item) => item.name === selected) || signingConfigs[0]; + return { + configured: Boolean(selected || config), + materialPathsPresent: materialPathsPresent(config?.material), + redacted: true, + }; +} + +function detectProject(input = {}) { + const workspacePath = normalizeWorkspace(input.workspacePath); + const buildProfilePath = path.join(workspacePath, "build-profile.json5"); + const appJsonPath = path.join(workspacePath, "AppScope", "app.json5"); + const moduleJsonPath = path.join(workspacePath, "entry", "src", "main", "module.json5"); + const diagnostics = []; + if (!fs.existsSync(buildProfilePath)) { + const project = { + kind: "unknown", + status: "notFound", + workspacePath, + }; + return { ok: false, status: "notFound", project, diagnostics: [diagnostic("info", "build-profile.json5 was not found", { stage: "detectProject" })] }; + } + const buildProfile = readJson5(buildProfilePath, {}); + const appJson = readJson5(appJsonPath, {}); + const moduleJson = readJson5(moduleJsonPath, {}); + const product = (buildProfile?.app?.products || [])[0] || {}; + const modules = (buildProfile?.modules || []).map((moduleRef) => { + const moduleRoot = path.resolve(workspacePath, moduleRef.srcPath || moduleRef.name || ""); + const moduleConfigPath = moduleRef.name === "entry" ? moduleJsonPath : path.join(moduleRoot, "src", "main", "module.json5"); + const config = moduleRef.name === "entry" ? moduleJson : readJson5(moduleConfigPath, {}); + const module = config.module || {}; + return { + name: module.name || moduleRef.name, + srcPath: moduleRef.srcPath || "", + type: module.type || "unknown", + mainElement: module.mainElement || null, + deviceTypes: module.deviceTypes || [], + abilities: (module.abilities || []).map((ability) => ({ + name: ability.name, + srcEntry: ability.srcEntry, + exported: Boolean(ability.exported), + label: ability.label, + })), + pages: module.pages || null, + }; + }); + const isHarmony = product.runtimeOS === "HarmonyOS"; + if (!isHarmony) diagnostics.push(diagnostic("warning", "build-profile.json5 exists but runtimeOS is not HarmonyOS", { stage: "detectProject" })); + const sourceHints = detectSourceHints(workspacePath); + const project = redactValue({ + kind: isHarmony ? "harmonyos" : "unknown", + status: isHarmony ? "matched" : "notFound", + workspacePath, + productName: appJson?.app?.label || appJson?.app?.bundleName || path.basename(workspacePath), + runtimeOS: product.runtimeOS || null, + targetSdkVersion: product.targetSdkVersion || null, + compatibleSdkVersion: product.compatibleSdkVersion || null, + bundleName: appJson?.app?.bundleName || null, + app: { + bundleName: appJson?.app?.bundleName || null, + versionName: appJson?.app?.versionName || null, + versionCode: appJson?.app?.versionCode || null, + label: appJson?.app?.label || null, + }, + modules, + signing: signingSummary(buildProfile), + sourceHints, + files: { + buildProfile: "build-profile.json5", + appJson: fs.existsSync(appJsonPath) ? "AppScope/app.json5" : null, + moduleJson: fs.existsSync(moduleJsonPath) ? "entry/src/main/module.json5" : null, + }, + }); + const runtimeState = writeRuntimeState(workspacePath, { + project, + diagnostics, + }); + return { ok: isHarmony, status: project.status, project, diagnostics, runtimeState }; +} + +function projectIdentity(workspacePath) { + const state = readRuntimeState(workspacePath); + if (state.project?.kind === "harmonyos") return state.project; + return detectProject({ workspacePath }).project; +} + +module.exports = { + detectProject, + projectIdentity, +}; diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/protocol.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/protocol.js new file mode 100644 index 00000000..976f9bc3 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/protocol.js @@ -0,0 +1,38 @@ +const fs = require("node:fs"); + +function emit(event) { + const line = `${JSON.stringify(event)}\n`; + try { + fs.writeSync(1, line); + } catch { + process.stdout.write(line); + } +} + +function emitStatus(message, status = "running") { + emit({ type: "run.status", status, message }); +} + +function readRequest() { + return new Promise((resolve, reject) => { + let input = ""; + process.stdin.setEncoding("utf8"); + process.stdin.on("data", (chunk) => { + input += chunk; + }); + process.stdin.on("end", () => { + try { + resolve(JSON.parse(input.trim() || "{}")); + } catch (error) { + reject(error); + } + }); + process.stdin.on("error", reject); + }); +} + +module.exports = { + emit, + emitStatus, + readRequest, +}; diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/redact.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/redact.js new file mode 100644 index 00000000..bfd22e39 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/redact.js @@ -0,0 +1,44 @@ +const SECRET_KEY_RE = /(password|passwd|token|secret|apikey|api_key|private|storePassword|keyPassword)/i; +const SECRET_VALUE_RE = /(keyPassword|storePassword|password|token|secret)\s*[:=]\s*["']?[^"',\s}]+/gi; + +function redactText(value) { + return String(value || "") + .replace(SECRET_VALUE_RE, (match) => { + const key = match.split(/[:=]/)[0] || "secret"; + return `${key}: [redacted]`; + }); +} + +function redactValue(value) { + if (Array.isArray(value)) return value.map(redactValue); + if (!value || typeof value !== "object") { + return typeof value === "string" ? redactText(value) : value; + } + const out = {}; + for (const [key, item] of Object.entries(value)) { + if (SECRET_KEY_RE.test(key)) { + out[key] = "[redacted]"; + } else if (/^(certpath|profile|storeFile)$/i.test(key)) { + out[key] = item ? "[path redacted]" : item; + } else if (typeof item === "string") { + out[key] = redactText(item); + } else { + out[key] = redactValue(item); + } + } + return out; +} + +function diagnostic(severity, message, extra = {}) { + return redactValue({ + severity, + message, + ...extra, + }); +} + +module.exports = { + diagnostic, + redactText, + redactValue, +}; diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/runtime-state.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/runtime-state.js new file mode 100644 index 00000000..3c28a830 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/src/runtime-state.js @@ -0,0 +1,39 @@ +const fs = require("node:fs"); +const { redactValue } = require("./redact"); +const { runtimeStatePath } = require("./paths"); + +function readRuntimeState(workspacePath) { + try { + return JSON.parse(fs.readFileSync(runtimeStatePath(workspacePath), "utf8")); + } catch { + return { + schemaVersion: 1, + updatedAt: Date.now(), + capabilities: { + hdcTarget: false, + bundleDump: "unknown", + abilityLaunch: "unknown", + screenshot: "unknown", + hierarchyDump: "unknown", + hilog: "unknown", + hotReload: "unknown", + }, + diagnostics: [], + }; + } +} + +function writeRuntimeState(workspacePath, patch) { + const next = redactValue({ + ...readRuntimeState(workspacePath), + ...patch, + updatedAt: Date.now(), + }); + fs.writeFileSync(runtimeStatePath(workspacePath), `${JSON.stringify(next, null, 2)}\n`, "utf8"); + return next; +} + +module.exports = { + readRuntimeState, + writeRuntimeState, +}; diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/worker.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/worker.js new file mode 100644 index 00000000..6b41fd5f --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/bridges/builtin-harmony-runtime/source/worker.js @@ -0,0 +1,84 @@ +const readline = require("node:readline"); +const { emit } = require("./src/protocol"); +const { normalizeWorkspace } = require("./src/paths"); +const { detectProject } = require("./src/project"); +const { detectToolchain } = require("./src/harmony-env"); +const { listEmulators, startEmulator, stopEmulator } = require("./src/emulator"); +const { assembleApp, buildProject, hotReload, runUnitTests } = require("./src/build"); +const { captureScreen, dumpHierarchy, installApp, launchAbility, listTargets, readLogs, readScreenshot } = require("./src/device"); +const { readDiagnostics } = require("./src/diagnostics"); +const { readRuntimeState } = require("./src/runtime-state"); +const { redactValue } = require("./src/redact"); + +async function dispatchAction(action, input) { + switch (action) { + case "detectProject": return detectProject(input); + case "detectToolchain": return detectToolchain(input); + case "listEmulators": return listEmulators(input); + case "startEmulator": return startEmulator(input); + case "stopEmulator": return stopEmulator(input); + case "listTargets": return listTargets(input); + case "runUnitTests": return runUnitTests(input); + case "assembleApp": return assembleApp(input); + case "buildProject": return buildProject(input); + case "hotReload": return hotReload(input); + case "installApp": return installApp(input); + case "launchAbility": return launchAbility(input); + case "captureScreen": return captureScreen(input); + case "readScreenshot": return readScreenshot(input); + case "dumpHierarchy": return dumpHierarchy(input); + case "readLogs": return readLogs(input); + case "readDiagnostics": return readDiagnostics(input); + case "getRuntimeState": return { ok: true, runtimeState: readRuntimeState(input.workspacePath) }; + default: throw new Error(`Unsupported HarmonyOS Dev Runtime action: ${action}`); + } +} + +async function handleRequest(request) { + const runId = request.runId || request.run_id || `harmony-${Date.now()}`; + const bridgeId = request.bridgeId || request.bridge_id || "builtin-harmony-runtime"; + const emitEvent = (event) => emit({ bridgeId, runId, event }); + const workspacePath = request.workspacePath || request.workspace_path || null; + const input = { + ...(request.input && typeof request.input === "object" ? request.input : {}), + workspacePath: workspacePath ? normalizeWorkspace(workspacePath) : null, + }; + emitEvent({ type: "run.started", run_id: runId }); + try { + const output = await dispatchAction(request.action, input); + emitEvent({ type: "run.completed", output: redactValue(output) }); + } catch (error) { + emitEvent({ + type: "run.failed", + error: { message: error instanceof Error ? error.message : String(error) }, + }); + } +} + +async function main() { + const lines = readline.createInterface({ input: process.stdin, crlfDelay: Infinity }); + let sawRequest = false; + for await (const rawLine of lines) { + const line = rawLine.trim(); + if (!line) continue; + sawRequest = true; + let request; + try { + request = JSON.parse(line); + } catch (error) { + process.stderr.write(`Invalid Bridge worker request: ${error instanceof Error ? error.message : String(error)}\n`); + process.exitCode = 1; + return; + } + await handleRequest(request); + } + if (!sawRequest) { + process.stderr.write("No Bridge worker request received on stdin\n"); + process.exitCode = 1; + } +} + +main().catch((error) => { + process.stderr.write(`Bridge worker failed: ${error instanceof Error ? error.message : String(error)}\n`); + process.exitCode = 1; +}); diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/component.json b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/component.json new file mode 100644 index 00000000..c63d207f --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/component.json @@ -0,0 +1,78 @@ +{ + "id": "builtin-harmony-dev-surface", + "kind": "surface", + "name": "HarmonyOS Device Preview Workbench", + "description": "The app-owned HarmonyOS preview, build, device, diagnostics, and AI collaboration surface.", + "packageSource": "appPrivate", + "ownerApp": { + "appId": "builtin-harmony-dev", + "appVersion": "13.0.1" + }, + "capabilities": [ + { + "id": "interactiveSurface", + "title": "Interactive surface", + "description": "Hosts the HarmonyOS Dev primary workspace.", + "actions": [ + "open", + "detectProject", + "refreshRuntimeState", + "selectTarget", + "startBuild", + "installAndLaunch", + "captureScreen" + ] + } + ], + "permissions": [ + { + "kind": "fs", + "summary": "Reads and writes app-owned HarmonyOS Dev surface state.", + "scopes": [ + "{appdata}" + ] + } + ], + "usedByApps": [ + "builtin-harmony-dev" + ], + "visibility": "appDependency", + "dependencies": [ + { + "componentId": "harmonyos-dev-agent", + "kind": "agent", + "source": "private", + "role": "harmonyAgent", + "capabilities": [ + "understandHarmonyProject", + "reviseHarmonyUi", + "buildInstallVerify", + "diagnoseHarmonyFailure" + ] + }, + { + "componentId": "builtin-harmony-runtime", + "kind": "bridge", + "source": "private", + "role": "harmonyRuntime", + "capabilities": [ + "sparo.harmonyDev" + ] + }, + { + "componentId": "product-app-runtime-host", + "kind": "runtime", + "source": "shared", + "role": "runtimeHost", + "version": "^1.0.0", + "capabilities": [ + "uiWorker" + ] + } + ], + "implementationRef": "app://builtin-harmony-dev@13.0.1/surfaces/builtin-harmony-dev-surface", + "usesCapabilities": [ + "session.read", + "component.run" + ] +} diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/index.html b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/index.html new file mode 100644 index 00000000..1b74b608 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/index.html @@ -0,0 +1,6 @@ +

+
+
+

Loading HarmonyOS Dev...

+
+
diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/source_manifest.json b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/source_manifest.json new file mode 100644 index 00000000..067c84e8 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/source_manifest.json @@ -0,0 +1,8 @@ +{ + "uiEntry": "ui.js", + "workerEntry": "worker.js", + "styleEntries": [ + "style.css" + ], + "buildMode": "nativeEsm" +} diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/actions.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/actions.js new file mode 100644 index 00000000..69643407 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/actions.js @@ -0,0 +1,314 @@ +import { callBackend } from "./backend.js"; +import { projectSummary, recommendedEmulator, selectedEmulator, targetState } from "./model.js"; +import { buildSelection, selectionSummary } from "./preview/selection-overlay.js"; +import { render } from "./views.js"; +import { state } from "./state.js"; +import { asArray, normalizeBox, runtime, stagePointFromEvent, t } from "./util.js"; + +function setBusy(label) { + state.loading = Boolean(label); + state.action = label || null; + if (label) state.status = label; + render(); +} + +function syncSelectedEmulator() { + const selected = state.selectedEmulatorName + ? selectedEmulator(state.emulators, state.selectedEmulatorName) + : null; + if (selected?.name) { + state.selectedEmulatorName = selected.name; + return selected; + } + const running = asArray(state.emulators).find((emulator) => emulator?.isRunning); + if (running?.name) { + state.selectedEmulatorName = running.name; + return running; + } + const recommended = state.recommendedEmulator || recommendedEmulator(state.emulators); + state.selectedEmulatorName = recommended?.name || null; + return recommended; +} + +function applyOutput(output = {}) { + if (output.project) state.project = output.project; + if (output.toolchain) state.toolchain = output.toolchain; + if (Array.isArray(output.emulators)) state.emulators = output.emulators; + if (output.recommendedEmulator) state.recommendedEmulator = output.recommendedEmulator; + if (output.emulator?.name) state.selectedEmulatorName = output.emulator.name; + if (Array.isArray(output.targets)) state.targets = output.targets; + if (output.runtimeState) state.runtimeState = output.runtimeState; + if (output.runtimeState?.selectedEmulator?.name) state.selectedEmulatorName = output.runtimeState.selectedEmulator.name; + if (output.build) state.build = output.build; + if (output.screen) state.screen = output.screen; + if (output.hierarchy) state.hierarchy = output.hierarchy; + if (Array.isArray(output.diagnostics)) state.diagnostics = output.diagnostics; + syncSelectedEmulator(); + state.error = null; +} + +function activeScreen() { + return state.screen || state.runtimeState?.screen || null; +} + +function hasUsableScreenData(screen) { + const dataUrl = String(screen?.dataUrl || ""); + const comma = dataUrl.indexOf(","); + return dataUrl.startsWith("data:image/") + && comma > 0 + && dataUrl.length > comma + 256 + && Number(screen?.width) > 0 + && Number(screen?.height) > 0 + && Number(screen?.size) > 0; +} + +async function hydrateScreenImage() { + const screen = activeScreen(); + if (!screen?.path || hasUsableScreenData(screen)) return; + if (state.hydratingScreenPath === screen.path) return; + state.hydratingScreenPath = screen.path; + try { + const output = await callBackend("readScreenshot", { + path: screen.path, + screen + }, { timeoutMs: 30000 }); + if (output?.screen) { + state.screen = { ...screen, ...output.screen }; + if (state.runtimeState?.screen?.path === screen.path) { + state.runtimeState = { + ...state.runtimeState, + screen: { ...state.runtimeState.screen, ...output.screen } + }; + } + render(); + } + } catch { + // Keep the stale screen metadata visible; the next capture can replace it. + } finally { + state.hydratingScreenPath = null; + } +} + +async function guarded(label, fn) { + setBusy(label); + try { + const output = await fn(); + applyOutput(output || {}); + void hydrateScreenImage(); + return output; + } catch (error) { + state.error = error instanceof Error ? error.message : String(error); + return null; + } finally { + setBusy(null); + render(); + } +} + +async function refreshFacts() { + if (!state.workspacePath) { + state.project = null; + state.toolchain = null; + state.targets = []; + render(); + return; + } + await guarded(t("detecting"), async () => { + const [project, toolchain, targets, emulators, runtimeState] = await Promise.all([ + callBackend("detectProject"), + callBackend("detectToolchain"), + callBackend("listTargets"), + callBackend("listEmulators"), + callBackend("getRuntimeState") + ]); + return { + project: project?.project || project, + toolchain: toolchain?.toolchain || toolchain, + targets: asArray(targets?.targets), + emulators: asArray(emulators?.emulators), + recommendedEmulator: emulators?.recommendedEmulator || recommendedEmulator(emulators?.emulators), + runtimeState: targets?.runtimeState || project?.runtimeState || emulators?.runtimeState || runtimeState?.runtimeState || runtimeState, + diagnostics: [ + ...asArray(project?.diagnostics), + ...asArray(toolchain?.diagnostics), + ...asArray(targets?.diagnostics), + ...asArray(emulators?.diagnostics) + ] + }; + }); +} + +async function startEmulator() { + const emulator = syncSelectedEmulator(); + if (!emulator?.name) return; + await guarded(t("waitingTarget"), () => callBackend("startEmulator", { name: emulator.name }, { timeoutMs: 180000 })); + await refreshFacts(); +} + +async function stopEmulator() { + const emulator = syncSelectedEmulator(); + if (!emulator?.name) return; + await guarded(t("stopEmulator"), () => callBackend("stopEmulator", { name: emulator.name }, { timeoutMs: 60000 })); + await refreshFacts(); +} + +async function runUnitTests() { + await guarded(t("test"), () => callBackend("runUnitTests", {}, { timeoutMs: 180000 })); +} + +async function buildProject() { + await guarded(t("build"), () => callBackend("buildProject", { includeTests: false }, { timeoutMs: 240000 })); +} + +async function hotReload() { + await guarded(t("hotReload"), () => callBackend("hotReload", {}, { timeoutMs: 180000 })); +} + +async function installApp() { + if (!targetState(state.targets).target) { + state.error = t("installNeedsTarget"); + render(); + return null; + } + return guarded(t("install"), () => callBackend("installApp", {}, { timeoutMs: 120000 })); +} + +async function launchAbility() { + if (!targetState(state.targets).target) { + state.error = t("launchNeedsTarget"); + render(); + return null; + } + return guarded(t("launch"), () => callBackend("launchAbility", {}, { timeoutMs: 90000 })); +} + +async function buildAndRun() { + await guarded(t("buildRun"), () => callBackend("buildProject", { includeTests: false }, { timeoutMs: 240000 })); + if (!state.error) await installApp(); + if (!state.error) await launchAbility(); + if (!state.error) await captureScreen(); + if (!state.error) await dumpHierarchy(); +} + +async function captureScreen() { + const target = targetState(state.targets).target; + const emulator = selectedEmulator(state.emulators, state.selectedEmulatorName) || state.recommendedEmulator || recommendedEmulator(state.emulators); + await guarded(t("capture"), () => callBackend("captureScreen", { + targetId: target?.id, + emulatorName: emulator?.isRunning ? emulator.name : undefined + }, { timeoutMs: 90000 })); +} + +async function dumpHierarchy() { + const target = targetState(state.targets).target; + await guarded(t("inspect"), () => callBackend("dumpHierarchy", { + targetId: target?.id + }, { timeoutMs: 90000 })); +} + +async function readDiagnostics() { + await guarded(t("diagnostics"), () => callBackend("readDiagnostics")); +} + +async function sendContext() { + const host = runtime(); + const project = projectSummary(state.project); + const context = { + workspacePath: state.workspacePath, + route: state.route, + project: state.project, + target: targetState(state.targets).target, + emulator: selectedEmulator(state.emulators, state.selectedEmulatorName), + app: { + bundleName: project.bundleName, + moduleName: project.moduleName, + abilityName: project.abilityName + }, + build: state.build || state.runtimeState?.build || null, + runtime: state.runtimeState, + screen: state.screen || state.runtimeState?.screen || null, + hierarchy: state.hierarchy || state.runtimeState?.hierarchy || null, + selection: state.selection, + diagnostics: state.diagnostics + }; + const prompt = `${t("askPrompt")}\n\nHarmonyOS context: ${selectionSummary(state.selection)}\n\`\`\`json\n${JSON.stringify(context, null, 2)}\n\`\`\``; + await host.host?.fillChatInput?.(prompt); +} + +function setSelectionFromBox(kind, box) { + state.selection = buildSelection(kind, box); + render(); +} + +function beginSelection(event) { + if (!event.target?.closest?.("[data-select-stage]")) return; + if (event.button !== 0) return; + const point = stagePointFromEvent(event); + if (!point) return; + state.selectionDragging = true; + state.selectionDraft = { startX: point.x, startY: point.y, x: point.x, y: point.y, width: 0, height: 0, moved: false }; + render(); +} + +function moveSelection(event) { + if (!state.selectionDragging || !state.selectionDraft) return; + const point = stagePointFromEvent(event); + if (!point) return; + const draft = state.selectionDraft; + draft.x = Math.min(draft.startX, point.x); + draft.y = Math.min(draft.startY, point.y); + draft.width = Math.abs(point.x - draft.startX); + draft.height = Math.abs(point.y - draft.startY); + draft.moved = draft.width > 1 || draft.height > 1; + render(); +} + +function endSelection() { + if (!state.selectionDragging) return; + const draft = state.selectionDraft; + state.selectionDragging = false; + state.selectionDraft = null; + if (!draft) { + render(); + return; + } + if (draft.moved) { + setSelectionFromBox("region", draft); + } else { + setSelectionFromBox("point", normalizeBox({ x: draft.startX - 1, y: draft.startY - 1, width: 2, height: 2 })); + } +} + +function clearSelection() { + state.selection = null; + state.selectionDraft = null; + state.selectionDragging = false; + render(); +} + +function setSelectedEmulator(name) { + state.selectedEmulatorName = name || null; + syncSelectedEmulator(); + render(); +} + +export { + beginSelection, + buildAndRun, + buildProject, + captureScreen, + clearSelection, + dumpHierarchy, + endSelection, + hotReload, + installApp, + launchAbility, + moveSelection, + readDiagnostics, + refreshFacts, + runUnitTests, + sendContext, + setSelectedEmulator, + startEmulator, + stopEmulator +}; diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/backend.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/backend.js new file mode 100644 index 00000000..29d2a4a1 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/backend.js @@ -0,0 +1,37 @@ +import { state } from "./state.js"; +import { bridgeOutput, runtime, t } from "./util.js"; + +async function callBackend(action, input = {}, options = {}) { + const host = runtime(); + if (!host.backend?.call) throw new Error(t("backendMissing")); + const result = await host.backend.call( + `harmonyRuntime.${action}`, + { + workspacePath: state.workspacePath, + ...input + }, + { + entityId: state.workspacePath || "default", + idempotencyKey: `harmony-dev-${action}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}` + } + ); + if (result?.bridgeResult) return bridgeOutput(result); + if (!result?.actionRunId || !host.backend?.status) return bridgeOutput(result); + + const timeoutMs = options.timeoutMs || 120000; + const startedAt = Date.now(); + while (Date.now() - startedAt < timeoutMs) { + const status = await host.backend.status(result.actionRunId, { + sessionId: result.sessionId, + turnId: result.turnId + }); + if (status?.status === "completed") return bridgeOutput(status); + if (status?.status === "failed" || status?.status === "cancelled") { + throw new Error(status?.message || status?.stderr || status?.status); + } + await new Promise((resolve) => setTimeout(resolve, 500)); + } + throw new Error(`Backend action timed out: ${action}`); +} + +export { callBackend }; diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/constants.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/constants.js new file mode 100644 index 00000000..93d55f0a --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/constants.js @@ -0,0 +1,166 @@ +const MESSAGES = { + "en-US": { + appTitle: "HarmonyOS Dev", + detect: "Detect", + startEmulator: "Start emulator", + stopEmulator: "Stop emulator", + emulator: "Emulator", + selectedEmulator: "Selected emulator", + running: "Running", + stopped: "Stopped", + online: "Online", + offline: "Offline", + more: "More", + overview: "Overview", + facts: "Overview", + screen: "Screen", + evidence: "Evidence", + environment: "Environment", + primaryAction: "Run", + quickActions: "Quick actions", + advanced: "Advanced", + manualActions: "Manual actions", + build: "Build", + test: "Test", + install: "Install", + launch: "Launch", + buildRun: "Build & Run", + capture: "Capture", + inspect: "Inspect", + hotReload: "Hot reload", + sendContext: "Send context", + clear: "Clear", + project: "Project", + device: "Device", + buildPanel: "Build", + runtime: "Runtime", + diagnostics: "Diagnostics", + context: "Context", + noWorkspace: "Open HarmonyOS Dev from a workspace to inspect the project and device facts.", + detecting: "Detecting project and runtime facts...", + ready: "Ready", + noProject: "This workspace does not look like a HarmonyOS project.", + noTarget: "No HDC target is online.", + targetReady: "Target online", + emulatorReady: "Emulator candidate ready", + toolchainMissing: "Toolchain needs attention", + projectReady: "HarmonyOS project detected", + buildReady: "Build ready", + buildFailed: "Build failed", + appRunning: "App launched", + previewUnavailable: "No screen evidence yet", + screenshotUnavailable: "Screenshot unavailable", + hierarchyUnavailable: "UI hierarchy unavailable", + selectHint: "Click or drag on the latest screenshot to create context.", + noSelection: "No UI selection", + selectedRegion: "Selected region", + selectedNode: "Selected node", + confidence: "confidence", + latestArtifact: "Latest artifact", + target: "Target", + updated: "Updated", + logs: "Logs", + redacted: "redacted", + publicSafe: "public default", + beta: "beta/non-public", + signed: "signing configured", + unsigned: "unsigned or not configured", + actionBlocked: "Action blocked", + installNeedsTarget: "Install needs an online HDC target.", + launchNeedsTarget: "Launch needs an online HDC target.", + captureNeedsTarget: "Capture needs an online target or emulator screenshot support.", + askPrompt: "Use this HarmonyOS runtime context as the current device fact source.", + backendMissing: "Harmony runtime backend is unavailable.", + waitingTarget: "Waiting for HDC target...", + started: "Started", + completed: "Completed", + failed: "Failed", + unknown: "Unknown" + }, + "zh-CN": { + appTitle: "HarmonyOS Dev", + detect: "检测", + startEmulator: "启动模拟器", + stopEmulator: "\u5173\u95ed\u6a21\u62df\u5668", + emulator: "\u6a21\u62df\u5668", + selectedEmulator: "已选模拟器", + running: "\u8fd0\u884c\u4e2d", + stopped: "\u672a\u8fd0\u884c", + online: "在线", + offline: "离线", + more: "更多", + overview: "概览", + facts: "概览", + screen: "屏幕", + evidence: "证据", + environment: "环境", + primaryAction: "运行", + quickActions: "快捷操作", + advanced: "高级", + manualActions: "手动操作", + build: "构建", + test: "测试", + install: "安装", + launch: "启动", + buildRun: "构建并运行", + capture: "截图", + inspect: "检查层级", + hotReload: "热重载", + sendContext: "发送上下文", + clear: "清除", + project: "项目", + device: "设备", + buildPanel: "构建", + runtime: "运行", + diagnostics: "诊断", + context: "上下文", + noWorkspace: "从工作区打开 HarmonyOS Dev 后可以检查项目与设备事实。", + detecting: "正在检测项目和运行时事实...", + ready: "就绪", + noProject: "当前工作区不像 HarmonyOS 项目。", + noTarget: "当前没有在线 HDC target。", + targetReady: "设备在线", + emulatorReady: "有可用模拟器候选", + toolchainMissing: "工具链需要处理", + projectReady: "已检测到 HarmonyOS 项目", + buildReady: "构建就绪", + buildFailed: "构建失败", + appRunning: "应用已启动", + previewUnavailable: "还没有屏幕证据", + screenshotUnavailable: "截图不可用", + hierarchyUnavailable: "UI 层级不可用", + selectHint: "在最新截图上点击或框选来生成上下文。", + noSelection: "尚未选择 UI", + selectedRegion: "已选择区域", + selectedNode: "已选择节点", + confidence: "置信度", + latestArtifact: "最近产物", + target: "目标", + updated: "更新", + logs: "日志", + redacted: "已脱敏", + publicSafe: "公开默认", + beta: "Beta/非公开", + signed: "已配置签名", + unsigned: "未签名或未配置", + actionBlocked: "动作被阻止", + installNeedsTarget: "安装需要在线 HDC target。", + launchNeedsTarget: "启动需要在线 HDC target。", + captureNeedsTarget: "截图需要在线 target 或模拟器截图能力。", + askPrompt: "请把以下 HarmonyOS 运行时上下文作为当前设备事实源。", + backendMissing: "Harmony runtime 后端不可用。", + waitingTarget: "正在等待 HDC target...", + started: "已启动", + completed: "已完成", + failed: "失败", + unknown: "未知" + } +}; + +function normalizeRoute(route) { + const value = String(route || "/preview").trim(); + if (!value || value === "/") return "/preview"; + return value.startsWith("/") ? value : `/${value}`; +} + +export { MESSAGES, normalizeRoute }; diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/model.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/model.js new file mode 100644 index 00000000..15af1cf2 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/model.js @@ -0,0 +1,40 @@ +import { asArray } from "./util.js"; + +function projectSummary(project) { + const modules = asArray(project?.modules); + const firstModule = modules[0] || {}; + const ability = asArray(firstModule.abilities)[0] || {}; + return { + productName: project?.productName || project?.app?.label || "HarmonyOS", + bundleName: project?.bundleName || project?.app?.bundleName || "-", + moduleName: firstModule.name || "-", + abilityName: firstModule.mainElement || ability.name || "-", + targetSdkVersion: project?.targetSdkVersion || "-", + signing: project?.signing || null + }; +} + +function targetState(targets) { + const list = asArray(targets); + if (!list.length) return { kind: "none", target: null }; + const online = list.find((target) => target.state === "online") || list[0]; + return { kind: "online", target: online }; +} + +function recommendedEmulator(emulators) { + return asArray(emulators) + .slice() + .sort((left, right) => (Number(right.rank || 0) - Number(left.rank || 0)) || String(left.name).localeCompare(String(right.name)))[0] || null; +} + +function selectedEmulator(emulators, selectedName) { + const list = asArray(emulators); + if (selectedName) return list.find((item) => item.name === selectedName) || null; + return recommendedEmulator(list); +} + +function runtimeCapabilities(runtimeState) { + return runtimeState?.capabilities || {}; +} + +export { projectSummary, recommendedEmulator, runtimeCapabilities, selectedEmulator, targetState }; diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/preview/selection-overlay.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/preview/selection-overlay.js new file mode 100644 index 00000000..873fac09 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/preview/selection-overlay.js @@ -0,0 +1,111 @@ +import { state } from "../state.js"; +import { asArray, normalizeBox, round2 } from "../util.js"; + +function parseNodeBounds(node) { + if (node?.boundsPercent) return normalizeBox(node.boundsPercent); + const bounds = node?.bounds || node?.rect; + if (!bounds || !state.screen?.width || !state.screen?.height) return null; + const text = String(bounds); + const match = text.match(/(-?\d+)[,\s]+(-?\d+)[,\s]+(-?\d+)[,\s]+(-?\d+)/); + if (!match) return null; + const left = Number(match[1]); + const top = Number(match[2]); + const right = Number(match[3]); + const bottom = Number(match[4]); + if (![left, top, right, bottom].every(Number.isFinite)) return null; + return normalizeBox({ + x: (left / state.screen.width) * 100, + y: (top / state.screen.height) * 100, + width: ((right - left) / state.screen.width) * 100, + height: ((bottom - top) / state.screen.height) * 100 + }); +} + +function boxCenter(box) { + return { x: box.x + box.width / 2, y: box.y + box.height / 2 }; +} + +function distance(a, b) { + return Math.hypot(a.x - b.x, a.y - b.y); +} + +function overlapScore(a, b) { + const x1 = Math.max(a.x, b.x); + const y1 = Math.max(a.y, b.y); + const x2 = Math.min(a.x + a.width, b.x + b.width); + const y2 = Math.min(a.y + a.height, b.y + b.height); + const intersection = Math.max(0, x2 - x1) * Math.max(0, y2 - y1); + const area = Math.max(1, a.width * a.height); + return intersection / area; +} + +function flattenHierarchyNodes(tree) { + const nodes = []; + const stack = asArray(tree?.nodes || tree?.children || tree?.root ? [tree.root || tree] : tree); + while (stack.length) { + const node = stack.pop(); + if (!node || typeof node !== "object") continue; + nodes.push(node); + asArray(node.children).forEach((child) => stack.push(child)); + } + return nodes; +} + +function matchHierarchyNode(selectionBox) { + const box = normalizeBox(selectionBox); + if (!box || !state.hierarchy) return null; + const center = boxCenter(box); + let best = null; + flattenHierarchyNodes(state.hierarchy).forEach((node) => { + const nodeBox = parseNodeBounds(node); + if (!nodeBox) return; + const score = overlapScore(box, nodeBox) * 100 - distance(center, boxCenter(nodeBox)); + if (!best || score > best.score) { + best = { node, nodeBox, score }; + } + }); + if (!best) return null; + return { + type: best.node.type || best.node.componentType || best.node.className || best.node.name, + text: best.node.text || best.node.content, + description: best.node.description || best.node.accessibilityText, + accessibilityId: best.node.accessibilityId || best.node.id, + path: best.node.path || best.node.pagePath, + bounds: best.node.bounds || best.node.rect, + boundsPercent: best.nodeBox + }; +} + +function buildSelection(kind, box) { + const normalized = normalizeBox(box); + if (!normalized) return null; + const node = matchHierarchyNode(normalized); + const confidence = node + ? (state.hierarchy?.timestamp && state.screen?.timestamp && Math.abs(Number(state.hierarchy.timestamp) - Number(state.screen.timestamp)) < 5000 ? "high" : "medium") + : "low"; + return { + kind, + screenshotId: state.screen?.id || null, + boundsPercent: normalized, + hierarchyNode: node, + sourceHints: { + etsFiles: asArray(state.project?.sourceHints?.etsFiles).slice(0, 12), + componentNames: [ + node?.type, + ...(asArray(state.project?.sourceHints?.componentNames).slice(0, 8)) + ].filter(Boolean), + resourceKeys: [], + confidence + } + }; +} + +function selectionSummary(selection = state.selection) { + if (!selection) return "none"; + const box = selection.boundsPercent || {}; + const node = selection.hierarchyNode; + const label = node?.text || node?.description || node?.type || `${round2(box.x)},${round2(box.y)} ${round2(box.width)}x${round2(box.height)}%`; + return `${selection.kind}: ${label} (${selection.sourceHints?.confidence || "low"})`; +} + +export { buildSelection, selectionSummary }; diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/state.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/state.js new file mode 100644 index 00000000..079103a4 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/state.js @@ -0,0 +1,30 @@ +import { normalizeRoute } from "./constants.js"; + +const state = { + locale: navigator.language || "en-US", + route: normalizeRoute(document.documentElement.dataset.route || "/preview"), + tabId: null, + sessionId: null, + workspacePath: null, + loading: false, + status: "idle", + error: null, + project: null, + toolchain: null, + emulators: [], + recommendedEmulator: null, + selectedEmulatorName: null, + targets: [], + runtimeState: null, + build: null, + screen: null, + hierarchy: null, + diagnostics: [], + selection: null, + selectionDraft: null, + selectionDragging: false, + hydratingScreenPath: null, + action: null +}; + +export { state }; diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/util.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/util.js new file mode 100644 index 00000000..647c9288 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/util.js @@ -0,0 +1,138 @@ +import { MESSAGES, normalizeRoute } from "./constants.js"; +import { state } from "./state.js"; + +function runtime() { + return window.app || {}; +} + +function messages() { + return MESSAGES[state.locale] || MESSAGES[state.locale.split("-")[0]] || MESSAGES["en-US"]; +} + +function t(key, params = {}) { + const template = messages()[key] || MESSAGES["en-US"][key] || key; + return Object.entries(params).reduce( + (value, [name, replacement]) => value.replaceAll(`{{${name}}}`, String(replacement ?? "")), + template + ); +} + +function escapeHtml(value) { + return String(value ?? "") + .replaceAll("&", "&") + .replaceAll("<", "<") + .replaceAll(">", ">") + .replaceAll('"', """) + .replaceAll("'", "'"); +} + +function asArray(value) { + return Array.isArray(value) ? value : []; +} + +function bridgeOutput(result) { + if (result?.bridgeResult?.output !== undefined) return result.bridgeResult.output; + if (result?.output !== undefined) return result.output; + return result; +} + +function rootElement() { + return document.getElementById("harmonyDevRoot"); +} + +function asElement(node) { + if (!node) return null; + return node.nodeType === 1 ? node : node.parentElement || null; +} + +function closestElement(target, selector) { + const element = asElement(target); + return typeof element?.closest === "function" ? element.closest(selector) : null; +} + +function workspaceLabel() { + const workspace = state.workspacePath || ""; + if (!workspace) return "-"; + return workspace.split(/[\\/]/).filter(Boolean).pop() || workspace; +} + +function routeKey(route = state.route) { + return normalizeRoute(route).replace("/", "") || "preview"; +} + +function formatTime(value) { + if (!value) return "-"; + const date = typeof value === "number" ? new Date(value) : new Date(String(value)); + if (Number.isNaN(date.getTime())) return "-"; + return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" }); +} + +function shortPath(value) { + const text = String(value || ""); + if (!text) return "-"; + const parts = text.split(/[\\/]/).filter(Boolean); + return parts.length > 4 ? `.../${parts.slice(-4).join("/")}` : text.replace(/\\/g, "/"); +} + +function round2(value) { + return Math.round((Number(value) || 0) * 100) / 100; +} + +function clamp(value, min, max) { + return Math.max(min, Math.min(max, value)); +} + +function normalizeBox(box) { + if (!box) return null; + const x = clamp(Number(box.x) || 0, 0, 100); + const y = clamp(Number(box.y) || 0, 0, 100); + const width = clamp(Number(box.width) || 0, 0, 100 - x); + const height = clamp(Number(box.height) || 0, 0, 100 - y); + return { x: round2(x), y: round2(y), width: round2(width), height: round2(height) }; +} + +function statusLabel(status) { + if (!status) return t("unknown"); + if (status === "completed" || status === "done" || status === "ok") return t("completed"); + if (status === "failed" || status === "error") return t("failed"); + if (status === "started" || status === "running") return t("started"); + return String(status); +} + +function primaryDiagnostic() { + return asArray(state.diagnostics)[0] + || asArray(state.build?.diagnostics)[0] + || asArray(state.runtimeState?.diagnostics)[0] + || null; +} + +function stagePointFromEvent(event) { + const stage = closestElement(event.target, "[data-select-stage]") || document.querySelector("[data-select-stage]"); + if (!stage) return null; + const rect = stage.getBoundingClientRect(); + if (rect.width <= 0 || rect.height <= 0) return null; + return { + x: round2(((event.clientX - rect.left) / rect.width) * 100), + y: round2(((event.clientY - rect.top) / rect.height) * 100) + }; +} + +export { + asArray, + bridgeOutput, + clamp, + closestElement, + escapeHtml, + formatTime, + normalizeBox, + primaryDiagnostic, + rootElement, + routeKey, + round2, + runtime, + shortPath, + stagePointFromEvent, + statusLabel, + t, + workspaceLabel +}; diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/views.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/views.js new file mode 100644 index 00000000..3138869e --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/src/views.js @@ -0,0 +1,319 @@ +import { projectSummary, recommendedEmulator, selectedEmulator, targetState } from "./model.js"; +import { selectionSummary } from "./preview/selection-overlay.js"; +import { state } from "./state.js"; +import { asArray, escapeHtml, formatTime, primaryDiagnostic, shortPath, t, workspaceLabel } from "./util.js"; + +function attrDisabled(condition) { + return condition ? "disabled" : ""; +} + +function diagnostics() { + return [ + ...asArray(state.diagnostics), + ...asArray(state.build?.diagnostics), + ...asArray(state.runtimeState?.diagnostics) + ].slice(0, 6); +} + +function emulatorLabel(emulator) { + return [ + emulator?.name, + emulator?.osVersion || emulator?.apiVersion, + emulator?.deviceType + ].filter(Boolean).join(" / ") || "-"; +} + +function selectedDevice() { + const emulators = asArray(state.emulators); + const recommended = state.recommendedEmulator || recommendedEmulator(emulators); + const explicit = state.selectedEmulatorName ? selectedEmulator(emulators, state.selectedEmulatorName) : null; + return explicit || emulators.find((item) => item?.isRunning) || recommended; +} + +function productTitle(project) { + const summary = projectSummary(project); + const raw = String(summary.productName || "").trim(); + if (!raw || raw.startsWith("$")) return summary.bundleName || t("appTitle"); + return raw; +} + +function statusModel() { + const project = projectSummary(state.project); + const target = targetState(state.targets); + const diag = primaryDiagnostic(); + const emulator = selectedDevice(); + if (state.error) return { tone: "danger", label: state.error, detail: diag?.message || state.error }; + if (state.loading) return { tone: "busy", label: state.action || t("detecting"), detail: t("detecting") }; + if (state.project?.status === "notFound") return { tone: "warn", label: t("noProject"), detail: workspaceLabel() }; + if (target.target) return { tone: "success", label: t("targetReady"), detail: target.target.id || target.target.serial || project.bundleName }; + if (emulator) return { tone: "warn", label: t("emulatorReady"), detail: emulatorLabel(emulator) }; + return { tone: "muted", label: t("noTarget"), detail: project.bundleName }; +} + +function compactRow(label, value, title = "") { + return ` +
+
${escapeHtml(label)}
+
${escapeHtml(value || "-")}
+
+ `; +} + +function renderKvs(rows) { + return `
${rows.join("")}
`; +} + +function renderTopbar() { + const project = projectSummary(state.project); + const target = targetState(state.targets).target; + const status = statusModel(); + + return ` +
+
+ ${escapeHtml(t("appTitle"))} + ${escapeHtml(workspaceLabel())} +
+
+ ${escapeHtml(project.bundleName)} + ${escapeHtml(project.abilityName)} + ${escapeHtml(target?.id || t("noTarget"))} +
+
+ + ${escapeHtml(status.label)} +
+
+ `; +} + +function renderEmulatorSelect(emulators, selected) { + if (!emulators.length) { + return `${escapeHtml(t("noTarget"))}`; + } + + return ` + + `; +} + +function renderDiagnostics(items) { + if (!items.length) return ""; + return ` +
+

${escapeHtml(t("diagnostics"))}

+
    + ${items.map((item) => ` +
  • + ${escapeHtml(item.severity || item.stage || "info")} +

    ${escapeHtml(item.message || item.summary || item.code || String(item))}

    +
  • + `).join("")} +
+
+ `; +} + +function renderCommandHeader() { + const project = projectSummary(state.project); + const target = targetState(state.targets).target; + const emulators = asArray(state.emulators); + const emulator = selectedDevice(); + const build = state.build || state.runtimeState?.build || {}; + const artifact = build.artifact || state.runtimeState?.latestArtifact; + const screen = state.screen || state.runtimeState?.screen; + const diagList = diagnostics(); + const busy = state.loading; + const hasTarget = Boolean(target); + const hasRunningEmulator = emulators.some((item) => item.isRunning); + const canCapture = hasTarget || hasRunningEmulator || emulator?.isRunning; + const emulatorAction = emulator?.isRunning ? "stop-emulator" : "start-emulator"; + const emulatorActionLabel = emulator?.isRunning ? t("stopEmulator") : t("startEmulator"); + + const overviewRows = [ + compactRow("Bundle", project.bundleName), + compactRow("Ability", project.abilityName), + compactRow(t("target"), target?.id || t("noTarget"), target?.raw || target?.id), + compactRow(t("latestArtifact"), shortPath(artifact?.path), artifact?.path || "") + ]; + const environmentRows = [ + compactRow("Module", project.moduleName), + compactRow("SDK", project.targetSdkVersion), + compactRow("Signing", project.signing?.configured ? t("signed") : t("unsigned")), + compactRow(t("updated"), formatTime(build.updatedAt || artifact?.createdAt || screen?.timestamp)) + ]; + + return ` + + `; +} + +function renderScreenStage() { + const screen = state.screen || state.runtimeState?.screen; + const selection = state.selection; + const hasImage = Boolean(screen?.dataUrl || screen?.uri); + const src = screen?.dataUrl || screen?.uri || ""; + const selectionBox = selection?.boundsPercent; + const screenWidth = Number(screen?.width) > 0 ? Math.round(Number(screen.width)) : 9; + const screenHeight = Number(screen?.height) > 0 ? Math.round(Number(screen.height)) : 19; + const screenAspect = Math.max(0.05, Math.min(5, screenWidth / screenHeight)); + const screenMeta = hasImage + ? `${screenWidth} x ${screenHeight}${screen?.timestamp ? ` / ${formatTime(screen.timestamp)}` : ""}` + : t("previewUnavailable"); + + return ` +
+
+ ${escapeHtml(t("screen"))} + ${escapeHtml(screenMeta)} +
+
+ ${hasImage ? ` +
+
+ HarmonyOS screenshot + ${selectionBox ? ` +
+ ` : ""} + ${state.selectionDraft ? ` +
+ ` : ""} +
+
+ ` : ` +
+
+ ${escapeHtml(t("previewUnavailable"))} + ${escapeHtml(t("selectHint"))} +
+
+ `} +
+
+ ${escapeHtml(t("context"))} + ${escapeHtml(selection ? selectionSummary() : t("noSelection"))} + ${selection ? `` : ""} + +
+
+ `; +} + +function fitScreenCanvas() { + const root = document.getElementById("harmonyDevRoot"); + if (!root) return; + root.querySelectorAll(".hd-screen-canvas").forEach((canvas) => { + const stage = canvas.closest(".hd-device-stage"); + if (!stage) return; + const screenWidth = Number(canvas.getAttribute("data-screen-width")) || 9; + const screenHeight = Number(canvas.getAttribute("data-screen-height")) || 19; + const rect = stage.getBoundingClientRect(); + const maxWidth = Math.max(1, rect.width - 44); + const maxHeight = Math.max(1, rect.height - 44); + const scale = Math.min(maxWidth / screenWidth, maxHeight / screenHeight); + canvas.style.width = `${Math.max(1, Math.floor(screenWidth * scale))}px`; + canvas.style.height = `${Math.max(1, Math.floor(screenHeight * scale))}px`; + }); +} + +function renderMain() { + if (!state.workspacePath) { + return ` +
+
${escapeHtml(t("noWorkspace"))}
+
+ `; + } + return ` +
+ ${renderScreenStage()} +
+ `; +} + +function render() { + const root = document.getElementById("harmonyDevRoot"); + if (!root) return; + root.dataset.route = state.route; + document.documentElement.dataset.route = state.route; + root.innerHTML = ` + ${renderTopbar()} + ${state.loading ? `
` : `
`} + ${renderCommandHeader()} +
${state.error ? escapeHtml(state.error) : ""}
+ ${renderMain()} + `; + if (typeof window.requestAnimationFrame === "function") { + window.requestAnimationFrame(fitScreenCanvas); + } else { + setTimeout(fitScreenCanvas, 0); + } +} + +export { fitScreenCanvas, render }; diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/style.css b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/style.css new file mode 100644 index 00000000..480b9243 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/style.css @@ -0,0 +1,764 @@ +.harmony-dev { + --hd-bg: var(--sparo-app-bg, Canvas); + --hd-surface: var(--sparo-app-surface, Canvas); + --hd-panel: var(--sparo-app-panel, Canvas); + --hd-soft: var(--sparo-app-card, color-mix(in srgb, Canvas 94%, CanvasText)); + --hd-soft-hover: var(--sparo-app-card-hover, color-mix(in srgb, Canvas 90%, CanvasText)); + --hd-control: var(--sparo-app-control-bg, Field); + --hd-control-hover: var(--sparo-app-control-hover, color-mix(in srgb, Field 92%, CanvasText)); + --hd-text: var(--sparo-app-text, CanvasText); + --hd-muted: var(--sparo-app-text-secondary, color-mix(in srgb, CanvasText 66%, Canvas)); + --hd-subtle: var(--sparo-app-text-muted, color-mix(in srgb, CanvasText 46%, Canvas)); + --hd-border: var(--sparo-app-border-subtle, color-mix(in srgb, CanvasText 14%, Canvas)); + --hd-border-strong: var(--sparo-app-border, color-mix(in srgb, CanvasText 22%, Canvas)); + --hd-accent: var(--sparo-app-accent, Highlight); + --hd-accent-hover: var(--sparo-app-accent-hover, color-mix(in srgb, Highlight 86%, CanvasText)); + --hd-accent-soft: var(--sparo-app-accent-soft, color-mix(in srgb, var(--hd-accent) 11%, transparent)); + --hd-accent-text: var(--sparo-app-accent-text, HighlightText); + --hd-info: var(--sparo-info, var(--hd-accent)); + --hd-success: var(--sparo-success, color-mix(in srgb, CanvasText 68%, Canvas)); + --hd-warn: var(--sparo-warning, color-mix(in srgb, CanvasText 72%, Canvas)); + --hd-danger: var(--sparo-error, color-mix(in srgb, CanvasText 72%, Canvas)); + --hd-focus: color-mix(in srgb, var(--sparo-app-focus-ring, var(--hd-accent)) 52%, transparent); + --hd-shadow: var(--sparo-app-shadow, 0 18px 48px color-mix(in srgb, CanvasText 16%, transparent)); + --hd-shadow-soft: var(--sparo-app-shadow-sm, 0 10px 26px color-mix(in srgb, CanvasText 10%, transparent)); + --hd-radius-sm: var(--sparo-app-radius-sm, 6px); + --hd-radius: var(--sparo-app-radius, 8px); + --hd-layer-popover: var(--sparo-z-popover, 20); + --hd-font-sans: var(--sparo-font-sans, Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif); + --hd-font-mono: var(--sparo-font-mono, "JetBrains Mono", ui-monospace, SFMono-Regular, monospace); + display: grid; + grid-template-rows: auto 2px auto auto minmax(0, 1fr); + width: 100%; + max-width: 100%; + height: 100vh; + max-height: 100vh; + min-height: 0; + overflow: hidden; + overflow-x: clip; + background: var(--hd-bg); + color: var(--hd-text); + font: 13px/1.45 var(--hd-font-sans); +} + +html, +body { + width: 100%; + max-width: 100%; + height: 100%; + min-width: 0; + margin: 0; + overflow: hidden; +} + +.harmony-dev *, +.harmony-dev *::before, +.harmony-dev *::after { + box-sizing: border-box; +} + +.harmony-dev button, +.harmony-dev select { + font: inherit; +} + +.harmony-dev button { + cursor: pointer; +} + +.harmony-dev__boot, +.hd-empty { + display: grid; + place-items: center; + min-height: 280px; + padding: 24px; + color: var(--hd-muted); + text-align: center; +} + +.harmony-dev__loader { + width: 24px; + height: 24px; + border: 2px solid var(--hd-border); + border-top-color: var(--hd-accent); + border-radius: 50%; + animation: hd-spin 900ms linear infinite; +} + +@keyframes hd-spin { + to { transform: rotate(360deg); } +} + +.hd-topbar { + display: grid; + grid-template-columns: minmax(160px, 1fr) minmax(180px, 1fr) auto; + align-items: center; + gap: 12px; + min-width: 0; + min-height: 42px; + padding: 6px 14px; + border-bottom: 1px solid var(--hd-border); + background: color-mix(in srgb, var(--hd-panel) 96%, transparent); +} + +.hd-title { + display: flex; + align-items: baseline; + gap: 9px; + min-width: 0; +} + +.hd-title strong { + flex: 0 0 auto; + font-size: 13px; + font-weight: 760; + letter-spacing: 0; +} + +.hd-title span, +.hd-topbar__meta span, +.hd-status span { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.hd-title span { + min-width: 0; + color: var(--hd-muted); + font-size: 12px; +} + +.hd-topbar__meta { + display: grid; + grid-template-columns: minmax(0, 1.2fr) minmax(0, .8fr) minmax(0, 1fr); + gap: 8px; + min-width: 0; + color: var(--hd-subtle); + font-size: 12px; +} + +.hd-status { + display: inline-grid; + grid-template-columns: 7px minmax(0, 1fr); + align-items: center; + gap: 7px; + min-width: 118px; + max-width: 220px; + min-height: 28px; + padding: 0 9px; + border: 1px solid var(--hd-border); + border-radius: var(--hd-radius-sm); + color: var(--hd-muted); + background: color-mix(in srgb, var(--hd-soft) 72%, transparent); +} + +.hd-status__dot { + width: 7px; + height: 7px; + border-radius: 50%; + background: var(--hd-subtle); +} + +.hd-status--success .hd-status__dot { background: var(--hd-success); } +.hd-status--warn .hd-status__dot { background: var(--hd-warn); } +.hd-status--danger .hd-status__dot { background: var(--hd-danger); } +.hd-status--busy .hd-status__dot { + background: var(--hd-accent); + animation: hd-pulse 1s ease-in-out infinite; +} + +@keyframes hd-pulse { + 50% { opacity: .36; } +} + +.hd-progress { + height: 2px; + overflow: hidden; + background: transparent; +} + +.hd-progress span { + display: block; + width: 34%; + height: 100%; + background: linear-gradient(90deg, transparent, var(--hd-accent), transparent); + animation: hd-progress 1.2s ease-in-out infinite; +} + +.hd-progress--idle span { + display: none; +} + +@keyframes hd-progress { + 0% { transform: translateX(-110%); } + 100% { transform: translateX(300%); } +} + +.hd-command-header { + position: relative; + z-index: 2; + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 8px; + min-width: 0; + padding: 8px 14px; + border-bottom: 1px solid var(--hd-border); + background: color-mix(in srgb, var(--hd-panel) 98%, transparent); +} + +.hd-command-title { + display: grid; + gap: 1px; + min-width: 0; + max-width: 220px; + flex: 1 1 150px; +} + +.hd-command-title span { + color: var(--hd-subtle); + font-size: 10px; + font-weight: 760; +} + +.hd-command-title strong { + overflow: hidden; + color: var(--hd-text); + font-size: 13px; + font-weight: 760; + text-overflow: ellipsis; + white-space: nowrap; +} + +.hd-command-actions, +.hd-device-inline { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 6px; + min-width: 0; +} + +.hd-command-actions { + flex: 0 1 auto; +} + +.hd-device-inline { + flex: 1 1 260px; + justify-content: flex-end; +} + +.hd-plain-button, +.hd-action, +.hd-state-button, +.hd-run-button, +.hd-more-menu summary, +.hd-more-actions button { + min-width: 0; + min-height: 30px; + border: 1px solid var(--hd-border); + border-radius: var(--hd-radius-sm); + background: var(--hd-control); + color: var(--hd-text); + font-weight: 650; + white-space: nowrap; + transition: + background .12s ease, + border-color .12s ease, + color .12s ease, + transform .08s ease, + box-shadow .12s ease; +} + +.hd-run-button { + padding: 0 12px; + border-color: color-mix(in srgb, var(--hd-info) 34%, var(--hd-border)); + background: color-mix(in srgb, var(--hd-info) 11%, var(--hd-control)); + color: var(--hd-text); +} + +.hd-action, +.hd-state-button, +.hd-more-menu summary, +.hd-more-actions button { + padding: 0 9px; + color: var(--hd-muted); + font-size: 12px; +} + +.hd-state-button.is-running { + border-color: color-mix(in srgb, var(--hd-danger) 34%, var(--hd-border)); + background: color-mix(in srgb, var(--hd-danger) 8%, var(--hd-control)); + color: var(--hd-danger); +} + +.hd-device-pill { + display: inline-flex; + flex: 0 1 auto; + align-items: center; + gap: 6px; + min-height: 26px; + color: var(--hd-subtle); + font-size: 11px; + font-weight: 720; + white-space: nowrap; +} + +.hd-device-pill i { + width: 7px; + height: 7px; + border-radius: 50%; + background: var(--hd-subtle); +} + +.hd-device-pill.is-online i { + background: var(--hd-success); +} + +.hd-device-select { + flex: 1 1 180px; + width: auto; + max-width: 100%; + min-width: 0; + min-height: 30px; + border: 1px solid var(--hd-border); + border-radius: var(--hd-radius-sm); + background: var(--hd-control); + color: var(--hd-text); + padding: 0 8px; + outline: none; +} + +.hd-device-empty { + color: var(--hd-subtle); + font-size: 12px; +} + +.hd-more-menu { + position: relative; + flex: 0 0 auto; +} + +.hd-more-menu summary { + display: inline-flex; + align-items: center; + list-style: none; + cursor: pointer; +} + +.hd-more-menu summary::-webkit-details-marker { + display: none; +} + +.hd-more-menu__panel { + position: absolute; + top: calc(100% + 7px); + right: 0; + z-index: var(--hd-layer-popover); + width: min(560px, calc(100vw - 32px)); + max-height: min(68vh, 620px); + overflow: auto; + padding: 10px; + border: 1px solid var(--hd-border); + border-radius: var(--hd-radius); + background: var(--hd-panel); + box-shadow: var(--hd-shadow); +} + +.hd-more-actions { + display: flex; + flex-wrap: wrap; + gap: 6px; + margin-bottom: 10px; +} + +.hd-menu-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 10px; +} + +.hd-menu-block { + min-width: 0; + padding: 10px; + border: 1px solid var(--hd-border); + border-radius: var(--hd-radius-sm); + background: color-mix(in srgb, var(--hd-soft) 58%, transparent); +} + +.hd-menu-block + .hd-menu-block { + margin-top: 10px; +} + +.hd-menu-block h3 { + margin: 0 0 8px; + color: var(--hd-text); + font-size: 12px; + font-weight: 760; +} + +.hd-error { + padding: 8px 14px; + border-bottom: 1px solid color-mix(in srgb, var(--hd-danger) 34%, var(--hd-border)); + background: color-mix(in srgb, var(--hd-danger) 9%, var(--hd-panel)); + color: var(--hd-danger); + font-size: 12px; +} + +.hd-error--empty { + height: 0; + overflow: hidden; + padding: 0; + border: 0; +} + +.hd-workbench { + min-width: 0; + min-height: 0; + padding: 12px 14px 14px; + overflow: hidden; + background: linear-gradient(180deg, color-mix(in srgb, var(--hd-surface) 98%, transparent), var(--hd-bg)); +} + +.hd-workbench--empty { + display: grid; + place-items: center; +} + +.hd-preview { + display: grid; + grid-template-rows: 34px minmax(0, 1fr) 38px; + height: 100%; + min-height: 0; + overflow: hidden; + border: 1px solid var(--hd-border); + border-radius: var(--hd-radius); + background: var(--hd-panel); + box-shadow: var(--hd-shadow-soft); +} + +.hd-preview__top, +.hd-context-bar { + display: grid; + align-items: center; + gap: 8px; + min-width: 0; + padding: 0 12px; + border-color: var(--hd-border); + background: color-mix(in srgb, var(--hd-panel) 94%, transparent); +} + +.hd-preview__top { + grid-template-columns: auto minmax(0, 1fr); + border-bottom: 1px solid var(--hd-border); +} + +.hd-preview__top span, +.hd-context-bar span { + color: var(--hd-subtle); + font-size: 11px; + font-weight: 700; +} + +.hd-preview__top strong, +.hd-context-bar strong { + min-width: 0; + overflow: hidden; + color: var(--hd-muted); + font-family: var(--hd-font-mono); + font-size: 11px; + font-weight: 600; + text-overflow: ellipsis; + white-space: nowrap; +} + +.hd-device-stage { + position: relative; + display: flex; + align-items: center; + justify-content: center; + min-height: 0; + padding: 18px; + overflow: hidden; + background: + linear-gradient(180deg, color-mix(in srgb, var(--hd-bg) 86%, var(--hd-text)), color-mix(in srgb, var(--hd-bg) 92%, var(--hd-text))); + user-select: none; + touch-action: none; +} + +.hd-phone-shell { + position: relative; + z-index: 1; + display: grid; + place-items: center; + max-width: 100%; + max-height: 100%; + padding: 10px; + border: 1px solid color-mix(in srgb, var(--hd-text) 16%, transparent); + border-radius: var(--hd-radius); + background: color-mix(in srgb, var(--hd-panel) 92%, var(--hd-text)); + box-shadow: var(--hd-shadow); +} + +.hd-phone-shell--empty { + width: min(320px, 78%); + height: min(620px, 86%); + min-height: 360px; +} + +.hd-screen-canvas { + position: relative; + width: min(320px, 100%); + max-width: 100%; + max-height: 100%; + aspect-ratio: var(--hd-screen-ratio, 9 / 19); + overflow: hidden; + border: 1px solid color-mix(in srgb, var(--hd-text) 12%, transparent); + border-radius: 4px; + background: var(--hd-bg); +} + +.hd-screen-image { + position: absolute; + inset: 0; + display: block; + width: 100%; + height: 100%; + object-fit: contain; + object-position: center; +} + +.hd-preview-empty { + display: grid; + gap: 6px; + padding: 24px; + text-align: center; + color: var(--hd-subtle); +} + +.hd-preview-empty strong { + color: var(--hd-text); + font-size: 14px; +} + +.hd-selection { + position: absolute; + border: 2px solid var(--hd-accent); + background: color-mix(in srgb, var(--hd-accent) 17%, transparent); + box-shadow: 0 0 0 1px color-mix(in srgb, var(--hd-text) 48%, transparent); + pointer-events: none; +} + +.hd-selection--draft { + border-style: dashed; +} + +.hd-context-bar { + grid-template-columns: auto minmax(0, 1fr) auto auto; + border-top: 1px solid var(--hd-border); +} + +.hd-plain-button { + min-height: 26px; + padding: 0 9px; + border: 1px solid var(--hd-border); + border-radius: var(--hd-radius-sm); + background: var(--hd-control); + color: var(--hd-muted); + font-weight: 650; +} + +.hd-plain-button--accent { + color: var(--hd-accent); +} + +.hd-kvs { + display: grid; + gap: 6px; + margin: 0; + padding: 0; +} + +.hd-kv { + display: grid; + grid-template-columns: 82px minmax(0, 1fr); + gap: 8px; + min-width: 0; + align-items: baseline; +} + +.hd-kv dt { + color: var(--hd-subtle); + font-size: 11px; +} + +.hd-kv dd { + min-width: 0; + margin: 0; + overflow: hidden; + color: var(--hd-muted); + font-family: var(--hd-font-mono); + font-size: 11px; + text-overflow: ellipsis; + white-space: nowrap; +} + +.hd-diagnostics { + display: grid; + gap: 8px; + margin: 0; + padding: 0; + list-style: none; +} + +.hd-diagnostics li { + display: grid; + grid-template-columns: 58px minmax(0, 1fr); + gap: 8px; + align-items: start; +} + +.hd-diagnostics span { + color: var(--hd-warn); + font-size: 10px; + font-weight: 760; +} + +.hd-diagnostics p { + margin: 0; + color: var(--hd-muted); + font-size: 12px; +} + +.hd-plain-button:hover:not(:disabled), +.hd-action:hover:not(:disabled), +.hd-state-button:hover:not(:disabled), +.hd-more-menu summary:hover, +.hd-more-actions button:hover:not(:disabled) { + border-color: var(--hd-border-strong); + background: var(--hd-control-hover); + color: var(--hd-text); +} + +.hd-run-button:hover:not(:disabled) { + border-color: color-mix(in srgb, var(--hd-info) 48%, var(--hd-border-strong)); + background: color-mix(in srgb, var(--hd-info) 15%, var(--hd-control-hover)); +} + +.hd-plain-button:active:not(:disabled), +.hd-action:active:not(:disabled), +.hd-state-button:active:not(:disabled), +.hd-run-button:active:not(:disabled), +.hd-more-actions button:active:not(:disabled) { + transform: translateY(1px); +} + +.hd-plain-button:focus-visible, +.hd-action:focus-visible, +.hd-state-button:focus-visible, +.hd-run-button:focus-visible, +.hd-more-menu summary:focus-visible, +.hd-more-actions button:focus-visible, +.hd-device-select:focus-visible { + outline: 2px solid var(--hd-focus); + outline-offset: 2px; +} + +.hd-plain-button:disabled, +.hd-action:disabled, +.hd-state-button:disabled, +.hd-run-button:disabled, +.hd-more-actions button:disabled { + cursor: not-allowed; + opacity: .48; + transform: none; +} + +@media (max-width: 980px) { + .hd-topbar { + grid-template-columns: minmax(0, 1fr) auto; + } + + .hd-topbar__meta { + display: none; + } + + .hd-command-header { + flex-wrap: wrap; + } + + .hd-device-inline { + order: 3; + flex-basis: 100%; + justify-content: flex-start; + } + + .hd-more-menu { + margin-left: auto; + } +} + +@media (max-width: 640px) { + .hd-topbar { + grid-template-columns: minmax(0, 1fr); + gap: 6px; + } + + .hd-status { + width: 100%; + max-width: none; + } + + .hd-command-title { + flex-basis: 100%; + max-width: none; + } + + .hd-command-actions { + flex: 1 1 100%; + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .hd-device-inline { + display: grid; + grid-template-columns: auto minmax(0, 1fr); + width: 100%; + } + + .hd-device-select, + .hd-state-button { + width: 100%; + } + + .hd-state-button { + grid-column: 1 / -1; + } + + .hd-more-menu { + margin-left: 0; + } + + .hd-more-menu__panel { + left: 0; + right: auto; + width: calc(100vw - 28px); + } + + .hd-menu-grid { + grid-template-columns: 1fr; + } + + .hd-workbench { + padding: 10px; + } + + .hd-device-stage { + padding: 12px; + } + + .hd-context-bar { + grid-template-columns: auto minmax(0, 1fr) auto; + } +} diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/ui.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/ui.js new file mode 100644 index 00000000..54a07430 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/ui.js @@ -0,0 +1,101 @@ +import { normalizeRoute } from "./src/constants.js"; +import { + beginSelection, + buildAndRun, + buildProject, + captureScreen, + clearSelection, + dumpHierarchy, + endSelection, + hotReload, + installApp, + launchAbility, + moveSelection, + refreshFacts, + runUnitTests, + sendContext, + setSelectedEmulator, + startEmulator, + stopEmulator +} from "./src/actions.js"; +import { state } from "./src/state.js"; +import { closestElement, runtime } from "./src/util.js"; +import { fitScreenCanvas, render } from "./src/views.js"; + +function handleRouteEvent(payload = {}) { + state.route = normalizeRoute(payload.route || state.route); + state.tabId = payload.tabId || state.tabId; + state.sessionId = payload.sessionId || state.sessionId; + const nextWorkspace = payload.workspacePath || payload.workbench?.workspacePath || state.workspacePath; + const workspaceChanged = nextWorkspace && nextWorkspace !== state.workspacePath; + state.workspacePath = nextWorkspace || state.workspacePath; + if (workspaceChanged) { + state.project = null; + state.toolchain = null; + state.targets = []; + state.emulators = []; + state.recommendedEmulator = null; + state.selectedEmulatorName = null; + state.runtimeState = null; + state.build = null; + state.screen = null; + state.hierarchy = null; + state.selection = null; + state.error = null; + } + render(); + if (workspaceChanged || (!state.project && state.workspacePath)) { + void refreshFacts(); + } +} + +document.addEventListener("click", (event) => { + const node = closestElement(event.target, "[data-action]"); + if (!node) return; + const action = node.dataset.action; + if (action === "detect") void refreshFacts(); + if (action === "start-emulator") void startEmulator(); + if (action === "stop-emulator") void stopEmulator(); + if (action === "test") void runUnitTests(); + if (action === "build") void buildProject(); + if (action === "install") void installApp(); + if (action === "launch") void launchAbility(); + if (action === "build-run") void buildAndRun(); + if (action === "capture") void captureScreen(); + if (action === "inspect") void dumpHierarchy(); + if (action === "hot-reload") void hotReload(); + if (action === "send-context") void sendContext(); + if (action === "clear-selection") clearSelection(); +}); + +document.addEventListener("change", (event) => { + const node = closestElement(event.target, "[data-emulator-select]"); + if (!node) return; + setSelectedEmulator(node.value); +}); + +document.addEventListener("pointerdown", beginSelection, true); +document.addEventListener("pointermove", moveSelection, true); +document.addEventListener("pointerup", endSelection, true); +window.addEventListener("resize", fitScreenCanvas); + +window.addEventListener("message", (event) => { + const message = event.data; + if (message?.type !== "sparo:event") return; + if (message.event === "localeChange") { + state.locale = message.payload?.locale || state.locale; + render(); + } + if (message.event === "productAppRuntimeRouteChange") { + handleRouteEvent(message.payload || {}); + } +}); + +runtime().onLocaleChange?.((locale) => { + state.locale = locale || state.locale; + render(); +}); + +window.addEventListener("DOMContentLoaded", () => { + render(); +}); diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/worker.js b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/worker.js new file mode 100644 index 00000000..5e47e0dc --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/components/surfaces/builtin-harmony-dev-surface/source/worker.js @@ -0,0 +1,4 @@ +// HarmonyOS Dev keeps product logic in the UI and delegates privileged work to +// the Harmony runtime Bridge Component. This worker is intentionally empty. + +export default {}; diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/config/data-schema.json b/bundles/product-apps/builtin-harmony-dev/13.0.1/config/data-schema.json new file mode 100644 index 00000000..1587a669 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/config/data-schema.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/config/default.json b/bundles/product-apps/builtin-harmony-dev/13.0.1/config/default.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/config/default.json @@ -0,0 +1 @@ +{} diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/tests/eval.json b/bundles/product-apps/builtin-harmony-dev/13.0.1/tests/eval.json new file mode 100644 index 00000000..0cb5e7bd --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/tests/eval.json @@ -0,0 +1,24 @@ +{ + "version": 1, + "cases": [ + { + "id": "primary-behavior", + "title": "HarmonyOS Dev responds from its declared app context", + "description": "Proves that the immutable Release can invoke its intelligent behavior.", + "input": { + "message": "Reply with SPARO_APP_READY, then briefly confirm you can help with HarmonyOS Dev." + }, + "expectations": [ + { + "kind": "text-contains", + "value": "SPARO_APP_READY" + } + ], + "evidenceKind": "behavior", + "tags": [ + "release-gate" + ], + "required": true + } + ] +} diff --git a/bundles/product-apps/builtin-harmony-dev/13.0.1/tests/rehearsal.json b/bundles/product-apps/builtin-harmony-dev/13.0.1/tests/rehearsal.json new file mode 100644 index 00000000..ecdfb11e --- /dev/null +++ b/bundles/product-apps/builtin-harmony-dev/13.0.1/tests/rehearsal.json @@ -0,0 +1,33 @@ +{ + "version": 1, + "scenarios": [ + { + "id": "critical-user-path", + "title": "Open HarmonyOS Dev and complete its first useful action", + "description": "An integrated HarmonyOS app development environment that brings ArkTS, ArkUI, building, packaging, debugging, and device runtime into one workspace.", + "kind": "user-path", + "steps": [ + { + "id": "open-app", + "action": "open", + "target": "primary", + "expect": [ + "HarmonyOS Dev opens" + ] + }, + { + "id": "observe-ready-state", + "action": "observe", + "target": "work-outcome", + "expect": [ + "A usable ready state is visible" + ] + } + ], + "expected": [ + "The app opens without a fatal runtime issue", + "The primary workflow exposes an observable path" + ] + } + ] +} diff --git a/bundles/product-apps/builtin-ppt-live/150.0.2/assets/icon.png b/bundles/product-apps/builtin-ppt-live/150.0.2/assets/icon.png deleted file mode 100644 index bdf2c47ecb3abe86c8dc4d6ec79371bf171c2243..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 816800 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� 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

P;PrwZF+p-T{Y@M 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 z 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�Y<0?&Hos}FBB{<1-UVyTkH&@i2Hu*MT+7i|( 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

d*07TVQoXC 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 $;>+t?xjmcNS7yKP$8PrLfB#4O>Hpx9 zef*1N&reVG{Nc%Nc(pITrus6uG*fg9tamD8tu!qhK$$~c8c2JQ-lw1j)sTTxuEk;y z54&iYExLmiQ!=YUAE<(Ch7zUb%>K(PcnOyFb^iQidxD&@HQ`420>bTP_8INzuX;B7 z9A;mo$;YSXc8y;F<^rTgYntU)f^jYb+M%DCrjWsfhI@-Tnz@^VwQpGH>-Hau;s7ib z0rQ^QkK0%VcIM!4#(-3pK_!lgCSff0_k1yV2F|>6@)E|!n!th1vaD>!=u~v!+zxqt z>sZA=J&I6I!HQxqTbKcfN!W6MH$iFHr=;l=gXTVsFiSHo9;c2S*U%BxZHrkpllQA> z4Jq3utuwlQ<@W*+ZQ&cw*4G*=g+KIckN5ZoZFMoGZbd%Y%JdUAp7r6s3XS9&O-8&T z`@Ep8V_@FAA+kGLQ5vZ8TY&7o`V8d&P!DPzoZ~!bX~~5I+jHu)2cu5X3JQL|

+;#SYBl*XP1@IrhvWO9kg8rqNttw&d=& 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

- - - diff --git a/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/deck-ai.js b/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/deck-ai.js deleted file mode 100644 index 815d0f5e..00000000 --- a/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/deck-ai.js +++ /dev/null @@ -1,1523 +0,0 @@ -import { translate as t, getLocale } from './i18n.js'; -import { clone, ensureState, makeSlide, normalizeSlide, uid } from './state.js'; -import { STYLE_PRESETS } from './style-presets.js'; - -const PPT_DESIGN_SKILL_CONTEXT = [ - 'You are PPT Live. Deck generation is owned by the Sparo agent with the ppt-design skill.', - 'The user is the final decision maker. Execute the PPT task end to end and do not impose any fixed content agenda on the topic.', - '', - 'Production method:', - '1. Publish assumptions: audience, page count, design style, and theme.', - '2. Produce an assertion-led outline with one message per slide.', - '3. Ground facts in pasted material, explicit URLs, or clearly marked assumptions.', - '4. Apply the ppt-design anti-slop rules: no purple gradient gimmicks, no emoji icons, no generic illustration filler, and no text-heavy pages.', - '5. Assemble the final editable deck blueprint with concise visible text and useful speaker notes.', - '', - 'Benchmark design target:', - '- Match the professional feel of beautiful.ai and gamma.app: smart templates, strong typographic hierarchy, generous whitespace, crisp card/grid systems, and content-aware layouts.', - '- Select the layout from the content type: cover, assertion split, evidence cards, data/chart, process/timeline, comparison matrix, quote/transition, and closing action.', - '- Prefer one dominant visual object per slide. Use proof objects, metric cards, compact charts, or structured text panels instead of filling space with bullets.', - '- Keep visible copy presentation-ready: one assertion title, one support line, and up to three short proof points unless the slide is explicitly a comparison or process.', - '', - 'Design principles from ppt-design:', - '- Use the user order and verified material as the only content authority.', - '- Every page carries one core message and keeps visible text concise.', - '- Keep titles concrete, assertion-led, and connected to the actual subject.', - '- If material is thin, clearly mark unknowns and verification notes while still producing a useful draft.', -].join('\n'); - -export function buildBriefFromInputs(state) { - const brief = { ...state.brief }; - if (!brief.slideTarget) delete brief.slideTarget; - return { - ...brief, - title: state.title, - currentOutline: state.outline, - style: state.style, - sources: state.sources || null, - locale: getLocale(), - }; -} - -export async function planPresentationTaskWithAi(state, instruction) { - const schema = { - operation: 'generate_deck|revise_deck|revise_slide|insert_slide|delete_slide|update_outline', - scope: 'deck|current_slide|slide_index', - slideIndex: null, - briefPatch: { - topic: 'optional refined topic', - audience: 'optional refined audience', - slideTarget: null, - intent: 'free-form inferred purpose, only if stated or strongly implied', - tone: 'free-form tone, only if stated or strongly implied', - }, - needsSources: true, - reason: 'why this operation is the right next step', - steps: [ - { stage: 'brief|research|verification|outline|visual|assembly', task: 'work to do', deliverable: 'expected output' }, - ], - acceptanceCriteria: ['What must be true when done'], - }; - const prompt = [ - 'Return strict JSON only, no markdown fences.', - `Shape: ${JSON.stringify(schema)}.`, - `Locale: ${getLocale()}.`, - PPT_DESIGN_SKILL_CONTEXT, - `User order: ${instruction || ''}.`, - `Current deck state: ${JSON.stringify({ - title: state.title, - brief: state.brief, - slideCount: state.slides?.length || 0, - activeSlideIndex: Math.max(0, state.slides?.findIndex((slide) => slide.id === state.activeSlideId) ?? 0), - outline: state.outline, - currentSlide: state.slides?.find((slide) => slide.id === state.activeSlideId) || state.slides?.[0] || null, - })}.`, - 'Choose the next executable operation autonomously. Prefer deck-level work when the user asks for a presentation outcome, structural change, rewrite, expansion, deletion by theme, or ambiguous improvement.', - 'Choose current-slide revision only when the user clearly targets the current page/slide.', - 'Choose delete_slide only when the user clearly asks to remove the current slide or a numbered slide. For deleting duplicate, weak, or irrelevant content, choose revise_deck so the deck can be reorganized.', - 'Set briefPatch only for fields inferred from the user order. Keep steps short and operational.', - ].join('\n'); - const data = await askAi(prompt, 1200); - return normalizeAgentPlan(data, state); -} - -export async function enrichSources(state) { - const urls = extractUrls(`${state.brief.topic || ''}\n${state.brief.material || ''}`); - const manual = stripUrls(`${state.brief.topic || ''}\n${state.brief.material || ''}`).trim(); - const sources = { - items: [], - facts: [], - warnings: [], - summary: '', - fetchedAt: Date.now(), - }; - if (manual.length >= 20) { - sources.items.push({ kind: 'user-text', title: t('sourceManualTitle'), url: '', text: manual.slice(0, 5000) }); - } - for (const url of urls.slice(0, 3)) { - try { - const fetched = await fetchReadableSources(url); - sources.items.push(...fetched); - } catch (error) { - window.app?.log?.warn?.('PPT Live source fetch failed', { url, error: String(error) }); - sources.warnings.push(t('sourceFetchFailed', { url })); - } - } - const combined = sources.items.map((item) => `${item.title}\n${item.text}`).join('\n\n').slice(0, 14000); - sources.facts = extractFacts(combined); - sources.summary = summarizeSource(combined, sources); - if (!sources.items.length) sources.warnings.push(t('sourceMissingWarning')); - state.sources = sources; - return sources; -} - -export async function generateOutlineWithAi(state) { - const prompt = [ - 'Return strict JSON only, no markdown fences.', - 'Shape: {"title":"deck title","outline":["slide title", "..."]}.', - `Locale: ${getLocale()}.`, - PPT_DESIGN_SKILL_CONTEXT, - `Brief: ${JSON.stringify(buildBriefFromInputs(state))}.`, - 'Generate the PPT outline as the Story academy.', - 'The outline must directly answer the user order and the fetched/pasted source. Do not substitute any preselected content agenda.', - 'Use TED 3S: Hook -> context -> core evidence -> shift -> takeaway. One concrete idea per slide.', - 'Every slide title must use concrete nouns from the user topic or source instead of abstract placeholders.', - 'Respect brief.slideTarget only when it is a positive number. Otherwise choose an appropriate outline length from the topic and material.', - ].join('\n'); - const data = await askAi(prompt, 1000); - if (!Array.isArray(data?.outline) || data.outline.length === 0) throw new Error('Invalid outline'); - const target = Number(state.brief.slideTarget) || 0; - const outline = target > 0 ? data.outline.slice(0, target).map(String) : data.outline.map(String); - return { - title: data.title || data.outline[0] || state.title, - outline, - }; -} - -export async function generateDeckWithAi(state) { - const schema = { - title: 'Deck title', - slides: [ - { - role: 'cover|content|data|transition|closing', - narrativeStage: 'hook|context|core|shift|takeaway', - title: 'Source-specific slide title', - kicker: '1-3 word slide role', - claim: 'One concrete idea this slide communicates', - proofObject: 'source-backed proof or visual direction for this page', - supportNote: 'What source fact or assumption supports this slide', - sourceNote: 'Source URL/name or verification note', - facts: ['Source-backed fact or clearly marked assumption, using source vocabulary'], - bullets: ['Short visible text, max 12 Chinese chars or 8 English words when possible'], - metric: { value: 'Only if explicitly present in source', label: 'Metric label' }, - chartData: [{ label: 'Only source-backed label', value: 0 }], - notes: 'Speaker notes', - layout: 'cover|brief|evidence|process|comparison|quote|data|closing', - }, - ], - }; - const prompt = [ - 'Return strict JSON only, no markdown fences.', - `Shape: ${JSON.stringify(schema)}.`, - `Locale: ${getLocale()}.`, - PPT_DESIGN_SKILL_CONTEXT, - `Brief: ${JSON.stringify(buildBriefFromInputs(state))}.`, - `Confirmed outline: ${JSON.stringify(state.outline)}.`, - 'Generate the final editable deck blueprint after internal research, verification, outline, visual planning, and assembly steps.', - 'Content fidelity is the top priority. Every slide must be about the user-requested topic/source. Do not introduce unrelated framing unless it is present in the user order or source.', - 'Use the user brief and source vocabulary aggressively: names, concepts, claims, examples, data, constraints, and domain-specific terms that actually appear in the material.', - 'Every non-cover slide must have exactly one dominant message and, when useful, a visual direction selected by the content.', - 'Visible text should be concise and presentation-ready. Speaker notes can carry explanation.', - 'Use chart/data slides only when numeric data exists in the source. Never invent precise numbers.', - 'If a source could not be read, mark that specific source as unavailable. If a source was read, do not say it was unread.', - 'Before returning JSON, self-check: (1) each title mentions the actual subject, (2) bullets are grounded in the order/source, (3) no preselected agenda, (4) requested page count is respected.', - ].join('\n'); - const data = await askAi(prompt, 2800); - if (!Array.isArray(data?.slides) || data.slides.length === 0) throw new Error('Invalid deck'); - return compileBlueprint({ title: data.title || state.title, slides: data.slides }, state); -} - -export async function applySlideInstructionWithAi(state, action, instruction) { - const current = state.slides.find((slide) => slide.id === state.activeSlideId) || state.slides[0]; - if (!current) return null; - const prompt = [ - 'Return strict JSON only, no markdown fences.', - 'Return one slide using the same editable JSON format as the current slide.', - `Locale: ${getLocale()}.`, - PPT_DESIGN_SKILL_CONTEXT, - `Action: ${action}.`, - `User instruction: ${instruction || ''}.`, - `Deck brief: ${JSON.stringify(buildBriefFromInputs(state))}.`, - `Current slide: ${JSON.stringify(current)}.`, - 'Preserve the core message, but improve content, layout, hierarchy, speaker notes, and visual clarity.', - 'Maintain a slide role, claim, proofObject, supportNote, and sourceNote. Strengthen the proof object before adding more text.', - ].join('\n'); - const data = await askAi(prompt, 1800); - if (!data?.elements?.length) throw new Error('Invalid slide'); - return normalizeSlide({ ...current, ...data, id: current.id }, state.slides.indexOf(current), state); -} - -export async function applyDeckInstructionWithAi(state, instruction) { - const schema = { - title: 'Deck title', - slides: [ - { - role: 'cover|content|data|transition|closing', - narrativeStage: 'hook|context|core|shift|takeaway', - title: 'Source-specific slide title', - kicker: '1-3 word slide role', - claim: 'One concrete idea this slide communicates', - proofObject: 'source-backed proof or visual direction for this page', - supportNote: 'What source fact or assumption supports this slide', - sourceNote: 'Source or verification note', - facts: ['Source-backed fact or clearly marked assumption, using source vocabulary'], - bullets: ['Short visible text'], - metric: { value: 'Only if explicitly present in source', label: 'Metric label' }, - chartData: [{ label: 'Only source-backed label', value: 0 }], - notes: 'Speaker notes', - layout: 'cover|brief|evidence|process|comparison|quote|data|closing', - }, - ], - }; - const prompt = [ - 'Return strict JSON only, no markdown fences.', - `Shape: ${JSON.stringify(schema)}.`, - `Locale: ${getLocale()}.`, - PPT_DESIGN_SKILL_CONTEXT, - `User revision request: ${instruction || ''}.`, - `Deck brief: ${JSON.stringify(buildBriefFromInputs(state))}.`, - `Current editable deck: ${JSON.stringify({ title: state.title, outline: state.outline, slides: state.slides })}.`, - 'Act as an end-to-end presentation agent, not a single-slide editor.', - 'Revise the whole deck as a coherent presentation while staying loyal to the user order and source material.', - 'You may generate a complete new deck, add slides, delete slides, reorder slides, merge duplicate slides, or rewrite existing slides when the user request calls for it.', - 'Preserve source constraints and never invent precise facts. Do not introduce a generic content formula unless the source or user asks for it.', - 'Keep the same approximate slide count only when the user asks for a style/content rewrite without structural change.', - 'Make every slide title source-specific and every slide revolve around one core message.', - ].join('\n'); - const data = await askAi(prompt, 3200); - if (!Array.isArray(data?.slides) || data.slides.length === 0) throw new Error('Invalid deck revision'); - return compileBlueprint({ title: data.title || state.title, slides: data.slides }, state, { respectSlideTarget: false }); -} - -export async function insertSlideWithAi(state, instruction) { - const index = Math.min(state.slides.length, Math.max(0, state.slides.findIndex((slide) => slide.id === state.activeSlideId) + 1)); - const prompt = [ - 'Return strict JSON only, no markdown fences.', - 'Return one slide using the same editable JSON format as the surrounding slides.', - `Locale: ${getLocale()}.`, - PPT_DESIGN_SKILL_CONTEXT, - `Insertion request: ${instruction || ''}.`, - `Deck brief: ${JSON.stringify(buildBriefFromInputs(state))}.`, - `Insert after slide index: ${index}.`, - `Deck outline: ${JSON.stringify(state.outline)}.`, - `Previous slide: ${JSON.stringify(state.slides[index - 1] || null)}.`, - `Next slide: ${JSON.stringify(state.slides[index] || null)}.`, - 'The inserted page must advance the story, not duplicate neighboring pages.', - 'Maintain a slide role, claim, proofObject, supportNote, sourceNote, speaker notes, and editable elements.', - ].join('\n'); - const data = await askAi(prompt, 1800); - if (!data?.elements?.length) throw new Error('Invalid inserted slide'); - return normalizeSlide(data, index, { ...state, slides: [...state.slides, data] }); -} - -export function localOutline(state) { - const topic = displayTopic(state.brief.topic || t('defaultDeckTitle')); - const facts = sourceFallbackFacts(state).filter(Boolean); - const base = [ - topic, - `${topic} 是什么,以及为什么值得关注`, - facts[0] || `${topic} 的核心能力来自已有素材`, - facts[1] || `${topic} 的工作方式需要用一个流程讲清楚`, - facts[2] || `${topic} 的典型场景决定它的价值`, - `${topic} 的证据和待验证问题`, - `${topic} 适合谁,以及不适合谁`, - `${topic} 的最终落点`, - ]; - return (state.brief.slideTarget > 0 ? base.slice(0, state.brief.slideTarget) : base).map(cleanTitle); -} - -export function localDeck(state) { - const outline = state.outline?.length ? state.outline : localOutline(state); - const next = ensureState({ ...clone(state), outline }); - const blueprint = localBlueprint(next, outline); - const compiled = compileBlueprint(blueprint, next); - next.slides = compiled.slides; - next.title = compiled.title; - next.activeSlideId = next.slides[0]?.id || ''; - next.selectedElementId = next.slides[0]?.elements[0]?.id || ''; - return next; -} - -export function compileBlueprint(blueprint, state, options = {}) { - const sourceCount = state.sources?.items?.length || 0; - const requestedSlides = blueprint.slides || []; - const fromAgentPayload = options.fromAgentPayload === true; - const deckDesign = resolveDeckDesign(blueprint, state); - const hasExplicitTarget = Number(state.brief.slideTarget) > 0 && options.respectSlideTarget !== false; - const slideSource = hasExplicitTarget - ? requestedSlides.slice(0, state.brief.slideTarget) - : requestedSlides; - const slides = slideSource.map((item, index, all) => { - const safeItem = normalizeBlueprintDataIntegrity(item, state); - const role = safeItem.role || roleForIndex(index, all.length); - const layout = safeItem.layout || layoutForRole(role, index, all.length); - const visualTreatment = normalizeVisualTreatment(safeItem.visualTreatment || safeItem.visual || safeItem.designIntent || layout, role, index, all.length); - const slide = { - id: uid('slide'), - title: cleanTitle(safeItem.title || safeItem.claim || state.outline[index] || t('newSlideTitle')), - subtitle: '', - kicker: displayKicker(safeItem.kicker || role), - claim: safeItem.claim || safeItem.title || '', - proofObject: safeItem.proofObject || proofForRole(role, sourceCount), - supportNote: safeItem.supportNote || supportForBlueprint(safeItem, state, fromAgentPayload), - sourceNote: safeItem.sourceNote || sourceNoteForBlueprint(state), - notes: safeItem.notes || t('defaultSpeakerNote', { title: safeItem.title || safeItem.claim || '' }), - layout: `${layout}-${deckDesign.styleKey}-${visualTreatment}`, - theme: themeFor(state, index, deckDesign, safeItem), - elements: elementsForBlueprint(safeItem, role, index, all.length, state, fromAgentPayload, deckDesign, visualTreatment), - }; - slide.quality = evaluateSlideQuality(slide, state, index); - const repairedSlide = repairSlideLayout(slide, state, index, role, all.length, deckDesign); - repairedSlide.quality = evaluateSlideQuality(repairedSlide, state, index); - return normalizeSlide(repairedSlide, index, state); - }); - return { - title: cleanTitle(blueprint.title || state.brief.topic || slides[0]?.title || state.title), - slides, - }; -} - -function clampSlideCount(value) { - return Math.max(1, Math.min(24, Number(value) || 1)); -} - -function resolveDeckDesign(blueprint, state) { - // Priority 1: explicit style preset from user selection - const presetKey = state.style?.stylePreset; - if (presetKey && STYLE_PRESETS[presetKey]) { - const preset = STYLE_PRESETS[presetKey]; - return { - styleKey: preset.styleKey, - palette: preset.palette || {}, - principles: ensureArray(blueprint.design?.layoutPrinciples).map(String), - }; - } - - // Priority 2: AI-detected style from blueprint - const raw = [ - blueprint.design?.stylePhilosophy, - blueprint.design?.style, - blueprint.stylePhilosophy, - blueprint.style, - state.style?.theme, - state.brief?.topic, - ].filter(Boolean).join(' ').toLowerCase(); - let styleKey = 'pentagram'; - if (/m[üu]ller|brockmann|grid|swiss|academic|技术|学术|严谨/.test(raw)) styleKey = 'muller'; - else if (/\bbuild\b|minimal|luxury|premium|高端|极简|品牌|宣言/.test(raw)) styleKey = 'build'; - else if (/kenya|hara|white|space|东方|留白|文化|艺术/.test(raw)) styleKey = 'hara'; - else if (/takram|soft|tech|research|柔和|科技人文|设计研究/.test(raw)) styleKey = 'takram'; - - const palette = blueprint.design?.palette || blueprint.palette || {}; - return { - styleKey, - palette, - principles: ensureArray(blueprint.design?.layoutPrinciples).map(String), - }; -} - -function normalizeBlueprintDataIntegrity(item, state) { - const next = { ...(item || {}) }; - if (Array.isArray(next.chartData) && !hasGroundedChartData(next, state)) { - delete next.chartData; - if (next.layout === 'data' && !hasSourceNumbers(state)) next.layout = 'evidence'; - next.supportNote = next.supportNote || t('bpSupportMissing'); - next.sourceNote = next.sourceNote || sourceNoteForBlueprint(state); - next.dataIntegrityWarning = 'chart_data_removed_without_source_numbers'; - } - if (next.metric?.value && !hasMetricSource(next.metric.value, state, next)) { - next.metric = null; - next.dataIntegrityWarning = next.dataIntegrityWarning || 'metric_removed_without_source'; - } - return next; -} - -function hasGroundedChartData(item, state) { - const data = ensureArray(item.chartData); - if (data.length < 2) return false; - if (!hasSourceNumbers(state)) return false; - const sourceText = sourceEvidenceText(state, item); - return data.every((point) => sourceText.includes(String(point?.label || '').trim()) || sourceText.includes(String(point?.value ?? '').trim())); -} - -function hasMetricSource(value, state, item = {}) { - if (!/\d/.test(String(value || ''))) return true; - return sourceEvidenceText(state, item).includes(String(value).trim()); -} - -function sourceEvidenceText(state, item = {}) { - return [ - ...(state.sources?.facts || []), - ...(state.sources?.items || []).map((source) => source.text || source.title || ''), - ...(ensureArray(item.facts)), - item.supportNote || '', - ].join('\n'); -} - -function normalizeVisualTreatment(value, role, index, total) { - const raw = String(value || '').toLowerCase(); - if (/process|workflow|timeline|flow|步骤|流程/.test(raw) || role === 'workflow') return 'process'; - if (/compare|versus|matrix|before|after|对比|比较/.test(raw) || role === 'comparison') return 'comparison'; - if (/data|chart|metric|number|数据|指标/.test(raw) || role === 'data') return 'data'; - if (/quote|transition|statement|宣言|引用/.test(raw) || role === 'transition') return 'editorial'; - if (/white|space|quiet|留白/.test(raw)) return 'white-space'; - if (/soft|tech|system|柔和|科技/.test(raw)) return 'soft-tech'; - if (index === 0 || index === total - 1) return 'typographic'; - return ['grid', 'editorial', 'data', 'process', 'comparison'][index % 5]; -} - -function displayKicker(value) { - const raw = String(value || '').replace(/[-_]/g, ' ').trim(); - const normalized = raw.toLowerCase(); - if (getLocale().startsWith('zh')) { - const zh = { - cover: '开场', - content: '核心', - data: '数据', - transition: '转场', - closing: '落点', - hook: '开场', - context: '背景', - finding: '发现', - takeaway: '结论', - }; - return zh[normalized] || raw; - } - return raw.toUpperCase(); -} - -function evaluateSlideQuality(slide, state, index) { - const issues = []; - const elements = ensureArray(slide.elements); - elements.forEach((element) => { - if (Number(element.x) + Number(element.w) > 100 || Number(element.y) + Number(element.h) > 100) { - issues.push(qualityIssue('high', 'bounds', t('qualityOutOfBounds'))); - } - if ((element.type === 'text' || element.type === 'list') && estimateTextLoad(element) > estimateTextCapacity(element)) { - issues.push(qualityIssue('medium', 'text_density', t('qualityTextDense'))); - } - if (element.type === 'chart' && !hasGroundedChartElement(element, state, slide)) { - issues.push(qualityIssue('high', 'chart_source', t('qualityChartUngrounded'))); - } - }); - for (let a = 0; a < elements.length; a += 1) { - for (let b = a + 1; b < elements.length; b += 1) { - if (elementsOverlap(elements[a], elements[b])) { - issues.push(qualityIssue('medium', 'overlap', t('qualityOverlap'))); - a = elements.length; - break; - } - } - } - if (index > 0 && !cleanTitle(slide.claim || slide.title)) { - issues.push(qualityIssue('low', 'claim', t('qualityMissingClaim'))); - } - const penalty = issues.reduce((sum, issue) => sum + (issue.severity === 'high' ? 30 : issue.severity === 'medium' ? 15 : 6), 0); - return { score: Math.max(0, 100 - penalty), issues: issues.slice(0, 8) }; -} - -function qualityIssue(severity, type, message) { - return { id: uid('quality'), severity, type, message }; -} - -function repairSlideLayout(slide, state, index, role, total, deckDesign) { - const highRisk = ensureArray(slide.quality?.issues).some((issue) => issue.type === 'bounds' || issue.type === 'overlap' || issue.type === 'text_density'); - if (!highRisk) return slide; - const item = { - title: slide.title, - claim: slide.claim, - kicker: slide.kicker, - role, - layout: role === 'cover' ? 'cover' : role === 'closing' ? 'closing' : 'evidence', - proofObject: slide.proofObject, - supportNote: slide.supportNote, - sourceNote: slide.sourceNote, - facts: [slide.supportNote, slide.sourceNote].filter(Boolean), - bullets: compactElementLines(slide.elements), - }; - const repairedElements = benchmarkElements( - item, - role, - index, - total, - slide.title, - slide.claim || slide.title, - item.facts, - item.bullets, - index === 0 ? 'cover' : index === total - 1 ? 'closing' : 'cards', - deckDesign.styleKey, - ); - return { ...slide, elements: repairedElements.length ? repairedElements : slide.elements }; -} - -function compactElementLines(elements) { - return ensureArray(elements) - .flatMap((element) => element.type === 'list' ? ensureArray(element.items) : [element.text, element.label]) - .map((item) => cleanTitle(item)) - .filter(Boolean) - .slice(0, 4); -} - -function estimateTextLoad(element) { - return String(element.text || '').length + ensureArray(element.items).join('').length; -} - -function estimateTextCapacity(element) { - const fontSize = Number(element.style?.fontSize || 18); - return Math.max(24, (Number(element.w || 1) * Number(element.h || 1) * 2.4) / Math.max(0.7, fontSize / 18)); -} - -function elementsOverlap(a, b) { - if (a.type === 'shape' || b.type === 'shape') return false; - const ax2 = Number(a.x) + Number(a.w); - const ay2 = Number(a.y) + Number(a.h); - const bx2 = Number(b.x) + Number(b.w); - const by2 = Number(b.y) + Number(b.h); - const overlapX = Math.max(0, Math.min(ax2, bx2) - Math.max(Number(a.x), Number(b.x))); - const overlapY = Math.max(0, Math.min(ay2, by2) - Math.max(Number(a.y), Number(b.y))); - return overlapX > 2 && overlapY > 2; -} - -function hasGroundedChartElement(element, state, slide) { - if (!ensureArray(element.data).length) return false; - return hasGroundedChartData({ chartData: element.data, facts: [slide.supportNote, slide.sourceNote] }, state); -} - -function normalizeAgentPlan(value, state) { - const allowed = new Set(['generate_deck', 'revise_deck', 'revise_slide', 'insert_slide', 'delete_slide', 'update_outline']); - const operation = allowed.has(value?.operation) ? value.operation : (state.slides?.length ? 'revise_deck' : 'generate_deck'); - const slideCount = state.slides?.length || 0; - const slideIndex = value?.slideIndex === null || value?.slideIndex === undefined - ? null - : Math.max(0, Math.min(slideCount - 1, Number(value.slideIndex) || 0)); - const scope = ['deck', 'current_slide', 'slide_index'].includes(value?.scope) ? value.scope : (operation === 'revise_slide' ? 'current_slide' : 'deck'); - return { - operation, - scope, - slideIndex, - briefPatch: normalizeBriefPatch(value?.briefPatch), - needsSources: Boolean(value?.needsSources), - reason: String(value?.reason || ''), - steps: Array.isArray(value?.steps) ? value.steps.slice(0, 8).map(normalizePlanStep) : [], - acceptanceCriteria: Array.isArray(value?.acceptanceCriteria) ? value.acceptanceCriteria.map(String).slice(0, 6) : [], - }; -} - -function normalizePlanStep(step) { - return { - agent: String(step?.agent || step?.stage || 'brief'), - task: String(step?.task || ''), - deliverable: String(step?.deliverable || ''), - }; -} - -function normalizeBriefPatch(value = {}) { - const patch = {}; - const topic = cleanPatchText(value.topic); - const audience = cleanPatchText(value.audience); - const intent = cleanPatchText(value.intent); - const tone = cleanPatchText(value.tone); - if (topic) patch.topic = topic; - if (audience) patch.audience = audience; - if (intent) patch.deckType = intent; - if (tone) patch.tone = tone; - const slideTarget = Number(value.slideTarget); - if (Number.isFinite(slideTarget) && slideTarget > 0) patch.slideTarget = Math.max(3, Math.min(24, slideTarget)); - return patch; -} - -function cleanPatchText(value) { - const text = typeof value === 'string' ? value.trim() : ''; - if (!text || /^optional\b/i.test(text)) return ''; - return text; -} - -function localBlueprint(state, outline) { - const topic = displayTopic(state.brief.topic || outline[0] || t('defaultDeckTitle')); - const facts = state.sources?.facts?.length ? state.sources.facts : sourceFallbackFacts(state); - const hasSource = hasGroundedSource(state); - const roles = ['cover', 'content', 'content', 'content', 'content', 'data', 'transition', 'closing']; - const titles = [ - topic, - hasSource ? `${topic} 的源材料提供了第一组线索` : `${topic} 需要先补充可验证材料`, - facts[0] || `${topic} 的定义和边界需要讲清楚`, - facts[1] || `${topic} 的结构可以拆成几个关键模块`, - facts[2] || `${topic} 的使用流程决定理解速度`, - facts[3] || `${topic} 需要用例来证明价值`, - facts[4] || `${topic} 需要把已知事实和未知问题分开呈现`, - `${topic} 的结尾要留下一个清晰记忆点`, - ]; - const slideCount = state.brief.slideTarget > 0 ? state.brief.slideTarget : roles.length; - return { - title: topic, - slides: roles.slice(0, slideCount).map((role, index) => ({ - role, - title: titles[index] || outline[index] || t('newSlideTitle'), - kicker: role, - claim: titles[index] || outline[index] || '', - proofObject: proofForRole(role, hasSource ? 1 : 0), - supportNote: hasSource ? t('bpSupportSource') : t('bpSupportMissing'), - sourceNote: sourceNoteForBlueprint(state), - facts: rotateFacts(facts, index, 3), - bullets: rotateFacts(facts, index + 1, 3), - notes: t('defaultSpeakerNote', { title: titles[index] || topic }), - layout: layoutForRole(role, index, roles.length), - })), - }; -} - -export function localSlideUpdate(state, action, instruction) { - const slide = clone(state.slides.find((item) => item.id === state.activeSlideId) || state.slides[0]); - if (!slide) return null; - const titleElement = slide.elements.find((element) => element.type === 'text'); - const listElement = slide.elements.find((element) => element.type === 'list'); - if (action === 'condense' && listElement) { - listElement.items = listElement.items.slice(0, 2).map((item) => item.replace(/\s+and\s+/i, ' / ')); - } else if (action === 'professional' && titleElement) { - titleElement.text = titleElement.text.replace(/\bmake\b/gi, 'deliver').replace(/\buse\b/gi, 'apply'); - } else if (action === 'notes') { - slide.notes = `Takeaway: ${slide.claim || slide.title}\nProof: Walk through the ${slide.proofObject || 'dominant proof object'} and call out the strongest evidence.\nDecision: Close by naming the owner, timing, or next action. ${instruction || ''}`.trim(); - } else if (action === 'visual' || action === 'redesign') { - const index = state.slides.findIndex((item) => item.id === slide.id); - const replacement = makeSlide(slide.title, index + 1, state.slides.length + 1, state); - replacement.id = slide.id; - replacement.notes = slide.notes; - return replacement; - } else if (titleElement) { - titleElement.text = instruction || titleElement.text; - } - return normalizeSlide(slide, state.slides.findIndex((item) => item.id === slide.id), state); -} - -export function localDeckUpdate(state, instruction) { - const next = clone(state); - const suffix = instruction ? ` ${instruction}` : ''; - next.slides = next.slides.map((slide, index) => normalizeSlide({ - ...slide, - supportNote: `${slide.supportNote || ''}${suffix}`.trim(), - notes: `${slide.notes || ''}\nRevision request: ${instruction || 'Improve clarity and flow.'}`.trim(), - }, index, next)); - next.outline = next.slides.map((slide) => slide.title); - return { title: next.title, slides: next.slides }; -} - -export function localInsertedSlide(state, instruction) { - const index = Math.min(state.slides.length, Math.max(0, state.slides.findIndex((slide) => slide.id === state.activeSlideId) + 1)); - const title = instruction || t('newSlideTitle'); - return makeSlide(title, index, state.slides.length + 1, state); -} - -function agentSlideLines(item) { - const facts = ensureArray(item.facts).map((line) => String(line).trim()).filter(Boolean); - const bullets = ensureArray(item.bullets).map((line) => String(line).trim()).filter(Boolean); - return { facts, bullets }; -} - -function resolveSlideLines(item, state, fromAgentPayload) { - const { facts: agentFacts, bullets: agentBullets } = agentSlideLines(item); - const claim = cleanTitle(item.claim || item.title || ''); - const support = cleanTitle(item.supportNote || ''); - if (fromAgentPayload) { - const facts = agentFacts.length ? agentFacts : agentBullets; - const bullets = agentBullets.length ? agentBullets : facts; - if (bullets.length || facts.length) { - return { facts, bullets }; - } - if (claim || support) { - const line = claim || support; - return { facts: [line], bullets: [line] }; - } - return { facts: [], bullets: [] }; - } - const trusted = hasGroundedSource(state); - const facts = trusted ? ensureBullets(item.facts?.length ? item.facts : item.bullets, state) : sourceFallbackFacts(state); - const bullets = trusted ? ensureBullets(item.bullets?.length ? item.bullets : facts, state) : sourceFallbackFacts(state); - return { facts, bullets }; -} - -function elementsForBlueprint(item, role, index, total, state, fromAgentPayload = false, deckDesign = resolveDeckDesign({}, state), visualTreatment = 'grid') { - const explicit = normalizeExplicitElements(item, deckDesign); - if (explicit.length) return explicit; - - const title = cleanTitle(item.title || item.claim || state.outline[index] || t('newSlideTitle')); - const claim = cleanTitle(item.claim || title); - const { facts, bullets } = resolveSlideLines(item, state, fromAgentPayload); - const styleKey = deckDesign.styleKey; - const pattern = smartLayoutPattern(item, role, index, total, facts, bullets, visualTreatment); - const benchmarkElements = benchmarkElements(item, role, index, total, title, claim, facts, bullets, pattern, styleKey); - if (benchmarkElements.length) return benchmarkElements; - - if (styleKey === 'build') return buildElements(item, role, index, total, title, claim, facts, bullets, visualTreatment); - if (styleKey === 'hara') return haraElements(item, role, index, total, title, claim, facts, bullets, visualTreatment); - if (styleKey === 'muller') return mullerElements(item, role, index, total, title, claim, facts, bullets, visualTreatment); - if (styleKey === 'takram') return takramElements(item, role, index, total, title, claim, facts, bullets, visualTreatment); - return pentagramElements(item, role, index, total, title, claim, facts, bullets, visualTreatment); -} - -function smartLayoutPattern(item, role, index, total, facts, bullets, visualTreatment) { - const raw = [role, item.layout, item.visualTreatment, item.visual, item.designIntent, item.proofObject, visualTreatment].filter(Boolean).join(' ').toLowerCase(); - if (role === 'cover' || index === 0) return 'cover'; - if (role === 'closing' || role === 'takeaway' || role === 'decision' || index === total - 1) return 'closing'; - if (/quote|transition|statement|宣言|引用/.test(raw)) return 'quote'; - if (/process|workflow|timeline|roadmap|journey|steps|architecture|flow|流程|步骤|路线|架构/.test(raw)) return 'process'; - if (/compare|versus|matrix|before|after|tradeoff|对比|比较|矩阵/.test(raw)) return 'comparison'; - if (/data|chart|metric|number|kpi|scorecard|数据|指标/.test(raw) || ensureArray(item.chartData).length >= 2 || facts.some((fact) => /\d/.test(String(fact)))) return 'data'; - if (ensureArray(bullets).length >= 3) return 'cards'; - return index % 3 === 1 ? 'split' : 'spotlight'; -} - -function benchmarkElements(item, role, index, total, title, claim, facts, bullets, pattern, styleKey) { - const titleSize = displayTitleSize(title, pattern, styleKey); - const body = compactLines(bullets, pattern === 'process' || pattern === 'comparison' ? 4 : 3); - const proof = facts[0] || item.supportNote || body[0] || claim; - if (pattern === 'cover') { - return [ - shape(6, 9, 88, 76, 'soft', 1, styleKey === 'muller' ? 0 : 28), - shape(9, 15, 1.2, 55, 'primary', 1, 99), - text(displayKicker(item.kicker || 'deck'), 13, 15, 22, 5, 10, 760, 'primary'), - text(title, 13, 23, 58, 25, titleSize, 840, 'ink'), - text(claim, 14, 55, 45, 11, 18, 520, 'muted'), - metric(String(total), t('slidesUnit'), 75, 54, 14, 17, 34), - ]; - } - if (pattern === 'closing') { - return [ - text(title, 9, 15, 65, 15, titleSize, 820, 'ink'), - text(claim, 10, 33, 46, 9, 17, 540, 'muted'), - ...cardGrid([t('closeConfirm'), t('closeOwner'), t('closeIteration')], 10, 50, 52, 22, 3, 18), - text(proof, 67, 48, 22, 20, 18, 720, 'primary', 'soft', 20), - ]; - } - if (pattern === 'quote') { - return [ - shape(11, 16, 10, 0.6, 'primary', 1, 99), - text(title, 13, 22, 64, 23, titleSize, 780, 'ink'), - text(body[0] || claim, 16, 53, 48, 11, 18, 520, 'muted'), - text(item.sourceNote || '', 70, 72, 18, 5, 10, 500, 'muted'), - ]; - } - if (pattern === 'process') { - return [ - text(title, 8, 10, 68, 12, titleSize, 820, 'ink'), - text(claim, 9, 25, 54, 7, 15, 520, 'muted'), - shape(10, 50, 78, 1.2, 'primary', 0.25, 99), - ...cardGrid(body.slice(0, 4), 10, 39, 78, 25, Math.min(4, body.length || 1), 16).map((element, pointIndex) => ({ ...element, text: `0${pointIndex + 1} ${element.text}` })), - ]; - } - if (pattern === 'comparison') { - const columns = body.length >= 4 ? body.slice(0, 4) : [body[0] || claim, body[1] || proof, body[2] || item.supportNote || '', body[3] || item.sourceNote || '']; - return [ - text(title, 7, 10, 72, 12, titleSize, 820, 'ink'), - text(claim, 8, 25, 48, 7, 15, 520, 'muted'), - ...cardGrid(columns, 8, 39, 82, 28, 2, 18), - ]; - } - if (pattern === 'data') { - const safeChartData = ensureArray(item.chartData).length >= 2 ? item.chartData : factsToChartData(facts); - const hasChart = safeChartData.length >= 2; - return [ - text(title, 8, 10, 66, 12, titleSize, 820, 'ink'), - text(claim, 9, 25, 47, 7, 15, 520, 'muted'), - hasChart - ? chart(item.proofObject || t('proofTrendChart'), safeChartData, 9, 39, 55, 31) - : metric(item.metric?.value || facts.find((fact) => /\d/.test(fact)) || String(index).padStart(2, '0'), item.metric?.label || item.proofObject || claim, 10, 40, 34, 28, 44), - text(proof, 69, 41, 20, 24, 17, 700, 'primary', 'soft', 18), - ]; - } - if (pattern === 'cards') { - const cards = body.length ? body : [claim]; - return [ - text(title, 8, 10, 68, 12, titleSize, 820, 'ink'), - text(claim, 9, 25, 51, 8, 15, 520, 'muted'), - ...cardGrid(cards, 9, 42, 78, 25, Math.min(3, cards.length), 17), - ]; - } - if (pattern === 'spotlight') { - return [ - text(title, 10, 15, 62, 15, titleSize, 820, 'ink'), - text(claim, 11, 34, 42, 10, 17, 520, 'muted'), - text(proof, 58, 38, 28, 24, 22, 760, 'primary', 'soft', 22), - shape(10, 72, 18, 0.6, 'primary', 1, 99), - ]; - } - return [ - text(title, 8, 10, 62, 12, titleSize, 820, 'ink'), - text(claim, 9, 26, 40, 9, 16, 520, 'muted'), - list(body, 9, 44, 36, 25, 17), - text(proof, 55, 39, 33, 27, 19, 720, 'primary', 'soft', 18), - ]; -} - -function cardGrid(items, x, y, w, h, columns, fontSize) { - const safeItems = ensureArray(items).filter(Boolean); - const safeColumns = Math.max(1, Math.min(columns || 1, safeItems.length || 1)); - const gap = 2.5; - const rows = Math.max(1, Math.ceil((safeItems.length || 1) / safeColumns)); - const cardW = (w - gap * (safeColumns - 1)) / safeColumns; - const cardH = (h - gap * (rows - 1)) / rows; - return safeItems.map((item, itemIndex) => text(item, x + (itemIndex % safeColumns) * (cardW + gap), y + Math.floor(itemIndex / safeColumns) * (cardH + gap), cardW, cardH, fontSize, itemIndex === 0 ? 760 : 620, itemIndex === 0 ? 'primary' : 'ink', itemIndex === 0 ? 'soft' : 'panel', 18)); -} - -function compactLines(items, maxCount) { - return ensureArray(items) - .map((item) => cleanTitle(item)) - .filter(Boolean) - .slice(0, maxCount); -} - -function displayTitleSize(title, pattern, styleKey) { - const length = String(title || '').length; - const base = pattern === 'cover' ? 44 : pattern === 'quote' || pattern === 'spotlight' ? 38 : 32; - const styleOffset = styleKey === 'build' ? 4 : styleKey === 'hara' ? -2 : 0; - if (length > 68) return Math.max(24, base - 10 + styleOffset); - if (length > 48) return Math.max(26, base - 6 + styleOffset); - return base + styleOffset; -} - -function pentagramElements(item, role, index, total, title, claim, facts, bullets, visualTreatment) { - if (role === 'cover' || index === 0) { - const coverTitleSize = title.length > 58 ? 25 : title.length > 42 ? 29 : 40; - return [ - shape(7, 15, 4, 56, 'primary', 1, 99), - text(title, 14, 18, 62, 28, coverTitleSize, 840, 'ink'), - text(claim, 15, 50, 56, 12, 18, 540, 'muted'), - metric(String(total), t('slidesUnit'), 75, 53, 15, 18), - ]; - } - if (visualTreatment === 'process' || role === 'workflow' || item.layout === 'process') { - return [ - text(title, 8, 13, 68, 13, 31, 810, 'ink'), - text(claim, 9, 29, 54, 9, 15, 540, 'muted'), - shape(10, 51, 78, 2, 'primary', 0.18, 99), - ...bullets.slice(0, 3).map((point, pointIndex) => metric(`0${pointIndex + 1}`, point, 10 + pointIndex * 27, 39, 22, 27, 28)), - ]; - } - if (visualTreatment === 'data' && Array.isArray(item.chartData) && item.chartData.length >= 2) { - return [ - text(title, 8, 12, 68, 13, 31, 810, 'ink'), - chart(item.proofObject || t('proofTrendChart'), item.chartData, 10, 34, 54, 36), - text(item.supportNote || bullets[0], 69, 38, 20, 25, 17, 700, 'primary', 'soft', 14), - ]; - } - if (visualTreatment === 'comparison') { - return [ - text(title, 7, 11, 70, 12, 30, 820, 'ink'), - text(bullets[0] || claim, 9, 35, 35, 28, 22, 760, 'ink', 'panel', 8), - text(bullets[1] || facts[0] || item.supportNote || '', 52, 35, 35, 28, 22, 760, 'primary', 'soft', 8), - shape(48, 30, 1, 44, 'primary', 1, 99), - ]; - } - if (role === 'risk' || item.layout === 'risk') { - return [ - text(title, 8, 12, 68, 13, 31, 810, 'ink'), - list(bullets.slice(0, 4), 9, 34, 47, 38, 19, 'panel'), - text(item.supportNote || t('bpSupportMissing'), 61, 36, 28, 30, 17, 650, 'muted', 'soft', 14), - ]; - } - if (role === 'decision' || index === total - 1) { - return [ - text(title, 9, 15, 70, 15, 38, 820, 'ink'), - list([t('closeConfirm'), t('closeOwner'), t('closeIteration')], 12, 42, 45, 32, 22), - text(bullets[0] || item.supportNote || '', 63, 42, 27, 24, 18, 720, 'primary', 'soft', 16), - ]; - } - return [ - text(title, 8, 12, 68, 13, 31, 810, 'ink'), - text(claim, 9, 29, 52, 9, 15, 540, 'muted'), - list(bullets.slice(0, 3), 9, 42, 39, 31, 18), - text(facts[0] || item.supportNote || '', 55, 38, 34, 29, 18, 700, 'primary', 'soft', 14), - ]; -} - -function mullerElements(item, role, index, total, title, claim, facts, bullets, visualTreatment) { - if (index === 0) { - return [ - text(String(total).padStart(2, '0'), 8, 10, 10, 10, 34, 820, 'primary'), - shape(8, 23, 82, 1, 'ink', 1, 0), - text(title, 8, 31, 72, 20, title.length > 48 ? 30 : 40, 760, 'ink'), - text(claim, 8, 59, 50, 10, 17, 500, 'muted'), - text(item.sourceNote || '', 67, 76, 22, 6, 11, 500, 'muted'), - ]; - } - if (visualTreatment === 'process') { - return [ - text(`0${index}`, 8, 10, 8, 8, 24, 780, 'primary'), - text(title, 20, 10, 62, 12, 28, 760, 'ink'), - shape(8, 27, 82, 1, 'ink', 1, 0), - ...bullets.slice(0, 4).map((point, pointIndex) => text(point, 10 + pointIndex * 21, 44, 17, 18, 17, 620, pointIndex === 0 ? 'primary' : 'ink')), - ]; - } - if (visualTreatment === 'data') { - const safeChartData = item.chartData?.length ? item.chartData : factsToChartData(facts); - return [ - text(`0${index}`, 8, 10, 8, 8, 24, 780, 'primary'), - text(title, 20, 10, 62, 12, 28, 760, 'ink'), - safeChartData.length >= 2 - ? chart(item.proofObject || t('proofTrendChart'), safeChartData, 15, 35, 62, 34) - : text(item.supportNote || facts[0] || bullets[0] || claim, 20, 38, 58, 24, 21, 650, 'primary', 'soft', 8), - ]; - } - return [ - text(`0${index}`, 8, 10, 8, 8, 24, 780, 'primary'), - text(title, 20, 10, 62, 12, 28, 760, 'ink'), - shape(8, 27, 82, 1, 'ink', 1, 0), - text(claim, 20, 36, 36, 18, 21, 650, 'ink'), - list(bullets.slice(0, 3), 61, 36, 25, 30, 15, 'transparent'), - ]; -} - -function buildElements(item, role, index, total, title, claim, facts, bullets, visualTreatment) { - if (index === 0) { - return [ - text(title, 9, 20, 72, 28, title.length > 46 ? 34 : 48, 500, 'ink'), - text(claim, 10, 62, 42, 10, 17, 420, 'muted'), - text(String(total), 83, 74, 8, 8, 20, 500, 'primary'), - ]; - } - if (visualTreatment === 'data') { - return [ - text(title, 9, 13, 72, 14, 32, 500, 'ink'), - metric(item.metric?.value || facts.find((fact) => /\d/.test(fact)) || `${index}`, item.metric?.label || item.proofObject || claim, 10, 42, 34, 26, 50), - text(bullets[0] || item.supportNote || '', 52, 47, 33, 14, 18, 420, 'muted'), - ]; - } - if (visualTreatment === 'white-space' || visualTreatment === 'editorial') { - return [ - text(title, 13, 24, 62, 24, title.length > 50 ? 30 : 42, 500, 'ink'), - text(bullets[0] || claim, 14, 58, 36, 12, 18, 420, 'muted'), - ]; - } - return [ - text(title, 9, 14, 68, 16, 34, 500, 'ink'), - text(claim, 10, 39, 48, 12, 19, 420, 'muted'), - list(bullets.slice(0, 2), 10, 60, 48, 18, 17, 'transparent'), - shape(76, 14, 1, 64, 'primary', 1, 0), - ]; -} - -function haraElements(item, role, index, total, title, claim, facts, bullets, visualTreatment) { - if (index === 0) { - return [ - text(title, 16, 28, 60, 20, title.length > 50 ? 28 : 38, 430, 'ink'), - text(claim, 17, 57, 34, 10, 15, 360, 'muted'), - shape(16, 78, 12, 0.4, 'primary', 1, 0), - ]; - } - return [ - text(title, 16, 18, 56, 16, 30, 420, 'ink'), - text(bullets[0] || claim, 18, 45, 38, 12, 17, 360, 'muted'), - text(bullets[1] || facts[0] || item.supportNote || '', 62, 64, 22, 10, 13, 340, 'muted'), - shape(16, 77, 10, 0.4, 'primary', 1, 0), - ]; -} - -function takramElements(item, role, index, total, title, claim, facts, bullets, visualTreatment) { - if (index === 0) { - return [ - shape(62, 12, 26, 55, 'soft', 1, 28), - text(title, 9, 17, 56, 22, title.length > 50 ? 30 : 40, 760, 'ink'), - text(claim, 10, 48, 42, 12, 17, 500, 'muted'), - metric(String(total), t('slidesUnit'), 68, 45, 16, 17, 36), - ]; - } - if (visualTreatment === 'process') { - return [ - text(title, 8, 12, 62, 12, 30, 740, 'ink'), - shape(10, 36, 78, 30, 'soft', 1, 24), - ...bullets.slice(0, 3).map((point, pointIndex) => metric(`0${pointIndex + 1}`, point, 14 + pointIndex * 24, 41, 18, 18, 24)), - ]; - } - if (visualTreatment === 'data') { - const safeChartData = item.chartData?.length ? item.chartData : factsToChartData(facts); - return [ - text(title, 8, 12, 62, 12, 30, 740, 'ink'), - safeChartData.length >= 2 - ? chart(item.proofObject || t('proofTrendChart'), safeChartData, 10, 34, 50, 34) - : text(item.supportNote || facts[0] || bullets[0] || claim, 10, 38, 48, 24, 20, 650, 'primary', 'soft', 18), - text(bullets[0] || claim, 65, 39, 22, 20, 17, 600, 'primary', 'soft', 18), - ]; - } - return [ - text(title, 8, 12, 64, 12, 30, 740, 'ink'), - text(claim, 9, 30, 44, 10, 16, 520, 'muted'), - list(bullets.slice(0, 3), 10, 49, 42, 24, 17, 'transparent'), - text(facts[0] || item.supportNote || '', 60, 40, 28, 24, 17, 620, 'primary', 'soft', 18), - ]; -} - -function normalizeExplicitElements(item, deckDesign) { - const elements = Array.isArray(item.elements) ? item.elements : []; - return elements - .filter((element) => element && typeof element === 'object') - .slice(0, 12) - .map((element) => ({ - type: ['text', 'list', 'shape', 'metric', 'chart', 'media'].includes(element.type) ? element.type : 'text', - text: String(element.text || ''), - label: String(element.label || ''), - items: ensureArray(element.items).map(String), - data: ensureArray(element.data).map((point, pointIndex) => ({ - label: String(point?.label || `#${pointIndex + 1}`), - value: Number(point?.value || 0), - })), - x: Number.isFinite(Number(element.x)) ? Number(element.x) : 8, - y: Number.isFinite(Number(element.y)) ? Number(element.y) : 12, - w: Number.isFinite(Number(element.w)) ? Number(element.w) : 60, - h: Number.isFinite(Number(element.h)) ? Number(element.h) : 12, - style: { - fontSize: Number(element.style?.fontSize || element.fontSize || 24), - fontWeight: Number(element.style?.fontWeight || element.fontWeight || 600), - color: semanticColor(element.style?.color || element.color || 'ink'), - background: semanticColor(element.style?.background || element.background || 'transparent'), - borderRadius: Number(element.style?.borderRadius || element.borderRadius || 0), - opacity: Number(element.style?.opacity ?? element.opacity ?? 1), - align: element.style?.align || element.align || 'left', - }, - })); -} - -function semanticColor(value) { - const raw = String(value || '').trim(); - if (!raw) return 'transparent'; - return raw; -} - -function factsToChartData(facts) { - const source = ensureArray(facts).filter((fact) => /\d/.test(String(fact))).slice(0, 4); - return source.map((fact, index) => ({ label: fact.slice(0, 12), value: extractFirstNumber(fact) ?? 35 + index * 15 })); -} - -function extractFirstNumber(value) { - const match = String(value || '').match(/-?\d+(?:\.\d+)?/); - if (!match) return null; - const number = Number(match[0]); - return Number.isFinite(number) ? number : null; -} - -function text(value, x, y, w, h, fontSize, fontWeight, color, background = 'transparent', borderRadius = 0) { - return { - type: 'text', - text: String(value || ''), - label: '', - items: [], - data: [], - x, - y, - w, - h, - style: { fontSize, fontWeight, color, background, borderRadius, opacity: 1, align: 'left' }, - }; -} - -function list(items, x, y, w, h, fontSize = 19, background = 'transparent') { - return { - type: 'list', - text: '', - label: '', - items: ensureArray(items).slice(0, 5), - data: [], - x, - y, - w, - h, - style: { fontSize, fontWeight: 560, color: 'ink', background, borderRadius: background === 'panel' ? 14 : 0, opacity: 1, align: 'left' }, - }; -} - -function metric(value, label, x, y, w, h, fontSize = 40) { - return { - type: 'metric', - text: String(value || ''), - label: String(label || ''), - items: [], - data: [], - x, - y, - w, - h, - style: { fontSize, fontWeight: 820, color: 'primary', background: 'panel', borderRadius: 14, opacity: 1, align: 'left' }, - }; -} - -function chart(title, data, x, y, w, h) { - return { - type: 'chart', - text: String(title || t('proofTrendChart')), - label: '', - items: [], - data: ensureArray(data).map((point, index) => ({ - label: String(point.label || `#${index + 1}`), - value: Number(point.value || 0), - })), - x, - y, - w, - h, - style: { fontSize: 18, fontWeight: 700, color: 'ink', background: 'panel', borderRadius: 14, opacity: 1, align: 'left' }, - }; -} - -function shape(x, y, w, h, background, opacity, borderRadius) { - return { - type: 'shape', - text: '', - label: '', - items: [], - data: [], - x, - y, - w, - h, - style: { fontSize: 18, fontWeight: 600, color: 'accent', background, borderRadius, opacity, align: 'center' }, - }; -} - -function themeFor(state, index, deckDesign = resolveDeckDesign({}, state), item = {}) { - const preset = DESIGN_THEMES[deckDesign.styleKey] || DESIGN_THEMES.pentagram; - const palette = { ...preset, ...(deckDesign.palette || {}), ...(item.palette || {}) }; - const primary = palette.primary || state.style?.brandPrimary || '#111111'; - const accent = palette.accent || state.style?.brandAccent || '#c84b31'; - return { - background: palette.background, - ink: palette.ink, - muted: palette.muted, - primary: index % 2 ? accent : primary, - accent: index % 2 ? primary : accent, - panel: palette.panel, - }; -} - -const DESIGN_THEMES = { - pentagram: { - background: '#fafaf7', - ink: '#1a1a1a', - muted: '#5f5f5a', - primary: '#111111', - accent: '#c84b31', - panel: '#ffffff', - }, - muller: { - background: '#f5f5f2', - ink: '#111111', - muted: '#616161', - primary: '#e11d2e', - accent: '#111111', - panel: '#ffffff', - }, - build: { - background: '#f8f6f1', - ink: '#15120d', - muted: '#746d62', - primary: '#8b6f47', - accent: '#1f1a14', - panel: '#fffdf8', - }, - hara: { - background: '#f7f5f0', - ink: '#26231f', - muted: '#8b867e', - primary: '#b8a46f', - accent: '#4b4640', - panel: '#fbfaf6', - }, - takram: { - background: '#f6f4ee', - ink: '#18202a', - muted: '#68717d', - primary: '#2f7f73', - accent: '#d88c51', - panel: '#fffdfa', - }, - // === PPT Live Style Presets (kept in sync with style-presets.js) === - 'clean-business': { - background: '#ffffff', - ink: '#1a1a1a', - muted: '#6b7280', - primary: '#2563eb', - accent: '#3b82f6', - panel: '#f8fafc', - }, - 'insight-report': { - background: '#ffffff', - ink: '#1f2937', - muted: '#64748b', - primary: '#1e3a8a', - accent: '#dc2626', - panel: '#f1f5f9', - }, - 'minimal-gallery': { - background: '#fafafa', - ink: '#171717', - muted: '#737373', - primary: '#171717', - accent: '#525252', - panel: '#ffffff', - }, - 'bold-editorial': { - background: '#ffffff', - ink: '#000000', - muted: '#525252', - primary: '#dc2626', - accent: '#ef4444', - panel: '#fafafa', - }, - 'yellow-magazine': { - background: '#facc15', - ink: '#171717', - muted: '#525252', - primary: '#171717', - accent: '#ffffff', - panel: '#fef08a', - }, - 'pink-pop': { - background: '#fce7f3', - ink: '#831843', - muted: '#be185d', - primary: '#db2777', - accent: '#f472b6', - panel: '#fdf2f8', - }, - 'creative-studio': { - background: '#ffffff', - ink: '#171717', - muted: '#525252', - primary: '#ea580c', - accent: '#c2410c', - panel: '#fafafa', - }, - 'retro-pop': { - background: '#fef3c7', - ink: '#451a03', - muted: '#92400e', - primary: '#dc2626', - accent: '#f59e0b', - panel: '#fffbeb', - }, - 'dark-neon': { - background: '#0a0a0a', - ink: '#e5e5e5', - muted: '#737373', - primary: '#22d3ee', - accent: '#f472b6', - panel: '#171717', - }, - 'pop-infographic': { - background: '#ffffff', - ink: '#171717', - muted: '#525252', - primary: '#ec4899', - accent: '#06b6d4', - panel: '#f0fdfa', - }, -}; - -function layoutForRole(role, index, total) { - if (role === 'cover' || index === 0) return 'cover'; - if (role === 'closing' || role === 'takeaway' || index === total - 1) return 'closing'; - if (role === 'transition') return 'quote'; - if (role === 'workflow' || role === 'architecture') return 'process'; - if (role === 'comparison' || role === 'data') return 'comparison'; - if (role === 'content' || role === 'example' || role === 'finding' || role === 'context' || role === 'hook') return 'split'; - return index % 2 ? 'metric' : 'split'; -} - -function proofForRole(role, sourceCount) { - const withSource = sourceCount > 0; - const map = { - cover: withSource ? t('proofSourceSummary') : t('proofVerificationPlan'), - content: withSource ? t('proofEvidenceList') : t('proofVerificationPlan'), - data: t('proofMetricBridge'), - transition: t('proofVisualProof'), - closing: t('proofDecisionTable'), - hook: withSource ? t('proofSourceSummary') : t('proofVerificationPlan'), - context: withSource ? t('proofSourceSummary') : t('proofVerificationPlan'), - finding: withSource ? t('proofEvidenceList') : t('proofVerificationPlan'), - architecture: t('proofProductDiagram'), - example: t('proofWorkedExample'), - comparison: t('proofComparison'), - data: t('proofMetricBridge'), - takeaway: t('proofDecisionTable'), - problem: t('proofComparison'), - solution: t('proofCapabilityMatrix'), - workflow: t('proofOperatingModel'), - proof: withSource ? t('proofEvidenceList') : t('proofVerificationPlan'), - risk: t('proofRiskRegister'), - decision: t('proofDecisionTable'), - }; - return map[role] || t('proofVisualProof'); -} - -function roleForIndex(index, total) { - if (index === 0) return 'cover'; - if (index === total - 1) return 'closing'; - return ['content', 'content', 'data', 'transition'][Math.max(0, index - 1) % 4]; -} - -function supportForBlueprint(item, state, fromAgentPayload = false) { - const support = cleanTitle(item.supportNote || ''); - if (fromAgentPayload) { - const { bullets, facts } = agentSlideLines(item); - return support || bullets[0] || facts[0] || cleanTitle(item.claim || item.title || ''); - } - if (!hasGroundedSource(state)) return t('bpSupportMissing'); - if (item.facts?.length) return item.facts[0]; - return state.sources?.items?.length ? t('bpSupportSource') : t('bpSupportMissing'); -} - -function sourceNoteForBlueprint(state) { - const urls = state.sources?.items?.filter((item) => item.url).map((item) => item.url); - if (urls?.length) return t('sourceFetchedNote', { count: urls.length }); - if (hasGroundedSource(state)) return t('sourceUserMaterial'); - return t('sourceDraftAssumption'); -} - -function hasGroundedSource(state) { - return Boolean(state.sources?.facts?.length || state.sources?.items?.some((item) => String(item.text || '').length >= 120)); -} - -function hasSourceNumbers(state) { - return Boolean(state.sources?.facts?.some((fact) => /\d/.test(String(fact)))); -} - -function sourceFallbackFacts(state) { - return state.sources?.warnings?.length - ? state.sources.warnings - : [t('bpMissingFact1'), t('bpMissingFact2'), t('bpMissingFact3')]; -} - -function rotateFacts(facts, offset, count) { - const source = ensureArray(facts).filter(Boolean); - if (!source.length) return []; - return Array.from({ length: Math.min(count, source.length) }, (_, index) => source[(offset + index) % source.length]); -} - -function ensureBullets(items, state) { - const source = ensureArray(items).map((item) => String(item).trim()).filter(Boolean); - if (source.length) return source; - return sourceFallbackFacts(state); -} - -function ensureArray(value) { - return Array.isArray(value) ? value : []; -} - -function cleanTitle(value) { - return String(value || '').replace(/\s+/g, ' ').trim().slice(0, 120); -} - -function displayTopic(value) { - const raw = cleanTitle(value); - const withoutUrls = stripUrls(raw).trim() || raw; - const normalized = withoutUrls - .replace(/^create\s+(an?|the)?\s*\d+\s*[- ]?\s*(page|slide)\s+/i, '') - .replace(/^create\s+(an?|the)?\s+/i, '') - .replace(/^make\s+(an?|the)?\s+/i, '') - .replace(/^build\s+(an?|the)?\s+/i, '') - .replace(/^add\s+(an?|the)?\s*(page|slide)\s+(about|on|for)?\s*/i, '') - .trim(); - const firstSentence = normalized.split(/[.!?。!?]/)[0]?.trim() || normalized; - const concise = firstSentence.length > 72 ? firstSentence.slice(0, 69).trimEnd() + '...' : firstSentence; - const urls = extractUrls(raw); - if (!urls.length) return concise || raw; - try { - const parsed = new URL(urls[0]); - if (parsed.hostname === 'github.com') { - const [, owner, repo] = parsed.pathname.split('/'); - if (owner && repo) return `${owner}/${repo}`; - } - return parsed.hostname.replace(/^www\./, ''); - } catch { - return concise || raw.replace(urls[0], '').trim() || urls[0]; - } -} - -function extractUrls(value) { - const matches = String(value || '').match(/https?:\/\/[^\s<>"'`]+/g) || []; - return Array.from(new Set(matches.map(cleanUrlToken).filter(Boolean))); -} - -function stripUrls(value) { - return String(value || '').replace(/https?:\/\/[^\s<>"'`]+/g, '').replace(/\s+/g, ' '); -} - -function cleanUrlToken(value) { - let url = String(value || '').trim(); - while (/[.,,。;;::!?!?、\])}\u300b\u300d\u300f]$/.test(url)) { - url = url.slice(0, -1); - } - return url; -} - -async function fetchReadableSources(url) { - const host = window.app; - if (!host?.net?.fetch) throw new Error('net unavailable'); - const targets = sourceTargets(url); - let lastError = null; - const found = []; - for (const target of targets) { - try { - const response = await host.net.fetch(target.url, { - headers: { - Accept: target.accept || 'text/html,text/plain,application/json', - 'User-Agent': 'PPT-Live/1.0', - }, - }); - if (Number(response.status) < 200 || Number(response.status) >= 300) throw new Error(`HTTP ${response.status}`); - const text = readableText(response.body || '', target.url); - if (text.length < 80) throw new Error('source too small'); - host.log?.info?.('PPT Live source fetched', { url: target.url, kind: target.kind, textLength: text.length }); - found.push({ - kind: target.kind, - title: target.title || target.url, - url: target.url, - text: text.slice(0, 9000), - }); - } catch (error) { - host.log?.warn?.('PPT Live source target failed', { url: target.url, kind: target.kind, error: String(error) }); - lastError = error; - } - } - if (found.length) return found; - throw lastError || new Error('fetch failed'); -} - -function sourceTargets(url) { - try { - const parsed = new URL(cleanUrlToken(url)); - if (parsed.hostname === 'github.com') { - const [, owner, repo] = parsed.pathname.split('/'); - if (owner && repo) { - const cleanRepo = repo.replace(/\.git$/i, ''); - return [ - { - kind: 'github-readme', - title: `${owner}/${cleanRepo} README`, - url: `https://raw.githubusercontent.com/${owner}/${cleanRepo}/HEAD/README.md`, - accept: 'text/plain', - }, - { - kind: 'github-api', - title: `${owner}/${cleanRepo}`, - url: `https://api.github.com/repos/${owner}/${cleanRepo}`, - accept: 'application/vnd.github+json', - }, - { kind: 'web-page', title: cleanUrlToken(url), url: cleanUrlToken(url) }, - ]; - } - } - } catch { - return [{ kind: 'web-page', title: cleanUrlToken(url), url: cleanUrlToken(url) }]; - } - return [{ kind: 'web-page', title: cleanUrlToken(url), url: cleanUrlToken(url) }]; -} - -function readableText(body, url) { - const raw = String(body || ''); - if (url.includes('api.github.com/repos/')) { - try { - const data = JSON.parse(raw); - return [ - data.full_name, - data.description, - `Stars: ${data.stargazers_count ?? 'unknown'}`, - `Forks: ${data.forks_count ?? 'unknown'}`, - `Language: ${data.language || 'unknown'}`, - `Topics: ${(data.topics || []).join(', ')}`, - `Updated: ${data.updated_at || 'unknown'}`, - data.homepage ? `Homepage: ${data.homepage}` : '', - ].filter(Boolean).join('\n'); - } catch { - return raw; - } - } - return raw - .replace(//gi, ' ') - .replace(//gi, ' ') - .replace(/<[^>]+>/g, ' ') - .replace(/ /g, ' ') - .replace(/&/g, '&') - .replace(/</g, '<') - .replace(/>/g, '>') - .replace(/\s+/g, ' ') - .trim(); -} - -function extractFacts(text) { - const clean = String(text || '').replace(/\s+/g, ' ').trim(); - const sentences = clean - .split(/(?<=[。!?.!?])\s+|[\n\r]+/) - .map((item) => item.trim()) - .filter((item) => item.length >= 16 && item.length <= 180); - const numeric = sentences.filter((item) => /\d/.test(item)); - return [...numeric, ...sentences].slice(0, 12); -} - -function summarizeSource(text, sources) { - const facts = extractFacts(text).slice(0, 6); - if (!facts.length) return ''; - return [t('sourceDigestTitle'), ...facts.map((fact) => `- ${fact}`), ...(sources.warnings || []).map((warning) => `- ${warning}`)].join('\n'); -} - -async function askAi() { - throw new Error('PPT Live generation must use the Sparo agent backend with the ppt-design skill'); -} - -function extractJson(value) { - const raw = typeof value === 'string' ? value : JSON.stringify(value); - try { - return JSON.parse(raw); - } catch { - const match = raw.match(/\{[\s\S]*\}/); - if (!match) return null; - return JSON.parse(match[0]); - } -} diff --git a/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/export-bundle-entry.mjs b/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/export-bundle-entry.mjs deleted file mode 100644 index c170329c..00000000 --- a/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/export-bundle-entry.mjs +++ /dev/null @@ -1,7 +0,0 @@ -export { - exportPptxFromDeck, - exportPptxPrepared, - exportPdfFromBase64Pages, - exportPngZipFromPages, - exportFileSafe, -} from './export-deck-browser.js'; diff --git a/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/export-deck-browser.js b/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/export-deck-browser.js deleted file mode 100644 index ae766889..00000000 --- a/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/export-deck-browser.js +++ /dev/null @@ -1,125 +0,0 @@ -import { PDFDocument } from 'pdf-lib'; -import JSZip from 'jszip'; -import { - buildSlideFromExtracted, - buildSpeakerNotes, - createPptxDeck, -} from './pptx-html-build.js'; -import { exportElementDeckToPptx } from './pptx-element-export.js'; - -const MIME_PPTX = 'application/vnd.openxmlformats-officedocument.presentationml.presentation'; - -const RASTER_TEXT_TYPES = new Set(['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'list', 'merged-text']); - -function filterSlideDataForRasterBackdrop(slideData) { - return { - ...slideData, - elements: (slideData.elements || []).filter((el) => RASTER_TEXT_TYPES.has(el.type)), - }; -} - -function uint8ToBase64(bytes) { - const chunk = 0x8000; - let binary = ''; - for (let i = 0; i < bytes.length; i += chunk) { - binary += String.fromCharCode(...bytes.subarray(i, i + chunk)); - } - return btoa(binary); -} - -export function exportFileSafe(value) { - return String(value || 'ppt-live').replace(/[\\/:*?"<>|]+/g, '-').slice(0, 96); -} - -async function pptxToExportResult(pptx, deck) { - const base64 = await pptx.write({ outputType: 'base64' }); - return { - filename: `${exportFileSafe(deck.title || 'ppt-live')}.pptx`, - mimeType: MIME_PPTX, - base64: String(base64 || '').replace(/^data:.*;base64,/, ''), - }; -} - -export async function exportPptxFromDeck(deck) { - const slides = Array.isArray(deck?.slides) ? deck.slides : []; - if (slides.some((slide) => slide?.html)) { - throw new Error('HTML slides must use the WebView prepare export path.'); - } - const pptx = await exportElementDeckToPptx(deck); - return pptxToExportResult(pptx, deck); -} - -export async function exportPptxPrepared(deck, preparedSlides) { - const prepared = Array.isArray(preparedSlides) ? preparedSlides : []; - if (!prepared.length) throw new Error('No prepared slides to export'); - const pptx = createPptxDeck(deck); - const slides = Array.isArray(deck?.slides) ? deck.slides : []; - for (const item of prepared) { - const sourceSlide = slides[item.index] || item.notes || {}; - let slideData = item.slideData; - if (item.rasterBase64) { - const raw = String(item.rasterBase64).replace(/^data:.*;base64,/, ''); - if (item.rasterOnly) { - slideData = { - ...slideData, - elements: (slideData.elements || []).filter((el) => !RASTER_TEXT_TYPES.has(el.type)), - background: { type: 'image', path: `data:image/png;base64,${raw}` }, - }; - } else { - slideData = filterSlideDataForRasterBackdrop(slideData); - slideData = { - ...slideData, - background: { type: 'image', path: `data:image/png;base64,${raw}` }, - }; - } - } - const result = await buildSlideFromExtracted( - slideData, - item.bodyDimensions, - pptx, - ); - const notes = buildSpeakerNotes(sourceSlide); - if (notes && result?.slide && typeof result.slide.addNotes === 'function') { - result.slide.addNotes(notes); - } - } - return pptxToExportResult(pptx, deck); -} - -export async function exportPdfFromBase64Pages(deck, pages) { - const list = Array.isArray(pages) ? pages : []; - if (!list.length) throw new Error('No rendered PDF pages to export'); - const merged = await PDFDocument.create(); - for (const pageBase64 of list) { - const raw = String(pageBase64 || '').replace(/^data:.*;base64,/, ''); - const buffer = Uint8Array.from(atob(raw), (c) => c.charCodeAt(0)); - const source = await PDFDocument.load(buffer); - const copied = await merged.copyPages(source, source.getPageIndices()); - copied.forEach((page) => merged.addPage(page)); - } - const bytes = await merged.save(); - return { - filename: `${exportFileSafe(deck?.title || 'ppt-live')}.pdf`, - mimeType: 'application/pdf', - base64: uint8ToBase64(bytes), - }; -} - -export async function exportPngZipFromPages(deck, pages) { - const list = Array.isArray(pages) ? pages : []; - if (!list.length) throw new Error('No rendered PNG pages to export'); - const zip = new JSZip(); - list.forEach((item, index) => { - const raw = typeof item === 'string' - ? item - : String(item?.base64 || '').replace(/^data:.*;base64,/, ''); - const slideIndex = (item?.index ?? index) + 1; - zip.file(`slide-${String(slideIndex).padStart(2, '0')}.png`, raw, { base64: true }); - }); - const blob = await zip.generateAsync({ type: 'base64', compression: 'DEFLATE' }); - return { - filename: `${exportFileSafe(deck?.title || 'ppt-live')}-slides.zip`, - mimeType: 'application/zip', - base64: String(blob || '').replace(/^data:.*;base64,/, ''), - }; -} diff --git a/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/export-deck-host.js b/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/export-deck-host.js deleted file mode 100644 index 2cc09274..00000000 --- a/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/export-deck-host.js +++ /dev/null @@ -1,6 +0,0 @@ -export { - exportPptxFromDeck, - exportPptxPrepared, - exportPdfFromBase64Pages, - exportPngZipFromPages, -} from './vendor/ppt-export.bundle.mjs'; diff --git a/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/export-format-icons.js b/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/export-format-icons.js deleted file mode 100644 index 93967a07..00000000 --- a/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/export-format-icons.js +++ /dev/null @@ -1,23 +0,0 @@ -const SVG_ATTRS = 'xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"'; - -/** Recognizable file-type marks for export format cards (inline SVG, no external assets). */ -const ICONS = { - pptx: ``, - pdf: `PDF`, - html: ``, - png: ``, -}; - -export function exportFormatIcon(formatId) { - return ICONS[formatId] || ICONS.html; -} - -export function exportFormatTone(formatId) { - const tones = { - pptx: '#d44726', - pdf: '#e01e3c', - html: '#0d9488', - png: '#2563eb', - }; - return tones[formatId] || '#475569'; -} diff --git a/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/export-html.js b/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/export-html.js deleted file mode 100644 index dec8af5c..00000000 --- a/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/export-html.js +++ /dev/null @@ -1,100 +0,0 @@ -import { escapeHtml } from './state.js'; -import { getLocale } from './i18n.js'; -import { normalizeSlideDocument, slideHtml } from './render.js'; - -export function buildHtmlDeck(state) { - if ((state.slides || []).some((slide) => slide.html)) { - return buildSourceHtmlDeck(state); - } - const slides = state.slides - .map((slide) => `
${slideHtml(slide)}
`) - .join('\n'); - return ` - - - - -${escapeHtml(state.title || 'PPT Live')} - - - -
${slides}
- -`; -} - -function buildSourceHtmlDeck(state) { - const slides = (state.slides || []) - .map((slide, index) => `
- -
`) - .join('\n'); - return ` - - - - -${escapeHtml(state.title || 'PPT Live')} - - - -
${slides}
- -`; -} - -export function downloadHtmlDeck(state) { - const blob = new Blob([buildHtmlDeck(state)], { type: 'text/html;charset=utf-8' }); - const url = URL.createObjectURL(blob); - const link = document.createElement('a'); - const filename = `${fileSafe(state.title || 'ppt-live')}.html`; - link.href = url; - link.download = filename; - document.body.append(link); - link.click(); - link.remove(); - URL.revokeObjectURL(url); - return filename; -} - -export function downloadBase64File(base64, filename, mimeType) { - const binary = atob(base64); - const bytes = new Uint8Array(binary.length); - for (let i = 0; i < binary.length; i += 1) bytes[i] = binary.charCodeAt(i); - const blob = new Blob([bytes], { type: mimeType }); - const url = URL.createObjectURL(blob); - const link = document.createElement('a'); - link.href = url; - link.download = filename; - document.body.append(link); - link.click(); - link.remove(); - URL.revokeObjectURL(url); -} - -export function fileSafe(value) { - return String(value || 'ppt-live').replace(/[\\/:*?"<>|]+/g, '-').slice(0, 96); -} - -function deckCss() { - return ` -body{margin:0;background:#111827;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif} -.deck{display:grid;gap:24px;padding:24px}.deck-slide{display:grid;place-items:center;min-height:100vh} -.slide{position:relative;width:min(100%,1280px);aspect-ratio:16/9;color:var(--slide-ink);background:var(--slide-bg);overflow:hidden;box-shadow:0 24px 70px rgba(0,0,0,.34)} -.free-slide{background:radial-gradient(circle at 84% 18%,color-mix(in srgb,var(--slide-primary) 14%,transparent),transparent 28%),linear-gradient(135deg,color-mix(in srgb,var(--slide-accent) 8%,transparent),transparent 42%),var(--slide-bg)} -.slide-element{position:absolute;padding:12px;overflow:hidden;white-space:pre-wrap;line-height:1.14;box-sizing:border-box} -.element-text{display:flex;align-items:center}.element-list{line-height:1.36}.element-list ul{margin:0;padding-left:1.1em;display:grid;gap:.5em} -.element-metric{display:flex;flex-direction:column;justify-content:center;gap:6px;box-shadow:0 18px 38px rgba(17,24,39,.12)} -.element-metric strong{font-size:inherit;line-height:.95}.element-metric span{color:var(--slide-muted);font-size:14px;line-height:1.25} -.element-media{display:grid;place-items:center;border:1px dashed color-mix(in srgb,var(--slide-primary) 40%,transparent)} -.element-chart{display:flex;flex-direction:column;gap:10px}.element-chart b{font-size:16px}.chart-bars{display:flex;align-items:end;gap:8px;flex:1;min-height:0}.chart-bars span{display:flex;flex:1;height:100%;align-items:end;gap:4px;flex-direction:column}.chart-bars i{display:block;width:100%;border-radius:5px 5px 0 0;background:var(--slide-primary)}.chart-bars em{font-size:10px;color:var(--slide-muted);font-style:normal} -`; -} diff --git a/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/export-slide-browser.js b/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/export-slide-browser.js deleted file mode 100644 index 7a5bd960..00000000 --- a/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/export-slide-browser.js +++ /dev/null @@ -1,315 +0,0 @@ -import { normalizeSlideDocument, scopeSlideAuthorStyles } from './render.js'; -import { sanitizeSlideDocumentRoot } from './sanitize-slide-html.js'; -import { extractSlideDataFromDocument, measureBodyDimensions } from './html2pptx-dom-core.js'; - -export const EXPORT_VIEWPORT = { width: 1280, height: 720 }; - -const RASTER_TEXT_SELECTOR_BY_TYPE = { - p: ['p'], - h1: ['h1'], - h2: ['h2'], - h3: ['h3'], - h4: ['h4'], - h5: ['h5'], - h6: ['h6'], - list: ['li'], - 'merged-text': ['span', 'em', 'strong', 'b', 'i', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'], -}; - -export function countVectorTextElements(slideData) { - return (slideData?.elements || []).filter((el) => RASTER_TEXT_TYPES.has(el.type)).length; -} - -function buildRasterTextHideStyle(slideData) { - const selectors = new Set(); - for (const el of slideData?.elements || []) { - if (!RASTER_TEXT_TYPES.has(el.type)) continue; - for (const tag of RASTER_TEXT_SELECTOR_BY_TYPE[el.type] || [el.type]) { - selectors.add(tag); - } - } - if (!selectors.size) return ''; - const rules = [...selectors] - .map((tag) => ( - `body[data-pptx-raster="1"] ${tag} { - color: transparent !important; - -webkit-text-fill-color: transparent !important; - text-shadow: none !important; -}` - )) - .join('\n'); - return rules; -} - -/** HTML for host WebView raster capture: hide only text that will be re-added as editable PPTX text. */ -export function slideHtmlForRasterBackdrop(html, slideData = null) { - const markup = normalizeSlideDocument(html); - if (!slideData || countVectorTextElements(slideData) === 0) { - return markup; - } - const hideCss = buildRasterTextHideStyle(slideData); - if (!hideCss) return markup; - if (markup.includes('data-pptx-raster="1"') && markup.includes('pptx-raster-hide-text')) { - return markup; - } - const styleTag = ``; - if (/<\/head>/i.test(markup)) { - return markup - .replace(/<\/head>/i, `${styleTag}`) - .replace(/ RASTER_TEXT_TYPES.has(el.type)), - }; -} - -let exportSessionHost = null; - -function getExportSessionHost() { - if (!exportSessionHost?.isConnected) { - exportSessionHost = document.createElement('div'); - exportSessionHost.id = 'ppt-export-session-host'; - exportSessionHost.setAttribute('aria-hidden', 'true'); - exportSessionHost.style.cssText = [ - 'position:fixed', - 'left:-24000px', - 'top:0', - 'width:1px', - 'height:1px', - 'overflow:hidden', - 'opacity:0', - 'pointer-events:none', - 'z-index:-1', - 'contain:strict', - ].join(';'); - document.body.appendChild(exportSessionHost); - } - return exportSessionHost; -} - -export function clearExportSessionHost() { - if (exportSessionHost?.isConnected) { - exportSessionHost.replaceChildren(''); - } -} - -function scopeAuthorStyles(cssText) { - return scopeSlideAuthorStyles(cssText, '.ppt-export-root', '.ppt-export-body'); -} - -function wrapExportDocument(root, body) { - return { - body, - documentElement: root, - defaultView: window, - querySelectorAll: (sel) => root.querySelectorAll(sel), - createElement: (tag) => document.createElement(tag), - getElementById: (id) => root.querySelector(`#${id}`), - head: root.querySelector('style')?.parentElement || root, - _exportRoot: root, - }; -} - -function createExportRoot() { - // Mount the slide inside a shadow root so its author styles (e.g. `* { ... }`, - // `p { ... }`, `table { ... }`) cannot leak into the app document. Leaked rules - // used to restyle the whole UI for a frame on every exported page, which made - // the export modal visibly jump. - const host = document.createElement('div'); - host.className = 'ppt-export-root-host'; - host.setAttribute('aria-hidden', 'true'); - host.style.cssText = [ - `width:${EXPORT_VIEWPORT.width}px`, - `height:${EXPORT_VIEWPORT.height}px`, - 'overflow:hidden', - ].join(';'); - getExportSessionHost().appendChild(host); - const shadow = host.attachShadow({ mode: 'open' }); - const root = document.createElement('div'); - root.className = 'ppt-export-root'; - root.style.cssText = [ - `width:${EXPORT_VIEWPORT.width}px`, - `height:${EXPORT_VIEWPORT.height}px`, - 'overflow:hidden', - ].join(';'); - shadow.appendChild(root); - root._exportHost = host; - return root; -} - -function removeExportRoot(root) { - const host = root?._exportHost || root; - if (host?.isConnected) host.remove(); -} - -async function waitForExportPaint() { - await new Promise((resolve) => { - requestAnimationFrame(() => requestAnimationFrame(resolve)); - }); -} - -function mountMarkupOnRoot(root, markup) { - const parsed = new DOMParser().parseFromString(markup, 'text/html'); - root.replaceChildren(); - - parsed.querySelectorAll('style').forEach((node) => { - const style = document.createElement('style'); - style.textContent = scopeAuthorStyles(node.textContent || ''); - root.appendChild(style); - }); - - const body = document.createElement('div'); - body.className = 'ppt-export-body'; - if (parsed.body) { - for (const attr of parsed.body.attributes) { - if (attr.name === 'class') { - body.classList.add(...attr.value.split(/\s+/).filter(Boolean)); - } else if (attr.name === 'style') { - body.style.cssText += `;${attr.value}`; - } else { - body.setAttribute(attr.name, attr.value); - } - } - body.innerHTML = parsed.body.innerHTML; - } - body.style.boxSizing = 'border-box'; - if (!/\bwidth\s*:/i.test(body.style.cssText)) { - body.style.width = `${EXPORT_VIEWPORT.width}px`; - } - if (!/\bheight\s*:/i.test(body.style.cssText)) { - body.style.height = `${EXPORT_VIEWPORT.height}px`; - } - root.appendChild(body); - return body; -} - -async function loadHtmlInExportRoot(html) { - const markup = normalizeSlideDocument(html); - const root = createExportRoot(); - const body = mountMarkupOnRoot(root, markup); - await waitForExportPaint(); - return wrapExportDocument(root, body); -} - -async function prepareSlideOnce(html, aggressive, options = {}) { - let exportRoot = null; - try { - const doc = await loadHtmlInExportRoot(html); - exportRoot = doc._exportRoot; - sanitizeSlideDocumentRoot(doc, aggressive); - await waitForExportPaint(); - - const bodyDimensions = measureBodyDimensions(doc); - const slideData = extractSlideDataFromDocument(doc); - // Content overflow must never block the export: clip/off-slide content is - // preferable to a failed run. Demote overflow findings to warnings. - const overflowWarnings = bodyDimensions.errors || []; - if (overflowWarnings.length) { - console.warn('[ppt-live-export] slide overflows canvas; exporting anyway:', overflowWarnings.join('; ')); - } - const safeBodyDimensions = { ...bodyDimensions, errors: [] }; - const errors = slideData.errors || []; - if (!errors.length || options.allowValidationErrors) { - return { slideData, bodyDimensions: safeBodyDimensions, aggressive, warnings: overflowWarnings }; - } - return { error: new Error(errors.join('\n')) }; - } finally { - if (exportRoot) removeExportRoot(exportRoot); - } -} - -export async function prepareSlideForPptxExport(html, options = {}) { - const first = await prepareSlideOnce(html, false, options); - if (first?.slideData) return first; - - const second = await prepareSlideOnce(html, true, options); - if (second?.slideData) return second; - throw second?.error || first?.error || new Error('PPT Live slide preparation failed'); -} - -export async function prepareSlidesForPptxExport(slides, options = {}) { - const prepared = []; - try { - for (const [index, slide] of slides.entries()) { - if (!slide?.html) continue; - const item = await prepareSlideForPptxExport(slide.html, options); - let rasterBase64 = null; - const vectorTextCount = countVectorTextElements(item.slideData); - const rasterOnly = vectorTextCount === 0; - if (typeof options.renderRaster === 'function') { - try { - if (typeof options.onRasterProgress === 'function') { - options.onRasterProgress(index, slide); - } - const rasterHtml = rasterOnly - ? slideExportHtml(slide) - : slideHtmlForRasterBackdrop(slide.html, item.slideData); - rasterBase64 = await options.renderRaster(rasterHtml, index); - } catch { - rasterBase64 = null; - } - } - prepared.push({ - index, - slideId: slide.id, - notes: slide, - ...item, - rasterBase64, - rasterOnly: Boolean(rasterBase64 && rasterOnly), - }); - } - return prepared; - } finally { - clearExportSessionHost(); - } -} - -export function buildElementSlideHtml(slide = {}) { - const theme = slide.theme || {}; - const title = String(slide.title || 'Slide').replace(/[<>&]/g, (ch) => ({ - '<': '<', '>': '>', '&': '&', - })[ch] || ch); - const subtitle = String(slide.subtitle || slide.claim || '').replace(/[<>&]/g, (ch) => ({ - '<': '<', '>': '>', '&': '&', - })[ch] || ch); - const background = theme.background || '#ffffff'; - const ink = theme.ink || '#111111'; - const muted = theme.muted || '#666666'; - return ` - - - - - - -

${title}

- ${subtitle ? `

${subtitle}

` : ''} - -`; -} - -export function slideExportHtml(slide) { - if (slide?.html) return normalizeSlideDocument(slide.html); - return buildElementSlideHtml(slide); -} diff --git a/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/flat-select.js b/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/flat-select.js deleted file mode 100644 index 8cef403a..00000000 --- a/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/flat-select.js +++ /dev/null @@ -1,220 +0,0 @@ -const OPEN_SELECTS = new Set(); - -function closeSelect(wrap) { - const menu = wrap.querySelector('.ppt-flat-select__menu'); - const trigger = wrap.querySelector('.ppt-flat-select__trigger'); - if (!menu || !trigger) return; - menu.hidden = true; - menu.style.top = ''; - menu.style.bottom = ''; - menu.style.left = ''; - menu.style.width = ''; - trigger.setAttribute('aria-expanded', 'false'); - wrap.classList.remove('is-open'); - OPEN_SELECTS.delete(wrap); -} - -function closeAllExcept(exceptWrap) { - OPEN_SELECTS.forEach((wrap) => { - if (wrap !== exceptWrap) closeSelect(wrap); - }); -} - -function positionMenu(wrap) { - const menu = wrap.querySelector('.ppt-flat-select__menu'); - const trigger = wrap.querySelector('.ppt-flat-select__trigger'); - if (!menu || !trigger) return; - - const rect = trigger.getBoundingClientRect(); - const menuHeight = Math.min(220, menu.scrollHeight || 220); - const spaceBelow = window.innerHeight - rect.bottom; - const openUpward = spaceBelow < menuHeight + 8 && rect.top > spaceBelow; - - // The menu is a fixed-position overlay (see .ppt-flat-select__menu), so it - // never affects panel layout or scrollbars; only its placement is inline. - menu.style.left = `${Math.max(8, rect.left)}px`; - menu.style.width = `${rect.width}px`; - - if (openUpward) { - menu.style.top = 'auto'; - menu.style.bottom = `${window.innerHeight - rect.top + 4}px`; - } else { - menu.style.top = `${rect.bottom + 4}px`; - menu.style.bottom = 'auto'; - } -} - -function openSelect(wrap) { - const menu = wrap.querySelector('.ppt-flat-select__menu'); - const trigger = wrap.querySelector('.ppt-flat-select__trigger'); - if (!menu || !trigger) return; - closeAllExcept(null); - menu.hidden = false; - positionMenu(wrap); - trigger.setAttribute('aria-expanded', 'true'); - wrap.classList.add('is-open'); - OPEN_SELECTS.add(wrap); - const selected = menu.querySelector('.ppt-flat-select__option.is-selected'); - selected?.scrollIntoView({ block: 'nearest' }); -} - -function moveMenuFocus(wrap, delta) { - const menu = wrap.querySelector('.ppt-flat-select__menu'); - if (!menu || menu.hidden) return; - const options = [...menu.querySelectorAll('.ppt-flat-select__option')]; - if (!options.length) return; - const activeIndex = options.indexOf(document.activeElement); - const currentIndex = activeIndex >= 0 - ? activeIndex - : options.findIndex((node) => node.classList.contains('is-selected')); - const nextIndex = Math.min(options.length - 1, Math.max(0, (currentIndex < 0 ? -delta : currentIndex) + delta)); - options[nextIndex]?.focus(); - options[nextIndex]?.scrollIntoView({ block: 'nearest' }); -} - -function syncFlatSelect(select) { - const wrap = select.closest('.ppt-flat-select'); - if (!wrap) return; - const label = wrap.querySelector('.ppt-flat-select__label'); - const menu = wrap.querySelector('.ppt-flat-select__menu'); - const selected = select.options[select.selectedIndex]; - if (label) label.textContent = selected?.textContent?.trim() || ''; - if (!menu) return; - - const existing = new Map([...menu.querySelectorAll('.ppt-flat-select__option')].map((node) => [node.dataset.value, node])); - [...select.options].forEach((opt) => { - let item = existing.get(opt.value); - if (!item) { - item = document.createElement('button'); - item.type = 'button'; - item.className = 'ppt-flat-select__option'; - item.setAttribute('role', 'option'); - item.dataset.value = opt.value; - item.addEventListener('click', () => { - select.value = opt.value; - syncFlatSelect(select); - closeSelect(wrap); - select.dispatchEvent(new Event('change', { bubbles: true })); - }); - menu.append(item); - } - item.textContent = opt.textContent; - if (opt.title) item.title = opt.title; - const isSelected = opt.value === select.value; - item.classList.toggle('is-selected', isSelected); - item.setAttribute('aria-selected', isSelected ? 'true' : 'false'); - }); - - [...menu.querySelectorAll('.ppt-flat-select__option')].forEach((node) => { - if (![...select.options].some((opt) => opt.value === node.dataset.value)) node.remove(); - }); - - if (wrap.classList.contains('is-open')) positionMenu(wrap); -} - -function isScrollInsideOpenMenu(target) { - if (!(target instanceof Node)) return false; - for (const wrap of OPEN_SELECTS) { - const menu = wrap.querySelector('.ppt-flat-select__menu'); - if (menu && (menu === target || menu.contains(target))) return true; - } - return false; -} - -function handleOutsideScroll(event) { - if (isScrollInsideOpenMenu(event.target)) return; - closeAllExcept(null); -} - -function handleOutsideClick(event) { - const target = event.target; - if (target instanceof Node) { - for (const wrap of OPEN_SELECTS) { - if (wrap.contains(target)) return; - } - } - closeAllExcept(null); -} - -export function enhanceFlatSelect(select) { - if (!select || select.dataset.flatSelect === 'true') return; - select.dataset.flatSelect = 'true'; - select.classList.remove('ppt-flat-select'); - select.classList.add('ppt-flat-select__native'); - select.tabIndex = -1; - select.setAttribute('aria-hidden', 'true'); - - const wrap = document.createElement('div'); - wrap.className = 'ppt-flat-select'; - - const trigger = document.createElement('button'); - trigger.type = 'button'; - trigger.className = 'ppt-flat-select__trigger'; - trigger.setAttribute('aria-haspopup', 'listbox'); - trigger.setAttribute('aria-expanded', 'false'); - - const label = document.createElement('span'); - label.className = 'ppt-flat-select__label'; - trigger.append(label); - - const menu = document.createElement('div'); - menu.className = 'ppt-flat-select__menu'; - menu.hidden = true; - menu.setAttribute('role', 'listbox'); - menu.addEventListener('wheel', (event) => event.stopPropagation(), { passive: true }); - menu.addEventListener('mousedown', (event) => event.stopPropagation()); - - trigger.addEventListener('click', (event) => { - event.stopPropagation(); - if (wrap.classList.contains('is-open')) { - closeSelect(wrap); - return; - } - openSelect(wrap); - }); - - wrap.addEventListener('keydown', (event) => { - if (event.key === 'ArrowDown' || event.key === 'ArrowUp') { - event.preventDefault(); - if (!wrap.classList.contains('is-open')) openSelect(wrap); - moveMenuFocus(wrap, event.key === 'ArrowDown' ? 1 : -1); - } else if (event.key === 'Escape' && wrap.classList.contains('is-open')) { - event.stopPropagation(); - closeSelect(wrap); - trigger.focus(); - } - }); - - const parent = select.parentNode; - parent.insertBefore(wrap, select); - wrap.append(trigger, menu, select); - syncFlatSelect(select); -} - -export function enhanceFlatSelects(root = document) { - root.querySelectorAll('select#stylePresetSelect, select#themeInput, select#slideTargetInput').forEach((select) => { - enhanceFlatSelect(select); - }); -} - -export function refreshFlatSelect(select) { - syncFlatSelect(select); -} - -export function refreshFlatSelectLabels() { - document.querySelectorAll('select[data-flat-select="true"]').forEach((select) => { - syncFlatSelect(select); - }); -} - -if (!window.__pptLiveFlatSelectBound) { - window.__pptLiveFlatSelectBound = true; - document.addEventListener('click', handleOutsideClick); - document.addEventListener('keydown', (event) => { - if (event.key === 'Escape') closeAllExcept(null); - }); - window.addEventListener('resize', () => { - OPEN_SELECTS.forEach((wrap) => positionMenu(wrap)); - }); - document.addEventListener('scroll', handleOutsideScroll, true); -} diff --git a/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/html2pptx-dom-core.js b/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/html2pptx-dom-core.js deleted file mode 100644 index 0fc8e144..00000000 --- a/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/src/html2pptx-dom-core.js +++ /dev/null @@ -1,1055 +0,0 @@ -export const PT_PER_PX = 0.75; -export const PX_PER_IN = 96; - -export function measureBodyDimensions(doc = document) { - const view = doc.defaultView || window; - const body = doc.body; - const style = view.getComputedStyle(body); - const bodyDimensions = { - width: parseFloat(style.width), - height: parseFloat(style.height), - scrollWidth: body.scrollWidth, - scrollHeight: body.scrollHeight, - }; - const errors = []; - const widthOverflowPx = Math.max(0, bodyDimensions.scrollWidth - bodyDimensions.width - 1); - const heightOverflowPx = Math.max(0, bodyDimensions.scrollHeight - bodyDimensions.height - 1); - const widthOverflowPt = widthOverflowPx * PT_PER_PX; - const heightOverflowPt = heightOverflowPx * PT_PER_PX; - if (widthOverflowPt > 0 || heightOverflowPt > 0) { - const directions = []; - if (widthOverflowPt > 0) directions.push(`${widthOverflowPt.toFixed(1)}pt horizontally`); - if (heightOverflowPt > 0) directions.push(`${heightOverflowPt.toFixed(1)}pt vertically`); - const reminder = heightOverflowPt > 0 ? ' (Remember: leave 0.5" margin at bottom of slide)' : ''; - errors.push(`HTML content overflows body by ${directions.join(' and ')}${reminder}`); - } - return { ...bodyDimensions, errors }; -} - -export function extractSlideDataFromDocument(doc = document) { - const document = doc; - const view = document.defaultView || window; - - const PT_PER_PX = 0.75; - const PX_PER_IN = 96; - - // Fonts that are single-weight and should not have bold applied - // (applying bold causes PowerPoint to use faux bold which makes text wider) - const SINGLE_WEIGHT_FONTS = ['impact']; - - // Helper: Check if a font should skip bold formatting - const shouldSkipBold = (fontFamily) => { - if (!fontFamily) return false; - const normalizedFont = fontFamily.toLowerCase().replace(/['"]/g, '').split(',')[0].trim(); - return SINGLE_WEIGHT_FONTS.includes(normalizedFont); - }; - - // Unit conversion helpers - const pxToInch = (px) => px / PX_PER_IN; - const pxToPoints = (pxStr) => parseFloat(pxStr) * PT_PER_PX; - const rgbToHex = (rgbStr) => { - // Handle transparent backgrounds by defaulting to white - if (rgbStr === 'rgba(0, 0, 0, 0)' || rgbStr === 'transparent') return 'FFFFFF'; - - const match = rgbStr.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/); - if (!match) return 'FFFFFF'; - return match.slice(1).map(n => parseInt(n).toString(16).padStart(2, '0')).join(''); - }; - - const extractAlpha = (rgbStr) => { - const match = rgbStr.match(/rgba\((\d+),\s*(\d+),\s*(\d+),\s*([\d.]+)\)/); - if (!match || !match[4]) return null; - const alpha = parseFloat(match[4]); - return Math.round((1 - alpha) * 100); - }; - - const parseRgbChannels = (rgbStr) => { - const match = String(rgbStr || '').match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/); - if (!match) return null; - return { - r: parseInt(match[1], 10), - g: parseInt(match[2], 10), - b: parseInt(match[3], 10), - a: match[4] != null ? parseFloat(match[4]) : 1, - }; - }; - - const hexToRgb = (hex) => { - const clean = String(hex || '0E0E12').replace('#', ''); - return { - r: parseInt(clean.slice(0, 2), 16), - g: parseInt(clean.slice(2, 4), 16), - b: parseInt(clean.slice(4, 6), 16), - }; - }; - - const resolveSolidFill = (rgbStr, backdropHex = '0E0E12') => { - const channels = parseRgbChannels(rgbStr); - if (!channels) { - return { fill: rgbToHex(rgbStr), transparency: extractAlpha(rgbStr) }; - } - if (channels.a >= 0.98) { - return { fill: rgbToHex(rgbStr), transparency: null }; - } - const bg = hexToRgb(backdropHex); - const r = Math.round(bg.r * (1 - channels.a) + channels.r * channels.a); - const g = Math.round(bg.g * (1 - channels.a) + channels.g * channels.a); - const b = Math.round(bg.b * (1 - channels.a) + channels.b * channels.a); - return { - fill: [r, g, b].map((n) => n.toString(16).padStart(2, '0')).join('').toUpperCase(), - transparency: null, - }; - }; - - const applyTextTransform = (text, textTransform) => { - if (textTransform === 'uppercase') return text.toUpperCase(); - if (textTransform === 'lowercase') return text.toLowerCase(); - if (textTransform === 'capitalize') { - return text.replace(/\b\w/g, c => c.toUpperCase()); - } - return text; - }; - - // Extract rotation angle from CSS transform and writing-mode - const getRotation = (transform, writingMode) => { - let angle = 0; - - // Handle writing-mode first - // PowerPoint: 90° = text rotated 90° clockwise (reads top to bottom, letters upright) - // PowerPoint: 270° = text rotated 270° clockwise (reads bottom to top, letters upright) - if (writingMode === 'vertical-rl') { - // vertical-rl alone = text reads top to bottom = 90° in PowerPoint - angle = 90; - } else if (writingMode === 'vertical-lr') { - // vertical-lr alone = text reads bottom to top = 270° in PowerPoint - angle = 270; - } - - // Then add any transform rotation - if (transform && transform !== 'none') { - // Try to match rotate() function - const rotateMatch = transform.match(/rotate\((-?\d+(?:\.\d+)?)deg\)/); - if (rotateMatch) { - angle += parseFloat(rotateMatch[1]); - } else { - // Browser may compute as matrix - extract rotation from matrix - const matrixMatch = transform.match(/matrix\(([^)]+)\)/); - if (matrixMatch) { - const values = matrixMatch[1].split(',').map(parseFloat); - // matrix(a, b, c, d, e, f) where rotation = atan2(b, a) - const matrixAngle = Math.atan2(values[1], values[0]) * (180 / Math.PI); - angle += Math.round(matrixAngle); - } - } - } - - // Normalize to 0-359 range - angle = angle % 360; - if (angle < 0) angle += 360; - - return angle === 0 ? null : angle; - }; - - // Get position/dimensions accounting for rotation - const getPositionAndSize = (el, rect, rotation) => { - if (rotation === null) { - return { x: rect.left, y: rect.top, w: rect.width, h: rect.height }; - } - - const isVertical = rotation === 90 || rotation === 270; - - if (isVertical) { - const centerX = rect.left + rect.width / 2; - const centerY = rect.top + rect.height / 2; - - return { - x: centerX - rect.height / 2, - y: centerY - rect.width / 2, - w: rect.height, - h: rect.width, - }; - } - - const centerX = rect.left + rect.width / 2; - const centerY = rect.top + rect.height / 2; - return { - x: centerX - el.offsetWidth / 2, - y: centerY - el.offsetHeight / 2, - w: el.offsetWidth, - h: el.offsetHeight, - }; - }; - - // Parse CSS box-shadow into PptxGenJS shadow properties - const parseBoxShadow = (boxShadow) => { - if (!boxShadow || boxShadow === 'none') return null; - - // Browser computed style format: "rgba(0, 0, 0, 0.3) 2px 2px 8px 0px [inset]" - // CSS format: "[inset] 2px 2px 8px 0px rgba(0, 0, 0, 0.3)" - - const insetMatch = boxShadow.match(/inset/); - - // IMPORTANT: PptxGenJS/PowerPoint doesn't properly support inset shadows - // Only process outer shadows to avoid file corruption - if (insetMatch) return null; - - // Extract color first (rgba or rgb at start) - const colorMatch = boxShadow.match(/rgba?\([^)]+\)/); - - // Extract numeric values (handles both px and pt units) - const parts = boxShadow.match(/([-\d.]+)(px|pt)/g); - - if (!parts || parts.length < 2) return null; - - const offsetX = parseFloat(parts[0]); - const offsetY = parseFloat(parts[1]); - const blur = parts.length > 2 ? parseFloat(parts[2]) : 0; - - // Calculate angle from offsets (in degrees, 0 = right, 90 = down) - let angle = 0; - if (offsetX !== 0 || offsetY !== 0) { - angle = Math.atan2(offsetY, offsetX) * (180 / Math.PI); - if (angle < 0) angle += 360; - } - - // Calculate offset distance (hypotenuse) - const offset = Math.sqrt(offsetX * offsetX + offsetY * offsetY) * PT_PER_PX; - - // Extract opacity from rgba - let opacity = 0.5; - if (colorMatch) { - const opacityMatch = colorMatch[0].match(/[\d.]+\)$/); - if (opacityMatch) { - opacity = parseFloat(opacityMatch[0].replace(')', '')); - } - } - - return { - type: 'outer', - angle: Math.round(angle), - blur: blur * 0.75, // Convert to points - color: colorMatch ? rgbToHex(colorMatch[0]) : '000000', - offset: offset, - opacity - }; - }; - - // Parse inline formatting tags (, , , , , ) into text runs - const parseInlineFormatting = (element, baseOptions = {}, runs = [], baseTextTransform = (x) => x) => { - let prevNodeIsText = false; - - element.childNodes.forEach((node) => { - let textTransform = baseTextTransform; - - const isText = node.nodeType === Node.TEXT_NODE || node.tagName === 'BR'; - if (isText) { - const text = node.tagName === 'BR' ? '\n' : textTransform(node.textContent.replace(/\s+/g, ' ')); - const prevRun = runs[runs.length - 1]; - if (prevNodeIsText && prevRun) { - prevRun.text += text; - } else { - runs.push({ text, options: { ...baseOptions } }); - } - - } else if (node.nodeType === Node.ELEMENT_NODE && node.textContent.trim()) { - const options = { ...baseOptions }; - const computed = view.getComputedStyle(node); - - // Handle inline elements with computed styles - if (node.tagName === 'SPAN' || node.tagName === 'B' || node.tagName === 'STRONG' || node.tagName === 'I' || node.tagName === 'EM' || node.tagName === 'U') { - const isBold = computed.fontWeight === 'bold' || parseInt(computed.fontWeight) >= 600; - if (isBold && !shouldSkipBold(computed.fontFamily)) options.bold = true; - if (computed.fontStyle === 'italic') options.italic = true; - if (computed.textDecoration && computed.textDecoration.includes('underline')) options.underline = true; - if (computed.color && computed.color !== 'rgb(0, 0, 0)') { - options.color = rgbToHex(computed.color); - const transparency = extractAlpha(computed.color); - if (transparency !== null) options.transparency = transparency; - } - if (computed.fontSize) options.fontSize = pxToPoints(computed.fontSize); - - // Apply text-transform on the span element itself - if (computed.textTransform && computed.textTransform !== 'none') { - const transformStr = computed.textTransform; - textTransform = (text) => applyTextTransform(text, transformStr); - } - - // Validate: Check for margins on inline elements - if (computed.marginLeft && parseFloat(computed.marginLeft) > 0) { - errors.push(`Inline element <${node.tagName.toLowerCase()}> has margin-left which is not supported in PowerPoint. Remove margin from inline elements.`); - } - if (computed.marginRight && parseFloat(computed.marginRight) > 0) { - errors.push(`Inline element <${node.tagName.toLowerCase()}> has margin-right which is not supported in PowerPoint. Remove margin from inline elements.`); - } - if (computed.marginTop && parseFloat(computed.marginTop) > 0) { - errors.push(`Inline element <${node.tagName.toLowerCase()}> has margin-top which is not supported in PowerPoint. Remove margin from inline elements.`); - } - if (computed.marginBottom && parseFloat(computed.marginBottom) > 0) { - errors.push(`Inline element <${node.tagName.toLowerCase()}> has margin-bottom which is not supported in PowerPoint. Remove margin from inline elements.`); - } - - // Recursively process the child node. This will flatten nested spans into multiple runs. - parseInlineFormatting(node, options, runs, textTransform); - } - } - - prevNodeIsText = isText; - }); - - // Trim leading space from first run and trailing space from last run - if (runs.length > 0) { - runs[0].text = runs[0].text.replace(/^\s+/, ''); - runs[runs.length - 1].text = runs[runs.length - 1].text.replace(/\s+$/, ''); - } - - return runs.filter(r => r.text.length > 0); - }; - - const isTransparentBg = (color) => !color || color === 'transparent' || color === 'rgba(0, 0, 0, 0)'; - - const resolveSlideBackground = (rootBody) => { - const candidates = [ - rootBody, - document.documentElement, - rootBody?.querySelector?.(':scope > section, :scope > div, :scope > main'), - ].filter(Boolean); - for (const el of candidates) { - const style = view.getComputedStyle(el); - const bgImage = style.backgroundImage || ''; - if (bgImage.includes('linear-gradient') || bgImage.includes('radial-gradient')) { - return { gradient: true }; - } - if (bgImage && bgImage !== 'none') { - const urlMatch = bgImage.match(/url\(["']?([^"')]+)["']?\)/); - if (urlMatch) return { type: 'image', path: urlMatch[1] }; - } - const bgColor = style.backgroundColor; - if (!isTransparentBg(bgColor)) { - return { type: 'color', value: rgbToHex(bgColor) }; - } - } - return { type: 'color', value: 'FFFFFF' }; - }; - - // Extract background from body / slide root wrapper - const body = document.body; - const bodyRect = body.getBoundingClientRect(); - const boxFor = (rect) => ({ - left: rect.left - bodyRect.left, - top: rect.top - bodyRect.top, - width: rect.width, - height: rect.height, - }); - const rectFor = (el) => boxFor(el.getBoundingClientRect()); - - const resolveTextColor = (computed, el) => { - const channels = parseRgbChannels(computed.color); - if (!channels || channels.a >= 0.2) return rgbToHex(computed.color); - const plain = el.textContent.trim(); - if (!plain) return rgbToHex(computed.color); - return 'E8E8E8'; - }; - - const expandTextFrame = (el, rect, rotation) => { - let { x, y, w, h } = getPositionAndSize(el, rect, rotation); - const slideWidthPx = bodyRect.width; - const slideHeightPx = bodyRect.height; - const maxWPx = Math.max(8, slideWidthPx - x - 4); - const scrollH = el.scrollHeight || 0; - const isHeading = /^H[1-6]$/.test(el.tagName); - const widthPad = isHeading ? Math.min(Math.max(8, w * 0.05), 32) : Math.min(Math.max(2, w * 0.02), 12); - if (isHeading) { - w = Math.max(w + widthPad, slideWidthPx * 0.92 - x); - } else { - w = Math.min(w + widthPad, maxWPx); - } - w = Math.min(w, maxWPx); - const heightPad = Math.max(6, h * (isHeading ? 0.18 : 0.12)); - const maxHPx = Math.max(8, slideHeightPx - y - 4); - if (scrollH > h + 2) h = Math.min(scrollH + heightPad, maxHPx); - else h = Math.min(h + heightPad, maxHPx); - return { x, y, w, h }; - }; - - const readZIndex = (el) => { - const raw = view.getComputedStyle(el).zIndex; - if (!raw || raw === 'auto') return 0; - const parsed = parseInt(raw, 10); - return Number.isFinite(parsed) ? parsed : 0; - }; - - const pushElement = (entry, el) => { - if (el) entry.zIndex = readZIndex(el); - elements.push(entry); - }; - - const resolveListBulletColor = (ul, liElements, textHex) => { - const ulComputed = view.getComputedStyle(ul); - const listColor = ulComputed.listStyleColor; - if (listColor && listColor !== 'rgba(0, 0, 0, 0)') { - const hex = rgbToHex(listColor); - if (hex && hex !== textHex) return hex; - } - for (const li of liElements) { - try { - const marker = view.getComputedStyle(li, '::marker'); - if (marker?.color) { - const hex = rgbToHex(marker.color); - if (hex && hex !== textHex) return hex; - } - } catch { - // ::marker not supported in this WebView - } - } - return null; - }; - - // Collect validation errors - const errors = []; - - const bgResolved = resolveSlideBackground(body); - if (bgResolved.gradient) { - errors.push( - 'CSS gradients are not supported. Use Sharp to rasterize gradients as PNG images first, ' + - 'then reference with background-image: url(\'gradient.png\')', - ); - } - - const background = bgResolved.gradient - ? { type: 'color', value: 'FFFFFF' } - : { type: bgResolved.type, ...(bgResolved.path ? { path: bgResolved.path } : { value: bgResolved.value }) }; - const slideBackdropHex = background.value || '0E0E12'; - - // Process all elements - const elements = []; - const placeholders = []; - const textTags = ['P', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'UL', 'OL', 'LI']; - const processed = new Set(); - - document.querySelectorAll('*').forEach((el) => { - if (processed.has(el)) return; - - // [data-pptx-merge="true"] — opt-in: merge all

/

-

descendants - // into ONE PowerPoint text frame (single editable text box). - // Each child paragraph becomes a run with breakLine:true at the end; - // per-paragraph fontSize/color/bold/italic/underline are preserved as run options. - // The container's bg/border (if any) still becomes its own shape, same as a normal div. - if (el.tagName === 'DIV' && el.dataset && el.dataset.pptxMerge === 'true') { - const containerRect = rectFor(el); - if (containerRect.width === 0 || containerRect.height === 0) { - processed.add(el); - return; - } - - // Reject nested merge containers — undefined behavior. - if (el.querySelector('[data-pptx-merge="true"]')) { - errors.push( - `data-pptx-merge container cannot contain another data-pptx-merge container. ` + - 'Nested merge is not supported.' - ); - processed.add(el); - return; - } - - const mergeComputed = view.getComputedStyle(el); - - // Container background image — same restriction as regular divs. - if (mergeComputed.backgroundImage && mergeComputed.backgroundImage !== 'none') { - errors.push( - 'Background images on data-pptx-merge container are not supported. ' + - 'Use solid colors or borders, or layer images via slide.addImage().' - ); - return; - } - - // Emit a shape for the container's bg/uniform-border (mirrors the regular div branch). - const mHasBg = mergeComputed.backgroundColor && mergeComputed.backgroundColor !== 'rgba(0, 0, 0, 0)'; - const mBorders = [ - mergeComputed.borderTopWidth, - mergeComputed.borderRightWidth, - mergeComputed.borderBottomWidth, - mergeComputed.borderLeftWidth - ].map(b => parseFloat(b) || 0); - const mHasBorder = mBorders.some(b => b > 0); - const mHasUniformBorder = mHasBorder && mBorders.every(b => b === mBorders[0]); - - if (mHasBg || mHasUniformBorder) { - elements.push({ - type: 'shape', - text: '', - position: { - x: pxToInch(containerRect.left), - y: pxToInch(containerRect.top), - w: pxToInch(containerRect.width), - h: pxToInch(containerRect.height) - }, - shape: { - fill: mHasBg ? rgbToHex(mergeComputed.backgroundColor) : null, - transparency: mHasBg ? extractAlpha(mergeComputed.backgroundColor) : null, - line: mHasUniformBorder ? { - color: rgbToHex(mergeComputed.borderColor), - width: pxToPoints(mergeComputed.borderWidth) - } : null, - rectRadius: (() => { - const radius = mergeComputed.borderRadius; - const radiusValue = parseFloat(radius); - if (radiusValue === 0) return 0; - if (radius.includes('%')) { - if (radiusValue >= 50) return 1; - const minDim = Math.min(containerRect.width, containerRect.height); - return (radiusValue / 100) * pxToInch(minDim); - } - if (radius.includes('pt')) return radiusValue / 72; - return radiusValue / PX_PER_IN; - })(), - shadow: parseBoxShadow(mergeComputed.boxShadow) - } - }); - } - - // Collect

/ descendants in document order. - const textDescendants = Array.from(el.querySelectorAll('p, h1, h2, h3, h4, h5, h6')); - if (textDescendants.length === 0) { - errors.push( - `data-pptx-merge container has no

/ children to merge. ` + - 'Remove the data-pptx-merge attribute or add text elements.' - ); - processed.add(el); - return; - } - - // Use the first text element's computed style as the textbox-level base - // (align / lineSpacing / paraSpace are paragraph/textbox-level in pptxgenjs, not per-run). - const firstComputed = view.getComputedStyle(textDescendants[0]); - const baseStyle = { - fontSize: pxToPoints(firstComputed.fontSize), - fontFace: firstComputed.fontFamily.split(',')[0].replace(/['"]/g, '').trim(), - color: rgbToHex(firstComputed.color), - align: firstComputed.textAlign === 'start' ? 'left' : firstComputed.textAlign, - lineSpacing: firstComputed.lineHeight && firstComputed.lineHeight !== 'normal' - ? pxToPoints(firstComputed.lineHeight) - : null, - paraSpaceBefore: 0, - paraSpaceAfter: 0, - // Container padding becomes the textbox internal margin (PptxGenJS: [left, right, bottom, top]). - margin: [ - pxToPoints(mergeComputed.paddingLeft), - pxToPoints(mergeComputed.paddingRight), - pxToPoints(mergeComputed.paddingBottom), - pxToPoints(mergeComputed.paddingTop) - ] - }; - const baseTransparency = extractAlpha(firstComputed.color); - if (baseTransparency !== null) baseStyle.transparency = baseTransparency; - - // Build the merged runs. - const mergedRuns = []; - textDescendants.forEach((textEl, idx) => { - const isLast = idx === textDescendants.length - 1; - const tComputed = view.getComputedStyle(textEl); - const transformStr = tComputed.textTransform; - - // Per-paragraph style overrides — only include if they differ from base. - const elemFontSize = pxToPoints(tComputed.fontSize); - const elemFontFace = tComputed.fontFamily.split(',')[0].replace(/['"]/g, '').trim(); - const elemColor = rgbToHex(tComputed.color); - const elemBold = tComputed.fontWeight === 'bold' || parseInt(tComputed.fontWeight) >= 600; - const elemItalic = tComputed.fontStyle === 'italic'; - const elemUnderline = tComputed.textDecoration.includes('underline'); - - const runBaseOptions = {}; - if (elemFontSize !== baseStyle.fontSize) runBaseOptions.fontSize = elemFontSize; - if (elemFontFace !== baseStyle.fontFace) runBaseOptions.fontFace = elemFontFace; - if (elemColor !== baseStyle.color) runBaseOptions.color = elemColor; - if (elemBold && !shouldSkipBold(tComputed.fontFamily)) runBaseOptions.bold = true; - if (elemItalic) runBaseOptions.italic = true; - if (elemUnderline) runBaseOptions.underline = true; - - const hasInline = textEl.querySelector('b, i, u, strong, em, span, br'); - let runs; - if (hasInline) { - runs = parseInlineFormatting( - textEl, - runBaseOptions, - [], - (str) => applyTextTransform(str, transformStr) - ); - } else { - const txt = applyTextTransform(textEl.textContent.trim(), transformStr); - if (!txt) return; - runs = [{ text: txt, options: { ...runBaseOptions } }]; - } - - if (runs.length > 0 && !isLast) { - runs[runs.length - 1].options.breakLine = true; - } - mergedRuns.push(...runs); - processed.add(textEl); - }); - - if (mergedRuns.length === 0) { - processed.add(el); - return; - } - - elements.push({ - type: 'merged-text', - items: mergedRuns, - position: { - x: pxToInch(containerRect.left), - y: pxToInch(containerRect.top), - w: pxToInch(containerRect.width), - h: pxToInch(containerRect.height) - }, - style: baseStyle - }); - - processed.add(el); - return; - } - - // Text tags with decorative boxes (pills, chips) become a shape + text. - if (textTags.includes(el.tagName)) { - const computed = view.getComputedStyle(el); - const hasBg = computed.backgroundColor && computed.backgroundColor !== 'rgba(0, 0, 0, 0)'; - const hasBorder = (computed.borderWidth && parseFloat(computed.borderWidth) > 0) || - (computed.borderTopWidth && parseFloat(computed.borderTopWidth) > 0) || - (computed.borderRightWidth && parseFloat(computed.borderRightWidth) > 0) || - (computed.borderBottomWidth && parseFloat(computed.borderBottomWidth) > 0) || - (computed.borderLeftWidth && parseFloat(computed.borderLeftWidth) > 0); - const hasShadow = computed.boxShadow && computed.boxShadow !== 'none'; - - if (hasBg || hasBorder || hasShadow) { - const decoRect = rectFor(el); - if (decoRect.width > 0 && decoRect.height > 0) { - const borders = [computed.borderTopWidth, computed.borderRightWidth, computed.borderBottomWidth, computed.borderLeftWidth] - .map((b) => parseFloat(b) || 0); - const hasUniformBorder = borders.some((b) => b > 0) && borders.every((b) => b === borders[0]); - const solid = hasBg ? resolveSolidFill(computed.backgroundColor, slideBackdropHex) : { fill: null, transparency: null }; - if (solid.fill || hasUniformBorder) { - const radius = computed.borderRadius; - const radiusValue = parseFloat(radius); - pushElement({ - type: 'shape', - text: '', - position: { - x: pxToInch(decoRect.left), - y: pxToInch(decoRect.top), - w: pxToInch(decoRect.width), - h: pxToInch(decoRect.height), - }, - shape: { - fill: solid.fill, - transparency: solid.transparency, - line: hasUniformBorder ? { - color: rgbToHex(computed.borderColor), - width: pxToPoints(computed.borderWidth), - } : null, - rectRadius: (() => { - if (!radiusValue) return 0; - if (radius.includes('%')) { - if (radiusValue >= 50) return 1; - const minDim = Math.min(decoRect.width, decoRect.height); - return (radiusValue / 100) * pxToInch(minDim); - } - if (radius.includes('pt')) return radiusValue / 72; - return radiusValue / PX_PER_IN; - })(), - shadow: parseBoxShadow(computed.boxShadow), - }, - }, el); - } - } - } - } - - // Extract placeholder elements (for charts, etc.) - if (el.className && el.className.includes('placeholder')) { - const rect = rectFor(el); - if (rect.width === 0 || rect.height === 0) { - errors.push( - `Placeholder "${el.id || 'unnamed'}" has ${rect.width === 0 ? 'width: 0' : 'height: 0'}. Check the layout CSS.` - ); - } else { - placeholders.push({ - id: el.id || `placeholder-${placeholders.length}`, - x: pxToInch(rect.left), - y: pxToInch(rect.top), - w: pxToInch(rect.width), - h: pxToInch(rect.height) - }); - } - processed.add(el); - return; - } - - // Extract images - if (el.tagName === 'IMG') { - const rect = rectFor(el); - if (rect.width > 0 && rect.height > 0) { - elements.push({ - type: 'image', - src: el.src, - position: { - x: pxToInch(rect.left), - y: pxToInch(rect.top), - w: pxToInch(rect.width), - h: pxToInch(rect.height) - } - }); - processed.add(el); - return; - } - } - - // Extract container blocks with backgrounds/borders as shapes - const containerTags = new Set(['DIV', 'SECTION', 'ARTICLE', 'ASIDE']); - const isContainer = containerTags.has(el.tagName); - if (isContainer) { - const computed = view.getComputedStyle(el); - const hasBg = computed.backgroundColor && computed.backgroundColor !== 'rgba(0, 0, 0, 0)'; - - // Validate: Check for unwrapped text content in DIV - for (const node of el.childNodes) { - if (node.nodeType === Node.TEXT_NODE) { - const text = node.textContent.trim(); - if (text) { - errors.push( - `DIV element contains unwrapped text "${text.substring(0, 50)}${text.length > 50 ? '...' : ''}". ` + - 'All text must be wrapped in

,

-

,

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 diff --git a/bundles/product-apps/builtin-ppt-live/150.0.2/assets/icon.svg b/bundles/product-apps/builtin-ppt-live/150.0.2/assets/icon.svg deleted file mode 100644 index 78d5845e..00000000 --- a/bundles/product-apps/builtin-ppt-live/150.0.2/assets/icon.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/bundles/product-apps/builtin-ppt-live/150.0.2/components/agents/builtin-ppt-live-agent/component.json b/bundles/product-apps/builtin-ppt-live/150.0.2/components/agents/builtin-ppt-live-agent/component.json deleted file mode 100644 index d9de02c2..00000000 --- a/bundles/product-apps/builtin-ppt-live/150.0.2/components/agents/builtin-ppt-live-agent/component.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "id": "builtin-ppt-live-agent", - "kind": "agent", - "name": "PPT Live Agent", - "description": "Presentation-focused agent for outlining decks, generating slide content, refining selected slides, and preparing export-ready review notes.", - "packageSource": "appPrivate", - "ownerApp": { - "appId": "builtin-ppt-live", - "appVersion": "150.0.2" - }, - "capabilities": [ - { - "id": "generateDeck", - "title": "Generate deck", - "description": "Plan a deck outline and generate structured slide content.", - "actions": [ - "generate", - "outline", - "generateSlides" - ] - }, - { - "id": "reviseSlide", - "title": "Revise slide", - "description": "Refine selected slide copy, structure, and visual direction.", - "actions": [ - "reviseSelection", - "summarizeReview" - ] - } - ], - "permissions": [ - { - "kind": "ai", - "summary": "Uses the configured AI agent for deck generation and revision.", - "scopes": [ - "PptLiveAgent" - ] - } - ], - "usedByApps": [ - "builtin-ppt-live" - ], - "visibility": "appDependency", - "dependencies": [], - "implementationRef": "agent://PptLiveAgent", - "usesCapabilities": [ - "session.read", - "model.invoke", - "tool.invoke" - ] -} diff --git a/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/component.json b/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/component.json deleted file mode 100644 index 75b3df65..00000000 --- a/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/component.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "id": "builtin-ppt-live-surface", - "kind": "surface", - "name": "PPT Live Deck Studio", - "description": "The app-owned deck outline, slide canvas, preview, and export surface.", - "packageSource": "appPrivate", - "ownerApp": { - "appId": "builtin-ppt-live", - "appVersion": "150.0.2" - }, - "capabilities": [ - { - "id": "interactiveSurface", - "title": "Interactive surface", - "description": "Hosts the PPT Live primary workspace.", - "actions": [ - "open", - "generateDeck", - "reviseSlide", - "preview", - "export" - ] - } - ], - "permissions": [ - { - "kind": "fs", - "summary": "Reads and writes app-owned deck state and export artifacts.", - "scopes": [ - "{appdata}" - ] - }, - { - "kind": "net", - "summary": "Fetches user-provided source URLs when generating source-grounded decks.", - "scopes": [ - "*" - ] - } - ], - "usedByApps": [ - "builtin-ppt-live" - ], - "visibility": "appDependency", - "dependencies": [ - { - "componentId": "builtin-ppt-live-agent", - "kind": "agent", - "source": "private", - "role": "ppt", - "capabilities": [ - "generateDeck", - "reviseSlide" - ] - }, - { - "componentId": "product-app-runtime-host", - "kind": "runtime", - "source": "shared", - "role": "runtimeHost", - "version": "^1.0.0", - "capabilities": [ - "uiWorker" - ] - } - ], - "implementationRef": "app://builtin-ppt-live@150.0.2/surfaces/builtin-ppt-live-surface", - "usesCapabilities": [ - "session.read", - "component.run" - ] -} diff --git a/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/index.html b/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/index.html deleted file mode 100644 index 08083e38..00000000 --- a/bundles/product-apps/builtin-ppt-live/150.0.2/components/surfaces/builtin-ppt-live-surface/source/index.html +++ /dev/null @@ -1,290 +0,0 @@ - - - - - - PPT Live - - - -

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%0Dkj5DmCYFz8 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%0AJSJFD=~F0l}m}73iNj6ei7( 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