@zetaloop/chappie 1.0.0 → 1.1.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.
@@ -1,21 +1,21 @@
1
1
  import { createRequire } from "node:module"; const require = createRequire(import.meta.url);
2
2
  import {
3
3
  definitions
4
- } from "./chunk-DM523QRR.js";
4
+ } from "./chunk-3MLW5U2C.js";
5
5
  import {
6
6
  McpServer,
7
7
  ResourceTemplate,
8
8
  serveStdio
9
- } from "./chunk-K2VE2MDU.js";
10
- import "./chunk-GX4JWLHH.js";
9
+ } from "./chunk-QNDFCQ66.js";
10
+ import "./chunk-RQKWETGT.js";
11
11
  import {
12
12
  package_default
13
- } from "./chunk-DN7OHZK6.js";
13
+ } from "./chunk-DDBZIUBF.js";
14
14
  import {
15
15
  getDirectory,
16
16
  readConfig,
17
17
  resourceDescriptors
18
- } from "./chunk-GWYP7B66.js";
18
+ } from "./chunk-ASDHNBR2.js";
19
19
  import {
20
20
  __callDispose,
21
21
  __using
@@ -23,13 +23,37 @@ import {
23
23
 
24
24
  // src/codex-plugin.ts
25
25
  import { fork } from "node:child_process";
26
- import { mkdir, open } from "node:fs/promises";
26
+ import {
27
+ copyFile,
28
+ mkdir,
29
+ mkdtempDisposable,
30
+ open,
31
+ rename
32
+ } from "node:fs/promises";
27
33
  import { get } from "node:http";
28
34
  import { join } from "node:path";
29
- async function startProvider() {
35
+ async function setupCodex() {
30
36
  var _stack = [];
31
37
  try {
32
38
  await mkdir(getDirectory(), { recursive: true });
39
+ const temporary = __using(_stack, await mkdtempDisposable(
40
+ join(getDirectory(), ".chappie-")
41
+ ), true);
42
+ const staged = join(temporary.path, "codex.json");
43
+ await copyFile(new URL("./codex.json", import.meta.url), staged);
44
+ const path = join(getDirectory(), "codex.json");
45
+ await rename(staged, path);
46
+ return path;
47
+ } catch (_) {
48
+ var _error = _, _hasError = true;
49
+ } finally {
50
+ var _promise = __callDispose(_stack, _error, _hasError);
51
+ _promise && await _promise;
52
+ }
53
+ }
54
+ async function startProvider() {
55
+ var _stack = [];
56
+ try {
33
57
  const log = __using(_stack, await open(join(getDirectory(), "codex.log"), "a"), true);
34
58
  const child = fork(
35
59
  new URL("./cli.js", import.meta.url),
@@ -64,7 +88,8 @@ async function startProvider() {
64
88
  _promise && await _promise;
65
89
  }
66
90
  }
67
- async function serveCodexPlugin(chatgpt = false) {
91
+ async function serveCodexPlugin() {
92
+ await setupCodex();
68
93
  const config = await readConfig();
69
94
  await startProvider();
70
95
  const base = `http://127.0.0.1:${config.codex?.port ?? 24275}`;
@@ -91,8 +116,10 @@ async function serveCodexPlugin(chatgpt = false) {
91
116
  name: "chappie",
92
117
  version: package_default.version
93
118
  });
94
- for (const definition of definitions) {
95
- const tool = server.registerTool(
119
+ for (const definition of definitions.filter(
120
+ (tool) => config.localTools || tool.name === "transfer"
121
+ )) {
122
+ server.registerTool(
96
123
  definition.name,
97
124
  {
98
125
  description: definition.description,
@@ -127,12 +154,10 @@ async function serveCodexPlugin(chatgpt = false) {
127
154
  };
128
155
  })
129
156
  ],
130
- ...result.details && typeof result.details === "object" ? { structuredContent: { details: result.details } } : {}
157
+ ...result.details && typeof result.details === "object" ? { _meta: { details: result.details } } : {}
131
158
  };
132
159
  }
133
160
  );
134
- if (chatgpt ? definition.name !== "transfer" : !config.localTools)
135
- tool.disable();
136
161
  }
137
162
  server.registerResource(
138
163
  "Session resource",
@@ -175,5 +200,6 @@ async function serveCodexPlugin(chatgpt = false) {
175
200
  }
176
201
  }
177
202
  export {
178
- serveCodexPlugin
203
+ serveCodexPlugin,
204
+ setupCodex
179
205
  };
package/dist/index.js CHANGED
@@ -1,24 +1,24 @@
1
1
  import { createRequire } from "node:module"; const require = createRequire(import.meta.url);
2
2
  import {
3
3
  journalHistory
4
- } from "./chunk-OWAAWZNT.js";
4
+ } from "./chunk-QTALHBOI.js";
5
5
  import {
6
6
  ProviderOutput,
7
7
  Session,
8
8
  createMessage
9
- } from "./chunk-5CKVVDZ2.js";
9
+ } from "./chunk-G4LG7HH2.js";
10
10
  import {
11
11
  localDeliveries,
12
12
  localTools
13
- } from "./chunk-DM523QRR.js";
13
+ } from "./chunk-3MLW5U2C.js";
14
+ import "./chunk-RQKWETGT.js";
14
15
  import "./chunk-EIPDEA3I.js";
15
- import "./chunk-GX4JWLHH.js";
16
16
  import {
17
17
  readConfig,
18
18
  toJSONSchema,
19
19
  transferDescription,
20
20
  transferInput
21
- } from "./chunk-GWYP7B66.js";
21
+ } from "./chunk-ASDHNBR2.js";
22
22
  import {
23
23
  __export
24
24
  } from "./chunk-UOFCCHBS.js";
