@g3nomaly/mods 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -21
- package/dist/cli/commands/add.d.ts.map +1 -1
- package/dist/cli/commands/add.js +2 -3
- package/dist/cli/commands/add.js.map +1 -1
- package/dist/cli/commands/init.d.ts +7 -4
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +6 -5
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/index.js +4 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/viewer.d.ts +16 -5
- package/dist/cli/viewer.d.ts.map +1 -1
- package/dist/cli/viewer.js +76 -18
- package/dist/cli/viewer.js.map +1 -1
- package/dist/relay/index.d.ts +2 -0
- package/dist/relay/index.d.ts.map +1 -0
- package/dist/relay/index.js +9 -0
- package/dist/relay/index.js.map +1 -0
- package/dist/relay/lines.d.ts +25 -0
- package/dist/relay/lines.d.ts.map +1 -0
- package/dist/relay/lines.js +35 -0
- package/dist/relay/lines.js.map +1 -0
- package/dist/relay/protocol.d.ts +123 -0
- package/dist/relay/protocol.d.ts.map +1 -0
- package/dist/relay/protocol.js +70 -0
- package/dist/relay/protocol.js.map +1 -0
- package/dist/relay/relay.d.ts +16 -0
- package/dist/relay/relay.d.ts.map +1 -0
- package/dist/relay/relay.js +213 -0
- package/dist/relay/relay.js.map +1 -0
- package/dist/relay/sessions.d.ts +28 -0
- package/dist/relay/sessions.d.ts.map +1 -0
- package/dist/relay/sessions.js +86 -0
- package/dist/relay/sessions.js.map +1 -0
- package/dist/viewer/index.d.ts +6 -0
- package/dist/viewer/index.d.ts.map +1 -1
- package/dist/viewer/index.js +3 -0
- package/dist/viewer/index.js.map +1 -1
- package/dist/viewer/machine.d.ts +37 -0
- package/dist/viewer/machine.d.ts.map +1 -0
- package/dist/viewer/machine.js +55 -0
- package/dist/viewer/machine.js.map +1 -0
- package/dist/viewer/relay.d.ts +23 -0
- package/dist/viewer/relay.d.ts.map +1 -0
- package/dist/viewer/relay.js +51 -0
- package/dist/viewer/relay.js.map +1 -0
- package/dist/viewer/viewerExtension.d.ts +27 -0
- package/dist/viewer/viewerExtension.d.ts.map +1 -0
- package/dist/viewer/viewerExtension.js +48 -0
- package/dist/viewer/viewerExtension.js.map +1 -0
- package/dist/vscode/g3n-mods-viewer.vsix +0 -0
- package/package.json +9 -5
package/README.md
CHANGED
|
@@ -2,30 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
`g3n-mods` installs Claude Code mods into a project. A mod adds a pane, a status line, a slash command or a hook to Claude Code. The g3n mods from [`@g3nomaly/g3n-mods`](../g3n-mods) are available by default, and you can register other sources: a git repository, an npm package or a local folder.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The Claude Code extension for VS Code does not draw mods itself, so `init` installs a viewer: a button in the editor title bar opens a tab that draws the mods of a running session. The mods also work in the terminal.
|
|
6
6
|
|
|
7
7
|
## Requirements
|
|
8
8
|
|
|
9
9
|
- [Bun](https://bun.sh)
|
|
10
10
|
- Claude Code for VS Code (`anthropic.claude-code`) 2.1.296 or newer
|
|
11
|
-
- A git repository to install into, unless you install with `--user`
|
|
12
|
-
|
|
13
11
|
## Install the mods
|
|
14
12
|
|
|
15
|
-
Run these from the root of your project:
|
|
16
|
-
|
|
17
13
|
```sh
|
|
18
|
-
bunx @g3nomaly/mods init # creates
|
|
19
|
-
bunx @g3nomaly/mods ls # lists the mods you can install
|
|
20
|
-
bunx @g3nomaly/mods add context-bar # installs one mod
|
|
21
|
-
bunx @g3nomaly/mods add g3n-mods # or every mod from the g3n-mods source
|
|
14
|
+
bunx @g3nomaly/mods init --user # creates ~/.claude/mods.json and installs the viewer
|
|
15
|
+
bunx @g3nomaly/mods ls --user # lists the mods you can install
|
|
16
|
+
bunx @g3nomaly/mods add context-bar --user # installs one mod
|
|
17
|
+
bunx @g3nomaly/mods add g3n-mods --user # or every mod from the g3n-mods source
|
|
22
18
|
```
|
|
23
19
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
Mods are copied to `.claude/skills/<mod>/`, where Claude Code finds them, and recorded in `.claude/mods.json`. Commit both if your team should get the same mods.
|
|
20
|
+
Mods are copied to `~/.claude/skills/<mod>/`, where Claude Code finds them in every project, and recorded in `~/.claude/mods.json`. Start a new Claude Code session, then click the **Mods** button in the editor title bar. Sessions that were already open before `init` do not show in the viewer until you start them again.
|
|
27
21
|
|
|
28
|
-
To install
|
|
22
|
+
To install into one project instead, leave out `--user` and run the commands from the project's git root. Mods then go to `.claude/skills/<mod>/` and `.claude/mods.json`. Claude Code skips them until the workspace is trusted, and the VS Code extension does not ask: run `claude` once in a terminal in the project, accept the trust dialog, then run `/reload-plugins`.
|
|
29
23
|
|
|
30
24
|
## The g3n mods
|
|
31
25
|
|
|
@@ -44,16 +38,19 @@ To install for every project instead of one, add `--user` to any command. Mods t
|
|
|
44
38
|
|
|
45
39
|
Each pane opens with its command. For `context-bar`, `tool-timeline`, `agents-panel` and `custom-crab-agents`, running the command again closes the pane.
|
|
46
40
|
|
|
47
|
-
##
|
|
41
|
+
## The viewer
|
|
48
42
|
|
|
49
|
-
`init`
|
|
43
|
+
`init` sets up three things, once per machine:
|
|
50
44
|
|
|
51
|
-
- `claudeCode.
|
|
52
|
-
|
|
45
|
+
1. **The relay.** It builds `~/.claude/g3n-mods/bin/g3n-mods-relay` and sets it as `claudeCode.claudeProcessWrapper` in VS Code's machine settings. The Claude Code extension then starts every session through the relay. The relay passes everything through unchanged, and lets the viewer ask that session for its mods' drawings.
|
|
46
|
+
2. **The viewer extension.** It installs *g3n Mods Viewer* with `code --install-extension`. Its button sits next to Split Editor and opens the viewer as an editor tab. To open it in a window of its own instead, turn on `g3nMods.viewer.openInNewWindow`.
|
|
47
|
+
3. **The chat view.** In `.vscode/settings.json` it sets `claudeCode.preferredLocation` to `panel` (pass `--location sidebar` to keep the side bar) and `claudeCode.useTerminal` to `false`.
|
|
53
48
|
|
|
54
|
-
The
|
|
49
|
+
The viewer shows every pane that is open in the session it is showing. Pick another session from the list at the top. Turn a mod's pane on or off with its command in the Claude Code chat, or close it with **×** in the viewer.
|
|
55
50
|
|
|
56
|
-
|
|
51
|
+
If another tool already set a process wrapper, `init` leaves it and says so. Run `init --replace-wrapper` to use the relay instead. If the `code` command is not found, `init` prints the path of the `.vsix` to install by hand.
|
|
52
|
+
|
|
53
|
+
`hide-personal-data` and `you-should-know` change how replies are drawn. The extension draws replies itself, so these two only work in the terminal.
|
|
57
54
|
|
|
58
55
|
## Keep mods up to date
|
|
59
56
|
|
|
@@ -92,5 +89,3 @@ bun run mods -- ls # the CLI from source
|
|
|
92
89
|
bun run typecheck
|
|
93
90
|
bun run build
|
|
94
91
|
```
|
|
95
|
-
|
|
96
|
-
The reasons behind the design are in [`documentation/spec/mods/decisions.md`](../../documentation/spec/mods/decisions.md).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/add.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGrD;;;;;GAKG;AACH,MAAM,WAAW,UAAW,SAAQ,cAAc;IAChD,KAAK,CAAC,EAAG,KAAK,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;GASG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,UAAe,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/add.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGrD;;;;;GAKG;AACH,MAAM,WAAW,UAAW,SAAQ,cAAc;IAChD,KAAK,CAAC,EAAG,KAAK,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;GASG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,UAAe,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAYjH"}
|
package/dist/cli/commands/add.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// packages/mods/src/cli/commands/add.ts
|
|
2
|
-
import { addFromSources
|
|
2
|
+
import { addFromSources } from "@g3nomaly/core/cli";
|
|
3
3
|
import { MOD_CONTEXT, installedMods, openModProject, openModRegistry } from "../project";
|
|
4
4
|
import { setUpViewer } from "../viewer";
|
|
5
5
|
/**
|
|
@@ -22,8 +22,7 @@ export async function addCommand(names, options = {}, deps = {}) {
|
|
|
22
22
|
registry.dispose();
|
|
23
23
|
}
|
|
24
24
|
if (Object.keys(installedMods(project)).length > 0) {
|
|
25
|
-
setUpViewer(project);
|
|
26
|
-
console.log(lineInfo(`New sessions load the mods; in a running one, run ${c.cmd("/reload-plugins")}.`));
|
|
25
|
+
await setUpViewer(project);
|
|
27
26
|
}
|
|
28
27
|
}
|
|
29
28
|
//# sourceMappingURL=add.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add.js","sourceRoot":"","sources":["../../../src/cli/commands/add.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,OAAO,EAAE,cAAc,EAAE,
|
|
1
|
+
{"version":3,"file":"add.js","sourceRoot":"","sources":["../../../src/cli/commands/add.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAEzF,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAaxC;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,KAAe,EAAE,OAAO,GAAe,EAAE,EAAE,IAAI,GAAgB,EAAE;IAChG,MAAM,OAAO,GAAI,cAAc,CAAC,OAAO,CAAC,KAAK,IAAI,SAAS,EAAE,IAAI,CAAC,CAAC;IAClE,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAChE,IAAI,CAAC;QACH,MAAM,cAAc,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;IAChF,CAAC;YAAS,CAAC;QACT,QAAQ,CAAC,OAAO,EAAE,CAAC;IACrB,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnD,MAAM,WAAW,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;AACH,CAAC"}
|
|
@@ -5,17 +5,20 @@ import type { ProjectDeps, Scope } from "../project";
|
|
|
5
5
|
*
|
|
6
6
|
* @property scope - Scope to create `mods.json` in; `project` when absent.
|
|
7
7
|
* @property location - Where Claude opens in VS Code; a location already set is kept when absent.
|
|
8
|
+
* @property replaceWrapper - Replace a process wrapper some other tool set.
|
|
8
9
|
*/
|
|
9
10
|
export interface InitOptions {
|
|
10
11
|
scope?: Scope;
|
|
11
12
|
location?: ViewerLocation;
|
|
13
|
+
replaceWrapper?: boolean;
|
|
12
14
|
}
|
|
13
15
|
/**
|
|
14
|
-
* @brief Creates the scope's `mods.json` when missing, sets up the viewer
|
|
15
|
-
* the
|
|
16
|
+
* @brief Creates the scope's `mods.json` when missing, sets up the viewer (the relay
|
|
17
|
+
* Claude Code sessions run through and the window that draws their mods), and
|
|
18
|
+
* lists the sources mods can be installed from.
|
|
16
19
|
*
|
|
17
|
-
* @param options - Scope and
|
|
20
|
+
* @param options - Scope, viewer location, and whether to replace another tool's wrapper.
|
|
18
21
|
* @param deps - Overrides for the project lookup, used by tests.
|
|
19
22
|
*/
|
|
20
|
-
export declare function initCommand(options?: InitOptions, deps?: ProjectDeps): void
|
|
23
|
+
export declare function initCommand(options?: InitOptions, deps?: ProjectDeps): Promise<void>;
|
|
21
24
|
//# sourceMappingURL=init.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAIrD
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAIrD;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAW,KAAK,CAAC;IACvB,QAAQ,CAAC,EAAQ,cAAc,CAAC;IAChC,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAAC,OAAO,GAAE,WAAgB,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAYlG"}
|
|
@@ -7,19 +7,20 @@ import { openModProject } from "../project";
|
|
|
7
7
|
import { setUpViewer } from "../viewer";
|
|
8
8
|
import { sourceLsCommand } from "./source";
|
|
9
9
|
/**
|
|
10
|
-
* @brief Creates the scope's `mods.json` when missing, sets up the viewer
|
|
11
|
-
* the
|
|
10
|
+
* @brief Creates the scope's `mods.json` when missing, sets up the viewer (the relay
|
|
11
|
+
* Claude Code sessions run through and the window that draws their mods), and
|
|
12
|
+
* lists the sources mods can be installed from.
|
|
12
13
|
*
|
|
13
|
-
* @param options - Scope and
|
|
14
|
+
* @param options - Scope, viewer location, and whether to replace another tool's wrapper.
|
|
14
15
|
* @param deps - Overrides for the project lookup, used by tests.
|
|
15
16
|
*/
|
|
16
|
-
export function initCommand(options = {}, deps = {}) {
|
|
17
|
+
export async function initCommand(options = {}, deps = {}) {
|
|
17
18
|
const project = openModProject(options.scope ?? "project", deps);
|
|
18
19
|
if (!fs.existsSync(project.target.manifest.filePath)) {
|
|
19
20
|
saveInstallManifest(project.target.manifest, ModMetaSchema);
|
|
20
21
|
console.log(lineSuccess(`Created ${c.file(project.target.manifest.filePath)}`));
|
|
21
22
|
}
|
|
22
|
-
setUpViewer(project, options.location);
|
|
23
|
+
await setUpViewer(project, { location: options.location, install: true, replaceWrapper: options.replaceWrapper });
|
|
23
24
|
console.log(c.header("\nSources"));
|
|
24
25
|
sourceLsCommand({ scope: project.scope }, deps);
|
|
25
26
|
console.log(`\nRun ${c.cmd("g3n-mods ls")} to see the mods, ${c.cmd("g3n-mods add <mod>")} to install one.`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,CAAC,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,CAAC,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAe3C;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAAO,GAAgB,EAAE,EAAE,IAAI,GAAgB,EAAE;IACjF,MAAM,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,KAAK,IAAI,SAAS,EAAE,IAAI,CAAC,CAAC;IAEjE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACrD,mBAAmB,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QAC5D,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;IAClF,CAAC;IACD,MAAM,WAAW,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IAElH,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;IACnC,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,CAAC;IAChD,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,qBAAqB,CAAC,CAAC,GAAG,CAAC,oBAAoB,CAAC,kBAAkB,CAAC,CAAC;AAC/G,CAAC"}
|
package/dist/cli/index.js
CHANGED
|
@@ -23,12 +23,13 @@ const program = new Command()
|
|
|
23
23
|
.description("Install Claude Code mods from registered sources");
|
|
24
24
|
program
|
|
25
25
|
.command("init")
|
|
26
|
-
.description("Create mods.json
|
|
26
|
+
.description("Create mods.json, set up the relay and install the mods viewer for VS Code")
|
|
27
27
|
.option("-u, --user", "Work on ~/.claude/ for every project")
|
|
28
28
|
.option("--location <where>", "Where Claude opens in VS Code: panel (an editor tab) or sidebar")
|
|
29
|
-
.
|
|
29
|
+
.option("--replace-wrapper", "Replace a Claude Code process wrapper another tool set")
|
|
30
|
+
.action(async (opts) => {
|
|
30
31
|
const location = opts.location === undefined ? undefined : ViewerLocationSchema.parse(opts.location);
|
|
31
|
-
initCommand({ scope: scopeOf(opts), location });
|
|
32
|
+
await initCommand({ scope: scopeOf(opts), location, replaceWrapper: opts.replaceWrapper });
|
|
32
33
|
});
|
|
33
34
|
program
|
|
34
35
|
.command("ls")
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AACA,iCAAiC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACvE,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC3F,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGlD;;;;;GAKG;AACH,SAAS,OAAO,CAAC,IAAwB;IACvC,OAAO,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AACjD,CAAC;AAED,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE;KAC1B,IAAI,CAAC,UAAU,CAAC;KAChB,WAAW,CAAC,kDAAkD,CAAC,CAAC;AAEnE,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/viewer.d.ts
CHANGED
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
import type { ViewerLocation } from "../viewer";
|
|
2
2
|
import type { ModProject } from "./project";
|
|
3
|
+
/** How `setUpViewer` sets up the viewer. */
|
|
4
|
+
export interface ViewerSetup {
|
|
5
|
+
/** Where Claude opens in VS Code; a location already set is kept when absent */
|
|
6
|
+
location?: ViewerLocation;
|
|
7
|
+
/** Build the relay, set it as Claude Code's process wrapper and install the viewer extension; `init` does, `add` only checks */
|
|
8
|
+
install?: boolean;
|
|
9
|
+
/** Replace a process wrapper some other tool set */
|
|
10
|
+
replaceWrapper?: boolean;
|
|
11
|
+
}
|
|
3
12
|
/**
|
|
4
|
-
* @brief Sets up where mods are seen and prints what it found
|
|
5
|
-
* Code settings
|
|
6
|
-
*
|
|
13
|
+
* @brief Sets up where mods are seen and prints what it found. Every run points the
|
|
14
|
+
* project's VS Code settings at the extension's own chat. With `install`, it
|
|
15
|
+
* also builds the relay the sessions run through, sets it as Claude Code's
|
|
16
|
+
* process wrapper, and installs the viewer extension; without, it says when
|
|
17
|
+
* that is still to do.
|
|
7
18
|
*
|
|
8
19
|
* @param project - Scope to set up; VS Code settings are written only for `project`.
|
|
9
|
-
* @param
|
|
20
|
+
* @param setup - Viewer location, whether to install, and whether to replace another tool's wrapper.
|
|
10
21
|
*/
|
|
11
|
-
export declare function setUpViewer(project: ModProject,
|
|
22
|
+
export declare function setUpViewer(project: ModProject, setup?: ViewerSetup): Promise<void>;
|
|
12
23
|
//# sourceMappingURL=viewer.d.ts.map
|
package/dist/cli/viewer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"viewer.d.ts","sourceRoot":"","sources":["../../src/cli/viewer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"viewer.d.ts","sourceRoot":"","sources":["../../src/cli/viewer.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C,4CAA4C;AAC5C,MAAM,WAAW,WAAW;IAC1B,gFAAgF;IAChF,QAAQ,CAAC,EAAQ,cAAc,CAAC;IAChC,gIAAgI;IAChI,OAAO,CAAC,EAAS,OAAO,CAAC;IACzB,oDAAoD;IACpD,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAwDD;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqB7F"}
|
package/dist/cli/viewer.js
CHANGED
|
@@ -1,33 +1,91 @@
|
|
|
1
1
|
// packages/mods/src/cli/viewer.ts
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import { c, lineError, lineInfo, lineSuccess, lineWarn } from "@g3nomaly/core/cli";
|
|
4
|
+
import { MIN_ENGINE_VERSION, compareVersions, configureViewer, findClaudeExtension, installRelay, installViewer, machineSettingsPath, relayBinaryPath, setProcessWrapper, } from "../viewer";
|
|
5
|
+
/** Checks the Claude Code extension's version against the one the mod API needs. */
|
|
6
|
+
function checkClaudeExtension() {
|
|
7
|
+
const extension = findClaudeExtension();
|
|
8
|
+
if (extension === null) {
|
|
9
|
+
console.log(lineWarn(`Claude Code for VS Code is not installed. Install it from the marketplace (anthropic.claude-code), ${MIN_ENGINE_VERSION} or newer.`));
|
|
10
|
+
}
|
|
11
|
+
else if (compareVersions(extension.version, MIN_ENGINE_VERSION) < 0) {
|
|
12
|
+
console.log(lineWarn(`Claude Code for VS Code is ${extension.version}; mods need ${MIN_ENGINE_VERSION} or newer. Update the extension.`));
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** Builds the relay and makes Claude Code launch its sessions through it. */
|
|
16
|
+
async function setUpRelay(replaceWrapper) {
|
|
17
|
+
const relay = await installRelay();
|
|
18
|
+
if (relay.kind === "failed") {
|
|
19
|
+
console.log(lineError(`Could not build the relay at ${c.file(relay.binary)}: ${relay.reason}`));
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (relay.kind === "built")
|
|
23
|
+
console.log(lineSuccess(`Built the relay ${c.dim(`(${c.file(relay.binary)})`)}`));
|
|
24
|
+
const wrapper = setProcessWrapper(relay.binary, { force: replaceWrapper });
|
|
25
|
+
switch (wrapper.kind) {
|
|
26
|
+
case "written":
|
|
27
|
+
console.log(lineSuccess(`Claude Code sessions start through the relay ${c.dim(`(${c.file(wrapper.file)})`)}`));
|
|
28
|
+
break;
|
|
29
|
+
case "taken":
|
|
30
|
+
console.log(lineWarn(`claudeCode.claudeProcessWrapper is already ${c.file(wrapper.current)}; left in place. Run ${c.cmd("g3n-mods init --replace-wrapper")} to use the relay.`));
|
|
31
|
+
break;
|
|
32
|
+
case "unreadable":
|
|
33
|
+
console.log(lineWarn(`${c.file(wrapper.file)} is not plain JSON — add by hand: "claudeCode.claudeProcessWrapper": "${relay.binary}"`));
|
|
34
|
+
break;
|
|
35
|
+
case "unchanged":
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** Installs the viewer extension that draws the mods in an editor tab. */
|
|
40
|
+
function setUpViewerExtension() {
|
|
41
|
+
const viewer = installViewer();
|
|
42
|
+
switch (viewer.kind) {
|
|
43
|
+
case "installed":
|
|
44
|
+
console.log(lineSuccess(`Installed the mods viewer. Click its button in the editor title bar, or run ${c.cmd("g3n Mods: Open Mods Viewer")}.`));
|
|
45
|
+
break;
|
|
46
|
+
case "no-cli":
|
|
47
|
+
console.log(lineWarn(`VS Code's ${c.cmd("code")} command was not found. Install the viewer by hand: Extensions → … → Install from VSIX → ${c.file(viewer.vsix)}`));
|
|
48
|
+
break;
|
|
49
|
+
case "no-package":
|
|
50
|
+
console.log(lineError(`The viewer package is missing (${c.file(viewer.vsix)}); reinstall @g3nomaly/mods.`));
|
|
51
|
+
break;
|
|
52
|
+
case "failed":
|
|
53
|
+
console.log(lineError(`Installing the viewer failed: ${viewer.reason}`));
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
4
57
|
/**
|
|
5
|
-
* @brief Sets up where mods are seen and prints what it found
|
|
6
|
-
* Code settings
|
|
7
|
-
*
|
|
58
|
+
* @brief Sets up where mods are seen and prints what it found. Every run points the
|
|
59
|
+
* project's VS Code settings at the extension's own chat. With `install`, it
|
|
60
|
+
* also builds the relay the sessions run through, sets it as Claude Code's
|
|
61
|
+
* process wrapper, and installs the viewer extension; without, it says when
|
|
62
|
+
* that is still to do.
|
|
8
63
|
*
|
|
9
64
|
* @param project - Scope to set up; VS Code settings are written only for `project`.
|
|
10
|
-
* @param
|
|
65
|
+
* @param setup - Viewer location, whether to install, and whether to replace another tool's wrapper.
|
|
11
66
|
*/
|
|
12
|
-
export function setUpViewer(project,
|
|
67
|
+
export async function setUpViewer(project, setup = {}) {
|
|
13
68
|
if (project.scope === "project") {
|
|
14
|
-
const result = configureViewer(project.projectRoot, location);
|
|
69
|
+
const result = configureViewer(project.projectRoot, setup.location);
|
|
15
70
|
if (result.kind === "written") {
|
|
16
|
-
console.log(lineSuccess(`VS Code opens Claude in its
|
|
71
|
+
console.log(lineSuccess(`VS Code opens Claude in its own chat view ${c.dim(`(${c.file(result.file)})`)}`));
|
|
17
72
|
}
|
|
18
73
|
else if (result.kind === "unreadable") {
|
|
19
74
|
console.log(lineWarn(`${c.file(result.file)} is not plain JSON — add these settings by hand: ${JSON.stringify(result.settings)}`));
|
|
20
75
|
}
|
|
21
76
|
}
|
|
22
|
-
|
|
23
|
-
if (
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
else {
|
|
30
|
-
console.log(lineInfo(`Claude Code for VS Code ${extension.version} draws mod panes. Run ${c.cmd("Claude Code: Open in New Window")} to give them a window of their own.`));
|
|
77
|
+
checkClaudeExtension();
|
|
78
|
+
if (setup.install === true) {
|
|
79
|
+
await setUpRelay(setup.replaceWrapper === true);
|
|
80
|
+
setUpViewerExtension();
|
|
81
|
+
console.log(lineInfo("Sessions started from now on show their mods in the viewer; restart open ones."));
|
|
82
|
+
return;
|
|
31
83
|
}
|
|
84
|
+
const settings = machineSettingsPath();
|
|
85
|
+
const isSetUp = fs.existsSync(relayBinaryPath()) && fs.existsSync(settings) && fs.readFileSync(settings, "utf8").includes(relayBinaryPath());
|
|
86
|
+
if (!isSetUp)
|
|
87
|
+
console.log(lineInfo(`Run ${c.cmd("g3n-mods init")} once to set up the viewer the mods are drawn in.`));
|
|
88
|
+
else
|
|
89
|
+
console.log(lineInfo("Mods show in the viewer of sessions started from now on; in a running one, run /reload-plugins."));
|
|
32
90
|
}
|
|
33
91
|
//# sourceMappingURL=viewer.js.map
|
package/dist/cli/viewer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"viewer.js","sourceRoot":"","sources":["../../src/cli/viewer.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"viewer.js","sourceRoot":"","sources":["../../src/cli/viewer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/relay/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// packages/mods/src/relay/index.ts
|
|
2
|
+
import { runRelay } from "./relay";
|
|
3
|
+
const [claudePath, ...args] = process.argv.slice(2);
|
|
4
|
+
if (claudePath === undefined) {
|
|
5
|
+
console.error("g3n-mods-relay: set as claudeCode.claudeProcessWrapper, it is launched as `<relay> <claude> [args...]`; no Claude Code path was given.");
|
|
6
|
+
process.exit(2);
|
|
7
|
+
}
|
|
8
|
+
process.exit(await runRelay(claudePath, args));
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/relay/index.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,MAAM,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACpD,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;IAC7B,OAAO,CAAC,KAAK,CAAC,wIAAwI,CAAC,CAAC;IACxJ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AACD,OAAO,CAAC,IAAI,CAAC,MAAM,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cuts a byte stream into whole lines. Holds the unfinished tail of each
|
|
3
|
+
* chunk until its newline arrives, so a writer can put its own lines between
|
|
4
|
+
* the stream's lines without splitting one.
|
|
5
|
+
*
|
|
6
|
+
* Created once per stream by `runRelay`, which feeds it every chunk the
|
|
7
|
+
* extension or Claude writes and acts on each line it returns.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* const lines = new LineSplitter();
|
|
11
|
+
* for (const line of lines.push(chunk)) forward(line);
|
|
12
|
+
*/
|
|
13
|
+
export declare class LineSplitter {
|
|
14
|
+
private tail;
|
|
15
|
+
private readonly decoder;
|
|
16
|
+
/**
|
|
17
|
+
* Adds a chunk and returns the lines it completed, each without its newline.
|
|
18
|
+
*
|
|
19
|
+
* @returns the completed lines; empty while the chunk ends mid-line
|
|
20
|
+
*/
|
|
21
|
+
push(chunk: Uint8Array | string): string[];
|
|
22
|
+
/** Returns what is left when the stream ends, or `undefined` when it ended on a newline. */
|
|
23
|
+
flush(): string | undefined;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=lines.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lines.d.ts","sourceRoot":"","sources":["../../src/relay/lines.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,IAAI,CAAM;IAClB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAE7C;;;;OAIG;IACH,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,GAAG,MAAM,EAAE,CAKzC;IAED,4FAA4F;IAC5F,KAAK,IAAI,MAAM,GAAG,SAAS,CAI1B;CACF"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// packages/mods/src/relay/lines.ts
|
|
2
|
+
/**
|
|
3
|
+
* Cuts a byte stream into whole lines. Holds the unfinished tail of each
|
|
4
|
+
* chunk until its newline arrives, so a writer can put its own lines between
|
|
5
|
+
* the stream's lines without splitting one.
|
|
6
|
+
*
|
|
7
|
+
* Created once per stream by `runRelay`, which feeds it every chunk the
|
|
8
|
+
* extension or Claude writes and acts on each line it returns.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* const lines = new LineSplitter();
|
|
12
|
+
* for (const line of lines.push(chunk)) forward(line);
|
|
13
|
+
*/
|
|
14
|
+
export class LineSplitter {
|
|
15
|
+
tail = "";
|
|
16
|
+
decoder = new TextDecoder();
|
|
17
|
+
/**
|
|
18
|
+
* Adds a chunk and returns the lines it completed, each without its newline.
|
|
19
|
+
*
|
|
20
|
+
* @returns the completed lines; empty while the chunk ends mid-line
|
|
21
|
+
*/
|
|
22
|
+
push(chunk) {
|
|
23
|
+
const text = typeof chunk === "string" ? chunk : this.decoder.decode(chunk, { stream: true });
|
|
24
|
+
const parts = (this.tail + text).split("\n");
|
|
25
|
+
this.tail = parts.pop() ?? "";
|
|
26
|
+
return parts;
|
|
27
|
+
}
|
|
28
|
+
/** Returns what is left when the stream ends, or `undefined` when it ended on a newline. */
|
|
29
|
+
flush() {
|
|
30
|
+
const rest = this.tail + this.decoder.decode();
|
|
31
|
+
this.tail = "";
|
|
32
|
+
return rest === "" ? undefined : rest;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=lines.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lines.js","sourceRoot":"","sources":["../../src/relay/lines.ts"],"names":[],"mappings":"AAAA,mCAAmC;AAEnC;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,YAAY;IACf,IAAI,GAAG,EAAE,CAAC;IACD,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAE7C;;;;OAIG;IACH,IAAI,CAAC,KAA0B;QAC7B,MAAM,IAAI,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9F,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,4FAA4F;IAC5F,KAAK;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QAC/C,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC;QACf,OAAO,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;IACxC,CAAC;CACF"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { SessionInfo } from "./sessions";
|
|
3
|
+
/** The surface the viewer draws as, and the client id it attaches under. */
|
|
4
|
+
export declare const VIEWER_SURFACE = "vscode";
|
|
5
|
+
export declare const VIEWER_CLIENT_ID = "g3n-viewer";
|
|
6
|
+
/** Prefix of the request ids the relay gives the control requests it sends for a viewer. */
|
|
7
|
+
export declare const RELAY_REQUEST_PREFIX = "g3nv:";
|
|
8
|
+
/** The engine's UI requests a viewer may send; the relay refuses every other subtype. */
|
|
9
|
+
export declare const ViewerRequestSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
10
|
+
subtype: z.ZodLiteral<"ui_render">;
|
|
11
|
+
component: z.ZodString;
|
|
12
|
+
instance_id: z.ZodString;
|
|
13
|
+
props: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
14
|
+
viewport: z.ZodOptional<z.ZodObject<{
|
|
15
|
+
columns: z.ZodNumber;
|
|
16
|
+
rows: z.ZodNumber;
|
|
17
|
+
}, z.core.$strip>>;
|
|
18
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
19
|
+
subtype: z.ZodLiteral<"ui_press">;
|
|
20
|
+
plugin: z.ZodString;
|
|
21
|
+
handle: z.ZodNumber;
|
|
22
|
+
key: z.ZodOptional<z.ZodString>;
|
|
23
|
+
href: z.ZodOptional<z.ZodString>;
|
|
24
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
25
|
+
subtype: z.ZodLiteral<"ui_input">;
|
|
26
|
+
plugin: z.ZodString;
|
|
27
|
+
handle: z.ZodNumber;
|
|
28
|
+
kind: z.ZodEnum<{
|
|
29
|
+
change: "change";
|
|
30
|
+
submit: "submit";
|
|
31
|
+
}>;
|
|
32
|
+
value: z.ZodString;
|
|
33
|
+
key: z.ZodOptional<z.ZodString>;
|
|
34
|
+
component: z.ZodOptional<z.ZodString>;
|
|
35
|
+
instance_id: z.ZodOptional<z.ZodString>;
|
|
36
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
37
|
+
subtype: z.ZodLiteral<"ui_select">;
|
|
38
|
+
plugin: z.ZodString;
|
|
39
|
+
handle: z.ZodNumber;
|
|
40
|
+
value: z.ZodString;
|
|
41
|
+
key: z.ZodOptional<z.ZodString>;
|
|
42
|
+
component: z.ZodOptional<z.ZodString>;
|
|
43
|
+
instance_id: z.ZodOptional<z.ZodString>;
|
|
44
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
45
|
+
subtype: z.ZodLiteral<"ui_panes">;
|
|
46
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
47
|
+
subtype: z.ZodLiteral<"ui_close">;
|
|
48
|
+
id: z.ZodString;
|
|
49
|
+
}, z.core.$strip>], "subtype">;
|
|
50
|
+
export type ViewerRequest = z.infer<typeof ViewerRequestSchema>;
|
|
51
|
+
/** One line a viewer sends the relay: a UI request it numbers itself. */
|
|
52
|
+
export declare const ViewerMessageSchema: z.ZodObject<{
|
|
53
|
+
id: z.ZodString;
|
|
54
|
+
request: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
55
|
+
subtype: z.ZodLiteral<"ui_render">;
|
|
56
|
+
component: z.ZodString;
|
|
57
|
+
instance_id: z.ZodString;
|
|
58
|
+
props: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
59
|
+
viewport: z.ZodOptional<z.ZodObject<{
|
|
60
|
+
columns: z.ZodNumber;
|
|
61
|
+
rows: z.ZodNumber;
|
|
62
|
+
}, z.core.$strip>>;
|
|
63
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
64
|
+
subtype: z.ZodLiteral<"ui_press">;
|
|
65
|
+
plugin: z.ZodString;
|
|
66
|
+
handle: z.ZodNumber;
|
|
67
|
+
key: z.ZodOptional<z.ZodString>;
|
|
68
|
+
href: z.ZodOptional<z.ZodString>;
|
|
69
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
70
|
+
subtype: z.ZodLiteral<"ui_input">;
|
|
71
|
+
plugin: z.ZodString;
|
|
72
|
+
handle: z.ZodNumber;
|
|
73
|
+
kind: z.ZodEnum<{
|
|
74
|
+
change: "change";
|
|
75
|
+
submit: "submit";
|
|
76
|
+
}>;
|
|
77
|
+
value: z.ZodString;
|
|
78
|
+
key: z.ZodOptional<z.ZodString>;
|
|
79
|
+
component: z.ZodOptional<z.ZodString>;
|
|
80
|
+
instance_id: z.ZodOptional<z.ZodString>;
|
|
81
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
82
|
+
subtype: z.ZodLiteral<"ui_select">;
|
|
83
|
+
plugin: z.ZodString;
|
|
84
|
+
handle: z.ZodNumber;
|
|
85
|
+
value: z.ZodString;
|
|
86
|
+
key: z.ZodOptional<z.ZodString>;
|
|
87
|
+
component: z.ZodOptional<z.ZodString>;
|
|
88
|
+
instance_id: z.ZodOptional<z.ZodString>;
|
|
89
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
90
|
+
subtype: z.ZodLiteral<"ui_panes">;
|
|
91
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
92
|
+
subtype: z.ZodLiteral<"ui_close">;
|
|
93
|
+
id: z.ZodString;
|
|
94
|
+
}, z.core.$strip>], "subtype">;
|
|
95
|
+
}, z.core.$strip>;
|
|
96
|
+
export type ViewerMessage = z.infer<typeof ViewerMessageSchema>;
|
|
97
|
+
/** One line the relay sends a viewer. */
|
|
98
|
+
export type RelayMessage =
|
|
99
|
+
/** The session the relay runs, on connect and whenever it learns more */
|
|
100
|
+
{
|
|
101
|
+
type: "session";
|
|
102
|
+
session: SessionInfo;
|
|
103
|
+
}
|
|
104
|
+
/** The engine's answer to a viewer request, or why it failed */
|
|
105
|
+
| {
|
|
106
|
+
type: "response";
|
|
107
|
+
id: string;
|
|
108
|
+
response?: unknown;
|
|
109
|
+
error?: string;
|
|
110
|
+
}
|
|
111
|
+
/** An engine push a viewer acts on: `ui_panes` (the pane roster) or `ui_invalidate` (redraw) */
|
|
112
|
+
| {
|
|
113
|
+
type: "push";
|
|
114
|
+
push: Record<string, unknown>;
|
|
115
|
+
};
|
|
116
|
+
/** Subtypes of the engine's `system` messages the relay copies to every viewer. */
|
|
117
|
+
export declare const RELAYED_PUSHES: Set<string>;
|
|
118
|
+
/**
|
|
119
|
+
* The control request a viewer request becomes on Claude's stdin: the
|
|
120
|
+
* viewer's surface and client id are filled in where the engine takes them.
|
|
121
|
+
*/
|
|
122
|
+
export declare function toControlRequest(request: ViewerRequest): Record<string, unknown>;
|
|
123
|
+
//# sourceMappingURL=protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/relay/protocol.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,4EAA4E;AAC5E,eAAO,MAAM,cAAc,WAAa,CAAC;AACzC,eAAO,MAAM,gBAAgB,eAAe,CAAC;AAE7C,4FAA4F;AAC5F,eAAO,MAAM,oBAAoB,UAAU,CAAC;AAE5C,yFAAyF;AACzF,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8BAoC9B,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,yEAAyE;AACzE,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAG9B,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,yCAAyC;AACzC,MAAM,MAAM,YAAY;AACtB,yEAAyE;AACvE;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE;AAC3C,gEAAgE;GAC9D;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE;AACtE,gGAAgG;GAC9F;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC;AAEpD,mFAAmF;AACnF,eAAO,MAAM,cAAc,aAAyC,CAAC;AAErE;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAYhF"}
|