Showing preview only (6,440K chars total). Download the full file or copy to clipboard to get everything.
Repository: wavetermdev/waveterm
Branch: main
Commit: f2b8c201b147
Files: 969
Total size: 6.0 MB
Directory structure:
gitextract_d_p9wdmp/
├── .editorconfig
├── .gitattributes
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug-report.yml
│ │ ├── config.yml
│ │ └── feature-request.yml
│ ├── copilot-instructions.md
│ ├── dependabot.yml
│ └── workflows/
│ ├── build-helper.yml
│ ├── bump-version.yml
│ ├── codeql.yml
│ ├── copilot-setup-steps.yml
│ ├── deploy-docsite.yml
│ ├── merge-gatekeeper.yml
│ ├── publish-release.yml
│ ├── testdriver-build.yml
│ └── testdriver.yml
├── .gitignore
├── .golangci.yml
├── .kilocode/
│ ├── rules/
│ │ ├── overview.md
│ │ └── rules.md
│ └── skills/
│ ├── add-config/
│ │ └── SKILL.md
│ ├── add-rpc/
│ │ └── SKILL.md
│ ├── add-wshcmd/
│ │ └── SKILL.md
│ ├── context-menu/
│ │ └── SKILL.md
│ ├── create-view/
│ │ └── SKILL.md
│ ├── electron-api/
│ │ └── SKILL.md
│ ├── waveenv/
│ │ └── SKILL.md
│ └── wps-events/
│ └── SKILL.md
├── .prettierignore
├── .roo/
│ └── rules/
│ ├── overview.md
│ └── rules.md
├── .vscode/
│ ├── extensions.json
│ └── settings.json
├── .zed/
│ └── settings.json
├── ACKNOWLEDGEMENTS.md
├── BUILD.md
├── CNAME
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── NOTICE
├── README.ko.md
├── README.md
├── RELEASES.md
├── ROADMAP.md
├── SECURITY.md
├── Taskfile.yml
├── aiprompts/
│ ├── aimodesconfig.md
│ ├── aisdk-streaming.md
│ ├── aisdk-uimessage-type.md
│ ├── anthropic-messages-api.md
│ ├── anthropic-streaming.md
│ ├── blockcontroller-lifecycle.md
│ ├── config-system.md
│ ├── conn-arch.md
│ ├── contextmenu.md
│ ├── fe-conn-arch.md
│ ├── focus-layout.md
│ ├── focus.md
│ ├── getsetconfigvar.md
│ ├── layout-simplification.md
│ ├── layout.md
│ ├── monaco-v0.53.md
│ ├── newview.md
│ ├── openai-request.md
│ ├── openai-streaming-text.md
│ ├── openai-streaming.md
│ ├── tailwind-container-queries.md
│ ├── tsunami-builder.md
│ ├── usechat-backend-design.md
│ ├── view-prompt.md
│ ├── wave-osc-16162.md
│ ├── waveai-architecture.md
│ ├── waveai-focus-updates.md
│ └── wps-events.md
├── build/
│ ├── deb-postinstall.tpl
│ ├── entitlements.mac.plist
│ └── icon.icns
├── cmd/
│ ├── generatego/
│ │ └── main-generatego.go
│ ├── generateschema/
│ │ └── main-generateschema.go
│ ├── generatets/
│ │ └── main-generatets.go
│ ├── packfiles/
│ │ └── main-packfiles.go
│ ├── server/
│ │ └── main-server.go
│ ├── test/
│ │ └── test-main.go
│ ├── test-conn/
│ │ ├── cliprovider.go
│ │ ├── main-test-conn.go
│ │ └── testutil.go
│ ├── test-streammanager/
│ │ ├── bridge.go
│ │ ├── deliverypipe.go
│ │ ├── generator.go
│ │ ├── main-test-streammanager.go
│ │ ├── metrics.go
│ │ └── verifier.go
│ ├── testai/
│ │ ├── main-testai.go
│ │ └── testschema.json
│ ├── testopenai/
│ │ └── main-testopenai.go
│ ├── testsummarize/
│ │ └── main-testsummarize.go
│ └── wsh/
│ ├── cmd/
│ │ ├── csscolormap.go
│ │ ├── setmeta_test.go
│ │ ├── wshcmd-ai.go
│ │ ├── wshcmd-badge.go
│ │ ├── wshcmd-blocks.go
│ │ ├── wshcmd-conn.go
│ │ ├── wshcmd-connserver.go
│ │ ├── wshcmd-createblock.go
│ │ ├── wshcmd-debug.go
│ │ ├── wshcmd-debugterm.go
│ │ ├── wshcmd-debugterm_test.go
│ │ ├── wshcmd-deleteblock.go
│ │ ├── wshcmd-editconfig.go
│ │ ├── wshcmd-editor.go
│ │ ├── wshcmd-file-util.go
│ │ ├── wshcmd-file.go
│ │ ├── wshcmd-focusblock.go
│ │ ├── wshcmd-getmeta.go
│ │ ├── wshcmd-getvar.go
│ │ ├── wshcmd-jobdebug.go
│ │ ├── wshcmd-jobmanager.go
│ │ ├── wshcmd-launch.go
│ │ ├── wshcmd-notify.go
│ │ ├── wshcmd-rcfiles.go
│ │ ├── wshcmd-readfile.go
│ │ ├── wshcmd-root.go
│ │ ├── wshcmd-run.go
│ │ ├── wshcmd-secret.go
│ │ ├── wshcmd-setbg.go
│ │ ├── wshcmd-setconfig.go
│ │ ├── wshcmd-setmeta.go
│ │ ├── wshcmd-setvar.go
│ │ ├── wshcmd-shell-unix.go
│ │ ├── wshcmd-shell-win.go
│ │ ├── wshcmd-ssh.go
│ │ ├── wshcmd-ssh_test.go
│ │ ├── wshcmd-tabindicator.go
│ │ ├── wshcmd-term.go
│ │ ├── wshcmd-termscrollback.go
│ │ ├── wshcmd-test.go
│ │ ├── wshcmd-token.go
│ │ ├── wshcmd-version.go
│ │ ├── wshcmd-view.go
│ │ ├── wshcmd-wavepath.go
│ │ ├── wshcmd-web.go
│ │ ├── wshcmd-workspace.go
│ │ └── wshcmd-wsl.go
│ └── main-wsh.go
├── db/
│ ├── db.go
│ ├── migrations-filestore/
│ │ ├── 000001_init.down.sql
│ │ └── 000001_init.up.sql
│ └── migrations-wstore/
│ ├── 000001_init.down.sql
│ ├── 000001_init.up.sql
│ ├── 000002_init.down.sql
│ ├── 000002_init.up.sql
│ ├── 000003_activity.down.sql
│ ├── 000003_activity.up.sql
│ ├── 000004_history.down.sql
│ ├── 000004_history.up.sql
│ ├── 000005_blockparent.down.sql
│ ├── 000005_blockparent.up.sql
│ ├── 000006_workspace.down.sql
│ ├── 000006_workspace.up.sql
│ ├── 000007_events.down.sql
│ ├── 000007_events.up.sql
│ ├── 000008_aimeta.down.sql
│ ├── 000008_aimeta.up.sql
│ ├── 000009_mainserver.down.sql
│ ├── 000009_mainserver.up.sql
│ ├── 000010_merge_pinned_tabs.down.sql
│ ├── 000010_merge_pinned_tabs.up.sql
│ ├── 000011_job.down.sql
│ └── 000011_job.up.sql
├── docs/
│ ├── .editorconfig
│ ├── .gitignore
│ ├── .prettierignore
│ ├── .remarkrc
│ ├── README.md
│ ├── babel.config.js
│ ├── docs/
│ │ ├── ai-presets.mdx
│ │ ├── claude-code.mdx
│ │ ├── config.mdx
│ │ ├── connections.mdx
│ │ ├── customization.mdx
│ │ ├── customwidgets.mdx
│ │ ├── durable-sessions.mdx
│ │ ├── faq.mdx
│ │ ├── gettingstarted.mdx
│ │ ├── index.mdx
│ │ ├── keybindings.mdx
│ │ ├── layout.mdx
│ │ ├── presets.mdx
│ │ ├── releasenotes.mdx
│ │ ├── secrets.mdx
│ │ ├── tabs.mdx
│ │ ├── telemetry-old.mdx
│ │ ├── telemetry.mdx
│ │ ├── waveai-modes.mdx
│ │ ├── waveai.mdx
│ │ ├── widgets.mdx
│ │ ├── workspaces.mdx
│ │ ├── wsh-reference.mdx
│ │ └── wsh.mdx
│ ├── docusaurus.config.ts
│ ├── eslint.config.js
│ ├── package.json
│ ├── prettier.config.cjs
│ ├── src/
│ │ ├── components/
│ │ │ ├── card.css
│ │ │ ├── card.tsx
│ │ │ ├── kbd.css
│ │ │ ├── kbd.tsx
│ │ │ ├── platformcontext.css
│ │ │ ├── platformcontext.tsx
│ │ │ ├── versionbadge.css
│ │ │ └── versionbadge.tsx
│ │ ├── css/
│ │ │ └── custom.scss
│ │ ├── renderer/
│ │ │ └── image-renderers.ts
│ │ └── theme/
│ │ └── MDXComponents/
│ │ └── Heading.tsx
│ ├── static/
│ │ └── .nojekyll
│ └── tsconfig.json
├── electron-builder.config.cjs
├── electron.vite.config.ts
├── emain/
│ ├── authkey.ts
│ ├── emain-activity.ts
│ ├── emain-builder.ts
│ ├── emain-events.ts
│ ├── emain-ipc.ts
│ ├── emain-log.ts
│ ├── emain-menu.ts
│ ├── emain-platform.ts
│ ├── emain-tabview.ts
│ ├── emain-util.ts
│ ├── emain-wavesrv.ts
│ ├── emain-web.ts
│ ├── emain-window.ts
│ ├── emain-wsh.ts
│ ├── emain.ts
│ ├── launchsettings.ts
│ ├── preload-webview.ts
│ ├── preload.ts
│ └── updater.ts
├── eslint.config.js
├── frontend/
│ ├── app/
│ │ ├── aipanel/
│ │ │ ├── ai-utils.ts
│ │ │ ├── aidroppedfiles.tsx
│ │ │ ├── aifeedbackbuttons.tsx
│ │ │ ├── aimessage.tsx
│ │ │ ├── aimode.tsx
│ │ │ ├── aipanel-contextmenu.ts
│ │ │ ├── aipanel.tsx
│ │ │ ├── aipanelheader.tsx
│ │ │ ├── aipanelinput.tsx
│ │ │ ├── aipanelmessages.tsx
│ │ │ ├── airatelimitstrip.tsx
│ │ │ ├── aitooluse.tsx
│ │ │ ├── aitypes.ts
│ │ │ ├── byokannouncement.tsx
│ │ │ ├── restorebackupmodal.tsx
│ │ │ ├── telemetryrequired.tsx
│ │ │ ├── waveai-focus-utils.ts
│ │ │ └── waveai-model.tsx
│ │ ├── app-bg.tsx
│ │ ├── app.scss
│ │ ├── app.tsx
│ │ ├── block/
│ │ │ ├── block-model.ts
│ │ │ ├── block.scss
│ │ │ ├── block.tsx
│ │ │ ├── blockenv.ts
│ │ │ ├── blockframe-header.tsx
│ │ │ ├── blockframe.tsx
│ │ │ ├── blocktypes.ts
│ │ │ ├── blockutil.tsx
│ │ │ ├── connectionbutton.tsx
│ │ │ ├── connstatusoverlay.tsx
│ │ │ └── durable-session-flyover.tsx
│ │ ├── element/
│ │ │ ├── ansiline.tsx
│ │ │ ├── button.scss
│ │ │ ├── button.tsx
│ │ │ ├── copybutton.scss
│ │ │ ├── copybutton.tsx
│ │ │ ├── emojibutton.tsx
│ │ │ ├── emojipalette.scss
│ │ │ ├── emojipalette.tsx
│ │ │ ├── errorboundary.tsx
│ │ │ ├── expandablemenu.scss
│ │ │ ├── expandablemenu.tsx
│ │ │ ├── flyoutmenu.scss
│ │ │ ├── flyoutmenu.tsx
│ │ │ ├── iconbutton.scss
│ │ │ ├── iconbutton.tsx
│ │ │ ├── input.scss
│ │ │ ├── input.tsx
│ │ │ ├── linkbutton.scss
│ │ │ ├── linkbutton.tsx
│ │ │ ├── magnify.scss
│ │ │ ├── magnify.tsx
│ │ │ ├── markdown-contentblock-plugin.ts
│ │ │ ├── markdown-util.ts
│ │ │ ├── markdown.scss
│ │ │ ├── markdown.tsx
│ │ │ ├── menubutton.scss
│ │ │ ├── menubutton.tsx
│ │ │ ├── modal.scss
│ │ │ ├── modal.tsx
│ │ │ ├── multilineinput.scss
│ │ │ ├── multilineinput.tsx
│ │ │ ├── popover.scss
│ │ │ ├── popover.tsx
│ │ │ ├── progressbar.scss
│ │ │ ├── progressbar.tsx
│ │ │ ├── quickelems.scss
│ │ │ ├── quickelems.tsx
│ │ │ ├── quicktips.tsx
│ │ │ ├── remark-mermaid-to-tag.ts
│ │ │ ├── search.scss
│ │ │ ├── search.tsx
│ │ │ ├── streamdown.tsx
│ │ │ ├── toggle.scss
│ │ │ ├── toggle.tsx
│ │ │ ├── tooltip.tsx
│ │ │ ├── typingindicator.scss
│ │ │ └── typingindicator.tsx
│ │ ├── hook/
│ │ │ ├── useDimensions.tsx
│ │ │ └── useLongClick.tsx
│ │ ├── modals/
│ │ │ ├── about.tsx
│ │ │ ├── conntypeahead.tsx
│ │ │ ├── messagemodal.scss
│ │ │ ├── messagemodal.tsx
│ │ │ ├── modal.scss
│ │ │ ├── modal.tsx
│ │ │ ├── modalregistry.tsx
│ │ │ ├── modalsrenderer.tsx
│ │ │ ├── typeaheadmodal.scss
│ │ │ ├── typeaheadmodal.tsx
│ │ │ └── userinputmodal.tsx
│ │ ├── monaco/
│ │ │ ├── monaco-env.ts
│ │ │ ├── monaco-react.tsx
│ │ │ ├── schemaendpoints.ts
│ │ │ └── yamlworker.js
│ │ ├── onboarding/
│ │ │ ├── fakechat.tsx
│ │ │ ├── onboarding-command.tsx
│ │ │ ├── onboarding-common.tsx
│ │ │ ├── onboarding-durable.tsx
│ │ │ ├── onboarding-features-footer.tsx
│ │ │ ├── onboarding-features.tsx
│ │ │ ├── onboarding-layout-term.tsx
│ │ │ ├── onboarding-layout.tsx
│ │ │ ├── onboarding-starask.tsx
│ │ │ ├── onboarding-upgrade-minor.tsx
│ │ │ ├── onboarding-upgrade-patch.tsx
│ │ │ ├── onboarding-upgrade-v0121.tsx
│ │ │ ├── onboarding-upgrade-v0122.tsx
│ │ │ ├── onboarding-upgrade-v0123.tsx
│ │ │ ├── onboarding-upgrade-v0130.tsx
│ │ │ ├── onboarding-upgrade-v0131.tsx
│ │ │ ├── onboarding-upgrade-v0140.tsx
│ │ │ ├── onboarding-upgrade-v0141.tsx
│ │ │ ├── onboarding-upgrade-v0142.tsx
│ │ │ ├── onboarding-upgrade.tsx
│ │ │ └── onboarding.tsx
│ │ ├── reset.scss
│ │ ├── shadcn/
│ │ │ └── lib/
│ │ │ └── utils.ts
│ │ ├── store/
│ │ │ ├── badge.ts
│ │ │ ├── client-model.ts
│ │ │ ├── connections-model.ts
│ │ │ ├── contextmenu.test.ts
│ │ │ ├── contextmenu.ts
│ │ │ ├── counters.ts
│ │ │ ├── focusManager.ts
│ │ │ ├── global-atoms.test.ts
│ │ │ ├── global-atoms.ts
│ │ │ ├── global-model.ts
│ │ │ ├── global.ts
│ │ │ ├── jotaiStore.ts
│ │ │ ├── keymodel.ts
│ │ │ ├── modalmodel.ts
│ │ │ ├── services.ts
│ │ │ ├── tab-model.ts
│ │ │ ├── tabrpcclient.ts
│ │ │ ├── windowtype.ts
│ │ │ ├── wos.ts
│ │ │ ├── wps.ts
│ │ │ ├── ws.ts
│ │ │ ├── wshclient.ts
│ │ │ ├── wshclientapi.ts
│ │ │ ├── wshrouter.ts
│ │ │ ├── wshrpcutil-base.ts
│ │ │ └── wshrpcutil.ts
│ │ ├── suggestion/
│ │ │ └── suggestion.tsx
│ │ ├── tab/
│ │ │ ├── tab.scss
│ │ │ ├── tab.tsx
│ │ │ ├── tabbadges.tsx
│ │ │ ├── tabbar-model.ts
│ │ │ ├── tabbar.scss
│ │ │ ├── tabbar.tsx
│ │ │ ├── tabbarenv.ts
│ │ │ ├── tabcontent.tsx
│ │ │ ├── tabcontextmenu.ts
│ │ │ ├── updatebanner.tsx
│ │ │ ├── vtab.test.tsx
│ │ │ ├── vtab.tsx
│ │ │ ├── vtabbar.tsx
│ │ │ ├── vtabbarenv.ts
│ │ │ ├── workspaceeditor.scss
│ │ │ ├── workspaceeditor.tsx
│ │ │ ├── workspaceswitcher.scss
│ │ │ └── workspaceswitcher.tsx
│ │ ├── theme.scss
│ │ ├── treeview/
│ │ │ ├── treeview.test.ts
│ │ │ └── treeview.tsx
│ │ ├── view/
│ │ │ ├── aifilediff/
│ │ │ │ └── aifilediff.tsx
│ │ │ ├── codeeditor/
│ │ │ │ ├── codeeditor.tsx
│ │ │ │ └── diffviewer.tsx
│ │ │ ├── helpview/
│ │ │ │ └── helpview.tsx
│ │ │ ├── launcher/
│ │ │ │ └── launcher.tsx
│ │ │ ├── preview/
│ │ │ │ ├── csvview.scss
│ │ │ │ ├── csvview.tsx
│ │ │ │ ├── directorypreview.scss
│ │ │ │ ├── entry-manager.tsx
│ │ │ │ ├── preview-directory-utils.tsx
│ │ │ │ ├── preview-directory.tsx
│ │ │ │ ├── preview-edit.tsx
│ │ │ │ ├── preview-error-overlay.tsx
│ │ │ │ ├── preview-markdown.tsx
│ │ │ │ ├── preview-model.tsx
│ │ │ │ ├── preview-streaming.tsx
│ │ │ │ ├── preview.tsx
│ │ │ │ └── previewenv.ts
│ │ │ ├── quicktipsview/
│ │ │ │ └── quicktipsview.tsx
│ │ │ ├── sysinfo/
│ │ │ │ └── sysinfo.tsx
│ │ │ ├── term/
│ │ │ │ ├── fitaddon.ts
│ │ │ │ ├── ijson.tsx
│ │ │ │ ├── osc-handlers.ts
│ │ │ │ ├── shellblocking.ts
│ │ │ │ ├── term-model.ts
│ │ │ │ ├── term-tooltip.tsx
│ │ │ │ ├── term-wsh.tsx
│ │ │ │ ├── term.scss
│ │ │ │ ├── term.tsx
│ │ │ │ ├── termsticker.tsx
│ │ │ │ ├── termtheme.ts
│ │ │ │ ├── termutil.ts
│ │ │ │ ├── termwrap.ts
│ │ │ │ └── xterm.css
│ │ │ ├── tsunami/
│ │ │ │ └── tsunami.tsx
│ │ │ ├── vdom/
│ │ │ │ ├── vdom-model.tsx
│ │ │ │ ├── vdom-utils.tsx
│ │ │ │ └── vdom.tsx
│ │ │ ├── waveai/
│ │ │ │ ├── waveai.scss
│ │ │ │ └── waveai.tsx
│ │ │ ├── waveconfig/
│ │ │ │ ├── secretscontent.tsx
│ │ │ │ ├── waveaivisual.tsx
│ │ │ │ ├── waveconfig-model.ts
│ │ │ │ ├── waveconfig.tsx
│ │ │ │ └── waveconfigenv.ts
│ │ │ └── webview/
│ │ │ ├── webview.scss
│ │ │ ├── webview.test.tsx
│ │ │ ├── webview.tsx
│ │ │ └── webviewenv.ts
│ │ ├── waveenv/
│ │ │ ├── mockboundary.tsx
│ │ │ ├── waveenv.ts
│ │ │ └── waveenvimpl.ts
│ │ └── workspace/
│ │ ├── widgetfilter.test.ts
│ │ ├── widgetfilter.ts
│ │ ├── widgets.tsx
│ │ ├── workspace-layout-model.ts
│ │ └── workspace.tsx
│ ├── builder/
│ │ ├── app-selection-modal.tsx
│ │ ├── builder-app.tsx
│ │ ├── builder-apppanel.tsx
│ │ ├── builder-buildpanel.tsx
│ │ ├── builder-workspace.tsx
│ │ ├── store/
│ │ │ ├── builder-apppanel-model.ts
│ │ │ ├── builder-buildpanel-model.ts
│ │ │ └── builder-focusmanager.ts
│ │ ├── tabs/
│ │ │ ├── builder-codetab.tsx
│ │ │ ├── builder-configdatatab.tsx
│ │ │ ├── builder-filestab.tsx
│ │ │ ├── builder-previewtab.tsx
│ │ │ └── builder-secrettab.tsx
│ │ └── utils/
│ │ └── builder-focus-utils.ts
│ ├── layout/
│ │ ├── index.ts
│ │ ├── lib/
│ │ │ ├── TileLayout.tsx
│ │ │ ├── layoutAtom.ts
│ │ │ ├── layoutModel.ts
│ │ │ ├── layoutModelHooks.ts
│ │ │ ├── layoutNode.ts
│ │ │ ├── layoutTree.ts
│ │ │ ├── nodeRefMap.ts
│ │ │ ├── tilelayout.scss
│ │ │ ├── types.ts
│ │ │ └── utils.ts
│ │ └── tests/
│ │ ├── layoutNode.test.ts
│ │ ├── layoutTree.test.ts
│ │ ├── model.ts
│ │ └── utils.test.ts
│ ├── preview/
│ │ ├── index.html
│ │ ├── mock/
│ │ │ ├── defaultconfig.ts
│ │ │ ├── mock-node-model.ts
│ │ │ ├── mockfilesystem.ts
│ │ │ ├── mockwaveenv.test.ts
│ │ │ ├── mockwaveenv.ts
│ │ │ ├── preview-electron-api.ts
│ │ │ ├── tabbar-mock.tsx
│ │ │ └── use-rpc-override.ts
│ │ ├── preview-contextmenu.tsx
│ │ ├── preview.css
│ │ ├── preview.tsx
│ │ ├── previews/
│ │ │ ├── .gitkeep
│ │ │ ├── aifilediff.preview-util.ts
│ │ │ ├── aifilediff.preview.test.ts
│ │ │ ├── aifilediff.preview.tsx
│ │ │ ├── modal-about.preview.tsx
│ │ │ ├── onboarding.preview.tsx
│ │ │ ├── sysinfo.preview-util.ts
│ │ │ ├── sysinfo.preview.test.ts
│ │ │ ├── sysinfo.preview.tsx
│ │ │ ├── tab.preview.tsx
│ │ │ ├── tabbar.preview.tsx
│ │ │ ├── treeview.preview.tsx
│ │ │ ├── vtabbar.preview.tsx
│ │ │ ├── web.preview.tsx
│ │ │ └── widgets.preview.tsx
│ │ └── vite.config.ts
│ ├── tailwindsetup.css
│ ├── types/
│ │ ├── custom.d.ts
│ │ ├── gotypes.d.ts
│ │ ├── jsx.d.ts
│ │ ├── media.d.ts
│ │ ├── vite-env.d.ts
│ │ └── waveevent.d.ts
│ ├── util/
│ │ ├── color-validator.test.ts
│ │ ├── color-validator.ts
│ │ ├── endpoints.ts
│ │ ├── fetchutil.ts
│ │ ├── focusutil.ts
│ │ ├── fontutil.ts
│ │ ├── getenv.ts
│ │ ├── historyutil.ts
│ │ ├── ijson.ts
│ │ ├── isdev.ts
│ │ ├── keyutil.ts
│ │ ├── platformutil.ts
│ │ ├── previewutil.ts
│ │ ├── sharedconst.ts
│ │ ├── util.ts
│ │ ├── waveutil.ts
│ │ └── wsutil.ts
│ └── wave.ts
├── go.mod
├── go.sum
├── index.html
├── package.json
├── pkg/
│ ├── aiusechat/
│ │ ├── aiutil/
│ │ │ └── aiutil.go
│ │ ├── anthropic/
│ │ │ ├── anthropic-backend.go
│ │ │ ├── anthropic-backend_test.go
│ │ │ └── anthropic-convertmessage.go
│ │ ├── chatstore/
│ │ │ └── chatstore.go
│ │ ├── gemini/
│ │ │ ├── doc.go
│ │ │ ├── gemini-backend.go
│ │ │ ├── gemini-convertmessage.go
│ │ │ └── gemini-types.go
│ │ ├── google/
│ │ │ ├── doc.go
│ │ │ ├── google-summarize.go
│ │ │ └── google-summarize_test.go
│ │ ├── openai/
│ │ │ ├── openai-backend.go
│ │ │ ├── openai-convertmessage.go
│ │ │ ├── openai-util.go
│ │ │ ├── stream-sample.txt
│ │ │ └── tool-sample.txt
│ │ ├── openaichat/
│ │ │ ├── openaichat-backend.go
│ │ │ ├── openaichat-convertmessage.go
│ │ │ └── openaichat-types.go
│ │ ├── toolapproval.go
│ │ ├── tools.go
│ │ ├── tools_builder.go
│ │ ├── tools_readdir.go
│ │ ├── tools_readdir_test.go
│ │ ├── tools_readfile.go
│ │ ├── tools_screenshot.go
│ │ ├── tools_term.go
│ │ ├── tools_tsunami.go
│ │ ├── tools_web.go
│ │ ├── tools_writefile.go
│ │ ├── uctypes/
│ │ │ └── uctypes.go
│ │ ├── usechat-backend.go
│ │ ├── usechat-mode.go
│ │ ├── usechat-prompts.go
│ │ ├── usechat-utils.go
│ │ ├── usechat.go
│ │ └── usechat_mode_test.go
│ ├── authkey/
│ │ └── authkey.go
│ ├── baseds/
│ │ └── baseds.go
│ ├── blockcontroller/
│ │ ├── .gitignore
│ │ ├── blockcontroller.go
│ │ ├── durableshellcontroller.go
│ │ ├── shellcontroller.go
│ │ └── tsunamicontroller.go
│ ├── blocklogger/
│ │ └── blocklogger.go
│ ├── buildercontroller/
│ │ └── buildercontroller.go
│ ├── eventbus/
│ │ └── eventbus.go
│ ├── faviconcache/
│ │ └── faviconcache.go
│ ├── filebackup/
│ │ └── filebackup.go
│ ├── filestore/
│ │ ├── blockstore.go
│ │ ├── blockstore_cache.go
│ │ ├── blockstore_dbops.go
│ │ ├── blockstore_dbsetup.go
│ │ └── blockstore_test.go
│ ├── genconn/
│ │ ├── genconn.go
│ │ ├── ssh-impl.go
│ │ └── wsl-impl.go
│ ├── gogen/
│ │ ├── gogen.go
│ │ └── gogen_test.go
│ ├── ijson/
│ │ ├── ijson.go
│ │ └── ijson_test.go
│ ├── jobcontroller/
│ │ └── jobcontroller.go
│ ├── jobmanager/
│ │ ├── cirbuf.go
│ │ ├── jobcmd.go
│ │ ├── jobmanager.go
│ │ ├── jobmanager_unix.go
│ │ ├── jobmanager_windows.go
│ │ ├── mainserverconn.go
│ │ ├── streammanager.go
│ │ └── streammanager_test.go
│ ├── panichandler/
│ │ └── panichandler.go
│ ├── remote/
│ │ ├── conncontroller/
│ │ │ ├── conncontroller.go
│ │ │ └── connmonitor.go
│ │ ├── connparse/
│ │ │ ├── connparse.go
│ │ │ └── connparse_test.go
│ │ ├── connutil.go
│ │ ├── fileshare/
│ │ │ ├── fspath/
│ │ │ │ └── fspath.go
│ │ │ ├── fsutil/
│ │ │ │ └── fsutil.go
│ │ │ └── wshfs/
│ │ │ └── wshfs.go
│ │ ├── sshagent_unix.go
│ │ ├── sshagent_unix_test.go
│ │ ├── sshagent_windows.go
│ │ ├── sshagent_windows_test.go
│ │ └── sshclient.go
│ ├── schema/
│ │ └── schema.go
│ ├── secretstore/
│ │ └── secretstore.go
│ ├── service/
│ │ ├── blockservice/
│ │ │ └── blockservice.go
│ │ ├── clientservice/
│ │ │ └── clientservice.go
│ │ ├── objectservice/
│ │ │ └── objectservice.go
│ │ ├── service.go
│ │ ├── userinputservice/
│ │ │ └── userinputservice.go
│ │ ├── windowservice/
│ │ │ └── windowservice.go
│ │ └── workspaceservice/
│ │ └── workspaceservice.go
│ ├── shellexec/
│ │ ├── conninterface.go
│ │ └── shellexec.go
│ ├── streamclient/
│ │ ├── stream_test.go
│ │ ├── streambroker.go
│ │ ├── streambroker_test.go
│ │ ├── streamreader.go
│ │ └── streamwriter.go
│ ├── suggestion/
│ │ ├── filewalk.go
│ │ └── suggestion.go
│ ├── telemetry/
│ │ ├── telemetry.go
│ │ └── telemetrydata/
│ │ └── telemetrydata.go
│ ├── trimquotes/
│ │ └── trimquotes.go
│ ├── tsgen/
│ │ ├── tsgen.go
│ │ ├── tsgen_wshclientapi_test.go
│ │ ├── tsgenevent.go
│ │ ├── tsgenevent_test.go
│ │ └── tsgenmeta/
│ │ └── tsgenmeta.go
│ ├── tsunamiutil/
│ │ └── tsunamiutil.go
│ ├── userinput/
│ │ └── userinput.go
│ ├── util/
│ │ ├── daystr/
│ │ │ ├── daystr.go
│ │ │ └── daystr_test.go
│ │ ├── dbutil/
│ │ │ ├── dbmappable.go
│ │ │ └── dbutil.go
│ │ ├── ds/
│ │ │ ├── expmap.go
│ │ │ ├── syncmap.go
│ │ │ └── syncmap_test.go
│ │ ├── envutil/
│ │ │ └── envutil.go
│ │ ├── fileutil/
│ │ │ ├── fileutil.go
│ │ │ ├── fileutil_test.go
│ │ │ ├── mimetypes.go
│ │ │ └── readdir.go
│ │ ├── iochan/
│ │ │ ├── iochan.go
│ │ │ ├── iochan_test.go
│ │ │ └── iochantypes/
│ │ │ └── iochantypes.go
│ │ ├── iterfn/
│ │ │ ├── iterfn.go
│ │ │ └── iterfn_test.go
│ │ ├── logutil/
│ │ │ └── logutil.go
│ │ ├── logview/
│ │ │ ├── logview.go
│ │ │ └── multibuf.go
│ │ ├── migrateutil/
│ │ │ └── migrateutil.go
│ │ ├── packetparser/
│ │ │ └── packetparser.go
│ │ ├── pamparse/
│ │ │ ├── pamparse.go
│ │ │ └── pamparse_test.go
│ │ ├── readutil/
│ │ │ └── readutil.go
│ │ ├── shellutil/
│ │ │ ├── shellintegration/
│ │ │ │ ├── bash_bashrc.sh
│ │ │ │ ├── bash_preexec.sh
│ │ │ │ ├── fish_wavefish.sh
│ │ │ │ ├── pwsh_wavepwsh.sh
│ │ │ │ ├── zsh_zlogin.sh
│ │ │ │ ├── zsh_zprofile.sh
│ │ │ │ ├── zsh_zshenv.sh
│ │ │ │ └── zsh_zshrc.sh
│ │ │ ├── shellquote.go
│ │ │ ├── shellquote_test.go
│ │ │ ├── shellutil.go
│ │ │ └── tokenswap.go
│ │ ├── sigutil/
│ │ │ ├── sigusr1_notwindows.go
│ │ │ ├── sigusr1_windows.go
│ │ │ └── sigutil.go
│ │ ├── syncbuf/
│ │ │ └── syncbuf.go
│ │ ├── unixutil/
│ │ │ ├── unixutil_unix.go
│ │ │ └── unixutil_windows.go
│ │ └── utilfn/
│ │ ├── compare.go
│ │ ├── marshal.go
│ │ ├── partial.go
│ │ ├── partial_test.go
│ │ ├── streamtolines.go
│ │ └── utilfn.go
│ ├── utilds/
│ │ ├── codederror.go
│ │ ├── idlist.go
│ │ ├── multireaderlinebuffer.go
│ │ ├── quickreorderqueue.go
│ │ ├── quickreorderqueue_test.go
│ │ ├── readerlinebuffer.go
│ │ ├── synccache.go
│ │ ├── versionts.go
│ │ └── workqueue.go
│ ├── vdom/
│ │ ├── cssparser/
│ │ │ ├── cssparser.go
│ │ │ └── cssparser_test.go
│ │ ├── vdom.go
│ │ ├── vdom_comp.go
│ │ ├── vdom_html.go
│ │ ├── vdom_root.go
│ │ ├── vdom_test.go
│ │ └── vdom_types.go
│ ├── waveai/
│ │ ├── anthropicbackend.go
│ │ ├── cloudbackend.go
│ │ ├── googlebackend.go
│ │ ├── openaibackend.go
│ │ ├── perplexitybackend.go
│ │ └── waveai.go
│ ├── waveapp/
│ │ ├── streamingresp.go
│ │ ├── waveapp.go
│ │ └── waveappserverimpl.go
│ ├── waveappstore/
│ │ └── waveappstore.go
│ ├── waveapputil/
│ │ └── waveapputil.go
│ ├── wavebase/
│ │ ├── wavebase-posix.go
│ │ ├── wavebase-win.go
│ │ └── wavebase.go
│ ├── wavejwt/
│ │ └── wavejwt.go
│ ├── waveobj/
│ │ ├── ctxupdate.go
│ │ ├── metaconsts.go
│ │ ├── metamap.go
│ │ ├── objrtinfo.go
│ │ ├── waveobj.go
│ │ ├── wtype.go
│ │ └── wtypemeta.go
│ ├── wcloud/
│ │ ├── wcloud.go
│ │ └── wclouddata.go
│ ├── wconfig/
│ │ ├── defaultconfig/
│ │ │ ├── defaultconfig.go
│ │ │ ├── mimetypes.json
│ │ │ ├── presets/
│ │ │ │ └── ai.json
│ │ │ ├── presets.json
│ │ │ ├── settings.json
│ │ │ ├── termthemes.json
│ │ │ ├── waveai.json
│ │ │ └── widgets.json
│ │ ├── filewatcher.go
│ │ ├── metaconsts.go
│ │ └── settingsconfig.go
│ ├── wcore/
│ │ ├── badge.go
│ │ ├── block.go
│ │ ├── layout.go
│ │ ├── wcore.go
│ │ ├── window.go
│ │ └── workspace.go
│ ├── web/
│ │ ├── sse/
│ │ │ └── ssehandler.go
│ │ ├── web.go
│ │ ├── webcmd/
│ │ │ └── webcmd.go
│ │ ├── webvdomproto.go
│ │ └── ws.go
│ ├── wps/
│ │ ├── wps.go
│ │ └── wpstypes.go
│ ├── wshrpc/
│ │ ├── wshclient/
│ │ │ ├── barerpcclient.go
│ │ │ ├── wshclient.go
│ │ │ └── wshclientutil.go
│ │ ├── wshremote/
│ │ │ ├── sysinfo.go
│ │ │ ├── wshremote.go
│ │ │ ├── wshremote_file.go
│ │ │ └── wshremote_job.go
│ │ ├── wshrpcmeta.go
│ │ ├── wshrpcmeta_test.go
│ │ ├── wshrpctypes.go
│ │ ├── wshrpctypes_builder.go
│ │ ├── wshrpctypes_const.go
│ │ ├── wshrpctypes_file.go
│ │ └── wshserver/
│ │ ├── resolvers.go
│ │ ├── wshserver.go
│ │ └── wshserverutil.go
│ ├── wshutil/
│ │ ├── wshadapter.go
│ │ ├── wshcmdreader.go
│ │ ├── wshevent.go
│ │ ├── wshproxy.go
│ │ ├── wshrouter.go
│ │ ├── wshrouter_controlimpl.go
│ │ ├── wshrpc.go
│ │ ├── wshrpcio.go
│ │ ├── wshstreamadapter.go
│ │ └── wshutil.go
│ ├── wsl/
│ │ ├── wsl-unix.go
│ │ └── wsl-win.go
│ ├── wslconn/
│ │ ├── wsl-util.go
│ │ └── wslconn.go
│ └── wstore/
│ ├── wstore.go
│ ├── wstore_dboldmigration.go
│ ├── wstore_dbops.go
│ ├── wstore_dbsetup.go
│ └── wstore_rtinfo.go
├── postinstall.cjs
├── prettier.config.cjs
├── schema/
│ ├── aipresets.json
│ ├── bgpresets.json
│ ├── connections.json
│ ├── settings.json
│ ├── waveai.json
│ └── widgets.json
├── staticcheck.conf
├── testdriver/
│ └── onboarding.yml
├── tests/
│ └── copytests/
│ ├── cases/
│ │ ├── test000.sh
│ │ ├── test001.sh
│ │ ├── test002.sh
│ │ ├── test003.sh
│ │ ├── test004.sh
│ │ ├── test005.sh
│ │ ├── test006.sh
│ │ ├── test007.sh
│ │ ├── test008.sh
│ │ ├── test009.sh
│ │ ├── test010.sh
│ │ ├── test011.sh
│ │ ├── test012.sh
│ │ ├── test013.sh
│ │ ├── test014.sh
│ │ ├── test015.sh
│ │ ├── test016.sh
│ │ ├── test017.sh
│ │ ├── test018.sh
│ │ ├── test019.sh
│ │ ├── test020.sh
│ │ ├── test021.sh
│ │ ├── test022.sh
│ │ ├── test023.sh
│ │ ├── test024.sh
│ │ ├── test025.sh
│ │ ├── test026.sh
│ │ ├── test027.sh
│ │ ├── test028.sh
│ │ ├── test029.sh
│ │ ├── test030.sh
│ │ ├── test032.sh
│ │ ├── test034.sh
│ │ ├── test036.sh
│ │ ├── test037.sh
│ │ ├── test038.sh
│ │ ├── test040.sh
│ │ ├── test041.sh
│ │ ├── test042.sh
│ │ ├── test043.sh
│ │ ├── test044.sh
│ │ ├── test045.sh
│ │ ├── test046.sh
│ │ ├── test047.sh
│ │ ├── test048.sh
│ │ ├── test049.sh
│ │ ├── test051.sh
│ │ └── test052.sh
│ ├── runner.sh
│ └── testutil.sh
├── tsconfig.json
├── tsunami/
│ ├── .gitignore
│ ├── app/
│ │ ├── atom.go
│ │ ├── defaultclient.go
│ │ └── hooks.go
│ ├── build/
│ │ ├── build-ast.go
│ │ ├── build.go
│ │ └── buildutil.go
│ ├── cmd/
│ │ └── main-tsunami.go
│ ├── demo/
│ │ ├── .gitignore
│ │ ├── cpuchart/
│ │ │ ├── app.go
│ │ │ ├── go.mod
│ │ │ ├── go.sum
│ │ │ └── static/
│ │ │ └── tw.css
│ │ ├── githubaction/
│ │ │ ├── app.go
│ │ │ ├── go.mod
│ │ │ ├── go.sum
│ │ │ └── static/
│ │ │ └── tw.css
│ │ ├── modaltest/
│ │ │ ├── app.go
│ │ │ ├── go.mod
│ │ │ ├── go.sum
│ │ │ └── static/
│ │ │ └── tw.css
│ │ ├── pomodoro/
│ │ │ ├── app.go
│ │ │ ├── go.mod
│ │ │ ├── go.sum
│ │ │ └── static/
│ │ │ └── tw.css
│ │ ├── recharts/
│ │ │ ├── app.go
│ │ │ ├── go.mod
│ │ │ ├── go.sum
│ │ │ └── static/
│ │ │ └── tw.css
│ │ ├── tabletest/
│ │ │ ├── app.go
│ │ │ ├── go.mod
│ │ │ ├── go.sum
│ │ │ └── static/
│ │ │ └── tw.css
│ │ ├── todo/
│ │ │ ├── app.go
│ │ │ ├── go.mod
│ │ │ ├── go.sum
│ │ │ ├── static/
│ │ │ │ └── tw.css
│ │ │ └── style.css
│ │ └── tsunamiconfig/
│ │ ├── app.go
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── static/
│ │ └── tw.css
│ ├── engine/
│ │ ├── asyncnotify.go
│ │ ├── atomimpl.go
│ │ ├── clientimpl.go
│ │ ├── comp.go
│ │ ├── errcomponent.go
│ │ ├── globalctx.go
│ │ ├── hooks.go
│ │ ├── render.go
│ │ ├── render.md
│ │ ├── rootelem.go
│ │ ├── schema.go
│ │ └── serverhandlers.go
│ ├── frontend/
│ │ ├── .gitignore
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── app.tsx
│ │ │ ├── element/
│ │ │ │ ├── markdown.tsx
│ │ │ │ ├── modals.tsx
│ │ │ │ └── tsunamiterm.tsx
│ │ │ ├── input.tsx
│ │ │ ├── main.tsx
│ │ │ ├── model/
│ │ │ │ ├── model-utils.ts
│ │ │ │ └── tsunami-model.tsx
│ │ │ ├── recharts/
│ │ │ │ └── recharts.tsx
│ │ │ ├── tailwind.css
│ │ │ ├── types/
│ │ │ │ ├── custom.d.ts
│ │ │ │ └── vdom.d.ts
│ │ │ ├── util/
│ │ │ │ ├── base64.ts
│ │ │ │ ├── clientid.ts
│ │ │ │ ├── keyutil.ts
│ │ │ │ └── platformutil.ts
│ │ │ └── vdom.tsx
│ │ ├── tsconfig.json
│ │ └── vite.config.ts
│ ├── go.mod
│ ├── go.sum
│ ├── rpctypes/
│ │ └── protocoltypes.go
│ ├── templates/
│ │ ├── app-init.go.tmpl
│ │ ├── app-main.go.tmpl
│ │ ├── empty-gomod.tmpl
│ │ ├── gitignore.tmpl
│ │ ├── package.json.tmpl
│ │ └── tailwind.css
│ ├── tsunamibase/
│ │ └── tsunamibase.go
│ ├── ui/
│ │ └── table.go
│ ├── util/
│ │ ├── compare.go
│ │ ├── marshal.go
│ │ ├── streamtolines.go
│ │ └── util.go
│ └── vdom/
│ ├── vdom.go
│ ├── vdom_test.go
│ └── vdom_types.go
├── version.cjs
└── vitest.config.ts
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
root = true
[*]
end_of_line = lf
insert_final_newline = true
[*.{js,jsx,ts,tsx,cjs,json,yml,yaml,css,less,scss}]
charset = utf-8
indent_style = space
indent_size = 4
[CNAME]
insert_final_newline = false
================================================
FILE: .gitattributes
================================================
* text=auto eol=lf
================================================
FILE: .github/FUNDING.yml
================================================
github: wavetermdev
================================================
FILE: .github/ISSUE_TEMPLATE/bug-report.yml
================================================
name: 🐞 Bug Report
description: Create a bug report to help us improve.
title: "[Bug]: "
labels: ["bug", "triage"]
body:
- type: markdown
attributes:
value: |
## Bug description
- type: textarea
attributes:
label: Current Behavior
description: A concise description of what you're experiencing.
validations:
required: true
- type: textarea
attributes:
label: Expected Behavior
description: A concise description of what you expected to happen.
validations:
required: true
- type: textarea
attributes:
label: Steps To Reproduce
description: Steps to reproduce the behavior.
placeholder: |
1. In this environment...
2. With this config...
3. Run '...'
4. See error...
validations:
required: true
- type: markdown
attributes:
value: |
## Environment details
We require that you provide us the version of Wave you're running so we can track issues across versions. To find the Wave version, go to the app menu (this always visible on macOS, for Windows and Linux, click the `...` button) and navigate to `Wave -> About Wave Terminal`. This will bring up the About modal. Copy the client version and paste it below.
- type: input
attributes:
label: Wave Version
description: The version of Wave you are running
placeholder: v0.8.8
validations:
required: true
- type: dropdown
attributes:
label: Platform
description: The OS platform of the computer where you are running Wave
options:
- macOS
- Linux
- Windows
validations:
required: true
- type: input
attributes:
label: OS Version/Distribution
description: The version of the operating system of the computer where you are running Wave
placeholder: Ubuntu 24.04
validations:
required: false
- type: dropdown
attributes:
label: Architecture
description: The architecture of the computer where you are running Wave
options:
- arm64
- x64
validations:
required: true
- type: markdown
attributes:
value: |
## Extra details
- type: textarea
attributes:
label: Anything else?
description: |
Links? References? Anything that will give us more context about the issue you are encountering!
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
validations:
required: false
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: true
contact_links:
- name: General Question
url: https://github.com/wavetermdev/waveterm/discussions
about: Have a question on something? Start a new discussion thread.
- name: Engage with us directly on Discord
url: https://discord.gg/XfvZ334gwU
about: Join our Discord server to get updates on new features, bug fixes, and more.
- name: Review open issues
url: https://github.com/wavetermdev/waveterm/issues
about: Please check if your issue isn't already there.
================================================
FILE: .github/ISSUE_TEMPLATE/feature-request.yml
================================================
name: 🚀 Feature Request / Idea
description: Suggest a new idea for this project.
title: "[Feature]: "
labels: ["enhancement", "triage"]
body:
- type: textarea
attributes:
label: Feature description
description: Describe the issue in detail and why we should add it. To help us out, please poke through our issue tracker and make sure it's not a duplicate issue. Ex. As a user, I can do [...]
validations:
required: true
- type: textarea
attributes:
label: Implementation Suggestion
description: If you have any suggestions on how to design this feature, list them here.
validations:
required: false
- type: textarea
attributes:
label: Anything else?
description: |
Links? References? Anything that will give us more context about how to deliver your feature!
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
validations:
required: false
================================================
FILE: .github/copilot-instructions.md
================================================
# Wave Terminal — Copilot Instructions
## Project Rules
- See the overview of the project in `.kilocode/rules/overview.md`
- Read and follow all guidelines in `.kilocode/rules/rules.md`
---
## Skill Guides
This project uses a set of "skill" guides — focused how-to documents for common implementation tasks. When your task matches one of the descriptions below, **read the linked SKILL.md file before proceeding** and follow its instructions precisely.
| Skill | File | Description |
| ------------ | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| add-config | `.kilocode/skills/add-config/SKILL.md` | Guide for adding new configuration settings to Wave Terminal. Use when adding a new setting to the configuration system, implementing a new config key, or adding user-customizable settings. |
| add-rpc | `.kilocode/skills/add-rpc/SKILL.md` | Guide for adding new RPC calls to Wave Terminal. Use when implementing new RPC commands, adding server-client communication methods, or extending the RPC interface with new functionality. |
| add-wshcmd | `.kilocode/skills/add-wshcmd/SKILL.md` | Guide for adding new wsh commands to Wave Terminal. Use when implementing new CLI commands, adding command-line functionality, or extending the wsh command interface. |
| context-menu | `.kilocode/skills/context-menu/SKILL.md` | Guide for creating and displaying context menus in Wave Terminal. Use when implementing right-click menus, adding context menu items, creating submenus, or handling menu interactions with checkboxes and separators. |
| create-view | `.kilocode/skills/create-view/SKILL.md` | Guide for implementing a new view type in Wave Terminal. Use when creating a new view component, implementing the ViewModel interface, registering a new view type in BlockRegistry, or adding a new content type to display within blocks. |
| electron-api | `.kilocode/skills/electron-api/SKILL.md` | Guide for adding new Electron APIs to Wave Terminal. Use when implementing new frontend-to-electron communications via preload/IPC. |
| waveenv | `.kilocode/skills/waveenv/SKILL.md` | Guide for creating WaveEnv narrowings in Wave Terminal. Use when writing a named subset type of WaveEnv for a component tree, documenting environmental dependencies, or enabling mock environments for preview/test server usage. |
| wps-events | `.kilocode/skills/wps-events/SKILL.md` | Guide for working with Wave Terminal's WPS (Wave PubSub) event system. Use when implementing new event types, publishing events, subscribing to events, or adding asynchronous communication between components. |
> **How skills work:** Each skill is a self-contained guide covering the exact files to edit, patterns to follow, and steps to take for a specific type of task in this codebase. If your task matches a skill's description, open that SKILL.md and treat it as your primary reference for the implementation.
---
## Preview Server
To run the standalone component preview (no Electron, no backend required):
```
task preview
```
This runs `cd frontend/preview && npx vite` and serves at **http://localhost:7007** (port configured in `frontend/preview/vite.config.ts`).
To build a static preview: `task build:preview`
**Do NOT use any of the following to start the preview — they all launch the full Electron app or serve the wrong content:**
- `npm run dev` — runs `electron-vite dev`, launches Electron
- `npm run start` — also launches Electron
- `npx vite` from the repo root — uses the Electron-Vite config, not the preview app
- Serving the `dist/` directory — the preview app is never built there; it has its own build output
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
day: "friday"
time: "09:00"
timezone: "America/Los_Angeles"
groups:
dev-dependencies-patch:
dependency-type: "development"
exclude-patterns:
- "*storybook*"
- "*electron*"
- "jotai"
- "react"
- "@types/react"
- "*react-dom"
- "*docusaurus*"
update-types:
- "patch"
dev-dependencies-minor:
dependency-type: "development"
exclude-patterns:
- "*storybook*"
- "*electron*"
- "jotai"
- "react"
- "@types/react"
- "*react-dom"
- "*docusaurus*"
update-types:
- "minor"
prod-dependencies-patch:
dependency-type: "production"
exclude-patterns:
- "*storybook*"
- "*electron*"
- "jotai"
- "react"
- "@types/react"
- "*react-dom"
- "*docusaurus*"
update-types:
- "patch"
prod-dependencies-minor:
dependency-type: "production"
exclude-patterns:
- "*storybook*"
- "*electron*"
- "jotai"
- "react"
- "@types/react"
- "*react-dom"
- "*docusaurus*"
update-types:
- "minor"
storybook-patch:
patterns:
- "*storybook*"
update-types:
- "patch"
storybook-minor:
patterns:
- "*storybook*"
update-types:
- "minor"
storybook-major:
patterns:
- "*storybook*"
update-types:
- "major"
electron-patch:
patterns:
- "*electron*"
update-types:
- "patch"
electron-minor:
patterns:
- "*electron*"
update-types:
- "minor"
electron-major:
patterns:
- "*electron*"
update-types:
- "major"
docusaurus-patch:
patterns:
- "*docusaurus*"
update-types:
- "patch"
docusaurus-minor:
patterns:
- "*docusaurus*"
update-types:
- "minor"
docusaurus-major:
patterns:
- "*docusaurus*"
update-types:
- "major"
react-patch:
patterns:
- "react"
- "@types/react"
- "*react-dom"
update-types:
- "patch"
react-minor:
patterns:
- "react"
- "@types/react"
- "*react-dom"
update-types:
- "minor"
react-major:
patterns:
- "react"
- "@types/react"
- "*react-dom"
update-types:
- "major"
jotai-patch:
patterns:
- "jotai"
update-types:
- "patch"
jotai-minor:
patterns:
- "jotai"
update-types:
- "minor"
jotai-major:
patterns:
- "jotai"
update-types:
- "major"
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "weekly"
day: "friday"
time: "09:00"
timezone: "America/Los_Angeles"
- package-ecosystem: "github-actions"
directory: "/.github/workflows"
schedule:
interval: "weekly"
day: "friday"
time: "09:00"
timezone: "America/Los_Angeles"
================================================
FILE: .github/workflows/build-helper.yml
================================================
# Build Helper workflow - Builds, signs, and packages binaries for each supported platform, then uploads to a staging bucket in S3 for wider distribution.
# For more information on the macOS signing and notarization, see https://www.electron.build/code-signing and https://www.electron.build/configuration/mac
# For more information on the Windows Code Signing, see https://docs.digicert.com/en/digicert-keylocker/ci-cd-integrations/plugins/github-custom-action-for-keypair-signing.html and https://docs.digicert.com/en/digicert-keylocker/signing-tools/sign-authenticode-with-electron-builder-using-ksp-integration.html
name: Build Helper
run-name: Build ${{ github.ref_name }}${{ github.event_name == 'workflow_dispatch' && ' - Manual' || '' }}
on:
push:
tags:
- "v[0-9]+.[0-9]+.[0-9]+*"
workflow_dispatch:
env:
GO_VERSION: "1.25.6"
NODE_VERSION: 22
NODE_OPTIONS: --max-old-space-size=4096
jobs:
build-app:
outputs:
version: ${{ steps.set-version.outputs.WAVETERM_VERSION }}
strategy:
matrix:
include:
- platform: "darwin"
runner: "macos-latest"
- platform: "linux"
runner: "ubuntu-latest"
- platform: "linux"
runner: ubuntu-24.04-arm
- platform: "windows"
runner: "windows-latest"
# - platform: "windows"
# runner: "windows-11-arm64-16core"
runs-on: ${{ matrix.runner }}
steps:
- uses: actions/checkout@v6
- name: Install Linux Build Dependencies (Linux only)
if: matrix.platform == 'linux'
run: |
sudo apt-get update
sudo apt-get install --no-install-recommends -y libarchive-tools libopenjp2-tools rpm squashfs-tools
sudo snap install snapcraft --classic
sudo snap install lxd
sudo lxd init --auto
sudo snap refresh
- name: Install Zig (not Mac)
if: matrix.platform != 'darwin'
uses: mlugg/setup-zig@v2
# The pre-installed version of the AWS CLI has a segfault problem so we'll install it via Homebrew instead.
- name: Upgrade AWS CLI (Mac only)
if: matrix.platform == 'darwin'
run: brew install awscli
# The version of FPM that comes bundled with electron-builder doesn't include a Linux ARM target. Installing Gems onto the runner is super quick so we'll just do this for all targets.
- name: Install FPM (not Windows)
if: matrix.platform != 'windows'
run: sudo gem install fpm
- name: Install FPM (Windows only)
if: matrix.platform == 'windows'
run: gem install fpm
# General build dependencies
- uses: actions/setup-go@v6
with:
go-version: ${{env.GO_VERSION}}
cache-dependency-path: |
go.sum
- uses: actions/setup-node@v6
with:
node-version: ${{env.NODE_VERSION}}
cache: npm
cache-dependency-path: package-lock.json
- name: Force git deps to HTTPS
run: |
git config --global url.https://github.com/.insteadof ssh://git@github.com/
git config --global url.https://github.com/.insteadof git@github.com:
- uses: nick-fields/retry@v3
name: npm ci
with:
command: npm ci --no-audit --no-fund
retry_on: error
max_attempts: 3
timeout_minutes: 5
env:
GIT_ASKPASS: "echo"
GIT_TERMINAL_PROMPT: "0"
- name: Install Task
uses: arduino/setup-task@v2
with:
version: 3.x
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: "Set Version"
id: set-version
run: echo "WAVETERM_VERSION=$(task version)" >> "$GITHUB_OUTPUT"
shell: bash
# Windows Code Signing Setup
- name: Set up certificate (Windows only)
if: matrix.platform == 'windows' && github.event_name != 'workflow_dispatch'
run: |
echo "${{ secrets.SM_CLIENT_CERT_FILE_B64 }}" | base64 --decode > /d/Certificate_pkcs12.p12
shell: bash
- name: Set signing variables (Windows only)
if: matrix.platform == 'windows' && github.event_name != 'workflow_dispatch'
id: variables
run: |
echo "SM_HOST=${{ secrets.SM_HOST }}" >> "$GITHUB_ENV"
echo "SM_API_KEY=${{ secrets.SM_API_KEY }}" >> "$GITHUB_ENV"
echo "SM_CODE_SIGNING_CERT_SHA1_HASH=${{ secrets.SM_CODE_SIGNING_CERT_SHA1_HASH }}" >> "$GITHUB_ENV"
echo "SM_CLIENT_CERT_FILE=D:\\Certificate_pkcs12.p12" >> "$GITHUB_ENV"
echo "SM_CLIENT_CERT_FILE=D:\\Certificate_pkcs12.p12" >> "$GITHUB_OUTPUT"
echo "SM_CLIENT_CERT_PASSWORD=${{ secrets.SM_CLIENT_CERT_PASSWORD }}" >> "$GITHUB_ENV"
echo "C:\Program Files (x86)\Windows Kits\10\App Certification Kit" >> $GITHUB_PATH
echo "C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools" >> $GITHUB_PATH
echo "C:\Program Files\DigiCert\DigiCert Keylocker Tools" >> $GITHUB_PATH
shell: bash
- name: Setup Keylocker KSP (Windows only)
if: matrix.platform == 'windows' && github.event_name != 'workflow_dispatch'
run: |
curl -X GET https://one.digicert.com/signingmanager/api-ui/v1/releases/Keylockertools-windows-x64.msi/download -H "x-api-key:%SM_API_KEY%" -o Keylockertools-windows-x64.msi
msiexec /i Keylockertools-windows-x64.msi /quiet /qn
C:\Windows\System32\certutil.exe -csp "DigiCert Signing Manager KSP" -key -user
smctl windows certsync
shell: cmd
# Build and upload packages
- name: Build (Linux)
if: matrix.platform == 'linux'
run: task package
env:
USE_SYSTEM_FPM: true # Ensure that the installed version of FPM is used rather than the bundled one.
SNAPCRAFT_BUILD_ENVIRONMENT: host
# Retry Darwin build in case of notarization failures
- uses: nick-fields/retry@v3
name: Build (Darwin)
if: matrix.platform == 'darwin'
with:
command: task package
timeout_minutes: 120
retry_on: error
max_attempts: 3
env:
USE_SYSTEM_FPM: true # Ensure that the installed version of FPM is used rather than the bundled one.
CSC_LINK: ${{ matrix.platform == 'darwin' && secrets.PROD_MACOS_CERTIFICATE_2}}
CSC_KEY_PASSWORD: ${{ matrix.platform == 'darwin' && secrets.PROD_MACOS_CERTIFICATE_PWD_2 }}
APPLE_ID: ${{ matrix.platform == 'darwin' && secrets.PROD_MACOS_NOTARIZATION_APPLE_ID_2 }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ matrix.platform == 'darwin' && secrets.PROD_MACOS_NOTARIZATION_PWD_2 }}
APPLE_TEAM_ID: ${{ matrix.platform == 'darwin' && secrets.PROD_MACOS_NOTARIZATION_TEAM_ID_2 }}
STATIC_DOCSITE_PATH: ${{env.STATIC_DOCSITE_PATH}}
- name: Build (Windows)
if: matrix.platform == 'windows'
run: task package
env:
USE_SYSTEM_FPM: true # Ensure that the installed version of FPM is used rather than the bundled one.
CSC_LINK: ${{ steps.variables.outputs.SM_CLIENT_CERT_FILE }}
CSC_KEY_PASSWORD: ${{ secrets.SM_CLIENT_CERT_PASSWORD }}
STATIC_DOCSITE_PATH: ${{env.STATIC_DOCSITE_PATH}}
shell: powershell # electron-builder's Windows code signing package has some compatibility issues with pwsh, so we need to use Windows Powershell
# Upload artifacts to the S3 staging and to the workflow output for the draft release job
- name: Upload to S3 staging
if: github.event_name != 'workflow_dispatch'
run: task artifacts:upload
env:
AWS_ACCESS_KEY_ID: "${{ secrets.ARTIFACTS_KEY_ID }}"
AWS_SECRET_ACCESS_KEY: "${{ secrets.ARTIFACTS_KEY_SECRET }}"
AWS_DEFAULT_REGION: us-west-2
- name: Upload artifacts
uses: actions/upload-artifact@v5
with:
name: ${{ matrix.runner }}
path: make
- name: Upload Snapcraft logs on failure
if: failure()
uses: actions/upload-artifact@v5
with:
name: ${{ matrix.runner }}-log
path: /home/runner/.local/state/snapcraft/log
create-release:
runs-on: ubuntu-latest
needs: build-app
permissions:
contents: write
if: ${{ github.event_name != 'workflow_dispatch' }}
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
with:
path: make
merge-multiple: true
- name: Create draft release
uses: softprops/action-gh-release@v2
with:
prerelease: ${{ contains(github.ref_name, '-beta') }}
name: Wave Terminal ${{ github.ref_name }} Release
generate_release_notes: true
draft: true
files: |
make/*.zip
make/*.dmg
make/*.exe
make/*.msi
make/*.rpm
make/*.deb
make/*.pacman
make/*.snap
make/*.flatpak
make/*.AppImage
================================================
FILE: .github/workflows/bump-version.yml
================================================
# Workflow to manage bumping the package version and pushing it to the target branch with a new tag.
# This workflow uses a GitHub App to bypass branch protection and uses the GitHub API directly to ensure commits and tags are signed.
# For more information, see this doc: https://github.com/Nautilus-Cyberneering/pygithub/blob/main/docs/how_to_sign_automatic_commits_in_github_actions.md
name: Bump Version
run-name: "branch: ${{ github.ref_name }}; semver-bump: ${{ inputs.bump }}; prerelease: ${{ inputs.is-prerelease }}"
on:
workflow_dispatch:
inputs:
bump:
description: SemVer Bump
required: true
type: choice
default: none
options:
- none
- patch
- minor
- major
is-prerelease:
description: Is Prerelease
required: true
type: boolean
default: true
env:
NODE_VERSION: 22
jobs:
bump-version:
runs-on: ubuntu-latest
steps:
- name: Get App Token
uses: actions/create-github-app-token@v2
id: app-token
with:
app-id: ${{ vars.WAVE_BUILDER_APPID }}
private-key: ${{ secrets.WAVE_BUILDER_KEY }}
- uses: actions/checkout@v6
with:
token: ${{ steps.app-token.outputs.token }}
# General build dependencies
- uses: actions/setup-node@v6
with:
node-version: ${{env.NODE_VERSION}}
cache: npm
cache-dependency-path: package-lock.json
- uses: nick-fields/retry@v3
name: npm ci
with:
command: npm ci --no-audit --no-fund
retry_on: error
max_attempts: 3
timeout_minutes: 5
- name: Install Task
uses: arduino/setup-task@v2
with:
version: 3.x
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: "Bump Version: ${{ inputs.bump }}"
id: bump-version
run: echo "WAVETERM_VERSION=$( task version -- ${{ inputs.bump }} ${{inputs.is-prerelease}} )" >> "$GITHUB_OUTPUT"
shell: bash
- name: "Push version bump: ${{ steps.bump-version.outputs.WAVETERM_VERSION }}"
if: github.ref_protected
run: |
# Create a new commit for the package version bump in package.json
export VERSION=${{ steps.bump-version.outputs.WAVETERM_VERSION }}
export MESSAGE="chore: bump package version to $VERSION"
export FILE=package.json
export BRANCH=${{github.ref_name}}
export SHA=$( git rev-parse $BRANCH:$FILE )
export CONTENT=$( base64 -i $FILE )
gh api --method PUT /repos/:owner/:repo/contents/$FILE \
--field branch="$BRANCH" \
--field message="$MESSAGE" \
--field content="$CONTENT" \
--field sha="$SHA"
# Fetch the new commit and create a tag referencing it
git fetch
export TAG_SHA=$( git rev-parse origin/$BRANCH )
gh api --method POST /repos/:owner/:repo/git/refs \
--field ref="refs/tags/v$VERSION" \
--field sha="$TAG_SHA"
shell: bash
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
================================================
FILE: .github/workflows/codeql.yml
================================================
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: ["main"]
paths:
- "**/*.go"
- "**/*.ts"
- "**/*.tsx"
pull_request:
branches: ["main"]
paths:
- "**/*.go"
- "**/*.ts"
- "**/*.tsx"
types:
- opened
- synchronize
- reopened
- ready_for_review
schedule:
- cron: "36 5 * * 5"
env:
NODE_VERSION: 22
GO_VERSION: "1.25.6"
jobs:
analyze:
name: Analyze
# Runner size impacts CodeQL analysis time. To learn more, please see:
# - https://gh.io/recommended-hardware-resources-for-running-codeql
# - https://gh.io/supported-runners-and-hardware-resources
# - https://gh.io/using-larger-runners
# Consider using larger runners for possible analysis time improvements.
if: github.event.pull_request.draft == false
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: ["go", "javascript-typescript"]
# CodeQL supports [ 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' ]
# Use only 'java-kotlin' to analyze code written in Java, Kotlin or both
# Use only 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Install Task
uses: arduino/setup-task@v2
with:
version: 3.x
repo-token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/setup-node@v6
with:
node-version: ${{env.NODE_VERSION}}
cache: npm
cache-dependency-path: package-lock.json
- uses: nick-fields/retry@v3
name: npm ci
with:
command: npm ci --no-audit --no-fund
retry_on: error
max_attempts: 3
timeout_minutes: 5
- name: Setup Go
uses: actions/setup-go@v6
with:
go-version: ${{env.GO_VERSION}}
cache-dependency-path: |
go.sum
# We use Zig instead of glibc for cgo compilation as it is more-easily statically linked
- name: Setup Zig
run: sudo snap install zig --classic --beta
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
- name: Generate bindings
run: task generate
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild (not Go)
if: matrix.language != 'go'
uses: github/codeql-action/autobuild@v4
- name: Build (Go only)
if: matrix.language == 'go'
run: |
task build:server
task build:wsh
# ℹ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4
with:
category: "/language:${{matrix.language}}"
================================================
FILE: .github/workflows/copilot-setup-steps.yml
================================================
name: Copilot Setup Steps
on:
workflow_dispatch:
push:
paths: [.github/workflows/copilot-setup-steps.yml]
pull_request:
paths: [.github/workflows/copilot-setup-steps.yml]
# Note: global env vars are NOT used here — they are not reliable in all
# GitHub Actions contexts (e.g. Copilot setup steps). Values are inlined
# directly into each step that needs them.
jobs:
copilot-setup-steps:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v6
# Go + Node versions match your helper
- uses: actions/setup-go@v6
with:
go-version: "1.25.6"
cache-dependency-path: go.sum
- uses: actions/setup-node@v6
with:
node-version: 22
cache: npm
cache-dependency-path: package-lock.json
# Zig is used by your Linux CGO builds (kept available, but we won't build here)
- uses: mlugg/setup-zig@v2
# Task CLI for your Taskfile
- uses: arduino/setup-task@v2
with:
version: 3.x
repo-token: ${{ secrets.GITHUB_TOKEN }}
# Git HTTPS so deps resolve non-interactively
- name: Force git deps to HTTPS
run: |
git config --global url.https://github.com/.insteadof ssh://git@github.com/
git config --global url.https://github.com/.insteadof git@github.com:
# Warm caches only (no builds)
- uses: nick-fields/retry@v3
name: npm ci
with:
command: npm ci --no-audit --no-fund
retry_on: error
max_attempts: 3
timeout_minutes: 5
env:
GIT_ASKPASS: "echo"
GIT_TERMINAL_PROMPT: "0"
- name: Pre-fetch Go modules
env:
GOTOOLCHAIN: auto
run: |
go version
go mod download
================================================
FILE: .github/workflows/deploy-docsite.yml
================================================
name: Docsite CI/CD
run-name: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && 'Build and Deploy' || 'Test Build' }} Docsite
env:
NODE_VERSION: 22
on:
push:
branches:
- main
workflow_dispatch:
# Also run any time a PR is opened targeting the docs
pull_request:
branches:
- main
types:
- opened
- synchronize
- reopened
- ready_for_review
paths:
- "docs/**"
- ".github/workflows/deploy-docsite.yml"
- "Taskfile.yml"
jobs:
build:
name: Build Docsite
runs-on: ubuntu-latest
if: github.event.pull_request.draft == false
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-node@v6
with:
node-version: ${{env.NODE_VERSION}}
cache: npm
cache-dependency-path: package-lock.json
- name: Install Task
uses: arduino/setup-task@v2
with:
version: 3.x
repo-token: ${{ secrets.GITHUB_TOKEN }}
- uses: nick-fields/retry@v3
name: npm ci
with:
command: npm ci --no-audit --no-fund
retry_on: error
max_attempts: 3
timeout_minutes: 5
- name: Build docsite
run: task docsite:build:public
- name: Upload Build Artifact
# Only upload the build artifact when pushed to the main branch
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
uses: actions/upload-pages-artifact@v3
with:
path: docs/build
deploy:
name: Deploy to GitHub Pages
# Only deploy when pushed to the main branch
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
needs: build
# Grant GITHUB_TOKEN the permissions required to make a Pages deployment
permissions:
pages: write # to deploy to Pages
id-token: write # to verify the deployment originates from an appropriate source
# Deploy to the github-pages environment
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
================================================
FILE: .github/workflows/merge-gatekeeper.yml
================================================
---
name: Merge Gatekeeper
on:
pull_request_target:
branches:
- main
- master
types:
- opened
- synchronize
- reopened
- ready_for_review
jobs:
merge-gatekeeper:
runs-on: ubuntu-latest
if: github.event.pull_request.draft == false
# Restrict permissions of the GITHUB_TOKEN.
# Docs: https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs
permissions:
checks: read
statuses: read
steps:
- name: Run Merge Gatekeeper
# NOTE: v1 is updated to reflect the latest v1.x.y. Please use any tag/branch that suits your needs:
# https://github.com/upsidr/merge-gatekeeper/tags
# https://github.com/upsidr/merge-gatekeeper/branches
uses: upsidr/merge-gatekeeper@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
ignored: Build for TestDriver.ai, TestDriver.ai Run, Analyze (go), Analyze (javascript-typescript), License Compliance, CodeRabbit
================================================
FILE: .github/workflows/publish-release.yml
================================================
# Workflow to copy artifacts from the staging bucket to the release bucket when a new GitHub Release is published.
name: Publish Release
run-name: Publish ${{ github.ref_name }}
on:
release:
types: [published]
jobs:
publish-s3:
name: Publish to Releases
if: ${{ startsWith(github.ref, 'refs/tags/') }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Install Task
uses: arduino/setup-task@v2
with:
version: 3.x
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Publish from staging
run: "task artifacts:publish:${{ github.ref_name }}"
env:
AWS_ACCESS_KEY_ID: "${{ secrets.PUBLISHER_KEY_ID }}"
AWS_SECRET_ACCESS_KEY: "${{ secrets.PUBLISHER_KEY_SECRET }}"
AWS_DEFAULT_REGION: us-west-2
shell: bash
publish-snap-amd64:
name: Publish AMD64 Snap
if: ${{ startsWith(github.ref, 'refs/tags/') }}
needs: [publish-s3]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Install Task
uses: arduino/setup-task@v2
with:
version: 3.x
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install Snapcraft
run: sudo snap install snapcraft --classic
shell: bash
- name: Download Snap from Release
uses: robinraju/release-downloader@v1
with:
tag: ${{github.ref_name}}
fileName: "*amd64.snap"
- name: Publish to Snapcraft
run: "task artifacts:snap:publish:${{ github.ref_name }}"
env:
SNAPCRAFT_STORE_CREDENTIALS: "${{secrets.SNAPCRAFT_LOGIN_CREDS}}"
shell: bash
publish-snap-arm64:
name: Publish ARM64 Snap
if: ${{ startsWith(github.ref, 'refs/tags/') }}
needs: [publish-s3]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Install Task
uses: arduino/setup-task@v2
with:
version: 3.x
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install Snapcraft
run: sudo snap install snapcraft --classic
shell: bash
- name: Download Snap from Release
uses: robinraju/release-downloader@v1
with:
tag: ${{github.ref_name}}
fileName: "*arm64.snap"
- name: Publish to Snapcraft
run: "task artifacts:snap:publish:${{ github.ref_name }}"
env:
SNAPCRAFT_STORE_CREDENTIALS: "${{secrets.SNAPCRAFT_LOGIN_CREDS}}"
shell: bash
bump-winget:
name: Submit WinGet PR
if: ${{ startsWith(github.ref, 'refs/tags/') && !contains(github.ref_name, 'beta') }}
needs: [publish-s3]
runs-on: windows-latest
steps:
- uses: actions/checkout@v6
- name: Install Task
uses: arduino/setup-task@v2
with:
version: 3.x
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install wingetcreate
run: winget install -e --silent --accept-package-agreements --accept-source-agreements wingetcreate
shell: pwsh
- name: Submit WinGet version bump
run: "task artifacts:winget:publish:${{ github.ref_name }}"
env:
GITHUB_TOKEN: ${{ secrets.WINGET_BUMP_PAT }}
shell: pwsh
================================================
FILE: .github/workflows/testdriver-build.yml
================================================
name: TestDriver.ai Build
on:
push:
branches:
- main
tags:
- "v[0-9]+.[0-9]+.[0-9]+*"
pull_request:
# branches:
# - main
# paths-ignore:
# - "docs/**"
# - ".storybook/**"
# - ".vscode/**"
# - ".editorconfig"
# - ".gitignore"
# - ".prettierrc"
# - ".eslintrc.js"
# - "**/*.md"
types:
- opened
- synchronize
- reopened
- ready_for_review
schedule:
- cron: 0 21 * * *
workflow_dispatch: null
env:
GO_VERSION: "1.25.6"
NODE_VERSION: 22
permissions:
contents: read # To allow the action to read repository contents
pull-requests: write # To allow the action to create/update pull request comments
jobs:
build_and_upload:
name: Build for TestDriver.ai
runs-on: windows-latest
if: github.event.pull_request.draft == false
steps:
- uses: actions/checkout@v6
# General build dependencies
- uses: actions/setup-go@v6
with:
go-version: ${{env.GO_VERSION}}
- uses: actions/setup-node@v6
with:
node-version: ${{env.NODE_VERSION}}
cache: npm
cache-dependency-path: package-lock.json
- uses: nick-fields/retry@v3
name: npm ci
with:
command: npm ci --no-audit --no-fund
retry_on: error
max_attempts: 3
timeout_minutes: 5
- name: Install Task
uses: arduino/setup-task@v2
with:
version: 3.x
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install Zig
uses: mlugg/setup-zig@v2
- name: Build
run: task package
env:
USE_SYSTEM_FPM: true # Ensure that the installed version of FPM is used rather than the bundled one.
CSC_IDENTITY_AUTO_DISCOVERY: false # disable codesign
shell: powershell # electron-builder's Windows code signing package has some compatibility issues with pwsh, so we need to use Windows Powershell
# Upload .exe as an artifact
- name: Upload .exe artifact
id: upload
uses: actions/upload-artifact@v5
with:
name: windows-exe
path: make/*.exe
================================================
FILE: .github/workflows/testdriver.yml
================================================
name: TestDriver.ai Run
on:
workflow_run:
workflows: ["TestDriver.ai Build"]
types:
- completed
env:
GO_VERSION: "1.25.6"
NODE_VERSION: 22
permissions:
contents: read
statuses: write
jobs:
context:
runs-on: ubuntu-22.04
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- name: Dump job context
env:
JOB_CONTEXT: ${{ toJson(job) }}
run: echo "$JOB_CONTEXT"
- name: Dump steps context
env:
STEPS_CONTEXT: ${{ toJson(steps) }}
run: echo "$STEPS_CONTEXT"
- name: Dump runner context
env:
RUNNER_CONTEXT: ${{ toJson(runner) }}
run: echo "$RUNNER_CONTEXT"
- name: Dump strategy context
env:
STRATEGY_CONTEXT: ${{ toJson(strategy) }}
run: echo "$STRATEGY_CONTEXT"
- name: Dump matrix context
env:
MATRIX_CONTEXT: ${{ toJson(matrix) }}
run: echo "$MATRIX_CONTEXT"
run_testdriver:
name: Run TestDriver.ai
runs-on: windows-latest
if: github.event.workflow_run.conclusion == 'success'
steps:
- uses: testdriverai/action@main
id: testdriver
env:
FORCE_COLOR: "3"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
key: ${{ secrets.DASHCAM_API }}
prerun: |
$headers = @{
Authorization = "token ${{ secrets.GITHUB_TOKEN }}"
}
$downloadFolder = "./download"
$artifactFileName = "waveterm.exe"
$artifactFilePath = "$downloadFolder/$artifactFileName"
Write-Host "Starting the artifact download process..."
# Create the download directory if it doesn't exist
if (-not (Test-Path -Path $downloadFolder)) {
Write-Host "Creating download folder..."
mkdir $downloadFolder
} else {
Write-Host "Download folder already exists."
}
# Fetch the artifact upload URL
Write-Host "Fetching the artifact upload URL..."
$artifactUrl = (Invoke-RestMethod -Uri "https://api.github.com/repos/${{ github.repository }}/actions/runs/${{ github.event.workflow_run.id }}/artifacts" -Headers $headers).artifacts[0].archive_download_url
if ($artifactUrl) {
Write-Host "Artifact URL successfully fetched: $artifactUrl"
} else {
Write-Error "Failed to fetch the artifact URL."
exit 1
}
# Download the artifact (zipped file)
Write-Host "Starting artifact download..."
$artifactZipPath = "$env:TEMP\artifact.zip"
try {
Invoke-WebRequest -Uri $artifactUrl `
-Headers $headers `
-OutFile $artifactZipPath `
-MaximumRedirection 5
Write-Host "Artifact downloaded successfully to $artifactZipPath"
} catch {
Write-Error "Error downloading artifact: $_"
exit 1
}
# Unzip the artifact
$artifactUnzipPath = "$env:TEMP\artifact"
Write-Host "Unzipping the artifact to $artifactUnzipPath..."
try {
Expand-Archive -Path $artifactZipPath -DestinationPath $artifactUnzipPath -Force
Write-Host "Artifact unzipped successfully to $artifactUnzipPath"
} catch {
Write-Error "Failed to unzip the artifact: $_"
exit 1
}
# Find the installer or app executable
$artifactInstallerPath = Get-ChildItem -Path $artifactUnzipPath -Filter *.exe -Recurse | Select-Object -First 1
if ($artifactInstallerPath) {
Write-Host "Executable file found: $($artifactInstallerPath.FullName)"
} else {
Write-Error "Executable file not found. Exiting."
exit 1
}
# Run the installer and log the result
Write-Host "Running the installer: $($artifactInstallerPath.FullName)..."
try {
Start-Process -FilePath $artifactInstallerPath.FullName -Wait
Write-Host "Installer ran successfully."
} catch {
Write-Error "Failed to run the installer: $_"
exit 1
}
# Optional: If the app executable is different from the installer, find and launch it
$wavePath = Join-Path $env:USERPROFILE "AppData\Local\Programs\waveterm\Wave.exe"
Write-Host "Launching the application: $($wavePath)"
Start-Process -FilePath $wavePath
Write-Host "Application launched."
prompt: |
1. /run testdriver/onboarding.yml
================================================
FILE: .gitignore
================================================
.task
frontend/dist
dist/
dist-dev/
frontend/node_modules
node_modules/
frontend/bindings
bindings/
*.log
bin/
*.dmg
*.exe
.DS_Store
*~
out/
make/
artifacts/
mikework/
aiplans/
manifests/
.env
out
# Yarn Modern
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
*storybook.log
storybook-static/
test-results.xml
docsite/
.kilo-format-temp-*
================================================
FILE: .golangci.yml
================================================
version: 2
linters:
disable:
- unused
issues:
exclude-rules:
- linters:
- unused
text: "unused parameter"
================================================
FILE: .kilocode/rules/overview.md
================================================
# Wave Terminal - High Level Architecture Overview
## Project Description
Wave Terminal is an open-source AI-native terminal built for seamless workflows. It's an Electron application that serves as a command line terminal host (it hosts CLI applications rather than running inside a CLI). The application combines a React frontend with a Go backend server to provide a modern terminal experience with advanced features.
## Top-Level Directory Structure
```
waveterm/
├── emain/ # Electron main process code
├── frontend/ # React application (renderer process)
├── cmd/ # Go command-line applications
├── pkg/ # Go packages/modules
├── db/ # Database migrations
├── docs/ # Documentation (Docusaurus)
├── build/ # Build configuration and assets
├── assets/ # Application assets (icons, images)
├── public/ # Static public assets
├── tests/ # Test files
├── .github/ # GitHub workflows and configuration
└── Configuration files (package.json, tsconfig.json, etc.)
```
## Architecture Components
### 1. Electron Main Process (`emain/`)
The Electron main process handles the native desktop application layer:
**Key Files:**
- [`emain.ts`](emain/emain.ts) - Main entry point, application lifecycle management
- [`emain-window.ts`](emain/emain-window.ts) - Window management (`WaveBrowserWindow` class)
- [`emain-tabview.ts`](emain/emain-tabview.ts) - Tab view management (`WaveTabView` class)
- [`emain-wavesrv.ts`](emain/emain-wavesrv.ts) - Go backend server integration
- [`emain-wsh.ts`](emain/emain-wsh.ts) - WSH (Wave Shell) client integration
- [`emain-ipc.ts`](emain/emain-ipc.ts) - IPC handlers for frontend ↔ main process communication
- [`emain-menu.ts`](emain/emain-menu.ts) - Application menu system
- [`updater.ts`](emain/updater.ts) - Auto-update functionality
- [`preload.ts`](emain/preload.ts) - Preload script for renderer security
- [`preload-webview.ts`](emain/preload-webview.ts) - Webview preload script
### 2. Frontend React Application (`frontend/`)
The React application runs in the Electron renderer process:
**Structure:**
```
frontend/
├── app/ # Main application code
│ ├── app.tsx # Root App component
│ ├── aipanel/ # AI panel UI
│ ├── block/ # Block-based UI components
│ ├── element/ # Reusable UI elements
│ ├── hook/ # Custom React hooks
│ ├── modals/ # Modal components
│ ├── store/ # State management (Jotai)
│ ├── tab/ # Tab components
│ ├── view/ # Different view types
│ │ ├── codeeditor/ # Code editor (Monaco)
│ │ ├── preview/ # File preview
│ │ ├── sysinfo/ # System info view
│ │ ├── term/ # Terminal view
│ │ ├── tsunami/ # Tsunami builder view
│ │ ├── vdom/ # Virtual DOM view
│ │ ├── waveai/ # AI chat integration
│ │ ├── waveconfig/ # Config editor view
│ │ └── webview/ # Web view
│ └── workspace/ # Workspace management
├── builder/ # Builder app entry
├── layout/ # Layout system
├── preview/ # Standalone preview renderer
├── types/ # TypeScript type definitions
└── util/ # Utility functions
```
**Key Technologies:**
- Electron (desktop application shell)
- React 19 with TypeScript
- Jotai for state management
- Monaco Editor for code editing
- XTerm.js for terminal emulation
- Tailwind CSS v4 for styling
- SCSS for additional styling (deprecated, new components should use Tailwind)
- Vite / electron-vite for bundling
- Task (Taskfile.yml) for build and code generation commands
### 3. Go Backend Server (`cmd/server/`)
The Go backend server handles all heavy lifting operations:
**Entry Point:** [`main-server.go`](cmd/server/main-server.go)
### 4. Go Packages (`pkg/`)
The Go codebase is organized into modular packages:
**Key Packages:**
- `wstore/` - Database and storage layer
- `wconfig/` - Configuration management
- `wcore/` - Core business logic
- `wshrpc/` - RPC communication system
- `wshutil/` - WSH (Wave Shell) utilities
- `blockcontroller/` - Block execution management
- `remote/` - Remote connection handling
- `filestore/` - File storage system
- `web/` - Web server and WebSocket handling
- `telemetry/` - Usage analytics and telemetry
- `waveobj/` - Core data objects
- `service/` - Service layer
- `wps/` - Wave PubSub event system
- `waveai/` - AI functionality
- `shellexec/` - Shell execution
- `util/` - Common utilities
### 5. Command Line Tools (`cmd/`)
Key Go command-line utilities:
- `wsh/` - Wave Shell command-line tool
- `server/` - Main backend server
- `generatego/` - Code generation
- `generateschema/` - Schema generation
- `generatets/` - TypeScript generation
## Communication Architecture
The core communication system is built around the **WSH RPC (Wave Shell RPC)** system, which provides a unified interface for all inter-process communication: frontend ↔ Go backend, Electron main process ↔ backend, and backend ↔ remote systems (SSH, WSL).
### WSH RPC System (`pkg/wshrpc/`)
The WSH RPC system is the backbone of Wave Terminal's communication architecture:
**Key Components:**
- [`wshrpctypes.go`](pkg/wshrpc/wshrpctypes.go) - Core RPC interface and type definitions (source of truth for all RPC commands)
- [`wshserver/`](pkg/wshrpc/wshserver/) - Server-side RPC implementation
- [`wshremote/`](pkg/wshrpc/wshremote/) - Remote connection handling
- [`wshclient.go`](pkg/wshrpc/wshclient.go) - Go client for making RPC calls
- [`frontend/app/store/wshclientapi.ts`](frontend/app/store/wshclientapi.ts) - Generated TypeScript RPC client
**Routing:** Callers address RPC calls using _routes_ (e.g. a block ID, connection name, or `"waveapp"`) rather than caring about the underlying transport. The RPC layer resolves the route to the correct transport (WebSocket, Unix socket, SSH tunnel, stdio) automatically. This means the same RPC interface works whether the target is local or a remote SSH connection.
## Development Notes
- **Build commands** - Use `task` (Taskfile.yml) for all build, generate, and packaging commands
- **Code generation** - Run `task generate` after modifying Go types in `pkg/wshrpc/wshrpctypes.go`, `pkg/wconfig/settingsconfig.go`, or `pkg/waveobj/wtypemeta.go`
- **Testing** - Vitest for frontend unit tests; standard `go test` for Go packages
- **Database migrations** - SQL migration files in `db/migrations-wstore/` and `db/migrations-filestore/`
- **Documentation** - Docusaurus site in `docs/`
================================================
FILE: .kilocode/rules/rules.md
================================================
Wave Terminal is a modern terminal which provides graphical blocks, dynamic layout, workspaces, and SSH connection management. It is cross platform and built on electron.
### Project Structure
It has a TypeScript/React frontend and a Go backend. They talk together over `wshrpc` a custom RPC protocol that is implemented over websocket (and domain sockets).
### Coding Guidelines
- **Go Conventions**:
- Don't use custom enum types in Go. Instead, use string constants (e.g., `const StatusRunning = "running"` rather than creating a custom type like `type Status string`).
- Use string constants for status values, packet types, and other string-based enumerations.
- in Go code, prefer using Printf() vs Println()
- use "Make" as opposed to "New" for struct initialization func names
- in general const decls go at the top of the file (before types and functions)
- NEVER run `go build` (especially in weird sub-package directories). we can tell if everything compiles by seeing there are no problems/errors.
- **Synchronization**:
- Always prefer to use the `lock.Lock(); defer lock.Unlock()` pattern for synchronization if possible
- Avoid inline lock/unlock pairs - instead create helper functions that use the defer pattern
- When accessing shared data structures (maps, slices, etc.), ensure proper locking
- Example: Instead of `gc.lock.Lock(); gc.map[key]++; gc.lock.Unlock()`, create a helper function like `getNextValue(key string) int { gc.lock.Lock(); defer gc.lock.Unlock(); gc.map[key]++; return gc.map[key] }`
- **TypeScript Imports**:
- Use `@/...` for imports from different parts of the project (configured in `tsconfig.json` as `"@/*": ["frontend/*"]`).
- Prefer relative imports (`"./name"`) only within the same directory.
- Use named exports exclusively; avoid default exports. It's acceptable to export functions directly (e.g., React Components).
- Our indent is 4 spaces
- **JSON Field Naming**: All fields must be lowercase, without underscores.
- **TypeScript Conventions**
- **Type Handling**:
- In TypeScript we have strict null checks off, so no need to add "| null" to all the types.
- In TypeScript for Jotai atoms, if we want to write, we need to type the atom as a PrimitiveAtom<Type>
- Jotai has a bug with strict null checks off where if you create a null atom, e.g. atom(null) it does not "type" correctly. That's no issue, just cast it to the proper PrimitiveAtom type (no "| null") and it will work fine.
- Generally never use "=== undefined" or "!== undefined". This is bad style. Just use a "== null" or "!= null" unless it is a very specific case where we need to distinguish undefined from null.
- **Coding Style**:
- Use all lowercase filenames (except where case is actually important like Taskfile.yml)
- Import the "cn" function from "@/util/util" to do classname / clsx class merge (it uses twMerge underneath)
- For element variants use class-variance-authority
- Do NOT create private fields in classes (they are impossible to inspect)
- Use PascalCase for global consts at the top of files
- **Component Practices**:
- Make sure to add cursor-pointer to buttons/links and clickable items
- NEVER use cursor-help (it looks terrible)
- useAtom() and useAtomValue() are react HOOKS, so they must be called at the component level not inline in JSX
- If you use React.memo(), make sure to add a displayName for the component
- Other
- never use atob() or btoa() (not UTF-8 safe). use functions in frontend/util/util.ts for base64 decoding and encoding
- In general, when writing functions, we prefer _early returns_ rather than putting the majority of a function inside of an if block.
### Styling
- We use **Tailwind v4** to style. Custom stuff is defined in frontend/tailwindsetup.css
- _never_ use cursor-help, or cursor-not-allowed (it looks terrible)
- We have custom CSS setup as well, so it is a hybrid system. For new code we prefer tailwind, and are working to migrate code to all use tailwind.
- For accent buttons, use "bg-accent/80 text-primary rounded hover:bg-accent transition-colors cursor-pointer" (if you do "bg-accent hover:bg-accent/80" it looks weird as on hover the button gets darker instead of lighter)
### RPC System
To define a new RPC call, add the new definition to `pkg/wshrpc/wshrpctypes.go` including any input/output data that is required. After modifying wshrpctypes.go run `task generate` to generate the client APIs.
For normal "server" RPCs (where a frontend client is calling the main server) you should implement the RPC call in `pkg/wshrpc/wshserver.go`.
### Electron API
From within the FE to get the electron API (e.g. the preload functions):
```ts
import { getApi } from "@/store/global";
getApi().getIsDev();
```
The full API is defined in custom.d.ts as type ElectronApi.
### Code Generation
- **TypeScript Types**: TypeScript types are automatically generated from Go types. After modifying Go types in `pkg/wshrpc/wshrpctypes.go`, run `task generate` to update the TypeScript type definitions in `frontend/types/gotypes.d.ts`.
- **Manual Edits**: Do not manually edit generated files like `frontend/types/gotypes.d.ts` or `frontend/app/store/wshclientapi.ts`. Instead, modify the source Go types and run `task generate`.
### Frontend Architecture
- The application uses Jotai for state management.
- When working with Jotai atoms that need to be updated, define them as `PrimitiveAtom<Type>` rather than just `atom<Type>`.
### Notes
- **CRITICAL: Completion format MUST be: "Done: [one-line description]"**
- **Keep your Task Completed summaries VERY short**
- **No lengthy pre-completion summaries** - Do not provide detailed explanations of implementation before using attempt_completion
- **No recaps of changes** - Skip explaining what was done before completion
- **Go directly to completion** - After making changes, proceed directly to attempt_completion without summarizing
- The project is currently an un-released POC / MVP. Do not worry about backward compatibility when making changes
- With React hooks, always complete all hook calls at the top level before any conditional returns (including jotai hook calls useAtom and useAtomValue); when a user explicitly tells you a function handles null inputs, trust them and stop trying to "protect" it with unnecessary checks or workarounds.
- **Match response length to question complexity** - For simple, direct questions in Ask mode (especially those that can be answered in 1-2 sentences), provide equally brief answers. Save detailed explanations for complex topics or when explicitly requested.
- **CRITICAL** - useAtomValue and useAtom are React HOOKS. They cannot be used inline in JSX code, they must appear at the top of a component in the hooks area of the react code.
- for simple functions, we prefer `if (!cond) { return }; functionality;` pattern over `if (cond) { functionality }` because it produces less indentation and is easier to follow.
- It is now 2026, so if you write new files, or update files use 2026 for the copyright year
- React.MutableRefObject is deprecated, just use React.RefObject now (in React 19 RefObject is always mutable)
### Strict Comment Rules
- **NEVER add comments that merely describe what code is doing**:
- ❌ `mutex.Lock() // Lock the mutex`
- ❌ `counter++ // Increment the counter`
- ❌ `buffer.Write(data) // Write data to buffer`
- ❌ `// Header component for app run list` (above AppRunListHeader)
- ❌ `// Updated function to include onClick parameter`
- ❌ `// Changed padding calculation`
- ❌ `// Removed unnecessary div`
- ❌ `// Using the model's width value here`
- **Only use comments for**:
- Explaining WHY a particular approach was chosen
- Documenting non-obvious edge cases or side effects
- Warning about potential pitfalls in usage
- Explaining complex algorithms that can't be simplified
- **When in doubt, leave it out**. No comment is better than a redundant comment.
- **Never add comments explaining code changes** - The code should speak for itself, and version control tracks changes. The one exception to this rule is if it is a very unobvious implementation. Something that someone would typically implement in a different (wrong) way. Then the comment helps us remember WHY we changed it to a less obvious implementation.
- **Never remove existing comments** unless specifically directed by the user. Comments that are already defined in existing code have been vetted by the user.
### Jotai Model Pattern (our rules)
- **Atoms live on the model.**
- **Simple atoms:** define as **field initializers**.
- **Atoms that depend on values/other atoms:** create in the **constructor**.
- Models **never use React hooks**; they use `globalStore.get/set`.
- It's fine to call model methods from **event handlers** or **`useEffect`**.
- Models use the **singleton pattern** with a `private static instance` field, a `private constructor`, and a `static getInstance()` method.
- The constructor is `private`; callers always use `getInstance()`.
```ts
// model/MyModel.ts
import * as jotai from "jotai";
import { globalStore } from "@/app/store/jotaiStore";
export class MyModel {
private static instance: MyModel | null = null;
// simple atoms (field init)
statusAtom = jotai.atom<"idle" | "running" | "error">("idle");
outputAtom = jotai.atom("");
// ctor-built atoms (need types)
lengthAtom!: jotai.Atom<number>;
thresholdedAtom!: jotai.Atom<boolean>;
private constructor(initialThreshold = 20) {
this.lengthAtom = jotai.atom((get) => get(this.outputAtom).length);
this.thresholdedAtom = jotai.atom((get) => get(this.lengthAtom) > initialThreshold);
}
static getInstance(): MyModel {
if (!MyModel.instance) {
MyModel.instance = new MyModel();
}
return MyModel.instance;
}
static resetInstance(): void {
MyModel.instance = null;
}
async doWork() {
globalStore.set(this.statusAtom, "running");
// ... do work ...
globalStore.set(this.statusAtom, "idle");
}
}
```
```tsx
// component usage (events & effects OK)
import { useAtomValue } from "jotai";
function Panel() {
const model = MyModel.getInstance();
const status = useAtomValue(model.statusAtom);
const isBig = useAtomValue(model.thresholdedAtom);
const onClick = () => model.doWork();
return (
<div>
{status} • {String(isBig)}
</div>
);
}
```
**Remember:** singleton pattern with `getInstance()`, `private constructor`, atoms on the model, simple-as-fields, ctor for dependent/derived, updates via `globalStore.set/get`.
**Note** Older models may not use the singleton pattern
### Tool Use
Do NOT use write_to_file unless it is a new file or very short. Always prefer to use replace_in_file. Often your diffs fail when a file may be out of date in your cache vs the actual on-disk format. You should RE-READ the file and try to create diffs again if your diffs fail rather than fall back to write_to_file. If you feel like your ONLY option is to use write_to_file please ask first.
Also when adding content to the end of files prefer to use the new append_file tool rather than trying to create a diff (as your diffs are often not specific enough and end up inserting code in the middle of existing functions).
### Directory Awareness
- **ALWAYS verify the current working directory before executing commands**
- Either run "pwd" first to verify the directory, or do a "cd" to the correct absolute directory before running commands
- When running tests, do not "cd" to the pkg directory and then run the test. This screws up the cwd and you never recover. run the test from the project root instead.
### Testing / Compiling Go Code
No need to run a `go build` or a `go run` to just check if the Go code compiles. VSCode's errors/problems cover this well.
If there are no Go errors in VSCode you can assume the code compiles fine.
================================================
FILE: .kilocode/skills/add-config/SKILL.md
================================================
---
name: add-config
description: Guide for adding new configuration settings to Wave Terminal. Use when adding a new setting to the configuration system, implementing a new config key, or adding user-customizable settings.
---
# Adding a New Configuration Setting to Wave Terminal
This guide explains how to add a new configuration setting to Wave Terminal's hierarchical configuration system.
## Configuration System Overview
Wave Terminal uses a hierarchical configuration system with:
1. **Go Struct Definitions** - Type-safe configuration structure in `pkg/wconfig/settingsconfig.go`
2. **JSON Schema** - Auto-generated validation schema in `schema/settings.json`
3. **Default Values** - Built-in defaults in `pkg/wconfig/defaultconfig/settings.json`
4. **User Configuration** - User overrides in `~/.config/waveterm/settings.json`
5. **Block Metadata** - Block-level overrides in `pkg/waveobj/wtypemeta.go`
6. **Documentation** - User-facing docs in `docs/docs/config.mdx`
Settings cascade from defaults → user settings → connection config → block overrides.
## Step-by-Step Guide
### Step 1: Add to Go Struct Definition
Edit `pkg/wconfig/settingsconfig.go` and add your new field to the `SettingsType` struct:
```go
type SettingsType struct {
// ... existing fields ...
// Add your new field with appropriate JSON tag
MyNewSetting string `json:"mynew:setting,omitempty"`
// For different types:
MyBoolSetting bool `json:"mynew:boolsetting,omitempty"`
MyNumberSetting float64 `json:"mynew:numbersetting,omitempty"`
MyIntSetting *int64 `json:"mynew:intsetting,omitempty"` // Use pointer for optional ints
MyArraySetting []string `json:"mynew:arraysetting,omitempty"`
}
```
**Naming Conventions:**
- Use namespace prefixes (e.g., `term:`, `window:`, `ai:`, `web:`, `app:`)
- Use lowercase with colons as separators
- Field names should be descriptive and follow Go naming conventions
- Use `omitempty` tag to exclude empty values from JSON
**Type Guidelines:**
- Use `*int64` and `*float64` for optional numeric values
- Use `*bool` for optional boolean values (or `bool` if default is false)
- Use `string` for text values
- Use `[]string` for arrays
- Use `float64` for numbers that can be decimals
**Namespace Organization:**
- `app:*` - Application-level settings
- `term:*` - Terminal-specific settings
- `window:*` - Window and UI settings
- `ai:*` - AI-related settings
- `web:*` - Web browser settings
- `editor:*` - Code editor settings
- `conn:*` - Connection settings
### Step 1.5: Add to Block Metadata (Optional)
If your setting should support block-level overrides, also add it to `pkg/waveobj/wtypemeta.go`:
```go
type MetaTSType struct {
// ... existing fields ...
// Add your new field with matching JSON tag and type
MyNewSetting *string `json:"mynew:setting,omitempty"` // Use pointer for optional values
// For different types:
MyBoolSetting *bool `json:"mynew:boolsetting,omitempty"`
MyNumberSetting *float64 `json:"mynew:numbersetting,omitempty"`
MyIntSetting *int `json:"mynew:intsetting,omitempty"`
MyArraySetting []string `json:"mynew:arraysetting,omitempty"`
}
```
**Block Metadata Guidelines:**
- Use pointer types (`*string`, `*bool`, `*int`, `*float64`) for optional overrides
- JSON tags should exactly match the corresponding settings field
- This enables the hierarchical config system: block metadata → connection config → global settings
- Only add settings here that make sense to override per-block or per-connection
### Step 2: Set Default Value (Optional)
If your setting should have a default value, add it to `pkg/wconfig/defaultconfig/settings.json`:
```json
{
"ai:preset": "ai@global",
"ai:model": "gpt-5-mini",
// ... existing defaults ...
"mynew:setting": "default value",
"mynew:boolsetting": true,
"mynew:numbersetting": 42.5,
"mynew:intsetting": 100
}
```
**Default Value Guidelines:**
- Only add defaults for settings that should have non-zero/non-empty initial values
- Ensure defaults make sense for typical user experience
- Keep defaults conservative and safe
- Boolean settings often don't need defaults if `false` is the correct default
### Step 3: Update Documentation
Add your new setting to the configuration table in `docs/docs/config.mdx`:
```markdown
| Key Name | Type | Function |
| ------------------- | -------- | ----------------------------------------- |
| mynew:setting | string | Description of what this setting controls |
| mynew:boolsetting | bool | Enable/disable some feature |
| mynew:numbersetting | float | Numeric setting for some parameter |
| mynew:intsetting | int | Integer setting for some configuration |
| mynew:arraysetting | string[] | Array of strings for multiple values |
```
**Documentation Guidelines:**
- Provide clear, concise descriptions
- For new settings in upcoming releases, add `<VersionBadge version="v0.14" />`
- Update the default configuration example if you added defaults
- Explain what values are valid and what they do
### Step 4: Regenerate Schema and TypeScript Types
Run the generate task to automatically regenerate the JSON schema and TypeScript types:
```bash
task generate
```
**What this does:**
- Runs `task build:schema` (automatically generates JSON schema from Go structs)
- Generates TypeScript type definitions in `frontend/types/gotypes.d.ts`
- Generates RPC client APIs
- Generates metadata constants
**Important:** The JSON schema in `schema/settings.json` is **automatically generated** from the Go struct definitions - you don't need to edit it manually.
### Step 5: Use in Frontend Code
Access your new setting in React components:
```typescript
import { getOverrideConfigAtom, getSettingsKeyAtom, useAtomValue } from "@/store/global";
// In a React component
const MyComponent = ({ blockId }: { blockId: string }) => {
// Use override config atom for hierarchical resolution
// This automatically checks: block metadata → connection config → global settings → default
const mySettingAtom = getOverrideConfigAtom(blockId, "mynew:setting");
const mySetting = useAtomValue(mySettingAtom) ?? "fallback value";
// For global-only settings (no block overrides)
const globalOnlySetting = useAtomValue(getSettingsKeyAtom("mynew:globalsetting")) ?? "fallback";
return <div>Setting value: {mySetting}</div>;
};
```
**Frontend Configuration Patterns:**
```typescript
// 1. Settings with block-level overrides (recommended for most view/display settings)
const termFontSize = useAtomValue(getOverrideConfigAtom(blockId, "term:fontsize")) ?? 12;
// 2. Global-only settings (app-wide settings that don't vary by block)
const appGlobalHotkey = useAtomValue(getSettingsKeyAtom("app:globalhotkey")) ?? "";
// 3. Connection-specific settings
const connStatus = useAtomValue(getConnStatusAtom(connectionName));
```
**When to use each pattern:**
- Use `getOverrideConfigAtom()` for settings that can vary by block or connection (most UI/display settings)
- Use `getSettingsKeyAtom()` for app-level settings that are always global
- Always provide a fallback value with `??` operator
### Step 6: Use in Backend Code
Access settings in Go code:
```go
// Get the full config
fullConfig := wconfig.GetWatcher().GetFullConfig()
// Access your setting
myValue := fullConfig.Settings.MyNewSetting
// For optional values (pointers)
if fullConfig.Settings.MyIntSetting != nil {
intValue := *fullConfig.Settings.MyIntSetting
// Use intValue
}
```
## Complete Examples
### Example 1: Simple Boolean Setting (No Block Override)
**Use case:** Add a setting to hide the AI button globally
#### 1. Go Struct (`pkg/wconfig/settingsconfig.go`)
```go
type SettingsType struct {
// ... existing fields ...
AppHideAiButton bool `json:"app:hideaibutton,omitempty"`
}
```
#### 2. Default Value (`pkg/wconfig/defaultconfig/settings.json`)
```json
{
"app:hideaibutton": false
}
```
#### 3. Documentation (`docs/docs/config.mdx`)
```markdown
| app:hideaibutton <VersionBadge version="v0.14" /> | bool | Hide the AI button in the tab bar (defaults to false) |
```
#### 4. Generate Types
```bash
task generate
```
#### 5. Frontend Usage
```typescript
import { getSettingsKeyAtom } from "@/store/global";
const TabBar = () => {
const hideAiButton = useAtomValue(getSettingsKeyAtom("app:hideaibutton"));
if (hideAiButton) {
return null; // Don't render AI button
}
return <button>AI</button>;
};
```
#### 6. Usage Examples
```bash
# Set in settings file
wsh setconfig app:hideaibutton=true
# Or edit ~/.config/waveterm/settings.json
{
"app:hideaibutton": true
}
```
### Example 2: Terminal Setting with Block Override
**Use case:** Add a terminal bell sound setting that can be overridden per block
#### 1. Go Struct (`pkg/wconfig/settingsconfig.go`)
```go
type SettingsType struct {
// ... existing fields ...
TermBellSound string `json:"term:bellsound,omitempty"`
}
```
#### 2. Block Metadata (`pkg/waveobj/wtypemeta.go`)
```go
type MetaTSType struct {
// ... existing fields ...
TermBellSound *string `json:"term:bellsound,omitempty"` // Pointer for optional override
}
```
#### 3. Default Value (`pkg/wconfig/defaultconfig/settings.json`)
```json
{
"term:bellsound": "default"
}
```
#### 4. Documentation (`docs/docs/config.mdx`)
```markdown
| term:bellsound <VersionBadge version="v0.14" /> | string | Sound to play for terminal bell ("default", "none", or custom sound file path) |
```
#### 5. Generate Types
```bash
task generate
```
#### 6. Frontend Usage
```typescript
import { getOverrideConfigAtom } from "@/store/global";
const TerminalView = ({ blockId }: { blockId: string }) => {
// Use override config for hierarchical resolution
const bellSoundAtom = getOverrideConfigAtom(blockId, "term:bellsound");
const bellSound = useAtomValue(bellSoundAtom) ?? "default";
const playBellSound = () => {
if (bellSound === "none") return;
// Play the bell sound
};
return <div>Terminal with bell: {bellSound}</div>;
};
```
#### 7. Usage Examples
```bash
# Set globally in settings file
wsh setconfig term:bellsound="custom.wav"
# Set for current block only
wsh setmeta term:bellsound="none"
# Set for specific block
wsh setmeta --block BLOCK_ID term:bellsound="beep"
# Or edit ~/.config/waveterm/settings.json
{
"term:bellsound": "custom.wav"
}
```
## Configuration Patterns
### Clear/Reset Pattern
Each namespace can have a "clear" field for resetting all settings in that namespace:
```go
AppClear bool `json:"app:*,omitempty"`
TermClear bool `json:"term:*,omitempty"`
```
### Optional vs Required Settings
- Use pointer types (`*bool`, `*int64`, `*float64`) for truly optional settings
- Use regular types for settings that should always have a value
- Provide sensible defaults for important settings
### Block-Level Overrides via RPC
Settings can be overridden at the block level using metadata:
```typescript
import { RpcApi } from "@/app/store/wshclientapi";
import { TabRpcClient } from "@/app/store/wshrpcutil";
import { WOS } from "@/store/global";
// Set block-specific override
await RpcApi.SetMetaCommand(TabRpcClient, {
oref: WOS.makeORef("block", blockId),
meta: { "mynew:setting": "block-specific value" },
});
```
## Common Pitfalls
### 1. Forgetting to Run `task generate`
**Problem:** TypeScript types not updated, schema out of sync
**Solution:** Always run `task generate` after modifying Go structs
### 2. Type Mismatch Between Settings and Metadata
**Problem:** Settings uses `string`, metadata uses `*int`
**Solution:** Ensure types match (except metadata uses pointers for optionals)
### 3. Not Providing Fallback Values
**Problem:** Component breaks if setting is undefined
**Solution:** Always use `??` operator with fallback:
```typescript
const value = useAtomValue(getSettingsKeyAtom("key")) ?? "default";
```
### 4. Using Wrong Config Atom
**Problem:** Using `getSettingsKeyAtom()` for settings that need block overrides
**Solution:** Use `getOverrideConfigAtom()` for any setting in `MetaTSType`
## Best Practices
### Naming
- **Use descriptive names**: `term:fontsize` not `term:fs`
- **Follow namespace conventions**: Group related settings with common prefix
- **Use consistent casing**: Always lowercase with colons
### Types
- **Use `bool`** for simple on/off settings (no pointer if false is default)
- **Use `*bool`** only if you need to distinguish unset from false
- **Use `*int64`/`*float64`** for optional numeric values
- **Use `string`** for text, paths, or enum-like values
- **Use `[]string`** for lists
### Defaults
- **Provide sensible defaults** for settings users will commonly change
- **Omit defaults** for advanced/optional settings
- **Keep defaults safe** - don't enable experimental features by default
- **Document defaults** clearly in config.mdx
### Block Overrides
- **Enable for view/display settings**: Font sizes, colors, themes, etc.
- **Don't enable for app-wide settings**: Global hotkeys, window behavior, etc.
- **Consider the use case**: Would a user want different values per block or connection?
### Documentation
- **Be specific**: Explain what the setting does and what values are valid
- **Provide examples**: Show common use cases
- **Add version badges**: Mark new settings with `<VersionBadge version="v0.x" />`
- **Keep it current**: Update docs when behavior changes
## Quick Reference
When adding a new configuration setting:
- [ ] Add field to `SettingsType` in `pkg/wconfig/settingsconfig.go`
- [ ] Add field to `MetaTSType` in `pkg/waveobj/wtypemeta.go` (if block override needed)
- [ ] Add default to `pkg/wconfig/defaultconfig/settings.json` (if needed)
- [ ] Document in `docs/docs/config.mdx`
- [ ] Run `task generate` to update TypeScript types
- [ ] Use appropriate atom (`getOverrideConfigAtom` or `getSettingsKeyAtom`) in frontend
## Related Documentation
- **User Documentation**: `docs/docs/config.mdx` - User-facing configuration docs
- **Type Definitions**: `pkg/wconfig/settingsconfig.go` - Go struct definitions
- **Metadata Types**: `pkg/waveobj/wtypemeta.go` - Block metadata definitions
================================================
FILE: .kilocode/skills/add-rpc/SKILL.md
================================================
---
name: add-rpc
description: Guide for adding new RPC calls to Wave Terminal. Use when implementing new RPC commands, adding server-client communication methods, or extending the RPC interface with new functionality.
---
# Adding RPC Calls Guide
## Overview
Wave Terminal uses a WebSocket-based RPC (Remote Procedure Call) system for communication between different components. The RPC system allows the frontend, backend, electron main process, remote servers, and terminal blocks to communicate with each other through well-defined commands.
This guide covers how to add a new RPC command to the system.
## Key Files
- `pkg/wshrpc/wshrpctypes.go` - RPC interface and type definitions
- `pkg/wshrpc/wshserver/wshserver.go` - Main server implementation (most common)
- `emain/emain-wsh.ts` - Electron main process implementation
- `frontend/app/store/tabrpcclient.ts` - Frontend tab implementation
- `pkg/wshrpc/wshremote/wshremote.go` - Remote server implementation
- `frontend/app/view/term/term-wsh.tsx` - Terminal block implementation
## RPC Command Structure
RPC commands in Wave Terminal follow these conventions:
- **Method names** must end with `Command`
- **First parameter** must be `context.Context`
- **Remaining parameters** are a regular Go parameter list (zero or more typed args)
- **Return values** can be either just an error, or one return value plus an error
- **Streaming commands** return a channel instead of a direct value
## Adding a New RPC Call
### Step 1: Define the Command in the Interface
Add your command to the `WshRpcInterface` in `pkg/wshrpc/wshrpctypes.go`:
```go
type WshRpcInterface interface {
// ... existing commands ...
// Add your new command
YourNewCommand(ctx context.Context, data CommandYourNewData) (*YourNewResponse, error)
}
```
**Method Signature Rules:**
- Method name must end with `Command`
- First parameter must be `ctx context.Context`
- Remaining parameters are a regular Go parameter list (zero or more)
- Return either `error` or `(ReturnType, error)`
- For streaming, return `chan RespOrErrorUnion[T]`
### Step 2: Define Request and Response Types
If your command needs structured input or output, define types in the same file:
```go
type CommandYourNewData struct {
FieldOne string `json:"fieldone"`
FieldTwo int `json:"fieldtwo"`
SomeId string `json:"someid"`
}
type YourNewResponse struct {
ResultField string `json:"resultfield"`
Success bool `json:"success"`
}
```
**Type Naming Conventions:**
- Request types: `Command[Name]Data` (e.g., `CommandGetMetaData`)
- Response types: `[Name]Response` or `Command[Name]RtnData` (e.g., `CommandResolveIdsRtnData`)
- Use `json` struct tags with lowercase field names
- Follow existing patterns in the file for consistency
### Step 3: Generate Bindings
After modifying `pkg/wshrpc/wshrpctypes.go`, run code generation to create TypeScript bindings and Go helper code:
```bash
task generate
```
This command will:
- Generate TypeScript type definitions in `frontend/types/gotypes.d.ts`
- Create RPC client bindings
- Update routing code
**Note:** If generation fails, check that your method signature follows all the rules above.
### Step 4: Implement the Command
Choose where to implement your command based on what it needs to do:
#### A. Main Server Implementation (Most Common)
Implement in `pkg/wshrpc/wshserver/wshserver.go`:
```go
func (ws *WshServer) YourNewCommand(ctx context.Context, data wshrpc.CommandYourNewData) (*wshrpc.YourNewResponse, error) {
// Validate input
if data.SomeId == "" {
return nil, fmt.Errorf("someid is required")
}
// Implement your logic
result := doSomething(data)
// Return response
return &wshrpc.YourNewResponse{
ResultField: result,
Success: true,
}, nil
}
```
**Use main server when:**
- Accessing the database
- Managing blocks, tabs, or workspaces
- Coordinating between components
- Handling file operations on the main filesystem
#### B. Electron Implementation
Implement in `emain/emain-wsh.ts`:
```typescript
async handle_yournew(rh: RpcResponseHelper, data: CommandYourNewData): Promise<YourNewResponse> {
// Electron-specific logic
const result = await electronAPI.doSomething(data);
return {
resultfield: result,
success: true,
};
}
```
**Use Electron when:**
- Accessing native OS features
- Managing application windows
- Using Electron APIs (notifications, system tray, etc.)
- Handling encryption/decryption with safeStorage
#### C. Frontend Tab Implementation
Implement in `frontend/app/store/tabrpcclient.ts`:
```typescript
async handle_yournew(rh: RpcResponseHelper, data: CommandYourNewData): Promise<YourNewResponse> {
// Access frontend state/models
const layoutModel = getLayoutModelForStaticTab();
// Implement tab-specific logic
const result = layoutModel.doSomething(data);
return {
resultfield: result,
success: true,
};
}
```
**Use tab client when:**
- Accessing React state or Jotai atoms
- Manipulating UI layout
- Capturing screenshots
- Reading frontend-only data
#### D. Remote Server Implementation
Implement in `pkg/wshrpc/wshremote/wshremote.go`:
```go
func (impl *ServerImpl) RemoteYourNewCommand(ctx context.Context, data wshrpc.CommandRemoteYourNewData) (*wshrpc.YourNewResponse, error) {
// Remote filesystem or process operations
result, err := performRemoteOperation(data)
if err != nil {
return nil, fmt.Errorf("remote operation failed: %w", err)
}
return &wshrpc.YourNewResponse{
ResultField: result,
Success: true,
}, nil
}
```
**Use remote server when:**
- Operating on remote filesystems
- Executing commands on remote hosts
- Managing remote processes
- Convention: prefix command name with `Remote` (e.g., `RemoteGetInfoCommand`)
#### E. Terminal Block Implementation
Implement in `frontend/app/view/term/term-wsh.tsx`:
```typescript
async handle_yournew(rh: RpcResponseHelper, data: CommandYourNewData): Promise<YourNewResponse> {
// Access terminal-specific data
const termWrap = this.model.termRef.current;
// Implement terminal logic
const result = termWrap.doSomething(data);
return {
resultfield: result,
success: true,
};
}
```
**Use terminal client when:**
- Accessing terminal buffer/scrollback
- Managing VDOM contexts
- Reading terminal-specific state
- Interacting with xterm.js
## Complete Example: Adding GetWaveInfo Command
### 1. Define Interface
In `pkg/wshrpc/wshrpctypes.go`:
```go
type WshRpcInterface interface {
// ... other commands ...
WaveInfoCommand(ctx context.Context) (*WaveInfoData, error)
}
type WaveInfoData struct {
Version string `json:"version"`
BuildTime string `json:"buildtime"`
ConfigPath string `json:"configpath"`
DataPath string `json:"datapath"`
}
```
### 2. Generate Bindings
```bash
task generate
```
### 3. Implement in Main Server
In `pkg/wshrpc/wshserver/wshserver.go`:
```go
func (ws *WshServer) WaveInfoCommand(ctx context.Context) (*wshrpc.WaveInfoData, error) {
return &wshrpc.WaveInfoData{
Version: wavebase.WaveVersion,
BuildTime: wavebase.BuildTime,
ConfigPath: wavebase.GetConfigDir(),
DataPath: wavebase.GetWaveDataDir(),
}, nil
}
```
### 4. Call from Frontend
```typescript
import { RpcApi } from "@/app/store/wshclientapi";
// Call the RPC
const info = await RpcApi.WaveInfoCommand(TabRpcClient);
console.log("Wave Version:", info.version);
```
## Streaming Commands
For commands that return data progressively, use channels:
### Define Streaming Interface
```go
type WshRpcInterface interface {
StreamYourDataCommand(ctx context.Context, request YourDataRequest) chan RespOrErrorUnion[YourDataType]
}
```
### Implement Streaming Command
```go
func (ws *WshServer) StreamYourDataCommand(ctx context.Context, request wshrpc.YourDataRequest) chan wshrpc.RespOrErrorUnion[wshrpc.YourDataType] {
rtn := make(chan wshrpc.RespOrErrorUnion[wshrpc.YourDataType])
go func() {
defer close(rtn)
defer func() {
panichandler.PanicHandler("StreamYourDataCommand", recover())
}()
// Stream data
for i := 0; i < 10; i++ {
select {
case <-ctx.Done():
return
default:
rtn <- wshrpc.RespOrErrorUnion[wshrpc.YourDataType]{
Response: wshrpc.YourDataType{
Value: i,
},
}
time.Sleep(100 * time.Millisecond)
}
}
}()
return rtn
}
```
## Best Practices
1. **Validation First**: Always validate input parameters at the start of your implementation
2. **Descriptive Names**: Use clear, action-oriented command names (e.g., `GetFullConfigCommand`, not `ConfigCommand`)
3. **Error Handling**: Return descriptive errors with context:
```go
return nil, fmt.Errorf("error creating block: %w", err)
```
4. **Context Awareness**: Respect context cancellation for long-running operations:
```go
select {
case <-ctx.Done():
return ctx.Err()
default:
// continue
}
```
5. **Consistent Types**: Follow existing naming patterns for request/response types
6. **JSON Tags**: Always use lowercase JSON tags matching frontend conventions
7. **Documentation**: Add comments explaining complex commands or special behaviors
8. **Type Safety**: Leverage TypeScript generation - your types will be checked on both ends
9. **Panic Recovery**: Use `panichandler.PanicHandler` in goroutines to prevent crashes
10. **Route Awareness**: For multi-route scenarios, use `wshutil.GetRpcSourceFromContext(ctx)` to identify callers
## Common Command Patterns
### Simple Query
```go
func (ws *WshServer) GetSomethingCommand(ctx context.Context, id string) (*Something, error) {
obj, err := wstore.DBGet[*Something](ctx, id)
if err != nil {
return nil, fmt.Errorf("error getting something: %w", err)
}
return obj, nil
}
```
### Mutation with Updates
```go
func (ws *WshServer) UpdateSomethingCommand(ctx context.Context, data wshrpc.CommandUpdateData) error {
ctx = waveobj.ContextWithUpdates(ctx)
// Make changes
err := wstore.UpdateObject(ctx, data.ORef, data.Updates)
if err != nil {
return fmt.Errorf("error updating: %w", err)
}
// Broadcast updates
updates := waveobj.ContextGetUpdatesRtn(ctx)
wps.Broker.SendUpdateEvents(updates)
return nil
}
```
### Command with Side Effects
```go
func (ws *WshServer) DoActionCommand(ctx context.Context, data wshrpc.CommandActionData) error {
// Perform action
result, err := performAction(data)
if err != nil {
return err
}
// Publish event about the action
go func() {
wps.Broker.Publish(wps.WaveEvent{
Event: wps.Event_ActionComplete,
Data: result,
})
}()
return nil
}
```
## Troubleshooting
### Command Not Found
- Ensure method name ends with `Command`
- Verify you ran `task generate`
- Check that the interface is in `WshRpcInterface`
### Type Mismatch Errors
- Run `task generate` after changing types
- Ensure JSON tags are lowercase
- Verify TypeScript code is using generated types
### Command Times Out
- Check for blocking operations
- Ensure context is passed through
- Consider using a streaming command for long operations
### Routing Issues
- For remote commands, ensure they're implemented in correct location
- Check route configuration in RpcContext
- Verify authentication for secured routes
## Quick Reference
When adding a new RPC command:
- [ ] Add method to `WshRpcInterface` in `pkg/wshrpc/wshrpctypes.go` (must end with `Command`)
- [ ] Define request/response types with JSON tags (if needed)
- [ ] Run `task generate` to create bindings
- [ ] Implement in appropriate location:
- [ ] `wshserver.go` for main server (most common)
- [ ] `emain-wsh.ts` for Electron
- [ ] `tabrpcclient.ts` for frontend
- [ ] `wshremote.go` for remote (prefix with `Remote`)
- [ ] `term-wsh.tsx` for terminal
- [ ] Add input validation
- [ ] Handle errors with context
- [ ] Test the command end-to-end
## Related Documentation
- **WPS Events**: See the `wps-events` skill - Publishing events from RPC commands
================================================
FILE: .kilocode/skills/add-wshcmd/SKILL.md
================================================
---
name: add-wshcmd
description: Guide for adding new wsh commands to Wave Terminal. Use when implementing new CLI commands, adding command-line functionality, or extending the wsh command interface.
---
# Adding a New wsh Command to Wave Terminal
This guide explains how to add a new command to the `wsh` CLI tool.
## wsh Command System Overview
Wave Terminal's `wsh` command provides CLI access to Wave Terminal features. The system uses:
1. **Cobra Framework** - CLI command structure and parsing
2. **Command Files** - Individual command implementations in `cmd/wsh/cmd/wshcmd-*.go`
3. **RPC Client** - Communication with Wave Terminal backend via `RpcClient`
4. **Activity Tracking** - Telemetry for command usage analytics
5. **Documentation** - User-facing docs in `docs/docs/wsh-reference.mdx`
Commands are registered in their `init()` functions and execute through the Cobra framework.
## Step-by-Step Guide
### Step 1: Create Command File
Create a new file in `cmd/wsh/cmd/` named `wshcmd-[commandname].go`:
```go
// Copyright 2025, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
package cmd
import (
"fmt"
"github.com/spf13/cobra"
"github.com/wavetermdev/waveterm/pkg/wshrpc"
"github.com/wavetermdev/waveterm/pkg/wshrpc/wshclient"
)
var myCommandCmd = &cobra.Command{
Use: "mycommand [args]",
Short: "Brief description of what this command does",
Long: `Detailed description of the command.
Can include multiple lines and examples of usage.`,
RunE: myCommandRun,
PreRunE: preRunSetupRpcClient, // Include if command needs RPC
DisableFlagsInUseLine: true,
}
// Flag variables
var (
myCommandFlagExample string
myCommandFlagVerbose bool
)
func init() {
// Add command to root
rootCmd.AddCommand(myCommandCmd)
// Define flags
myCommandCmd.Flags().StringVarP(&myCommandFlagExample, "example", "e", "", "example flag description")
myCommandCmd.Flags().BoolVarP(&myCommandFlagVerbose, "verbose", "v", false, "enable verbose output")
}
func myCommandRun(cmd *cobra.Command, args []string) (rtnErr error) {
// Always track activity for telemetry
defer func() {
sendActivity("mycommand", rtnErr == nil)
}()
// Validate arguments
if len(args) == 0 {
OutputHelpMessage(cmd)
return fmt.Errorf("requires at least one argument")
}
// Command implementation
fmt.Printf("Command executed successfully\n")
return nil
}
```
**File Naming Convention:**
- Use `wshcmd-[commandname].go` format
- Use lowercase, hyphenated names for multi-word commands
- Examples: `wshcmd-getvar.go`, `wshcmd-setmeta.go`, `wshcmd-ai.go`
### Step 2: Command Structure
#### Basic Command Structure
```go
var myCommandCmd = &cobra.Command{
Use: "mycommand [required] [optional...]",
Short: "One-line description (shown in help)",
Long: `Detailed multi-line description`,
// Argument validation
Args: cobra.MinimumNArgs(1), // Or cobra.ExactArgs(1), cobra.NoArgs, etc.
// Execution function
RunE: myCommandRun,
// Pre-execution setup (if needed)
PreRunE: preRunSetupRpcClient, // Sets up RPC client for backend communication
// Example usage (optional)
Example: " wsh mycommand foo\n wsh mycommand --flag bar",
// Disable flag notation in usage line
DisableFlagsInUseLine: true,
}
```
**Key Fields:**
- `Use`: Command name and argument pattern
- `Short`: Brief description for command list
- `Long`: Detailed description shown in help
- `Args`: Argument validator (optional)
- `RunE`: Main execution function (returns error)
- `PreRunE`: Setup function that runs before `RunE`
- `Example`: Usage examples (optional)
- `DisableFlagsInUseLine`: Clean up help display
#### When to Use PreRunE
Include `PreRunE: preRunSetupRpcClient` if your command:
- Communicates with the Wave Terminal backend
- Needs access to `RpcClient`
- Requires JWT authentication (WAVETERM_JWT env var)
- Makes RPC calls via `wshclient.*Command()` functions
**Don't include PreRunE** for commands that:
- Only manipulate local state
- Don't need backend communication
- Are purely informational/local operations
### Step 3: Implement Command Logic
#### Command Function Pattern
```go
func myCommandRun(cmd *cobra.Command, args []string) (rtnErr error) {
// Step 1: Always track activity (for telemetry)
defer func() {
sendActivity("mycommand", rtnErr == nil)
}()
// Step 2: Validate arguments and flags
if len(args) != 1 {
OutputHelpMessage(cmd)
return fmt.Errorf("requires exactly one argument")
}
// Step 3: Parse/prepare data
targetArg := args[0]
// Step 4: Make RPC call if needed
result, err := wshclient.SomeCommand(RpcClient, wshrpc.CommandSomeData{
Field: targetArg,
}, &wshrpc.RpcOpts{Timeout: 2000})
if err != nil {
return fmt.Errorf("executing command: %w", err)
}
// Step 5: Output results
fmt.Printf("Result: %s\n", result)
return nil
}
```
**Important Patterns:**
1. **Activity Tracking**: Always include deferred `sendActivity()` call
```go
defer func() {
sendActivity("commandname", rtnErr == nil)
}()
```
2. **Error Handling**: Return errors, don't call `os.Exit()`
```go
if err != nil {
return fmt.Errorf("context: %w", err)
}
```
3. **Output**: Use standard `fmt` package for output
```go
fmt.Printf("Success message\n")
fmt.Fprintf(os.Stderr, "Error message\n")
```
4. **Help Messages**: Show help when arguments are invalid
```go
if len(args) == 0 {
OutputHelpMessage(cmd)
return fmt.Errorf("requires arguments")
}
```
5. **Exit Codes**: Set custom exit code via `WshExitCode`
```go
if notFound {
WshExitCode = 1
return nil // Don't return error, just set exit code
}
```
### Step 4: Define Flags
Add flags in the `init()` function:
```go
var (
// Declare flag variables at package level
myCommandFlagString string
myCommandFlagBool bool
myCommandFlagInt int
)
func init() {
rootCmd.AddCommand(myCommandCmd)
// String flag with short version
myCommandCmd.Flags().StringVarP(&myCommandFlagString, "name", "n", "default", "description")
// Boolean flag
myCommandCmd.Flags().BoolVarP(&myCommandFlagBool, "verbose", "v", false, "enable verbose")
// Integer flag
myCommandCmd.Flags().IntVar(&myCommandFlagInt, "count", 10, "set count")
// Flag without short version
myCommandCmd.Flags().StringVar(&myCommandFlagString, "longname", "", "description")
}
```
**Flag Types:**
- `StringVar/StringVarP` - String values
- `BoolVar/BoolVarP` - Boolean flags
- `IntVar/IntVarP` - Integer values
- The `P` suffix versions include a short flag name
**Flag Naming:**
- Use camelCase for variable names: `myCommandFlagName`
- Use kebab-case for flag names: `--flag-name`
- Prefix variable names with command name for clarity
### Step 5: Working with Block Arguments
Many commands operate on blocks. Use the standard block resolution pattern:
```go
func myCommandRun(cmd *cobra.Command, args []string) (rtnErr error) {
defer func() {
sendActivity("mycommand", rtnErr == nil)
}()
// Resolve block using the -b/--block flag
fullORef, err := resolveBlockArg()
if err != nil {
return err
}
// Use the blockid in RPC call
err = wshclient.SomeCommand(RpcClient, wshrpc.CommandSomeData{
BlockId: fullORef.OID,
}, &wshrpc.RpcOpts{Timeout: 2000})
if err != nil {
return fmt.Errorf("command failed: %w", err)
}
return nil
}
```
**Block Resolution:**
- The `-b/--block` flag is defined globally in `wshcmd-root.go`
- `resolveBlockArg()` resolves the block argument to a full ORef
- Supports: `this`, `tab`, full UUIDs, 8-char prefixes, block numbers
- Default is `"this"` (current block)
**Alternative: Manual Block Resolution**
```go
// Get tab ID from environment
tabId := os.Getenv("WAVETERM_TABID")
if tabId == "" {
return fmt.Errorf("WAVETERM_TABID not set")
}
// Create route for tab-level operations
route := wshutil.MakeTabRouteId(tabId)
// Use route in RPC call
err := wshclient.SomeCommand(RpcClient, commandData, &wshrpc.RpcOpts{
Route: route,
Timeout: 2000,
})
```
### Step 6: Making RPC Calls
Use the `wshclient` package to make RPC calls:
```go
import (
"github.com/wavetermdev/waveterm/pkg/wshrpc"
"github.com/wavetermdev/waveterm/pkg/wshrpc/wshclient"
)
// Simple RPC call
result, err := wshclient.GetMetaCommand(RpcClient, wshrpc.CommandGetMetaData{
ORef: *fullORef,
}, &wshrpc.RpcOpts{Timeout: 2000})
if err != nil {
return fmt.Errorf("getting metadata: %w", err)
}
// RPC call with routing
err := wshclient.SetMetaCommand(RpcClient, wshrpc.CommandSetMetaData{
ORef: *fullORef,
Meta: metaMap,
}, &wshrpc.RpcOpts{
Route: route,
Timeout: 5000,
})
if err != nil {
return fmt.Errorf("setting metadata: %w", err)
}
```
**RPC Options:**
- `Timeout`: Request timeout in milliseconds (typically 2000-5000)
- `Route`: Route ID for targeting specific components
- Available routes: `wshutil.ControlRoute`, `wshutil.MakeTabRouteId(tabId)`
### Step 7: Add Documentation
Add your command to `docs/docs/wsh-reference.mdx`:
````markdown
## mycommand
Brief description of what the command does.
```sh
wsh mycommand [args] [flags]
```
Detailed explanation of the command's purpose and behavior.
Flags:
- `-n, --name <value>` - description of this flag
- `-v, --verbose` - enable verbose output
- `-b, --block <blockid>` - specify target block (default: current block)
Examples:
```sh
# Basic usage
wsh mycommand arg1
# With flags
wsh mycommand --name value arg1
# With block targeting
wsh mycommand -b 2 arg1
# Complex example
wsh mycommand -v --name "example" arg1 arg2
```
Additional notes, tips, or warnings about the command.
---
````
**Documentation Guidelines:**
- Place in alphabetical order with other commands
- Include command signature with argument pattern
- List all flags with short and long versions
- Provide practical examples (at least 3-5)
- Explain common use cases and patterns
- Add tips or warnings if relevant
- Use `---` separator between commands
### Step 8: Test Your Command
Build and test the command:
```bash
# Build wsh
task build:wsh
# Or build everything
task build
# Test the command
./bin/wsh/wsh mycommand --help
./bin/wsh/wsh mycommand arg1 arg2
```
**Testing Checklist:**
- [ ] Help message displays correctly
- [ ] Required arguments validated
- [ ] Flags work as expected
- [ ] Error messages are clear
- [ ] Success cases work correctly
- [ ] RPC calls complete successfully
- [ ] Output is formatted correctly
## Complete Examples
### Example 1: Simple Command with No RPC
**Use case:** A command that prints Wave Terminal version info
#### Command File (`cmd/wsh/cmd/wshcmd-version.go`)
```go
// Copyright 2025, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
package cmd
import (
"github.com/spf13/cobra"
"github.com/wavetermdev/waveterm/pkg/wavebase"
)
var versionCmd = &cobra.Command{
Use: "version",
Short: "Print Wave Terminal version",
RunE: versionRun,
}
func init() {
rootCmd.AddCommand(versionCmd)
}
func versionRun(cmd *cobra.Command, args []string) (rtnErr error) {
defer func() {
sendActivity("version", rtnErr == nil)
}()
fmt.Printf("Wave Terminal %s\n", wavebase.WaveVersion)
return nil
}
```
#### Documentation
````markdown
## version
Print the current Wave Terminal version.
```sh
wsh version
```
Examples:
```sh
# Print version
wsh version
```
````
### Example 2: Command with Flags and RPC
**Use case:** A command to update block title
#### Command File (`cmd/wsh/cmd/wshcmd-settitle.go`)
```go
// Copyright 2025, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
package cmd
import (
"fmt"
"github.com/spf13/cobra"
"github.com/wavetermdev/waveterm/pkg/wshrpc"
"github.com/wavetermdev/waveterm/pkg/wshrpc/wshclient"
)
var setTitleCmd = &cobra.Command{
Use: "settitle [title]",
Short: "Set block title",
Long: `Set the title for the current or specified block.`,
Args: cobra.ExactArgs(1),
RunE: setTitleRun,
PreRunE: preRunSetupRpcClient,
DisableFlagsInUseLine: true,
}
var setTitleIcon string
func init() {
rootCmd.AddCommand(setTitleCmd)
setTitleCmd.Flags().StringVarP(&setTitleIcon, "icon", "i", "", "set block icon")
}
func setTitleRun(cmd *cobra.Command, args []string) (rtnErr error) {
defer func() {
sendActivity("settitle", rtnErr == nil)
}()
title := args[0]
// Resolve block
fullORef, err := resolveBlockArg()
if err != nil {
return err
}
// Build metadata map
meta := make(map[string]interface{})
meta["title"] = title
if setTitleIcon != "" {
meta["icon"] = setTitleIcon
}
// Make RPC call
err = wshclient.SetMetaCommand(RpcClient, wshrpc.CommandSetMetaData{
ORef: *fullORef,
Meta: meta,
}, &wshrpc.RpcOpts{Timeout: 2000})
if err != nil {
return fmt.Errorf("setting title: %w", err)
}
fmt.Printf("title updated\n")
return nil
}
```
#### Documentation
````markdown
## settitle
Set the title for a block.
```sh
wsh settitle [title]
```
Update the display title for the current or specified block. Optionally set an icon as well.
Flags:
- `-i, --icon <icon>` - set block icon along with title
- `-b, --block <blockid>` - specify target block (default: current block)
Examples:
```sh
# Set title for current block
wsh settitle "My Terminal"
# Set title and icon
wsh settitle --icon "terminal" "Development Shell"
# Set title for specific block
wsh settitle -b 2 "Build Output"
```
````
### Example 3: Subcommands
**Use case:** Command with multiple subcommands (like `wsh conn`)
#### Command File (`cmd/wsh/cmd/wshcmd-mygroup.go`)
```go
// Copyright 2025, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
package cmd
import (
"fmt"
"github.com/spf13/cobra"
"github.com/wavetermdev/waveterm/pkg/wshrpc"
"github.com/wavetermdev/waveterm/pkg/wshrpc/wshclient"
)
var myGroupCmd = &cobra.Command{
Use: "mygroup",
Short: "Manage something",
}
var myGroupListCmd = &cobra.Command{
Use: "list",
Short: "List items",
RunE: myGroupListRun,
PreRunE: preRunSetupRpcClient,
}
var myGroupAddCmd = &cobra.Command{
Use: "add [name]",
Short: "Add an item",
Args: cobra.ExactArgs(1),
RunE: myGroupAddRun,
PreRunE: preRunSetupRpcClient,
}
func init() {
// Add parent command
rootCmd.AddCommand(myGroupCmd)
// Add subcommands
myGroupCmd.AddCommand(myGroupListCmd)
myGroupCmd.AddCommand(myGroupAddCmd)
}
func myGroupListRun(cmd *cobra.Command, args []string) (rtnErr error) {
defer func() {
sendActivity("mygroup:list", rtnErr == nil)
}()
// Implementation
fmt.Printf("Listing items...\n")
return nil
}
func myGroupAddRun(cmd *cobra.Command, args []string) (rtnErr error) {
defer func() {
sendActivity("mygroup:add", rtnErr == nil)
}()
name := args[0]
fmt.Printf("Adding item: %s\n", name)
return nil
}
```
#### Documentation
````markdown
## mygroup
Manage something with subcommands.
### list
List all items.
```sh
wsh mygroup list
```
### add
Add a new item.
```sh
wsh mygroup add [name]
```
Examples:
```sh
# List items
wsh mygroup list
# Add an item
wsh mygroup add "new-item"
```
````
## Common Patterns
### Reading from Stdin
```go
import "io"
func myCommandRun(cmd *cobra.Command, args []string) (rtnErr error) {
defer func() {
sendActivity("mycommand", rtnErr == nil)
}()
// Check if reading from stdin (using "-" convention)
var data []byte
var err error
if len(args) > 0 && args[0] == "-" {
data, err = io.ReadAll(os.Stdin)
if err != nil {
return fmt.Errorf("reading stdin: %w", err)
}
} else {
// Read from file or other source
data, err = os.ReadFile(args[0])
if err != nil {
return fmt.Errorf("reading file: %w", err)
}
}
// Process data
fmt.Printf("Read %d bytes\n", len(data))
return nil
}
```
### JSON File Input
```go
import (
"encoding/json"
"io"
)
func loadJSONFile(filepath string) (map[string]interface{}, error) {
var data []byte
var err error
if filepath == "-" {
data, err = io.ReadAll(os.Stdin)
if err != nil {
return nil, fmt.Errorf("reading stdin: %w", err)
}
} else {
data, err = os.ReadFile(filepath)
if err != nil {
return nil, fmt.Errorf("reading file: %w", err)
}
}
var result map[string]interface{}
if err := json.Unmarshal(data, &result); err != nil {
return nil, fmt.Errorf("parsing JSON: %w", err)
}
return result, nil
}
```
### Conditional Output (TTY Detection)
```go
func myCommandRun(cmd *cobra.Command, args []string) (rtnErr error) {
defer func() {
sendActivity("mycommand", rtnErr == nil)
}()
isTty := getIsTty()
// Output value
fmt.Printf("%s", value)
// Add newline only if TTY (for better piping experience)
if isTty {
fmt.Printf("\n")
}
return nil
}
```
### Environment Variable Access
```go
func myCommandRun(cmd *cobra.Command, args []string) (rtnErr error) {
defer func() {
sendActivity("mycommand", rtnErr == nil)
}()
// Get block ID from environment
blockId := os.Getenv("WAVETERM_BLOCKID")
if blockId == "" {
return fmt.Errorf("WAVETERM_BLOCKID not set")
}
// Get tab ID from environment
tabId := os.Getenv("WAVETERM_TABID")
if tabId == "" {
return fmt.Errorf("WAVETERM_TABID not set")
}
fmt.Printf("Block: %s, Tab: %s\n", blockId, tabId)
return nil
}
```
## Best Practices
### Command Design
1. **Single Responsibility**: Each command should do one thing well
2. **Composable**: Design commands to work with pipes and other commands
3. **Consistent**: Follow existing wsh command patterns and conventions
4. **Documented**: Provide clear help text and examples
### Error Handling
1. **Context**: Wrap errors with context using `fmt.Errorf("context: %w", err)`
2. **User-Friendly**: Make error messages clear and actionable
3. **No Panics**: Return errors instead of calling `os.Exit()` or `panic()`
4. **Exit Codes**: Use `WshExitCode` for custom exit codes
### Output
1. **Structured**: Use consistent formatting for output
2. **Quiet by Default**: Only output what's necessary
3. **Verbose Flag**: Optionally provide `-v` for detailed output
4. **Stderr for Errors**: Use `fmt.Fprintf(os.Stderr, ...)` for error messages
### Flags
1. **Short Versions**: Provide `-x` short versions for common flags
2. **Sensible Defaults**: Choose defaults that work for most users
3. **Boolean Flags**: Use for on/off options
4. **String Flags**: Use for values that need user input
### RPC Calls
1. **Timeouts**: Always specify reasonable timeouts
2. **Error Context**: Wrap RPC errors with operation context
3. **Retries**: Don't retry automatically; let user retry command
4. **Routes**: Use appropriate routes for different operations
## Common Pitfalls
### 1. Forgetting Activity Tracking
**Problem**: Command usage not tracked in telemetry
**Solution**: Always include deferred `sendActivity()` call:
```go
defer func() {
sendActivity("commandname", rtnErr == nil)
}()
```
### 2. Using os.Exit() Instead of Returning Error
**Problem**: Breaks defer statements and cleanup
**Solution**: Return errors from RunE function:
```go
// Bad
if err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
// Good
if err != nil {
return fmt.Errorf("operation failed: %w", err)
}
```
### 3. Not Validating Arguments
**Problem**: Command crashes with nil pointer or index out of range
**Solution**: Validate arguments early and show help:
```go
if len(args) == 0 {
OutputHelpMessage(cmd)
return fmt.Errorf("requires at least one argument")
}
```
### 4. Forgetting to Add to init()
**Problem**: Command not available when running wsh
**Solution**: Always add command in `init()` function:
```go
func init() {
rootCmd.AddCommand(myCommandCmd)
}
```
### 5. Inconsistent Output
**Problem**: Inconsistent use of output methods
**Solution**: Use standard `fmt` package functions:
```go
// For stdout
fmt.Printf("output\n")
// For stderr
fmt.Fprintf(os.Stderr, "error message\n")
```
## Quick Reference Checklist
When adding a new wsh command:
- [ ] Create `cmd/wsh/cmd/wshcmd-[commandname].go`
- [ ] Define command struct with Use, Short, Long descriptions
- [ ] Add `PreRunE: preRunSetupRpcClient` if using RPC
- [ ] Implement command function with activity tracking
- [ ] Add command to `rootCmd` in `init()` function
- [ ] Define flags in `init()` function if needed
- [ ] Add documentation to `docs/docs/wsh-reference.mdx`
- [ ] Build and test: `task build:wsh`
- [ ] Test help: `wsh [commandname] --help`
- [ ] Test all flag combinations
- [ ] Test error cases
## Related Files
- **Root Command**: `cmd/wsh/cmd/wshcmd-root.go` - Main command setup and utilities
- **RPC Client**: `pkg/wshrpc/wshclient/` - Client functions for RPC calls
- **RPC Types**: `pkg/wshrpc/wshrpctypes.go` - RPC request/response data structures
- **Documentation**: `docs/docs/wsh-reference.mdx` - User-facing command reference
- **Examples**: `cmd/wsh/cmd/wshcmd-*.go` - Existing command implementations
================================================
FILE: .kilocode/skills/context-menu/SKILL.md
================================================
---
name: context-menu
description: Guide for creating and displaying context menus in Wave Terminal. Use when implementing right-click menus, adding context menu items, creating submenus, or handling menu interactions with checkboxes and separators.
---
# Context Menu Quick Reference
This guide provides a quick overview of how to create and display a context menu using our system.
---
## ContextMenuItem Type
Define each menu item using the `ContextMenuItem` type:
```ts
type ContextMenuItem = {
label?: string;
type?: "separator" | "normal" | "submenu" | "checkbox" | "radio";
role?: string; // Electron role (optional)
click?: () => void; // Callback for item selection (not needed if role is set)
submenu?: ContextMenuItem[]; // For nested menus
checked?: boolean; // For checkbox or radio items
visible?: boolean;
enabled?: boolean;
sublabel?: string;
};
```
---
## Import and Show the Menu
Import the context menu module:
```ts
import { ContextMenuModel } from "@/app/store/contextmenu";
```
To display the context menu, call:
```ts
ContextMenuModel.getInstance().showContextMenu(menu, event);
```
- **menu**: An array of `ContextMenuItem`.
- **event**: The mouse event that triggered the context menu (typically from an onContextMenu handler).
---
## Basic Example
A simple context menu with a separator:
```ts
const menu: ContextMenuItem[] = [
{
label: "New File",
click: () => {
/* create a new file */
},
},
{
label: "New Folder",
click: () => {
/* create a new folder */
},
},
{ type: "separator" },
{
label: "Rename",
click: () => {
/* rename item */
},
},
];
ContextMenuModel.getInstance().showContextMenu(menu, e);
```
---
## Example with Submenu and Checkboxes
Toggle settings using a submenu with checkbox items:
```ts
const isClearOnStart = true; // Example setting
const menu: ContextMenuItem[] = [
{
label: "Clear Output On Restart",
submenu: [
{
label: "On",
type: "checkbox",
checked: isClearOnStart,
click: () => {
// Set the config to enable clear on restart
},
},
{
label: "Off",
type: "checkbox",
checked: !isClearOnStart,
click: () => {
// Set the config to disable clear on restart
},
},
],
},
];
ContextMenuModel.getInstance().showContextMenu(menu, e);
```
---
## Editing a Config File Example
Open a configuration file (e.g., `widgets.json`) in preview mode:
```ts
{
label: "Edit widgets.json",
click: () => {
fireAndForget(async () => {
const path = `${getApi().getConfigDir()}/widgets.json`;
const blockDef: BlockDef = {
meta: { view: "preview", file: path },
};
await createBlock(blockDef, false, true);
});
},
}
```
---
## Summary
- **Menu Definition**: Use the `ContextMenuItem` type.
- **Actions**: Use `click` for actions; use `submenu` for nested options.
- **Separators**: Use `type: "separator"` to group items.
- **Toggles**: Use `type: "checkbox"` or `"radio"` with the `checked` property.
- **Displaying**: Use `ContextMenuModel.getInstance().showContextMenu(menu, event)` to render the menu.
## Common Use Cases
### File/Folder Operations
Context menus are commonly used for file operations like creating, renaming, and deleting files or folders.
### Settings Toggles
Use checkbox menu items to toggle settings on and off, with the `checked` property reflecting the current state.
### Nested Options
Use `submenu` to organize related options hierarchically, keeping the top-level menu clean and organized.
### Conditional Items
Use the `visible` and `enabled` properties to dynamically show or disable menu items based on the current state.
================================================
FILE: .kilocode/skills/create-view/SKILL.md
================================================
---
name: create-view
description: Guide for implementing a new view type in Wave Terminal. Use when creating a new view component, implementing the ViewModel interface, registering a new view type in BlockRegistry, or adding a new content type to display within blocks.
---
# Creating a New View in Wave Terminal
This guide explains how to implement a new view type in Wave Terminal. Views are the core content components displayed within blocks in the terminal interface.
## Architecture Overview
Wave Terminal uses a **Model-View architecture** where:
- **ViewModel** - Contains all state, logic, and UI configuration as Jotai atoms
- **ViewComponent** - Pure React component that renders the UI using the model
- **BlockFrame** - Wraps views with a header, connection management, and standard controls
The separation between model and component ensures:
- Models can update state without React hooks
- Components remain pure and testable
- State is centralized in Jotai atoms for easy access
## ViewModel Interface
Every view must implement the `ViewModel` interface defined in `frontend/types/custom.d.ts`:
```typescript
interface ViewModel {
// Required: The type identifier for this view (e.g., "term", "web", "preview")
viewType: string;
// Required: The React component that renders this view
viewComponent: ViewComponent<ViewModel>;
// Optional: Icon shown in block header (FontAwesome icon name or IconButtonDecl)
viewIcon?: jotai.Atom<string | IconButtonDecl>;
// Optional: Display name shown in block header (e.g., "Terminal", "Web", "Preview")
viewName?: jotai.Atom<string>;
// Optional: Additional header elements (text, buttons, inputs) shown after the name
viewText?: jotai.Atom<string | HeaderElem[]>;
// Optional: Icon button shown before the view name in header
preIconButton?: jotai.Atom<IconButtonDecl>;
// Optional: Icon buttons shown at the end of the header (before settings/close)
endIconButtons?: jotai.Atom<IconButtonDecl[]>;
// Optional: Custom background styling for the block
blockBg?: jotai.Atom<MetaType>;
// Optional: If true, completely hides the block header
noHeader?: jotai.Atom<boolean>;
// Optional: If true, shows connection picker in header for remote connections
manageConnection?: jotai.Atom<boolean>;
// Optional: If true, filters out 'nowsh' connections from connection picker
filterOutNowsh?: jotai.Atom<boolean>;
// Optional: If true, removes default padding from content area
noPadding?: jotai.Atom<boolean>;
// Optional: Atoms for managing in-block search functionality
searchAtoms?: SearchAtoms;
// Optional: Returns whether this is a basic terminal (for multi-input feature)
isBasicTerm?: (getFn: jotai.Getter) => boolean;
// Optional: Returns context menu items for the settings dropdown
getSettingsMenuItems?: () => ContextMenuItem[];
// Optional: Focuses the view when called, returns true if successful
giveFocus?: () => boolean;
// Optional: Handles keyboard events, returns true if handled
keyDownHandler?: (e: WaveKeyboardEvent) => boolean;
// Optional: Cleanup when block is closed
dispose?: () => void;
}
```
### Key Concepts
**Atoms**: All UI-related properties must be Jotai atoms. This enables:
- Reactive updates when state changes
- Access from anywhere via `globalStore.get()`/`globalStore.set()`
- Derived atoms that compute values from other atoms
**ViewComponent**: The React component receives these props:
```typescript
type ViewComponentProps<T extends ViewModel> = {
blockId: string; // Unique ID for this block
blockRef: React.RefObject<HTMLDivElement>; // Ref to block container
contentRef: React.RefObject<HTMLDivElement>; // Ref to content area
model: T; // Your ViewModel instance
};
```
## Step-by-Step Guide
### 1. Create the View Model Class
Create a new file for your view model (e.g., `frontend/app/view/myview/myview-model.ts`):
```typescript
import { BlockNodeModel } from "@/app/block/blocktypes";
import { globalStore } from "@/app/store/jotaiStore";
import { WOS, useBlockAtom } from "@/store/global";
import * as jotai from "jotai";
import { MyView } from "./myview";
export class MyViewModel implements ViewModel {
viewType: string;
blockId: string;
nodeModel: BlockNodeModel;
blockAtom: jotai.Atom<Block>;
// Define your atoms (simple field initializers)
viewIcon = jotai.atom<string>("circle");
viewName = jotai.atom<string>("My View");
noPadding = jotai.atom<boolean>(true);
// Derived atom (created in constructor)
viewText!: jotai.Atom<HeaderElem[]>;
constructor(blockId: string, nodeModel: BlockNodeModel) {
this.viewType = "myview";
this.blockId = blockId;
this.nodeModel = nodeModel;
this.blockAtom = WOS.getWaveObjectAtom<Block>(`block:${blockId}`);
// Create derived atoms that depend on block data or other atoms
this.viewText = jotai.atom((get) => {
const blockData = get(this.blockAtom);
const rtn: HeaderElem[] = [];
// Add header buttons/text based on state
rtn.push({
elemtype: "iconbutton",
icon: "refresh",
title: "Refresh",
click: () => this.refresh(),
});
return rtn;
});
}
get viewComponent(): ViewComponent {
return MyView;
}
refresh() {
// Update state using globalStore
// Never use React hooks in model methods
console.log("refreshing...");
}
giveFocus(): boolean {
// Focus your view component
return true;
}
dispose() {
// Cleanup resources (unsubscribe from events, etc.)
}
}
```
### 2. Create the View Component
Create your React component (e.g., `frontend/app/view/myview/myview.tsx`):
```typescript
import { ViewComponentProps } from "@/app/block/blocktypes";
import { MyViewModel } from "./myview-model";
import { useAtomValue } from "jotai";
import "./myview.scss";
export const MyView: React.FC<ViewComponentProps<MyViewModel>> = ({
blockId,
model,
contentRef
}) => {
// Use atoms from the model (these are React hooks - call at top level!)
const blockData = useAtomValue(model.blockAtom);
return (
<div className="myview-container" ref={contentRef}>
<div>Block ID: {blockId}</div>
<div>View: {model.viewType}</div>
{/* Your view content here */}
</div>
);
};
```
### 3. Register the View
Add your view to the `BlockRegistry` in `frontend/app/block/block.tsx`:
```typescript
const BlockRegistry: Map<string, ViewModelClass> = new Map();
BlockRegistry.set("term", TermViewModel);
BlockRegistry.set("preview", PreviewModel);
BlockRegistry.set("web", WebViewModel);
// ... existing registrations ...
BlockRegistry.set("myview", MyViewModel); // Add your view here
```
The registry key (e.g., `"myview"`) becomes the view type used in block metadata.
### 4. Create Blocks with Your View
Users can create blocks with your view type:
- Via CLI: `wsh view myview`
- Via RPC: Use the block's `meta.view` field set to `"myview"`
## Real-World Examples
### Example 1: Terminal View (`term-model.ts`)
The terminal view demonstrates:
- **Connection management** via `manageConnection` atom
- **Dynamic header buttons** showing shell status (play/restart)
- **Mode switching** between terminal and vdom views
- **Custom keyboard handling** for terminal-specific shortcuts
- **Focus management** to focus the xterm.js instance
- **Shell integration status** showing AI capability indicators
Key features:
```typescript
this.manageConnection = jotai.atom((get) => {
const termMode = get(this.termMode);
if (termMode == "vdom") return false;
return true; // Show connection picker for regular terminal mode
});
this.endIconButtons = jotai.atom((get) => {
const shellProcStatus = get(this.shellProcStatus);
const buttons: IconButtonDecl[] = [];
if (shellProcStatus == "running") {
buttons.push({
elemtype: "iconbutton",
icon: "refresh",
title: "Restart Shell",
click: this.forceRestartController.bind(this),
});
}
return buttons;
});
```
### Example 2: Web View (`webview.tsx`)
The web view shows:
- **Complex header controls** (back/forward/home/URL input)
- **State management** for loading, URL, and navigation
- **Event handling** for webview navigation events
- **Custom styling** with `noPadding` for full-bleed content
- **Media controls** showing play/pause/mute when media is active
Key features:
```typescript
this.viewText = jotai.atom((get) => {
const url = get(this.url);
const rtn: HeaderElem[] = [];
// Navigation buttons
rtn.push({
elemtype: "iconbutton",
icon: "chevron-left",
click: this.handleBack.bind(this),
disabled: this.shouldDisableBackButton(),
});
// URL input with nested controls
rtn.push({
elemtype: "div",
className: "block-frame-div-url",
children: [
{
elemtype: "input",
value: url,
onChange: this.handleUrlChange.bind(this),
onKeyDown: this.handleKeyDown.bind(this),
},
{
elemtype: "iconbutton",
icon: "rotate-right",
click: this.handleRefresh.bind(this),
},
],
});
return rtn;
});
```
## Header Elements (`HeaderElem`)
The `viewText` atom can return an array of these element types:
```typescript
// Icon button
{
elemtype: "iconbutton",
icon: "refresh",
title: "Tooltip text",
click: () => { /* handler */ },
disabled?: boolean,
iconColor?: string,
iconSpin?: boolean,
noAction?: boolean, // Shows icon but no click action
}
// Text element
{
elemtype: "text",
text: "Display text",
className?: string,
noGrow?: boolean,
ref?: React.RefObject<HTMLElement>,
onClick?: (e: React.MouseEvent) => void,
}
// Text button
{
elemtype: "textbutton",
text: "Button text",
className?: string,
title: "Tooltip",
onClick: (e: React.MouseEvent) => void,
}
// Input field
{
elemtype: "input",
value: string,
className?: string,
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void,
onKeyDown?: (e: React.KeyboardEvent<HTMLInputElement>) => void,
onFocus?: (e: React.FocusEvent<HTMLInputElement>) => void,
onBlur?: (e: React.FocusEvent<HTMLInputElement>) => void,
ref?: React.RefObject<HTMLInputElement>,
}
// Container with children
{
elemtype: "div",
className?: string,
children: HeaderElem[],
onMouseOver?: (e: React.MouseEvent) => void,
onMouseOut?: (e: React.MouseEvent) => void,
}
// Menu button (dropdown)
{
elemtype: "menubutton",
// ... MenuButtonProps ...
}
```
## Best Practices
### Jotai Model Pattern
Follow these rules for Jotai atoms in models:
1. **Simple atoms as field initializers**:
```typescript
viewIcon = jotai.atom<string>("circle");
noPadding = jotai.atom<boolean>(true);
```
2. **Derived atoms in constructor** (need dependency on other atoms):
```typescript
constructor(blockId: string, nodeModel: BlockNodeModel) {
this.viewText = jotai.atom((get) => {
const blockData = get(this.blockAtom);
return [/* computed based on blockData */];
});
}
```
3. **Models never use React hooks** - Use `globalStore.get()`/`set()`:
```typescript
refresh() {
const currentData = globalStore.get(this.blockAtom);
globalStore.set(this.dataAtom, newData);
}
```
4. **Components use hooks for atoms**:
```typescript
const data = useAtomValue(model.dataAtom);
const [value, setValue] = useAtom(model.valueAtom);
```
### State Management
- All view state should live in atoms on the model
- Use `useBlockAtom()` helper for block-scoped atoms that persist
- Use `globalStore` for imperative access outside React components
- Subscribe to Wave events using `waveEventSubscribe()`
### Styling
- Create a `.scss` file for your view styles
- Use Tailwind utilities where possible (v4)
- Add `noPadding: atom(true)` for full-bleed content
- Use `blockBg` atom to customize block background
### Focus Management
Implement `giveFocus()` to focus your view when:
- Block gains focus via keyboard navigation
- User clicks the block
- Return `true` if successfully focused, `false` otherwise
### Keyboard Handling
Implement `keyDownHandler(e: WaveKeyboardEvent)` for:
- View-specific keyboard shortcuts
- Return `true` if event was handled (prevents propagation)
- Use `keyutil.checkKeyPressed(waveEvent, "Cmd:K")` for shortcut checks
### Cleanup
Implement `dispose()` to:
- Unsubscribe from Wave events
- Unregister routes/handlers
- Clear timers/intervals
- Release resources
### Connection Management
For views that need remote connections:
```typescript
this.manageConnection = jotai.atom(true); // Show connection picker
this.filterOutNowsh = jotai.atom(true); // Hide nowsh connections
```
Access connection status:
```typescript
const connStatus = jotai.atom((get) => {
const blockData = get(this.blockAtom);
const connName = blockData?.meta?.connection;
return get(getConnStatusAtom(connName));
});
```
## Common Patterns
### Reading Block Metadata
```typescript
import { getBlockMetaKeyAtom } from "@/store/global";
// In constructor:
this.someFlag = getBlockMetaKeyAtom(blockId, "myview:flag");
// In component:
const flag = useAtomValue(model.someFlag);
```
### Configuration Overrides
Wave has a hierarchical config system (global → connection → block):
```typescript
import { getOverrideConfigAtom } from "@/store/global";
this.settingAtom = jotai.atom((get) => {
// Checks block meta, then connection config, then global settings
return get(getOverrideConfigAtom(this.blockId, "myview:setting")) ?? defaultValue;
});
```
### Updating Block Metadata
```typescript
import { RpcApi } from "@/app/store/wshclientapi";
import { TabRpcClient } from "@/app/store/wshrpcutil";
import { WOS } from "@/store/global";
await RpcApi.SetMetaCommand(TabRpcClient, {
oref: WOS.makeORef("block", this.blockId),
meta: { "myview:key": value },
});
```
## Additional Resources
- `frontend/app/block/blockframe-header.tsx` - Block header rendering
- `frontend/app/view/term/term-model.ts` - Complex view example
- `frontend/app/view/webview/webview.tsx` - Navigation UI example
- `frontend/types/custom.d.ts` - Type definitions
================================================
FILE: .kilocode/skills/electron-api/SKILL.md
================================================
---
name: electron-api
description: Guide for adding new Electron APIs to Wave Terminal. Use when implementing new frontend-to-electron communications via preload/IPC.
---
# Adding Electron APIs
Electron APIs allow the frontend to call Electron main process functionality directly via IPC.
## Four Files to Edit
1. [`frontend/types/custom.d.ts`](frontend/types/custom.d.ts) - TypeScript [`ElectronApi`](frontend/types/custom.d.ts:82) type
2. [`emain/preload.ts`](emain/preload.ts) - Expose method via `contextBridge`
3. [`emain/emain-ipc.ts`](emain/emain-ipc.ts) - Implement IPC handler
4. [`frontend/preview/preview-electron-api.ts`](frontend/preview/preview-electron-api.ts) - Add a no-op stub to keep the `previewElectronApi` object in sync with the `ElectronApi` type
## Three Communication Patterns
1. **Sync** - `ipcRenderer.sendSync()` + `ipcMain.on()` + `event.returnValue = ...`
2. **Async** - `ipcRenderer.invoke()` + `ipcMain.handle()`
3. **Fire-and-forget** - `ipcRenderer.send()` + `ipcMain.on()`
## Example: Async Method
### 1. Define TypeScript Interface
In [`frontend/types/custom.d.ts`](frontend/types/custom.d.ts):
```typescript
type ElectronApi = {
captureScreenshot: (rect: Electron.Rectangle) => Promise<string>; // capture-screenshot
};
```
### 2. Expose in Preload
In [`emain/preload.ts`](emain/preload.ts):
```typescript
contextBridge.exposeInMainWorld("api", {
captureScreenshot: (rect: Rectangle) => ipcRenderer.invoke("capture-screenshot", rect),
});
```
### 3. Implement Handler
In [`emain/emain-ipc.ts`](emain/emain-ipc.ts):
```typescript
electron.ipcMain.handle("capture-screenshot", async (event, rect) => {
const tabView = getWaveTabViewByWebContentsId(event.sender.id);
if (!tabView) throw new Error("No tab view found");
const image = await tabView.webContents.capturePage(rect);
return `data:image/png;base64,${image.toPNG().toString("base64")}`;
});
```
### 4. Add Preview Stub
In [`frontend/preview/preview-electron-api.ts`](frontend/preview/preview-electron-api.ts):
```typescript
captureScreenshot: (_rect: Electron.Rectangle) => Promise.resolve(""),
```
### 5. Call from Frontend
```typescript
import { getApi } from "@/store/global";
const dataUrl = await getApi().captureScreenshot({ x: 0, y: 0, width: 800, height: 600 });
```
## Example: Sync Method
### 1. Define
```typescript
type ElectronApi = {
getUserName: () => string; // get-user-name
};
```
### 2. Preload
```typescript
getUserName: () => ipcRenderer.sendSync("get-user-name"),
```
### 3. Handler (⚠️ MUST set event.returnValue or browser hangs)
```typescript
electron.ipcMain.on("get-user-name", (event) => {
event.returnValue = process.env.USER || "unknown";
});
```
### 4. Call
```typescript
import { getApi } from "@/store/global";
const userName = getApi().getUserName(); // blocks until returns
```
## Example: Fire-and-Forget
### 1. Define
```typescript
type ElectronApi = {
openExternal: (url: string) => void; // open-external
};
```
### 2. Preload
```typescript
openExternal: (url) => ipcRenderer.send("open-external", url),
```
### 3. Handler
```typescript
electron.ipcMain.on("open-external", (event, url) => {
electron.shell.openExternal(url);
});
```
## Example: Event Listener
### 1. Define
```typescript
type ElectronApi = {
onZoomFactorChange: (callback: (zoomFactor: number) => void) => void; // zoom-factor-change
};
```
### 2. Preload
```typescript
onZoomFactorChange: (callback) =>
ipcRenderer.on("zoom-factor-change", (_event, zoomFactor) => callback(zoomFactor)),
```
### 3. Send from Main
```typescript
webContents.send("zoom-factor-change", newZoomFactor);
```
## Quick Reference
**Use Sync when:**
- Getting config/env vars
- Quick lookups, no I/O
- ⚠️ **CRITICAL**: Always set `event.returnValue` or browser hangs
**Use Async when:**
- File operations
- Network requests
- Can fail or take time
**Use Fire-and-forget when:**
- No return value needed
- Triggering actions
**Electron API vs RPC:**
- Electron API: Native OS features, window management, Electron APIs
- RPC: Database, backend logic, remote servers
## Checklist
- [ ] Add to [`ElectronApi`](frontend/types/custom.d.ts:82) in [`custom.d.ts`](frontend/types/custom.d.ts)
- [ ] Include IPC channel name in comment
- [ ] Expose in [`preload.ts`](emain/preload.ts)
- [ ] Implement in [`emain-ipc.ts`](emain/emain-ipc.ts)
- [ ] Add no-op stub to [`preview-electron-api.ts`](frontend/preview/preview-electron-api.ts)
- [ ] IPC channel names match exactly
- [ ] **For sync**: Set `event.returnValue` (or browser hangs!)
- [ ] Test end-to-end
================================================
FILE: .kilocode/skills/waveenv/SKILL.md
================================================
---
name: waveenv
description: Guide for creating WaveEnv narrowings in Wave Terminal. Use when writing a named subset type of WaveEnv for a component tree, documenting environmental dependencies, or enabling mock environments for preview/test server usage.
---
# WaveEnv Narrowing Skill
## Purpose
A WaveEnv narrowing creates a _named subset type_ of `WaveEnv` that:
1. Documents exactly which parts of the environment a component tree actually uses.
2. Forms a type contract so callers and tests know what to provide.
3. Enables mocking in the preview/test server — you only need to implement what's listed.
## When To Create One
Create a narrowing whenever you are writing a component (or group of components) that you want to test in the preview server, or when you want to make the environmental dependencies of a component tree explicit.
## Core Principle: Only Include What You Use
**Only list the fields, methods, atoms, and keys that the component tree actually accesses.** If you don't call `wos`, don't include `wos`. If you only call one RPC command, only list that one command. The narrowing is a precise dependency declaration — not a copy of `WaveEnv`.
## File Location
- **Separate file** (preferred for shared/complex envs): name it `<feature>env.ts` next to the component, e.g. `frontend/app/block/blockenv.ts`.
- **Inline** (acceptable for small, single-file components): export the type directly from the component file, e.g. `WidgetsEnv` in `frontend/app/workspace/widgets.tsx`.
## Imports Required
```ts
import {
BlockMetaKeyAtomFnType, // only if you use getBlockMetaKeyAtom
ConnConfigKeyAtomFnType, // only if you use getConnConfigKeyAtom
SettingsKeyAtomFnType, // only if you use getSettingsKeyAtom
WaveEnv,
WaveEnvSubset,
} from "@/app/waveenv/waveenv";
```
## The Shape
```ts
export type MyEnv = WaveEnvSubset<{
// --- Simple WaveEnv properties ---
// Copy the type verbatim from WaveEnv with WaveEnv["key"] syntax.
isDev: WaveEnv["isDev"];
createBlock: WaveEnv["createBlock"];
showContextMenu: WaveEnv["showContextMenu"];
platform: WaveEnv["platform"];
// --- electron: list only the methods you call ---
electron: {
openExternal: WaveEnv["electron"]["openExternal"];
};
// --- rpc: list only the commands you call ---
rpc: {
ActivityCommand: WaveEnv["rpc"]["ActivityCommand"];
ConnEnsureCommand: WaveEnv["rpc"]["ConnEnsureCommand"];
};
// --- atoms: list only the atoms you read ---
atoms: {
modalOpen: WaveEnv["atoms"]["modalOpen"];
fullConfigAtom: WaveEnv["atoms"]["fullConfigAtom"];
};
// --- wos: always take the whole thing, no sub-typing needed ---
wos: WaveEnv["wos"];
// --- services: list only the services you call; no method-level narrowing ---
services: {
block: WaveEnv["services"]["block"];
workspace: WaveEnv["services"]["workspace"];
};
// --- key-parameterized atom factories: enumerate the keys you use ---
getSettingsKeyAtom: SettingsKeyAtomFnType<"app:focusfollowscursor" | "window:magnifiedblockopacity">;
getBlockMetaKeyAtom: BlockMetaKeyAtomFnType<"view" | "frame:title" | "connection">;
getConnConfigKeyAtom: ConnConfigKeyAtomFnType<"conn:wshenabled">;
// --- other atom helpers: copy verbatim ---
getConnStatusAtom: WaveEnv["getConnStatusAtom"];
getLocalHostDisplayNameAtom: WaveEnv["getLocalHostDisplayNameAtom"];
}>;
```
### Automatically Included Fields
Every `WaveEnvSubset<T>` automatically includes the mock fields — you never need to declare them:
- `isMock: boolean`
- `mockSetWaveObj: <T extends WaveObj>(oref: string, obj: T) => void`
- `mockModels?: Map<any, any>`
### Rules for Each Section
| Section | Pattern | Notes |
| -------------------------- | ------------------------------------------------------ | -------------------------------------------------------------------------------------------------- |
| `electron` | `electron: { method: WaveEnv["electron"]["method"]; }` | List every method called; omit the rest. |
| `rpc` | `rpc: { Cmd: WaveEnv["rpc"]["Cmd"]; }` | List every RPC command called; omit the rest. |
| `atoms` | `atoms: { atom: WaveEnv["atoms"]["atom"]; }` | List every atom read; omit the rest. |
| `wos` | `wos: WaveEnv["wos"]` | Take the whole `wos` object (no sub-typing needed), but **only add it if `wos` is actually used**. |
| `services` | `services: { svc: WaveEnv["services"]["svc"]; }` | List each service used; take the whole service object (no method-level narrowing). |
| `getSettingsKeyAtom` | `SettingsKeyAtomFnType<"key1" \| "key2">` | Union all settings keys accessed. |
| `getBlockMetaKeyAtom` | `BlockMetaKeyAtomFnType<"key1" \| "key2">` | Union all block meta keys accessed. |
| `getConnConfigKeyAtom` | `ConnConfigKeyAtomFnType<"key1">` | Union all conn config keys accessed. |
| All other `WaveEnv` fields | `WaveEnv["fieldName"]` | Copy type verbatim. |
## Using the Narrowed Type in Components
```ts
import { useWaveEnv } from "@/app/waveenv/waveenv";
import { MyEnv } from "./myenv";
const MyComponent = memo(() => {
const env = useWaveEnv<MyEnv>();
// TypeScript now enforces you only access what's in MyEnv.
const val = useAtomValue(env.getSettingsKeyAtom("app:focusfollowscursor"));
...
});
```
The generic parameter on `useWaveEnv<MyEnv>()` casts the context to your narrowed type. The real production `WaveEnv` satisfies every narrowing; mock envs only need to implement the listed subset.
## Real Examples
- `BlockEnv` in `frontend/app/block/blockenv.ts` — complex narrowing with all section types, in a separate file.
- `WidgetsEnv` in `frontend/app/workspace/widgets.tsx` — smaller narrowing defined inline in the component file.
================================================
FILE: .kilocode/skills/wps-events/SKILL.md
================================================
---
name: wps-events
description: Guide for working with Wave Terminal's WPS (Wave PubSub) event system. Use when implementing new event types, publishing events, subscribing to events, or adding asynchronous communication between components.
---
# WPS Events Guide
## Overview
WPS (Wave PubSub) is Wave Terminal's publish-subscribe event system that enables different parts of the application to communicate asynchronously. The system uses a broker pattern to route events from publishers to subscribers based on event types and scopes.
## Key Files
- `pkg/wps/wpstypes.go` - Event type constants and data structures
- `pkg/wps/wps.go` - Broker implementation and core logic
- `pkg/wcore/wcore.go` - Example usage patterns
## Event Structure
Events in WPS have the following structure:
```go
type WaveEvent struct {
Event string `json:"event"` // Event type constant
Scopes []string `json:"scopes,omitempty"` // Optional scopes for targeted delivery
Sender string `json:"sender,omitempty"` // Optional sender identifier
Persist int `json:"persist,omitempty"` // Number of events to persist in history
Data any `json:"data,omitempty"` // Event payload
}
```
## Adding a New Event Type
### Step 1: Define the Event Constant
Add your event type constant to `pkg/wps/wpstypes.go`:
```go
const (
Event_BlockClose = "blockclose"
Event_ConnChange = "connchange"
// ... other events ...
Event_YourNewEvent = "your:newevent" // type: YourEventData (or "none" if no data)
)
```
**Naming Convention:**
- Use descriptive PascalCase for the constant name with `Event_` prefix
- Use lowercase with colons for the string value (e.g., "namespace:eventname")
- Group related events with the same namespace prefix
- Always add a `// type: <TypeName>` comment; use `// type: none` if no data is sent
### Step 2: Add to AllEvents
Add your new constant to the `AllEvents` slice in `pkg/wps/wpstypes.go`:
```go
var AllEvents []string = []string{
// ... existing events ...
Event_YourNewEvent,
}
```
### Step 3: Register in WaveEventDataTypes (REQUIRED)
You **must** add an entry to `WaveEventDataTypes` in `pkg/tsgen/tsgenevent.go`. This drives TypeScript type generation for the event's `data` field:
```go
var WaveEventDataTypes = map[string]reflect.Type{
// ... existing entries ...
wps.Event_YourNewEvent: reflect.TypeOf(YourEventData{}), // value type
// wps.Event_YourNewEvent: reflect.TypeOf((*YourEventData)(nil)), // pointer type
// wps.Event_YourNewEvent: nil, // no data (type: none)
}
```
- Use `reflect.TypeOf(YourType{})` for value types
- Use `reflect.TypeOf((*YourType)(nil))` for pointer types
- Use `nil` if no data is sent for the event
### Step 4: Define Event Data Structure (Optional)
If your event carries structured data, define a type for it:
```go
type YourEventData struct {
Field1 string `json:"field1"`
Field2 int `json:"field2"`
}
```
### Step 5: Expose Type to Frontend (If Needed)
If your event data type isn't already exposed via an RPC call, you need to add it to `pkg/tsgen/tsgen.go` so TypeScript types are generated:
```go
// add extra types to generate here
var ExtraTypes = []any{
waveobj.ORef{},
// ... other types ...
uctypes.RateLimitInfo{}, // Example: already added
YourEventData{}, // Add your new type here
}
```
Then run code generation:
```bash
task generate
```
This will update `frontend/types/gotypes.d.ts` with TypeScript definitions for your type, ensuring type safety in the frontend when handling these events.
## Publishing Events
### Basic Publishing
To publish an event, use the global broker:
```go
import "github.com/wavetermdev/waveterm/pkg/wps"
wps.Broker.Publish(wps.WaveEvent{
Event: wps.Event_YourNewEvent,
Data: yourData,
})
```
### Publishing with Scopes
Scopes allow targeted event delivery. Subscribers can filter events by scope:
```go
wps.Broker.Publish(wps.WaveEvent{
Event: wps.Event_WaveObjUpdate,
Scopes: []string{oref.String()}, // Target specific object
Data: updateData,
})
```
### Publishing in a Goroutine
To avoid blocking the caller, publish events asynchronously:
```go
go func() {
wps.Broker.Publish(wps.WaveEvent{
Event: wps.Event_YourNewEvent,
Data: data,
})
}()
```
**When to use goroutines:**
- When publishing from performance-critical code paths
- When the event is informational and doesn't need immediate delivery
- When publishing from code that holds locks (to prevent deadlocks)
### Event Persistence
Events can be persisted in memory for late subscribers:
```go
wps.Broker.Publish(wps.WaveEvent{
Event: wps.Event_YourNewEvent,
Persist: 100, // Keep last 100 events
Data: data,
})
```
## Complete Example: Rate Limit Updates
This example shows how rate limit information is published when AI chat responses include rate limit headers.
### 1. Define the Event Type
In `pkg/wps/wpstypes.go`:
```go
const (
// ... other events ...
Event_WaveAIRateLimit = "waveai:ratelimit"
)
```
### 2. Publish the Event
In `pkg/aiusechat/usechat.go`:
```go
import "github.com/wavetermdev/waveterm/pkg/wps"
func updateRateLimit(info *uctypes.RateLimitInfo) {
if info == nil {
return
}
rateLimitLock.Lock()
defer rateLimitLock.Unlock()
globalRateLimitInfo = info
// Publish event in goroutine to avoid blocking
go func() {
wps.Broker.Publish(wps.WaveEvent{
Event: wps.Event_WaveAIRateLimit,
Data: info, // RateLimitInfo struct
})
}()
}
```
### 3. Subscribe to the Event (Frontend)
In the frontend, subscribe to events via WebSocket:
```typescript
// Subscribe to rate limit updates
const subscription = {
event: "waveai:ratelimit",
allscopes: true, // Receive all rate limit events
};
```
## Subscribing to Events
### From Go Code
```go
// Subscribe to all events of a type
wps.Broker.Subscribe(routeId, wps.SubscriptionRequest{
Event: wps.Event_YourNewEvent,
AllScopes: true,
})
// Subscribe to specific scopes
wps.Broker.Subscribe(routeId, wps.SubscriptionRequest{
Event: wps.Event_WaveObjUpdate,
Scopes: []string{"workspace:123"},
})
// Unsubscribe
wps.Broker.Unsubscribe(routeId, wps.Event_YourNewEvent)
```
### Scope Matching
Scopes support wildcard matching:
- `*` matches a single scope segment
- `**` matches multiple scope segments
```go
// Subscribe to all workspace events
wps.Broker.Subscribe(routeId, wps.SubscriptionRequest{
Event: wps.Event_WaveObjUpdate,
Scopes: []string{"workspace:*"},
})
```
## Best Practices
1. **Use Namespaces**: Prefix event names with a namespace (e.g., `waveai:`, `workspace:`, `block:`)
2. **Don't Block**: Use goroutines when publishing from performance-critical code or while holding locks
3. **Type-Safe Data**: Define struct types for event data rather than using maps
4. **Scope Wisely**: Use scopes to limit event delivery and reduce unnecessary processing
5. **Document Events**: Add comments explaining when events are fired and what data they carry
6. **Consider Persistence**: Use `Persist` for events that late subscribers might need (like status updates). This is normally not used. We normally do a live RPC call to get the current value and then subscribe for updates.
## Common Event Patterns
### Status Updates
```go
wps.Broker.Publish(wps.WaveEvent{
Event: wps.Event_ControllerStatus,
Scopes: []string{blockId},
Persist: 1, // Keep only latest status
Data: statusData,
})
```
### Object Updates
```go
wps.Broker.Publish(wps.WaveEvent{
Event: wps.Event_WaveObjUpdate,
Scopes: []string{oref.String()},
Data: waveobj.WaveObjUpdate{
UpdateType: waveobj.UpdateType_Update,
OType: obj.GetOType(),
OID: waveobj.GetOID(obj),
Obj: obj,
},
})
```
### Batch Updates
```go
// Helper function for multiple updates
func (b *BrokerType) SendUpdateEvents(updates waveobj.UpdatesRtnType) {
for _, update := range updates {
b.Publish(WaveEvent{
Event: Event_WaveObjUpdate,
Scopes: []string{waveobj.MakeORef(update.OType, update.OID).String()},
Data: update,
})
}
}
```
## Debugging
To debug event flow:
1. Check broker subscription map: `wps.Broker.SubMap`
2. View persisted events: `wps.Broker.ReadEventHistory(eventType, scope, maxItems)`
3. Add logging in publish/subscribe methods
4. Monitor WebSocket traffic in browser dev tools
## Quick Reference
When adding a new event:
- [ ] Add event constant to [`pkg/wps/wpstypes.go`](pkg/wps/wpstypes.go) with a `// type: <TypeName>` comment (use `none` if no data)
- [ ] Add the constant to `AllEvents` in [`pkg/wps/wpstypes.go`](pkg/wps/wpstypes.go)
- [ ] **REQUIRED**: Add an entry to `WaveEventDataTypes` in [`pkg/tsgen/tsgenevent.go`](pkg/tsgen/tsgenevent.go) — use `nil` for events with no data
- [ ] Define event data structure (if needed)
- [ ] Add data type to `pkg/tsgen/tsgen.go` for frontend use (if not already exposed via RPC)
- [ ] Run `task generate` to update TypeScript types
- [ ] Publish events using `wps.Broker.Publish()`
- [ ] Use goroutines for non-blocking publish when appropriate
- [ ] Subscribe to events in relevant components
================================================
FILE: .prettierignore
================================================
build
bin
.git
frontend/dist
frontend/node_modules
*.min.*
frontend/app/store/services.ts
frontend/types/gotypes.d.ts
================================================
FILE: .roo/rules/overview.md
================================================
# Wave Terminal - High Level Architecture Overview
## Project Description
Wave Terminal is an open-source AI-native terminal built for seamless workflows. It's an Electron application that serves as a command line terminal host (it hosts CLI applications rather than running inside a CLI). The application combines a React frontend with a Go backend server to provide a modern terminal experience with advanced features.
## Top-Level Directory Structure
```
waveterm/
├── emain/ # Electron main process code
├── frontend/ # React application (renderer process)
├── cmd/ # Go command-line applications
├── pkg/ # Go packages/modules
├── db/ # Database migrations
├── docs/ # Documentation (Docusaurus)
├── build/ # Build configuration and assets
├── assets/ # Application assets (icons, images)
├── public/ # Static public assets
├── tests/ # Test files
├── .github/ # GitHub workflows and configuration
└── Configuration files (package.json, tsconfig.json, etc.)
```
## Architecture Components
### 1. Electron Main Process (`emain/`)
The Electron main process handles the native desktop application layer:
**Key Files:**
- [`emain.ts`](emain/emain.ts) - Main entry point, application lifecycle management
- [`emain-window.ts`](emain/emain-window.ts) - Window management (`WaveBrowserWindow` class)
- [`emain-tabview.ts`](emain/emain-tabview.ts) - Tab view management (`WaveTabView` class)
- [`emain-wavesrv.ts`](emain/emain-wavesrv.ts) - Go backend server integration
- [`emain-wsh.ts`](emain/emain-wsh.ts) - WSH (Wave Shell) client integration
- [`emain-ipc.ts`](emain/emain-ipc.ts) - IPC handlers for frontend ↔ main process communication
- [`emain-menu.ts`](emain/emain-menu.ts) - Application menu system
- [`updater.ts`](emain/updater.ts) - Auto-update functionality
- [`preload.ts`](emain/preload.ts) - Preload script for renderer security
- [`preload-webview.ts`](emain/preload-webview.ts) - Webview preload script
### 2. Frontend React Application (`frontend/`)
The React application runs in the Electron renderer process:
**Structure:**
```
frontend/
├── app/ # Main application code
│ ├── app.tsx # Root App component
│ ├── aipanel/ # AI panel UI
│ ├── block/ # Block-based UI components
│ ├── element/ # Reusable UI elements
│ ├── hook/ # Custom React hooks
│ ├── modals/ # Modal components
│ ├── store/ # State management (Jotai)
│ ├── tab/ # Tab components
│ ├── view/ # Different view types
│ │ ├── codeeditor/ # Code editor (Monaco)
│ │ ├── preview/ # File preview
│ │ ├── sysinfo/ # System info view
│ │ ├── term/ # Terminal view
│ │ ├── tsunami/ # Tsunami builder view
│ │ ├── vdom/ # Virtual DOM view
│ │ ├── waveai/ # AI chat integration
│ │ ├── waveconfig/ # Config editor view
│ │ └── webview/ # Web view
│ └── workspace/ # Workspace management
├── builder/ # Builder app entry
├── layout/ # Layout system
├── preview/ # Standalone preview renderer
├── types/ # TypeScript type definitions
└── util/ # Utility functions
```
**Key Technologies:**
- Electron (desktop application shell)
- React 19 with TypeScript
- Jotai for state management
- Monaco Editor for code editing
- XTerm.js for terminal emulation
- Tailwind CSS v4 for styling
- SCSS for additional styling (deprecated, new components should use Tailwind)
- Vite / electron-vite for bundling
- Task (Taskfile.yml) for build and code generation commands
### 3. Go Backend Server (`cmd/server/`)
The Go backend server handles all heavy lifting operations:
**Entry Point:** [`main-server.go`](cmd/server/main-server.go)
### 4. Go Packages (`pkg/`)
The Go codebase is organized into modular packages:
**Key Packages:**
- `wstore/` - Database and storage layer
- `wconfig/` - Configuration management
- `wcore/` - Core business logic
- `wshrpc/` - RPC communication system
- `wshutil/` - WSH (Wave Shell) utilities
- `blockcontroller/` - Block execution management
- `remote/` - Remote connection handling
- `filestore/` - File storage system
- `web/` - Web server and WebSocket handling
- `telemetry/` - Usage analytics and telemetry
- `waveobj/` - Core data objects
- `service/` - Service layer
- `wps/` - Wave PubSub event system
- `waveai/` - AI functionality
- `shellexec/` - Shell execution
- `util/` - Common utilities
### 5. Command Line Tools (`cmd/`)
Key Go command-line utilities:
- `wsh/` - Wave Shell command-line tool
- `server/` - Main backend server
- `generatego/` - Code generation
- `generateschema/` - Schema generation
- `generatets/` - TypeScript generation
## Communication Architecture
The core communication system is built around the **WSH RPC (Wave Shell RPC)** system, which provides a unified interface for all inter-process communication: frontend ↔ Go backend, Electron main process ↔ backend, and backend ↔ remote systems (SSH, WSL).
### WSH RPC System (`pkg/wshrpc/`)
The WSH RPC system is the backbone of Wave Terminal's communication architecture:
**Key Components:**
- [`wshrpctypes.go`](pkg/wshrpc/wshrpctypes.go) - Core RPC interface and type definitions (source of truth for all RPC commands)
- [`wshserver/`](pkg/wshrpc/wshserver/) - Server-side RPC implementation
- [`wshremote/`](pkg/wshrpc/wshremote/) - Remote connection handling
- [`wshclient.go`](pkg/wshrpc/wshclient.go) - Go client for making RPC calls
- [`frontend/app/store/wshclientapi.ts`](frontend/app/store/wshclientapi.ts) - Generated TypeScript RPC client
**Routing:** Callers address RPC calls using _routes_ (e.g. a block ID, connection name, or `"waveapp"`) rather than caring about the underlying transport. The RPC layer resolves the route to the correct transport (WebSocket, Unix socket, SSH tunnel, stdio) automatically. This means the same RPC interface works whether the target is local or a remote SSH connection.
## Development Notes
- **Build commands** - Use `task` (Taskfile.yml) for all build, generate, and packaging commands
- **Code generation** - Run `task generate` after modifying Go types in `pkg/wshrpc/wshrpctypes.go`, `pkg/wconfig/settingsconfig.go`, or `pkg/waveobj/wtypemeta.go`
- **Testing** - Vitest for frontend unit tests; standard `go test` for Go packages
- **Database migrations** - SQL migration files in `db/migrations-wstore/` and `db/migrations-filestore/`
- **Documentation** - Docusaurus site in `docs/`
================================================
FILE: .roo/rules/rules.md
================================================
Wave Terminal is a modern terminal which provides graphical blocks, dynamic layout, workspaces, and SSH connection management. It is cross platform and built on electron.
### Project Structure
It has a TypeScript/React frontend and a Go backend. They talk together over `wshrpc` a custom RPC protocol that is implemented over websocket (and domain sockets).
### Coding Guidelines
- **Go Conventions**:
- Don't use custom enum types in Go. Instead, use string constants (e.g., `const StatusRunning = "running"` rather than creating a custom type like `type Status string`).
- Use string constants for status values, packet types, and other string-based enumerations.
- in Go code, prefer using Printf() vs Println()
- use "Make" as opposed to "New" for struct initialization func names
- in general const decls go at the top of the file (before types and functions)
- NEVER run `go build` (especially in weird sub-package directories). we can tell if everything compiles by seeing there are no problems/errors.
- **Synchronization**:
- Always prefer to use the `lock.Lock(); defer lock.Unlock()` pattern for synchronization if possible
- Avoid inline lock/unlock pairs - instead create helper functions that use the defer pattern
- When accessing shared data structures (maps, slices, etc.), ensure proper locking
- Example: Instead of `gc.lock.Lock(); gc.map[key]++; gc.lock.Unlock()`, create a helper function like `getNextValue(key string) int { gc.lock.Lock(); defer gc.lock.Unlock(); gc.map[key]++; return gc.map[key] }`
- **TypeScript Imports**:
- Use `@/...` for imports from different parts of the project (configured in `tsconfig.json` as `"@/*": ["frontend/*"]`).
- Prefer relative imports (`"./name"`) only within the same directory.
- Use named exports exclusively; avoid default exports. It's acceptable to export functions directly (e.g., React Components).
- Our indent is 4 spaces
- **JSON Field Naming**: All fields must be lowercase, without underscores.
- **TypeScript Conventions**
- **Type Handling**:
- In TypeScript we have strict null checks off, so no need to add "| null" to all the types.
- In TypeScript for Jotai atoms, if we want to write, we need to type the atom as a PrimitiveAtom<Type>
- Jotai has a bug with strict null checks off where if you create a null atom, e.g. atom(null) it does not "type" correctly. That's no issue, just cast it to the proper PrimitiveAtom type (no "| null") and it will work fine.
- Generally never use "=== undefined" or "!== undefined". This is bad style. Just use a "== null" or "!= null" unless it is a very specific case where we need to distinguish undefined from null.
- **Coding Style**:
- Use all lowercase filenames (except where case is actually important like Taskfile.yml)
- Import the "cn" function from "@/util/util" to do classname / clsx class merge (it uses twMerge underneath)
- For element variants use class-variance-authority
- Do NOT create private fields in classes (they are impossible to inspect)
- Use PascalCase for global consts at the top of files
- **Component Practices**:
- Make sure to add cursor-pointer to buttons/links and clickable items
- NEVER use cursor-help (it looks terrible)
- useAtom() and useAtomValue() are react HOOKS, so they must be called at the component level not inline in JSX
- If you use React.memo(), make sure to add a displayName for the component
- Other
- never use atob() or btoa() (not UTF-8 safe). use functions in frontend/util/util.ts for base64 decoding and encoding
- In general, when writing functions, we prefer _early returns_ rather than putting the majority of a function inside of an if block.
### Styling
- We use **Tailwind v4** to style. Custom stuff is defined in frontend/tailwindsetup.css
- _never_ use cursor-help, or cursor-not-allowed (it looks terrible)
- We have custom CSS setup as well, so it is a hybrid system. For new code we prefer tailwind, and are working to migrate code to all use tailwind.
- For accent buttons, use "bg-accent/80 text-primary rounded hover:bg-accent transition-colors cursor-pointer" (if you do "bg-accent hover:bg-accent/80" it looks weird as on hover the button gets darker instead of lighter)
### RPC System
To define a new RPC call, add the new definition to `pkg/wshrpc/wshrpctypes.go` including any input/output data that is required. After modifying wshrpctypes.go run `task generate` to generate the client APIs.
For normal "server" RPCs (where a frontend client is calling the main server) you should implement the RPC call in `pkg/wshrpc/wshserver.go`.
### Electron API
From within the FE to get the electron API (e.g. the preload functions):
```ts
import { getApi } from "@/store/global";
getApi().getIsDev();
```
The full API is defined in custom.d.ts as type ElectronApi.
### Code Generation
- **TypeScript Types**: TypeScript types are automatically generated from Go types. After modifying Go types in `pkg/wshrpc/wshrpctypes.go`, run `task generate` to update the TypeScript type definitions in `frontend/types/gotypes.d.ts`.
- **Manual Edits**: Do not manually edit generated files like `frontend/types/gotypes.d.ts` or `frontend/app/store/wshclientapi.ts`. Instead, modify the source Go types and run `task generate`.
### Frontend Architecture
- The application uses Jotai for state management.
- When working with Jotai atoms that need to be updated, define them as `PrimitiveAtom<Type>` rather than just `atom<Type>`.
### Notes
- **CRITICAL: Completion format MUST be: "Done: [one-line description]"**
- **Keep your Task Completed summaries VERY short**
- **No double-summarization** - Put your summary ONLY inside attempt_completion. Do not write a summary in the message body AND then repeat it in attempt_completion. One summary, one place.
- **Go directly to completion** - After making changes, proceed directly to attempt_completion without summarizing
- The project is currently an un-released POC / MVP. Do not worry about backward compatibility when making changes
- With React hooks, always complete all hook calls at the top level before any conditional returns (including jotai hook calls useAtom and useAtomValue); when a user explicitly tells you a function handles null inputs, trust them and stop trying to "protect" it with unnecessary checks or workarounds.
- **Match response length to question complexity** - For simple, direct questions in Ask mode (especially those that can be answered in 1-2 sentences), provide equally brief answers. Save detailed explanations for complex topics or when explicitly requested.
- **CRITICAL** - useAtomValue and useAtom are React HOOKS. They cannot be used inline in JSX code, they must appear at the top of a component in the hooks area of the react code.
- for simple functions, we prefer `if (!cond) { return }; functionality;` pattern over `if (cond) { functionality }` because it produces less indentation and is easier to follow.
- It is now 2026, so if you write new files, or update files use 2026 for the copyright year
- React.MutableRefObject is deprecated, just use React.RefObject now (in React 19 RefObject is always mutable)
### Strict Comment Rules
- **NEVER add comments that merely describe what code is doing**:
- ❌ `mutex.Lock() // Lock the mutex`
- ❌ `counter++ // Increment the counter`
- ❌ `buffer.Write(data) // Write data to buffer`
- ❌ `// Header component for app run list` (above AppRunListHeader)
- ❌ `// Updated function to include onClick parameter`
- ❌ `// Changed padding calculation`
- ❌ `// Removed unnecessary div`
- ❌ `// Using the model's width value here`
- **Only use comments for**:
- Explaining WHY a particular approach was chosen
- Documenting non-obvious edge cases or side effects
- Warning about potential pitfalls in usage
- Explaining complex algorithms that can't be simplified
- **When in doubt, leave it out**. No comment is better than a redundant comment.
- **Never add comments explaining code changes** - The code should speak for itself, and version control tracks changes. The one exception to this rule is if it is a very unobvious implementation. Something that someone would typically implement in a different (wrong) way. Then the comment helps us remember WHY we changed it to a less obvious implementation.
- **Never remove existing comments** unless specifically directed by the user. Comments that are already defined in existing code have been vetted by the user.
### Jotai Model Pattern (our rules)
- **Atoms live on the model.**
- **Simple atoms:** define as **field initializers**.
- **Atoms that depend on values/other atoms:** create in the **constructor**.
- Models **never use React hooks**; they use `globalStore.get/set`.
- It's fine to call model methods from **event handlers** or **`useEffect`**.
- Models use the **singleton pattern** with a `private static instance` field, a `private constructor`, and a `static getInstance()` method.
- The constructor is `private`; callers always use `getInstance()`.
```ts
// model/MyModel.ts
import * as jotai from "jotai";
import { globalStore } from "@/app/store/jotaiStore";
export class MyModel {
private static instance: MyModel | null = null;
// simple atoms (field init)
statusAtom = jotai.atom<"idle" | "running" | "error">("idle");
outputAtom = jotai.atom("");
// ctor-built atoms (need types)
lengthAtom!: jotai.Atom<number>;
thresholdedAtom!: jotai.Atom<boolean>;
private constructor(initialThreshold = 20) {
this.lengthAtom = jotai.atom((get) => get(this.outputAtom).length);
this.thresholdedAtom = jotai.atom((get) => get(this.lengthAtom) > initialThreshold);
}
static getInstance(): MyModel {
if (!MyModel.instance) {
MyModel.instance = new MyModel();
}
return MyModel.instance;
}
static resetInstance(): void {
MyModel.instance = null;
}
async doWork() {
globalStore.set(this.statusAtom, "running");
// ... do work ...
globalStore.set(this.statusAtom, "idle");
}
}
```
```tsx
// component usage (events & effects OK)
import { useAtomValue } from "jotai";
function Panel() {
const model = MyModel.getInstance();
const status = useAtomValue(model.statusAtom);
const isBig = useAtomValue(model.thresholdedAtom);
const onClick = () => model.doWork();
return (
<div>
{status} • {String(isBig)}
</div>
);
}
```
**Remember:** singleton pattern with `getInstance()`, `private constructor`, atoms on the model, simple-as-fields, ctor for dependent/derived, updates via `globalStore.set/get`.
**Note** Older models may not use the singleton pattern
### Tool Use
Do NOT use write_to_file unless it is a new file or very short. Always prefer to use replace_in_file. Often your diffs fail when a file may be out of date in your cache vs the actual on-disk format. You should RE-READ the file and try to create diffs again if your diffs fail rather than fall back to write_to_file. If you feel like your ONLY option is to use write_to_file please ask first.
Also when adding content to the end of files prefer to use the new append_file tool rather than trying to create a diff (as your diffs are often not specific enough and end up inserting code in the middle of existing functions).
### Directory Awareness
- **ALWAYS verify the current working directory before executing commands**
- Either run "pwd" first to verify the directory, or do a "cd" to the correct absolute directory before running commands
- When running tests, do not "cd" to the pkg directory and then run the test. This screws up the cwd and you never recover. run the test from the project root instead.
### Testing / Compiling Go Code
No need to run a `go build` or a `go run` to just check if the Go code compiles. VSCode's errors/problems cover this well.
If there are no Go errors in VSCode you can assume the code compiles fine.
================================================
FILE: .vscode/extensions.json
================================================
{
"recommendations": [
"esbenp.prettier-vscode",
"golang.go",
"dbaeumer.vscode-eslint",
"vitest.explorer",
"task.vscode-task"
]
}
================================================
FILE: .vscode/settings.json
================================================
{
"editor.formatOnSave": true,
"editor.detectIndentation": false,
"editor.formatOnPaste": true,
"editor.tabSize": 4,
"editor.insertSpaces": false,
"prettier.useEditorConfig": true,
"diffEditor.renderSideBySide": false,
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[less]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[scss]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[css]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[html]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[yaml]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.insertSpaces": true,
"editor.autoIndent": "keep"
},
"[github-actions-workflow]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.insertSpaces": true,
"editor.autoIndent": "keep"
},
"[go]": {
"editor.defaultFormatter": "golang.go"
},
"[mdx]": {
"editor.wordWrap": "on"
},
"[md]": {
"editor.wordWrap": "on"
},
"files.associations": {
"*.css": "tailwindcss"
},
"gopls": {
"analyses": {
"QF1003": false
},
"directoryFilters": ["-tsunami/frontend/scaffold", "-dist", "-make"]
},
"tailwindCSS.lint.suggestCanonicalClasses": "ignore",
"go.coverageDecorator": {
"type": "gutter"
}
}
================================================
FILE: .zed/settings.json
================================================
{
"format_on_save": "on",
"languages": {
"JavaScript": {
"formatter": {
"external": {
"command": "./node_modules/.bin/prettier",
"arguments": ["--stdin-filepath", "{buffer_path}"]
}
}
},
"JSON": {
"formatter": {
"external": {
"command": "./node_modules/.bin/prettier",
"arguments": ["--stdin-filepath", "{buffer_path}"]
}
}
},
"TypeScript": {
"formatter": {
"external": {
"command": "./node_modules/.bin/prettier",
"arguments": ["--stdin-filepath", "{buffer_path}"]
}
}
},
"CSS": {
"formatter": {
"external": {
"command": "./node_modules/.bin/prettier",
"arguments": ["--stdin-filepath", "{buffer_path}"]
}
}
},
"SCSS": {
"formatter": {
"external": {
"command": "./node_modules/.bin/prettier",
"arguments": ["--stdin-filepath", "{buffer_path}"]
}
}
},
"YAML": {
"formatter": {
"external": {
"command": "./node_modules/.bin/prettier",
"arguments": ["--stdin-filepath", "{buffer_path}"]
}
}
}
},
"lsp": {
"eslint": {
"settings": {
"codeActionOnSave": {
"rules": ["import/order"]
},
"nodePath": "./node_modules/.bin",
"language_ids": ["typescript", "javascript", "typescriptreact", "javascriptreact"]
}
}
}
}
================================================
FILE: ACKNOWLEDGEMENTS.md
================================================
# Open-Source Acknowledgements
We make use of many amazing open-source projects to build Wave Terminal. We automatically generate license reports via FOSSA to comply with the license distribution requirements of our dependencies. Below is a summary of the licenses used by our product. For a full report, see [here](https://app.fossa.com/reports/24d13570-624b-4450-8c22-756e513060c9?full=true) (the page may take 20-30s to load).
[](https://app.fossa.com/projects/git%2Bgithub.com%2Fwavetermdev%2Fwaveterm?ref=badge_large)
================================================
FILE: BUILD.md
================================================
# Building Wave Terminal
These instructions are for setting up dependencies and building Wave Terminal from source on macOS, Linux, and Windows.
## Prerequisites
### OS-specific dependencies
See [Minimum requirements](README.md#minimum-requirements) to learn whether your OS is supported.
#### macOS
macOS does not have any platform-specific dependencies.
#### Linux
You must have `zip` installed. We also require the [Zig](https://ziglang.org/) compiler for statically linking CGO.
Debian/Ubuntu:
```sh
sudo apt install zip snapd
sudo snap install zig --classic --beta
```
Fedora/RHEL:
```sh
sudo dnf install zip zig
```
Arch:
```sh
sudo pacman -S zip zig
```
##### For packaging
For packaging, the following additional packages are required:
- `fpm` — If you're on x64 you can skip this. If you're on ARM64, install fpm via [Gem](https://rubygems.org/gems/fpm)
- `rpm` — If you're not on Fedora, install RPM via your package manager.
- `snapd` — If your distro doesn't already include it, [install `snapd`](https://snapcraft.io/docs/installing-snapd)
- `lxd` — [Installation instructions](https://canonical.com/lxd/install)
- `snapcraft` — Run `sudo snap install snapcraft --classic`
- `libarchive-tools` — Install via your package manager
- `binutils` — Install via your package manager
- `libopenjp2-tools` — Install via your package manager
- `squashfs-tools` — Install via your package manager
#### Windows
You will need the [Zig](https://ziglang.org/) compiler for statically linking CGO.
You can find installation instructions for Zig on Windows [here](https://ziglang.org/learn/getting-started/#managers).
### Task
Download and install Task (to run the build commands): https://taskfile.dev/installation/
Task is a modern equivalent to GNU Make. We use it to coordinate our build steps. You can find our full Task configuration in [Taskfile.yml](Taskfile.yml).
### Go
Download and install Go via your package manager or directly from the website: https://go.dev/doc/install
### NodeJS
Make sure you have a NodeJS 22 LTS installed.
See NodeJS's website for platform-specific instructions: https://nodejs.org/en/download
We now use `npm`, so you can just run an `npm install` to install node dependencies.
## Clone the Repo
```sh
git clone git@github.com:wavetermdev/waveterm.git
```
or
```sh
git clone https://github.com/wavetermdev/waveterm.git
```
## Install code dependencies
The first time you clone the repo, you'll need to run the following to load the dependencies. If you ever have issues building the app, try running this again:
```sh
task init
```
## Build and Run
All the methods below will install Node and Go dependencies when they run the first time. All these should be run from within the Git repository.
### Development server
Run the following command to build the app and run it via Vite's development server (this enables Hot Module Reloading):
```sh
task dev
```
### Standalone
Run the following command to build the app and run it standalone, without the development server. This will not reload on change:
```sh
task start
```
### Packaged
Run the following command to generate a production build and package it. This lets you install the app locally. All artifacts will be placed in `make/`.
```sh
task package
```
If you're on Linux ARM64, run the following:
```sh
USE_SYSTEM_FPM=1 task package
```
## Debugging
### Frontend logs
You can use the regular Chrome DevTools to debug the frontend application. You can open the DevTools using the keyboard shortcut `Cmd+Option+I` on macOS or `Ctrl+Option+I` on Linux and Windows. Logs will be sent to the Console tab in DevTools.
### Backend logs
Backend logs for the development version of Wave can be found at `~/.waveterm-dev/waveapp.log`. Both the NodeJS backend from Electron and the main Go backend will log here.
================================================
FILE: CNAME
================================================
docs.waveterm.dev
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
coc@commandline.dev.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to Wave Terminal
Wave Terminal is an opinionated project with a single active maintainer. Contributions are welcome, but **alignment matters more than volume**.
This document helps you decide _whether_ and _how_ to contribute in a way that's likely to be accepted, saving both of us time.
## High-level expectations
- Wave has a strong product direction and centralized ownership.
- Review bandwidth is limited.
- Not all contributions can or will be accepted, even if they are technically correct.
This is normal for a solo-maintainer project.
## What makes a great contribution
The following are most likely to be accepted:
- **Bug fixes** - especially with clear reproduction steps
- **Documentation improvements** - typos, clarifications, examples
- **Discussed features** - after alignment in Discord
- **Small, focused changes** - easy to review and low risk
If your change is small and obvious (typo fix, narrowly-scoped bug fix, small docs improvement), you are welcome to open a pull request directly.
## Keep changes focused
**Only change what is necessary to accomplish your stated goal.**
If you're fixing a bug in `file.ts`, do not:
- Reformat other files
- Clean up unrelated code
- Fix style issues in files you didn't need to touch
- Combine multiple unrelated fixes in one PR
Even if these changes are "improvements," they make review harder and require unnecessary back-and-forth. If you want to clean up code, discuss it first and submit it as a separate, focused PR.
**One PR = one logical change.**
## Discuss first (required for larger changes)
For anything beyond a small fix, **discussion is required before opening a pull request**.
This includes:
- New features
- UI/UX changes or changes to default behavior
- Refactors or "cleanup" work
- Performance rewrites
- Architectural changes
- Changes that touch many files or systems
**Where to discuss:** Discord is the preferred place for these conversations -- https://discord.gg/XfvZ334gwU
Pull requests that introduce larger changes without prior discussion will be closed without detailed review.
This is not meant to discourage contribution — it is meant to ensure alignment before significant work is done.
## What this project is not
To set expectations clearly:
- Wave is not designed as a "first open source contribution" project
- We do not currently curate beginner-friendly or mentorship issues
- Large, unsolicited changes are unlikely to be accepted
- Mechanical refactors, broad style changes, or drive-by rewrites are not helpful
- AI-assisted contributions are welcome, but PRs must reflect clear understanding of context, existing patterns, and project direction. Low-effort or poorly supervised changes will be closed.
Being clear about this helps everyone spend their time effectively.
## FAQ
**Q: Should I ask before fixing a typo or obvious bug?**
A: No, just open a PR for small, obvious fixes.
**Q: I have an idea for a new feature.**
A: Great! Come discuss it in Discord first. Do not open a PR without prior discussion.
**Q: My PR was closed without detailed feedback.**
A: This usually means it didn't align with project direction or required more review bandwidth than available. This is normal for a solo-maintained project.
**Q: Can I work on an open issue?**
A: Comment on the issue first to confirm it's still relevant and that nobody else is working on it. For anything non-trivial, discuss your approach before implementing.
**Q: I noticed some code that could be cleaner while working on my fix.**
A: Focus on your stated goal. Submit cleanup as a separate PR after discussion, if desired.
## Contributor License Agreement (CLA)
Contributions to this project must be accompanied by a Contributor License Agreement (CLA). You (or your employer) retain the copyright to your contribution; the CLA simply gives us permission to use and
gitextract_d_p9wdmp/ ├── .editorconfig ├── .gitattributes ├── .github/ │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── bug-report.yml │ │ ├── config.yml │ │ └── feature-request.yml │ ├── copilot-instructions.md │ ├── dependabot.yml │ └── workflows/ │ ├── build-helper.yml │ ├── bump-version.yml │ ├── codeql.yml │ ├── copilot-setup-steps.yml │ ├── deploy-docsite.yml │ ├── merge-gatekeeper.yml │ ├── publish-release.yml │ ├── testdriver-build.yml │ └── testdriver.yml ├── .gitignore ├── .golangci.yml ├── .kilocode/ │ ├── rules/ │ │ ├── overview.md │ │ └── rules.md │ └── skills/ │ ├── add-config/ │ │ └── SKILL.md │ ├── add-rpc/ │ │ └── SKILL.md │ ├── add-wshcmd/ │ │ └── SKILL.md │ ├── context-menu/ │ │ └── SKILL.md │ ├── create-view/ │ │ └── SKILL.md │ ├── electron-api/ │ │ └── SKILL.md │ ├── waveenv/ │ │ └── SKILL.md │ └── wps-events/ │ └── SKILL.md ├── .prettierignore ├── .roo/ │ └── rules/ │ ├── overview.md │ └── rules.md ├── .vscode/ │ ├── extensions.json │ └── settings.json ├── .zed/ │ └── settings.json ├── ACKNOWLEDGEMENTS.md ├── BUILD.md ├── CNAME ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE ├── README.ko.md ├── README.md ├── RELEASES.md ├── ROADMAP.md ├── SECURITY.md ├── Taskfile.yml ├── aiprompts/ │ ├── aimodesconfig.md │ ├── aisdk-streaming.md │ ├── aisdk-uimessage-type.md │ ├── anthropic-messages-api.md │ ├── anthropic-streaming.md │ ├── blockcontroller-lifecycle.md │ ├── config-system.md │ ├── conn-arch.md │ ├── contextmenu.md │ ├── fe-conn-arch.md │ ├── focus-layout.md │ ├── focus.md │ ├── getsetconfigvar.md │ ├── layout-simplification.md │ ├── layout.md │ ├── monaco-v0.53.md │ ├── newview.md │ ├── openai-request.md │ ├── openai-streaming-text.md │ ├── openai-streaming.md │ ├── tailwind-container-queries.md │ ├── tsunami-builder.md │ ├── usechat-backend-design.md │ ├── view-prompt.md │ ├── wave-osc-16162.md │ ├── waveai-architecture.md │ ├── waveai-focus-updates.md │ └── wps-events.md ├── build/ │ ├── deb-postinstall.tpl │ ├── entitlements.mac.plist │ └── icon.icns ├── cmd/ │ ├── generatego/ │ │ └── main-generatego.go │ ├── generateschema/ │ │ └── main-generateschema.go │ ├── generatets/ │ │ └── main-generatets.go │ ├── packfiles/ │ │ └── main-packfiles.go │ ├── server/ │ │ └── main-server.go │ ├── test/ │ │ └── test-main.go │ ├── test-conn/ │ │ ├── cliprovider.go │ │ ├── main-test-conn.go │ │ └── testutil.go │ ├── test-streammanager/ │ │ ├── bridge.go │ │ ├── deliverypipe.go │ │ ├── generator.go │ │ ├── main-test-streammanager.go │ │ ├── metrics.go │ │ └── verifier.go │ ├── testai/ │ │ ├── main-testai.go │ │ └── testschema.json │ ├── testopenai/ │ │ └── main-testopenai.go │ ├── testsummarize/ │ │ └── main-testsummarize.go │ └── wsh/ │ ├── cmd/ │ │ ├── csscolormap.go │ │ ├── setmeta_test.go │ │ ├── wshcmd-ai.go │ │ ├── wshcmd-badge.go │ │ ├── wshcmd-blocks.go │ │ ├── wshcmd-conn.go │ │ ├── wshcmd-connserver.go │ │ ├── wshcmd-createblock.go │ │ ├── wshcmd-debug.go │ │ ├── wshcmd-debugterm.go │ │ ├── wshcmd-debugterm_test.go │ │ ├── wshcmd-deleteblock.go │ │ ├── wshcmd-editconfig.go │ │ ├── wshcmd-editor.go │ │ ├── wshcmd-file-util.go │ │ ├── wshcmd-file.go │ │ ├── wshcmd-focusblock.go │ │ ├── wshcmd-getmeta.go │ │ ├── wshcmd-getvar.go │ │ ├── wshcmd-jobdebug.go │ │ ├── wshcmd-jobmanager.go │ │ ├── wshcmd-launch.go │ │ ├── wshcmd-notify.go │ │ ├── wshcmd-rcfiles.go │ │ ├── wshcmd-readfile.go │ │ ├── wshcmd-root.go │ │ ├── wshcmd-run.go │ │ ├── wshcmd-secret.go │ │ ├── wshcmd-setbg.go │ │ ├── wshcmd-setconfig.go │ │ ├── wshcmd-setmeta.go │ │ ├── wshcmd-setvar.go │ │ ├── wshcmd-shell-unix.go │ │ ├── wshcmd-shell-win.go │ │ ├── wshcmd-ssh.go │ │ ├── wshcmd-ssh_test.go │ │ ├── wshcmd-tabindicator.go │ │ ├── wshcmd-term.go │ │ ├── wshcmd-termscrollback.go │ │ ├── wshcmd-test.go │ │ ├── wshcmd-token.go │ │ ├── wshcmd-version.go │ │ ├── wshcmd-view.go │ │ ├── wshcmd-wavepath.go │ │ ├── wshcmd-web.go │ │ ├── wshcmd-workspace.go │ │ └── wshcmd-wsl.go │ └── main-wsh.go ├── db/ │ ├── db.go │ ├── migrations-filestore/ │ │ ├── 000001_init.down.sql │ │ └── 000001_init.up.sql │ └── migrations-wstore/ │ ├── 000001_init.down.sql │ ├── 000001_init.up.sql │ ├── 000002_init.down.sql │ ├── 000002_init.up.sql │ ├── 000003_activity.down.sql │ ├── 000003_activity.up.sql │ ├── 000004_history.down.sql │ ├── 000004_history.up.sql │ ├── 000005_blockparent.down.sql │ ├── 000005_blockparent.up.sql │ ├── 000006_workspace.down.sql │ ├── 000006_workspace.up.sql │ ├── 000007_events.down.sql │ ├── 000007_events.up.sql │ ├── 000008_aimeta.down.sql │ ├── 000008_aimeta.up.sql │ ├── 000009_mainserver.down.sql │ ├── 000009_mainserver.up.sql │ ├── 000010_merge_pinned_tabs.down.sql │ ├── 000010_merge_pinned_tabs.up.sql │ ├── 000011_job.down.sql │ └── 000011_job.up.sql ├── docs/ │ ├── .editorconfig │ ├── .gitignore │ ├── .prettierignore │ ├── .remarkrc │ ├── README.md │ ├── babel.config.js │ ├── docs/ │ │ ├── ai-presets.mdx │ │ ├── claude-code.mdx │ │ ├── config.mdx │ │ ├── connections.mdx │ │ ├── customization.mdx │ │ ├── customwidgets.mdx │ │ ├── durable-sessions.mdx │ │ ├── faq.mdx │ │ ├── gettingstarted.mdx │ │ ├── index.mdx │ │ ├── keybindings.mdx │ │ ├── layout.mdx │ │ ├── presets.mdx │ │ ├── releasenotes.mdx │ │ ├── secrets.mdx │ │ ├── tabs.mdx │ │ ├── telemetry-old.mdx │ │ ├── telemetry.mdx │ │ ├── waveai-modes.mdx │ │ ├── waveai.mdx │ │ ├── widgets.mdx │ │ ├── workspaces.mdx │ │ ├── wsh-reference.mdx │ │ └── wsh.mdx │ ├── docusaurus.config.ts │ ├── eslint.config.js │ ├── package.json │ ├── prettier.config.cjs │ ├── src/ │ │ ├── components/ │ │ │ ├── card.css │ │ │ ├── card.tsx │ │ │ ├── kbd.css │ │ │ ├── kbd.tsx │ │ │ ├── platformcontext.css │ │ │ ├── platformcontext.tsx │ │ │ ├── versionbadge.css │ │ │ └── versionbadge.tsx │ │ ├── css/ │ │ │ └── custom.scss │ │ ├── renderer/ │ │ │ └── image-renderers.ts │ │ └── theme/ │ │ └── MDXComponents/ │ │ └── Heading.tsx │ ├── static/ │ │ └── .nojekyll │ └── tsconfig.json ├── electron-builder.config.cjs ├── electron.vite.config.ts ├── emain/ │ ├── authkey.ts │ ├── emain-activity.ts │ ├── emain-builder.ts │ ├── emain-events.ts │ ├── emain-ipc.ts │ ├── emain-log.ts │ ├── emain-menu.ts │ ├── emain-platform.ts │ ├── emain-tabview.ts │ ├── emain-util.ts │ ├── emain-wavesrv.ts │ ├── emain-web.ts │ ├── emain-window.ts │ ├── emain-wsh.ts │ ├── emain.ts │ ├── launchsettings.ts │ ├── preload-webview.ts │ ├── preload.ts │ └── updater.ts ├── eslint.config.js ├── frontend/ │ ├── app/ │ │ ├── aipanel/ │ │ │ ├── ai-utils.ts │ │ │ ├── aidroppedfiles.tsx │ │ │ ├── aifeedbackbuttons.tsx │ │ │ ├── aimessage.tsx │ │ │ ├── aimode.tsx │ │ │ ├── aipanel-contextmenu.ts │ │ │ ├── aipanel.tsx │ │ │ ├── aipanelheader.tsx │ │ │ ├── aipanelinput.tsx │ │ │ ├── aipanelmessages.tsx │ │ │ ├── airatelimitstrip.tsx │ │ │ ├── aitooluse.tsx │ │ │ ├── aitypes.ts │ │ │ ├── byokannouncement.tsx │ │ │ ├── restorebackupmodal.tsx │ │ │ ├── telemetryrequired.tsx │ │ │ ├── waveai-focus-utils.ts │ │ │ └── waveai-model.tsx │ │ ├── app-bg.tsx │ │ ├── app.scss │ │ ├── app.tsx │ │ ├── block/ │ │ │ ├── block-model.ts │ │ │ ├── block.scss │ │ │ ├── block.tsx │ │ │ ├── blockenv.ts │ │ │ ├── blockframe-header.tsx │ │ │ ├── blockframe.tsx │ │ │ ├── blocktypes.ts │ │ │ ├── blockutil.tsx │ │ │ ├── connectionbutton.tsx │ │ │ ├── connstatusoverlay.tsx │ │ │ └── durable-session-flyover.tsx │ │ ├── element/ │ │ │ ├── ansiline.tsx │ │ │ ├── button.scss │ │ │ ├── button.tsx │ │ │ ├── copybutton.scss │ │ │ ├── copybutton.tsx │ │ │ ├── emojibutton.tsx │ │ │ ├── emojipalette.scss │ │ │ ├── emojipalette.tsx │ │ │ ├── errorboundary.tsx │ │ │ ├── expandablemenu.scss │ │ │ ├── expandablemenu.tsx │ │ │ ├── flyoutmenu.scss │ │ │ ├── flyoutmenu.tsx │ │ │ ├── iconbutton.scss │ │ │ ├── iconbutton.tsx │ │ │ ├── input.scss │ │ │ ├── input.tsx │ │ │ ├── linkbutton.scss │ │ │ ├── linkbutton.tsx │ │ │ ├── magnify.scss │ │ │ ├── magnify.tsx │ │ │ ├── markdown-contentblock-plugin.ts │ │ │ ├── markdown-util.ts │ │ │ ├── markdown.scss │ │ │ ├── markdown.tsx │ │ │ ├── menubutton.scss │ │ │ ├── menubutton.tsx │ │ │ ├── modal.scss │ │ │ ├── modal.tsx │ │ │ ├── multilineinput.scss │ │ │ ├── multilineinput.tsx │ │ │ ├── popover.scss │ │ │ ├── popover.tsx │ │ │ ├── progressbar.scss │ │ │ ├── progressbar.tsx │ │ │ ├── quickelems.scss │ │ │ ├── quickelems.tsx │ │ │ ├── quicktips.tsx │ │ │ ├── remark-mermaid-to-tag.ts │ │ │ ├── search.scss │ │ │ ├── search.tsx │ │ │ ├── streamdown.tsx │ │ │ ├── toggle.scss │ │ │ ├── toggle.tsx │ │ │ ├── tooltip.tsx │ │ │ ├── typingindicator.scss │ │ │ └── typingindicator.tsx │ │ ├── hook/ │ │ │ ├── useDimensions.tsx │ │ │ └── useLongClick.tsx │ │ ├── modals/ │ │ │ ├── about.tsx │ │ │ ├── conntypeahead.tsx │ │ │ ├── messagemodal.scss │ │ │ ├── messagemodal.tsx │ │ │ ├── modal.scss │ │ │ ├── modal.tsx │ │ │ ├── modalregistry.tsx │ │ │ ├── modalsrenderer.tsx │ │ │ ├── typeaheadmodal.scss │ │ │ ├── typeaheadmodal.tsx │ │ │ └── userinputmodal.tsx │ │ ├── monaco/ │ │ │ ├── monaco-env.ts │ │ │ ├── monaco-react.tsx │ │ │ ├── schemaendpoints.ts │ │ │ └── yamlworker.js │ │ ├── onboarding/ │ │ │ ├── fakechat.tsx │ │ │ ├── onboarding-command.tsx │ │ │ ├── onboarding-common.tsx │ │ │ ├── onboarding-durable.tsx │ │ │ ├── onboarding-features-footer.tsx │ │ │ ├── onboarding-features.tsx │ │ │ ├── onboarding-layout-term.tsx │ │ │ ├── onboarding-layout.tsx │ │ │ ├── onboarding-starask.tsx │ │ │ ├── onboarding-upgrade-minor.tsx │ │ │ ├── onboarding-upgrade-patch.tsx │ │ │ ├── onboarding-upgrade-v0121.tsx │ │ │ ├── onboarding-upgrade-v0122.tsx │ │ │ ├── onboarding-upgrade-v0123.tsx │ │ │ ├── onboarding-upgrade-v0130.tsx │ │ │ ├── onboarding-upgrade-v0131.tsx │ │ │ ├── onboarding-upgrade-v0140.tsx │ │ │ ├── onboarding-upgrade-v0141.tsx │ │ │ ├── onboarding-upgrade-v0142.tsx │ │ │ ├── onboarding-upgrade.tsx │ │ │ └── onboarding.tsx │ │ ├── reset.scss │ │ ├── shadcn/ │ │ │ └── lib/ │ │ │ └── utils.ts │ │ ├── store/ │ │ │ ├── badge.ts │ │ │ ├── client-model.ts │ │ │ ├── connections-model.ts │ │ │ ├── contextmenu.test.ts │ │ │ ├── contextmenu.ts │ │ │ ├── counters.ts │ │ │ ├── focusManager.ts │ │ │ ├── global-atoms.test.ts │ │ │ ├── global-atoms.ts │ │ │ ├── global-model.ts │ │ │ ├── global.ts │ │ │ ├── jotaiStore.ts │ │ │ ├── keymodel.ts │ │ │ ├── modalmodel.ts │ │ │ ├── services.ts │ │ │ ├── tab-model.ts │ │ │ ├── tabrpcclient.ts │ │ │ ├── windowtype.ts │ │ │ ├── wos.ts │ │ │ ├── wps.ts │ │ │ ├── ws.ts │ │ │ ├── wshclient.ts │ │ │ ├── wshclientapi.ts │ │ │ ├── wshrouter.ts │ │ │ ├── wshrpcutil-base.ts │ │ │ └── wshrpcutil.ts │ │ ├── suggestion/ │ │ │ └── suggestion.tsx │ │ ├── tab/ │ │ │ ├── tab.scss │ │ │ ├── tab.tsx │ │ │ ├── tabbadges.tsx │ │ │ ├── tabbar-model.ts │ │ │ ├── tabbar.scss │ │ │ ├── tabbar.tsx │ │ │ ├── tabbarenv.ts │ │ │ ├── tabcontent.tsx │ │ │ ├── tabcontextmenu.ts │ │ │ ├── updatebanner.tsx │ │ │ ├── vtab.test.tsx │ │ │ ├── vtab.tsx │ │ │ ├── vtabbar.tsx │ │ │ ├── vtabbarenv.ts │ │ │ ├── workspaceeditor.scss │ │ │ ├── workspaceeditor.tsx │ │ │ ├── workspaceswitcher.scss │ │ │ └── workspaceswitcher.tsx │ │ ├── theme.scss │ │ ├── treeview/ │ │ │ ├── treeview.test.ts │ │ │ └── treeview.tsx │ │ ├── view/ │ │ │ ├── aifilediff/ │ │ │ │ └── aifilediff.tsx │ │ │ ├── codeeditor/ │ │ │ │ ├── codeeditor.tsx │ │ │ │ └── diffviewer.tsx │ │ │ ├── helpview/ │ │ │ │ └── helpview.tsx │ │ │ ├── launcher/ │ │ │ │ └── launcher.tsx │ │ │ ├── preview/ │ │ │ │ ├── csvview.scss │ │ │ │ ├── csvview.tsx │ │ │ │ ├── directorypreview.scss │ │ │ │ ├── entry-manager.tsx │ │ │ │ ├── preview-directory-utils.tsx │ │ │ │ ├── preview-directory.tsx │ │ │ │ ├── preview-edit.tsx │ │ │ │ ├── preview-error-overlay.tsx │ │ │ │ ├── preview-markdown.tsx │ │ │ │ ├── preview-model.tsx │ │ │ │ ├── preview-streaming.tsx │ │ │ │ ├── preview.tsx │ │ │ │ └── previewenv.ts │ │ │ ├── quicktipsview/ │ │ │ │ └── quicktipsview.tsx │ │ │ ├── sysinfo/ │ │ │ │ └── sysinfo.tsx │ │ │ ├── term/ │ │ │ │ ├── fitaddon.ts │ │ │ │ ├── ijson.tsx │ │ │ │ ├── osc-handlers.ts │ │ │ │ ├── shellblocking.ts │ │ │ │ ├── term-model.ts │ │ │ │ ├── term-tooltip.tsx │ │ │ │ ├── term-wsh.tsx │ │ │ │ ├── term.scss │ │ │ │ ├── term.tsx │ │ │ │ ├── termsticker.tsx │ │ │ │ ├── termtheme.ts │ │ │ │ ├── termutil.ts │ │ │ │ ├── termwrap.ts │ │ │ │ └── xterm.css │ │ │ ├── tsunami/ │ │ │ │ └── tsunami.tsx │ │ │ ├── vdom/ │ │ │ │ ├── vdom-model.tsx │ │ │ │ ├── vdom-utils.tsx │ │ │ │ └── vdom.tsx │ │ │ ├── waveai/ │ │ │ │ ├── waveai.scss │ │ │ │ └── waveai.tsx │ │ │ ├── waveconfig/ │ │ │ │ ├── secretscontent.tsx │ │ │ │ ├── waveaivisual.tsx │ │ │ │ ├── waveconfig-model.ts │ │ │ │ ├── waveconfig.tsx │ │ │ │ └── waveconfigenv.ts │ │ │ └── webview/ │ │ │ ├── webview.scss │ │ │ ├── webview.test.tsx │ │ │ ├── webview.tsx │ │ │ └── webviewenv.ts │ │ ├── waveenv/ │ │ │ ├── mockboundary.tsx │ │ │ ├── waveenv.ts │ │ │ └── waveenvimpl.ts │ │ └── workspace/ │ │ ├── widgetfilter.test.ts │ │ ├── widgetfilter.ts │ │ ├── widgets.tsx │ │ ├── workspace-layout-model.ts │ │ └── workspace.tsx │ ├── builder/ │ │ ├── app-selection-modal.tsx │ │ ├── builder-app.tsx │ │ ├── builder-apppanel.tsx │ │ ├── builder-buildpanel.tsx │ │ ├── builder-workspace.tsx │ │ ├── store/ │ │ │ ├── builder-apppanel-model.ts │ │ │ ├── builder-buildpanel-model.ts │ │ │ └── builder-focusmanager.ts │ │ ├── tabs/ │ │ │ ├── builder-codetab.tsx │ │ │ ├── builder-configdatatab.tsx │ │ │ ├── builder-filestab.tsx │ │ │ ├── builder-previewtab.tsx │ │ │ └── builder-secrettab.tsx │ │ └── utils/ │ │ └── builder-focus-utils.ts │ ├── layout/ │ │ ├── index.ts │ │ ├── lib/ │ │ │ ├── TileLayout.tsx │ │ │ ├── layoutAtom.ts │ │ │ ├── layoutModel.ts │ │ │ ├── layoutModelHooks.ts │ │ │ ├── layoutNode.ts │ │ │ ├── layoutTree.ts │ │ │ ├── nodeRefMap.ts │ │ │ ├── tilelayout.scss │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ └── tests/ │ │ ├── layoutNode.test.ts │ │ ├── layoutTree.test.ts │ │ ├── model.ts │ │ └── utils.test.ts │ ├── preview/ │ │ ├── index.html │ │ ├── mock/ │ │ │ ├── defaultconfig.ts │ │ │ ├── mock-node-model.ts │ │ │ ├── mockfilesystem.ts │ │ │ ├── mockwaveenv.test.ts │ │ │ ├── mockwaveenv.ts │ │ │ ├── preview-electron-api.ts │ │ │ ├── tabbar-mock.tsx │ │ │ └── use-rpc-override.ts │ │ ├── preview-contextmenu.tsx │ │ ├── preview.css │ │ ├── preview.tsx │ │ ├── previews/ │ │ │ ├── .gitkeep │ │ │ ├── aifilediff.preview-util.ts │ │ │ ├── aifilediff.preview.test.ts │ │ │ ├── aifilediff.preview.tsx │ │ │ ├── modal-about.preview.tsx │ │ │ ├── onboarding.preview.tsx │ │ │ ├── sysinfo.preview-util.ts │ │ │ ├── sysinfo.preview.test.ts │ │ │ ├── sysinfo.preview.tsx │ │ │ ├── tab.preview.tsx │ │ │ ├── tabbar.preview.tsx │ │ │ ├── treeview.preview.tsx │ │ │ ├── vtabbar.preview.tsx │ │ │ ├── web.preview.tsx │ │ │ └── widgets.preview.tsx │ │ └── vite.config.ts │ ├── tailwindsetup.css │ ├── types/ │ │ ├── custom.d.ts │ │ ├── gotypes.d.ts │ │ ├── jsx.d.ts │ │ ├── media.d.ts │ │ ├── vite-env.d.ts │ │ └── waveevent.d.ts │ ├── util/ │ │ ├── color-validator.test.ts │ │ ├── color-validator.ts │ │ ├── endpoints.ts │ │ ├── fetchutil.ts │ │ ├── focusutil.ts │ │ ├── fontutil.ts │ │ ├── getenv.ts │ │ ├── historyutil.ts │ │ ├── ijson.ts │ │ ├── isdev.ts │ │ ├── keyutil.ts │ │ ├── platformutil.ts │ │ ├── previewutil.ts │ │ ├── sharedconst.ts │ │ ├── util.ts │ │ ├── waveutil.ts │ │ └── wsutil.ts │ └── wave.ts ├── go.mod ├── go.sum ├── index.html ├── package.json ├── pkg/ │ ├── aiusechat/ │ │ ├── aiutil/ │ │ │ └── aiutil.go │ │ ├── anthropic/ │ │ │ ├── anthropic-backend.go │ │ │ ├── anthropic-backend_test.go │ │ │ └── anthropic-convertmessage.go │ │ ├── chatstore/ │ │ │ └── chatstore.go │ │ ├── gemini/ │ │ │ ├── doc.go │ │ │ ├── gemini-backend.go │ │ │ ├── gemini-convertmessage.go │ │ │ └── gemini-types.go │ │ ├── google/ │ │ │ ├── doc.go │ │ │ ├── google-summarize.go │ │ │ └── google-summarize_test.go │ │ ├── openai/ │ │ │ ├── openai-backend.go │ │ │ ├── openai-convertmessage.go │ │ │ ├── openai-util.go │ │ │ ├── stream-sample.txt │ │ │ └── tool-sample.txt │ │ ├── openaichat/ │ │ │ ├── openaichat-backend.go │ │ │ ├── openaichat-convertmessage.go │ │ │ └── openaichat-types.go │ │ ├── toolapproval.go │ │ ├── tools.go │ │ ├── tools_builder.go │ │ ├── tools_readdir.go │ │ ├── tools_readdir_test.go │ │ ├── tools_readfile.go │ │ ├── tools_screenshot.go │ │ ├── tools_term.go │ │ ├── tools_tsunami.go │ │ ├── tools_web.go │ │ ├── tools_writefile.go │ │ ├── uctypes/ │ │ │ └── uctypes.go │ │ ├── usechat-backend.go │ │ ├── usechat-mode.go │ │ ├── usechat-prompts.go │ │ ├── usechat-utils.go │ │ ├── usechat.go │ │ └── usechat_mode_test.go │ ├── authkey/ │ │ └── authkey.go │ ├── baseds/ │ │ └── baseds.go │ ├── blockcontroller/ │ │ ├── .gitignore │ │ ├── blockcontroller.go │ │ ├── durableshellcontroller.go │ │ ├── shellcontroller.go │ │ └── tsunamicontroller.go │ ├── blocklogger/ │ │ └── blocklogger.go │ ├── buildercontroller/ │ │ └── buildercontroller.go │ ├── eventbus/ │ │ └── eventbus.go │ ├── faviconcache/ │ │ └── faviconcache.go │ ├── filebackup/ │ │ └── filebackup.go │ ├── filestore/ │ │ ├── blockstore.go │ │ ├── blockstore_cache.go │ │ ├── blockstore_dbops.go │ │ ├── blockstore_dbsetup.go │ │ └── blockstore_test.go │ ├── genconn/ │ │ ├── genconn.go │ │ ├── ssh-impl.go │ │ └── wsl-impl.go │ ├── gogen/ │ │ ├── gogen.go │ │ └── gogen_test.go │ ├── ijson/ │ │ ├── ijson.go │ │ └── ijson_test.go │ ├── jobcontroller/ │ │ └── jobcontroller.go │ ├── jobmanager/ │ │ ├── cirbuf.go │ │ ├── jobcmd.go │ │ ├── jobmanager.go │ │ ├── jobmanager_unix.go │ │ ├── jobmanager_windows.go │ │ ├── mainserverconn.go │ │ ├── streammanager.go │ │ └── streammanager_test.go │ ├── panichandler/ │ │ └── panichandler.go │ ├── remote/ │ │ ├── conncontroller/ │ │ │ ├── conncontroller.go │ │ │ └── connmonitor.go │ │ ├── connparse/ │ │ │ ├── connparse.go │ │ │ └── connparse_test.go │ │ ├── connutil.go │ │ ├── fileshare/ │ │ │ ├── fspath/ │ │ │ │ └── fspath.go │ │ │ ├── fsutil/ │ │ │ │ └── fsutil.go │ │ │ └── wshfs/ │ │ │ └── wshfs.go │ │ ├── sshagent_unix.go │ │ ├── sshagent_unix_test.go │ │ ├── sshagent_windows.go │ │ ├── sshagent_windows_test.go │ │ └── sshclient.go │ ├── schema/ │ │ └── schema.go │ ├── secretstore/ │ │ └── secretstore.go │ ├── service/ │ │ ├── blockservice/ │ │ │ └── blockservice.go │ │ ├── clientservice/ │ │ │ └── clientservice.go │ │ ├── objectservice/ │ │ │ └── objectservice.go │ │ ├── service.go │ │ ├── userinputservice/ │ │ │ └── userinputservice.go │ │ ├── windowservice/ │ │ │ └── windowservice.go │ │ └── workspaceservice/ │ │ └── workspaceservice.go │ ├── shellexec/ │ │ ├── conninterface.go │ │ └── shellexec.go │ ├── streamclient/ │ │ ├── stream_test.go │ │ ├── streambroker.go │ │ ├── streambroker_test.go │ │ ├── streamreader.go │ │ └── streamwriter.go │ ├── suggestion/ │ │ ├── filewalk.go │ │ └── suggestion.go │ ├── telemetry/ │ │ ├── telemetry.go │ │ └── telemetrydata/ │ │ └── telemetrydata.go │ ├── trimquotes/ │ │ └── trimquotes.go │ ├── tsgen/ │ │ ├── tsgen.go │ │ ├── tsgen_wshclientapi_test.go │ │ ├── tsgenevent.go │ │ ├── tsgenevent_test.go │ │ └── tsgenmeta/ │ │ └── tsgenmeta.go │ ├── tsunamiutil/ │ │ └── tsunamiutil.go │ ├── userinput/ │ │ └── userinput.go │ ├── util/ │ │ ├── daystr/ │ │ │ ├── daystr.go │ │ │ └── daystr_test.go │ │ ├── dbutil/ │ │ │ ├── dbmappable.go │ │ │ └── dbutil.go │ │ ├── ds/ │ │ │ ├── expmap.go │ │ │ ├── syncmap.go │ │ │ └── syncmap_test.go │ │ ├── envutil/ │ │ │ └── envutil.go │ │ ├── fileutil/ │ │ │ ├── fileutil.go │ │ │ ├── fileutil_test.go │ │ │ ├── mimetypes.go │ │ │ └── readdir.go │ │ ├── iochan/ │ │ │ ├── iochan.go │ │ │ ├── iochan_test.go │ │ │ └── iochantypes/ │ │ │ └── iochantypes.go │ │ ├── iterfn/ │ │ │ ├── iterfn.go │ │ │ └── iterfn_test.go │ │ ├── logutil/ │ │ │ └── logutil.go │ │ ├── logview/ │ │ │ ├── logview.go │ │ │ └── multibuf.go │ │ ├── migrateutil/ │ │ │ └── migrateutil.go │ │ ├── packetparser/ │ │ │ └── packetparser.go │ │ ├── pamparse/ │ │ │ ├── pamparse.go │ │ │ └── pamparse_test.go │ │ ├── readutil/ │ │ │ └── readutil.go │ │ ├── shellutil/ │ │ │ ├── shellintegration/ │ │ │ │ ├── bash_bashrc.sh │ │ │ │ ├── bash_preexec.sh │ │ │ │ ├── fish_wavefish.sh │ │ │ │ ├── pwsh_wavepwsh.sh │ │ │ │ ├── zsh_zlogin.sh │ │ │ │ ├── zsh_zprofile.sh │ │ │ │ ├── zsh_zshenv.sh │ │ │ │ └── zsh_zshrc.sh │ │ │ ├── shellquote.go │ │ │ ├── shellquote_test.go │ │ │ ├── shellutil.go │ │ │ └── tokenswap.go │ │ ├── sigutil/ │ │ │ ├── sigusr1_notwindows.go │ │ │ ├── sigusr1_windows.go │ │ │ └── sigutil.go │ │ ├── syncbuf/ │ │ │ └── syncbuf.go │ │ ├── unixutil/ │ │ │ ├── unixutil_unix.go │ │ │ └── unixutil_windows.go │ │ └── utilfn/ │ │ ├── compare.go │ │ ├── marshal.go │ │ ├── partial.go │ │ ├── partial_test.go │ │ ├── streamtolines.go │ │ └── utilfn.go │ ├── utilds/ │ │ ├── codederror.go │ │ ├── idlist.go │ │ ├── multireaderlinebuffer.go │ │ ├── quickreorderqueue.go │ │ ├── quickreorderqueue_test.go │ │ ├── readerlinebuffer.go │ │ ├── synccache.go │ │ ├── versionts.go │ │ └── workqueue.go │ ├── vdom/ │ │ ├── cssparser/ │ │ │ ├── cssparser.go │ │ │ └── cssparser_test.go │ │ ├── vdom.go │ │ ├── vdom_comp.go │ │ ├── vdom_html.go │ │ ├── vdom_root.go │ │ ├── vdom_test.go │ │ └── vdom_types.go │ ├── waveai/ │ │ ├── anthropicbackend.go │ │ ├── cloudbackend.go │ │ ├── googlebackend.go │ │ ├── openaibackend.go │ │ ├── perplexitybackend.go │ │ └── waveai.go │ ├── waveapp/ │ │ ├── streamingresp.go │ │ ├── waveapp.go │ │ └── waveappserverimpl.go │ ├── waveappstore/ │ │ └── waveappstore.go │ ├── waveapputil/ │ │ └── waveapputil.go │ ├── wavebase/ │ │ ├── wavebase-posix.go │ │ ├── wavebase-win.go │ │ └── wavebase.go │ ├── wavejwt/ │ │ └── wavejwt.go │ ├── waveobj/ │ │ ├── ctxupdate.go │ │ ├── metaconsts.go │ │ ├── metamap.go │ │ ├── objrtinfo.go │ │ ├── waveobj.go │ │ ├── wtype.go │ │ └── wtypemeta.go │ ├── wcloud/ │ │ ├── wcloud.go │ │ └── wclouddata.go │ ├── wconfig/ │ │ ├── defaultconfig/ │ │ │ ├── defaultconfig.go │ │ │ ├── mimetypes.json │ │ │ ├── presets/ │ │ │ │ └── ai.json │ │ │ ├── presets.json │ │ │ ├── settings.json │ │ │ ├── termthemes.json │ │ │ ├── waveai.json │ │ │ └── widgets.json │ │ ├── filewatcher.go │ │ ├── metaconsts.go │ │ └── settingsconfig.go │ ├── wcore/ │ │ ├── badge.go │ │ ├── block.go │ │ ├── layout.go │ │ ├── wcore.go │ │ ├── window.go │ │ └── workspace.go │ ├── web/ │ │ ├── sse/ │ │ │ └── ssehandler.go │ │ ├── web.go │ │ ├── webcmd/ │ │ │ └── webcmd.go │ │ ├── webvdomproto.go │ │ └── ws.go │ ├── wps/ │ │ ├── wps.go │ │ └── wpstypes.go │ ├── wshrpc/ │ │ ├── wshclient/ │ │ │ ├── barerpcclient.go │ │ │ ├── wshclient.go │ │ │ └── wshclientutil.go │ │ ├── wshremote/ │ │ │ ├── sysinfo.go │ │ │ ├── wshremote.go │ │ │ ├── wshremote_file.go │ │ │ └── wshremote_job.go │ │ ├── wshrpcmeta.go │ │ ├── wshrpcmeta_test.go │ │ ├── wshrpctypes.go │ │ ├── wshrpctypes_builder.go │ │ ├── wshrpctypes_const.go │ │ ├── wshrpctypes_file.go │ │ └── wshserver/ │ │ ├── resolvers.go │ │ ├── wshserver.go │ │ └── wshserverutil.go │ ├── wshutil/ │ │ ├── wshadapter.go │ │ ├── wshcmdreader.go │ │ ├── wshevent.go │ │ ├── wshproxy.go │ │ ├── wshrouter.go │ │ ├── wshrouter_controlimpl.go │ │ ├── wshrpc.go │ │ ├── wshrpcio.go │ │ ├── wshstreamadapter.go │ │ └── wshutil.go │ ├── wsl/ │ │ ├── wsl-unix.go │ │ └── wsl-win.go │ ├── wslconn/ │ │ ├── wsl-util.go │ │ └── wslconn.go │ └── wstore/ │ ├── wstore.go │ ├── wstore_dboldmigration.go │ ├── wstore_dbops.go │ ├── wstore_dbsetup.go │ └── wstore_rtinfo.go ├── postinstall.cjs ├── prettier.config.cjs ├── schema/ │ ├── aipresets.json │ ├── bgpresets.json │ ├── connections.json │ ├── settings.json │ ├── waveai.json │ └── widgets.json ├── staticcheck.conf ├── testdriver/ │ └── onboarding.yml ├── tests/ │ └── copytests/ │ ├── cases/ │ │ ├── test000.sh │ │ ├── test001.sh │ │ ├── test002.sh │ │ ├── test003.sh │ │ ├── test004.sh │ │ ├── test005.sh │ │ ├── test006.sh │ │ ├── test007.sh │ │ ├── test008.sh │ │ ├── test009.sh │ │ ├── test010.sh │ │ ├── test011.sh │ │ ├── test012.sh │ │ ├── test013.sh │ │ ├── test014.sh │ │ ├── test015.sh │ │ ├── test016.sh │ │ ├── test017.sh │ │ ├── test018.sh │ │ ├── test019.sh │ │ ├── test020.sh │ │ ├── test021.sh │ │ ├── test022.sh │ │ ├── test023.sh │ │ ├── test024.sh │ │ ├── test025.sh │ │ ├── test026.sh │ │ ├── test027.sh │ │ ├── test028.sh │ │ ├── test029.sh │ │ ├── test030.sh │ │ ├── test032.sh │ │ ├── test034.sh │ │ ├── test036.sh │ │ ├── test037.sh │ │ ├── test038.sh │ │ ├── test040.sh │ │ ├── test041.sh │ │ ├── test042.sh │ │ ├── test043.sh │ │ ├── test044.sh │ │ ├── test045.sh │ │ ├── test046.sh │ │ ├── test047.sh │ │ ├── test048.sh │ │ ├── test049.sh │ │ ├── test051.sh │ │ └── test052.sh │ ├── runner.sh │ └── testutil.sh ├── tsconfig.json ├── tsunami/ │ ├── .gitignore │ ├── app/ │ │ ├── atom.go │ │ ├── defaultclient.go │ │ └── hooks.go │ ├── build/ │ │ ├── build-ast.go │ │ ├── build.go │ │ └── buildutil.go │ ├── cmd/ │ │ └── main-tsunami.go │ ├── demo/ │ │ ├── .gitignore │ │ ├── cpuchart/ │ │ │ ├── app.go │ │ │ ├── go.mod │ │ │ ├── go.sum │ │ │ └── static/ │ │ │ └── tw.css │ │ ├── githubaction/ │ │ │ ├── app.go │ │ │ ├── go.mod │ │ │ ├── go.sum │ │ │ └── static/ │ │ │ └── tw.css │ │ ├── modaltest/ │ │ │ ├── app.go │ │ │ ├── go.mod │ │ │ ├── go.sum │ │ │ └── static/ │ │ │ └── tw.css │ │ ├── pomodoro/ │ │ │ ├── app.go │ │ │ ├── go.mod │ │ │ ├── go.sum │ │ │ └── static/ │ │ │ └── tw.css │ │ ├── recharts/ │ │ │ ├── app.go │ │ │ ├── go.mod │ │ │ ├── go.sum │ │ │ └── static/ │ │ │ └── tw.css │ │ ├── tabletest/ │ │ │ ├── app.go │ │ │ ├── go.mod │ │ │ ├── go.sum │ │ │ └── static/ │ │ │ └── tw.css │ │ ├── todo/ │ │ │ ├── app.go │ │ │ ├── go.mod │ │ │ ├── go.sum │ │ │ ├── static/ │ │ │ │ └── tw.css │ │ │ └── style.css │ │ └── tsunamiconfig/ │ │ ├── app.go │ │ ├── go.mod │ │ ├── go.sum │ │ └── static/ │ │ └── tw.css │ ├── engine/ │ │ ├── asyncnotify.go │ │ ├── atomimpl.go │ │ ├── clientimpl.go │ │ ├── comp.go │ │ ├── errcomponent.go │ │ ├── globalctx.go │ │ ├── hooks.go │ │ ├── render.go │ │ ├── render.md │ │ ├── rootelem.go │ │ ├── schema.go │ │ └── serverhandlers.go │ ├── frontend/ │ │ ├── .gitignore │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── app.tsx │ │ │ ├── element/ │ │ │ │ ├── markdown.tsx │ │ │ │ ├── modals.tsx │ │ │ │ └── tsunamiterm.tsx │ │ │ ├── input.tsx │ │ │ ├── main.tsx │ │ │ ├── model/ │ │ │ │ ├── model-utils.ts │ │ │ │ └── tsunami-model.tsx │ │ │ ├── recharts/ │ │ │ │ └── recharts.tsx │ │ │ ├── tailwind.css │ │ │ ├── types/ │ │ │ │ ├── custom.d.ts │ │ │ │ └── vdom.d.ts │ │ │ ├── util/ │ │ │ │ ├── base64.ts │ │ │ │ ├── clientid.ts │ │ │ │ ├── keyutil.ts │ │ │ │ └── platformutil.ts │ │ │ └── vdom.tsx │ │ ├── tsconfig.json │ │ └── vite.config.ts │ ├── go.mod │ ├── go.sum │ ├── rpctypes/ │ │ └── protocoltypes.go │ ├── templates/ │ │ ├── app-init.go.tmpl │ │ ├── app-main.go.tmpl │ │ ├── empty-gomod.tmpl │ │ ├── gitignore.tmpl │ │ ├── package.json.tmpl │ │ └── tailwind.css │ ├── tsunamibase/ │ │ └── tsunamibase.go │ ├── ui/ │ │ └── table.go │ ├── util/ │ │ ├── compare.go │ │ ├── marshal.go │ │ ├── streamtolines.go │ │ └── util.go │ └── vdom/ │ ├── vdom.go │ ├── vdom_test.go │ └── vdom_types.go ├── version.cjs └── vitest.config.ts
Showing preview only (670K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (7200 symbols across 604 files)
FILE: cmd/generatego/main-generatego.go
constant WshClientFileName (line 19) | WshClientFileName = "pkg/wshrpc/wshclient/wshclient.go"
constant WaveObjMetaConstsFileName (line 20) | WaveObjMetaConstsFileName = "pkg/waveobj/metaconsts.go"
constant SettingsMetaConstsFileName (line 21) | SettingsMetaConstsFileName = "pkg/wconfig/metaconsts.go"
function GenerateWshClient (line 23) | func GenerateWshClient() error {
function GenerateWaveObjMetaConsts (line 56) | func GenerateWaveObjMetaConsts() error {
function GenerateSettingsMetaConsts (line 69) | func GenerateSettingsMetaConsts() error {
function main (line 82) | func main() {
FILE: cmd/generateschema/main-generateschema.go
constant WaveSchemaSettingsFileName (line 19) | WaveSchemaSettingsFileName = "schema/settings.json"
constant WaveSchemaConnectionsFileName (line 20) | WaveSchemaConnectionsFileName = "schema/connections.json"
constant WaveSchemaAiPresetsFileName (line 21) | WaveSchemaAiPresetsFileName = "schema/aipresets.json"
constant WaveSchemaWidgetsFileName (line 22) | WaveSchemaWidgetsFileName = "schema/widgets.json"
constant WaveSchemaBgPresetsFileName (line 23) | WaveSchemaBgPresetsFileName = "schema/bgpresets.json"
constant WaveSchemaWaveAIFileName (line 24) | WaveSchemaWaveAIFileName = "schema/waveai.json"
type ViewNameType (line 28) | type ViewNameType
method JSONSchema (line 30) | func (ViewNameType) JSONSchema() *jsonschema.Schema {
type ControllerNameType (line 45) | type ControllerNameType
method JSONSchema (line 47) | func (ControllerNameType) JSONSchema() *jsonschema.Schema {
type WidgetsMetaSchemaHints (line 63) | type WidgetsMetaSchemaHints struct
function generateSchema (line 108) | func generateSchema(template any, dir string) error {
function generateWidgetsSchema (line 125) | func generateWidgetsSchema(dir string) error {
function main (line 165) | func main() {
FILE: cmd/generatets/main-generatets.go
function generateTypesFile (line 20) | func generateTypesFile(tsTypesMap map[reflect.Type]string) error {
function generateWaveEventFile (line 66) | func generateWaveEventFile(tsTypesMap map[reflect.Type]string) error {
function generateServicesFile (line 84) | func generateServicesFile(tsTypesMap map[reflect.Type]string) error {
function generateWshClientApiFile (line 129) | func generateWshClientApiFile(tsTypeMap map[reflect.Type]string) error {
function main (line 164) | func main() {
FILE: cmd/packfiles/main-packfiles.go
function main (line 14) | func main() {
FILE: cmd/server/main-server.go
constant InitialTelemetryWait (line 58) | InitialTelemetryWait = 10 * time.Second
constant TelemetryTick (line 59) | TelemetryTick = 2 * time.Minute
constant TelemetryInterval (line 60) | TelemetryInterval = 4 * time.Hour
constant TelemetryInitialCountsWait (line 61) | TelemetryInitialCountsWait = 5 * time.Second
constant TelemetryCountsInterval (line 62) | TelemetryCountsInterval = 1 * time.Hour
constant BackupCleanupTick (line 63) | BackupCleanupTick = 2 * time.Minute
constant BackupCleanupInterval (line 64) | BackupCleanupInterval = 4 * time.Hour
constant InitialDiagnosticWait (line 65) | InitialDiagnosticWait = 5 * time.Minute
constant DiagnosticTick (line 66) | DiagnosticTick = 10 * time.Minute
function init (line 70) | func init() {
function doShutdown (line 78) | func doShutdown(reason string) {
function stdinReadWatch (line 100) | func stdinReadWatch() {
function startConfigWatcher (line 114) | func startConfigWatcher() {
function telemetryLoop (line 121) | func telemetryLoop() {
function diagnosticLoop (line 136) | func diagnosticLoop() {
function sendDiagnosticPing (line 157) | func sendDiagnosticPing() bool {
function setupTelemetryConfigHandler (line 172) | func setupTelemetryConfigHandler() {
function backupCleanupLoop (line 189) | func backupCleanupLoop() {
function panicTelemetryHandler (line 206) | func panicTelemetryHandler(panicName string) {
function sendTelemetryWrapper (line 217) | func sendTelemetryWrapper() {
function updateTelemetryCounts (line 231) | func updateTelemetryCounts(lastCounts telemetrydata.TEventProps) telemet...
function updateTelemetryCountsLoop (line 274) | func updateTelemetryCountsLoop() {
function beforeSendActivityUpdate (line 290) | func beforeSendActivityUpdate(ctx context.Context) {
function startupActivityUpdate (line 305) | func startupActivityUpdate(firstLaunch bool) {
function shutdownActivityUpdate (line 366) | func shutdownActivityUpdate() {
function createMainWshClient (line 385) | func createMainWshClient() {
function grabAndRemoveEnvVars (line 398) | func grabAndRemoveEnvVars() error {
function clearTempFiles (line 424) | func clearTempFiles() error {
function maybeStartPprofServer (line 435) | func maybeStartPprofServer() {
function main (line 458) | func main() {
FILE: cmd/test-conn/cliprovider.go
type CLIProvider (line 16) | type CLIProvider struct
method GetUserInput (line 20) | func (p *CLIProvider) GetUserInput(ctx context.Context, request *useri...
FILE: cmd/test-conn/main-test-conn.go
function usage (line 19) | func usage() {
function main (line 48) | func main() {
FILE: cmd/test-conn/testutil.go
function setupWaveEnvVars (line 30) | func setupWaveEnvVars() error {
function initTestHarness (line 63) | func initTestHarness(autoAccept bool) error {
function testBasicConnect (line 107) | func testBasicConnect(connName string, timeout time.Duration) error {
function testShellWithCommand (line 142) | func testShellWithCommand(connName string, cmd string, timeout time.Dura...
function testWshExec (line 192) | func testWshExec(connName string, cmd string, timeout time.Duration) err...
function testInteractiveShell (line 268) | func testInteractiveShell(connName string, timeout time.Duration) error {
FILE: cmd/test-streammanager/bridge.go
type WriterBridge (line 14) | type WriterBridge struct
method StreamDataCommand (line 18) | func (b *WriterBridge) StreamDataCommand(data wshrpc.CommandStreamData...
method StreamDataAckCommand (line 23) | func (b *WriterBridge) StreamDataAckCommand(ack wshrpc.CommandStreamAc...
type ReaderBridge (line 29) | type ReaderBridge struct
method StreamDataCommand (line 33) | func (b *ReaderBridge) StreamDataCommand(data wshrpc.CommandStreamData...
method StreamDataAckCommand (line 37) | func (b *ReaderBridge) StreamDataAckCommand(ack wshrpc.CommandStreamAc...
FILE: cmd/test-streammanager/deliverypipe.go
type DeliveryConfig (line 16) | type DeliveryConfig struct
type taggedPacket (line 21) | type taggedPacket struct
type DeliveryPipe (line 30) | type DeliveryPipe struct
method SetDataTarget (line 68) | func (dp *DeliveryPipe) SetDataTarget(fn func(wshrpc.CommandStreamData...
method SetAckTarget (line 74) | func (dp *DeliveryPipe) SetAckTarget(fn func(wshrpc.CommandStreamAckDa...
method EnqueueData (line 80) | func (dp *DeliveryPipe) EnqueueData(pkt wshrpc.CommandStreamData) {
method EnqueueAck (line 108) | func (dp *DeliveryPipe) EnqueueAck(pkt wshrpc.CommandStreamAckData) {
method computeDeliveryTime (line 132) | func (dp *DeliveryPipe) computeDeliveryTime() time.Time {
method sortPending (line 145) | func (dp *DeliveryPipe) sortPending(pending *[]taggedPacket) {
method Start (line 155) | func (dp *DeliveryPipe) Start() {
method dataDeliveryLoop (line 161) | func (dp *DeliveryPipe) dataDeliveryLoop() {
method ackDeliveryLoop (line 184) | func (dp *DeliveryPipe) ackDeliveryLoop() {
method deliveryLoop (line 203) | func (dp *DeliveryPipe) deliveryLoop(
method Close (line 243) | func (dp *DeliveryPipe) Close() {
function NewDeliveryPipe (line 59) | func NewDeliveryPipe(config DeliveryConfig, metrics *Metrics) *DeliveryP...
FILE: cmd/test-streammanager/generator.go
constant Base64Chars (line 11) | Base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234...
type TestDataGenerator (line 13) | type TestDataGenerator struct
method Read (line 22) | func (g *TestDataGenerator) Read(p []byte) (n int, err error) {
function NewTestDataGenerator (line 18) | func NewTestDataGenerator(totalBytes int64) *TestDataGenerator {
FILE: cmd/test-streammanager/main-test-streammanager.go
type TestConfig (line 19) | type TestConfig struct
function init (line 39) | func init() {
function main (line 49) | func main() {
function runTest (line 55) | func runTest(config TestConfig) error {
function runStreamManagerMode (line 162) | func runStreamManagerMode(config TestConfig, writerBroker *streamclient....
function runWriterMode (line 183) | func runWriterMode(config TestConfig, writerBroker *streamclient.Broker,...
type BrokerDataSender (line 208) | type BrokerDataSender struct
method SendData (line 212) | func (s *BrokerDataSender) SendData(dataPk wshrpc.CommandStreamData) {
type MetricsWriter (line 217) | type MetricsWriter struct
method Write (line 222) | func (mw *MetricsWriter) Write(p []byte) (n int, err error) {
type SlowReader (line 231) | type SlowReader struct
method Read (line 243) | func (sr *SlowReader) Read(p []byte) (n int, err error) {
function NewSlowReader (line 236) | func NewSlowReader(reader io.Reader, bytesPerSec int) *SlowReader {
FILE: cmd/test-streammanager/metrics.go
type Metrics (line 12) | type Metrics struct
method Start (line 37) | func (m *Metrics) Start() {
method End (line 43) | func (m *Metrics) End() {
method AddDataPacket (line 49) | func (m *Metrics) AddDataPacket() {
method AddAckPacket (line 55) | func (m *Metrics) AddAckPacket() {
method AddOOOPacket (line 61) | func (m *Metrics) AddOOOPacket() {
method AddBytes (line 67) | func (m *Metrics) AddBytes(n int64) {
method UpdatePipeHighWaterMark (line 73) | func (m *Metrics) UpdatePipeHighWaterMark(currentBytes int64) {
method GetPipeHighWaterMark (line 81) | func (m *Metrics) GetPipeHighWaterMark() int64 {
method Report (line 87) | func (m *Metrics) Report() string {
function NewMetrics (line 33) | func NewMetrics() *Metrics {
FILE: cmd/test-streammanager/verifier.go
type Verifier (line 10) | type Verifier struct
method Write (line 25) | func (v *Verifier) Write(p []byte) (n int, err error) {
method TotalReceived (line 47) | func (v *Verifier) TotalReceived() int64 {
method Mismatches (line 53) | func (v *Verifier) Mismatches() int {
method FirstMismatch (line 59) | func (v *Verifier) FirstMismatch() int64 {
function NewVerifier (line 18) | func NewVerifier(totalBytes int64) *Verifier {
FILE: cmd/test/test-main.go
function main (line 6) | func main() {
FILE: cmd/testai/main-testai.go
constant DefaultAnthropicModel (line 27) | DefaultAnthropicModel = "claude-sonnet-4-5"
constant DefaultOpenAIModel (line 28) | DefaultOpenAIModel = "gpt-5.1"
constant DefaultOpenRouterModel (line 29) | DefaultOpenRouterModel = "mistralai/mistral-small-3.2-24b-instruct"
constant DefaultNanoGPTModel (line 30) | DefaultNanoGPTModel = "zai-org/glm-4.7"
constant DefaultGeminiModel (line 31) | DefaultGeminiModel = "gemini-3-pro-preview"
type TestResponseWriter (line 35) | type TestResponseWriter struct
method Header (line 39) | func (w *TestResponseWriter) Header() http.Header {
method Write (line 46) | func (w *TestResponseWriter) Write(data []byte) (int, error) {
method WriteHeader (line 51) | func (w *TestResponseWriter) WriteHeader(statusCode int) {
method Flush (line 56) | func (w *TestResponseWriter) Flush() {
method SetWriteDeadline (line 61) | func (w *TestResponseWriter) SetWriteDeadline(deadline time.Time) error {
method SetReadDeadline (line 66) | func (w *TestResponseWriter) SetReadDeadline(deadline time.Time) error {
function getToolDefinitions (line 71) | func getToolDefinitions() []uctypes.ToolDefinition {
function testOpenAI (line 111) | func testOpenAI(ctx context.Context, model, message string, tools []ucty...
function testOpenAIComp (line 161) | func testOpenAIComp(ctx context.Context, model, message string, tools []...
function testOpenRouter (line 211) | func testOpenRouter(ctx context.Context, model, message string, tools []...
function testNanoGPT (line 261) | func testNanoGPT(ctx context.Context, model, message string, tools []uct...
function testAnthropic (line 310) | func testAnthropic(ctx context.Context, model, message string, tools []u...
function testGemini (line 360) | func testGemini(ctx context.Context, model, message string, tools []ucty...
function testT1 (line 411) | func testT1(ctx context.Context) {
function testT2 (line 417) | func testT2(ctx context.Context) {
function testT3 (line 423) | func testT3(ctx context.Context) {
function testT4 (line 427) | func testT4(ctx context.Context) {
function printUsage (line 433) | func printUsage() {
function main (line 465) | func main() {
FILE: cmd/testopenai/main-testopenai.go
function makeOpenAIRequest (line 22) | func makeOpenAIRequest(ctx context.Context, apiKey, model, message strin...
function processSSEStream (line 93) | func processSSEStream(reader io.Reader) error {
function printUsage (line 111) | func printUsage() {
function main (line 124) | func main() {
FILE: cmd/testsummarize/main-testsummarize.go
function printUsage (line 16) | func printUsage() {
function main (line 36) | func main() {
FILE: cmd/wsh/cmd/setmeta_test.go
function TestParseMetaSets (line 11) | func TestParseMetaSets(t *testing.T) {
function TestParseMetaValue (line 136) | func TestParseMetaValue(t *testing.T) {
FILE: cmd/wsh/cmd/wshcmd-ai.go
function init (line 47) | func init() {
function detectMimeType (line 54) | func detectMimeType(data []byte) string {
function getMaxFileSize (line 59) | func getMaxFileSize(mimeType string) (int, string) {
function aiRun (line 69) | func aiRun(cmd *cobra.Command, args []string) (rtnErr error) {
FILE: cmd/wsh/cmd/wshcmd-badge.go
function init (line 36) | func init() {
function badgeRun (line 45) | func badgeRun(cmd *cobra.Command, args []string) (rtnErr error) {
FILE: cmd/wsh/cmd/wshcmd-blocks.go
type BlockDetails (line 30) | type BlockDetails struct
function init (line 73) | func init() {
function blocksListRun (line 100) | func blocksListRun(cmd *cobra.Command, args []string) error {
function matchesViewType (line 259) | func matchesViewType(actual, filter string) bool {
function isKnownViewFilter (line 283) | func isKnownViewFilter(f string) bool {
FILE: cmd/wsh/cmd/wshcmd-conn.go
function init (line 69) | func init() {
function validateConnectionName (line 79) | func validateConnectionName(name string) error {
function getAllConnStatus (line 89) | func getAllConnStatus() ([]wshrpc.ConnStatus, error) {
function connStatusRun (line 104) | func connStatusRun(cmd *cobra.Command, args []string) error {
function connReinstallRun (line 125) | func connReinstallRun(cmd *cobra.Command, args []string) error {
function connDisconnectRun (line 148) | func connDisconnectRun(cmd *cobra.Command, args []string) error {
function connDisconnectAllRun (line 161) | func connDisconnectAllRun(cmd *cobra.Command, args []string) error {
function connConnectRun (line 180) | func connConnectRun(cmd *cobra.Command, args []string) error {
function connEnsureRun (line 197) | func connEnsureRun(cmd *cobra.Command, args []string) error {
FILE: cmd/wsh/cmd/wshcmd-connserver.go
constant JobLogRetentionTime (line 42) | JobLogRetentionTime = 48 * time.Hour
constant JobLogCleanupDelay (line 43) | JobLogCleanupDelay = 10 * time.Second
constant JobLogCleanupInterval (line 44) | JobLogCleanupInterval = 1 * time.Hour
function init (line 54) | func init() {
function cleanupOldJobLogs (line 62) | func cleanupOldJobLogs() {
function startJobLogCleanup (line 98) | func startJobLogCleanup() {
function getRemoteDomainSocketName (line 117) | func getRemoteDomainSocketName() string {
function MakeRemoteUnixListener (line 122) | func MakeRemoteUnixListener() (net.Listener, error) {
function handleNewListenerConn (line 134) | func handleNewListenerConn(conn net.Conn, router *wshutil.WshRouter) {
function runListener (line 167) | func runListener(listener net.Listener, router *wshutil.WshRouter) {
function setupConnServerRpcClientWithRouter (line 186) | func setupConnServerRpcClientWithRouter(router *wshutil.WshRouter, sockN...
function serverRunRouter (line 202) | func serverRunRouter() error {
function serverRunRouterDomainSocket (line 287) | func serverRunRouterDomainSocket(jwtToken string) error {
function serverRunNormal (line 395) | func serverRunNormal(jwtToken string) error {
function askForJwtToken (line 416) | func askForJwtToken() (string, error) {
function serverRun (line 436) | func serverRun(cmd *cobra.Command, args []string) error {
FILE: cmd/wsh/cmd/wshcmd-createblock.go
function init (line 26) | func init() {
function createBlockRun (line 31) | func createBlockRun(cmd *cobra.Command, args []string) error {
FILE: cmd/wsh/cmd/wshcmd-debug.go
function init (line 34) | func init() {
function debugSendTelemetryRun (line 40) | func debugSendTelemetryRun(cmd *cobra.Command, args []string) error {
function debugBlockIdsRun (line 45) | func debugBlockIdsRun(cmd *cobra.Command, args []string) error {
FILE: cmd/wsh/cmd/wshcmd-debugterm.go
constant DebugTermModeHex (line 23) | DebugTermModeHex = "hex"
constant DebugTermModeDecode (line 24) | DebugTermModeDecode = "decode"
function init (line 43) | func init() {
function debugTermRun (line 51) | func debugTermRun(cmd *cobra.Command, args []string) (rtnErr error) {
function debugTermPreRun (line 119) | func debugTermPreRun(cmd *cobra.Command, args []string) error {
function getDebugTermMode (line 126) | func getDebugTermMode() (string, error) {
type debugTermStdinEntry (line 134) | type debugTermStdinEntry struct
function parseDebugTermStdinData (line 138) | func parseDebugTermStdinData(data []byte) ([]byte, error) {
function formatDebugTermHex (line 165) | func formatDebugTermHex(data []byte) string {
function parseCursorForwardN (line 169) | func parseCursorForwardN(seq []byte) (int, bool) {
function splitOnCRLFRuns (line 186) | func splitOnCRLFRuns(s string) []string {
function formatDebugTermDecode (line 211) | func formatDebugTermDecode(data []byte) string {
function describeSGR (line 384) | func describeSGR(params string) string {
function formatDebugTermCSILine (line 426) | func formatDebugTermCSILine(seq []byte) string {
function consumeDebugTermCSI (line 467) | func consumeDebugTermCSI(data []byte, start int) ([]byte, int) {
function formatDebugTermOSCLine (line 478) | func formatDebugTermOSCLine(seq []byte) string {
function consumeDebugTermOSC (line 497) | func consumeDebugTermOSC(data []byte, start int) ([]byte, int) {
function consumeDebugTermST (line 511) | func consumeDebugTermST(data []byte, start int) ([]byte, int) {
function isDebugTermC0Control (line 522) | func isDebugTermC0Control(b byte) bool {
function consumeDebugTermText (line 526) | func consumeDebugTermText(data []byte, i int) (start, end int) {
FILE: cmd/wsh/cmd/wshcmd-debugterm_test.go
function TestFormatDebugTermHex (line 11) | func TestFormatDebugTermHex(t *testing.T) {
function TestFormatDebugTermDecode (line 18) | func TestFormatDebugTermDecode(t *testing.T) {
function TestParseDebugTermStdinData (line 37) | func TestParseDebugTermStdinData(t *testing.T) {
function TestParseDebugTermStdinDataStructs (line 56) | func TestParseDebugTermStdinDataStructs(t *testing.T) {
function TestFormatDebugTermDecodeCursorForward (line 75) | func TestFormatDebugTermDecodeCursorForward(t *testing.T) {
function TestParseDebugTermStdinDataRaw (line 91) | func TestParseDebugTermStdinDataRaw(t *testing.T) {
FILE: cmd/wsh/cmd/wshcmd-deleteblock.go
function init (line 21) | func init() {
function deleteBlockRun (line 25) | func deleteBlockRun(cmd *cobra.Command, args []string) (rtnErr error) {
FILE: cmd/wsh/cmd/wshcmd-editconfig.go
function init (line 26) | func init() {
function editConfigRun (line 31) | func editConfigRun(cmd *cobra.Command, args []string) (rtnErr error) {
FILE: cmd/wsh/cmd/wshcmd-editor.go
function init (line 28) | func init() {
function editorRun (line 33) | func editorRun(cmd *cobra.Command, args []string) (rtnErr error) {
FILE: cmd/wsh/cmd/wshcmd-file-util.go
function convertNotFoundErr (line 21) | func convertNotFoundErr(err error) error {
function ensureFile (line 31) | func ensureFile(fileData wshrpc.FileData) (*wshrpc.FileInfo, error) {
function streamWriteToFile (line 51) | func streamWriteToFile(fileData wshrpc.FileData, reader io.Reader) error {
function streamReadFromFile (line 93) | func streamReadFromFile(ctx context.Context, fileData wshrpc.FileData, w...
function fixRelativePaths (line 98) | func fixRelativePaths(path string) (string, error) {
FILE: cmd/wsh/cmd/wshcmd-file.go
constant MaxFileSize (line 26) | MaxFileSize = 10 * 1024 * 1024
constant TimeoutYear (line 28) | TimeoutYear = int64(365) * 24 * 60 * 60 * 1000
constant UriHelpText (line 30) | UriHelpText = `
function init (line 64) | func init() {
function fileCatRun (line 169) | func fileCatRun(cmd *cobra.Command, args []string) error {
function fileInfoRun (line 192) | func fileInfoRun(cmd *cobra.Command, args []string) error {
function fileRmRun (line 228) | func fileRmRun(cmd *cobra.Command, args []string) error {
function fileWriteRun (line 246) | func fileWriteRun(cmd *cobra.Command, args []string) error {
function fileAppendRun (line 272) | func fileAppendRun(cmd *cobra.Command, args []string) error {
function checkFileSize (line 330) | func checkFileSize(path string, maxSize int64) (*wshrpc.FileInfo, error) {
function fileCpRun (line 352) | func fileCpRun(cmd *cobra.Command, args []string) error {
function fileMvRun (line 386) | func fileMvRun(cmd *cobra.Command, args []string) error {
function filePrintColumns (line 416) | func filePrintColumns(filesChan <-chan wshrpc.RespOrErrorUnion[wshrpc.Co...
function filePrintLong (line 459) | func filePrintLong(filesChan <-chan wshrpc.RespOrErrorUnion[wshrpc.Comma...
function fileListRun (line 499) | func fileListRun(cmd *cobra.Command, args []string) error {
FILE: cmd/wsh/cmd/wshcmd-focusblock.go
function init (line 23) | func init() {
function focusBlockRun (line 27) | func focusBlockRun(cmd *cobra.Command, args []string) (rtnErr error) {
FILE: cmd/wsh/cmd/wshcmd-getmeta.go
function init (line 30) | func init() {
function filterMetaKeys (line 37) | func filterMetaKeys(meta map[string]interface{}, keys []string) map[stri...
function getMetaRun (line 75) | func getMetaRun(cmd *cobra.Command, args []string) (rtnErr error) {
FILE: cmd/wsh/cmd/wshcmd-getvar.go
function init (line 33) | func init() {
function shouldPrintNewline (line 43) | func shouldPrintNewline() bool {
function getVarRun (line 54) | func getVarRun(cmd *cobra.Command, args []string) error {
function getAllVariables (line 110) | func getAllVariables(zoneId string) error {
FILE: cmd/wsh/cmd/wshcmd-jobdebug.go
function init (line 115) | func init() {
function jobDebugListRun (line 163) | func jobDebugListRun(cmd *cobra.Command, args []string) error {
function jobDebugDeleteRun (line 242) | func jobDebugDeleteRun(cmd *cobra.Command, args []string) error {
function jobDebugDeleteAllRun (line 252) | func jobDebugDeleteAllRun(cmd *cobra.Command, args []string) error {
function jobDebugPruneRun (line 277) | func jobDebugPruneRun(cmd *cobra.Command, args []string) error {
function jobDebugTerminateRun (line 308) | func jobDebugTerminateRun(cmd *cobra.Command, args []string) error {
function jobDebugDisconnectRun (line 318) | func jobDebugDisconnectRun(cmd *cobra.Command, args []string) error {
function jobDebugReconnectRun (line 328) | func jobDebugReconnectRun(cmd *cobra.Command, args []string) error {
function jobDebugReconnectConnRun (line 338) | func jobDebugReconnectConnRun(cmd *cobra.Command, args []string) error {
function jobDebugGetOutputRun (line 348) | func jobDebugGetOutputRun(cmd *cobra.Command, args []string) error {
function jobDebugStartRun (line 383) | func jobDebugStartRun(cmd *cobra.Command, args []string) error {
function jobDebugAttachJobRun (line 405) | func jobDebugAttachJobRun(cmd *cobra.Command, args []string) error {
function jobDebugDetachJobRun (line 420) | func jobDebugDetachJobRun(cmd *cobra.Command, args []string) error {
function jobDebugBlockAttachmentRun (line 430) | func jobDebugBlockAttachmentRun(cmd *cobra.Command, args []string) error {
FILE: cmd/wsh/cmd/wshcmd-jobmanager.go
function init (line 31) | func init() {
function jobManagerRun (line 39) | func jobManagerRun(cmd *cobra.Command, args []string) error {
function readJobAuthToken (line 82) | func readJobAuthToken(ctx context.Context) (string, error) {
FILE: cmd/wsh/cmd/wshcmd-launch.go
function init (line 24) | func init() {
function launchRun (line 29) | func launchRun(cmd *cobra.Command, args []string) (rtnErr error) {
FILE: cmd/wsh/cmd/wshcmd-notify.go
function init (line 26) | func init() {
function notifyRun (line 32) | func notifyRun(cmd *cobra.Command, args []string) (rtnErr error) {
FILE: cmd/wsh/cmd/wshcmd-rcfiles.go
function init (line 11) | func init() {
FILE: cmd/wsh/cmd/wshcmd-readfile.go
function init (line 25) | func init() {
function runReadFile (line 29) | func runReadFile(cmd *cobra.Command, args []string) {
FILE: cmd/wsh/cmd/wshcmd-root.go
type WrappedWriter (line 38) | type WrappedWriter struct
method Write (line 42) | func (w *WrappedWriter) Write(p []byte) (n int, err error) {
function WriteStderr (line 70) | func WriteStderr(fmtStr string, args ...interface{}) {
function WriteStdout (line 74) | func WriteStdout(fmtStr string, args ...interface{}) {
function OutputHelpMessage (line 78) | func OutputHelpMessage(cmd *cobra.Command) {
function preRunSetupRpcClient (line 84) | func preRunSetupRpcClient(cmd *cobra.Command, args []string) error {
function getIsTty (line 96) | func getIsTty() bool {
function activityWrap (line 105) | func activityWrap(activityStr string, origRunE RunEFnType) RunEFnType {
function resolveBlockArg (line 114) | func resolveBlockArg() (*waveobj.ORef, error) {
function setupRpcClientWithToken (line 126) | func setupRpcClientWithToken(swapTokenStr string) (wshrpc.CommandAuthent...
function setupRpcClient (line 147) | func setupRpcClient(serverImpl wshutil.ServerImpl, jwtToken string) error {
function isFullORef (line 174) | func isFullORef(orefStr string) bool {
function resolveSimpleId (line 179) | func resolveSimpleId(id string) (*waveobj.ORef, error) {
function getTabIdFromEnv (line 205) | func getTabIdFromEnv() string {
function sendActivity (line 214) | func sendActivity(wshCmdName string, success bool) {
function Execute (line 227) | func Execute() {
FILE: cmd/wsh/cmd/wshcmd-run.go
function init (line 28) | func init() {
function runRun (line 41) | func runRun(cmd *cobra.Command, args []string) (rtnErr error) {
FILE: cmd/wsh/cmd/wshcmd-secret.go
function init (line 68) | func init() {
function secretGetRun (line 78) | func secretGetRun(cmd *cobra.Command, args []string) (rtnErr error) {
function secretSetRun (line 102) | func secretSetRun(cmd *cobra.Command, args []string) (rtnErr error) {
function secretListRun (line 138) | func secretListRun(cmd *cobra.Command, args []string) (rtnErr error) {
function secretDeleteRun (line 154) | func secretDeleteRun(cmd *cobra.Command, args []string) (rtnErr error) {
function secretUiRun (line 174) | func secretUiRun(cmd *cobra.Command, args []string) (rtnErr error) {
FILE: cmd/wsh/cmd/wshcmd-setbg.go
function init (line 48) | func init() {
function validateHexColor (line 61) | func validateHexColor(color string) error {
function setBgRun (line 76) | func setBgRun(cmd *cobra.Command, args []string) (rtnErr error) {
FILE: cmd/wsh/cmd/wshcmd-setconfig.go
function init (line 22) | func init() {
function setConfigRun (line 26) | func setConfigRun(cmd *cobra.Command, args []string) (rtnErr error) {
FILE: cmd/wsh/cmd/wshcmd-setmeta.go
function init (line 29) | func init() {
function loadJSONFile (line 34) | func loadJSONFile(filepath string) (map[string]interface{}, error) {
function parseMetaValue (line 62) | func parseMetaValue(setVal string) (any, error) {
function setNestedValue (line 97) | func setNestedValue(meta map[string]any, path []string, value any) {
function parseMetaSets (line 128) | func parseMetaSets(metaSets []string) (map[string]any, error) {
function simpleMergeMeta (line 148) | func simpleMergeMeta(meta map[string]interface{}, metaUpdate map[string]...
function setMetaRun (line 159) | func setMetaRun(cmd *cobra.Command, args []string) (rtnErr error) {
FILE: cmd/wsh/cmd/wshcmd-setvar.go
constant DefaultVarFileName (line 15) | DefaultVarFileName = "var"
function init (line 36) | func init() {
function parseKeyValue (line 43) | func parseKeyValue(arg string) (key, value string, err error) {
function setVarRun (line 59) | func setVarRun(cmd *cobra.Command, args []string) (rtnErr error) {
FILE: cmd/wsh/cmd/wshcmd-shell-unix.go
function init (line 17) | func init() {
function shellCmdInner (line 30) | func shellCmdInner() string {
FILE: cmd/wsh/cmd/wshcmd-shell-win.go
function init (line 12) | func init() {
function shellCmdInner (line 25) | func shellCmdInner() {
FILE: cmd/wsh/cmd/wshcmd-ssh.go
function init (line 32) | func init() {
function sshRun (line 40) | func sshRun(cmd *cobra.Command, args []string) (rtnErr error) {
function applySSHOverrides (line 112) | func applySSHOverrides(sshArg string, login string, port string) (string...
FILE: cmd/wsh/cmd/wshcmd-ssh_test.go
function TestApplySSHOverrides (line 8) | func TestApplySSHOverrides(t *testing.T) {
FILE: cmd/wsh/cmd/wshcmd-tabindicator.go
function init (line 35) | func init() {
function tabIndicatorRun (line 44) | func tabIndicatorRun(cmd *cobra.Command, args []string) (rtnErr error) {
FILE: cmd/wsh/cmd/wshcmd-term.go
function init (line 28) | func init() {
function termRun (line 33) | func termRun(cmd *cobra.Command, args []string) (rtnErr error) {
FILE: cmd/wsh/cmd/wshcmd-termscrollback.go
function init (line 37) | func init() {
function termScrollbackRun (line 46) | func termScrollbackRun(cmd *cobra.Command, args []string) (rtnErr error) {
FILE: cmd/wsh/cmd/wshcmd-test.go
function init (line 19) | func init() {
function runTestCmd (line 23) | func runTestCmd(cmd *cobra.Command, args []string) error {
FILE: cmd/wsh/cmd/wshcmd-token.go
function init (line 20) | func init() {
function tokenCmdRun (line 24) | func tokenCmdRun(cmd *cobra.Command, args []string) (rtnErr error) {
FILE: cmd/wsh/cmd/wshcmd-version.go
function init (line 27) | func init() {
function runVersionCmd (line 33) | func runVersionCmd(cmd *cobra.Command, args []string) error {
FILE: cmd/wsh/cmd/wshcmd-view.go
function init (line 36) | func init() {
function viewRun (line 43) | func viewRun(cmd *cobra.Command, args []string) (rtnErr error) {
FILE: cmd/wsh/cmd/wshcmd-wavepath.go
function init (line 24) | func init() {
function wavepathRun (line 31) | func wavepathRun(cmd *cobra.Command, args []string) (rtnErr error) {
function tailLogFile (line 86) | func tailLogFile(path string) error {
FILE: cmd/wsh/cmd/wshcmd-web.go
function init (line 44) | func init() {
function webGetRun (line 55) | func webGetRun(cmd *cobra.Command, args []string) error {
function webOpenRun (line 98) | func webOpenRun(cmd *cobra.Command, args []string) (rtnErr error) {
FILE: cmd/wsh/cmd/wshcmd-workspace.go
function init (line 18) | func init() {
function workspaceListRun (line 30) | func workspaceListRun(cmd *cobra.Command, args []string) {
FILE: cmd/wsh/cmd/wshcmd-wsl.go
function init (line 26) | func init() {
function wslRun (line 31) | func wslRun(cmd *cobra.Command, args []string) (rtnErr error) {
FILE: cmd/wsh/main-wsh.go
function main (line 15) | func main() {
FILE: db/migrations-filestore/000001_init.up.sql
type db_wave_file (line 1) | CREATE TABLE db_wave_file (
type db_file_data (line 12) | CREATE TABLE db_file_data (
FILE: db/migrations-wstore/000001_init.up.sql
type db_client (line 1) | CREATE TABLE db_client (
type db_window (line 7) | CREATE TABLE db_window (
type db_workspace (line 13) | CREATE TABLE db_workspace (
type db_tab (line 19) | CREATE TABLE db_tab (
type db_block (line 25) | CREATE TABLE db_block (
FILE: db/migrations-wstore/000002_init.up.sql
type db_layout (line 1) | CREATE TABLE db_layout (
FILE: db/migrations-wstore/000003_activity.up.sql
type db_activity (line 1) | CREATE TABLE db_activity (
FILE: db/migrations-wstore/000004_history.up.sql
type history_migrated (line 1) | CREATE TABLE history_migrated (
FILE: db/migrations-wstore/000007_events.up.sql
type db_tevent (line 1) | CREATE TABLE db_tevent (
FILE: db/migrations-wstore/000009_mainserver.up.sql
type db_mainserver (line 1) | CREATE TABLE IF NOT EXISTS db_mainserver (
FILE: db/migrations-wstore/000011_job.up.sql
type db_job (line 1) | CREATE TABLE IF NOT EXISTS db_job (
FILE: docs/src/components/card.tsx
type CardProps (line 4) | interface CardProps {
function Card (line 11) | function Card({ icon, title, description, href }: CardProps) {
function CardGroup (line 21) | function CardGroup({ children }) {
FILE: docs/src/components/kbd.tsx
function convertKey (line 7) | function convertKey(platform: Platform, key: string): [any, string, bool...
FILE: docs/src/components/platformcontext.tsx
type Platform (line 7) | type Platform = "mac" | "linux" | "windows";
type PlatformContextProps (line 9) | interface PlatformContextProps {
function getOS (line 16) | function getOS(): Platform {
function PlatformProvider (line 46) | function PlatformProvider({ children }: { children: ReactNode }) {
function PlatformSelectorButtonInternal (line 62) | function PlatformSelectorButtonInternal() {
function PlatformSelectorButton (line 86) | function PlatformSelectorButton() {
type PlatformItemProps (line 90) | interface PlatformItemProps {
FILE: docs/src/components/versionbadge.tsx
type VersionBadgeProps (line 3) | interface VersionBadgeProps {
function VersionBadge (line 8) | function VersionBadge({ version, noLeftMargin }: VersionBadgeProps) {
FILE: docs/src/renderer/image-renderers.ts
function docSectionPath (line 101) | function docSectionPath(slug: string, title: string) {
function getTtfFont (line 116) | async function getTtfFont(family: string, axes: string[], value: number[...
FILE: docs/src/theme/MDXComponents/Heading.tsx
type Props (line 5) | type Props = WrapperProps<typeof HeadingType>;
function HeadingWrapper (line 7) | function HeadingWrapper(props: Props): JSX.Element {
FILE: electron.vite.config.ts
constant CHROME (line 12) | const CHROME = "chrome140";
constant NODE (line 13) | const NODE = "node22";
function whoImportsTarget (line 17) | function whoImportsTarget(target: string) {
method manualChunks (line 135) | manualChunks(id) {
FILE: emain/authkey.ts
function configureAuthKeyRequestInjection (line 15) | function configureAuthKeyRequestInjection(session: Electron.Session) {
FILE: emain/emain-activity.ts
function setWasActive (line 17) | function setWasActive(val: boolean) {
function setWasInFg (line 21) | function setWasInFg(val: boolean) {
function getActivityState (line 25) | function getActivityState(): { wasActive: boolean; wasInFg: boolean } {
function setGlobalIsQuitting (line 29) | function setGlobalIsQuitting(val: boolean) {
function getGlobalIsQuitting (line 33) | function getGlobalIsQuitting(): boolean {
function setGlobalIsStarting (line 37) | function setGlobalIsStarting(val: boolean) {
function getGlobalIsStarting (line 41) | function getGlobalIsStarting(): boolean {
function setGlobalIsRelaunching (line 45) | function setGlobalIsRelaunching(val: boolean) {
function getGlobalIsRelaunching (line 49) | function getGlobalIsRelaunching(): boolean {
function setForceQuit (line 53) | function setForceQuit(val: boolean) {
function getForceQuit (line 57) | function getForceQuit(): boolean {
function setUserConfirmedQuit (line 61) | function setUserConfirmedQuit(val: boolean) {
function getUserConfirmedQuit (line 65) | function getUserConfirmedQuit(): boolean {
function incrementTermCommandsRun (line 69) | function incrementTermCommandsRun() {
function getAndClearTermCommandsRun (line 73) | function getAndClearTermCommandsRun(): number {
function incrementTermCommandsRemote (line 79) | function incrementTermCommandsRemote() {
function getAndClearTermCommandsRemote (line 83) | function getAndClearTermCommandsRemote(): number {
function incrementTermCommandsWsl (line 89) | function incrementTermCommandsWsl() {
function getAndClearTermCommandsWsl (line 93) | function getAndClearTermCommandsWsl(): number {
function incrementTermCommandsDurable (line 99) | function incrementTermCommandsDurable() {
function getAndClearTermCommandsDurable (line 103) | function getAndClearTermCommandsDurable(): number {
FILE: emain/emain-builder.ts
type BuilderWindowType (line 14) | type BuilderWindowType = BrowserWindow & {
function getBuilderWindowById (line 23) | function getBuilderWindowById(builderId: string): BuilderWindowType {
function getBuilderWindowByWebContentsId (line 27) | function getBuilderWindowByWebContentsId(webContentsId: number): Builder...
function getAllBuilderWindows (line 31) | function getAllBuilderWindows(): BuilderWindowType[] {
function createBuilderWindow (line 35) | async function createBuilderWindow(appId: string): Promise<BuilderWindow...
FILE: emain/emain-events.ts
type GlobalEvents (line 6) | interface GlobalEvents {
class GlobalEventEmitter (line 10) | class GlobalEventEmitter extends EventEmitter {
method emit (line 11) | emit<K extends keyof GlobalEvents>(event: K, ...args: Parameters<Globa...
method on (line 15) | on<K extends keyof GlobalEvents>(event: K, listener: GlobalEvents[K]):...
method once (line 19) | once<K extends keyof GlobalEvents>(event: K, listener: GlobalEvents[K]...
method off (line 23) | off<K extends keyof GlobalEvents>(event: K, listener: GlobalEvents[K])...
FILE: emain/emain-ipc.ts
function openBuilderWindow (line 35) | function openBuilderWindow(appId?: string) {
type UrlInSessionResult (line 46) | type UrlInSessionResult = {
function getSingleHeaderVal (line 52) | function getSingleHeaderVal(headers: Record<string, string | string[]>, ...
function cleanMimeType (line 63) | function cleanMimeType(mimeType: string): string {
function getFileNameFromUrl (line 71) | function getFileNameFromUrl(url: string): string {
function getUrlInSession (line 81) | function getUrlInSession(session: Electron.Session, url: string): Promis...
function saveImageFileWithNativeDialog (line 133) | function saveImageFileWithNativeDialog(
function initIpcHandlers (line 195) | function initIpcHandlers() {
FILE: emain/emain-log.ts
function findHighestLogNumber (line 12) | function findHighestLogNumber(logsDir: string): number {
function pruneOldLogs (line 30) | function pruneOldLogs(logsDir: string): { pruned: string[]; error: any } {
function rotateLogIfNeeded (line 68) | function rotateLogIfNeeded(): string | null {
function log (line 121) | function log(...msg: any[]) {
FILE: emain/emain-menu.ts
type AppMenuCallbacks (line 25) | type AppMenuCallbacks = {
function getWindowWebContents (line 30) | function getWindowWebContents(window: electron.BaseWindow): electron.Web...
function getWorkspaceMenu (line 48) | async function getWorkspaceMenu(ww?: WaveBrowserWindow): Promise<Electro...
function makeEditMenu (line 78) | function makeEditMenu(fullConfig?: FullConfigType): Electron.MenuItemCon...
function makeFileMenu (line 128) | function makeFileMenu(
function makeAppMenuItems (line 174) | function makeAppMenuItems(webContents: electron.WebContents): Electron.M...
function makeViewMenu (line 203) | function makeViewMenu(
function makeFullAppMenu (line 317) | async function makeFullAppMenu(callbacks: AppMenuCallbacks, workspaceOrB...
function instantiateAppMenu (line 366) | function instantiateAppMenu(workspaceOrBuilderId?: string): Promise<elec...
function makeAndSetAppMenu (line 377) | function makeAndSetAppMenu() {
function initMenuEventSubscriptions (line 387) | function initMenuEventSubscriptions() {
function getWebContentsByWorkspaceOrBuilderId (line 394) | function getWebContentsByWorkspaceOrBuilderId(workspaceOrBuilderId: stri...
function convertMenuDefArrToMenu (line 408) | function convertMenuDefArrToMenu(
method click (line 493) | click() {
function makeDockTaskbar (line 499) | function makeDockTaskbar() {
FILE: emain/emain-platform.ts
function checkIfRunningUnderARM64Translation (line 44) | function checkIfRunningUnderARM64Translation(fullConfig: FullConfigType) {
function getWaveHomeDir (line 74) | function getWaveHomeDir(): string {
function ensurePathExists (line 94) | function ensurePathExists(path: string): string {
function getWaveConfigDir (line 106) | function getWaveConfigDir(): string {
function getWaveDataDir (line 131) | function getWaveDataDir(): string {
function getElectronAppBasePath (line 151) | function getElectronAppBasePath(): string {
function getElectronAppUnpackedBasePath (line 156) | function getElectronAppUnpackedBasePath(): string {
function getElectronAppResourcesPath (line 160) | function getElectronAppResourcesPath(): string {
function getWaveSrvPath (line 170) | function getWaveSrvPath(): string {
function getWaveSrvCwd (line 179) | function getWaveSrvCwd(): string {
function getXdgCurrentDesktop (line 215) | function getXdgCurrentDesktop(): string {
function callWithOriginalXdgCurrentDesktop (line 230) | function callWithOriginalXdgCurrentDesktop(callback: () => void) {
function callWithOriginalXdgCurrentDesktopAsync (line 252) | async function callWithOriginalXdgCurrentDesktopAsync(callback: () => Pr...
FILE: emain/emain-tabview.ts
function handleWindowsMenuAccelerators (line 24) | function handleWindowsMenuAccelerators(
function computeBgColor (line 96) | function computeBgColor(fullConfig: FullConfigType): string {
function getWaveTabViewByWebContentsId (line 111) | function getWaveTabViewByWebContentsId(webContentsId: number): WaveTabVi...
class WaveTabView (line 118) | class WaveTabView extends WebContentsView {
method constructor (line 136) | constructor(fullConfig: FullConfigType) {
method waveTabId (line 175) | get waveTabId(): string {
method waveTabId (line 179) | set waveTabId(waveTabId: string) {
method setKeyboardChordMode (line 183) | setKeyboardChordMode(mode: boolean) {
method positionTabOnScreen (line 200) | positionTabOnScreen(winBounds: Rectangle) {
method positionTabOffScreen (line 213) | positionTabOffScreen(winBounds: Rectangle) {
method isOnScreen (line 222) | isOnScreen() {
method destroy (line 227) | destroy() {
function setMaxTabCacheSize (line 240) | function setMaxTabCacheSize(size: number) {
function getWaveTabView (line 245) | function getWaveTabView(waveTabId: string): WaveTabView | undefined {
function tryEvictEntry (line 253) | function tryEvictEntry(waveTabId: string): boolean {
function checkAndEvictCache (line 278) | function checkAndEvictCache(): void {
function clearTabCache (line 295) | function clearTabCache() {
function getOrCreateWebViewForTab (line 304) | async function getOrCreateWebViewForTab(waveWindowId: string, tabId: str...
function setWaveTabView (line 360) | function setWaveTabView(waveTabId: string, wcv: WaveTabView): void {
function removeWaveTabView (line 368) | function removeWaveTabView(waveTabId: string): void {
function ensureHotSpareTab (line 377) | function ensureHotSpareTab(fullConfig: FullConfigType) {
function getSpareTab (line 384) | function getSpareTab(fullConfig: FullConfigType): WaveTabView {
FILE: emain/emain-util.ts
function broadcastZoomFactorChanged (line 21) | function broadcastZoomFactorChanged(newZoomFactor: number): void {
function increaseZoomLevel (line 30) | function increaseZoomLevel(webContents: electron.WebContents): void {
function decreaseZoomLevel (line 36) | function decreaseZoomLevel(webContents: electron.WebContents): void {
function resetZoomLevel (line 42) | function resetZoomLevel(webContents: electron.WebContents): void {
function getElectronExecPath (line 47) | function getElectronExecPath(): string {
function delay (line 54) | function delay(ms): Promise<void> {
function setCtrlShift (line 58) | function setCtrlShift(wc: Electron.WebContents, state: boolean) {
function handleCtrlShiftFocus (line 63) | function handleCtrlShiftFocus(sender: Electron.WebContents, focused: boo...
function handleCtrlShiftState (line 69) | function handleCtrlShiftState(sender: Electron.WebContents, waveEvent: W...
function shNavHandler (line 100) | function shNavHandler(event: Electron.Event<Electron.WebContentsWillNavi...
function frameOrAncestorHasName (line 122) | function frameOrAncestorHasName(frame: Electron.WebFrameMain, name: stri...
function shFrameNavHandler (line 133) | function shFrameNavHandler(event: Electron.Event<Electron.WebContentsWil...
function isWindowFullyVisible (line 187) | function isWindowFullyVisible(bounds: electron.Rectangle): boolean {
function findDisplayWithMostArea (line 210) | function findDisplayWithMostArea(bounds: electron.Rectangle): electron.D...
function adjustBoundsToFitDisplay (line 230) | function adjustBoundsToFitDisplay(bounds: electron.Rectangle, display: e...
function ensureBoundsAreVisible (line 254) | function ensureBoundsAreVisible(bounds: electron.Rectangle): electron.Re...
function waveKeyToElectronKey (line 267) | function waveKeyToElectronKey(waveKey: string): string {
FILE: emain/emain-wavesrv.ts
function getWaveVersion (line 34) | function getWaveVersion(): { version: string; buildTime: number } {
function getWaveSrvReady (line 43) | function getWaveSrvReady(): Promise<boolean> {
function getWaveSrvProc (line 47) | function getWaveSrvProc(): child_process.ChildProcessWithoutNullStreams ...
function getIsWaveSrvDead (line 51) | function getIsWaveSrvDead(): boolean {
function runWaveSrv (line 55) | function runWaveSrv(handleWSEvent: (evtMsg: WSEventType) => void): Promi...
FILE: emain/emain-web.ts
function getWebContentsByBlockId (line 7) | function getWebContentsByBlockId(ww: WaveBrowserWindow, tabId: string, b...
function escapeSelector (line 27) | function escapeSelector(selector: string): string {
type WebGetOpts (line 37) | type WebGetOpts = {
function webGetSelector (line 42) | async function webGetSelector(wc: WebContents, selector: string, opts?: ...
FILE: emain/emain-window.ts
type WindowOpts (line 27) | type WindowOpts = {
function calculateWindowBounds (line 36) | function calculateWindowBounds(
function getClientId (line 107) | async function getClientId() {
type WindowActionQueueEntry (line 116) | type WindowActionQueueEntry =
function isNonEmptyUnsavedWorkspace (line 135) | function isNonEmptyUnsavedWorkspace(workspace: Workspace): boolean {
class WaveBrowserWindow (line 139) | class WaveBrowserWindow extends BaseWindow {
method constructor (line 148) | constructor(waveWindow: WaveWindow, fullConfig: FullConfigType, opts: ...
method removeAllChildViews (line 349) | private removeAllChildViews() {
method switchWorkspace (line 358) | async switchWorkspace(workspaceId: string) {
method setActiveTab (line 381) | async setActiveTab(tabId: string, setInBackend: boolean, primaryStartu...
method initializeTab (line 393) | private async initializeTab(tabView: WaveTabView, primaryStartupTab: b...
method awaitWithDevTimeout (line 420) | private async awaitWithDevTimeout<T>(promise: Promise<T>, name: string...
method setTabViewIntoWindow (line 446) | private async setTabViewIntoWindow(tabView: WaveTabView, tabInitialize...
method repositionTabsSlowly (line 483) | private async repositionTabsSlowly(delayMs: number) {
method finalizePositioning (line 512) | private finalizePositioning() {
method queueCreateTab (line 526) | async queueCreateTab() {
method queueCloseTab (line 530) | async queueCloseTab(tabId: string) {
method _queueActionInternal (line 534) | private async _queueActionInternal(entry: WindowActionQueueEntry) {
method removeTabViewLater (line 546) | private removeTabViewLater(tabId: string, delayMs: number) {
method processActionQueue (line 556) | private async processActionQueue() {
method mainResizeHandler (line 629) | private async mainResizeHandler(_: any) {
method removeTabView (line 645) | removeTabView(tabId: string, force: boolean) {
method destroy (line 661) | destroy() {
function getWaveWindowByTabId (line 668) | function getWaveWindowByTabId(tabId: string): WaveBrowserWindow {
function getWaveWindowByWebContentsId (line 676) | function getWaveWindowByWebContentsId(webContentsId: number): WaveBrowse...
function getWaveWindowById (line 687) | function getWaveWindowById(windowId: string): WaveBrowserWindow {
function getWaveWindowByWorkspaceId (line 691) | function getWaveWindowByWorkspaceId(workspaceId: string): WaveBrowserWin...
function getAllWaveWindows (line 699) | function getAllWaveWindows(): WaveBrowserWindow[] {
function createWindowForWorkspace (line 703) | async function createWindowForWorkspace(workspaceId: string) {
function createBrowserWindow (line 717) | async function createBrowserWindow(
function createWorkspace (line 795) | async function createWorkspace(window: WaveBrowserWindow) {
function createNewWaveWindow (line 847) | async function createNewWaveWindow() {
function relaunchBrowserWindows (line 879) | async function relaunchBrowserWindows() {
function registerGlobalHotkey (line 926) | function registerGlobalHotkey(rawGlobalHotKey: string) {
FILE: emain/emain-wsh.ts
class ElectronWshClientType (line 13) | class ElectronWshClientType extends WshClient {
method constructor (line 14) | constructor() {
method handle_webselector (line 18) | async handle_webselector(rh: RpcResponseHelper, data: CommandWebSelect...
method handle_notify (line 34) | async handle_notify(rh: RpcResponseHelper, notificationOptions: WaveNo...
method handle_getupdatechannel (line 42) | async handle_getupdatechannel(rh: RpcResponseHelper): Promise<string> {
method handle_focuswindow (line 46) | async handle_focuswindow(rh: RpcResponseHelper, windowId: string) {
method handle_electronencrypt (line 63) | async handle_electronencrypt(
method handle_electrondecrypt (line 84) | async handle_electrondecrypt(
method handle_networkonline (line 105) | async handle_networkonline(rh: RpcResponseHelper): Promise<boolean> {
method handle_electronsystembell (line 109) | async handle_electronsystembell(rh: RpcResponseHelper): Promise<void> {
function initElectronWshClient (line 126) | function initElectronWshClient() {
FILE: emain/emain.ts
function handleWSEvent (line 85) | function handleWSEvent(evtMsg: WSEventType) {
function getActivityDisplays (line 123) | function getActivityDisplays(): ActivityDisplayType[] {
function sendDisplaysTDataEvent (line 143) | async function sendDisplaysTDataEvent() {
function logActiveState (line 168) | function logActiveState() {
function runActiveTimer (line 236) | function runActiveTimer() {
function hideWindowWithCatch (line 241) | function hideWindowWithCatch(window: WaveBrowserWindow) {
function appMain (line 372) | async function appMain() {
FILE: emain/launchsettings.ts
function getLaunchSettings (line 13) | function getLaunchSettings(): SettingsType {
FILE: emain/updater.ts
function getUpdateChannel (line 19) | function getUpdateChannel(settings: SettingsType): string {
class Updater (line 38) | class Updater {
method constructor (line 47) | constructor(settings: SettingsType) {
method status (line 109) | get status(): UpdaterStatus {
method status (line 113) | private set status(value: UpdaterStatus) {
method start (line 126) | async start() {
method stop (line 139) | stop() {
method checkForUpdates (line 151) | async checkForUpdates(userInput: boolean) {
method promptToInstallUpdate (line 181) | async promptToInstallUpdate() {
method installUpdate (line 203) | async installUpdate() {
function getResolvedUpdateChannel (line 213) | function getResolvedUpdateChannel(): string {
function configureAutoUpdater (line 230) | async function configureAutoUpdater() {
FILE: frontend/app/aipanel/ai-utils.ts
type FileSizeError (line 303) | interface FileSizeError {
type FilteredAIModeConfigs (line 540) | interface FilteredAIModeConfigs {
function getModeDisplayName (line 584) | function getModeDisplayName(config: AIModeConfigType): string {
FILE: frontend/app/aipanel/aidroppedfiles.tsx
type AIDroppedFilesProps (line 10) | interface AIDroppedFilesProps {
FILE: frontend/app/aipanel/aifeedbackbuttons.tsx
type AIFeedbackButtonsProps (line 8) | interface AIFeedbackButtonsProps {
FILE: frontend/app/aipanel/aimessage.tsx
type UserMessageFilesProps (line 62) | interface UserMessageFilesProps {
type AIMessagePartProps (line 107) | interface AIMessagePartProps {
type AIMessageProps (line 138) | interface AIMessageProps {
type MessagePart (line 152) | type MessagePart =
FILE: frontend/app/aipanel/aimode.tsx
type AIModeMenuItemProps (line 14) | interface AIModeMenuItemProps {
type ConfigSection (line 58) | interface ConfigSection {
function computeCompatibleSections (line 65) | function computeCompatibleSections(
function computeWaveCloudSections (line 114) | function computeWaveCloudSections(
type AIModeDropdownProps (line 135) | interface AIModeDropdownProps {
FILE: frontend/app/aipanel/aipanel-contextmenu.ts
function handleWaveAIContextMenu (line 12) | async function handleWaveAIContextMenu(e: React.MouseEvent, showCopy: bo...
FILE: frontend/app/aipanel/aipanel.tsx
type AIPanelComponentInnerProps (line 248) | type AIPanelComponentInnerProps = {
type AIPanelComponentProps (line 615) | type AIPanelComponentProps = {
FILE: frontend/app/aipanel/aipanelinput.tsx
type AIPanelInputProps (line 12) | interface AIPanelInputProps {
type AIPanelInputRef (line 18) | interface AIPanelInputRef {
FILE: frontend/app/aipanel/aipanelmessages.tsx
type AIPanelMessagesProps (line 11) | interface AIPanelMessagesProps {
FILE: frontend/app/aipanel/airatelimitstrip.tsx
function formatTimeRemaining (line 44) | function formatTimeRemaining(expirationEpoch: number): string {
FILE: frontend/app/aipanel/aitooluse.tsx
type ToolDescLineProps (line 17) | interface ToolDescLineProps {
type ToolDescProps (line 59) | interface ToolDescProps {
function getEffectiveApprovalStatus (line 80) | function getEffectiveApprovalStatus(baseApproval: string, isStreaming: b...
type AIToolApprovalButtonsProps (line 84) | interface AIToolApprovalButtonsProps {
type AIToolUseBatchItemProps (line 114) | interface AIToolUseBatchItemProps {
type AIToolUseBatchProps (line 142) | interface AIToolUseBatchProps {
type AIToolUseProps (line 187) | interface AIToolUseProps {
type AIToolProgressProps (line 322) | interface AIToolProgressProps {
type AIToolUseGroupProps (line 344) | interface AIToolUseGroupProps {
type ToolGroupItem (line 349) | type ToolGroupItem =
FILE: frontend/app/aipanel/aitypes.ts
type WaveUIDataTypes (line 6) | type WaveUIDataTypes = {
type WaveUIMessage (line 35) | type WaveUIMessage = UIMessage<unknown, WaveUIDataTypes, any>;
type WaveUIMessagePart (line 36) | type WaveUIMessagePart = UIMessagePart<WaveUIDataTypes, any>;
type UseChatSetMessagesType (line 38) | type UseChatSetMessagesType = (
type UseChatSendMessageType (line 42) | type UseChatSendMessageType = (
FILE: frontend/app/aipanel/restorebackupmodal.tsx
type RestoreBackupModalProps (line 11) | interface RestoreBackupModalProps {
FILE: frontend/app/aipanel/telemetryrequired.tsx
type TelemetryRequiredMessageProps (line 10) | interface TelemetryRequiredMessageProps {
FILE: frontend/app/aipanel/waveai-focus-utils.ts
function findWaveAIPanel (line 4) | function findWaveAIPanel(element: HTMLElement): HTMLElement | null {
function waveAIHasFocusWithin (line 15) | function waveAIHasFocusWithin(focusTarget?: Element | null): boolean {
function waveAIHasSelection (line 44) | function waveAIHasSelection(): boolean {
FILE: frontend/app/aipanel/waveai-model.tsx
type DroppedFile (line 35) | interface DroppedFile {
class WaveAIModel (line 44) | class WaveAIModel {
method constructor (line 79) | private constructor(orefContext: ORef, inBuilder: boolean) {
method getPanelVisibleAtom (line 148) | getPanelVisibleAtom(): jotai.Atom<boolean> {
method getInstance (line 152) | static getInstance(): WaveAIModel {
method resetInstance (line 168) | static resetInstance(): void {
method getUseChatEndpointUrl (line 172) | getUseChatEndpointUrl(): string {
method addFile (line 176) | async addFile(file: File): Promise<DroppedFile> {
method addFileFromRemoteUri (line 202) | async addFileFromRemoteUri(draggedFile: DraggedFile): Promise<void> {
method removeFile (line 250) | removeFile(fileId: string) {
method clearFiles (line 256) | clearFiles() {
method clearChat (line 269) | clearChat() {
method setError (line 285) | setError(message: string) {
method clearError (line 289) | clearError() {
method registerInputRef (line 293) | registerInputRef(ref: React.RefObject<AIPanelInputRef>) {
method registerScrollToBottom (line 297) | registerScrollToBottom(callback: () => void) {
method registerUseChatData (line 301) | registerUseChatData(
method scrollToBottom (line 313) | scrollToBottom() {
method focusInput (line 317) | focusInput() {
method reloadChatFromBackend (line 326) | async reloadChatFromBackend(chatIdValue: string): Promise<WaveUIMessag...
method stopResponse (line 333) | async stopResponse() {
method getAndClearMessage (line 349) | getAndClearMessage(): AIMessage | null {
method hasNonEmptyInput (line 355) | hasNonEmptyInput(): boolean {
method appendText (line 360) | appendText(text: string, newLine?: boolean, opts?: { scrollToBottom?: ...
method setModel (line 382) | setModel(model: string) {
method setWidgetAccess (line 389) | setWidgetAccess(enabled: boolean) {
method isValidMode (line 396) | isValidMode(mode: string): boolean {
method setAIMode (line 410) | setAIMode(mode: string) {
method setAIModeToDefault (line 422) | setAIModeToDefault() {
method fixModeAfterConfigChange (line 431) | async fixModeAfterConfigChange(): Promise<void> {
method getRTInfo (line 441) | async getRTInfo(): Promise<Record<string, any>> {
method loadInitialChat (line 448) | async loadInitialChat(): Promise<WaveUIMessage[]> {
method handleSubmit (line 483) | async handleSubmit() {
method uiLoadInitialChat (line 550) | async uiLoadInitialChat() {
method ensureRateLimitSet (line 560) | async ensureRateLimitSet() {
method handleAIFeedback (line 575) | handleAIFeedback(feedback: "good" | "bad") {
method requestWaveAIFocus (line 588) | requestWaveAIFocus() {
method requestNodeFocus (line 596) | requestNodeFocus() {
method getChatId (line 604) | getChatId(): string {
method toolUseSendApproval (line 608) | toolUseSendApproval(toolcallid: string, approval: string) {
method openDiff (line 615) | async openDiff(fileName: string, toolcallid: string) {
method openWaveAIConfig (line 634) | async openWaveAIConfig() {
method openRestoreBackupModal (line 644) | openRestoreBackupModal(toolcallid: string) {
method closeRestoreBackupModal (line 648) | closeRestoreBackupModal() {
method restoreBackup (line 654) | async restoreBackup(toolcallid: string, backupFilePath: string, restor...
method canCloseWaveAIPanel (line 672) | canCloseWaveAIPanel(): boolean {
method closeWaveAIPanel (line 679) | closeWaveAIPanel() {
FILE: frontend/app/app-bg.tsx
function AppBackground (line 13) | function AppBackground() {
FILE: frontend/app/app.tsx
function isContentEditableBeingEdited (line 60) | function isContentEditableBeingEdited(): boolean {
function canEnablePaste (line 69) | function canEnablePaste(): boolean {
function canEnableCopy (line 74) | function canEnableCopy(): boolean {
function canEnableCut (line 79) | function canEnableCut(): boolean {
function getClipboardURL (line 87) | async function getClipboardURL(): Promise<URL> {
function handleContextMenu (line 103) | async function handleContextMenu(e: React.MouseEvent<HTMLDivElement>) {
function AppSettingsUpdater (line 139) | function AppSettingsUpdater() {
function appFocusIn (line 169) | function appFocusIn(e: FocusEvent) {
function appFocusOut (line 173) | function appFocusOut(e: FocusEvent) {
function appSelectionChange (line 177) | function appSelectionChange(e: Event) {
function AppFocusHandler (line 182) | function AppFocusHandler() {
FILE: frontend/app/block/block-model.ts
type BlockHighlightType (line 7) | interface BlockHighlightType {
class BlockModel (line 12) | class BlockModel {
method constructor (line 18) | private constructor() {
method getBlockHighlightAtom (line 22) | getBlockHighlightAtom(blockId: string): jotai.Atom<BlockHighlightType ...
method setBlockHighlight (line 37) | setBlockHighlight(highlight: BlockHighlightType | null) {
method getInstance (line 41) | static getInstance(): BlockModel {
method resetInstance (line 48) | static resetInstance(): void {
FILE: frontend/app/block/block.tsx
function makeViewModel (line 58) | function makeViewModel(
function getViewElem (line 72) | function getViewElem(
function makeDefaultViewModel (line 89) | function makeDefaultViewModel(viewType: string): ViewModel {
FILE: frontend/app/block/blockenv.ts
type BlockEnv (line 12) | type BlockEnv = WaveEnvSubset<{
FILE: frontend/app/block/blockframe-header.tsx
function handleHeaderContextMenu (line 28) | function handleHeaderContextMenu(
type HeaderTextElemsProps (line 65) | type HeaderTextElemsProps = {
type HeaderEndIconsProps (line 109) | type HeaderEndIconsProps = {
FILE: frontend/app/block/blocktypes.ts
type BlockNodeModel (line 7) | interface BlockNodeModel {
type FullBlockProps (line 16) | type FullBlockProps = {
type BlockProps (line 22) | interface BlockProps {
type FullSubBlockProps (line 27) | type FullSubBlockProps = {
type SubBlockProps (line 32) | interface SubBlockProps {
type BlockComponentModel2 (line 36) | interface BlockComponentModel2 {
type BlockFrameProps (line 43) | interface BlockFrameProps {
FILE: frontend/app/block/blockutil.tsx
function blockViewToIcon (line 15) | function blockViewToIcon(view: string): string {
function blockViewToName (line 37) | function blockViewToName(view: string): string {
function processTitleString (line 62) | function processTitleString(titleString: string): React.ReactNode[] {
function getBlockHeaderIcon (line 126) | function getBlockHeaderIcon(blockIcon: string, overrideIconColor?: strin...
function getViewIconElem (line 146) | function getViewIconElem(
function renderHeaderElements (line 235) | function renderHeaderElements(headerTextUnion: HeaderElem[], preview: bo...
function computeConnColorNum (line 247) | function computeConnColorNum(connStatus: ConnStatus): number {
FILE: frontend/app/block/connectionbutton.tsx
type ConnectionButtonProps (line 14) | interface ConnectionButtonProps {
FILE: frontend/app/block/connstatusoverlay.tsx
function formatElapsedTime (line 17) | function formatElapsedTime(elapsedMs: number): string {
FILE: frontend/app/block/durable-session-flyover.tsx
function isTermViewModel (line 24) | function isTermViewModel(viewModel: ViewModel): viewModel is TermViewMod...
function LearnMoreButton (line 28) | function LearnMoreButton() {
type StandardSessionContentProps (line 40) | interface StandardSessionContentProps {
function StandardSessionContent (line 45) | function StandardSessionContent({ viewModel, onClose }: StandardSessionC...
type DurableAttachedContentProps (line 74) | interface DurableAttachedContentProps {
function DurableAttachedContent (line 78) | function DurableAttachedContent({ onClose }: DurableAttachedContentProps) {
type DurableDetachedContentProps (line 94) | interface DurableDetachedContentProps {
function DurableDetachedContent (line 98) | function DurableDetachedContent({ onClose }: DurableDetachedContentProps) {
type DurableAwaitingStartProps (line 114) | interface DurableAwaitingStartProps {
function DurableAwaitingStart (line 120) | function DurableAwaitingStart({ connected, viewModel, onClose }: Durable...
type DurableStartingContentProps (line 162) | interface DurableStartingContentProps {
function DurableStartingContent (line 166) | function DurableStartingContent({ onClose }: DurableStartingContentProps) {
type DurableEndedContentProps (line 179) | interface DurableEndedContentProps {
function DurableEndedContent (line 186) | function DurableEndedContent({ doneReason, startupError, viewModel, onCl...
function getContentToRender (line 264) | function getContentToRender(
function getIconProps (line 300) | function getIconProps(jobStatus: BlockJobStatusData, connStatus: ConnSta...
type DurableSessionFlyoverProps (line 325) | interface DurableSessionFlyoverProps {
function DurableSessionFlyover (line 332) | function DurableSessionFlyover({
FILE: frontend/app/element/ansiline.tsx
constant ANSI_TAILWIND_MAP (line 1) | const ANSI_TAILWIND_MAP = {
type InternalStateType (line 52) | type InternalStateType = {
type SegmentType (line 59) | type SegmentType = {
FILE: frontend/app/element/button.tsx
type ButtonProps (line 9) | interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonEleme...
FILE: frontend/app/element/copybutton.tsx
type CopyButtonProps (line 9) | type CopyButtonProps = {
FILE: frontend/app/element/emojipalette.tsx
type EmojiItem (line 13) | type EmojiItem = { emoji: string; name: string };
type EmojiPaletteProps (line 216) | interface EmojiPaletteProps {
FILE: frontend/app/element/errorboundary.tsx
class ErrorBoundary (line 6) | class ErrorBoundary extends React.Component<
method constructor (line 10) | constructor(props) {
method componentDidCatch (line 15) | componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
method render (line 20) | render() {
class NullErrorBoundary (line 35) | class NullErrorBoundary extends React.Component<
method constructor (line 39) | constructor(props: { children: React.ReactNode; debugName?: string }) {
method getDerivedStateFromError (line 44) | static getDerivedStateFromError() {
method componentDidCatch (line 48) | componentDidCatch(error: Error, info: React.ErrorInfo) {
method render (line 52) | render() {
FILE: frontend/app/element/expandablemenu.tsx
type BaseExpandableMenuItem (line 13) | type BaseExpandableMenuItem = {
type ExpandableMenuItemType (line 18) | interface ExpandableMenuItemType extends BaseExpandableMenuItem {
type ExpandableMenuItemGroupTitleType (line 25) | interface ExpandableMenuItemGroupTitleType {
type ExpandableMenuItemGroupType (line 31) | interface ExpandableMenuItemGroupType extends BaseExpandableMenuItem {
type ExpandableMenuItemData (line 38) | type ExpandableMenuItemData = ExpandableMenuItemType | ExpandableMenuIte...
type ExpandableMenuProps (line 40) | type ExpandableMenuProps = {
type ExpandableMenuItemProps (line 60) | type ExpandableMenuItemProps = {
type ExpandableMenuItemGroupTitleProps (line 80) | type ExpandableMenuItemGroupTitleProps = {
type ExpandableMenuItemGroupProps (line 94) | type ExpandableMenuItemGroupProps = {
type ExpandableMenuItemLeftElementProps (line 167) | type ExpandableMenuItemLeftElementProps = {
type ExpandableMenuItemRightElementProps (line 180) | type ExpandableMenuItemRightElementProps = {
FILE: frontend/app/element/flyoutmenu.tsx
type MenuProps (line 11) | type MenuProps = {
type SubMenuProps (line 201) | type SubMenuProps = {
FILE: frontend/app/element/iconbutton.tsx
type IconButtonProps (line 11) | type IconButtonProps = { decl: IconButtonDecl; className?: string };
type ToggleIconButtonProps (line 40) | type ToggleIconButtonProps = { decl: ToggleIconButtonDecl; className?: s...
FILE: frontend/app/element/input.tsx
type InputGroupProps (line 9) | interface InputGroupProps {
type InputLeftElementProps (line 40) | interface InputLeftElementProps {
type InputRightElementProps (line 49) | interface InputRightElementProps {
type InputProps (line 58) | interface InputProps {
FILE: frontend/app/element/linkbutton.tsx
type LinkButtonProps (line 9) | interface LinkButtonProps {
FILE: frontend/app/element/magnify.tsx
type MagnifyIconProps (line 8) | interface MagnifyIconProps {
function MagnifyIcon (line 12) | function MagnifyIcon({ enabled }: MagnifyIconProps) {
FILE: frontend/app/element/markdown-contentblock-plugin.ts
type ContentBlockPluginOptions (line 8) | interface ContentBlockPluginOptions {
function createContentBlockPlugin (line 12) | function createContentBlockPlugin(opts: ContentBlockPluginOptions) {
FILE: frontend/app/element/markdown-util.ts
type MarkdownContentBlockType (line 10) | type MarkdownContentBlockType = {
function formatInlineContentBlock (line 19) | function formatInlineContentBlock(block: MarkdownContentBlockType): stri...
function parseOptions (line 23) | function parseOptions(str: string): Record<string, any> {
function makeMarkdownWaveBlockKey (line 39) | function makeMarkdownWaveBlockKey(block: MarkdownContentBlockType): stri...
function transformBlocks (line 43) | function transformBlocks(content: string): { content: string; blocks: Ma...
FILE: frontend/app/element/markdown.tsx
type CodeBlockProps (line 133) | type CodeBlockProps = {
type WaveBlockProps (line 214) | interface WaveBlockProps {
function WaveBlock (line 219) | function WaveBlock(props: WaveBlockProps) {
type MarkdownProps (line 294) | type MarkdownProps = {
FILE: frontend/app/element/modal.tsx
type ModalProps (line 9) | interface ModalProps {
function Modal (line 15) | function Modal({ children, onClickOut, id = "modal", ...otherProps }: Mo...
type ModalContentProps (line 31) | interface ModalContentProps {
function ModalContent (line 35) | function ModalContent({ children }: ModalContentProps) {
type ModalHeaderProps (line 39) | interface ModalHeaderProps {
function ModalHeader (line 44) | function ModalHeader({ title, description }: ModalHeaderProps) {
type ModalFooterProps (line 53) | interface ModalFooterProps {
function ModalFooter (line 57) | function ModalFooter({ children }: ModalFooterProps) {
type WaveModalProps (line 61) | interface WaveModalProps {
function WaveModal (line 71) | function WaveModal({ title, description, onSubmit, onCancel, buttonLabel...
FILE: frontend/app/element/multilineinput.tsx
type MultiLineInputProps (line 9) | interface MultiLineInputProps {
FILE: frontend/app/element/popover.tsx
type PopoverProps (line 32) | interface PopoverProps {
type PopoverButtonProps (line 119) | interface PopoverButtonProps extends React.ButtonHTMLAttributes<HTMLButt...
type PopoverContentProps (line 168) | interface PopoverContentProps extends React.HTMLAttributes<HTMLDivElemen...
FILE: frontend/app/element/progressbar.tsx
type ProgressBarProps (line 7) | type ProgressBarProps = {
FILE: frontend/app/element/quickelems.tsx
function CenteredLoadingDiv (line 7) | function CenteredLoadingDiv() {
function CenteredDiv (line 11) | function CenteredDiv({ children }: { children: React.ReactNode }) {
FILE: frontend/app/element/search.tsx
type SearchProps (line 12) | type SearchProps = SearchAtoms & {
type SearchOptions (line 199) | type SearchOptions = {
function useSearch (line 207) | function useSearch(options?: SearchOptions): SearchProps {
FILE: frontend/app/element/streamdown.tsx
function extractText (line 15) | function extractText(node: React.ReactNode): string {
function CodePlain (line 24) | function CodePlain({ className = "", isCodeBlock, text }: { className?: ...
function CodeHighlight (line 36) | function CodeHighlight({ className = "", lang, text }: { className?: str...
function Code (line 108) | function Code({ className = "", children }: { className?: string; childr...
type CodeBlockProps (line 121) | type CodeBlockProps = {
function Collapsible (line 181) | function Collapsible({ title, children, defaultOpen = false }) {
type WaveStreamdownProps (line 200) | interface WaveStreamdownProps {
FILE: frontend/app/element/toggle.tsx
type ToggleProps (line 8) | interface ToggleProps {
FILE: frontend/app/element/tooltip.tsx
type TooltipProps (line 17) | interface TooltipProps {
function TooltipInner (line 31) | function TooltipInner({
function Tooltip (line 175) | function Tooltip({
FILE: frontend/app/element/typingindicator.tsx
type TypingIndicatorProps (line 8) | type TypingIndicatorProps = {
FILE: frontend/app/hook/useDimensions.tsx
function useDimensionsWithCallbackRef (line 10) | function useDimensionsWithCallbackRef<T extends HTMLElement>(
function useOnResize (line 62) | function useOnResize<T extends HTMLElement>(
function useDimensionsWithExistingRef (line 107) | function useDimensionsWithExistingRef<T extends HTMLElement>(
FILE: frontend/app/modals/about.tsx
type AboutModalVProps (line 15) | interface AboutModalVProps {
FILE: frontend/app/modals/conntypeahead.tsx
function filterConnections (line 27) | function filterConnections(
function sortConnSuggestionItems (line 41) | function sortConnSuggestionItems(
function createRemoteSuggestionItems (line 55) | function createRemoteSuggestionItems(
function createWslSuggestionItems (line 76) | function createWslSuggestionItems(
function createFilteredLocalSuggestionItem (line 97) | function createFilteredLocalSuggestionItem(
function getReconnectItem (line 116) | function getReconnectItem(
function getLocalSuggestions (line 144) | function getLocalSuggestions(
function getRemoteSuggestions (line 182) | function getRemoteSuggestions(
function getDisconnectItem (line 203) | function getDisconnectItem(
function getConnectionsEditItem (line 230) | function getConnectionsEditItem(
function getNewConnectionSuggestionItem (line 259) | function getNewConnectionSuggestionItem(
FILE: frontend/app/modals/messagemodal.tsx
function closeModal (line 11) | function closeModal() {
FILE: frontend/app/modals/modal.tsx
type ModalProps (line 12) | interface ModalProps {
type ModalContentProps (line 75) | interface ModalContentProps {
function ModalContent (line 79) | function ModalContent({ children }: ModalContentProps) {
type ModalFooterProps (line 83) | interface ModalFooterProps {
type FlexiModalProps (line 116) | interface FlexiModalProps {
type FlexiModalComponent (line 122) | interface FlexiModalComponent extends React.ForwardRefExoticComponent<
FILE: frontend/app/modals/typeaheadmodal.tsx
type SuggestionsProps (line 13) | interface SuggestionsProps {
type TypeAheadModalProps (line 74) | interface TypeAheadModalProps {
FILE: frontend/app/monaco/monaco-env.ts
method getWorker (line 22) | getWorker(_, label) {
function loadMonaco (line 42) | function loadMonaco() {
FILE: frontend/app/monaco/monaco-react.tsx
function createModel (line 10) | function createModel(value: string, path: string, language?: string) {
type CodeEditorProps (line 15) | type CodeEditorProps = {
function MonacoCodeEditor (line 25) | function MonacoCodeEditor({ text, readonly, language, onChange, onMount,...
type DiffViewerProps (line 119) | type DiffViewerProps = {
function MonacoDiffViewer (line 127) | function MonacoDiffViewer({ original, modified, language, path, options ...
FILE: frontend/app/monaco/schemaendpoints.ts
type SchemaInfo (line 11) | type SchemaInfo = {
FILE: frontend/app/onboarding/fakechat.tsx
type ChatConfig (line 7) | interface ChatConfig {
FILE: frontend/app/onboarding/onboarding-command.tsx
type CommandRevealProps (line 9) | type CommandRevealProps = {
type FakeCommandProps (line 65) | type FakeCommandProps = {
FILE: frontend/app/onboarding/onboarding-common.tsx
function OnboardingGradientBg (line 6) | function OnboardingGradientBg() {
FILE: frontend/app/onboarding/onboarding-features.tsx
type FeaturePageName (line 20) | type FeaturePageName = "waveai" | "durable" | "magnify" | "files";
FILE: frontend/app/onboarding/onboarding-layout-term.tsx
type FakeTermBlockProps (line 9) | type FakeTermBlockProps = {
type OverlayState (line 88) | type OverlayState = null | "disconnected" | "connected";
FILE: frontend/app/onboarding/onboarding-layout.tsx
type FakeBlockProps (line 10) | type FakeBlockProps = {
FILE: frontend/app/onboarding/onboarding-starask.tsx
type StarAskPageProps (line 11) | type StarAskPageProps = {
function StarAskPage (line 16) | function StarAskPage({ onClose, page = "upgrade" }: StarAskPageProps) {
FILE: frontend/app/onboarding/onboarding-upgrade-minor.tsx
type UpgradeMinorWelcomePageProps (line 20) | type UpgradeMinorWelcomePageProps = {
FILE: frontend/app/onboarding/onboarding-upgrade-patch.tsx
type VersionConfig (line 29) | interface VersionConfig {
type UpgradeOnboardingPatchProps (line 36) | interface UpgradeOnboardingPatchProps {
type UpgradeOnboardingFooterProps (line 40) | interface UpgradeOnboardingFooterProps {
function UpgradeOnboardingFooter (line 50) | function UpgradeOnboardingFooter({
FILE: frontend/app/onboarding/onboarding.tsx
type PageName (line 28) | type PageName = "init" | "notelemetrystar" | "features";
FILE: frontend/app/shadcn/lib/utils.ts
function cn (line 11) | function cn(...inputs: ClassValue[]) {
function formatDate (line 15) | function formatDate(input: string | number): string {
function absoluteUrl (line 24) | function absoluteUrl(path: string) {
FILE: frontend/app/store/badge.ts
type BadgeEnv (line 14) | type BadgeEnv = WaveEnvSubset<{
type LoadBadgesEnv (line 20) | type LoadBadgesEnv = WaveEnvSubset<{
type TabBadgesEnv (line 26) | type TabBadgesEnv = WaveEnvSubset<{
function publishBadgeEvent (line 33) | function publishBadgeEvent(eventData: WaveEvent, env?: BadgeEnv) {
function clearBadgeInternal (line 41) | function clearBadgeInternal(oref: string, env?: BadgeEnv) {
function clearBadgesForBlockOnFocus (line 53) | function clearBadgesForBlockOnFocus(blockId: string, env?: BadgeEnv) {
function clearBadgesForTabOnFocus (line 62) | function clearBadgesForTabOnFocus(tabId: string, env?: BadgeEnv) {
function clearAllBadges (line 71) | function clearAllBadges(env?: BadgeEnv) {
function clearBadgesForTab (line 83) | function clearBadgesForTab(tabId: string, env?: BadgeEnv) {
function getBadgeAtom (line 96) | function getBadgeAtom(oref: string): PrimitiveAtom<Badge> {
function getBlockBadgeAtom (line 108) | function getBlockBadgeAtom(blockId: string): Atom<Badge> {
function getTabBadgeAtom (line 116) | function getTabBadgeAtom(tabId: string, env?: TabBadgesEnv): Atom<Badge[...
function loadBadges (line 147) | async function loadBadges(env?: LoadBadgesEnv) {
function setBadge (line 162) | function setBadge(blockId: string, badge: Omit<Badge, "badgeid"> & { bad...
function clearBadgeById (line 180) | function clearBadgeById(blockId: string, badgeId: string, env?: BadgeEnv) {
function setupBadgesSubscription (line 193) | function setupBadgesSubscription() {
function cmpBadge (line 230) | function cmpBadge(a: Badge, b: Badge): number {
function sortBadges (line 240) | function sortBadges(badges: Badge[]): Badge[] {
function sortBadgesForTab (line 244) | function sortBadgesForTab(badges: Badge[]): Badge[] {
FILE: frontend/app/store/client-model.ts
class ClientModel (line 7) | class ClientModel {
method constructor (line 13) | private constructor() {
method getInstance (line 17) | static getInstance(): ClientModel {
method initialize (line 24) | initialize(clientId: string): void {
FILE: frontend/app/store/connections-model.ts
class ConnectionsModel (line 10) | class ConnectionsModel {
method constructor (line 15) | private constructor() {
method getInstance (line 26) | static getInstance(): ConnectionsModel {
method loadGitBashPath (line 33) | async loadGitBashPath(rescan: boolean = false): Promise<void> {
method getGitBashPath (line 46) | getGitBashPath(): string {
FILE: frontend/app/store/contextmenu.ts
type ShowContextMenuOpts (line 6) | type ShowContextMenuOpts = {
class ContextMenuModel (line 12) | class ContextMenuModel {
method constructor (line 17) | private constructor() {
method getInstance (line 21) | static getInstance(): ContextMenuModel {
method handleContextMenuClick (line 28) | handleContextMenuClick(id: string | null): void {
method _convertAndRegisterMenu (line 43) | _convertAndRegisterMenu(menu: ContextMenuItem[]): ElectronContextMenuI...
method showContextMenu (line 71) | showContextMenu(menu: ContextMenuItem[], ev: React.MouseEvent<any>, op...
FILE: frontend/app/store/counters.ts
function countersClear (line 6) | function countersClear() {
function counterInc (line 10) | function counterInc(name: string, incAmt: number = 1) {
function countersPrint (line 16) | function countersPrint() {
FILE: frontend/app/store/focusManager.ts
type FocusStrType (line 9) | type FocusStrType = "node" | "waveai";
class FocusManager (line 11) | class FocusManager {
method constructor (line 17) | private constructor() {
method getInstance (line 28) | static getInstance(): FocusManager {
method setWaveAIFocused (line 35) | setWaveAIFocused(force: boolean = false) {
method setBlockFocus (line 44) | setBlockFocus(force: boolean = false) {
method waveAIFocusWithin (line 53) | waveAIFocusWithin(): boolean {
method nodeFocusWithin (line 57) | nodeFocusWithin(): boolean {
method requestNodeFocus (line 61) | requestNodeFocus(): void {
method requestWaveAIFocus (line 65) | requestWaveAIFocus(): void {
method getFocusType (line 69) | getFocusType(): FocusStrType {
method refocusNode (line 73) | refocusNode() {
FILE: frontend/app/store/global-atoms.ts
function initGlobalAtoms (line 14) | function initGlobalAtoms(initOpts: GlobalInitOptions) {
function getAtoms (line 155) | function getAtoms(): GlobalAtomsType {
function getApi (line 162) | function getApi(): ElectronApi {
FILE: frontend/app/store/global-model.ts
class GlobalModel (line 10) | class GlobalModel {
method constructor (line 22) | private constructor() {
method getInstance (line 26) | static getInstance(): GlobalModel {
method initialize (line 33) | async initialize(initOpts: GlobalInitOptions): Promise<void> {
method setIsActive (line 55) | setIsActive(): void {
FILE: frontend/app/store/global.ts
function initGlobal (line 42) | function initGlobal(initOpts: GlobalInitOptions) {
function initGlobalWaveEventSubs (line 55) | function initGlobalWaveEventSubs(initOpts: WaveInitOpts) {
function useBlockCache (line 105) | function useBlockCache<T>(blockId: string, name: string, makeFn: () => T...
function getBlockMetaKeyAtom (line 119) | function getBlockMetaKeyAtom<T extends keyof MetaType>(blockId: string, ...
function getOrefMetaKeyAtom (line 135) | function getOrefMetaKeyAtom<T extends keyof MetaType>(oref: string, key:...
function useOrefMetaKeyAtom (line 151) | function useOrefMetaKeyAtom<T extends keyof MetaType>(oref: string, key:...
function getConnConfigKeyAtom (line 155) | function getConnConfigKeyAtom<T extends keyof ConnKeywords>(connName: st...
function getOverrideConfigAtom (line 173) | function getOverrideConfigAtom<T extends keyof SettingsType>(blockId: st...
function useOverrideConfigAtom (line 205) | function useOverrideConfigAtom<T extends keyof SettingsType>(blockId: st...
function getSettingsKeyAtom (line 212) | function getSettingsKeyAtom<T extends keyof SettingsType>(key: T): Atom<...
function useSettingsKeyAtom (line 228) | function useSettingsKeyAtom<T extends keyof SettingsType>(key: T): Setti...
function getSettingsPrefixAtom (line 232) | function getSettingsPrefixAtom(prefix: string): Atom<SettingsType> {
function getSingleBlockAtomCache (line 248) | function getSingleBlockAtomCache(blockId: string): Map<string, Atom<any>> {
function getSingleConnAtomCache (line 253) | function getSingleConnAtomCache(connName: string): Map<string, Atom<any>> {
function getSingleOrefAtomCache (line 259) | function getSingleOrefAtomCache(oref: string): Map<string, Atom<any>> {
function getBlockTermDurableAtom (line 271) | function getBlockTermDurableAtom(blockId: string): Atom<null | boolean> {
function useBlockAtom (line 316) | function useBlockAtom<T>(blockId: string, name: string, makeFn: () => At...
function readAtom (line 330) | function readAtom<T>(atom: Atom<T>): T {
function getApi (line 340) | function getApi(): ElectronApi {
function createBlockSplitHorizontally (line 344) | async function createBlockSplitHorizontally(
function createBlockSplitVertically (line 367) | async function createBlockSplitVertically(
function createBlock (line 390) | async function createBlock(blockDef: BlockDef, magnified = false, epheme...
function replaceBlock (line 408) | async function replaceBlock(blockId: string, blockDef: BlockDef, focus: ...
function fetchWaveFile (line 430) | async function fetchWaveFile(
function setNodeFocus (line 460) | function setNodeFocus(nodeId: string) {
function getObjectId (line 467) | function getObjectId(obj: any): number {
function isDev (line 476) | function isDev() {
function getUserName (line 485) | function getUserName(): string {
function getHostName (line 494) | function getHostName(): string {
function getLocalHostDisplayNameAtom (line 509) | function getLocalHostDisplayNameAtom(): Atom<string> {
function openLink (line 518) | async function openLink(uri: string, forceOpenInternally = false) {
function registerBlockComponentModel (line 532) | function registerBlockComponentModel(blockId: string, bcm: BlockComponen...
function unregisterBlockComponentModel (line 536) | function unregisterBlockComponentModel(blockId: string) {
function getBlockComponentModel (line 540) | function getBlockComponentModel(blockId: string): BlockComponentModel {
function getAllBlockComponentModels (line 544) | function getAllBlockComponentModels(): BlockComponentModel[] {
function getFocusedBlockId (line 548) | function getFocusedBlockId(): string {
function refocusNode (line 556) | function refocusNode(blockId: string) {
function loadConnStatus (line 577) | async function loadConnStatus() {
function subscribeToConnEvents (line 588) | function subscribeToConnEvents() {
function makeDefaultConnStatus (line 607) | function makeDefaultConnStatus(conn: string): ConnStatus {
function getConnStatusAtom (line 630) | function getConnStatusAtom(conn: string): PrimitiveAtom<ConnStatus> {
function createTab (line 642) | function createTab() {
function setActiveTab (line 646) | function setActiveTab(tabId: string) {
function recordTEvent (line 650) | function recordTEvent(event: string, props?: TEventProps) {
FILE: frontend/app/store/keymodel.ts
type KeyHandler (line 34) | type KeyHandler = (event: WaveKeyboardEvent) => boolean;
function resetChord (line 45) | function resetChord() {
function setActiveChord (line 53) | function setActiveChord(activeChordArg: string) {
function keyboardMouseDownHandler (line 62) | function keyboardMouseDownHandler(e: MouseEvent) {
function getFocusedBlockInStaticTab (line 68) | function getFocusedBlockInStaticTab(): string {
function getSimpleControlShiftAtom (line 74) | function getSimpleControlShiftAtom() {
function setControlShift (line 78) | function setControlShift() {
function unsetControlShift (line 91) | function unsetControlShift() {
function disableGlobalKeybindings (line 96) | function disableGlobalKeybindings() {
function enableGlobalKeybindings (line 100) | function enableGlobalKeybindings() {
function shouldDispatchToBlock (line 104) | function shouldDispatchToBlock(e: WaveKeyboardEvent): boolean {
function getStaticTabBlockCount (line 123) | function getStaticTabBlockCount(): number {
function simpleCloseStaticTab (line 131) | function simpleCloseStaticTab() {
function uxCloseBlock (line 147) | function uxCloseBlock(blockId: string) {
function genericClose (line 182) | function genericClose() {
function switchBlockByBlockNum (line 231) | function switchBlockByBlockNum(index: number) {
function switchBlockInDirection (line 242) | function switchBlockInDirection(direction: NavigateDirection) {
function getAllTabs (line 279) | function getAllTabs(ws: Workspace): string[] {
function switchTabAbs (line 283) | function switchTabAbs(index: number) {
function switchTab (line 295) | function switchTab(offset: number) {
function handleCmdI (line 315) | function handleCmdI() {
function globalRefocusWithTimeout (line 319) | function globalRefocusWithTimeout(timeoutVal: number) {
function globalRefocus (line 325) | function globalRefocus() {
function getDefaultNewBlockDef (line 344) | function getDefaultNewBlockDef(): BlockDef {
function handleCmdN (line 378) | async function handleCmdN() {
function handleSplitHorizontal (line 383) | async function handleSplitHorizontal(position: "before" | "after") {
function handleSplitVertical (line 393) | async function handleSplitVertical(position: "before" | "after") {
function checkKeyMap (line 406) | function checkKeyMap<T>(waveEvent: WaveKeyboardEvent, keyMap: Map<string...
function appHandleKeyDown (line 416) | function appHandleKeyDown(waveEvent: WaveKeyboardEvent): boolean {
function registerControlShiftStateUpdateHandler (line 470) | function registerControlShiftStateUpdateHandler() {
function registerElectronReinjectKeyHandler (line 480) | function registerElectronReinjectKeyHandler() {
function tryReinjectKey (line 486) | function tryReinjectKey(event: WaveKeyboardEvent): boolean {
function countTermBlocks (line 490) | function countTermBlocks(): number {
function registerGlobalKeys (line 503) | function registerGlobalKeys() {
function registerBuilderGlobalKeys (line 760) | function registerBuilderGlobalKeys() {
function getAllGlobalKeyBindings (line 769) | function getAllGlobalKeyBindings(): string[] {
FILE: frontend/app/store/modalmodel.ts
class ModalsModel (line 7) | class ModalsModel {
method constructor (line 12) | constructor() {
method hasOpenModals (line 32) | hasOpenModals(): boolean {
method isModalOpen (line 37) | isModalOpen(displayName: string): boolean {
FILE: frontend/app/store/services.ts
function callBackendService (line 9) | function callBackendService(waveEnv: WaveEnv, service: string, method: s...
class BlockServiceType (line 17) | class BlockServiceType {
method constructor (line 20) | constructor(waveEnv?: WaveEnv) {
method CleanupOrphanedBlocks (line 26) | CleanupOrphanedBlocks(tabId: string): Promise<void> {
method GetControllerStatus (line 29) | GetControllerStatus(arg2: string): Promise<BlockControllerRuntimeStatu...
method SaveTerminalState (line 34) | SaveTerminalState(blockId: string, state: string, stateType: string, p...
method SaveWaveAiData (line 37) | SaveWaveAiData(arg2: string, arg3: WaveAIPromptMessageType[]): Promise...
class ClientServiceType (line 45) | class ClientServiceType {
method constructor (line 48) | constructor(waveEnv?: WaveEnv) {
method AgreeTos (line 53) | AgreeTos(): Promise<void> {
method FocusWindow (line 56) | FocusWindow(arg2: string): Promise<void> {
method GetAllConnStatus (line 59) | GetAllConnStatus(): Promise<ConnStatus[]> {
method GetClientData (line 62) | GetClientData(): Promise<Client> {
method GetTab (line 65) | GetTab(arg1: string): Promise<Tab> {
method TelemetryUpdate (line 68) | TelemetryUpdate(arg2: boolean): Promise<void> {
class ObjectServiceType (line 76) | class ObjectServiceType {
method constructor (line 79) | constructor(waveEnv?: WaveEnv) {
method CreateBlock (line 84) | CreateBlock(blockDef: BlockDef, rtOpts: RuntimeOpts): Promise<string> {
method DeleteBlock (line 89) | DeleteBlock(blockId: string): Promise<void> {
method GetObject (line 94) | GetObject(oref: string): Promise<WaveObj> {
method GetObjects (line 99) | GetObjects(orefs: string[]): Promise<WaveObj[]> {
method UpdateObject (line 104) | UpdateObject(waveObj: WaveObj, returnUpdates: boolean): Promise<void> {
method UpdateObjectMeta (line 109) | UpdateObjectMeta(oref: string, meta: MetaType): Promise<void> {
class UserInputServiceType (line 117) | class UserInputServiceType {
method constructor (line 120) | constructor(waveEnv?: WaveEnv) {
method SendUserInputResponse (line 124) | SendUserInputResponse(arg1: UserInputResponse): Promise<void> {
class WindowServiceType (line 132) | class WindowServiceType {
method constructor (line 135) | constructor(waveEnv?: WaveEnv) {
method CloseWindow (line 139) | CloseWindow(windowId: string, fromElectron: boolean): Promise<void> {
method CreateWindow (line 142) | CreateWindow(winSize: WinSize, workspaceId: string): Promise<WaveWindo...
method GetWindow (line 145) | GetWindow(windowId: string): Promise<WaveWindow> {
method SetWindowPosAndSize (line 151) | SetWindowPosAndSize(windowId: string, pos: Point, size: WinSize): Prom...
method SwitchWorkspace (line 154) | SwitchWorkspace(windowId: string, workspaceId: string): Promise<Worksp...
class WorkspaceServiceType (line 162) | class WorkspaceServiceType {
method constructor (line 165) | constructor(waveEnv?: WaveEnv) {
method CloseTab (line 170) | CloseTab(workspaceId: string, tabId: string, fromElectron: boolean): P...
method CreateTab (line 175) | CreateTab(workspaceId: string, tabName: string, activateTab: boolean):...
method CreateWorkspace (line 180) | CreateWorkspace(name: string, icon: string, color: string, applyDefaul...
method DeleteWorkspace (line 185) | DeleteWorkspace(workspaceId: string): Promise<string> {
method GetColors (line 190) | GetColors(): Promise<string[]> {
method GetIcons (line 195) | GetIcons(): Promise<string[]> {
method GetWorkspace (line 200) | GetWorkspace(workspaceId: string): Promise<Workspace> {
method ListWorkspaces (line 203) | ListWorkspaces(): Promise<WorkspaceListEntry[]> {
method SetActiveTab (line 208) | SetActiveTab(workspaceId: string, tabId: string): Promise<void> {
method UpdateWorkspace (line 213) | UpdateWorkspace(workspaceId: string, name: string, icon: string, color...
FILE: frontend/app/store/tab-model.ts
type TabModelEnv (line 10) | type TabModelEnv = WaveEnvSubset<{
class TabModel (line 17) | class TabModel {
method constructor (line 25) | constructor(tabId: string, waveEnv?: TabModelEnv) {
method getTabMetaAtom (line 40) | getTabMetaAtom<T extends keyof MetaType>(metaKey: T): Atom<MetaType[T]> {
function getTabModelByTabId (line 53) | function getTabModelByTabId(tabId: string, waveEnv?: TabModelEnv): TabMo...
function getActiveTabModel (line 71) | function getActiveTabModel(waveEnv?: TabModelEnv): TabModel | null {
function useTabModel (line 81) | function useTabModel(): TabModel {
function useTabModelMaybe (line 89) | function useTabModelMaybe(): TabModel {
FILE: frontend/app/store/tabrpcclient.ts
class TabClient (line 13) | class TabClient extends WshClient {
method constructor (line 14) | constructor(routeId: string) {
method handle_captureblockscreenshot (line 18) | handle_captureblockscreenshot(rh: RpcResponseHelper, data: CommandCapt...
method captureBlockScreenshot (line 22) | async captureBlockScreenshot(blockId: string): Promise<string> {
method handle_waveaiaddcontext (line 65) | async handle_waveaiaddcontext(rh: RpcResponseHelper, data: CommandWave...
method handle_setblockfocus (line 95) | async handle_setblockfocus(rh: RpcResponseHelper, blockId: string): Pr...
method handle_getfocusedblockdata (line 109) | async handle_getfocusedblockdata(rh: RpcResponseHelper): Promise<Focus...
FILE: frontend/app/store/windowtype.ts
function getWaveWindowType (line 7) | function getWaveWindowType(): "tab" | "builder" | "preview" {
function isBuilderWindow (line 11) | function isBuilderWindow(): boolean {
function isTabWindow (line 15) | function isTabWindow(): boolean {
function isPreviewWindow (line 19) | function isPreviewWindow(): boolean {
function setWaveWindowType (line 23) | function setWaveWindowType(windowType: "tab" | "builder" | "preview") {
FILE: frontend/app/store/wos.ts
type WaveObjectDataItemType (line 15) | type WaveObjectDataItemType<T extends WaveObj> = {
type WaveObjectValue (line 20) | type WaveObjectValue<T extends WaveObj> = {
function splitORef (line 25) | function splitORef(oref: string): [string, string] {
function isBlank (line 33) | function isBlank(str: string): boolean {
function isBlankNum (line 37) | function isBlankNum(num: number): boolean {
function isValidWaveObj (line 41) | function isValidWaveObj(val: WaveObj): boolean {
function makeORef (line 51) | function makeORef(otype: string, oid: string): string {
function mockObjectForPreview (line 60) | function mockObjectForPreview<T extends WaveObj>(oref: string, obj: T): ...
function GetObject (line 67) | function GetObject<T>(oref: string): Promise<T> {
function debugLogBackendCall (line 74) | function debugLogBackendCall(methodName: string, durationStr: string, ar...
function wpsSubscribeToObject (line 91) | function wpsSubscribeToObject(oref: string): () => void {
function callBackendService (line 101) | function callBackendService(service: string, method: string, args: any[]...
function reloadWaveObject (line 151) | function reloadWaveObject<T extends WaveObj>(oref: string): Promise<T> {
function createWaveValueObject (line 164) | function createWaveValueObject<T extends WaveObj>(oref: string, shouldFe...
function getWaveObjectValue (line 193) | function getWaveObjectValue<T extends WaveObj>(oref: string, createIfMis...
function loadAndPinWaveObject (line 202) | function loadAndPinWaveObject<T extends WaveObj>(oref: string): Promise<...
function getWaveObjectAtom (line 213) | function getWaveObjectAtom<T extends WaveObj>(oref: string): Atom<T> {
function getWaveObjectLoadingAtom (line 225) | function getWaveObjectLoadingAtom(oref: string): Atom<boolean> {
function isWaveObjectNullAtom (line 240) | function isWaveObjectNullAtom(oref: string): Atom<boolean> {
function useWaveObjectValue (line 251) | function useWaveObjectValue<T extends WaveObj>(oref: string): [T, boolea...
function updateWaveObject (line 257) | function updateWaveObject(update: WaveObjUpdate) {
function updateWaveObjects (line 281) | function updateWaveObjects(vals: WaveObjUpdate[]) {
function getObjectValue (line 290) | function getObjectValue<T extends WaveObj>(oref: string, getFn?: Getter)...
function setObjectValue (line 302) | function setObjectValue<T extends WaveObj>(value: T, setFn?: Setter, pus...
FILE: frontend/app/store/wps.ts
function setWpsRpcClient (line 12) | function setWpsRpcClient(client: WshClient) {
type WaveEventSubject (line 16) | type WaveEventSubject<T extends WaveEventName = WaveEventName> = {
type WaveEventSubjectContainer (line 21) | type WaveEventSubjectContainer = {
type WaveEventSubscription (line 27) | type WaveEventSubscription<T extends WaveEventName = WaveEventName> = Wa...
type WaveEventUnsubscribe (line 31) | type WaveEventUnsubscribe = {
function wpsReconnectHandler (line 40) | function wpsReconnectHandler() {
function updateWaveEventSub (line 46) | function updateWaveEventSub(eventType: string) {
function waveEventSubscribeSingle (line 67) | function waveEventSubscribeSingle<T extends WaveEventName>(subscription:...
function waveEventUnsubscribe (line 88) | function waveEventUnsubscribe(...unsubscribes: WaveEventUnsubscribe[]) {
function getFileSubject (line 111) | function getFileSubject(zoneId: string, fileName: string): SubjectWithRe...
function handleWaveEvent (line 130) | function handleWaveEvent(event: WaveEvent) {
FILE: frontend/app/store/ws.ts
function addWSReconnectHandler (line 17) | function addWSReconnectHandler(handler: () => void) {
function removeWSReconnectHandler (line 21) | function removeWSReconnectHandler(handler: () => void) {
type WSEventCallback (line 28) | type WSEventCallback = (arg0: WSEventType) => void;
type ElectronOverrideOpts (line 30) | type ElectronOverrideOpts = {
class WSControl (line 34) | class WSControl {
method constructor (line 51) | constructor(
method shutdown (line 65) | shutdown() {
method connectNow (line 70) | connectNow(desc: string) {
method reconnect (line 98) | reconnect(forceClose?: boolean) {
method onclose (line 129) | onclose(event: CloseEvent) {
method onopen (line 146) | onopen(e: Event) {
method runMsgQueue (line 160) | runMsgQueue() {
method onmessage (line 174) | onmessage(event: MessageEvent) {
method sendPing (line 199) | sendPing() {
method sendMessage (line 206) | sendMessage(data: WSCommandType) {
method pushMessage (line 222) | pushMessage(data: WSCommandType) {
function initGlobalWS (line 238) | function initGlobalWS(
function sendRawRpcMessage (line 247) | function sendRawRpcMessage(msg: RpcMessage) {
function sendWSCommand (line 252) | function sendWSCommand(cmd: WSCommandType) {
FILE: frontend/app/store/wshclient.ts
class RpcResponseHelper (line 9) | class RpcResponseHelper {
method constructor (line 14) | constructor(client: WshClient, cmdMsg: RpcMessage) {
method getSource (line 21) | getSource(): string {
method sendResponse (line 25) | sendResponse(msg: RpcMessage) {
class WshClient (line 42) | class WshClient {
method constructor (line 46) | constructor(routeId: string) {
method wshRpcCall (line 50) | wshRpcCall(command: string, data: any, opts: RpcOpts): Promise<any> {
method wshRpcStream (line 75) | wshRpcStream(command: string, data: any, opts: RpcOpts): AsyncGenerato...
method handleIncomingCommand (line 95) | async handleIncomingCommand(msg: RpcMessage) {
method recvRpcMessage (line 129) | recvRpcMessage(msg: RpcMessage) {
method handle_message (line 150) | async handle_message(helper: RpcResponseHelper, data: CommandMessageDa...
method handle_default (line 154) | async handle_default(helper: RpcResponseHelper, msg: RpcMessage): Prom...
FILE: frontend/app/store/wshclientapi.ts
type MockRpcClient (line 8) | interface MockRpcClient {
class RpcApiType (line 14) | class RpcApiType {
method setMockRpcClient (line 17) | setMockRpcClient(client: MockRpcClient): void {
method ActivityCommand (line 22) | ActivityCommand(client: WshClient, data: ActivityUpdate, opts?: RpcOpt...
method AiSendMessageCommand (line 28) | AiSendMessageCommand(client: WshClient, data: AiMessageData, opts?: Rp...
method AuthenticateCommand (line 34) | AuthenticateCommand(client: WshClient, data: string, opts?: RpcOpts): ...
method AuthenticateJobManagerCommand (line 40) | AuthenticateJobManagerCommand(client: WshClient, data: CommandAuthenti...
method AuthenticateJobManagerVerifyCommand (line 46) | AuthenticateJobManagerVerifyCommand(client: WshClient, data: CommandAu...
method AuthenticateToJobManagerCommand (line 52) | AuthenticateToJobManagerCommand(client: WshClient, data: CommandAuthen...
method AuthenticateTokenCommand (line 58) | AuthenticateTokenCommand(client: WshClient, data: CommandAuthenticateT...
method AuthenticateTokenVerifyCommand (line 64) | AuthenticateTokenVerifyCommand(client: WshClient, data: CommandAuthent...
method BadgeWatchPidCommand (line 70) | BadgeWatchPidCommand(client: WshClient, data: CommandBadgeWatchPidData...
method BlockInfoCommand (line 76) | BlockInfoCommand(client: WshClient, data: string, opts?: RpcOpts): Pro...
method BlockJobStatusCommand (line 82) | BlockJobStatusCommand(client: WshClient, data: string, opts?: RpcOpts)...
method BlocksListCommand (line 88) | BlocksListCommand(client: WshClient, data: BlocksListRequest, opts?: R...
method CaptureBlockScreenshotCommand (line 94) | CaptureBlockScreenshotCommand(client: WshClient, data: CommandCaptureB...
method CheckGoVersionCommand (line 100) | CheckGoVersionCommand(client: WshClient, opts?: RpcOpts): Promise<Comm...
method ConnConnectCommand (line 106) | ConnConnectCommand(client: WshClient, data: ConnRequest, opts?: RpcOpt...
method ConnDisconnectCommand (line 112) | ConnDisconnectCommand(client: WshClient, data: string, opts?: RpcOpts)...
method ConnEnsureCommand (line 118) | ConnEnsureCommand(client: WshClient, data: ConnExtData, opts?: RpcOpts...
method ConnListCommand (line 124) | ConnListCommand(client: WshClient, opts?: RpcOpts): Promise<string[]> {
method ConnReinstallWshCommand (line 130) | ConnReinstallWshCommand(client: WshClient, data: ConnExtData, opts?: R...
method ConnServerInitCommand (line 136) | ConnServerInitCommand(client: WshClient, data: CommandConnServerInitDa...
method ConnStatusCommand (line 142) | ConnStatusCommand(client: WshClient, opts?: RpcOpts): Promise<ConnStat...
method ConnUpdateWshCommand (line 148) | ConnUpdateWshCommand(client: WshClient, data: RemoteInfo, opts?: RpcOp...
method ControlGetRouteIdCommand (line 154) | ControlGetRouteIdCommand(client: WshClient, opts?: RpcOpts): Promise<s...
method ControllerAppendOutputCommand (line 160) | ControllerAppendOutputCommand(client: WshClient, data: CommandControll...
method ControllerDestroyCommand (line 166) | ControllerDestroyCommand(client: WshClient, data: string, opts?: RpcOp...
method ControllerInputCommand (line 172) | ControllerInputCommand(client: WshClient, data: CommandBlockInputData,...
method ControllerResyncCommand (line 178) | ControllerResyncCommand(client: WshClient, data: CommandControllerResy...
method CreateBlockCommand (line 184) | CreateBlockCommand(client: WshClient, data: CommandCreateBlockData, op...
method CreateSubBlockCommand (line 190) | CreateSubBlockCommand(client: WshClient, data: CommandCreateSubBlockDa...
method DebugTermCommand (line 196) | DebugTermCommand(client: WshClient, data: CommandDebugTermData, opts?:...
method DeleteAppFileCommand (line 202) | DeleteAppFileCommand(client: WshClient, data: CommandDeleteAppFileData...
method DeleteBlockCommand (line 208) | DeleteBlockCommand(client: WshClient, data: CommandDeleteBlockData, op...
method DeleteBuilderCommand (line 214) | DeleteBuilderCommand(client: WshClient, data: string, opts?: RpcOpts):...
method DeleteSubBlockCommand (line 220) | DeleteSubBlockCommand(client: WshClient, data: CommandDeleteBlockData,...
method DismissWshFailCommand (line 226) | DismissWshFailCommand(client: WshClient, data: string, opts?: RpcOpts)...
method DisposeCommand (line 232) | DisposeCommand(client: WshClient, data: CommandDisposeData, opts?: Rpc...
method DisposeSuggestionsCommand (line 238) | DisposeSuggestionsCommand(client: WshClient, data: string, opts?: RpcO...
method ElectronDecryptCommand (line 244) | ElectronDecryptCommand(client: WshClient, data: CommandElectronDecrypt...
method ElectronEncryptCommand (line 250) | ElectronEncryptCommand(client: WshClient, data: CommandElectronEncrypt...
method ElectronSystemBellCommand (line 256) | ElectronSystemBellCommand(client: WshClient, opts?: RpcOpts): Promise<...
method EventPublishCommand (line 262) | EventPublishCommand(client: WshClient, data: WaveEvent, opts?: RpcOpts...
method EventReadHistoryCommand (line 268) | EventReadHistoryCommand(client: WshClient, data: CommandEventReadHisto...
method EventRecvCommand (line 274) | EventRecvCommand(client: WshClient, data: WaveEvent, opts?: RpcOpts): ...
method EventSubCommand (line 280) | EventSubCommand(client: WshClient, data: SubscriptionRequest, opts?: R...
method EventUnsubCommand (line 286) | EventUnsubCommand(client: WshClient, data: string, opts?: RpcOpts): Pr...
method EventUnsubAllCommand (line 292) | EventUnsubAllCommand(client: WshClient, opts?: RpcOpts): Promise<void> {
method FetchSuggestionsCommand (line 298) | FetchSuggestionsCommand(client: WshClient, data: FetchSuggestionsData,...
method FileAppendCommand (line 304) | FileAppendCommand(client: WshClient, data: FileData, opts?: RpcOpts): ...
method FileCopyCommand (line 310) | FileCopyCommand(client: WshClient, data: CommandFileCopyData, opts?: R...
method FileCreateCommand (line 316) | FileCreateCommand(client: WshClient, data: FileData, opts?: RpcOpts): ...
method FileDeleteCommand (line 322) | FileDeleteCommand(client: WshClient, data: CommandDeleteFileData, opts...
method FileInfoCommand (line 328) | FileInfoCommand(client: WshClient, data: FileData, opts?: RpcOpts): Pr...
method FileJoinCommand (line 334) | FileJoinCommand(client: WshClient, data: string[], opts?: RpcOpts): Pr...
method FileListCommand (line 340) | FileListCommand(client: WshClient, data: FileListData, opts?: RpcOpts)...
method FileListStreamCommand (line 346) | FileListStreamCommand(client: WshClient, data: FileListData, opts?: Rp...
method FileMkdirCommand (line 352) | FileMkdirCommand(client: WshClient, data: FileData, opts?: RpcOpts): P...
method FileMoveCommand (line 358) | FileMoveCommand(client: WshClient, data: CommandFileCopyData, opts?: R...
method FileReadCommand (line 364) | FileReadCommand(client: WshClient, data: FileData, opts?: RpcOpts): Pr...
method FileReadStreamCommand (line 370) | FileReadStreamCommand(client: WshClient, data: FileData, opts?: RpcOpt...
method FileRestoreBackupCommand (line 376) | FileRestoreBackupCommand(client: WshClient, data: CommandFileRestoreBa...
method FileStreamCommand (line 382) | FileStreamCommand(client: WshClient, data: CommandFileStreamData, opts...
method FileWriteCommand (line 388) | FileWriteCommand(client: WshClient, data: FileData, opts?: RpcOpts): P...
method FindGitBashCommand (line 394) | FindGitBashCommand(client: WshClient, data: boolean, opts?: RpcOpts): ...
method FocusWindowCommand (line 400) | FocusWindowCommand(client: WshClient, data: string, opts?: RpcOpts): P...
method GetAllBadgesCommand (line 406) | GetAllBadgesCommand(client: WshClient, opts?: RpcOpts): Promise<BadgeE...
method GetAllVarsCommand (line 412) | GetAllVarsCommand(client: WshClient, data: CommandVarData, opts?: RpcO...
method GetBuilderOutputCommand (line 418) | GetBuilderOutputCommand(client: WshClient, data: string, opts?: RpcOpt...
method GetBuilderStatusCommand (line 424) | GetBuilderStatusCommand(client: WshClient, data: string, opts?: RpcOpt...
method GetFocusedBlockDataCommand (line 430) | GetFocusedBlockDataCommand(client: WshClient, opts?: RpcOpts): Promise...
method GetFullConfigCommand (line 436) | GetFullConfigCommand(client: WshClient, opts?: RpcOpts): Promise<FullC...
method GetJwtPublicKeyCommand (line 442) | GetJwtPublicKeyCommand(client: WshClient, opts?: RpcOpts): Promise<str...
method GetMetaCommand (line 448) | GetMetaCommand(client: WshClient, data: CommandGetMetaData, opts?: Rpc...
method GetRTInfoCommand (line 454) | GetRTInfoCommand(client: WshClient, data: CommandGetRTInfoData, opts?:...
method GetSecretsCommand (line 460) | GetSecretsCommand(client: WshClient, data: string[], opts?: RpcOpts): ...
method GetSecretsLinuxStorageBackendCommand (line 466) | GetSecretsLinuxStorageBackendCommand(client: WshClient, opts?: RpcOpts...
method GetSecretsNamesCommand (line 472) | GetSecretsNamesCommand(client: WshClient, opts?: RpcOpts): Promise<str...
method GetTabCommand (line 478) | GetTabCommand(client: WshClient, data: string, opts?: RpcOpts): Promis...
method GetTempDirCommand (line 484) | GetTempDirCommand(client: WshClient, data: CommandGetTempDirData, opts...
method GetUpdateChannelCommand (line 490) | GetUpdateChannelCommand(client: WshClient, opts?: RpcOpts): Promise<st...
method GetVarCommand (line 496) | GetVarCommand(client: WshClient, data: CommandVarData, opts?: RpcOpts)...
method GetWaveAIChatCommand (line 502) | GetWaveAIChatCommand(client: WshClient, data: CommandGetWaveAIChatData...
method GetWaveAIModeConfigCommand (line 508) | GetWaveAIModeConfigCommand(client: WshClient, opts?: RpcOpts): Promise...
method GetWaveAIRateLimitCommand (line 514) | GetWaveAIRateLimitCommand(client: WshClient, opts?: RpcOpts): Promise<...
method JobCmdExitedCommand (line 520) | JobCmdExitedCommand(client: WshClient, data: CommandJobCmdExitedData, ...
method JobControllerAttachJobCommand (line 526) | JobControllerAttachJobCommand(client: WshClient, data: CommandJobContr...
method JobControllerConnectedJobsCommand (line 532) | JobControllerConnectedJobsCommand(client: WshClient, opts?: RpcOpts): ...
method JobControllerDeleteJobCommand (line 538) | JobControllerDeleteJobCommand(client: WshClient, data: string, opts?: ...
method JobControllerDetachJobCommand (line 544) | JobControllerDetachJobCommand(client: WshClient, data: string, opts?: ...
method JobControllerDisconnectJobCommand (line 550) | JobControllerDisconnectJobCommand(client: WshClient, data: string, opt...
method JobControllerExitJobCommand (line 556) | JobControllerExitJobCommand(client: WshClient, data: string, opts?: Rp...
method JobControllerGetAllJobManagerStatusCommand (line 562) | JobControllerGetAllJobManagerStatusCommand(client: WshClient, opts?: R...
method JobControllerListCommand (line 568) | JobControllerListCommand(client: WshClient, opts?: RpcOpts): Promise<J...
method JobControllerReconnectJobCommand (line 574) | JobControllerReconnectJobCommand(client: WshClient, data: string, opts...
method JobControllerReconnectJobsForConnCommand (line 580) | JobControllerReconnectJobsForConnCommand(client: WshClient, data: stri...
method JobControllerStartJobCommand (line 586) | JobControllerStartJobCommand(client: WshClient, data: CommandJobContro...
method JobInputCommand (line 592) | JobInputCommand(client: WshClient, data: CommandJobInputData, opts?: R...
method JobPrepareConnectCommand (line 598) | JobPrepareConnectCommand(client: WshClient, data: CommandJobPrepareCon...
method JobStartStreamCommand (line 604) | JobStartStreamCommand(client: WshClient, data: CommandJobStartStreamDa...
method ListAllAppFilesCommand (line 610) | ListAllAppFilesCommand(client: WshClient, data: CommandListAllAppFiles...
method ListAllAppsCommand (line 616) | ListAllAppsCommand(client: WshClient, opts?: RpcOpts): Promise<AppInfo...
method ListAllEditableAppsCommand (line 622) | ListAllEditableAppsCommand(client: WshClient, opts?: RpcOpts): Promise...
method MacOSVersionCommand (line 628) | MacOSVersionCommand(client: WshClient, opts?: RpcOpts): Promise<string> {
method MakeDraftFromLocalCommand (line 634) | MakeDraftFromLocalCommand(client: WshClient, data: CommandMakeDraftFro...
method MessageCommand (line 640) | MessageCommand(client: WshClient, data: CommandMessageData, opts?: Rpc...
method NetworkOnlineCommand (line 646) | NetworkOnlineCommand(client: WshClient, opts?: RpcOpts): Promise<boole...
method NotifyCommand (line 652) | NotifyCommand(client: WshClient, data: WaveNotificationOptions, opts?:...
method NotifySystemResumeCommand (line 658) | NotifySystemResumeCommand(client: WshClient, opts?: RpcOpts): Promise<...
method PathCommand (line 664) | PathCommand(client: WshClient, data: PathCommandData, opts?: RpcOpts):...
method PublishAppCommand (line 670) | PublishAppCommand(client: WshClient, data: CommandPublishAppData, opts...
method ReadAppFileCommand (line 676) | ReadAppFileCommand(client: WshClient, data: CommandReadAppFileData, op...
method RecordTEventCommand (line 682) | RecordTEventCommand(client: WshClient, data: TEvent, opts?: RpcOpts): ...
method RemoteDisconnectFromJobManagerCommand (line 688) | RemoteDisconnectFromJobManagerCommand(client: WshClient, data: Command...
method RemoteFileCopyCommand (line 694) | RemoteFileCopyCommand(client: WshClient, data: CommandFileCopyData, op...
method RemoteFileDeleteCommand (line 700) | RemoteFileDeleteCommand(client: WshClient, data: CommandDeleteFileData...
method RemoteFileInfoCommand (line 706) | RemoteFileInfoCommand(client: WshClient, data: string, opts?: RpcOpts)...
method RemoteFileJoinCommand (line 712) | RemoteFileJoinCommand(client: WshClient, data: string[], opts?: RpcOpt...
method RemoteFileMoveCommand (line 718) | RemoteFileMoveCommand(client: WshClient, data: CommandFileCopyData, op...
method RemoteFileMultiInfoCommand (line 724) | RemoteFileMultiInfoCommand(client: WshClient, data: CommandRemoteFileM...
method RemoteFileStreamCommand (line 730) | RemoteFileStreamCommand(client: WshClient, data: CommandRemoteFileStre...
method RemoteFileTouchCommand (line 736) | RemoteFileTouchCommand(client: WshClient, data: string, opts?: RpcOpts...
method RemoteGetInfoCommand (line 742) | RemoteGetInfoCommand(client: WshClient, opts?: RpcOpts): Promise<Remot...
method RemoteInstallRcFilesCommand (line 748) | RemoteInstallRcFilesCommand(client: WshClient, opts?: RpcOpts): Promis...
method RemoteListEntriesCommand (line 754) | RemoteListEntriesCommand(client: WshClient, data: CommandRemoteListEnt...
method RemoteMkdirCommand (line 760) | RemoteMkdirCommand(client: WshClient, data: string, opts?: RpcOpts): P...
method RemoteReconnectToJobManagerCommand (line 766) | RemoteReconnectToJobManagerCommand(client: WshClient, data: CommandRem...
method RemoteStartJobCommand (line 772) | RemoteStartJobCommand(client: WshClient, data: CommandRemoteStartJobDa...
method RemoteStreamCpuDataCommand (line 778) | RemoteStreamCpuDataCommand(client: WshClient, opts?: RpcOpts): AsyncGe...
method RemoteStreamFileCommand (line 784) | RemoteStreamFileCommand(client: WshClient, data: CommandRemoteStreamFi...
method RemoteTerminateJobManagerCommand (line 790) | RemoteTerminateJobManagerCommand(client: WshClient, data: CommandRemot...
method RemoteWriteFileCommand (line 796) | RemoteWriteFileCommand(client: WshClient, data: FileData, opts?: RpcOp...
method RenameAppFileCommand (line 802) | RenameAppFileCommand(client: WshClient, data: CommandRenameAppFileData...
method ResolveIdsCommand (line 808) | ResolveIdsCommand(client: WshClient, data: CommandResolveIdsData, opts...
method RestartBuilderAndWaitCommand (line 814) | RestartBuilderAndWaitCommand(client: WshClient, data: CommandRestartBu...
method RouteAnnounceCommand (line 820) | RouteAnnounceCommand(client: WshClient, opts?: RpcOpts): Promise<void> {
method RouteUnannounceCommand (line 826) | RouteUnannounceCommand(client: WshClient, opts?: RpcOpts): Promise<voi...
method SendTelemetryCommand (line 832) | SendTelemetryCommand(client: WshClient, opts?: RpcOpts): Promise<void> {
method SetBlockFocusCommand (line 838) | SetBlockFocusCommand(client: WshClient, data: string, opts?: RpcOpts):...
method SetConfigCommand (line 844) | SetConfigCommand(client: WshClient, data: SettingsType, opts?: RpcOpts...
method SetConnectionsConfigCommand (line 850) | SetConnectionsConfigCommand(client: WshClient, data: ConnConfigRequest...
method SetMetaCommand (line 856) | SetMetaCommand(client: WshClient, data: CommandSetMetaData, opts?: Rpc...
method SetPeerInfoCommand (line 862) | SetPeerInfoCommand(client: WshClient, data: string, opts?: RpcOpts): P...
method SetRTInfoCommand (line 868) | SetRTInfoCommand(client: WshClient, data: CommandSetRTInfoData, opts?:...
method SetSecretsCommand (line 874) | SetSecretsCommand(client: WshClient, data: {[key: string]: string}, op...
method SetVarCommand (line 880) | SetVarCommand(client: WshClient, data: CommandVarData, opts?: RpcOpts)...
method StartBuilderCommand (line 886) | StartBuilderCommand(client: WshClient, data: CommandStartBuilderData, ...
method StartJobCommand (line 892) | StartJobCommand(client: WshClient, data: CommandStartJobData, opts?: R...
method StopBuilderCommand (line 898) | StopBuilderCommand(client: WshClient, data: string, opts?: RpcOpts): P...
method StreamCpuDataCommand (line 904) | StreamCpuDataCommand(client: WshClient, data: CpuDataRequest, opts?: R...
method StreamDataCommand (line 910) | StreamDataCommand(client: WshClient, data: CommandStreamData, opts?: R...
method StreamDataAckCommand (line 916) | StreamDataAckCommand(client: WshClient, data: CommandStreamAckData, op...
method StreamTestCommand (line 922) | StreamTestCommand(client: WshClient, opts?: RpcOpts): AsyncGenerator<n...
method StreamWaveAiCommand (line 928) | StreamWaveAiCommand(client: WshClient, data: WaveAIStreamRequest, opts...
method TermGetScrollbackLinesCommand (line 934) | TermGetScrollbackLinesCommand(client: WshClient, data: CommandTermGetS...
method TestCommand (line 940) | TestCommand(client: WshClient, data: string, opts?: RpcOpts): Promise<...
method TestMultiArgCommand (line 946) | TestMultiArgCommand(client: WshClient, arg1: string, arg2: number, arg...
method UpdateTabNameCommand (line 952) | UpdateTabNameCommand(client: WshClient, arg1: string, arg2: string, op...
method UpdateWorkspaceTabIdsCommand (line 958) | UpdateWorkspaceTabIdsCommand(client: WshClient, arg1: string, arg2: st...
method VDomAsyncInitiationCommand (line 964) | VDomAsyncInitiationCommand(client: WshClient, data: VDomAsyncInitiatio...
method VDomCreateContextCommand (line 970) | VDomCreateContextCommand(client: WshClient, data: VDomCreateContext, o...
method VDomRenderCommand (line 976) | VDomRenderCommand(client: WshClient, data: VDomFrontendUpdate, opts?: ...
method VDomUrlRequestCommand (line 982) | VDomUrlRequestCommand(client: WshClient, data: VDomUrlRequestData, opt...
method WaitForRouteCommand (line 988) | WaitForRouteCommand(client: WshClient, data: CommandWaitForRouteData, ...
method WaveAIAddContextCommand (line 994) | WaveAIAddContextCommand(client: WshClient, data: CommandWaveAIAddConte...
method WaveAIEnableTelemetryCommand (line 1000) | WaveAIEnableTelemetryCommand(client: WshClient, opts?: RpcOpts): Promi...
method WaveAIGetToolDiffCommand (line 1006) | WaveAIGetToolDiffCommand(client: WshClient, data: CommandWaveAIGetTool...
method WaveAIToolApproveCommand (line 1012) | WaveAIToolApproveCommand(client: WshClient, data: CommandWaveAIToolApp...
method WaveFileReadStreamCommand (line 1018) | WaveFileReadStreamCommand(client: WshClient, data: CommandWaveFileRead...
method WaveInfoCommand (line 1024) | WaveInfoCommand(client: WshClient, opts?: RpcOpts): Promise<WaveInfoDa...
method WebSelectorCommand (line 1030) | WebSelectorCommand(client: WshClient, data: CommandWebSelectorData, op...
method WorkspaceListCommand (line 1036) | WorkspaceListCommand(client: WshClient, opts?: RpcOpts): Promise<Works...
method WriteAppFileCommand (line 1042) | WriteAppFileCommand(client: WshClient, data: CommandWriteAppFileData, ...
method WriteAppGoFileCommand (line 1048) | WriteAppGoFileCommand(client: WshClient, data: CommandWriteAppGoFileDa...
method WriteAppSecretBindingsCommand (line 1054) | WriteAppSecretBindingsCommand(client: WshClient, data: CommandWriteApp...
method WriteTempFileCommand (line 1060) | WriteTempFileCommand(client: WshClient, data: CommandWriteTempFileData...
method WshActivityCommand (line 1066) | WshActivityCommand(client: WshClient, data: {[key: string]: number}, o...
method WslDefaultDistroCommand (line 1072) | WslDefaultDistroCommand(client: WshClient, opts?: RpcOpts): Promise<st...
method WslListCommand (line 1078) | WslListCommand(client: WshClient, opts?: RpcOpts): Promise<string[]> {
method WslStatusCommand (line 1084) | WslStatusCommand(client: WshClient, opts?: RpcOpts): Promise<ConnStatu...
FILE: frontend/app/store/wshrouter.ts
type RouteInfo (line 13) | type RouteInfo = {
function makeFeBlockRouteId (line 19) | function makeFeBlockRouteId(feBlockId: string): string {
function makeTabRouteId (line 23) | function makeTabRouteId(tabId: string): string {
function makeBuilderRouteId (line 27) | function makeBuilderRouteId(builderId: string): string {
class WshRouter (line 31) | class WshRouter {
method constructor (line 36) | constructor(upstreamClient: AbstractWshClient) {
method reannounceRoutes (line 45) | reannounceRoutes() {
method _sendRoutedMessage (line 58) | _sendRoutedMessage(msg: RpcMessage, destRouteId: string) {
method _registerRouteInfo (line 71) | _registerRouteInfo(reqid: string, sourceRouteId: string, destRouteId: ...
method recvRpcMessage (line 84) | recvRpcMessage(msg: RpcMessage) {
method registerRoute (line 130) | registerRoute(routeId: string, client: AbstractWshClient) {
method unregisterRoute (line 146) | unregisterRoute(routeId: string) {
FILE: frontend/app/store/wshrpcutil-base.ts
function setDefaultRouter (line 12) | function setDefaultRouter(router: WshRouter) {
function sendRpcCancel (line 74) | function sendRpcCancel(reqid: string) {
function sendRpcResponse (line 79) | function sendRpcResponse(msg: RpcMessage) {
function sendRpcCommand (line 83) | function sendRpcCommand(
function consumeGenerator (line 96) | async function consumeGenerator(gen: AsyncGenerator<any, any, any>) {
function initElectronWshrpc (line 114) | function initElectronWshrpc(electronClient: WshClient, eoOpts: ElectronO...
function shutdownWshrpc (line 129) | function shutdownWshrpc() {
class UpstreamWshRpcProxy (line 133) | class UpstreamWshRpcProxy implements AbstractWshClient {
method recvRpcMessage (line 134) | recvRpcMessage(msg: RpcMessage): void {
FILE: frontend/app/store/wshrpcutil.ts
function initWshrpc (line 13) | function initWshrpc(routeId: string): WSControl {
class UpstreamWshRpcProxy (line 31) | class UpstreamWshRpcProxy implements AbstractWshClient {
method recvRpcMessage (line 32) | recvRpcMessage(msg: RpcMessage): void {
FILE: frontend/app/suggestion/suggestion.tsx
type SuggestionControlProps (line 11) | interface SuggestionControlProps {
type BlockHeaderSuggestionControlProps (line 23) | type BlockHeaderSuggestionControlProps = Omit<SuggestionControlProps, "a...
function SuggestionControl (line 28) | function SuggestionControl({
function highlightPositions (line 45) | function highlightPositions(target: string, positions: number[]): ReactN...
function getMimeTypeIconAndColor (line 72) | function getMimeTypeIconAndColor(fullConfig: FullConfigType, mimeType: s...
function SuggestionIcon (line 87) | function SuggestionIcon({ suggestion }: { suggestion: SuggestionType }) {
function SuggestionContent (line 115) | function SuggestionContent({ suggestion }: { suggestion: SuggestionType ...
function BlockHeaderSuggestionControl (line 131) | function BlockHeaderSuggestionControl(props: BlockHeaderSuggestionContro...
function SuggestionControlNoResults (line 152) | function SuggestionControlNoResults({ children }: { children?: React.Rea...
function SuggestionControlNoData (line 160) | function SuggestionControlNoData({ children }: { children?: React.ReactN...
type SuggestionControlInnerProps (line 168) | type SuggestionControlInnerProps = Omit<SuggestionControlProps, "isOpen">;
function SuggestionControlInner (line 170) | function SuggestionControlInner({
FILE: frontend/app/tab/tab.tsx
type TabEnv (line 19) | type TabEnv = WaveEnvSubset<{
type TabVProps (line 34) | interface TabVProps {
type TabProps (line 222) | interface TabProps {
FILE: frontend/app/tab/tabbadges.tsx
type TabBadgesProps (line 9) | interface TabBadgesProps {
function TabBadges (line 18) | function TabBadges({ badges, flagColor, className }: TabBadgesProps) {
FILE: frontend/app/tab/tabbar-model.ts
class TabBarModel (line 4) | class TabBarModel {
method constructor (line 7) | private constructor() {}
method getInstance (line 9) | static getInstance(): TabBarModel {
FILE: frontend/app/tab/tabbar.tsx
type TabBarProps (line 43) | interface TabBarProps {
function strArrayIsEqual (line 78) | function strArrayIsEqual(a: string[], b: string[]) {
function onEllipsisClick (line 568) | function onEllipsisClick() {
FILE: frontend/app/tab/tabbarenv.ts
type TabBarEnv (line 6) | type TabBarEnv = WaveEnvSubset<{
FILE: frontend/app/tab/tabcontent.tsx
function onNodeDelete (line 37) | function onNodeDelete(data: TabLayoutData) {
FILE: frontend/app/tab/tabcontextmenu.ts
function buildTabBarContextMenu (line 20) | function buildTabBarContextMenu(env: TabEnv): ContextMenuItem[] {
function buildTabContextMenu (line 39) | function buildTabContextMenu(
FILE: frontend/app/tab/updatebanner.tsx
type UpdateBannerEnv (line 9) | type UpdateBannerEnv = WaveEnvSubset<{
function getUpdateStatusMessage (line 18) | function getUpdateStatusMessage(status: string): string {
FILE: frontend/app/tab/vtab.test.tsx
function renderVTab (line 11) | function renderVTab(tab: VTabItem): string {
FILE: frontend/app/tab/vtab.tsx
type VTabItem (line 11) | interface VTabItem {
type VTabProps (line 19) | interface VTabProps {
function VTab (line 37) | function VTab({
FILE: frontend/app/tab/vtabbar.tsx
type VTabBarProps (line 81) | interface VTabBarProps {
type VTabWrapperProps (line 86) | interface VTabWrapperProps {
function VTabWrapper (line 104) | function VTabWrapper({
function VTabBar (line 175) | function VTabBar({ workspace, className }: VTabBarProps) {
FILE: frontend/app/tab/vtabbarenv.ts
type VTabBarEnv (line 6) | type VTabBarEnv = WaveEnvSubset<{
FILE: frontend/app/tab/workspaceeditor.tsx
type ColorSelectorProps (line 9) | interface ColorSelectorProps {
type IconSelectorProps (line 35) | interface IconSelectorProps {
type WorkspaceEditorProps (line 63) | interface WorkspaceEditorProps {
FILE: frontend/app/tab/workspaceswitcher.tsx
type WorkspaceSwitcherEnv (line 28) | type WorkspaceSwitcherEnv = WaveEnvSubset<{
type WorkspaceListEntry (line 43) | type WorkspaceListEntry = {
type WorkspaceList (line 48) | type WorkspaceList = WorkspaceListEntry[];
FILE: frontend/app/treeview/treeview.test.ts
function makeNodes (line 7) | function makeNodes(entries: TreeNodeData[]): Map<string, TreeNodeData> {
FILE: frontend/app/treeview/treeview.tsx
type TreeNodeChildrenStatus (line 19) | type TreeNodeChildrenStatus = "unloaded" | "loading" | "loaded" | "error...
type TreeNodeData (line 21) | interface TreeNodeData {
type FetchDirResult (line 37) | interface FetchDirResult {
type TreeViewVisibleRow (line 43) | interface TreeViewVisibleRow {
type TreeViewProps (line 56) | interface TreeViewProps {
type TreeViewRef (line 73) | interface TreeViewRef {
function normalizeLabel (line 82) | function normalizeLabel(node: TreeNodeData): string {
function sortIdsByNode (line 91) | function sortIdsByNode(nodesById: Map<string, TreeNodeData>, ids: string...
function buildVisibleRows (line 109) | function buildVisibleRows(
function getNodeIcon (line 179) | function getNodeIcon(node: TreeNodeData, isExpanded: boolean): string {
FILE: frontend/app/view/aifilediff/aifilediff.tsx
type DiffData (line 14) | type DiffData = {
type AiFileDiffEnv (line 20) | type AiFileDiffEnv = WaveEnvSubset<{
class AiFileDiffViewModel (line 27) | class AiFileDiffViewModel implements ViewModel {
method constructor (line 41) | constructor({ blockId, nodeModel, tabModel, waveEnv }: ViewModelInitTy...
method viewComponent (line 58) | get viewComponent(): ViewComponent {
function AiFileDiffView (line 63) | function AiFileDiffView({ blockId, model }: ViewComponentProps<AiFileDif...
FILE: frontend/app/view/codeeditor/codeeditor.tsx
function defaultEditorOptions (line 11) | function defaultEditorOptions(): MonacoTypes.editor.IEditorOptions {
type CodeEditorProps (line 32) | interface CodeEditorProps {
function CodeEditor (line 42) | function CodeEditor({ blockId, text, language, fileName, readonly, onCha...
FILE: frontend/app/view/codeeditor/diffviewer.tsx
type DiffViewerProps (line 10) | interface DiffViewerProps {
function defaultDiffEditorOptions (line 18) | function defaultDiffEditorOptions(): MonacoTypes.editor.IDiffEditorOptio...
function DiffViewer (line 39) | function DiffViewer({ blockId, original, modified, language, fileName }:...
FILE: frontend/app/view/helpview/helpview.tsx
class HelpViewModel (line 12) | class HelpViewModel extends WebViewModel {
method viewComponent (line 13) | get viewComponent(): ViewComponent {
method constructor (line 17) | constructor(initOpts: ViewModelInitType) {
method setZoomFactor (line 49) | setZoomFactor(factor: number | null) {
method getSettingsMenuItems (line 68) | getSettingsMenuItems(): ContextMenuItem[] {
function HelpView (line 126) | function HelpView(props: ViewComponentProps<HelpViewModel>) {
FILE: frontend/app/view/launcher/launcher.tsx
function sortByDisplayOrder (line 14) | function sortByDisplayOrder(wmap: { [key: string]: WidgetConfigType } | ...
type GridLayoutType (line 21) | type GridLayoutType = { columns: number; tileWidth: number; tileHeight: ...
class LauncherViewModel (line 23) | class LauncherViewModel implements ViewModel {
method constructor (line 38) | constructor({ blockId, nodeModel, tabModel }: ViewModelInitType) {
method giveFocus (line 54) | giveFocus(): boolean {
method keyDownHandler (line 62) | keyDownHandler(e: WaveKeyboardEvent): boolean {
method handleWidgetSelect (line 131) | async handleWidgetSelect(widget: WidgetConfigType) {
function LauncherView (line 140) | function LauncherView({ blockId, model }: ViewComponentProps<LauncherVie...
FILE: frontend/app/view/preview/csvview.tsx
constant MAX_DATA_SIZE (line 19) | const MAX_DATA_SIZE = 10 * 1024 * 1024;
type CSVRow (line 21) | type CSVRow = {
type CSVViewProps (line 25) | interface CSVViewProps {
type State (line 32) | interface State {
FILE: frontend/app/view/preview/entry-manager.tsx
type EntryManagerType (line 8) | enum EntryManagerType {
type EntryManagerOverlayProps (line 14) | type EntryManagerOverlayProps = {
FILE: frontend/app/view/preview/preview-directory-utils.tsx
function getBestUnit (line 27) | function getBestUnit(bytes: number, si = false, sigfig = 3): string {
function padDay (line 41) | function padDay(day: number) {
function getLastModifiedTime (line 45) | function getLastModifiedTime(unixMillis: number): string {
function isIconValid (line 61) | function isIconValid(icon: string): boolean {
function getSortIcon (line 68) | function getSortIcon(sortType: string | boolean): React.ReactNode {
function cleanMimetype (line 79) | function cleanMimetype(input: string): string {
function handleRename (line 84) | function handleRename(
function handleFileDelete (line 114) | function handleFileDelete(
function makeDirectoryDefaultMenuItems (line 155) | function makeDirectoryDefaultMenuItems(model: PreviewModel): ContextMenu...
FILE: frontend/app/view/preview/preview-directory.tsx
type DirectoryTableHeaderCellProps (line 51) | interface DirectoryTableHeaderCellProps {
function DirectoryTableHeaderCell (line 55) | function DirectoryTableHeaderCell({ header }: DirectoryTableHeaderCellPr...
type TableMeta (line 78) | interface TableMeta<TData extends RowData> {
type DirectoryTableProps (line 85) | interface DirectoryTableProps {
function DirectoryTable (line 101) | function DirectoryTable({
type TableBodyProps (line 301) | interface TableBodyProps {
function TableBody (line 315) | function TableBody({
type TableRowProps (line 492) | type TableRowProps = {
function TableRow (line 502) | function TableRow({ model, row, focusIndex, setFocusIndex, setSearch, id...
type DirectoryPreviewProps (line 560) | interface DirectoryPreviewProps {
function DirectoryPreview (line 564) | function DirectoryPreview({ model }: DirectoryPreviewProps) {
FILE: frontend/app/view/preview/preview-edit.tsx
function CodeEditPreview (line 39) | function CodeEditPreview({ model }: SpecializedViewProps) {
FILE: frontend/app/view/preview/preview-markdown.tsx
function MarkdownPreview (line 11) | function MarkdownPreview({ model }: SpecializedViewProps) {
FILE: frontend/app/view/preview/preview-model.tsx
constant BOOKMARKS (line 26) | const BOOKMARKS: { label: string; path: string }[] = [
function isTextFile (line 59) | function isTextFile(mimeType: string): boolean {
function isStreamingType (line 72) | function isStreamingType(mimeType: string): boolean {
function isMarkdownLike (line 84) | function isMarkdownLike(mimeType: string): boolean {
function iconForFile (line 91) | function iconForFile(mimeType: string): string {
class PreviewModel (line 119) | class PreviewModel implements ViewModel {
method constructor (line 173) | constructor({ blockId, nodeModel, tabModel, waveEnv }: ViewModelInitTy...
method markdownShowTocToggle (line 494) | markdownShowTocToggle() {
method viewComponent (line 498) | get viewComponent(): ViewComponent {
method getSpecializedView (line 502) | async getSpecializedView(getFn: Getter): Promise<{ specializedView?: s...
method updateOpenFileModalAndError (line 556) | updateOpenFileModalAndError(isOpen, errorMsg = null) {
method toggleOpenFileModal (line 571) | toggleOpenFileModal() {
method goHistory (line 580) | async goHistory(newPath: string) {
method goParentDirectory (line 598) | async goParentDirectory({ fileInfo = null }: { fileInfo?: FileInfo | n...
method goHistoryBack (line 618) | async goHistoryBack() {
method goHistoryForward (line 630) | async goHistoryForward() {
method setEditMode (line 642) | async setEditMode(edit: boolean) {
method handleFileSave (line 648) | async handleFileSave() {
method handleFileRevert (line 677) | async handleFileRevert() {
method handleOpenFile (line 683) | async handleOpenFile(filePath: string) {
method isSpecializedView (line 698) | isSpecializedView(sv: string): boolean {
method getSettingsMenuItems (line 703) | getSettingsMenuItems(): ContextMenuItem[] {
method giveFocus (line 808) | giveFocus(): boolean {
method keyDownHandler (line 821) | keyDownHandler(e: WaveKeyboardEvent): boolean {
method formatRemoteUri (line 862) | async formatRemoteUri(path: string, get: Getter): Promise<string> {
FILE: frontend/app/view/preview/preview-streaming.tsx
function ImageZoomControls (line 14) | function ImageZoomControls() {
function StreamingImagePreview (line 32) | function StreamingImagePreview({ url }: { url: string }) {
function StreamingPreview (line 49) | function StreamingPreview({ model }: SpecializedViewProps) {
FILE: frontend/app/view/preview/preview.tsx
type SpecializedViewProps (line 21) | type SpecializedViewProps = {
function canPreview (line 34) | function canPreview(mimeType: string): boolean {
function CSVViewPreview (line 41) | function CSVViewPreview({ model, parentRef }: SpecializedViewProps) {
function PreviewView (line 99) | function PreviewView({
FILE: frontend/app/view/preview/previewenv.ts
type PreviewEnv (line 6) | type PreviewEnv = WaveEnvSubset<{
FILE: frontend/app/view/quicktipsview/quicktipsview.tsx
class QuickTipsViewModel (line 10) | class QuickTipsViewModel implements ViewModel {
method constructor (line 18) | constructor({ blockId, nodeModel, tabModel }: ViewModelInitType) {
method viewComponent (line 26) | get viewComponent(): ViewComponent {
method showTocToggle (line 30) | showTocToggle() {
function QuickTipsView (line 35) | function QuickTipsView({ model }: { model: QuickTipsViewModel }) {
FILE: frontend/app/view/sysinfo/sysinfo.tsx
type SysinfoEnv (line 20) | type SysinfoEnv = WaveEnvSubset<{
type DataItem (line 34) | type DataItem = {
function defaultCpuMeta (line 39) | function defaultCpuMeta(name: string): TimeSeriesMeta {
function defaultMemMeta (line 50) | function defaultMemMeta(name: string, maxY: string): TimeSeriesMeta {
function convertWaveEventToDataItem (line 93) | function convertWaveEventToDataItem(event: Extract<WaveEvent, { event: "...
class SysinfoViewModel (line 105) | class SysinfoViewModel implements ViewModel {
method constructor (line 129) | constructor({ blockId, waveEnv }: ViewModelInitType) {
method viewComponent (line 249) | get viewComponent(): ViewComponent {
method loadInitialData (line 253) | async loadInitialData() {
method getSettingsMenuItems (line 278) | getSettingsMenuItems(): ContextMenuItem[] {
method getDefaultData (line 318) | getDefaultData(): DataItem[] {
type SysinfoViewProps (line 332) | type SysinfoViewProps = {
function resolveDomainBound (line 337) | function resolveDomainBound(value: number | string, dataItem: DataItem):...
function SysinfoView (line 347) | function SysinfoView({ model, blockId }: SysinfoViewProps) {
type SingleLinePlotProps (line 396) | type SingleLinePlotProps = {
function SingleLinePlot (line 407) | function SingleLinePlot({
FILE: frontend/app/view/term/fitaddon.ts
type ITerminalDimensions (line 13) | interface ITerminalDimensions {
constant MINIMUM_COLS (line 25) | const MINIMUM_COLS = 2;
constant MINIMUM_ROWS (line 26) | const MINIMUM_ROWS = 1;
class FitAddon (line 28) | class FitAddon implements ITerminalAddon, IFitApi {
method activate (line 32) | public activate(terminal: Terminal): void {
method dispose (line 36) | public dispose(): void {}
method fit (line 38) | public fit(): void {
method proposeDimensions (line 54) | public proposeDimensions(): ITerminalDimensions | undefined {
FILE: frontend/app/view/term/ijson.tsx
type IJsonNode (line 7) | type IJsonNode = {
function convertNodeToTag (line 15) | function convertNodeToTag(node: IJsonNode | string, idx?: number): React...
function IJsonHtmlTag (line 33) | function IJsonHtmlTag({ node }: { node: IJsonNode }) {
function IJsonView (line 83) | function IJsonView({ rootNode }: { rootNode: IJsonNode }) {
FILE: frontend/app/view/term/osc-handlers.ts
type ShellIntegrationStatus (line 26) | type ShellIntegrationStatus = "ready" | "running-command";
type Osc16162Command (line 28) | type Osc16162Command =
function checkCommandForTelemetry (line 46) | function checkCommandForTelemetry(decodedCmd: string) {
function handleShellIntegrationCommandStart (line 81) | function handleShellIntegrationCommandStart(
function handleOsc52Command (line 120) | function handleOsc52Command(data: string, blockId: string, loaded: boole...
function handleOsc7Command (line 200) | function handleOsc7Command(data: string, blockId: string, loaded: boolea...
function handleOsc16162Command (line 263) | function handleOsc16162Command(data: string, blockId: string, loaded: bo...
FILE: frontend/app/view/term/shellblocking.ts
constant ALWAYS_BLOCK (line 5) | const ALWAYS_BLOCK = [
constant BARE_REPLS (line 22) | const BARE_REPLS = [
constant SHELLS (line 27) | const SHELLS = [
constant WRAPPERS (line 33) | const WRAPPERS = [
function looksInteractiveShellArgs (line 38) | function looksInteractiveShellArgs(args: string[]): boolean {
function isNonInteractiveShellExec (line 48) | function isNonInteractiveShellExec(args: string[]): boolean {
function isAttachLike (line 56) | function isAttachLike(cmd: string, args: string[]): boolean {
function isSshInteractive (line 69) | function isSshInteractive(args: string[]): boolean {
function getBlockingCommand (line 75) | function getBlockingCommand(lastCommand: string | null, inAltBuffer: boo...
FILE: frontend/app/view/term/term-model.ts
class TermViewModel (line 46) | class TermViewModel implements ViewModel {
method constructor (line 88) | constructor({ blockId, nodeModel, tabModel }: ViewModelInitType) {
method getShellIntegrationIconButton (line 402) | getShellIntegrationIconButton(get: jotai.Getter): IconButtonDecl | null {
method getWebGlIconButton (line 448) | getWebGlIconButton(get: jotai.Getter): IconButtonDecl | null {
method viewComponent (line 480) | get viewComponent(): ViewComponent {
method isBasicTerm (line 484) | isBasicTerm(getFn: jotai.Getter): boolean {
method multiInputHandler (line 496) | multiInputHandler(data: string) {
method sendDataToController (line 505) | sendDataToController(data: string) {
method setTermMode (line 510) | setTermMode(mode: "term" | "vdom") {
method getTermRenderer (line 520) | getTermRenderer(): "webgl" | "canvas" {
method isWebGlEnabled (line 524) | isWebGlEnabled(): boolean {
method toggleWebGl (line 528) | toggleWebGl() {
method triggerRestartAtom (line 536) | triggerRestartAtom() {
method handleBlockJobStatusUpdate (line 543) | handleBlockJobStatusUpdate(status: BlockJobStatusData) {
method updateShellProcStatus (line 554) | updateShellProcStatus(fullStatus: BlockControllerRuntimeStatus) {
method getVDomModel (line 564) | getVDomModel(): VDomModel {
method getVDomToolbarModel (line 576) | getVDomToolbarModel(): VDomModel {
method dispose (line 588) | dispose() {
method giveFocus (line 597) | giveFocus(): boolean {
method keyDownHandler (line 612) | keyDownHandler(waveEvent: WaveKeyboardEvent): boolean {
method shouldHandleCtrlVPaste (line 676) | shouldHandleCtrlVPaste(): boolean {
method handleTerminalKeydown (line 695) | handleTerminalKeydown(event: KeyboardEvent): boolean {
method setTerminalTheme (line 783) | setTerminalTheme(themeName: string) {
method forceRestartController (line 790) | async forceRestartController() {
method restartSessionWithDurability (line 808) | async restartSessionWithDurability(isDurable: boolean) {
method getContextMenuItems (line 826) | getContextMenuItems(): ContextMenuItem[] {
method getSettingsMenuItems (line 914) | getSettingsMenuItems(): ContextMenuItem[] {
function getAllBasicTermModels (line 1370) | function getAllBasicTermModels(): TermViewModel[] {
FILE: frontend/app/view/term/term-tooltip.tsx
type TermTooltipProps (line 11) | interface TermTooltipProps {
method getBoundingClientRect (line 41) | getBoundingClientRect() {
function clearTimeoutRef (line 68) | function clearTimeoutRef(ref: React.RefObject<number | null>) {
type TermLinkTooltipProps (line 80) | interface TermLinkTooltipProps {
FILE: frontend/app/view/term/term-wsh.tsx
class TermWshClient (line 16) | class TermWshClient extends WshClient {
method constructor (line 20) | constructor(blockId: string, model: TermViewModel) {
method handle_vdomcreatecontext (line 26) | async handle_vdomcreatecontext(rh: RpcResponseHelper, data: VDomCreate...
method handle_termgetscrollbacklines (line 108) | async handle_termgetscrollbacklines(
FILE: frontend/app/view/term/term.tsx
type TerminalViewProps (line 32) | interface TerminalViewProps {
FILE: frontend/app/view/term/termsticker.tsx
type StickerType (line 13) | type StickerType = {
type StickerTermConfig (line 34) | type StickerTermConfig = {
function convertWidthDimToPx (line 42) | function convertWidthDimToPx(dim: number, config: StickerTermConfig) {
function convertHeightDimToPx (line 49) | function convertHeightDimToPx(dim: number, config: StickerTermConfig) {
function TermSticker (line 56) | function TermSticker({ sticker, config }: { sticker: StickerType; config...
function TermStickers (line 117) | function TermStickers({ config }: { config: StickerTermConfig }) {
FILE: frontend/app/view/term/termtheme.ts
type TermThemeProps (line 11) | interface TermThemeProps {
FILE: frontend/app/view/term/termutil.ts
type GenClipboardItem (line 11) | type GenClipboardItem = { text?: string; image?: Blob };
function normalizeCursorStyle (line 13) | function normalizeCursorStyle(cursorStyle: string): TermTypes.Terminal["...
function applyTransparencyToColor (line 20) | function applyTransparencyToColor(hexColor: string, transparency: number...
function computeTheme (line 26) | function computeTheme(
constant MIME_TO_EXT (line 49) | const MIME_TO_EXT: Record<string, string> = {
function createTempFileFromBlob (line 74) | async function createTempFileFromBlob(blob: Blob): Promise<string> {
function extractClipboardData (line 120) | async function extractClipboardData(item: ClipboardItem): Promise<GenCli...
function findFirstDataTransferItem (line 169) | function findFirstDataTransferItem(
function findAllDataTransferItems (line 191) | function findAllDataTransferItems(
function extractDataTransferItems (line 231) | async function extractDataTransferItems(items: DataTransferItemList): Pr...
function extractAllClipboardData (line 300) | async function extractAllClipboardData(e?: ClipboardEvent): Promise<Arra...
function bufferLinesToText (line 341) | function bufferLinesToText(buffer: TermTypes.IBuffer, startIndex: number...
FILE: frontend/app/view/term/termwrap.ts
function detectWebGLSupport (line 50) | function detectWebGLSupport(): boolean {
type TermWrapOptions (line 63) | type TermWrapOptions = {
class TermWrap (line 70) | class TermWrap {
method constructor (line 131) | constructor(
method getZoneId (line 292) | getZoneId(): string {
method setCursorStyle (line 296) | setCursorStyle(cursorStyle: string) {
method setCursorBlink (line 300) | setCursorBlink(cursorBlink: boolean) {
method setTermRenderer (line 304) | setTermRenderer(renderer: "webgl" | "canvas") {
method getTermRenderer (line 350) | getTermRenderer(): "webgl" | "canvas" {
method isWebGlEnabled (line 354) | isWebGlEnabled(): boolean {
method resetCompositionState (line 358) | resetCompositionState() {
method initTerminal (line 385) | async initTerminal() {
method dispose (line 466) | dispose() {
method handleTermData (line 484) | handleTermData(data: string) {
method addFocusListener (line 504) | addFocusListener(focusFn: () => void) {
method handleNewFileSubjectData (line 508) | handleNewFileSubjectData(msg: WSFileEventData) {
method doTerminalWrite (line 525) | doTerminalWrite(data: string | Uint8Array, setPtyOffset?: number): Pro...
method loadInitialTerminalData (line 550) | async loadInitialTerminalData(): Promise<void> {
method resyncController (line 584) | async resyncController(reason: string) {
method setAtBottom (line 598) | setAtBottom(atBottom: boolean) {
method wasRecentlyAtBottom (line 608) | wasRecentlyAtBottom(): boolean {
method handleViewportScroll (line 615) | handleViewportScroll(viewportElem: HTMLElement) {
method handleResize (line 628) | handleResize() {
method processAndCacheData (line 663) | processAndCacheData() {
method runProcessIdleTimeout (line 676) | runProcessIdleTimeout() {
method pasteHandler (line 685) | async pasteHandler(e?: ClipboardEvent): Promise<void> {
method getScrollbackContent (line 715) | getScrollbackContent(): string {
FILE: frontend/app/view/tsunami/tsunami.tsx
class TsunamiViewModel (line 13) | class TsunamiViewModel extends WebViewModel {
method constructor (line 22) | constructor(initOpts: ViewModelInitType) {
method viewComponent (line 78) | get viewComponent(): ViewComponent {
method updateShellProcStatus (line 82) | updateShellProcStatus(fullStatus: BlockControllerRuntimeStatus) {
method triggerRestartAtom (line 93) | triggerRestartAtom() {
method doControllerResync (line 100) | private doControllerResync(forceRestart: boolean, logContext: string, ...
method resyncController (line 115) | resyncController() {
method destroyController (line 119) | destroyController() {
method restartController (line 124) | async restartController() {
method restartAndForceRebuild (line 145) | restartAndForceRebuild() {
method forceRestartController (line 149) | forceRestartController() {
method remixInBuilder (line 154) | async remixInBuilder() {
method dispose (line 172) | dispose() {
method getSettingsMenuItems (line 181) | getSettingsMenuItems(): ContextMenuItem[] {
FILE: frontend/app/view/vdom/vdom-model.tsx
type AtomContainer (line 23) | type AtomContainer = {
type RefContainer (line 29) | type RefContainer = {
function makeVDomIdMap (line 36) | function makeVDomIdMap(vdom: VDomElem, idMap: Map<string, VDomElem>) {
function annotateEvent (line 51) | function annotateEvent(event: VDomEvent, propName: string, reactEvent: R...
class VDomWshClient (line 92) | class VDomWshClient extends WshClient {
method constructor (line 95) | constructor(model: VDomModel) {
method handle_vdomasyncinitiation (line 100) | handle_vdomasyncinitiation(rh: RpcResponseHelper, data: VDomAsyncIniti...
class VDomModel (line 106) | class VDomModel {
method constructor (line 143) | constructor({ blockId, nodeModel, tabModel }: ViewModelInitType) {
method viewComponent (line 191) | get viewComponent(): ViewComponent {
method dispose (line 195) | dispose() {
method reset (line 200) | reset() {
method getBackendRoute (line 225) | getBackendRoute(): string {
method transformVDomUrl (line 230) | transformVDomUrl(url: string): string {
method makeVDomUrl (line 241) | makeVDomUrl(path: string): string {
method keyDownHandler (line 257) | keyDownHandler(e: WaveKeyboardEvent): boolean {
method hasRefUpdates (line 279) | hasRefUpdates() {
method getRefUpdates (line 288) | getRefUpdates(): VDomRefUpdate[] {
method queueUpdate (line 313) | queueUpdate(quick: boolean = false, delay: number = 10) {
method _sendRenderRequest (line 356) | async _sendRenderRequest(force: boolean) {
method getAtomContainer (line 404) | getAtomContainer(atomName: string): AtomContainer {
method getOrCreateRefContainer (line 417) | getOrCreateRefContainer(vdomRef: VDomRef): RefContainer {
method tagUseAtoms (line 438) | tagUseAtoms(waveId: string, atomNames: Set<string>) {
method tagUnuseAtoms (line 445) | tagUnuseAtoms(waveId: string, atomNames: Set<string>) {
method getVDomNodeVersionAtom (line 452) | getVDomNodeVersionAtom(vdom: VDomElem) {
method incVDomNodeVersion (line 461) | incVDomNodeVersion(vdom: VDomElem) {
method addErrorMessage (line 469) | addErrorMessage(message: string) {
method handleRenderUpdates (line 476) | handleRenderUpdates(update: VDomBackendUpdate, idMap: Map<string, VDom...
method setAtomValue (line 547) | setAtomValue(atomName: string, value: any, fromBe: boolean, idMap: Map...
method handleStateSync (line 559) | handleStateSync(update: VDomBackendUpdate, idMap: Map<string, VDomElem...
method getRefElem (line 568) | getRefElem(refId: string): HTMLElement {
method handleRefOperations (line 576) | handleRefOperations(update: VDomBackendUpdate, idMap: Map<string, VDom...
method handleBackendUpdate (line 606) | handleBackendUpdate(update: VDomBackendUpdate) {
method renderDone (line 634) | renderDone(version: number) {
method callVDomFunc (line 643) | callVDomFunc(fnDecl: VDomFunc, e: React.SyntheticEvent, compId: string...
method createFeUpdate (line 656) | createFeUpdate(): VDomFrontendUpdate {
method getBackendRouteId (line 687) | getBackendRouteId(): string {
FILE: frontend/app/view/vdom/vdom-utils.tsx
function getTextChildren (line 11) | function getTextChildren(elem: VDomElem): string {
function convertVDomId (line 24) | function convertVDomId(model: VDomModel, id: string): string {
function validateAndWrapCss (line 28) | function validateAndWrapCss(model: VDomModel, cssText: string, wrapperCl...
function cssTransformStyleValue (line 84) | function cssTransformStyleValue(model: VDomModel, property: string, valu...
function validateAndWrapReactStyle (line 114) | function validateAndWrapReactStyle(model: VDomModel, style: Record<strin...
function restoreVDomElems (line 138) | function restoreVDomElems(backendUpdate: VDomBackendUpdate) {
function mergeBackendUpdates (line 175) | function mergeBackendUpdates(baseUpdate: VDomBackendUpdate, nextUpdate: ...
function applyCanvasOp (line 199) | function applyCanvasOp(canvas: HTMLCanvasElement, canvasOp: VDomRefOpera...
FILE: frontend/app/view/vdom/vdom.tsx
type VDomReactTagType (line 32) | type VDomReactTagType = (props: { elem: VDomElem; model: VDomModel }) =>...
function convertVDomFunc (line 145) | function convertVDomFunc(model: VDomModel, fnDecl: VDomFunc, compId: str...
function convertElemToTag (line 170) | function convertElemToTag(elem: VDomElem, model: VDomModel): React.React...
function isObject (line 180) | function isObject(v: any): boolean {
function isArray (line 184) | function isArray(v: any): boolean {
function resolveBinding (line 188) | function resolveBinding(binding: VDomBinding, model: VDomModel): [any, s...
type GenericPropsType (line 208) | type GenericPropsType = { [key: string]: any };
function convertProps (line 211) | function convertProps(elem: VDomElem, model: VDomModel): [GenericPropsTy...
function convertChildren (line 296) | function convertChildren(elem: VDomElem, model: VDomModel): React.ReactN...
function stringSetsEqual (line 313) | function stringSetsEqual(set1: Set<string>, set2: Set<string>): boolean {
function useVDom (line 325) | function useVDom(model: VDomModel, elem: VDomElem): GenericPropsType {
function WaveMarkdown (line 345) | function WaveMarkdown({ elem, model }: { elem: VDomElem; model: VDomMode...
function StyleTag (line 358) | function StyleTag({ elem, model }: { elem: VDomElem; model: VDomModel }) {
function WaveStyle (line 372) | function WaveStyle({ src, model, onMount }: { src: string; model: VDomMo...
function VDomTag (line 410) | function VDomTag({ elem, model }: { elem: VDomElem; model: VDomModel }) {
function vdomText (line 439) | function vdomText(text: string): VDomElem {
function VDomRoot (line 463) | function VDomRoot({ model }: { model: VDomModel }) {
type VDomViewProps (line 477) | type VDomViewProps = {
function VDomInnerView (line 482) | function VDomInnerView({ blockId, model }: VDomViewProps) {
function VDomView (line 497) | function VDomView({ blockId, model }: VDomViewProps) {
FILE: frontend/app/view/waveai/waveai.tsx
type ChatMessageType (line 28) | interface ChatMessageType {
type ChatItemProps (line 38) | interface ChatItemProps {
function promptToMsg (line 43) | function promptToMsg(prompt: WaveAIPromptMessageType): ChatMessageType {
class AiWshClient (line 51) | class AiWshClient extends WshClient {
method constructor (line 55) | constructor(blockId: string, model: WaveAiModel) {
method handle_aisendmessage (line 61) | handle_aisendmessage(rh: RpcResponseHelper, data: AiMessageData) {
class WaveAiModel (line 69) | class WaveAiModel implements ViewModel {
method constructor (line 96) | constructor({ blockId, nodeModel, tabModel }: ViewModelInitType) {
method viewComponent (line 307) | get viewComponent(): ViewComponent {
method dispose (line 311) | dispose() {
method populateMessages (line 315) | async populateMessages(): Promise<void> {
method fetchAiData (line 320) | async fetchAiData(): Promise<Array<WaveAIPromptMessageType>> {
method giveFocus (line 329) | giveFocus(): boolean {
method getAiName (line 337) | getAiName(): string {
method setLocked (line 344) | setLocked(locked: boolean) {
method sendMessage (line 348) | sendMessage(text: string, user: string = "user") {
method useWaveAi (line 437) | useWaveAi() {
method clearMessages (line 443) | async clearMessages() {
method keyDownHandler (line 448) | keyDownHandler(waveEvent: WaveKeyboardEvent): boolean {
type ChatWindowProps (line 526) | interface ChatWindowProps {
type ChatInputProps (line 632) | interface ChatInputProps {
FILE: frontend/app/view/waveconfig/secretscontent.tsx
type ErrorDisplayProps (line 9) | interface ErrorDisplayProps {
type SecretListViewProps (line 78) | interface SecretListViewProps {
type AddSecretFormProps (line 117) | interface AddSecretFormProps {
type SecretDetailViewProps (line 201) | interface SecretDetailViewProps {
type SecretsContentProps (line 310) | interface SecretsContentProps {
FILE: frontend/app/view/waveconfig/waveaivisual.tsx
type WaveAIVisualContentProps (line 7) | interface WaveAIVisualContentProps {
FILE: frontend/app/view/waveconfig/waveconfig-model.ts
type ValidationResult (line 17) | type ValidationResult = { success: true } | { error: string };
type ConfigValidator (line 18) | type ConfigValidator = (parsed: any) => ValidationResult;
type ConfigFile (line 20) | type ConfigFile = {
function validateBgJson (line 35) | function validateBgJson(parsed: any): ValidationResult {
function validateAiJson (line 45) | function validateAiJson(parsed: any): ValidationResult {
function validateWaveAiJson (line 55) | function validateWaveAiJson(parsed: any): ValidationResult {
function makeConfigFiles (line 68) | function makeConfigFiles(isWindows: boolean): ConfigFile[] {
class WaveConfigViewModel (line 139) | class WaveConfigViewModel implements ViewModel {
method constructor (line 176) | constructor({ blockId, nodeModel, tabModel, waveEnv }: ViewModelInitTy...
method checkPresetsJsonExists (line 219) | async checkPresetsJsonExists() {
method initialize (line 233) | initialize() {
method getConfigFiles (line 259) | getConfigFiles(): ConfigFile[] {
method getDeprecatedConfigFiles (line 263) | getDeprecatedConfigFiles(): ConfigFile[] {
method hasChanges (line 273) | hasChanges(): boolean {
method markAsEdited (line 277) | markAsEdited() {
method loadFile (line 281) | async loadFile(file: ConfigFile) {
method saveFile (line 324) | async saveFile() {
method clearError (line 399) | clearError() {
method clearValidationError (line 403) | clearValidationError() {
method checkStorageBackend (line 407) | async checkStorageBackend() {
method refreshSecrets (line 423) | async refreshSecrets() {
method viewSecret (line 437) | async viewSecret(name: string) {
method closeSecretView (line 444) | closeSecretView() {
method showSecret (line 450) | async showSecret() {
method saveSecret (line 475) | async saveSecret() {
method deleteSecret (line 506) | async deleteSecret() {
method startAddingSecret (line 527) | startAddingSecret() {
method cancelAddingSecret (line 534) | cancelAddingSecret() {
method addNewSecret (line 541) | async addNewSecret() {
method giveFocus (line 590) | giveFocus(): boolean {
FILE: frontend/app/view/waveconfig/waveconfig.tsx
type ConfigSidebarProps (line 17) | interface ConfigSidebarProps {
FILE: frontend/app/view/waveconfig/waveconfigenv.ts
type WaveConfigEnv (line 6) | type WaveConfigEnv = WaveEnvSubset<{
FILE: frontend/app/view/webview/webview.tsx
constant USER_AGENT_IPHONE (line 29) | const USER_AGENT_IPHONE =
constant USER_AGENT_ANDROID (line 31) | const USER_AGENT_ANDROID =
function getWebviewPreloadUrl (line 36) | function getWebviewPreloadUrl(env: WebViewEnv) {
class WebViewModel (line 47) | class WebViewModel implements ViewModel {
method constructor (line 78) | constructor({ blockId, nodeModel, tabModel, waveEnv }: ViewModelInitTy...
method viewComponent (line 214) | get viewComponent(): ViewComponent {
method shouldDisableBackButton (line 222) | shouldDisableBackButton() {
method shouldDisableForwardButton (line 233) | shouldDisableForwardButton() {
method shouldDisableHomeButton (line 244) | shouldDisableHomeButton() {
method handleHome (line 252) | handleHome(e?: React.MouseEvent<HTMLDivElement, MouseEvent>) {
method setMediaPlaying (line 260) | setMediaPlaying(isPlaying: boolean) {
method handleMuteChange (line 264) | handleMuteChange(e: React.ChangeEvent<HTMLInputElement>) {
method setTypeaheadOpen (line 278) | setTypeaheadOpen(open: boolean) {
method fetchBookmarkSuggestions (line 282) | async fetchBookmarkSuggestions(
method handleUrlWrapperMouseOver (line 295) | handleUrlWrapperMouseOver(e: React.MouseEvent<HTMLDivElement, MouseEve...
method handleUrlWrapperMouseOut (line 302) | handleUrlWrapperMouseOut(e: React.MouseEvent<HTMLDivElement, MouseEven...
method handleBack (line 309) | handleBack(e?: React.MouseEvent<HTMLDivElement, MouseEvent>) {
method handleForward (line 317) | handleForward(e?: React.MouseEvent<HTMLDivElement, MouseEvent>) {
method handleRefresh (line 325) | handleRefresh(e: React.MouseEvent<HTMLDivElement, MouseEvent>) {
method handleUrlChange (line 341) | handleUrlChange(event: React.ChangeEvent<HTMLInputElement>) {
method handleKeyDown (line 345) | handleKeyDown(event: React.KeyboardEvent<HTMLInputElement>) {
method handleFocus (line 358) | handleFocus(event: React.FocusEvent<HTMLInputElement>) {
method handleBlur (line 365) | handleBlur(event: React.FocusEvent<HTMLInputElement>) {
method handleNavigate (line 374) | handleNavigate(url: string) {
method ensureUrlScheme (line 387) | ensureUrlScheme(url: string, searchTemplate: string) {
method loadUrl (line 425) | loadUrl(newUrl: string, reason: string) {
method loadUrlPromise (line 447) | loadUrlPromise(newUrl: string, reason: string): Promise<void> {
method getUrl (line 472) | getUrl() {
method setRefreshIcon (line 476) | setRefreshIcon(refreshIcon: string) {
method setIsLoading (line 480) | setIsLoading(isLoading: boolean) {
method setHomepageUrl (line 484) | async setHomepageUrl(url: string, scope: "global" | "block") {
method giveFocus (line 504) | giveFocus(): boolean {
method copyUrlToClipboard (line 529) | copyUrlToClipboard() {
method clearHistory (line 536) | clearHistory() {
method clearCookiesAndStorage (line 544) | async clearCookiesAndStorage() {
method keyDownHandler (line 555) | keyDownHandler(e: WaveKeyboardEvent): boolean {
method setZoomFactor (line 581) | setZoomFactor(factor: number | null) {
method getSettingsMenuItems (line 600) | getSettingsMenuItems(): ContextMenuItem[] {
type WebViewProps (line 806) | interface WebViewProps {
function getWebPreviewDisplayUrl (line 815) | function getWebPreviewDisplayUrl(url?: string | null): string {
function WebViewPreviewFallback (line 819) | function WebViewPreviewFallback({ url }: { url?: string | null }) {
function setBgColor (line 921) | function setBgColor() {
FILE: frontend/app/view/webview/webviewenv.ts
type WebViewEnv (line 6) | type WebViewEnv = WaveEnvSubset<{
FILE: frontend/app/waveenv/mockboundary.tsx
type MockBoundaryProps (line 7) | type MockBoundaryProps = {
function MockBoundary (line 12) | function MockBoundary({ fallback, children }: MockBoundaryProps) {
FILE: frontend/app/waveenv/waveenv.ts
type BlockMetaKeyAtomFnType (line 9) | type BlockMetaKeyAtomFnType<Keys extends keyof MetaType = keyof MetaType...
type ConnConfigKeyAtomFnType (line 14) | type ConnConfigKeyAtomFnType<Keys extends keyof ConnKeywords = keyof Con...
type SettingsKeyAtomFnType (line 19) | type SettingsKeyAtomFnType<Keys extends keyof SettingsType = keyof Setti...
type OmitNever (line 23) | type OmitNever<T> = {
type Subset (line 27) | type Subset<T, U> = OmitNever<{
type ComplexWaveEnvKeys (line 31) | type ComplexWaveEnvKeys = {
type WaveEnvMockFields (line 39) | type WaveEnvMockFields = {
type WaveEnvSubset (line 45) | type WaveEnvSubset<T> = WaveEnvMockFields &
type WaveEnv (line 55) | type WaveEnv = {
type EnvContract (line 87) | type EnvContract<T> = {
function useWaveEnv (line 91) | function useWaveEnv<T extends EnvContract<WaveEnv> = WaveEnv>(): T {
FILE: frontend/app/waveenv/waveenvimpl.ts
function makeWaveEnvImpl (line 21) | function makeWaveEnvImpl(): WaveEnv {
FILE: frontend/app/workspace/widgetfilter.ts
function shouldIncludeWidgetForWorkspace (line 4) | function shouldIncludeWidgetForWorkspace(widget: WidgetConfigType, works...
FILE: frontend/app/workspace/widgets.tsx
type WidgetsEnv (line 23) | type WidgetsEnv = WaveEnvSubset<{
function sortByDisplayOrder (line 41) | function sortByDisplayOrder(wmap: { [key: string]: WidgetConfigType }): ...
type WidgetPropsType (line 52) | type WidgetPropsType = {
function handleWidgetSelect (line 58) | async function handleWidgetSelect(widget: WidgetConfigType, env: Widgets...
function calculateGridSize (line 103) | function calculateGridSize(appCount: number): number {
function SettingsTooltipContent (line 111) | function SettingsTooltipContent({ hasConfigErrors }: { hasConfigErrors: ...
type FloatingWindowPropsType (line 126) | type FloatingWindowPropsType = {
FILE: frontend/app/workspace/workspace-layout-model.ts
function clampVTabWidth (line 28) | function clampVTabWidth(w: number): number {
function clampAIPanelWidth (line 32) | function clampAIPanelWidth(w: number, windowWidth: number): number {
class WorkspaceLayoutModel (line 38) | class WorkspaceLayoutModel {
method constructor (line 61) | private constructor() {
method getInstance (line 103) | static getInstance(): WorkspaceLayoutModel {
method getTabId (line 112) | private getTabId(): string {
method getWorkspaceId (line 116) | private getWorkspaceId(): string {
method getPanelOpenAtom (line 120) | private getPanelOpenAtom(): jotai.Atom<boolean> {
method getPanelWidthAtom (line 124) | private getPanelWidthAtom(): jotai.Atom<number> {
method getVTabBarWidthAtom (line 128) | private getVTabBarWidthAtom(): jotai.Atom<number> {
method initializeFromMeta (line 132) | private initializeFromMeta(): void {
method getResolvedAIWidth (line 156) | private getResolvedAIWidth(windowWidth: number): number {
method getResolvedVTabWidth (line 166) | private getResolvedVTabWidth(): number {
method computeLayout (line 176) | private computeLayout(windowWidth: number): { outer: number[]; inner: ...
method commitLayouts (line 199) | private commitLayouts(windowWidth: number): void {
method handleOuterPanelLayout (line 213) | handleOuterPanelLayout(sizes: number[]): void {
method handleInnerPanelLayout (line 237) | handleInnerPanelLayout(sizes: number[]): void {
method handleWindowResize (line 262) | handleWindowResize(): void {
method syncVTabWidthFromMeta (line 268) | syncVTabWidthFromMeta(): void {
method registerRefs (line 276) | registerRefs(
method syncPanelCollapse (line 297) | private syncPanelCollapse(): void {
method enableTransitions (line 316) | enableTransitions(duration: number): void {
method updateWrapperWidth (line 336) | updateWrapperWidth(): void {
method getAIPanelVisible (line 344) | getAIPanelVisible(): boolean {
method getAIPanelWidth (line 349) | getAIPanelWidth(): number {
method getLeftGroupInitialPercentage (line 355) | getLeftGroupInitialPercentage(windowWidth: number, showLeftTabBar: boo...
method getInnerVTabInitialPercentage (line 362) | getInnerVTabInitialPercentage(windowWidth: number, showLeftTabBar: boo...
method getInnerAIPanelInitialPercentage (line 372) | getInnerAIPanelInitialPercentage(windowWidth: number, showLeftTabBar: ...
method setAIPanelVisible (line 383) | setAIPanelVisible(visible: boolean, opts?: { nofocus?: boolean }): void {
method setShowLeftTabBar (line 424) | setShowLeftTabBar(showLeftTabBar: boolean): void {
FILE: frontend/builder/app-selection-modal.tsx
function CreateNewWaveApp (line 16) | function CreateNewWaveApp({ onCreateApp }: { onCreateApp: (appName: stri...
function AppSelectionModal (line 101) | function AppSelectionModal() {
FILE: frontend/builder/builder-app.tsx
type BuilderAppProps (line 17) | type BuilderAppProps = {
function BuilderAppInner (line 34) | function BuilderAppInner() {
function BuilderApp (line 62) | function BuilderApp({ initOpts, onFirstRender }: BuilderAppProps) {
FILE: frontend/builder/builder-apppanel.tsx
type TabButtonProps (line 51) | type TabButtonProps = {
FILE: frontend/builder/builder-buildpanel.tsx
function handleBuildPanelContextMenu (line 13) | function handleBuildPanelContextMenu(e: React.MouseEvent, selectedText: ...
FILE: frontend/builder/store/builder-apppanel-model.ts
type TabType (line 14) | type TabType = "preview" | "files" | "code" | "secrets" | "configdata";
type EnvVar (line 16) | type EnvVar = {
class BuilderAppPanelModel (line 22) | class BuilderAppPanelModel {
method constructor (line 43) | private constructor() {
method getInstance (line 52) | static getInstance(): BuilderAppPanelModel {
method setActiveTab (line 59) | setActiveTab(tab: TabType) {
method getActiveTab (line 63) | getActiveTab(): TabType {
method setCodeContent (line 67) | setCodeContent(content: string) {
method initialize (line 71) | async initialize() {
method updateSecretsLatch (line 117) | updateSecretsLatch(status: BuilderStatusData) {
method updateSecretBindings (line 125) | updateSecretBindings(newBindings: { [key: string]: string }) {
method loadEnvVars (line 135) | async loadEnvVars(builderId: string) {
method saveEnvVars (line 149) | async saveEnvVars(builderId: string) {
method getEnvVarIndexAtom (line 176) | getEnvVarIndexAtom(index: number): Atom<EnvVar | null> {
method addEnvVar (line 186) | addEnvVar() {
method removeEnvVar (line 192) | removeEnvVar(index: number) {
method setEnvVarAtIndex (line 199) | setEnvVarAtIndex(index: number, envVar: EnvVar, dirty: boolean) {
method startBuilder (line 209) | async startBuilder() {
method restartBuilder (line 221) | async restartBuilder() {
method switchBuilderApp (line 226) | async switchBuilderApp() {
method loadAppFile (line 244) | async loadAppFile(appId: string) {
method saveAppFile (line 277) | async saveAppFile(appId: string) {
method clearError (line 296) | clearError() {
method giveFocus (line 300) | giveFocus() {
method setFocusElemRef (line 309) | setFocusElemRef(ref: HTMLInputElement | null) {
method setMonacoEditorRef (line 313) | setMonacoEditorRef(ref: MonacoTypes.editor.IStandaloneCodeEditor | nul...
method dispose (line 317) | dispose() {
FILE: frontend/builder/store/builder-buildpanel-model.ts
class BuilderBuildPanelModel (line 11) | class BuilderBuildPanelModel {
method constructor (line 19) | private constructor() {}
method getInstance (line 21) | static getInstance(): BuilderBuildPanelModel {
method initialize (line 28) | async initialize() {
method clearOutput (line 62) | clearOutput() {
method dispose (line 66) | dispose() {
FILE: frontend/builder/store/builder-focusmanager.ts
type BuilderFocusType (line 7) | type BuilderFocusType = "waveai" | "app";
class BuilderFocusManager (line 9) | class BuilderFocusManager {
method constructor (line 14) | private constructor() {}
method getInstance (line 16) | static getInstance(): BuilderFocusManager {
method setWaveAIFocused (line 23) | setWaveAIFocused() {
method setAppFocused (line 27) | setAppFocused() {
method getFocusType (line 31) | getFocusType(): BuilderFocusType {
FILE: frontend/builder/tabs/builder-configdatatab.tsx
type ConfigDataState (line 61) | type ConfigDataState = {
FILE: frontend/builder/tabs/builder-filestab.tsx
type FileEntry (line 18) | type FileEntry = {
FILE: frontend/builder/tabs/builder-secrettab.tsx
type SecretRowProps (line 16) | type SecretRowProps = {
type SetSecretDialogProps (line 74) | type SetSecretDialogProps = {
FILE: frontend/builder/utils/builder-focus-utils.ts
function findBuilderAppPanel (line 4) | function findBuilderAppPanel(element: HTMLElement): HTMLElement | null {
function builderAppHasFocusWithin (line 15) | function builderAppHasFocusWithin(focusTarget?: Element | null): boolean {
function builderAppHasSelection (line 44) | function builderAppHasSelection(): boolean {
FILE: frontend/layout/lib/TileLayout.tsx
type TileLayoutProps (line 36) | interface TileLayoutProps {
function TileLayoutComponent (line 57) | function TileLayoutComponent({ tabAtom, contents, getCursorPoint }: Tile...
function NodeBackdrops (line 139) | function NodeBackdrops({ layoutModel }: { layoutModel: LayoutModel }) {
type DisplayNodesWrapperProps (line 194) | interface DisplayNodesWrapperProps {
type DisplayNodeProps (line 213) | interface DisplayNodeProps {
type OverlayNodeWrapperProps (line 321) | interface OverlayNodeWrapperProps {
type OverlayNodeProps (line 344) | interface OverlayNodeProps {
type ResizeHandleWrapperProps (line 410) | interface ResizeHandleWrapperProps {
type ResizeHandleComponentProps (line 422) | interface ResizeHandleComponentProps {
function onPointerDown (line 446) | function onPointerDown(event: React.PointerEvent<HTMLDivElement>) {
function onPointerCapture (line 451) | function onPointerCapture(event: React.PointerEvent<HTMLDivElement>) {
type PlaceholderProps (line 479) | interface PlaceholderProps {
FILE: frontend/layout/lib/layoutAtom.ts
function getLayoutStateAtomFromTab (line 7) | function getLayoutStateAtomFromTab(tabAtom: Atom<Tab>, get: Getter): Ato...
FILE: frontend/layout/lib/layoutModel.ts
type ResizeContext (line 61) | interface ResizeContext {
class LayoutModel (line 76) | class LayoutModel {
method constructor (line 240) | constructor(
method initializeFromWaveObject (line 357) | private initializeFromWaveObject() {
method onBackendUpdate (line 379) | onBackendUpdate() {
method processPendingBackendActions (line 387) | private async processPendingBackendActions() {
method cleanupOrphanedBlocks (line 411) | private async cleanupOrphanedBlocks() {
method handleBackendAction (line 435) | private async handleBackendAction(action: LayoutActionData) {
method persistToBackend (line 576) | private persistToBackend() {
method registerTileLayout (line 600) | registerTileLayout(contents: TileLayoutContents) {
method treeReducer (line 615) | treeReducer(action: LayoutTreeAction, setState = true) {
method onTreeStateAtomUpdated (line 708) | async onTreeStateAtomUpdated(force = false) {
method updateTree (line 724) | updateTree(balanceTree = true) {
method updateTreeHelper (line 785) | private updateTreeHelper(
method focusedNodeId (line 900) | get focusedNodeId(): string {
method validateFocusedNode (line 908) | private validateFocusedNode(leafOrder: LeafOrderEntry[]) {
method validateMagnifiedNode (line 936) | private validateMagnifiedNode(leafOrder: LeafOrderEntry[], addlProps: ...
method getPlaceholderTransform (line 954) | private getPlaceholderTransform(pendingAction: LayoutTreeAction): CSSP...
method getNodeModel (line 1042) | getNodeModel(node: LayoutNode): NodeModel {
method cleanupNodeModels (line 1104) | private cleanupNodeModels(leafOrder: LeafOrderEntry[]) {
method switchNodeFocusInDirection (line 1117) | switchNodeFocusInDirection(direction: NavigateDirection, inWaveAI: boo...
method switchNodeFocusByBlockNum (line 1216) | switchNodeFocusByBlockNum(newBlockNum: number) {
method focusNode (line 1230) | focusNode(nodeId: string) {
method focusFirstNode (line 1250) | focusFirstNode() {
method getFirstBlockId (line 1257) | getFirstBlockId(): string | undefined {
method magnifyNodeToggle (line 1269) | magnifyNodeToggle(nodeId: string, setState = true) {
method closeNode (line 1285) | async closeNode(nodeId: string) {
method closeFocusedNode (line 1317) | async closeFocusedNode() {
method newEphemeralNode (line 1321) | newEphemeralNode(blockId: string) {
method addEphemeralNodeToLayout (line 1338) | addEphemeralNodeToLayout() {
method updateEphemeralNodeProps (line 1356) | updateEphemeralNodeProps(
method onDrop (line 1385) | onDrop() {
method onResizeMove (line 1415) | onResizeMove(resizeHandle: ResizeHandleProps, x: number, y: number) {
method onResizeEnd (line 1483) | onResizeEnd() {
method getNodeByBlockId (line 1495) | getNodeByBlockId(blockId: string): LayoutNode {
method getNodeAdditionalPropertiesAtom (line 1509) | getNodeAdditionalPropertiesAtom(nodeId: string): Atom<LayoutNodeAdditi...
method getNodeAdditionalPropertiesById (line 1521) | getNodeAdditionalPropertiesById(nodeId: string): LayoutNodeAdditionalP...
method getNodeAdditionalProperties (line 1531) | getNodeAdditionalProperties(node: LayoutNode): LayoutNodeAdditionalPro...
method getNodeTransformById (line 1540) | getNodeTransformById(nodeId: string): CSSProperties {
method getNodeTransform (line 1549) | getNodeTransform(node: LayoutNode): CSSProperties {
method getNodeRectById (line 1558) | getNodeRectById(nodeId: string): Dimensions {
method getNodeRect (line 1567) | getNodeRect(node: LayoutNode): Dimensions {
function getLeafOrder (line 1572) | function getLeafOrder(
FILE: frontend/layout/lib/layoutModelHooks.ts
function getLayoutModelForTab (line 15) | function getLayoutModelForTab(tabAtom: Atom<Tab>): LayoutModel {
function getLayoutModelForTabById (line 39) | function getLayoutModelForTabById(tabId: string) {
function getLayoutModelForStaticTab (line 45) | function getLayoutModelForStaticTab() {
function deleteLayoutModelForTab (line 50) | function deleteLayoutModelForTab(tabId: string) {
function useLayoutModel (line 54) | function useLayoutModel(tabAtom: Atom<Tab>): LayoutModel {
function useTileLayout (line 58) | function useTileLayout(tabAtom: Atom<Tab>, tileContent: TileLayoutConten...
function useNodeModel (line 72) | function useNodeModel(layoutModel: LayoutModel, layoutNode: LayoutNode):...
function useDebouncedNodeInnerRect (line 76) | function useDebouncedNodeInnerRect(nodeModel: NodeModel): CSSProperties {
FILE: frontend/layout/lib/layoutNode.ts
function newLayoutNode (line 16) | function newLayoutNode(
function addChildAt (line 43) | function addChildAt(node: LayoutNode, idx: number, ...children: LayoutNo...
function addIntermediateNode (line 75) | function addIntermediateNode(node: LayoutNode): LayoutNode {
function removeChild (line 100) | function removeChild(parent: LayoutNode, childToRemove: LayoutNode, star...
function findNode (line 113) | function findNode(node: LayoutNode, id: string): LayoutNode | undefined {
function findParent (line 130) | function findParent(node: LayoutNode, id: string): LayoutNode | undefined {
function validateNode (line 145) | function validateNode(node: LayoutNode): boolean {
function walkNodes (line 164) | function walkNodes(
function balanceNode (line 182) | function balanceNode(
function findNextInsertLocation (line 227) | function findNextInsertLocation(
function findInsertLocationFromIndexArr (line 241) | function findInsertLocationFromIndexArr(
function findNextInsertLocationHelper (line 263) | function findNextInsertLocationHelper(
function totalChildrenSize (line 283) | function totalChildrenSize(node: LayoutNode): number {
FILE: frontend/layout/lib/layoutTree.ts
constant DEFAULT_MAX_CHILDREN (line 35) | const DEFAULT_MAX_CHILDREN = 5;
function computeMoveNode (line 43) | function computeMoveNode(layoutState: LayoutTreeState, computeInsertActi...
function moveNode (line 230) | function moveNode(layoutState: LayoutTreeState, action: LayoutTreeMoveNo...
function insertNode (line 279) | function insertNode(layoutState: LayoutTreeState, action: LayoutTreeInse...
function insertNodeAtIndex (line 299) | function insertNodeAtIndex(layoutState: LayoutTreeState, action: LayoutT...
function swapNode (line 323) | function swapNode(layoutState: LayoutTreeState, action: LayoutTreeSwapNo...
function deleteNode (line 354) | function deleteNode(layoutState: LayoutTreeState, action: LayoutTreeDele...
function resizeNode (line 379) | function resizeNode(layoutState: LayoutTreeState, action: LayoutTreeResi...
function focusNode (line 393) | function focusNode(layoutState: LayoutTreeState, action: LayoutTreeFocus...
function magnifyNodeToggle (line 402) | function magnifyNodeToggle(layoutState: LayoutTreeState, action: LayoutT...
function clearTree (line 419) | function clearTree(layoutState: LayoutTreeState) {
function replaceNode (line 426) | function replaceNode(layoutState: LayoutTreeState, action: LayoutTreeRep...
function splitHorizontal (line 454) | function splitHorizontal(layoutState: LayoutTreeState, action: LayoutTre...
function splitVertical (line 497) | function splitVertical(layoutState: LayoutTreeState, action: LayoutTreeS...
FILE: frontend/layout/lib/nodeRefMap.ts
class NodeRefMap (line 4) | class NodeRefMap {
method set (line 8) | set(id: string, ref: React.RefObject<HTMLDivElement>) {
method delete (line 13) | delete(id: string) {
method get (line 20) | get(id: string): React.RefObject<HTMLDivElement> {
FILE: frontend/layout/lib/types.ts
type NavigateDirection (line 7) | enum NavigateDirection {
function navigateDirectionToString (line 14) | function navigateDirectionToString(dir: NavigateDirection): string {
type DropDirection (line 29) | enum DropDirection {
type FlexDirection (line 41) | enum FlexDirection {
type MoveOperation (line 49) | type MoveOperation = {
type LayoutTreeActionType (line 74) | enum LayoutTreeActionType {
type LayoutTreeAction (line 96) | interface LayoutTreeAction {
type LayoutTreeComputeMoveNodeAction (line 106) | interface LayoutTreeComputeMoveNodeAction extends LayoutTreeAction {
type LayoutTreeMoveNodeAction (line 118) | interface LayoutTreeMoveNodeAction extends LayoutTreeAction, MoveOperati...
type LayoutTreeSwapNodeAction (line 126) | interface LayoutTreeSwapNodeAction extends LayoutTreeAction {
type InsertNodeOperation (line 139) | interface InsertNodeOperation {
type LayoutTreeInsertNodeAction (line 158) | interface LayoutTreeInsertNodeAction extends LayoutTreeAction, InsertNod...
type LayoutTreeInsertNodeAtIndexAction (line 165) | interface LayoutTreeInsertNodeAtIndexAction extends LayoutTreeAction, In...
type LayoutTreeDeleteNodeAction (line 177) | interface LayoutTreeDeleteNodeAction extends LayoutTreeAction {
type LayoutTreeSetPendingAction (line 185) | interface LayoutTreeSetPendingAction extends LayoutTreeAction {
type LayoutTreeCommitPendingAction (line 197) | interface LayoutTreeCommitPendingAction extends LayoutTreeAction {
type LayoutTreeClearPendingAction (line 204) | interface LayoutTreeClearPendingAction extends LayoutTreeAction {
type LayoutTreeReplaceNodeAction (line 209) | interface LayoutTreeReplaceNodeAction extends LayoutTreeAction {
type LayoutTreeSplitHorizontalAction (line 219) | interface LayoutTreeSplitHorizontalAction extends LayoutTreeAction {
type LayoutTreeSplitVerticalAction (line 228) | interface LayoutTreeSplitVerticalAction extends LayoutTreeAction {
type ResizeNodeOperation (line 239) | interface ResizeNodeOperation {
type LayoutTreeResizeNodeAction (line 253) | interface LayoutTreeResizeNodeAction extends LayoutTreeAction {
type LayoutTreeFocusNodeAction (line 265) | interface LayoutTreeFocusNodeAction extends LayoutTreeAction {
type LayoutTreeMagnifyNodeToggleAction (line 277) | interface LayoutTreeMagnifyNodeToggleAction extends LayoutTreeAction {
type LayoutTreeClearTreeAction (line 289) | interface LayoutTreeClearTreeAction extends LayoutTreeAction {
type LayoutNode (line 296) | interface LayoutNode {
type LayoutTreeStateSetter (line 304) | type LayoutTreeStateSetter = (value: LayoutState) => void;
type LayoutTreeState (line 306) | type LayoutTreeState = {
type WritableLayoutTreeStateAtom (line 317) | type WritableLayoutTreeStateAtom = WritableAtom<LayoutTreeState, [value:...
type ContentRenderer (line 319) | type ContentRenderer = (nodeModel: NodeModel) => React.ReactNode;
type PreviewRenderer (line 321) | type PreviewRenderer = (nodeModel: NodeModel) => React.ReactElement;
type TileLayoutContents (line 329) | interface TileLayoutContents {
type ResizeHandleProps (line 365) | interface ResizeHandleProps {
type LayoutNodeAdditionalProps (line 374) | interface LayoutNodeAdditionalProps {
type NodeModel (line 382) | interface NodeModel {
type NavigationResult (line 408) | interface NavigationResult {
FILE: frontend/layout/lib/utils.ts
function reverseFlexDirection (line 8) | function reverseFlexDirection(flexDirection: FlexDirection): FlexDirecti...
function determineDropDirection (line 12) | function determineDropDirection(dimensions?: Dimensions, offset?: XYCoor...
function setTransform (line 61) | function setTransform(
function getCenter (line 84) | function getCenter(dimensions: Dimensions): Point {
function navigateDirectionToOffset (line 91) | function navigateDirectionToOffset(direction: NavigateDirection): Point {
FILE: frontend/layout/tests/model.ts
function newLayoutTreeState (line 6) | function newLayoutTreeState(rootNode: LayoutNode): LayoutTreeState {
FILE: frontend/preview/mock/mock-node-model.ts
type MockNodeModelOpts (line 8) | type MockNodeModelOpts = {
function makeMockNodeModel (line 15) | function makeMockNodeModel(opts: MockNodeModelOpts): NodeModel {
FILE: frontend/preview/mock/mockfilesystem.ts
type MockFsEntry (line 33) | type MockFsEntry = {
type MockFsEntryInput (line 47) | type MockFsEntryInput = {
type MockFilesystem (line 55) | type MockFilesystem = {
function normalizeMockPath (line 68) | function normalizeMockPath(path: string, basePath = MockHomePath): string {
function getDirName (line 100) | function getDirName(path: string): string {
function getBaseName (line 111) | function getBaseName(path: string): string {
function getMimeType (line 119) | function getMimeType(path: string, isdir: boolean): string {
function makeContentBytes (line 165) | function makeContentBytes(content: string | Uint8Array): Uint8Array {
function makeMockFsInput (line 172) | function makeMockFsInput(path: string, content?: string | Uint8Array, mi...
function createMockFilesystemEntries (line 176) | function createMockFilesystemEntries(): MockFsEntryInput[] {
function buildEntries (line 326) | function buildEntries(): Map<string, MockFsEntry> {
function toFileInfo (line 375) | function toFileInfo(entry: MockFsEntry): FileInfo {
function makeNotFoundInfo (line 390) | function makeNotFoundInfo(path: string): FileInfo {
function sliceEntries (line 401) | function sliceEntries(entries: FileInfo[], opts?: FileListOpts): FileInf...
function joinPaths (line 411) | function joinPaths(paths: string[]): string {
function getReadRange (line 422) | function getReadRange(data: FileData, size: number): { offset: number; e...
function makeMockFilesystem (line 428) | function makeMockFilesystem(): MockFilesystem {
FILE: frontend/preview/mock/mockwaveenv.ts
type RpcHandlerType (line 50) | type RpcHandlerType = (...args: any[]) => Promise<any>;
type RpcStreamHandlerType (line 51) | type RpcStreamHandlerType = (...args: any[]) => AsyncGenerator<any, void...
type RpcOverrides (line 53) | type RpcOverrides = {
type RpcStreamOverrides (line 57) | type RpcStreamOverrides = {
type ServiceOverrides (line 61) | type ServiceOverrides = {
type MockEnv (line 67) | type MockEnv = {
type MockWaveEnv (line 83) | type MockWaveEnv = WaveEnv & {
function mergeRecords (line 89) | function mergeRecords<T>(base: Record<string, T>, overrides: Record<stri...
function mergeMockEnv (line 96) | function mergeMockEnv(base: MockEnv, overrides: MockEnv): MockEnv {
function makeMockSettingsKeyAtom (line 127) | function makeMockSettingsKeyAtom(settingsAtom: Atom<SettingsType>): Wave...
function makeMockGlobalAtoms (line 140) | function makeMockGlobalAtoms(
type MockWosFns (line 199) | type MockWosFns = {
function makeMockRpc (line 206) | function makeMockRpc(
function applyMockEnvOverrides (line 369) | function applyMockEnvOverrides(env: WaveEnv, newOverrides: MockEnv): Moc...
function makeMockWaveEnv (line 375) | function makeMockWaveEnv(mockEnv?: MockEnv): MockWaveEnv {
FILE: frontend/preview/mock/preview-electron-api.ts
function installPreviewElectronApi (line 64) | function installPreviewElectronApi() {
FILE: frontend/preview/mock/tabbar-mock.tsx
type PreviewTabEntry (line 11) | type PreviewTabEntry = {
function badgeBlockId (line 18) | function badgeBlockId(tabId: string, badgeId: string): string {
function makeTabWaveObj (line 22) | function makeTabWaveObj(tab: PreviewTabEntry): Tab {
function makeMockBadgeEvents (line 34) | function makeMockBadgeEvents(): BadgeEvent[] {
function makeMockWorkspace (line 80) | function makeMockWorkspace(tabIds: string[]): Workspace {
function makeTabBarMockEnv (line 92) | function makeTabBarMockEnv(
type TabBarMockEnvProviderProps (line 163) | type TabBarMockEnvProviderProps = {
function TabBarMockEnvProvider (line 167) | function TabBarMockEnvProvider({ children }: TabBarMockEnvProviderProps) {
FILE: frontend/preview/mock/use-rpc-override.ts
function useRpcOverride (line 8) | function useRpcOverride<K extends keyof RpcOverrides>(command: K, handle...
function useRpcStreamOverride (line 17) | function useRpcStreamOverride<K extends keyof RpcStreamOverrides>(comman...
FILE: frontend/preview/preview-contextmenu.tsx
type PreviewContextMenuState (line 17) | type PreviewContextMenuState = {
type PreviewContextMenuPanelProps (line 23) | type PreviewContextMenuPanelProps = {
type PreviewContextMenuItemProps (line 35) | type PreviewContextMenuItemProps = {
function makeVirtualElement (line 48) | function makeVirtualElement(x: number, y: number): VirtualElement {
function isPathOpen (line 66) | function isPathOpen(openPath: number[], path: number[]): boolean {
function getVisibleItems (line 73) | function getVisibleItems(items: ContextMenuItem[]): ContextMenuItem[] {
function activateItem (line 77) | function activateItem(item: ContextMenuItem, closeMenu: () => void): void {
function getPreviewContextMenuItemId (line 82) | function getPreviewContextMenuItemId(item: ContextMenuItem): string {
function showPreviewContextMenu (line 243) | function showPreviewContextMenu(menu: ContextMenuItem[], e: React.MouseE...
FILE: frontend/preview/preview.tsx
function pathToKey (line 35) | function pathToKey(path: string): string {
function PreviewIndex (line 50) | function PreviewIndex() {
function PreviewHeader (line 78) | function PreviewHeader({ previewName }: { previewName: string }) {
function PreviewRoot (line 96) | function PreviewRoot() {
function PreviewApp (line 110) | function PreviewApp() {
function initPreview (line 146) | function initPreview() {
FILE: frontend/preview/previews/aifilediff.preview-util.ts
function makeMockAiFileDiffResponse (line 29) | function makeMockAiFileDiffResponse(
FILE: frontend/preview/previews/aifilediff.preview.tsx
function AiFileDiffPreview (line 18) | function AiFileDiffPreview() {
FILE: frontend/preview/previews/modal-about.preview.tsx
function AboutModalPreview (line 6) | function AboutModalPreview() {
FILE: frontend/preview/previews/onboarding.preview.tsx
function OnboardingModalWrapper (line 13) | function OnboardingModalWrapper({ width, children }: { width: string; ch...
function OnboardingFeaturesV (line 22) | function OnboardingFeaturesV() {
function UpgradeOnboardingPatchV (line 48) | function UpgradeOnboardingPatchV() {
function UpgradeOnboardingMinorV (line 82) | function UpgradeOnboardingMinorV() {
function StarAskV (line 91) | function StarAskV() {
function OnboardingPreview (line 100) | function OnboardingPreview() {
FILE: frontend/preview/previews/sysinfo.preview-util.ts
function clamp (line 10) | function clamp(value: number, minValue: number, maxValue: number): number {
function round1 (line 14) | function round1(value: number): number {
function makeMockSysinfoEvent (line 18) | function makeMockSysinfoEvent(
function makeMockSysinfoHistory (line 49) | function makeMockSysinfoHistory(
FILE: frontend/preview/previews/sysinfo.preview.tsx
function SysinfoPreview (line 19) | function SysinfoPreview() {
FILE: frontend/preview/previews/tab.preview.tsx
constant TAB_WIDTH (line 7) | const TAB_WIDTH = 130;
constant TAB_HEIGHT (line 8) | const TAB_HEIGHT = 26;
type PreviewTabEntry (line 10) | interface PreviewTabEntry {
function TabPreview (line 60) | function TabPreview() {
FILE: frontend/preview/previews/tabbar.preview.tsx
function TabBarPreview (line 19) | function TabBarPreview() {
type TabBarPreviewInnerProps (line 33) | type TabBarPreviewInnerProps = {
function TabBarPreviewInner (line 38) | function TabBarPreviewInner({ platform, setPlatform }: TabBarPreviewInne...
FILE: frontend/preview/previews/treeview.preview.tsx
function TreeViewPreview (line 52) | function TreeViewPreview() {
FILE: frontend/preview/previews/vtabbar.preview.tsx
function VTabBarPreview (line 14) | function VTabBarPreview() {
type VTabBarPreviewInnerProps (line 28) | type VTabBarPreviewInnerProps = {
function VTabBarPreviewInner (line 33) | function VTabBarPreviewInner({ platform, setPlatform }: VTabBarPreviewIn...
FILE: frontend/preview/previews/web.preview.tsx
function WebPreview (line 11) | function WebPreview() {
FILE: frontend/preview/previews/widgets.preview.tsx
function makeMockApp (line 15) | function makeMockApp(name: string, icon: string, iconcolor: string): App...
function makeWidgetsEnv (line 90) | function makeWidgetsEnv(
function WidgetsScenario (line 108) | function WidgetsScenario({
function WidgetsResizable (line 147) | function WidgetsResizable({ isDev }: { isDev: boolean }) {
function PreviewControls (line 183) | function PreviewControls() {
function WidgetsPreview (line 218) | function WidgetsPreview() {
FILE: frontend/types/custom.d.ts
type GlobalAtomsType (line 10) | type GlobalAtomsType = {
type ThrottledValueAtom (line 34) | type ThrottledValueAtom<T> = jotai.WritableAtom<T, [update: jotai.SetSta...
type AtomWithThrottle (line 36) | type AtomWithThrottle<T> = {
type DebouncedValueAtom (line 41) | type DebouncedValueAtom<T> = jotai.WritableAtom<T, [update: jotai.SetSta...
type AtomWithDebounce (line 43) | type AtomWithDebounce<T> = {
type SplitAtom (line 48) | type SplitAtom<Item> = Atom<Atom<Item>[]>;
type WritableSplitAtom (line 49) | type WritableSplitAtom<Item> = WritableAtom<PrimitiveAtom<Item>[], [Spli...
type TabLayoutData (line 51) | type TabLayoutData = {
type GlobalInitOptions (line 55) | type GlobalInitOptions = {
type WaveInitOpts (line 66) | type WaveInitOpts = {
type BuilderInitOpts (line 74) | type BuilderInitOpts = {
type ElectronApi (line 80) | type ElectronApi = {
type ElectronContextMenuItem (line 140) | type ElectronContextMenuItem = {
type ContextMenuItem (line 152) | type ContextMenuItem
Condensed preview — 969 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (6,726K chars).
[
{
"path": ".editorconfig",
"chars": 206,
"preview": "root = true\n\n[*]\nend_of_line = lf\ninsert_final_newline = true\n\n[*.{js,jsx,ts,tsx,cjs,json,yml,yaml,css,less,scss}]\nchars"
},
{
"path": ".gitattributes",
"chars": 18,
"preview": "* text=auto eol=lf"
},
{
"path": ".github/FUNDING.yml",
"chars": 20,
"preview": "github: wavetermdev\n"
},
{
"path": ".github/ISSUE_TEMPLATE/bug-report.yml",
"chars": 2856,
"preview": "name: 🐞 Bug Report\ndescription: Create a bug report to help us improve.\ntitle: \"[Bug]: \"\nlabels: [\"bug\", \"triage\"]\nbody:"
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 536,
"preview": "blank_issues_enabled: true\ncontact_links:\n - name: General Question\n url: https://github.com/wavetermdev/waveter"
},
{
"path": ".github/ISSUE_TEMPLATE/feature-request.yml",
"chars": 1061,
"preview": "name: 🚀 Feature Request / Idea\ndescription: Suggest a new idea for this project.\ntitle: \"[Feature]: \"\nlabels: [\"enhancem"
},
{
"path": ".github/copilot-instructions.md",
"chars": 4474,
"preview": "# Wave Terminal — Copilot Instructions\n\n## Project Rules\n\n- See the overview of the project in `.kilocode/rules/overview"
},
{
"path": ".github/dependabot.yml",
"chars": 4462,
"preview": "version: 2\nupdates:\n - package-ecosystem: \"npm\"\n directory: \"/\"\n schedule:\n interval: \"weekly\"\n "
},
{
"path": ".github/workflows/build-helper.yml",
"chars": 10417,
"preview": "# Build Helper workflow - Builds, signs, and packages binaries for each supported platform, then uploads to a staging bu"
},
{
"path": ".github/workflows/bump-version.yml",
"chars": 3738,
"preview": "# Workflow to manage bumping the package version and pushing it to the target branch with a new tag.\n# This workflow use"
},
{
"path": ".github/workflows/codeql.yml",
"chars": 5508,
"preview": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# Y"
},
{
"path": ".github/workflows/copilot-setup-steps.yml",
"chars": 2147,
"preview": "name: Copilot Setup Steps\n\non:\n workflow_dispatch:\n push:\n paths: [.github/workflows/copilot-setup-steps.ym"
},
{
"path": ".github/workflows/deploy-docsite.yml",
"chars": 2623,
"preview": "name: Docsite CI/CD\n\nrun-name: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && 'Build and Deploy' "
},
{
"path": ".github/workflows/merge-gatekeeper.yml",
"chars": 1145,
"preview": "---\nname: Merge Gatekeeper\n\non:\n pull_request_target:\n branches:\n - main\n - master\n "
},
{
"path": ".github/workflows/publish-release.yml",
"chars": 3765,
"preview": "# Workflow to copy artifacts from the staging bucket to the release bucket when a new GitHub Release is published.\n\nname"
},
{
"path": ".github/workflows/testdriver-build.yml",
"chars": 2596,
"preview": "name: TestDriver.ai Build\n\non:\n push:\n branches:\n - main\n tags:\n - \"v[0-9]+.[0-9]"
},
{
"path": ".github/workflows/testdriver.yml",
"chars": 5892,
"preview": "name: TestDriver.ai Run\n\non:\n workflow_run:\n workflows: [\"TestDriver.ai Build\"]\n types:\n - c"
},
{
"path": ".gitignore",
"chars": 385,
"preview": ".task\nfrontend/dist\ndist/\ndist-dev/\nfrontend/node_modules\nnode_modules/\nfrontend/bindings\nbindings/\n*.log\nbin/\n*.dmg\n*.e"
},
{
"path": ".golangci.yml",
"chars": 156,
"preview": "version: 2\n\nlinters:\n disable:\n - unused\n\nissues:\n exclude-rules:\n - linters:\n - unused"
},
{
"path": ".kilocode/rules/overview.md",
"chars": 6649,
"preview": "# Wave Terminal - High Level Architecture Overview\n\n## Project Description\n\nWave Terminal is an open-source AI-native te"
},
{
"path": ".kilocode/rules/rules.md",
"chars": 11956,
"preview": "Wave Terminal is a modern terminal which provides graphical blocks, dynamic layout, workspaces, and SSH connection manag"
},
{
"path": ".kilocode/skills/add-config/SKILL.md",
"chars": 14361,
"preview": "---\nname: add-config\ndescription: Guide for adding new configuration settings to Wave Terminal. Use when adding a new se"
},
{
"path": ".kilocode/skills/add-rpc/SKILL.md",
"chars": 12604,
"preview": "---\nname: add-rpc\ndescription: Guide for adding new RPC calls to Wave Terminal. Use when implementing new RPC commands, "
},
{
"path": ".kilocode/skills/add-wshcmd/SKILL.md",
"chars": 21935,
"preview": "---\nname: add-wshcmd\ndescription: Guide for adding new wsh commands to Wave Terminal. Use when implementing new CLI comm"
},
{
"path": ".kilocode/skills/context-menu/SKILL.md",
"chars": 3841,
"preview": "---\nname: context-menu\ndescription: Guide for creating and displaying context menus in Wave Terminal. Use when implement"
},
{
"path": ".kilocode/skills/create-view/SKILL.md",
"chars": 14327,
"preview": "---\nname: create-view\ndescription: Guide for implementing a new view type in Wave Terminal. Use when creating a new view"
},
{
"path": ".kilocode/skills/electron-api/SKILL.md",
"chars": 4629,
"preview": "---\nname: electron-api\ndescription: Guide for adding new Electron APIs to Wave Terminal. Use when implementing new front"
},
{
"path": ".kilocode/skills/waveenv/SKILL.md",
"chars": 6562,
"preview": "---\nname: waveenv\ndescription: Guide for creating WaveEnv narrowings in Wave Terminal. Use when writing a named subset t"
},
{
"path": ".kilocode/skills/wps-events/SKILL.md",
"chars": 9418,
"preview": "---\nname: wps-events\ndescription: Guide for working with Wave Terminal's WPS (Wave PubSub) event system. Use when implem"
},
{
"path": ".prettierignore",
"chars": 118,
"preview": "build\nbin\n.git\nfrontend/dist\nfrontend/node_modules\n*.min.*\nfrontend/app/store/services.ts\nfrontend/types/gotypes.d.ts\n"
},
{
"path": ".roo/rules/overview.md",
"chars": 6649,
"preview": "# Wave Terminal - High Level Architecture Overview\n\n## Project Description\n\nWave Terminal is an open-source AI-native te"
},
{
"path": ".roo/rules/rules.md",
"chars": 11938,
"preview": "Wave Terminal is a modern terminal which provides graphical blocks, dynamic layout, workspaces, and SSH connection manag"
},
{
"path": ".vscode/extensions.json",
"chars": 178,
"preview": "{\n \"recommendations\": [\n \"esbenp.prettier-vscode\",\n \"golang.go\",\n \"dbaeumer.vscode-eslint\",\n "
},
{
"path": ".vscode/settings.json",
"chars": 1882,
"preview": "{\n \"editor.formatOnSave\": true,\n \"editor.detectIndentation\": false,\n \"editor.formatOnPaste\": true,\n \"editor."
},
{
"path": ".zed/settings.json",
"chars": 1922,
"preview": "{\n \"format_on_save\": \"on\",\n \"languages\": {\n \"JavaScript\": {\n \"formatter\": {\n \"ext"
},
{
"path": "ACKNOWLEDGEMENTS.md",
"chars": 633,
"preview": "# Open-Source Acknowledgements\n\nWe make use of many amazing open-source projects to build Wave Terminal. We automaticall"
},
{
"path": "BUILD.md",
"chars": 3906,
"preview": "# Building Wave Terminal\n\nThese instructions are for setting up dependencies and building Wave Terminal from source on m"
},
{
"path": "CNAME",
"chars": 17,
"preview": "docs.waveterm.dev"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 5220,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participa"
},
{
"path": "CONTRIBUTING.md",
"chars": 4771,
"preview": "# Contributing to Wave Terminal\n\nWave Terminal is an opinionated project with a single active maintainer. Contributions "
},
{
"path": "LICENSE",
"chars": 10937,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "NOTICE",
"chars": 34,
"preview": "Copyright 2025, Command Line Inc.\n"
},
{
"path": "README.ko.md",
"chars": 3719,
"preview": "<p align=\"center\">\n <a href=\"https://www.waveterm.dev\">\n\t<picture>\n\t\t<source media=\"(prefers-color-scheme: dark)\" srcse"
},
{
"path": "README.md",
"chars": 5425,
"preview": "<p align=\"center\">\n <a href=\"https://www.waveterm.dev\">\n\t<picture>\n\t\t<source media=\"(prefers-color-scheme: dark)\" srcse"
},
{
"path": "RELEASES.md",
"chars": 8704,
"preview": "# Building for release\n\n## Step-by-step guide\n\n1. Go to the [Actions tab](https://github.com/wavetermdev/waveterm/action"
},
{
"path": "ROADMAP.md",
"chars": 3006,
"preview": "# Wave Terminal Roadmap\n\nThis roadmap outlines major upcoming features and improvements for Wave Terminal. As with any r"
},
{
"path": "SECURITY.md",
"chars": 238,
"preview": "## Reporting Security Issues\n\nTo report vulnerabilities or security concerns, please email us at: [security@commandline."
},
{
"path": "Taskfile.yml",
"chars": 24328,
"preview": "# Copyright 2026, Command Line Inc.\n# SPDX-License-Identifier: Apache-2.0\n\nversion: \"3\"\n\nvars:\n APP_NAME: \"Wave\"\n "
},
{
"path": "aiprompts/aimodesconfig.md",
"chars": 24843,
"preview": "# Wave AI Modes Configuration - Visual Editor Architecture\n\n## Overview\n\nWave Terminal's AI modes configuration system a"
},
{
"path": "aiprompts/aisdk-streaming.md",
"chars": 5488,
"preview": "## Data Stream Protocol\n\nA data stream follows a special protocol that the AI SDK provides to send information to the fr"
},
{
"path": "aiprompts/aisdk-uimessage-type.md",
"chars": 5051,
"preview": "# `UIMessage`\n\n`UIMessage` serves as the source of truth for your application's state, representing the complete message"
},
{
"path": "aiprompts/anthropic-messages-api.md",
"chars": 113471,
"preview": "# Messages\n\n> Send a structured list of input messages with text and/or image content, and the model will generate the n"
},
{
"path": "aiprompts/anthropic-streaming.md",
"chars": 23249,
"preview": "# Streaming Messages\n\nWhen creating a Message, you can set `\"stream\": true` to incrementally stream the response using ["
},
{
"path": "aiprompts/blockcontroller-lifecycle.md",
"chars": 10222,
"preview": "# Block Controller Lifecycle\n\n## Overview\n\nBlock controllers manage the execution lifecycle of terminal shells, commands"
},
{
"path": "aiprompts/config-system.md",
"chars": 12548,
"preview": "# Wave Terminal Configuration System\n\nThis document explains how Wave Terminal's configuration system works and provides"
},
{
"path": "aiprompts/conn-arch.md",
"chars": 25733,
"preview": "# Wave Terminal Connection Architecture\n\n## Overview\n\nWave Terminal's connection system is designed to provide a unified"
},
{
"path": "aiprompts/contextmenu.md",
"chars": 2975,
"preview": "# Context Menu Quick Reference\n\nThis guide provides a quick overview of how to create and display a context menu using o"
},
{
"path": "aiprompts/fe-conn-arch.md",
"chars": 30228,
"preview": "# Wave Terminal Frontend Connection Architecture\n\n## Overview\n\nThe frontend connection architecture provides a reactive "
},
{
"path": "aiprompts/focus-layout.md",
"chars": 5175,
"preview": "# Wave Terminal Focus System - Layout State Flow\n\nThis document explains how focus state changes in the layout system pr"
},
{
"path": "aiprompts/focus.md",
"chars": 7622,
"preview": "# Wave Terminal Focus System\n\nThis document explains how the focus system works in Wave Terminal, particularly for termi"
},
{
"path": "aiprompts/getsetconfigvar.md",
"chars": 1663,
"preview": "# Setting and Reading Config Variables\n\nThis document provides a quick reference for updating and reading configuration "
},
{
"path": "aiprompts/layout-simplification.md",
"chars": 29416,
"preview": "# Wave Terminal Layout System - Simplification via Write Cache Pattern\n\n## Executive Summary\n\nThe current layout system "
},
{
"path": "aiprompts/layout.md",
"chars": 12898,
"preview": "# Wave Terminal Layout System Architecture\n\nThe Wave Terminal layout system is a sophisticated tile-based layout engine "
},
{
"path": "aiprompts/monaco-v0.53.md",
"chars": 4941,
"preview": "# Monaco 0.52 → 0.53 ESM Migration Plan (Vite/Electron)\n\n**Status:** Deferred to next release.\n**Current:** Pinned to `m"
},
{
"path": "aiprompts/newview.md",
"chars": 15786,
"preview": "# Creating a New View in Wave Terminal\n\nThis guide explains how to implement a new view type in Wave Terminal. Views are"
},
{
"path": "aiprompts/openai-request.md",
"chars": 4772,
"preview": "# OpenAI Request Input Field Structure (On-the-Wire Format)\n\nThis document describes the actual JSON structure sent to t"
},
{
"path": "aiprompts/openai-streaming-text.md",
"chars": 1404,
"preview": "For **just text streaming**, you only need to handle these 3 core events:\n\n## Essential Events\n\n### 1. `response.created"
},
{
"path": "aiprompts/openai-streaming.md",
"chars": 7816,
"preview": "# OpenAI Responses API SSE Events Documentation\n\nThis document outlines the Server-Sent Events (SSE) format used by Open"
},
{
"path": "aiprompts/tailwind-container-queries.md",
"chars": 1896,
"preview": "### Tailwind v4 Container Queries (Quick Overview)\n\n- **Viewport breakpoints**: `sm:`, `md:`, `lg:`, etc. → respond to *"
},
{
"path": "aiprompts/tsunami-builder.md",
"chars": 7018,
"preview": "# Tsunami AI Builder - V1 Architecture\n\n## Overview\n\nA split-screen builder for creating Tsunami applications: chat inte"
},
{
"path": "aiprompts/usechat-backend-design.md",
"chars": 13862,
"preview": "# useChat Compatible Backend Design for Wave Terminal\n\n## Overview\n\nThis document outlines how to create a `useChat()` c"
},
{
"path": "aiprompts/view-prompt.md",
"chars": 7517,
"preview": "# Wave Terminal ViewModel Guide\n\n## Overview\n\nWave Terminal uses a modular ViewModel system to define interactive blocks"
},
{
"path": "aiprompts/wave-osc-16162.md",
"chars": 5946,
"preview": "# Wave Terminal OSC 16162 Escape Sequences\n\nWave Terminal uses a custom OSC (Operating System Command) escape sequence n"
},
{
"path": "aiprompts/waveai-architecture.md",
"chars": 11831,
"preview": "# Wave AI Architecture Documentation\n\n## Overview\n\nWave AI is a chat-based AI assistant feature integrated into Wave Ter"
},
{
"path": "aiprompts/waveai-focus-updates.md",
"chars": 22245,
"preview": "# Wave Terminal Focus System - Wave AI Integration\n\n## Problem\n\nWave AI focus handling is fragile compared to blocks:\n\n1"
},
{
"path": "aiprompts/wps-events.md",
"chars": 7792,
"preview": "# WPS Events Guide\n\n## Overview\n\nWPS (Wave PubSub) is Wave Terminal's publish-subscribe event system that enables differ"
},
{
"path": "build/deb-postinstall.tpl",
"chars": 765,
"preview": "#!/bin/bash\n\nif type update-alternatives 2>/dev/null >&1; then\n # Remove previous link if it doesn't use update-alter"
},
{
"path": "build/entitlements.mac.plist",
"chars": 1023,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "cmd/generatego/main-generatego.go",
"chars": 3369,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"refle"
},
{
"path": "cmd/generateschema/main-generateschema.go",
"chars": 7318,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage main\n\nimport (\n\t\"encoding/json\"\n\t\"f"
},
{
"path": "cmd/generatets/main-generatets.go",
"chars": 7232,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage main\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"os"
},
{
"path": "cmd/packfiles/main-packfiles.go",
"chars": 1952,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io"
},
{
"path": "cmd/server/main-server.go",
"chars": 18939,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\""
},
{
"path": "cmd/test/test-main.go",
"chars": 108,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage main\n\nfunc main() {\n\n}\n"
},
{
"path": "cmd/test-conn/cliprovider.go",
"chars": 1202,
"preview": "// Copyright 2026, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage main\n\nimport (\n\t\"bufio\"\n\t\"context\"\n"
},
{
"path": "cmd/test-conn/main-test-conn.go",
"chars": 2309,
"preview": "// Copyright 2026, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"log"
},
{
"path": "cmd/test-conn/testutil.go",
"chars": 8591,
"preview": "// Copyright 2026, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\""
},
{
"path": "cmd/test-streammanager/bridge.go",
"chars": 1072,
"preview": "// Copyright 2026, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com"
},
{
"path": "cmd/test-streammanager/deliverypipe.go",
"chars": 5102,
"preview": "// Copyright 2026, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage main\n\nimport (\n\t\"encoding/base64\"\n\t"
},
{
"path": "cmd/test-streammanager/generator.go",
"chars": 873,
"preview": "// Copyright 2026, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage main\n\nimport (\n\t\"io\"\n)\n\n// Base64 c"
},
{
"path": "cmd/test-streammanager/main-test-streammanager.go",
"chars": 6869,
"preview": "// Copyright 2026, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n"
},
{
"path": "cmd/test-streammanager/metrics.go",
"chars": 2010,
"preview": "// Copyright 2026, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"tim"
},
{
"path": "cmd/test-streammanager/verifier.go",
"chars": 1264,
"preview": "// Copyright 2026, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage main\n\nimport (\n\t\"sync\"\n)\n\ntype Veri"
},
{
"path": "cmd/testai/main-testai.go",
"chars": 16160,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage main\n\nimport (\n\t\"context\"\n\t_ \"embed"
},
{
"path": "cmd/testai/testschema.json",
"chars": 3437,
"preview": "{\n \"config\": {\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"description\": \"Application"
},
{
"path": "cmd/testopenai/main-testopenai.go",
"chars": 4021,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage main\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\""
},
{
"path": "cmd/testsummarize/main-testsummarize.go",
"chars": 2730,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage main\n\nimport (\n\t\"context\"\n\t\"flag\"\n\t"
},
{
"path": "cmd/wsh/cmd/csscolormap.go",
"chars": 4469,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nvar CssColorNames = map[string"
},
{
"path": "cmd/wsh/cmd/setmeta_test.go",
"chars": 3494,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"reflect\"\n\t\"testing\""
},
{
"path": "cmd/wsh/cmd/wshcmd-ai.go",
"chars": 5691,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"encoding/base64\"\n\t\""
},
{
"path": "cmd/wsh/cmd/wshcmd-badge.go",
"chars": 3321,
"preview": "// Copyright 2026, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\t\"runtime\"\n\n\t\""
},
{
"path": "cmd/wsh/cmd/wshcmd-blocks.go",
"chars": 8702,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"encoding/json\"\n\t\"fm"
},
{
"path": "cmd/wsh/cmd/wshcmd-conn.go",
"chars": 5636,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\""
},
{
"path": "cmd/wsh/cmd/wshcmd-connserver.go",
"chars": 14656,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"encoding/base64\"\n\t\""
},
{
"path": "cmd/wsh/cmd/wshcmd-createblock.go",
"chars": 1429,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/"
},
{
"path": "cmd/wsh/cmd/wshcmd-debug.go",
"chars": 1302,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"encoding/json\"\n\n\t\"g"
},
{
"path": "cmd/wsh/cmd/wshcmd-debugterm.go",
"chars": 13280,
"preview": "// Copyright 2026, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"encoding/base64\"\n\t\""
},
{
"path": "cmd/wsh/cmd/wshcmd-debugterm_test.go",
"chars": 2607,
"preview": "// Copyright 2026, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"strings\"\n\t\"testing\""
},
{
"path": "cmd/wsh/cmd/wshcmd-deleteblock.go",
"chars": 1034,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/"
},
{
"path": "cmd/wsh/cmd/wshcmd-editconfig.go",
"chars": 1612,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/"
},
{
"path": "cmd/wsh/cmd/wshcmd-editor.go",
"chars": 2404,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\""
},
{
"path": "cmd/wsh/cmd/wshcmd-file-util.go",
"chars": 3150,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"context\"\n\t\"encoding"
},
{
"path": "cmd/wsh/cmd/wshcmd-file.go",
"chars": 14979,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"e"
},
{
"path": "cmd/wsh/cmd/wshcmd-focusblock.go",
"chars": 1106,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"githu"
},
{
"path": "cmd/wsh/cmd/wshcmd-getmeta.go",
"chars": 3064,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"encoding/json\"\n\t\"fm"
},
{
"path": "cmd/wsh/cmd/wshcmd-getvar.go",
"chars": 3078,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/"
},
{
"path": "cmd/wsh/cmd/wshcmd-jobdebug.go",
"chars": 13014,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"encoding/json\"\n\t\"fm"
},
{
"path": "cmd/wsh/cmd/wshcmd-jobmanager.go",
"chars": 2879,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t"
},
{
"path": "cmd/wsh/cmd/wshcmd-launch.go",
"chars": 1738,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/"
},
{
"path": "cmd/wsh/cmd/wshcmd-notify.go",
"chars": 1296,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/"
},
{
"path": "cmd/wsh/cmd/wshcmd-rcfiles.go",
"chars": 508,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"github.com/spf13/co"
},
{
"path": "cmd/wsh/cmd/wshcmd-readfile.go",
"chars": 1640,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"io\"\n\t\"os\"\n\n\t\"github"
},
{
"path": "cmd/wsh/cmd/wshcmd-root.go",
"chars": 7033,
"preview": "// Copyright 2026, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\""
},
{
"path": "cmd/wsh/cmd/wshcmd-run.go",
"chars": 4541,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/f"
},
{
"path": "cmd/wsh/cmd/wshcmd-secret.go",
"chars": 5022,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"st"
},
{
"path": "cmd/wsh/cmd/wshcmd-setbg.go",
"chars": 5460,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"encoding/hex\"\n\t\"enc"
},
{
"path": "cmd/wsh/cmd/wshcmd-setconfig.go",
"chars": 957,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/"
},
{
"path": "cmd/wsh/cmd/wshcmd-setmeta.go",
"chars": 4602,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"encoding/json\"\n\t\"fm"
},
{
"path": "cmd/wsh/cmd/wshcmd-setvar.go",
"chars": 2433,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\""
},
{
"path": "cmd/wsh/cmd/wshcmd-shell-unix.go",
"chars": 706,
"preview": "//go:build !windows\n\n// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n"
},
{
"path": "cmd/wsh/cmd/wshcmd-shell-win.go",
"chars": 438,
"preview": "//go:build windows\n\n// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t"
},
{
"path": "cmd/wsh/cmd/wshcmd-ssh.go",
"chars": 3364,
"preview": "// Copyright 2026, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/"
},
{
"path": "cmd/wsh/cmd/wshcmd-ssh_test.go",
"chars": 1616,
"preview": "// Copyright 2026, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport \"testing\"\n\nfunc TestApp"
},
{
"path": "cmd/wsh/cmd/wshcmd-tabindicator.go",
"chars": 2839,
"preview": "// Copyright 2026, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"githu"
},
{
"path": "cmd/wsh/cmd/wshcmd-term.go",
"chars": 1972,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/f"
},
{
"path": "cmd/wsh/cmd/wshcmd-termscrollback.go",
"chars": 3225,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"string"
},
{
"path": "cmd/wsh/cmd/wshcmd-test.go",
"chars": 589,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"github.com/spf13/co"
},
{
"path": "cmd/wsh/cmd/wshcmd-token.go",
"chars": 1157,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/"
},
{
"path": "cmd/wsh/cmd/wshcmd-version.go",
"chars": 2098,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"encoding/json\"\n\t\"fm"
},
{
"path": "cmd/wsh/cmd/wshcmd-view.go",
"chars": 3023,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\""
},
{
"path": "cmd/wsh/cmd/wshcmd-wavepath.go",
"chars": 3318,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\""
},
{
"path": "cmd/wsh/cmd/wshcmd-web.go",
"chars": 3813,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"encoding/json\"\n\t\"fm"
},
{
"path": "cmd/wsh/cmd/wshcmd-workspace.go",
"chars": 1345,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"github.com/spf13/co"
},
{
"path": "cmd/wsh/cmd/wshcmd-wsl.go",
"chars": 1553,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\""
},
{
"path": "cmd/wsh/main-wsh.go",
"chars": 369,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage main\n\nimport (\n\t\"github.com/waveter"
},
{
"path": "db/db.go",
"chars": 244,
"preview": "// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage db\n\nimport \"embed\"\n\n//go:embed migr"
},
{
"path": "db/migrations-filestore/000001_init.down.sql",
"chars": 51,
"preview": "DROP TABLE db_wave_file;\n\nDROP TABLE db_file_data;\n"
},
{
"path": "db/migrations-filestore/000001_init.up.sql",
"chars": 446,
"preview": "CREATE TABLE db_wave_file (\n zoneid varchar(36) NOT NULL,\n name varchar(200) NOT NULL,\n size bigint NOT NULL,\n "
},
{
"path": "db/migrations-wstore/000001_init.down.sql",
"chars": 90,
"preview": "DROP TABLE db_client;\n\nDROP TABLE db_workspace;\n\nDROP TABLE db_tab;\n\nDROP TABLE db_block;\n"
},
{
"path": "db/migrations-wstore/000001_init.up.sql",
"chars": 554,
"preview": "CREATE TABLE db_client (\n oid varchar(36) PRIMARY KEY,\n version int NOT NULL,\n data json NOT NULL\n);\n\nCREATE TA"
},
{
"path": "db/migrations-wstore/000002_init.down.sql",
"chars": 22,
"preview": "DROP TABLE db_layout;\n"
},
{
"path": "db/migrations-wstore/000002_init.up.sql",
"chars": 110,
"preview": "CREATE TABLE db_layout (\n oid varchar(36) PRIMARY KEY,\n version int NOT NULL,\n data json NOT NULL\n);\n"
},
{
"path": "db/migrations-wstore/000003_activity.down.sql",
"chars": 23,
"preview": "DROP TABLE db_activity;"
},
{
"path": "db/migrations-wstore/000003_activity.up.sql",
"chars": 350,
"preview": "CREATE TABLE db_activity (\n day varchar(20) PRIMARY KEY,\n uploaded boolean NOT NULL,\n tdata json NOT NULL,\n "
},
{
"path": "db/migrations-wstore/000004_history.down.sql",
"chars": 28,
"preview": "DROP TABLE history_migrated;"
},
{
"path": "db/migrations-wstore/000004_history.up.sql",
"chars": 252,
"preview": "CREATE TABLE history_migrated (\n\thistoryid varchar(36) PRIMARY KEY,\n ts bigint NOT NULL,\n\tremotename varchar(200) NOT"
},
{
"path": "db/migrations-wstore/000005_blockparent.down.sql",
"chars": 37,
"preview": "-- we don't need to remove parentoref"
},
{
"path": "db/migrations-wstore/000005_blockparent.up.sql",
"chars": 181,
"preview": "UPDATE db_block\nSET data = json_set(db_block.data, '$.parentoref', 'tab:' || db_tab.oid)\nFROM db_tab\nWHERE db_block.oid "
},
{
"path": "db/migrations-wstore/000006_workspace.down.sql",
"chars": 612,
"preview": "-- Step 1: Restore the $.activetabid field to db_window.data\nUPDATE db_window\nSET data = json_set(\n db_window.data,\n "
},
{
"path": "db/migrations-wstore/000006_workspace.up.sql",
"chars": 525,
"preview": "-- Step 1: Update db_workspace.data to set the $.activetabid field\nUPDATE db_workspace\nSET data = json_set(\n db_works"
},
{
"path": "db/migrations-wstore/000007_events.down.sql",
"chars": 22,
"preview": "DROP TABLE db_tevent;\n"
},
{
"path": "db/migrations-wstore/000007_events.up.sql",
"chars": 208,
"preview": "CREATE TABLE db_tevent (\n uuid varchar(36) PRIMARY KEY,\n ts int NOT NULL,\n tslocal varchar(100) NOT NULL,\n event"
},
{
"path": "db/migrations-wstore/000008_aimeta.down.sql",
"chars": 106,
"preview": "-- presets exist in config files, and should automatically prepopulate the meta in the older code versions"
},
{
"path": "db/migrations-wstore/000008_aimeta.up.sql",
"chars": 455,
"preview": "--- removes all ai: keys except ai:preset\nUPDATE db_block\nSET data = json_remove(\n db_block.data,\n '$.meta.ai:*',\n"
},
{
"path": "db/migrations-wstore/000009_mainserver.down.sql",
"chars": 36,
"preview": "DROP TABLE IF EXISTS db_mainserver;\n"
},
{
"path": "db/migrations-wstore/000009_mainserver.up.sql",
"chars": 128,
"preview": "CREATE TABLE IF NOT EXISTS db_mainserver (\n oid varchar(36) PRIMARY KEY,\n version int NOT NULL,\n data json NOT "
},
{
"path": "db/migrations-wstore/000010_merge_pinned_tabs.down.sql",
"chars": 95,
"preview": "-- This migration cannot be reversed as pinned tab state is lost\n-- during the merge operation\n"
},
{
"path": "db/migrations-wstore/000010_merge_pinned_tabs.up.sql",
"chars": 631,
"preview": "-- Merge PinnedTabIds into TabIds, preserving tab order\nUPDATE db_workspace\nSET data = json_set(\n data,\n '$.tabids',\n "
},
{
"path": "db/migrations-wstore/000011_job.down.sql",
"chars": 29,
"preview": "DROP TABLE IF EXISTS db_job;\n"
},
{
"path": "db/migrations-wstore/000011_job.up.sql",
"chars": 121,
"preview": "CREATE TABLE IF NOT EXISTS db_job (\n oid varchar(36) PRIMARY KEY,\n version int NOT NULL,\n data json NOT NULL\n);"
},
{
"path": "docs/.editorconfig",
"chars": 201,
"preview": "root = true\n\n[*]\nend_of_line = lf\ninsert_final_newline = true\n\n[*.{js,jsx,ts,tsx,cjs,json,yml,yaml,css,less}]\ncharset = "
},
{
"path": "docs/.gitignore",
"chars": 250,
"preview": "# Dependencies\n/node_modules\n/.yarn\n\n# Production\n/build\nbuild.zip\n\n# Generated files\n.docusaurus\n.cache-loader\n\n# Misc\n"
},
{
"path": "docs/.prettierignore",
"chars": 44,
"preview": "build\n.git\nnode_modules\n*.min.*\n*.mdx\nCNAME\n"
},
{
"path": "docs/.remarkrc",
"chars": 141,
"preview": "{\n \"plugins\": [\n \"remark-preset-lint-consistent\",\n \"remark-preset-lint-recommended\",\n \"remark-mdx\",\n \"remar"
},
{
"path": "docs/README.md",
"chars": 868,
"preview": "# Wave Terminal Documentation\n\nThis is the home for Wave Terminal's documentation site. This README is specifically abou"
},
{
"path": "docs/babel.config.js",
"chars": 91,
"preview": "module.exports = {\n presets: [require.resolve(\"@docusaurus/core/lib/babel/preset\")],\n};\n"
},
{
"path": "docs/docs/ai-presets.mdx",
"chars": 5913,
"preview": "---\nsidebar_position: 3.6\nid: \"ai-presets\"\ntitle: \"AI Presets (Deprecated)\"\n---\n:::warning Deprecation Notice\nThe AI Wid"
},
{
"path": "docs/docs/claude-code.mdx",
"chars": 5961,
"preview": "---\nsidebar_position: 1.9\nid: \"claude-code\"\ntitle: \"Claude Code Integration\"\n---\n\nimport { VersionBadge } from \"@site/sr"
},
{
"path": "docs/docs/config.mdx",
"chars": 40176,
"preview": "---\nsidebar_position: 3.45\nid: \"config\"\ntitle: \"Configuration\"\n---\n\nimport { Kbd } from \"@site/src/components/kbd\";\nimpo"
},
{
"path": "docs/docs/connections.mdx",
"chars": 23490,
"preview": "---\nsidebar_position: 3.1\nid: \"connections\"\ntitle: \"Connections\"\n---\n\nimport { VersionBadge } from \"@site/src/components"
},
{
"path": "docs/docs/customization.mdx",
"chars": 4129,
"preview": "---\nsidebar_position: 3.2\nid: \"customization\"\ntitle: \"Customization\"\n---\n\n## Tab Themes\n\n\"\n---\n\nimport { VersionBadge } from \"@"
},
{
"path": "docs/docs/waveai.mdx",
"chars": 4344,
"preview": "---\nsidebar_position: 1.5\nid: \"waveai\"\ntitle: \"Wave AI\"\n---\n\nimport { Kbd } from \"@site/src/components/kbd\";\nimport { Pl"
},
{
"path": "docs/docs/widgets.mdx",
"chars": 8575,
"preview": "---\nsidebar_position: 3.3\nid: \"widgets\"\ntitle: \"Widgets\"\n---\n\nimport { Kbd } from \"@site/src/components/kbd\";\nimport { P"
},
{
"path": "docs/docs/workspaces.mdx",
"chars": 4825,
"preview": "---\nsidebar_position: 3\nid: \"workspaces\"\ntitle: \"Workspaces\"\n---\n\n# Workspaces\n\nWorkspaces are a powerful way to organiz"
},
{
"path": "docs/docs/wsh-reference.mdx",
"chars": 29616,
"preview": "---\nsidebar_position: 4.1\nid: \"wsh-reference\"\ntitle: \"wsh reference\"\n---\n\nimport { Kbd } from \"@site/src/components/kbd\""
},
{
"path": "docs/docs/wsh.mdx",
"chars": 6340,
"preview": "---\nsidebar_position: 4\nid: \"wsh\"\ntitle: \"wsh overview\"\n---\n\nThe `wsh` command provides Wave Terminal's core command lin"
}
]
// ... and 769 more files (download for full content)
About this extraction
This page contains the full source code of the wavetermdev/waveterm GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 969 files (6.0 MB), approximately 1.6M tokens, and a symbol index with 7200 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.