@@ -4591,22 +4591,10 @@ async function chappie(pi) {
4591
4591
  };
4592
4592
  const session = new Session(host, config);
4593
4593
  const tools = localTools(session);
4594
- const names = new Set(tools.map((tool) => tool.name));
4595
- function updateTools() {
4596
- const desired = session.active ? ["transfer"] : session.localTools ? [...names] : [];
4597
- const active = pi.getActiveTools();
4598
- const enabled = active.filter((name) => names.has(name));
4599
- if (enabled.length === desired.length && enabled.every((name) => desired.includes(name)))
4600
- return;
4601
- pi.setActiveTools([
4602
- ...active.filter((name) => !names.has(name)),
4603
- ...desired
4604
- ]);
4605
- }
4606
4594
  const update = (ctx, selected = ctx.model) => {
4607
4595
  context = ctx;
4608
4596
  model = selected;
4609
- if (session.update()) updateTools();
4597
+ session.update();
4610
4598
  };
4611
4599
  pi.registerEntryRenderer(
4612
4600
  "chappie.notice",
package/dist/omp.js CHANGED
@@ -1,24 +1,24 @@
1
1
  import { createRequire } from "node:module"; const require = createRequire(import.meta.url);
2
2
  import {
3
3
  journalHistory
4
- } from "./chunk-OWAAWZNT.js";
4
+ } from "./chunk-QTALHBOI.js";
5
5
  import {
6
6
  ProviderOutput,
7
7
  Session,
8
8
  createMessage
9
- } from "./chunk-5CKVVDZ2.js";
9
+ } from "./chunk-G4LG7HH2.js";
10
10
  import {
11
11
  localTools
12
- } from "./chunk-DM523QRR.js";
12
+ } from "./chunk-3MLW5U2C.js";
13
+ import "./chunk-RQKWETGT.js";
13
14
  import {
14
15
  ipcEndpoint
15
16
  } from "./chunk-EIPDEA3I.js";
16
- import "./chunk-GX4JWLHH.js";
17
17
  import {
18
18
  getDirectory,
19
19
  readConfig,
20
20
  toJSONSchema
21
- } from "./chunk-GWYP7B66.js";
21
+ } from "./chunk-ASDHNBR2.js";
22
22
  import "./chunk-UOFCCHBS.js";
23
23
 
24
24
  // src/omp.ts
@@ -118,19 +118,7 @@ async function chappie(omp) {
118
118
  };
119
119
  const session = new Session(host, config);
120
120
  const tools = localTools(session);
