Skip to content

Commit f960fd2

Browse files
committed
Merge remote-tracking branch 'origin/main' into copilot/add-file-explorer-functionality
2 parents c4e5d6a + 52dd0a2 commit f960fd2

File tree

128 files changed

+4966
-1545
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

128 files changed

+4966
-1545
lines changed

.github/copilot-instructions.md

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,45 @@
22

33
## Project Rules
44

5-
Read and follow all guidelines in [`.roo/rules/rules.md`](./.roo/rules/rules.md).
5+
- See the overview of the project in `.kilocode/rules/overview.md`
6+
- Read and follow all guidelines in `.kilocode/rules/rules.md`
67

78
---
89

910
## Skill Guides
1011

1112
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.
1213

13-
| Skill | Description |
14-
|-------|-------------|
15-
| [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. |
16-
| [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. |
17-
| [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. |
18-
| [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. |
19-
| [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. |
20-
| [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. |
21-
| [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. |
14+
| Skill | File | Description |
15+
| ------------ | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
16+
| 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. |
17+
| 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. |
18+
| 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. |
19+
| 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. |
20+
| 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. |
21+
| 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. |
22+
| 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. |
23+
| 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. |
2224

2325
> **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.
26+
27+
---
28+
29+
## Preview Server
30+
31+
To run the standalone component preview (no Electron, no backend required):
32+
33+
```
34+
task preview
35+
```
36+
37+
This runs `cd frontend/preview && npx vite` and serves at **http://localhost:7007** (port configured in `frontend/preview/vite.config.ts`).
38+
39+
To build a static preview: `task build:preview`
40+
41+
**Do NOT use any of the following to start the preview — they all launch the full Electron app or serve the wrong content:**
42+
43+
- `npm run dev` — runs `electron-vite dev`, launches Electron
44+
- `npm run start` — also launches Electron
45+
- `npx vite` from the repo root — uses the Electron-Vite config, not the preview app
46+
- Serving the `dist/` directory — the preview app is never built there; it has its own build output

.kilocode/skills/add-rpc/SKILL.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ RPC commands in Wave Terminal follow these conventions:
2626

2727
- **Method names** must end with `Command`
2828
- **First parameter** must be `context.Context`
29-
- **Second parameter** (optional) is the command data structure
29+
- **Remaining parameters** are a regular Go parameter list (zero or more typed args)
3030
- **Return values** can be either just an error, or one return value plus an error
3131
- **Streaming commands** return a channel instead of a direct value
3232

@@ -49,7 +49,7 @@ type WshRpcInterface interface {
4949

5050
- Method name must end with `Command`
5151
- First parameter must be `ctx context.Context`
52-
- Optional second parameter for input data
52+
- Remaining parameters are a regular Go parameter list (zero or more)
5353
- Return either `error` or `(ReturnType, error)`
5454
- For streaming, return `chan RespOrErrorUnion[T]`
5555

.kilocode/skills/waveenv/SKILL.md

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
---
2+
name: waveenv
3+
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.
4+
---
5+
6+
# WaveEnv Narrowing Skill
7+
8+
## Purpose
9+
10+
A WaveEnv narrowing creates a _named subset type_ of `WaveEnv` that:
11+
12+
1. Documents exactly which parts of the environment a component tree actually uses.
13+
2. Forms a type contract so callers and tests know what to provide.
14+
3. Enables mocking in the preview/test server — you only need to implement what's listed.
15+
16+
## When To Create One
17+
18+
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.
19+
20+
## Core Principle: Only Include What You Use
21+
22+
**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`.
23+
24+
## File Location
25+
26+
- **Separate file** (preferred for shared/complex envs): name it `<feature>env.ts` next to the component, e.g. `frontend/app/block/blockenv.ts`.
27+
- **Inline** (acceptable for small, single-file components): export the type directly from the component file, e.g. `WidgetsEnv` in `frontend/app/workspace/widgets.tsx`.
28+
29+
## Imports Required
30+
31+
```ts
32+
import {
33+
BlockMetaKeyAtomFnType, // only if you use getBlockMetaKeyAtom
34+
ConnConfigKeyAtomFnType, // only if you use getConnConfigKeyAtom
35+
SettingsKeyAtomFnType, // only if you use getSettingsKeyAtom
36+
WaveEnv,
37+
WaveEnvSubset,
38+
} from "@/app/waveenv/waveenv";
39+
```
40+
41+
## The Shape
42+
43+
```ts
44+
export type MyEnv = WaveEnvSubset<{
45+
// --- Simple WaveEnv properties ---
46+
// Copy the type verbatim from WaveEnv with WaveEnv["key"] syntax.
47+
isDev: WaveEnv["isDev"];
48+
createBlock: WaveEnv["createBlock"];
49+
showContextMenu: WaveEnv["showContextMenu"];
50+
platform: WaveEnv["platform"];
51+
52+
// --- electron: list only the methods you call ---
53+
electron: {
54+
openExternal: WaveEnv["electron"]["openExternal"];
55+
};
56+
57+
// --- rpc: list only the commands you call ---
58+
rpc: {
59+
ActivityCommand: WaveEnv["rpc"]["ActivityCommand"];
60+
ConnEnsureCommand: WaveEnv["rpc"]["ConnEnsureCommand"];
61+
};
62+
63+
// --- atoms: list only the atoms you read ---
64+
atoms: {
65+
modalOpen: WaveEnv["atoms"]["modalOpen"];
66+
fullConfigAtom: WaveEnv["atoms"]["fullConfigAtom"];
67+
};
68+
69+
// --- wos: always take the whole thing, no sub-typing needed ---
70+
wos: WaveEnv["wos"];
71+
72+
// --- services: list only the services you call; no method-level narrowing ---
73+
services: {
74+
block: WaveEnv["services"]["block"];
75+
workspace: WaveEnv["services"]["workspace"];
76+
};
77+
78+
// --- key-parameterized atom factories: enumerate the keys you use ---
79+
getSettingsKeyAtom: SettingsKeyAtomFnType<"app:focusfollowscursor" | "window:magnifiedblockopacity">;
80+
getBlockMetaKeyAtom: BlockMetaKeyAtomFnType<"view" | "frame:title" | "connection">;
81+
getConnConfigKeyAtom: ConnConfigKeyAtomFnType<"conn:wshenabled">;
82+
83+
// --- other atom helpers: copy verbatim ---
84+
getConnStatusAtom: WaveEnv["getConnStatusAtom"];
85+
getLocalHostDisplayNameAtom: WaveEnv["getLocalHostDisplayNameAtom"];
86+
}>;
87+
```
88+
89+
### Automatically Included Fields
90+
91+
Every `WaveEnvSubset<T>` automatically includes the mock fields — you never need to declare them:
92+
93+
- `isMock: boolean`
94+
- `mockSetWaveObj: <T extends WaveObj>(oref: string, obj: T) => void`
95+
- `mockModels?: Map<any, any>`
96+
97+
### Rules for Each Section
98+
99+
| Section | Pattern | Notes |
100+
| -------------------------- | ------------------------------------------------------ | -------------------------------------------------------------------------------------------------- |
101+
| `electron` | `electron: { method: WaveEnv["electron"]["method"]; }` | List every method called; omit the rest. |
102+
| `rpc` | `rpc: { Cmd: WaveEnv["rpc"]["Cmd"]; }` | List every RPC command called; omit the rest. |
103+
| `atoms` | `atoms: { atom: WaveEnv["atoms"]["atom"]; }` | List every atom read; omit the rest. |
104+
| `wos` | `wos: WaveEnv["wos"]` | Take the whole `wos` object (no sub-typing needed), but **only add it if `wos` is actually used**. |
105+
| `services` | `services: { svc: WaveEnv["services"]["svc"]; }` | List each service used; take the whole service object (no method-level narrowing). |
106+
| `getSettingsKeyAtom` | `SettingsKeyAtomFnType<"key1" \| "key2">` | Union all settings keys accessed. |
107+
| `getBlockMetaKeyAtom` | `BlockMetaKeyAtomFnType<"key1" \| "key2">` | Union all block meta keys accessed. |
108+
| `getConnConfigKeyAtom` | `ConnConfigKeyAtomFnType<"key1">` | Union all conn config keys accessed. |
109+
| All other `WaveEnv` fields | `WaveEnv["fieldName"]` | Copy type verbatim. |
110+
111+
## Using the Narrowed Type in Components
112+
113+
```ts
114+
import { useWaveEnv } from "@/app/waveenv/waveenv";
115+
import { MyEnv } from "./myenv";
116+
117+
const MyComponent = memo(() => {
118+
const env = useWaveEnv<MyEnv>();
119+
// TypeScript now enforces you only access what's in MyEnv.
120+
const val = useAtomValue(env.getSettingsKeyAtom("app:focusfollowscursor"));
121+
...
122+
});
123+
```
124+
125+
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.
126+
127+
## Real Examples
128+
129+
- `BlockEnv` in `frontend/app/block/blockenv.ts` — complex narrowing with all section types, in a separate file.
130+
- `WidgetsEnv` in `frontend/app/workspace/widgets.tsx` — smaller narrowing defined inline in the component file.

.roo/rules/rules.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,7 @@ The full API is defined in custom.d.ts as type ElectronApi.
8484

8585
- **CRITICAL: Completion format MUST be: "Done: [one-line description]"**
8686
- **Keep your Task Completed summaries VERY short**
87-
- **No lengthy pre-completion summaries** - Do not provide detailed explanations of implementation before using attempt_completion
88-
- **No recaps of changes** - Skip explaining what was done before completion
87+
- **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.
8988
- **Go directly to completion** - After making changes, proceed directly to attempt_completion without summarizing
9089
- The project is currently an un-released POC / MVP. Do not worry about backward compatibility when making changes
9190
- 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.

cmd/generatego/main-generatego.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,15 @@ func GenerateWshClient() error {
2424
fmt.Fprintf(os.Stderr, "generating wshclient file to %s\n", WshClientFileName)
2525
var buf strings.Builder
2626
gogen.GenerateBoilerplate(&buf, "wshclient", []string{
27+
"github.com/wavetermdev/waveterm/pkg/aiusechat/uctypes",
28+
"github.com/wavetermdev/waveterm/pkg/baseds",
2729
"github.com/wavetermdev/waveterm/pkg/telemetry/telemetrydata",
28-
"github.com/wavetermdev/waveterm/pkg/wshutil",
29-
"github.com/wavetermdev/waveterm/pkg/wshrpc",
30-
"github.com/wavetermdev/waveterm/pkg/wconfig",
30+
"github.com/wavetermdev/waveterm/pkg/vdom",
3131
"github.com/wavetermdev/waveterm/pkg/waveobj",
32+
"github.com/wavetermdev/waveterm/pkg/wconfig",
3233
"github.com/wavetermdev/waveterm/pkg/wps",
33-
"github.com/wavetermdev/waveterm/pkg/vdom",
34-
"github.com/wavetermdev/waveterm/pkg/aiusechat/uctypes",
34+
"github.com/wavetermdev/waveterm/pkg/wshrpc",
35+
"github.com/wavetermdev/waveterm/pkg/wshutil",
3536
})
3637
wshDeclMap := wshrpc.GenerateWshCommandDeclMap()
3738
for _, key := range utilfn.GetOrderedMapKeys(wshDeclMap) {

cmd/generatets/main-generatets.go

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,37 @@ func generateServicesFile(tsTypesMap map[reflect.Type]string) error {
8888
fmt.Fprintf(&buf, "// Copyright 2026, Command Line Inc.\n")
8989
fmt.Fprintf(&buf, "// SPDX-License-Identifier: Apache-2.0\n\n")
9090
fmt.Fprintf(&buf, "// generated by cmd/generate/main-generatets.go\n\n")
91-
fmt.Fprintf(&buf, "import * as WOS from \"./wos\";\n\n")
91+
fmt.Fprintf(&buf, "import * as WOS from \"./wos\";\n")
92+
fmt.Fprintf(&buf, "import type { WaveEnv } from \"@/app/waveenv/waveenv\";\n\n")
93+
fmt.Fprintf(&buf, "function callBackendService(waveEnv: WaveEnv, service: string, method: string, args: any[], noUIContext?: boolean): Promise<any> {\n")
94+
fmt.Fprintf(&buf, " if (waveEnv != null) {\n")
95+
fmt.Fprintf(&buf, " return waveEnv.callBackendService(service, method, args, noUIContext)\n")
96+
fmt.Fprintf(&buf, " }\n")
97+
fmt.Fprintf(&buf, " return WOS.callBackendService(service, method, args, noUIContext);\n")
98+
fmt.Fprintf(&buf, "}\n\n")
9299
orderedKeys := utilfn.GetOrderedMapKeys(service.ServiceMap)
93100
for _, serviceName := range orderedKeys {
94101
serviceObj := service.ServiceMap[serviceName]
95102
svcStr := tsgen.GenerateServiceClass(serviceName, serviceObj, tsTypesMap)
96103
fmt.Fprint(&buf, svcStr)
97104
fmt.Fprint(&buf, "\n")
98105
}
106+
fmt.Fprintf(&buf, "export const AllServiceTypes = {\n")
107+
for _, serviceName := range orderedKeys {
108+
serviceObj := service.ServiceMap[serviceName]
109+
serviceType := reflect.TypeOf(serviceObj)
110+
tsServiceName := serviceType.Elem().Name()
111+
fmt.Fprintf(&buf, " %q: %sType,\n", serviceName, tsServiceName)
112+
}
113+
fmt.Fprintf(&buf, "};\n\n")
114+
fmt.Fprintf(&buf, "export const AllServiceImpls = {\n")
115+
for _, serviceName := range orderedKeys {
116+
serviceObj := service.ServiceMap[serviceName]
117+
serviceType := reflect.TypeOf(serviceObj)
118+
tsServiceName := serviceType.Elem().Name()
119+
fmt.Fprintf(&buf, " %q: %s,\n", serviceName, tsServiceName)
120+
}
121+
fmt.Fprintf(&buf, "};\n")
99122
written, err := utilfn.WriteFileIfDifferent(fileName, buf.Bytes())
100123
if !written {
101124
fmt.Fprintf(os.Stderr, "no changes to %s\n", fileName)
@@ -112,9 +135,17 @@ func generateWshClientApiFile(tsTypeMap map[reflect.Type]string) error {
112135
fmt.Fprintf(&buf, "// SPDX-License-Identifier: Apache-2.0\n\n")
113136
fmt.Fprintf(&buf, "// generated by cmd/generate/main-generatets.go\n\n")
114137
fmt.Fprintf(&buf, "import { WshClient } from \"./wshclient\";\n\n")
138+
fmt.Fprintf(&buf, "export interface MockRpcClient {\n")
139+
fmt.Fprintf(&buf, " mockWshRpcCall(client: WshClient, command: string, data: any, opts?: RpcOpts): Promise<any>;\n")
140+
fmt.Fprintf(&buf, " mockWshRpcStream(client: WshClient, command: string, data: any, opts?: RpcOpts): AsyncGenerator<any, void, boolean>;\n")
141+
fmt.Fprintf(&buf, "}\n\n")
115142
orderedKeys := utilfn.GetOrderedMapKeys(declMap)
116143
fmt.Fprintf(&buf, "// WshServerCommandToDeclMap\n")
117-
fmt.Fprintf(&buf, "class RpcApiType {\n")
144+
fmt.Fprintf(&buf, "export class RpcApiType {\n")
145+
fmt.Fprintf(&buf, " mockClient: MockRpcClient = null;\n\n")
146+
fmt.Fprintf(&buf, " setMockRpcClient(client: MockRpcClient): void {\n")
147+
fmt.Fprintf(&buf, " this.mockClient = client;\n")
148+
fmt.Fprintf(&buf, " }\n\n")
118149
for _, methodDecl := range orderedKeys {
119150
methodDecl := declMap[methodDecl]
120151
methodStr := tsgen.GenerateWshClientApiMethod(methodDecl, tsTypeMap)

cmd/server/main-server.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,11 @@ func main() {
573573
blocklogger.InitBlockLogger()
574574
jobcontroller.InitJobController()
575575
blockcontroller.InitBlockController()
576-
wcore.InitTabIndicatorStore()
576+
err = wcore.InitBadgeStore()
577+
if err != nil {
578+
log.Printf("error initializing badge store: %v\n", err)
579+
return
580+
}
577581
go func() {
578582
defer func() {
579583
panichandler.PanicHandler("GetSystemSummary", recover())

0 commit comments

Comments
 (0)