openclaw-codex-app-server 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +22 -0
- package/LICENSE +21 -0
- package/README.md +129 -0
- package/index.ts +69 -0
- package/openclaw.plugin.json +105 -0
- package/package.json +28 -0
- package/src/client.test.ts +332 -0
- package/src/client.ts +2914 -0
- package/src/config.ts +103 -0
- package/src/controller.test.ts +1177 -0
- package/src/controller.ts +3232 -0
- package/src/format.test.ts +502 -0
- package/src/format.ts +869 -0
- package/src/openclaw-plugin-sdk.d.ts +237 -0
- package/src/pending-input.test.ts +298 -0
- package/src/pending-input.ts +785 -0
- package/src/state.test.ts +228 -0
- package/src/state.ts +354 -0
- package/src/thread-picker.test.ts +47 -0
- package/src/thread-picker.ts +98 -0
- package/src/thread-selection.test.ts +89 -0
- package/src/thread-selection.ts +106 -0
- package/src/types.ts +372 -0
- package/tsconfig.json +24 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Repository Guidelines
|
|
2
|
+
|
|
3
|
+
## Project Structure & Module Organization
|
|
4
|
+
`index.ts` is the plugin entrypoint and registers commands, services, and interactive handlers. Core implementation lives in [`src/`](./src): controller flow in `controller.ts`, API/client integration in `client.ts`, configuration in `config.ts`, state and thread helpers in `state.ts`, `thread-picker.ts`, and `thread-selection.ts`, and user-facing text formatting in `format.ts`. Tests are colocated with source files as `src/*.test.ts`. Plugin metadata lives in `openclaw.plugin.json`; package and TypeScript settings are in `package.json` and `tsconfig.json`.
|
|
5
|
+
|
|
6
|
+
## Build, Test, and Development Commands
|
|
7
|
+
Use `pnpm` for local work.
|
|
8
|
+
|
|
9
|
+
- `pnpm test`: run the Vitest suite once.
|
|
10
|
+
- `pnpm typecheck`: run strict TypeScript checking with `tsc --noEmit`.
|
|
11
|
+
- `pnpm openclaw plugins install --link /path/to/openclaw-codex-app-server`: link this package into a local OpenClaw checkout for manual integration testing.
|
|
12
|
+
|
|
13
|
+
There is no separate build step in this repository; correctness is gated by tests and typechecking.
|
|
14
|
+
|
|
15
|
+
## Coding Style & Naming Conventions
|
|
16
|
+
Write TypeScript targeting Node ESM (`"module": "NodeNext"`). Match the existing style: 2-space indentation, double quotes, semicolons, and small focused helpers. Use `PascalCase` for classes and types, `camelCase` for functions and variables, and `SCREAMING_SNAKE_CASE` for shared constants such as command lists or namespace identifiers. Keep command and plugin-facing strings explicit and near the registration code when possible.
|
|
17
|
+
|
|
18
|
+
## Testing Guidelines
|
|
19
|
+
Tests use Vitest and should stay next to the code they cover, named `*.test.ts`. Prefer narrow unit tests over broad fixtures; most existing tests assert exact payloads and formatting behavior. Run `pnpm test` and `pnpm typecheck` before opening a PR. Add or update tests for any command handling, thread-selection logic, formatting branch, or protocol-shape change.
|
|
20
|
+
|
|
21
|
+
## Commit & Pull Request Guidelines
|
|
22
|
+
Follow the repository’s existing commit style: short imperative subjects, often with a `Plugin:` prefix, for example `Plugin: restore Codex interactive workflows`. Keep commits scoped to one behavior change. PRs should include a concise summary, linked issue or context, and the exact validation performed (`pnpm test`, `pnpm typecheck`, manual OpenClaw plugin exercise). Include screenshots or message transcripts when changing interactive Telegram or Discord flows.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# OpenClaw Codex App Server Plugin
|
|
2
|
+
|
|
3
|
+
Codex App Server as an OpenClaw plugin for Telegram and Discord conversations. It binds a chat to a Codex thread, forwards plain-text messages into that thread, and exposes command-driven controls for resume, planning, review, model selection, compaction, and more.
|
|
4
|
+
|
|
5
|
+
## Local Setup Before OpenClaw PR #45318 Lands
|
|
6
|
+
|
|
7
|
+
This plugin targets the plugin interface from [openclaw/openclaw#45318](https://github.com/openclaw/openclaw/pull/45318). Until that work is merged and shipped in the latest OpenClaw release, develop against a local OpenClaw checkout on that PR branch or `main` once merged.
|
|
8
|
+
|
|
9
|
+
### 0. Clone this repository
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
git clone <this-repo-url>
|
|
13
|
+
cd openclaw-codex-app-server
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
### 1. Check out OpenClaw with the plugin interface
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
git clone https://github.com/openclaw/openclaw.git
|
|
20
|
+
cd openclaw
|
|
21
|
+
gh pr checkout 45318
|
|
22
|
+
pnpm install
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
If you are not using `gh`, fetch the PR directly:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
git fetch origin pull/45318/head:pr-45318
|
|
29
|
+
git checkout pr-45318
|
|
30
|
+
pnpm install
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Once the PR is merged, use `main` instead.
|
|
34
|
+
|
|
35
|
+
### 2. Point this plugin repo at your local OpenClaw checkout
|
|
36
|
+
|
|
37
|
+
From this repository:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pnpm add -D openclaw@file:/absolute/path/to/openclaw
|
|
41
|
+
pnpm install
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
That makes the local `openclaw` package available to this plugin before a published release includes the new interface.
|
|
45
|
+
|
|
46
|
+
### 3. Install the plugin from your local checkout
|
|
47
|
+
|
|
48
|
+
From the openclaw repository:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pnpm openclaw plugins install --link "/absolute/path/to/openclaw-codex-app-server"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 4. Start OpenClaw
|
|
55
|
+
|
|
56
|
+
From your OpenClaw checkout:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
pnpm gateway:watch
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Typical Workflow
|
|
63
|
+
|
|
64
|
+
1. Start in the Telegram or Discord conversation where you want Codex bound.
|
|
65
|
+
2. Run `/codex_resume`.
|
|
66
|
+
3. Use the buttons to browse projects and threads, or pass filters in the command.
|
|
67
|
+
4. Once bound, plain text in that conversation routes to the selected Codex thread.
|
|
68
|
+
5. Use the control commands below as needed.
|
|
69
|
+
|
|
70
|
+
Buttons are presented for project and thread selection, model switching, and skill shortcuts. If your filter is ambiguous, the plugin sends a picker instead of guessing.
|
|
71
|
+
|
|
72
|
+
## Command Reference
|
|
73
|
+
|
|
74
|
+
| Command | What it does | Notes / examples |
|
|
75
|
+
| --- | --- | --- |
|
|
76
|
+
| `/codex_resume` | Bind this conversation to a Codex thread. | With no args, opens a picker for recent sessions in the current workspace. |
|
|
77
|
+
| `/codex_resume --projects` | Browse projects first. | Opens a project picker, then a thread picker. |
|
|
78
|
+
| `/codex_resume --all` | Search recent sessions across projects. | Useful when the thread is not in the current workspace. |
|
|
79
|
+
| `/codex_resume --cwd ~/github/openclaw` | Restrict browsing/search to one workspace. | `--cwd` accepts an absolute path or `~/...`. |
|
|
80
|
+
| `/codex_resume --sync` | Resume and try to sync the chat/topic name to the Codex thread. | You can combine this with other flags. |
|
|
81
|
+
| `/codex_resume release-fix` | Resume a matching thread by title or id. | If more than one thread matches, you get buttons to choose. |
|
|
82
|
+
| `/codex_status` | Show the current binding and thread state. | Includes thread id, model, workspace, sandbox, and permissions when available. |
|
|
83
|
+
| `/codex_detach` | Unbind this conversation from Codex. | Stops routing plain text from this conversation into the bound thread. |
|
|
84
|
+
| `/codex_stop` | Interrupt the active Codex run. | Only applies when a turn is currently in progress. |
|
|
85
|
+
| `/codex_steer <message>` | Send follow-up steer text to an active run. | Example: `/codex_steer focus on the failing tests first` |
|
|
86
|
+
| `/codex_plan <goal>` | Ask Codex to plan instead of execute. | The plugin relays plan questions and the final plan back into chat. |
|
|
87
|
+
| `/codex_plan off` | Exit plan mode for this conversation. | Interrupts a lingering plan run so future turns go back to default coding mode. |
|
|
88
|
+
| `/codex_review` | Review the current uncommitted changes in the bound workspace. | Requires an existing binding. |
|
|
89
|
+
| `/codex_review <focus>` | Review with custom instructions. | Example: `/codex_review focus on thread selection regressions` |
|
|
90
|
+
| `/codex_compact` | Compact the bound Codex thread. | The plugin posts progress and final context usage. |
|
|
91
|
+
| `/codex_skills` | List available Codex skills for the workspace. | Adds buttons for up to eight skill shortcuts. |
|
|
92
|
+
| `/codex_skills review` | Filter the skills list. | Matches skill name, description, or cwd. |
|
|
93
|
+
| `/codex_experimental` | List experimental features reported by Codex. | Read-only. |
|
|
94
|
+
| `/codex_mcp` | List configured MCP servers. | Shows auth state and counts for tools/resources/templates. |
|
|
95
|
+
| `/codex_mcp github` | Filter MCP servers. | Matches name and auth status. |
|
|
96
|
+
| `/codex_fast` | Toggle fast mode for the bound thread. | Equivalent to switching the service tier between default and fast. |
|
|
97
|
+
| `/codex_fast on|off|status` | Set or inspect fast mode explicitly. | Example: `/codex_fast status` |
|
|
98
|
+
| `/codex_model` | List models and show model-selection buttons. | If the conversation is not bound yet, it lists models only. |
|
|
99
|
+
| `/codex_model gpt-5.4` | Set the model for the bound thread. | Requires an existing binding. |
|
|
100
|
+
| `/codex_permissions` | Show account, rate-limit, and thread permission information. | Works with or without a current binding. |
|
|
101
|
+
| `/codex_init ...` | Forward `/init` to Codex. | Sends the alias straight through to the App Server. |
|
|
102
|
+
| `/codex_diff ...` | Forward `/diff` to Codex. | Sends the alias straight through to the App Server. |
|
|
103
|
+
| `/codex_rename <new name>` | Rename the bound Codex thread. | Example: `/codex_rename approval flow cleanup` |
|
|
104
|
+
| `/codex_rename --sync <new name>` | Rename the thread and try to sync the conversation/topic name too. | Requires an existing binding. |
|
|
105
|
+
|
|
106
|
+
## Screenshot Placeholders
|
|
107
|
+
|
|
108
|
+
- `[TODO screenshot] /codex_resume --projects` project picker
|
|
109
|
+
- `[TODO screenshot] /codex_resume` thread picker with buttons
|
|
110
|
+
- `[TODO screenshot] bound conversation after /codex_status`
|
|
111
|
+
- `[TODO screenshot] /codex_model` button list
|
|
112
|
+
|
|
113
|
+
## Plugin Config Notes
|
|
114
|
+
|
|
115
|
+
The plugin schema in [`openclaw.plugin.json`](./openclaw.plugin.json) supports:
|
|
116
|
+
|
|
117
|
+
- `transport`: `stdio` or `websocket`
|
|
118
|
+
- `command` and `args`: the Codex executable and CLI args for `stdio`
|
|
119
|
+
- `url`, `authToken`, `headers`: connection settings for `websocket`
|
|
120
|
+
- `defaultWorkspaceDir`: fallback workspace for unbound actions
|
|
121
|
+
- `defaultModel`: model used when a new thread starts without an explicit selection
|
|
122
|
+
- `defaultServiceTier`: default service tier for new turns
|
|
123
|
+
|
|
124
|
+
## Development Checks
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
pnpm test
|
|
128
|
+
pnpm typecheck
|
|
129
|
+
```
|
package/index.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
2
|
+
import { CodexPluginController } from "./src/controller.js";
|
|
3
|
+
import { INTERACTIVE_NAMESPACE } from "./src/types.js";
|
|
4
|
+
|
|
5
|
+
const COMMANDS = [
|
|
6
|
+
["codex_resume", "Resume or bind an existing Codex thread."],
|
|
7
|
+
["codex_detach", "Detach this conversation from the current Codex thread."],
|
|
8
|
+
["codex_status", "Show the current Codex binding and thread state."],
|
|
9
|
+
["codex_stop", "Stop the active Codex turn."],
|
|
10
|
+
["codex_steer", "Send a steer message to the active Codex turn."],
|
|
11
|
+
["codex_plan", "Ask Codex to produce a plan, or use 'off' to exit plan mode."],
|
|
12
|
+
["codex_review", "Run Codex review on the current changes."],
|
|
13
|
+
["codex_compact", "Compact the current Codex thread."],
|
|
14
|
+
["codex_skills", "List Codex skills."],
|
|
15
|
+
["codex_experimental", "List Codex experimental features."],
|
|
16
|
+
["codex_mcp", "List Codex MCP servers."],
|
|
17
|
+
["codex_fast", "Toggle Codex fast mode."],
|
|
18
|
+
["codex_model", "List or switch the Codex model."],
|
|
19
|
+
["codex_permissions", "Show Codex permissions and account status."],
|
|
20
|
+
["codex_init", "Forward /init to Codex."],
|
|
21
|
+
["codex_diff", "Forward /diff to Codex."],
|
|
22
|
+
["codex_rename", "Rename the Codex thread and sync the channel name when possible."],
|
|
23
|
+
] as const;
|
|
24
|
+
|
|
25
|
+
const plugin = {
|
|
26
|
+
id: "openclaw-codex-app-server",
|
|
27
|
+
name: "OpenClaw App Server",
|
|
28
|
+
description: "Codex App Server as an OpenClaw plugin.",
|
|
29
|
+
register(api: OpenClawPluginApi) {
|
|
30
|
+
const controller = new CodexPluginController(api);
|
|
31
|
+
|
|
32
|
+
api.registerService(controller.createService());
|
|
33
|
+
|
|
34
|
+
api.on("inbound_claim", async (event) => {
|
|
35
|
+
return await controller.handleInboundClaim(event);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
api.registerInteractiveHandler({
|
|
39
|
+
channel: "telegram",
|
|
40
|
+
namespace: INTERACTIVE_NAMESPACE,
|
|
41
|
+
handler: async (ctx) => {
|
|
42
|
+
await controller.handleTelegramInteractive(ctx);
|
|
43
|
+
return { handled: true };
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
api.registerInteractiveHandler({
|
|
48
|
+
channel: "discord",
|
|
49
|
+
namespace: INTERACTIVE_NAMESPACE,
|
|
50
|
+
handler: async (ctx) => {
|
|
51
|
+
await controller.handleDiscordInteractive(ctx);
|
|
52
|
+
return { handled: true };
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
for (const [name, description] of COMMANDS) {
|
|
57
|
+
api.registerCommand({
|
|
58
|
+
name,
|
|
59
|
+
description,
|
|
60
|
+
acceptsArgs: true,
|
|
61
|
+
handler: async (ctx) => {
|
|
62
|
+
return await controller.handleCommand(name, ctx);
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export default plugin;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "openclaw-codex-app-server",
|
|
3
|
+
"name": "OpenClaw Codex App Server",
|
|
4
|
+
"description": "Codex App Server as an OpenClaw plugin with bound Telegram and Discord conversations.",
|
|
5
|
+
"configSchema": {
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"properties": {
|
|
9
|
+
"enabled": {
|
|
10
|
+
"type": "boolean"
|
|
11
|
+
},
|
|
12
|
+
"transport": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"enum": [
|
|
15
|
+
"stdio",
|
|
16
|
+
"websocket"
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
"command": {
|
|
20
|
+
"type": "string"
|
|
21
|
+
},
|
|
22
|
+
"args": {
|
|
23
|
+
"type": "array",
|
|
24
|
+
"items": {
|
|
25
|
+
"type": "string"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"url": {
|
|
29
|
+
"type": "string"
|
|
30
|
+
},
|
|
31
|
+
"authToken": {
|
|
32
|
+
"type": "string"
|
|
33
|
+
},
|
|
34
|
+
"headers": {
|
|
35
|
+
"type": "object",
|
|
36
|
+
"additionalProperties": {
|
|
37
|
+
"type": "string"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"requestTimeoutMs": {
|
|
41
|
+
"type": "number",
|
|
42
|
+
"minimum": 100
|
|
43
|
+
},
|
|
44
|
+
"inputTimeoutMs": {
|
|
45
|
+
"type": "number",
|
|
46
|
+
"minimum": 1000
|
|
47
|
+
},
|
|
48
|
+
"defaultWorkspaceDir": {
|
|
49
|
+
"type": "string"
|
|
50
|
+
},
|
|
51
|
+
"defaultModel": {
|
|
52
|
+
"type": "string"
|
|
53
|
+
},
|
|
54
|
+
"defaultServiceTier": {
|
|
55
|
+
"type": "string"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"uiHints": {
|
|
60
|
+
"enabled": {
|
|
61
|
+
"label": "Enabled"
|
|
62
|
+
},
|
|
63
|
+
"transport": {
|
|
64
|
+
"label": "Transport"
|
|
65
|
+
},
|
|
66
|
+
"command": {
|
|
67
|
+
"label": "Codex Command",
|
|
68
|
+
"help": "Used for stdio mode. Defaults to codex."
|
|
69
|
+
},
|
|
70
|
+
"args": {
|
|
71
|
+
"label": "Codex Args",
|
|
72
|
+
"advanced": true
|
|
73
|
+
},
|
|
74
|
+
"url": {
|
|
75
|
+
"label": "WebSocket URL"
|
|
76
|
+
},
|
|
77
|
+
"authToken": {
|
|
78
|
+
"label": "WebSocket Bearer Token",
|
|
79
|
+
"sensitive": true
|
|
80
|
+
},
|
|
81
|
+
"headers": {
|
|
82
|
+
"label": "Extra Headers",
|
|
83
|
+
"advanced": true
|
|
84
|
+
},
|
|
85
|
+
"requestTimeoutMs": {
|
|
86
|
+
"label": "Request Timeout (ms)",
|
|
87
|
+
"advanced": true
|
|
88
|
+
},
|
|
89
|
+
"inputTimeoutMs": {
|
|
90
|
+
"label": "Input Timeout (ms)",
|
|
91
|
+
"advanced": true
|
|
92
|
+
},
|
|
93
|
+
"defaultWorkspaceDir": {
|
|
94
|
+
"label": "Default Workspace Dir"
|
|
95
|
+
},
|
|
96
|
+
"defaultModel": {
|
|
97
|
+
"label": "Default Model",
|
|
98
|
+
"advanced": true
|
|
99
|
+
},
|
|
100
|
+
"defaultServiceTier": {
|
|
101
|
+
"label": "Default Service Tier",
|
|
102
|
+
"advanced": true
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "openclaw-codex-app-server",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "OpenClaw plugin for Codex App Server conversations",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"openclaw": {
|
|
8
|
+
"extensions": [
|
|
9
|
+
"./index.ts"
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
"peerDependencies": {
|
|
13
|
+
"openclaw": "*"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"ws": "^8.18.3"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@types/node": "^24.6.0",
|
|
20
|
+
"openclaw": "2026.3.13",
|
|
21
|
+
"typescript": "^5.9.2",
|
|
22
|
+
"vitest": "^3.2.4"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"test": "vitest run",
|
|
26
|
+
"typecheck": "tsc --noEmit"
|
|
27
|
+
}
|
|
28
|
+
}
|