121
- const names = new Set(tools.map((tool) => tool.name));
122
- async function updateTools() {
123
- const desired = session.active ? ["transfer"] : session.localTools ? [...names] : [];
124
- const active = omp.getActiveTools();
125
- const enabled = active.filter((name) => names.has(name));
126
- if (enabled.length === desired.length && enabled.every((name) => desired.includes(name)))
127
- return;
128
- await omp.setActiveTools([
129
- ...active.filter((name) => !names.has(name)),
130
- ...desired
131
- ]);
132
- }
133
- async function update(ctx) {
121
+ function update(ctx) {
134
122
  context = ctx;
135
123
  if (manager !== ctx.sessionManager) {
136
124
  unsubscribe?.();
@@ -139,7 +127,7 @@ async function chappie(omp) {
139
127
  const append = store.appendModelChange;
140
128
  const record = function(...args) {
141
129
  const result = append.apply(this, args);
142
- if (session.update()) void updateTools();
130
+ session.update();
143
131
  return result;
144
132
  };
145
133
  store.appendModelChange = record;
@@ -150,13 +138,13 @@ async function chappie(omp) {
150
138
  store.appendModelChange = append;
151
139
  };
152
140
  }
153
- if (session.update()) await updateTools();
141
+ session.update();
154
142
  }
155
143
  omp.on("session_start", (_event, ctx) => update(ctx));
156
144
  omp.on("session_switch", (_event, ctx) => update(ctx));
157
145
  omp.on("session_branch", (_event, ctx) => update(ctx));
158
- omp.on("session_tree", async (_event, ctx) => {
159
- await update(ctx);
146
+ omp.on("session_tree", (_event, ctx) => {
147
+ update(ctx);
160
148
  session.resetInputs();
161
149
  session.historyChanged();
162
150
  });
package/dist/opencode.js CHANGED
@@ -3,20 +3,20 @@ import {
3
3
  ProviderOutput,
4
4
  Session,
5
5
  createMessage
6
- } from "./chunk-5CKVVDZ2.js";
6
+ } from "./chunk-G4LG7HH2.js";
7
7
  import {
8
8
  definitions,
9
9
  localTools
10
- } from "./chunk-DM523QRR.js";
10
+ } from "./chunk-3MLW5U2C.js";
11
+ import "./chunk-RQKWETGT.js";
11
12
  import "./chunk-EIPDEA3I.js";
12
- import "./chunk-GX4JWLHH.js";
13
13
  import {
14
14
  historyPage,
15
15
  historyResult,
16
16
  readConfig,
17
17
  resourceDescriptors,
18
18
  toJSONSchema
19
- } from "./chunk-GWYP7B66.js";
19
+ } from "./chunk-ASDHNBR2.js";
20
20
  import {
21
21
  __export,
22
22
  exports_client3
@@ -564,7 +564,9 @@ var opencode_default = {
564
564
  })
565
565
  );
566
566
  await context.tool.transform((editor) => {
567
- for (const definition of definitions)
567
+ for (const definition of definitions.filter(
568
+ (tool) => config.localTools || tool.name === "transfer"
569
+ ))
568
570
  editor.add({
569
571
  name: definition.name,
570
572
  description: definition.description,
@@ -599,9 +601,6 @@ var opencode_default = {
599
601
  };
600
602
  state.busy = true;
601
603
  state.session.update();
602
- for (const tool of definitions)
603
- if (state.active() ? tool.name !== "transfer" : !state.session.localTools)
604
- delete event.tools[tool.name];
605
604
  if (state.active()) {
606
605
  event.messages = [];
607
606
  event.system = [];
@@ -1,19 +1,19 @@
1
1
  import { createRequire } from "node:module"; const require = createRequire(import.meta.url);
2
- import {
3
- IpcServer,
4
- source,
5
- sourceLabel
6
- } from "./chunk-EIPDEA3I.js";
7
2
  import {
8
3
  McpServer,
9
4
  ResourceTemplate,
10
5
  StdioServerTransport,
11
6
  serveStdio
12
- } from "./chunk-K2VE2MDU.js";
13
- import "./chunk-GX4JWLHH.js";
7
+ } from "./chunk-QNDFCQ66.js";
8
+ import "./chunk-RQKWETGT.js";
9
+ import {
10
+ IpcServer,
11
+ source,
12
+ sourceLabel
13
+ } from "./chunk-EIPDEA3I.js";
14
14
  import {
15
15
  package_default
16
- } from "./chunk-DN7OHZK6.js";
16
+ } from "./chunk-DDBZIUBF.js";
17
17
  import {
18
18
  array,
19
19
  boolean,
@@ -35,7 +35,7 @@ import {
35
35
  toolResult,
36
36
  transferDescription,
37
37
  transferInput
38
- } from "./chunk-GWYP7B66.js";
38
+ } from "./chunk-ASDHNBR2.js";
39
39
  import "./chunk-UOFCCHBS.js";
40
40
 
41
41
  // src/broker.ts
package/docs/setup.md CHANGED
@@ -1,12 +1,14 @@
1
1
  # Setup and configuration
2
2
 
3
- The broker is available as `chappie` after global installation, or through `pnpx -y @zetaloop/chappie`. Agent plugins connect to it from their own devices.
3
+ The broker is available as `chappie` after global installation. Agent plugins connect to it from their own devices.
4
4
 
5
5
  ## Codex
6
6
 
7
- Install the plugin from this repository's marketplace:
7
+ On the Codex device, install Chappie, create its model catalog, and add the plugin:
8
8
 
9
9
  ```sh
10
+ pnpm add -g @zetaloop/chappie@1
11
+ chappie codex setup
10
12
  codex plugin marketplace add zetaloop/chappie
11
13
  codex plugin add chappie@chappie
12
14
  ```
@@ -17,38 +19,37 @@ Enable `localTools` in Chappie's configuration. The installed plugin provides to
17
19
 
18
20
  ### Using the Chappie model
19
21
 
20
- To receive work in Codex, save the [model catalog](https://raw.githubusercontent.com/zetaloop/chappie/main/src/codex.json) locally and reference its absolute path in Codex's user configuration, `~/.codex/config.toml` or `$CODEX_HOME/config.toml`:
22
+ To receive work in Codex, select Chappie in Codex's user configuration, `~/.codex/config.toml` or `$CODEX_HOME/config.toml`:
21
23
 
22
24
  ```toml
23
25
  model_provider = "chappie"
24
26
  model = "chatgpt"
25
- model_catalog_json = "/absolute/path/to/codex.json"
27
+ model_catalog_json = "~/.chappie/codex.json"
26
28
 
27
29
  [model_providers.chappie]
28
30
  name = "Chappie"
29
31
  base_url = "http://127.0.0.1:24275/v1"
30
-
31
- [mcp_servers.chappie]
32
- command = "pnpx"
33
- args = ["-y", "@zetaloop/chappie", "codex", "--chatgpt"]
34
- env_vars = ["CODEX_HOME"]
35
32
  ```
36
33
 
37
- Restart the Codex app after changing its provider configuration. The plugin starts the local provider service.
34
+ Restart the Codex app after changing its provider configuration. The plugin starts the local provider service and refreshes the model catalog.
35
+
36
+ Start a new conversation or open an existing Chappie conversation to make it available to connected assistants. Existing conversations use their saved provider.
38
37
 
39
- To return to an ordinary model, restore its model, provider, and catalog settings and remove the `[mcp_servers.chappie]` override shown above, then restart the app. The installed plugin supplies the local tools.
38
+ To start new conversations with an ordinary model, restore its model, provider, and catalog settings, then restart the app.
40
39
 
41
40
  ## Configuration
42
41
 
43
42
  Settings live in `~/.chappie/config.json`. The broker and agent plugins read this file at startup; an absent file uses the defaults.
44
43
 
45
- | Setting | Default | Used by | Purpose |
46
- |---|---|---|---|
47
- | `ask` | `true` | Broker | Enable question widgets in ChatGPT. |
48
- | `cooldown` | `20` | Broker | Participation window, in seconds. |
49
- | `listen` | `false` | Broker | Accept TCP connections; `true` uses port `24274`, or supply a port number. |
50
- | `connect` | Local socket | Agent plugins | Broker hostname, optionally followed by `:port`. |
51
- | `localTools` | `false` | Agent plugins | Provide collaboration tools to ordinary models. |
44
+ Agent plugins provide `transfer` in every session. Enable `localTools` for the complete [local tool set](tools.md#local-tools).
45
+
46
+ | Setting | Default | Used by | Purpose |
47
+ | ------------ | ------------ | ------------- | -------------------------------------------------------------------------- |
48
+ | `ask` | `true` | Broker | Enable question widgets in ChatGPT. |
49
+ | `cooldown` | `20` | Broker | Participation window, in seconds. |
50
+ | `listen` | `false` | Broker | Accept TCP connections; `true` uses port `24274`, or supply a port number. |
51
+ | `connect` | Local socket | Agent plugins | Broker hostname, optionally followed by `:port`. |
52
+ | `localTools` | `false` | Agent plugins | Enable collaboration tools. |
52
53
 
53
54
  `cooldown` applies to each ChatGPT conversation and target session. Repeated initialization within the window returns [observation instructions](tools.md#participation). The window refreshes when a question widget first loads or a resource is accessed; `0` disables it.
54
55
 
@@ -74,9 +75,9 @@ Chappie discovers OpenCode's local background service automatically. For a stand
74
75
 
75
76
  ### Codex service
76
77
 
77
- | Setting | Default | Purpose |
78
- |---|---|---|
79
- | `codex.port` | `24275` | Local provider HTTP port. |
80
- | `codex.appServer` | Default control socket | Codex app-server endpoint: `unix://<path>` or a WebSocket URL. |
78
+ | Setting | Default | Purpose |
79
+ | ----------------- | -------------------------- | ------------------------------------------------------------ |
80
+ | `codex.port` | `24275` | Local provider HTTP port. |
81
+ | `codex.appServer` | Default CLI control socket | CLI app-server endpoint: `unix://<path>` or a WebSocket URL. |
81
82
 
82
83
  When changing `codex.port`, update `model_providers.chappie.base_url` in Codex's configuration to match.
package/docs/tools.md CHANGED
@@ -1,18 +1,18 @@
1
1
  # Tools
2
2
 
3
- ChatGPT uses the tools below. Agent sessions using ordinary models have a [local tool set](#local-models).
4
-
5
- | Tool | Purpose |
6
- |---|---|
7
- | `sessions` | Find sessions by agent, device, directory, or name. |
8
- | `init` | Select this ChatGPT conversation's default session and read its environment. |
9
- | `tools` | Read the selected session's native tool definitions. |
10
- | `call` | Execute a native tool batch. |
11
- | `chat` | Send an assistant message or answer a model request. |
12
- | `history` | Read the agent's transcript with entry IDs and timestamps. |
13
- | `transfer` | Exchange files and images with ChatGPT or another session. |
14
- | `ask` | Create a persistent question in ChatGPT. |
15
- | `ask_assert` | Confirm that its widget loaded. |
3
+ ChatGPT uses the tools below. Agent sessions also provide [local tools](#local-tools).
4
+
5
+ | Tool | Purpose |
6
+ | ------------ | ---------------------------------------------------------------------------- |
7
+ | `sessions` | Find sessions by agent, device, directory, or name. |
8
+ | `init` | Select this ChatGPT conversation's default session and read its environment. |
9
+ | `tools` | Read the selected session's native tool definitions. |
10
+ | `call` | Execute a native tool batch. |
11
+ | `chat` | Send an assistant message or answer a model request. |
12
+ | `history` | Read the agent's transcript with entry IDs and timestamps. |
13
+ | `transfer` | Exchange files and images with ChatGPT or another session. |
14
+ | `ask` | Create a persistent question in ChatGPT. |
15
+ | `ask_assert` | Confirm that its widget loaded. |
16
16
 
17
17
  ## Sessions
18
18
 
@@ -145,20 +145,20 @@ Retrieve files using `from`:
145
145
 
146
146
  Both sides use their existing broker connections and resolve paths on their own devices. Different agents use the same transfer operations. Completed files remain available when another file in the batch fails or is cancelled.
147
147
 
148
- ## Local models
148
+ ## Local tools
149
149
 
150
- Enable `localTools` in Chappie's configuration to provide these tools to ordinary models:
150
+ Every agent session provides `transfer`. Enable `localTools` in Chappie's configuration for the complete tool set:
151
151
 
152
- | Tool | Target |
153
- |---|---|
154
- | `sessions` | Online Chappie sessions, with the current local ID reported as `self`. |
155
- | `remote_tools` | Tool definitions from the required `sessionId`. |
156
- | `remote_call` | One native tool batch in the required `sessionId`. |
157
- | `remote_chat` | An assistant message or model-request reply in the required `sessionId`. |
158
- | `history` | The current local transcript, or a Chappie session named by `sessionId`. |
159
- | `transfer` | Local files and resources exchanged with Chappie sessions. |
152
+ | Tool | Target |
153
+ | -------------- | ------------------------------------------------------------------------ |
154
+ | `sessions` | Online Chappie sessions, with the current local ID reported as `self`. |
155
+ | `remote_tools` | Tool definitions from the required `sessionId`. |
156
+ | `remote_call` | One native tool batch in the required `sessionId`. |
157
+ | `remote_chat` | An assistant message or model-request reply in the required `sessionId`. |
158
+ | `history` | The current local transcript, or a Chappie session named by `sessionId`. |
159
+ | `transfer` | Local files and resources exchanged with Chappie sessions. |
160
160
 
161
- Use an ordinary model in the controlling session and the Chappie model in each target. This supports agent-to-agent collaboration, such as building a project on another operating system.
161
+ Select the Chappie model in each target session. This supports agent-to-agent collaboration, such as building a project on another operating system.
162
162
 
163
163
  Local `history` reads the controlling session; pass `sessionId` for a target's transcript. `transfer` uses local paths and exchanges files with targets through `from` and `to`.
164
164
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zetaloop/chappie",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Connect ChatGPT and coding agents across devices",
5
5
  "devDependencies": {
6
6
  "@ai-sdk/provider": "^3.0.8",