antechamber 0.2.3 → 0.2.5
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/CHANGELOG.md +32 -0
- package/README.md +25 -10
- package/bin/opencode-antechamber +4 -6
- package/dist/cli.js +8 -0
- package/dist/commands/context.d.ts +4 -0
- package/dist/commands/context.js +19 -0
- package/dist/commands/doctor.js +8 -3
- package/dist/commands/help.d.ts +1 -1
- package/dist/commands/help.js +2 -0
- package/dist/commands/serve.js +14 -0
- package/dist/commands/setup.d.ts +1 -0
- package/dist/commands/setup.js +34 -5
- package/dist/commands/upgrade.d.ts +2 -0
- package/dist/commands/upgrade.js +7 -0
- package/dist/lifecycle.d.ts +1 -0
- package/dist/lifecycle.js +4 -0
- package/dist/mcp.d.ts +70 -0
- package/dist/mcp.js +494 -0
- package/dist/misc-routes.js +2 -3
- package/dist/monitor-sessions.d.ts +48 -0
- package/dist/monitor-sessions.js +295 -0
- package/dist/pi-event-translation.d.ts +2 -0
- package/dist/pi-event-translation.js +3 -0
- package/dist/pi-rpc.js +2 -0
- package/dist/route-services.d.ts +2 -0
- package/dist/routes-v1.js +24 -8
- package/dist/routes-v2.js +11 -5
- package/dist/self-update.d.ts +32 -0
- package/dist/self-update.js +188 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.js +2 -0
- package/dist/sessions.d.ts +6 -0
- package/dist/sessions.js +19 -1
- package/dist/types.d.ts +5 -0
- package/dist/v2.js +2 -0
- package/extensions/omo-dag/package.json +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,38 @@ and this project uses [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.5] - 2026-10-15
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- OmO terminal monitors now appear in OpenChamber as read-only child sessions of
|
|
15
|
+
the session that started them. They are listed under Subagents and keep a live
|
|
16
|
+
sidebar dot while the watch runs, and their transcript shows the watched
|
|
17
|
+
command, filter, event count and how the watch ended. A session with a live
|
|
18
|
+
watch is no longer evicted as idle, which used to stop the watch.
|
|
19
|
+
- MCP servers configured in OmO now appear in OpenChamber's MCP status, and the
|
|
20
|
+
Authorize button for a server that needs sign-in runs OmO's native
|
|
21
|
+
`/mcp auth` flow in the running session. Status and authorization use the
|
|
22
|
+
most recently used live session in the directory. The flow never adds a
|
|
23
|
+
message to the conversation, and it never revives a dormant session.
|
|
24
|
+
- Completing an MCP sign-in with a pasted code or redirect URL (OpenChamber's
|
|
25
|
+
callback page or paste box) now works through `/mcp/{name}/auth/callback`.
|
|
26
|
+
The code goes to OmO's waiting loopback listener, or to
|
|
27
|
+
`/mcp auth-complete` when OmO parked the flow.
|
|
28
|
+
- OpenChamber 2.x now lists OmO MCP servers (`GET /api/mcp`) and can sign in
|
|
29
|
+
through `mcp_*` integrations. These run OmO's headless `/mcp auth-start` and
|
|
30
|
+
`/mcp auth-complete` with a paste-the-code step. A completed sign-in emits
|
|
31
|
+
`mcp.status.changed`.
|
|
32
|
+
|
|
33
|
+
## [0.2.4] - 2026-10-15
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- feat(cli): `antechamber setup --auto-update` points OpenChamber at a launcher that installs the latest release in the background on every start; it is now the recommended install path
|
|
38
|
+
- feat(cli): `antechamber upgrade` installs the latest release with the package manager that owns the global install, so OpenChamber 2.3.2's Update button now upgrades antechamber
|
|
39
|
+
- feat(api): `POST /global/upgrade` upgrades antechamber itself instead of returning `UnsupportedError`
|
|
40
|
+
- feat(config): `ANTECHAMBER_AUTO_UPDATE=1` enables the post-start background update
|
|
41
|
+
|
|
10
42
|
## [0.2.3] - 2026-10-15
|
|
11
43
|
|
|
12
44
|
### Fixed
|
package/README.md
CHANGED
|
@@ -73,13 +73,23 @@ Needs Node.js 22+ and OmO's `omo` command on PATH (`bun add -g omo-ai`).
|
|
|
73
73
|
npm i -g antechamber
|
|
74
74
|
# or: bun add -g antechamber
|
|
75
75
|
antechamber doctor
|
|
76
|
-
antechamber setup
|
|
76
|
+
antechamber setup --auto-update
|
|
77
77
|
```
|
|
78
78
|
|
|
79
79
|
`setup` updates OpenChamber's `opencodeBinary`, preserves all other settings,
|
|
80
80
|
and backs up an existing settings file before changing it. Restart OpenChamber
|
|
81
81
|
after setup. Preview changes with `antechamber setup --dry-run`.
|
|
82
82
|
|
|
83
|
+
`--auto-update` keeps antechamber current without any action from you. It
|
|
84
|
+
writes a small launcher, `~/.config/antechamber/opencode-antechamber`, and points
|
|
85
|
+
OpenChamber at it. Each time OpenChamber starts antechamber, the launcher
|
|
86
|
+
checks npm for a newer release once the server is up and installs it with the
|
|
87
|
+
package manager that owns the global install. The new version runs from the
|
|
88
|
+
next start; startup never waits on the network, and an offline start just
|
|
89
|
+
skips the check. It needs a global npm or bun install, so it is refused for
|
|
90
|
+
source checkouts and `npx`. Drop the flag (plain `antechamber setup`) to point
|
|
91
|
+
OpenChamber back at the `antechamber` bin and stop auto-updates.
|
|
92
|
+
|
|
83
93
|
Optionally, add the bundled [OmO Graph extension](#openchamber-extension-omo-graph):
|
|
84
94
|
`setup` ends by printing its folder
|
|
85
95
|
(`$(npm root -g)/antechamber/extensions/omo-dag`). In OpenChamber, open
|
|
@@ -131,28 +141,33 @@ antechamber serve --hostname 127.0.0.1 --port 4096
|
|
|
131
141
|
| Command | Purpose / options |
|
|
132
142
|
|---|---|
|
|
133
143
|
| `antechamber serve` | OpenCode-compatible server; `--hostname`/`--host`, `--port`, `--directory`. Bare `antechamber` also starts the server. |
|
|
134
|
-
| `antechamber setup` | Configure OpenChamber; `--settings <file>`, `--profile <dir>`, `--binary <path>`, `--dry-run`, `--systemd [unit]`, `--pi-binary <path>`, `--restart`. |
|
|
144
|
+
| `antechamber setup` | Configure OpenChamber; `--settings <file>`, `--profile <dir>`, `--binary <path>`, `--dry-run`, `--systemd [unit]`, `--pi-binary <path>`, `--restart`, `--auto-update`. |
|
|
135
145
|
| `antechamber doctor` | Read-only Node, backend, agent/state directories, teardown, OpenChamber and auth checks; `--json`, `--settings <file>`, `--profile <dir>`. Exits 1 on any FAIL; warnings do not fail. |
|
|
146
|
+
| `antechamber upgrade` | Install the latest release over a global npm or bun install, with the package manager that owns it. Refused for source checkouts and `npx`. |
|
|
136
147
|
| `antechamber version` | Package version plus OpenCode API contract version. `--version`/`-v` deliberately print exactly `opencode v2.0.20` for OpenChamber. |
|
|
137
148
|
| `antechamber help` | Usage and options; also `--help`/`-h`. |
|
|
138
149
|
|
|
139
150
|
## Upgrade, uninstall and rollback
|
|
140
151
|
|
|
152
|
+
With `setup --auto-update` there is nothing to do: each start installs the
|
|
153
|
+
latest release for the next one. Otherwise:
|
|
154
|
+
|
|
141
155
|
```bash
|
|
142
|
-
|
|
143
|
-
# or: bun add -g antechamber
|
|
156
|
+
antechamber upgrade
|
|
157
|
+
# equivalent: npm update -g antechamber (or: bun add -g antechamber)
|
|
144
158
|
```
|
|
145
159
|
|
|
146
160
|
Restart OpenChamber, or `systemctl --user restart openchamber.service` for a
|
|
147
161
|
managed service. Run `antechamber doctor` again. If the executable moved,
|
|
148
162
|
rerun `antechamber setup`.
|
|
149
163
|
|
|
150
|
-
OpenChamber 2.3.2
|
|
151
|
-
OpenCode API 2.0.20, the minimum OpenChamber accepts
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
164
|
+
OpenChamber 2.3.2 shows an "OpenCode update" notice because antechamber
|
|
165
|
+
reports OpenCode API 2.0.20, the minimum OpenChamber accepts. The notice names
|
|
166
|
+
an OpenCode version, but its **Update** button runs `<opencodeBinary> upgrade`,
|
|
167
|
+
which upgrades antechamber itself (a no-op when it is already current). Click
|
|
168
|
+
**Reload OpenCode** afterwards to restart onto the new version. OpenChamber
|
|
169
|
+
1.x shows no notice; its `POST /global/upgrade` call upgrades antechamber the
|
|
170
|
+
same way.
|
|
156
171
|
|
|
157
172
|
To roll back wiring, copy the backup printed by setup over the settings file:
|
|
158
173
|
|
package/bin/opencode-antechamber
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
# OpenChamber launcher: point `settings.opencodeBinary` (or $OPENCODE_BINARY)
|
|
3
3
|
# at this file. OpenChamber runs `<binary> serve --hostname H --port P` and
|
|
4
|
-
# `<binary> --version
|
|
4
|
+
# `<binary> --version`, and OpenChamber 2.x's Update action runs `<binary> upgrade`;
|
|
5
|
+
# anything else is rejected.
|
|
5
6
|
# Requires a build (`npm run build`) so that dist/cli.js exists.
|
|
6
7
|
set -eu
|
|
7
8
|
SCRIPT_PATH=$0
|
|
@@ -22,10 +23,7 @@ fi
|
|
|
22
23
|
case "${1:-}" in
|
|
23
24
|
serve) shift; exec node "$CLI" serve "$@" ;;
|
|
24
25
|
--version|-v) exec node "$CLI" --version ;;
|
|
25
|
-
upgrade)
|
|
26
|
-
echo "opencode-antechamber: OpenChamber cannot upgrade antechamber; run 'npm update -g antechamber' (or 'bun add -g antechamber') instead" >&2
|
|
27
|
-
exit 1
|
|
28
|
-
;;
|
|
26
|
+
upgrade) exec node "$CLI" upgrade ;;
|
|
29
27
|
esac
|
|
30
|
-
echo "opencode-antechamber: unsupported command '${1:-}' (only 'serve'
|
|
28
|
+
echo "opencode-antechamber: unsupported command '${1:-}' (only 'serve', '--version' and 'upgrade' are implemented)" >&2
|
|
31
29
|
exit 1
|
package/dist/cli.js
CHANGED
|
@@ -26,6 +26,7 @@ try {
|
|
|
26
26
|
systemd: { type: "boolean" },
|
|
27
27
|
"pi-binary": { type: "string" },
|
|
28
28
|
restart: { type: "boolean" },
|
|
29
|
+
"auto-update": { type: "boolean" },
|
|
29
30
|
json: { type: "boolean" },
|
|
30
31
|
},
|
|
31
32
|
});
|
|
@@ -49,8 +50,15 @@ try {
|
|
|
49
50
|
...(values.systemd ? { systemd: positionals[1] ?? "openchamber.service" } : {}),
|
|
50
51
|
dryRun: values["dry-run"] ?? false,
|
|
51
52
|
restart: values.restart ?? false,
|
|
53
|
+
autoUpdate: values["auto-update"] ?? false,
|
|
52
54
|
});
|
|
53
55
|
}
|
|
56
|
+
else if (command === "upgrade") {
|
|
57
|
+
if (positionals.length > 1)
|
|
58
|
+
throw new Error("Unexpected upgrade argument");
|
|
59
|
+
const { upgrade } = await import("./commands/upgrade.js");
|
|
60
|
+
await upgrade();
|
|
61
|
+
}
|
|
54
62
|
else if (command === "doctor") {
|
|
55
63
|
const { doctor, formatDoctor } = await import("./commands/doctor.js");
|
|
56
64
|
const report = doctor({
|
|
@@ -22,4 +22,8 @@ export interface SettingsOptions {
|
|
|
22
22
|
export declare function settingsPath(options: SettingsOptions, ctx: CommandContext): string;
|
|
23
23
|
export declare function readSettings(path: string, ctx: CommandContext): Record<string, unknown>;
|
|
24
24
|
export declare function shellQuote(value: string): string;
|
|
25
|
+
/** OpenChamber launcher written by `setup --auto-update`, kept beside the session registry. */
|
|
26
|
+
export declare function autoUpdateLauncherPath(ctx: CommandContext): string;
|
|
27
|
+
export declare function autoUpdateLauncherText(binary: string): string;
|
|
28
|
+
export declare function autoUpdateLauncherTarget(text: string): string | undefined;
|
|
25
29
|
export declare function isPackageBinary(binary: string, ctx: CommandContext): boolean;
|
package/dist/commands/context.js
CHANGED
|
@@ -3,6 +3,7 @@ import * as fs from "node:fs";
|
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { delimiter, isAbsolute, join, resolve } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { defaultStateDir, envSetting } from "../config.js";
|
|
6
7
|
export function createContext(overrides = {}) {
|
|
7
8
|
const env = overrides.env ?? process.env;
|
|
8
9
|
const cwd = overrides.cwd ?? process.cwd();
|
|
@@ -80,6 +81,24 @@ export function readSettings(path, ctx) {
|
|
|
80
81
|
export function shellQuote(value) {
|
|
81
82
|
return /^[\w./:@=-]+$/.test(value) ? value : `'${value.replaceAll("'", "'\\''")}'`;
|
|
82
83
|
}
|
|
84
|
+
/** OpenChamber launcher written by `setup --auto-update`, kept beside the session registry. */
|
|
85
|
+
export function autoUpdateLauncherPath(ctx) {
|
|
86
|
+
return resolve(ctx.cwd, envSetting("STATE_DIR", ctx.env) ?? defaultStateDir(ctx.home, ctx.fs.existsSync), "opencode-antechamber");
|
|
87
|
+
}
|
|
88
|
+
export function autoUpdateLauncherText(binary) {
|
|
89
|
+
return [
|
|
90
|
+
"#!/bin/sh",
|
|
91
|
+
"# Written by `antechamber setup --auto-update`; rerun `antechamber setup` without it to stop auto-updates.",
|
|
92
|
+
"ANTECHAMBER_AUTO_UPDATE=1",
|
|
93
|
+
"export ANTECHAMBER_AUTO_UPDATE",
|
|
94
|
+
`exec '${binary.replaceAll("'", "'\\''")}' "$@"`,
|
|
95
|
+
"",
|
|
96
|
+
].join("\n");
|
|
97
|
+
}
|
|
98
|
+
export function autoUpdateLauncherTarget(text) {
|
|
99
|
+
const match = /^exec '((?:[^']|'\\'')*)' "\$@"$/m.exec(text);
|
|
100
|
+
return match?.[1]?.replaceAll("'\\''", "'");
|
|
101
|
+
}
|
|
83
102
|
export function isPackageBinary(binary, ctx) {
|
|
84
103
|
const resolved = resolveBinary(binary, ctx);
|
|
85
104
|
if (resolved === undefined)
|
package/dist/commands/doctor.js
CHANGED
|
@@ -3,7 +3,7 @@ import { piAgentDir } from "../agent-dir.js";
|
|
|
3
3
|
import { detectAgentName } from "../agent-name.js";
|
|
4
4
|
import { agentBinary, defaultStateDir, envSetting, isPlainPi } from "../config.js";
|
|
5
5
|
import { findPidfdPython } from "../pidfd.js";
|
|
6
|
-
import { createContext, isPackageBinary, readSettings, resolveBinary, settingsPath, } from "./context.js";
|
|
6
|
+
import { autoUpdateLauncherPath, autoUpdateLauncherTarget, createContext, isPackageBinary, readSettings, resolveBinary, settingsPath, } from "./context.js";
|
|
7
7
|
/** Checks capabilities with access/stat only, never creating state or config files. */
|
|
8
8
|
export function doctor(options = {}, ctx = createContext()) {
|
|
9
9
|
const checks = [];
|
|
@@ -75,8 +75,13 @@ export function doctor(options = {}, ctx = createContext()) {
|
|
|
75
75
|
else {
|
|
76
76
|
try {
|
|
77
77
|
const configured = readSettings(settings, ctx).opencodeBinary;
|
|
78
|
-
const
|
|
79
|
-
|
|
78
|
+
const launcher = autoUpdateLauncherPath(ctx);
|
|
79
|
+
const launcherTarget = configured === launcher && ctx.fs.existsSync(launcher)
|
|
80
|
+
? autoUpdateLauncherTarget(ctx.fs.readFileSync(launcher, "utf8"))
|
|
81
|
+
: undefined;
|
|
82
|
+
const viaLauncher = launcherTarget !== undefined && isPackageBinary(launcherTarget, ctx);
|
|
83
|
+
const matches = viaLauncher || (typeof configured === "string" && isPackageBinary(configured, ctx));
|
|
84
|
+
add("openchamber-settings", matches ? "PASS" : "WARN", `${settings}: opencodeBinary=${JSON.stringify(configured ?? null)}${viaLauncher ? ` (auto-update launcher for ${launcherTarget})` : matches ? "" : "; does not point at this antechamber installation"}`);
|
|
80
85
|
}
|
|
81
86
|
catch (error) {
|
|
82
87
|
add("openchamber-settings", "WARN", error instanceof Error ? error.message : String(error));
|
package/dist/commands/help.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const help = "Usage: antechamber [command] [options]\n\nCommands:\n serve Run the OpenCode-compatible HTTP/SSE server (also the default)\n setup Point OpenChamber at this installation; back up changed files\n doctor Read-only installation and backend checks (exit 1 on FAIL)\n version Print the npm package and OpenCode API versions\n help Show this help (--help, -h)\n\nServe: --port 4096 --host 127.0.0.1 (or --hostname) --directory <path>\n --insecure-no-auth\nSetup: --settings <file> | --profile <dir>\n --binary <path> --dry-run --systemd [unit] --pi-binary <path> --restart\nDoctor: --settings <file> | --profile <dir> --json\nProbe: --version, -v prints the OpenCode compatibility version for OpenChamber";
|
|
1
|
+
export declare const help = "Usage: antechamber [command] [options]\n\nCommands:\n serve Run the OpenCode-compatible HTTP/SSE server (also the default)\n setup Point OpenChamber at this installation; back up changed files\n doctor Read-only installation and backend checks (exit 1 on FAIL)\n upgrade Install the latest release over a global npm or bun install\n version Print the npm package and OpenCode API versions\n help Show this help (--help, -h)\n\nServe: --port 4096 --host 127.0.0.1 (or --hostname) --directory <path>\n --insecure-no-auth\nSetup: --settings <file> | --profile <dir>\n --binary <path> --dry-run --systemd [unit] --pi-binary <path> --restart\n --auto-update (launch through a wrapper that upgrades on each start)\nDoctor: --settings <file> | --profile <dir> --json\nProbe: --version, -v prints the OpenCode compatibility version for OpenChamber";
|
package/dist/commands/help.js
CHANGED
|
@@ -4,6 +4,7 @@ Commands:
|
|
|
4
4
|
serve Run the OpenCode-compatible HTTP/SSE server (also the default)
|
|
5
5
|
setup Point OpenChamber at this installation; back up changed files
|
|
6
6
|
doctor Read-only installation and backend checks (exit 1 on FAIL)
|
|
7
|
+
upgrade Install the latest release over a global npm or bun install
|
|
7
8
|
version Print the npm package and OpenCode API versions
|
|
8
9
|
help Show this help (--help, -h)
|
|
9
10
|
|
|
@@ -11,5 +12,6 @@ Serve: --port 4096 --host 127.0.0.1 (or --hostname) --directory <path>
|
|
|
11
12
|
--insecure-no-auth
|
|
12
13
|
Setup: --settings <file> | --profile <dir>
|
|
13
14
|
--binary <path> --dry-run --systemd [unit] --pi-binary <path> --restart
|
|
15
|
+
--auto-update (launch through a wrapper that upgrades on each start)
|
|
14
16
|
Doctor: --settings <file> | --profile <dir> --json
|
|
15
17
|
Probe: --version, -v prints the OpenCode compatibility version for OpenChamber`;
|
package/dist/commands/serve.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { envSetting } from "../config.js";
|
|
2
|
+
import { selfUpdate } from "../self-update.js";
|
|
2
3
|
import { AdapterServer, isLoopbackHost, serverPassword } from "../server.js";
|
|
3
4
|
export async function serve(options) {
|
|
4
5
|
const { port, host, directory, insecureNoAuth, compatible } = options;
|
|
@@ -26,4 +27,17 @@ export async function serve(options) {
|
|
|
26
27
|
console.log(`antechamber listening on ${server.url}`);
|
|
27
28
|
console.log(`default directory: ${directory}`);
|
|
28
29
|
}
|
|
30
|
+
// After the listening line: OpenChamber's startup timeout must not wait on the registry.
|
|
31
|
+
if (envSetting("AUTO_UPDATE") === "1")
|
|
32
|
+
void autoUpdate();
|
|
33
|
+
}
|
|
34
|
+
async function autoUpdate() {
|
|
35
|
+
try {
|
|
36
|
+
const result = await selfUpdate();
|
|
37
|
+
if (result.updated)
|
|
38
|
+
console.error(`antechamber: auto-update installed ${result.to} (running ${result.from}); it starts next time`);
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
console.error(`antechamber: auto-update skipped: ${error instanceof Error ? error.message : String(error)}`);
|
|
42
|
+
}
|
|
29
43
|
}
|
package/dist/commands/setup.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ interface SetupOptions extends SettingsOptions {
|
|
|
5
5
|
readonly systemd?: string;
|
|
6
6
|
readonly piBinary?: string;
|
|
7
7
|
readonly restart?: boolean;
|
|
8
|
+
readonly autoUpdate?: boolean;
|
|
8
9
|
/** User-unit root, overridable without touching the real systemd configuration. */
|
|
9
10
|
readonly systemdDir?: string;
|
|
10
11
|
}
|
package/dist/commands/setup.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { dirname, join, resolve } from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import { installMethod, npmBinaryFor } from "../self-update.js";
|
|
4
|
+
import { autoUpdateLauncherPath, autoUpdateLauncherText, createContext, isPackageBinary, readSettings, resolveBinary, settingsPath, shellQuote, } from "./context.js";
|
|
4
5
|
function systemdValue(value) {
|
|
5
6
|
if (/[\r\n\0]/.test(value))
|
|
6
7
|
throw new Error("systemd environment values cannot contain newlines or NUL");
|
|
@@ -40,8 +41,24 @@ export function setup(options, ctx = createContext()) {
|
|
|
40
41
|
if (binary === ctx.cliPath && !ctx.fs.readFileSync(binary, "utf8").startsWith("#!/usr/bin/env node\n")) {
|
|
41
42
|
throw new Error(`Package CLI ${binary} is missing its node shebang; run npm run build`);
|
|
42
43
|
}
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
let launcher;
|
|
45
|
+
let launcherText;
|
|
46
|
+
let oldLauncher;
|
|
47
|
+
if (options.autoUpdate) {
|
|
48
|
+
installMethod({
|
|
49
|
+
packageRoot: resolve(dirname(ctx.cliPath), ".."),
|
|
50
|
+
env: ctx.env,
|
|
51
|
+
home: ctx.home,
|
|
52
|
+
realpath: (path) => ctx.fs.realpathSync(path),
|
|
53
|
+
}, () => ctx.exec(npmBinaryFor(), ["root", "-g"]));
|
|
54
|
+
launcher = autoUpdateLauncherPath(ctx);
|
|
55
|
+
launcherText = autoUpdateLauncherText(binary);
|
|
56
|
+
if (ctx.fs.existsSync(launcher))
|
|
57
|
+
oldLauncher = ctx.fs.readFileSync(launcher, "utf8");
|
|
58
|
+
}
|
|
59
|
+
const configured = launcher ?? binary;
|
|
60
|
+
const updated = `${JSON.stringify({ ...data, opencodeBinary: configured }, null, 2)}\n`;
|
|
61
|
+
const changed = data.opencodeBinary !== configured;
|
|
45
62
|
let dropIn;
|
|
46
63
|
let dropInText;
|
|
47
64
|
let oldDropIn;
|
|
@@ -102,10 +119,22 @@ export function setup(options, ctx = createContext()) {
|
|
|
102
119
|
report(`Made ${binary} executable`);
|
|
103
120
|
}
|
|
104
121
|
}
|
|
122
|
+
if (launcher !== undefined && launcherText !== undefined) {
|
|
123
|
+
if (oldLauncher === launcherText && (ctx.fs.statSync(launcher).mode & 0o111) !== 0)
|
|
124
|
+
report(`Already configured: ${launcher}`);
|
|
125
|
+
else if (options.dryRun)
|
|
126
|
+
report(`Would write auto-update launcher ${launcher} for ${binary}`);
|
|
127
|
+
else {
|
|
128
|
+
ctx.fs.mkdirSync(dirname(launcher), { recursive: true });
|
|
129
|
+
writeAtomically(launcher, launcherText, ctx);
|
|
130
|
+
ctx.fs.chmodSync(launcher, 0o755);
|
|
131
|
+
report(`Wrote auto-update launcher ${launcher} for ${binary}`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
105
134
|
if (changed) {
|
|
106
135
|
report(`${options.dryRun ? "Would update" : "Updating"} ${settings}`);
|
|
107
136
|
report(`- opencodeBinary: ${JSON.stringify(data.opencodeBinary ?? null)}`);
|
|
108
|
-
report(`+ opencodeBinary: ${JSON.stringify(
|
|
137
|
+
report(`+ opencodeBinary: ${JSON.stringify(configured)}`);
|
|
109
138
|
if (existing)
|
|
110
139
|
backup(settings);
|
|
111
140
|
if (!options.dryRun) {
|
|
@@ -115,7 +144,7 @@ export function setup(options, ctx = createContext()) {
|
|
|
115
144
|
}
|
|
116
145
|
}
|
|
117
146
|
else
|
|
118
|
-
report(`Already configured: ${settings} points at ${
|
|
147
|
+
report(`Already configured: ${settings} points at ${configured}`);
|
|
119
148
|
if (dropIn !== undefined && dropInText !== undefined) {
|
|
120
149
|
if (oldDropIn === dropInText)
|
|
121
150
|
report(`Already configured: ${dropIn}`);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { selfUpdate } from "../self-update.js";
|
|
2
|
+
export async function upgrade(update = selfUpdate, output = console.log) {
|
|
3
|
+
const result = await update();
|
|
4
|
+
output(result.updated
|
|
5
|
+
? `Updated antechamber ${result.from} -> ${result.to} with ${result.method}; restart OpenChamber to use it.`
|
|
6
|
+
: `antechamber ${result.from} is already the latest release.`);
|
|
7
|
+
}
|
package/dist/lifecycle.d.ts
CHANGED
|
@@ -30,6 +30,7 @@ export declare class SessionLifecycle {
|
|
|
30
30
|
private stopping;
|
|
31
31
|
constructor(sessions: () => Iterable<ManagedSession>, options?: LifecycleOptions);
|
|
32
32
|
touch(s: ManagedSession): void;
|
|
33
|
+
lastUsed(s: ManagedSession): number;
|
|
33
34
|
private idle;
|
|
34
35
|
/** Protect the caller across awaits, including admission of a dormant session. */
|
|
35
36
|
use<T>(s: ManagedSession, action: () => Promise<T>): Promise<T>;
|
package/dist/lifecycle.js
CHANGED
|
@@ -45,6 +45,9 @@ export class SessionLifecycle {
|
|
|
45
45
|
touch(s) {
|
|
46
46
|
this.used.set(s, this.clock.now());
|
|
47
47
|
}
|
|
48
|
+
lastUsed(s) {
|
|
49
|
+
return this.used.get(s) ?? 0;
|
|
50
|
+
}
|
|
48
51
|
idle(s) {
|
|
49
52
|
return (!this.active.has(s) &&
|
|
50
53
|
s.pi !== undefined &&
|
|
@@ -52,6 +55,7 @@ export class SessionLifecycle {
|
|
|
52
55
|
s.status.type === "idle" &&
|
|
53
56
|
!s.hasPendingInteraction() &&
|
|
54
57
|
!s.hasRunningChildren() &&
|
|
58
|
+
!s.hasBackgroundWork?.() &&
|
|
55
59
|
s.piSessionId !== undefined &&
|
|
56
60
|
s.piPath !== undefined);
|
|
57
61
|
}
|
package/dist/mcp.d.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode MCP routes (v1 `/mcp*`, v2 `/api/mcp` and `mcp_*` integrations) backed by OmO's MCP service.
|
|
3
|
+
*
|
|
4
|
+
* OpenChamber scopes MCP calls by directory only, while OmO owns MCP per session process.
|
|
5
|
+
* Everything therefore targets the most recently used LIVE session in the directory; a
|
|
6
|
+
* dormant session is never revived just to answer an MCP request.
|
|
7
|
+
*
|
|
8
|
+
* Status comes from the read-only `get_loaded_surfaces` RPC. Authorization drives OmO's
|
|
9
|
+
* documented `/mcp` subcommands (docs/mcp.md "Auth"):
|
|
10
|
+
* - `/mcp auth <name>`: OmO opens a loopback listener and the browser, exchanges the code
|
|
11
|
+
* and reconnects. With `mcp.oauthCallbackUrl` set it parks a pending flow instead.
|
|
12
|
+
* - `/mcp auth-start <name>` then `/mcp auth-complete <name> <redirect-url>`: the headless
|
|
13
|
+
* paste flow; the pending PKCE state lives in that session process, so completion must
|
|
14
|
+
* reach the same process.
|
|
15
|
+
* Commands are sent straight to the agent, outside the conversation queue: they neither
|
|
16
|
+
* wait behind a running turn nor create a user message, and the session is held active so
|
|
17
|
+
* the reaper cannot stop the process (and its listener or pending state) mid-flow.
|
|
18
|
+
*/
|
|
19
|
+
import type { RouteServices } from "./route-services.js";
|
|
20
|
+
type OCMcpStatus = {
|
|
21
|
+
status: "connected";
|
|
22
|
+
} | {
|
|
23
|
+
status: "disabled";
|
|
24
|
+
} | {
|
|
25
|
+
status: "failed";
|
|
26
|
+
error: string;
|
|
27
|
+
} | {
|
|
28
|
+
status: "needs_auth";
|
|
29
|
+
} | {
|
|
30
|
+
status: "needs_client_registration";
|
|
31
|
+
error: string;
|
|
32
|
+
};
|
|
33
|
+
type V2McpStatus = {
|
|
34
|
+
status: "connected";
|
|
35
|
+
} | {
|
|
36
|
+
status: "pending";
|
|
37
|
+
} | {
|
|
38
|
+
status: "disabled";
|
|
39
|
+
} | {
|
|
40
|
+
status: "failed";
|
|
41
|
+
error: string;
|
|
42
|
+
} | {
|
|
43
|
+
status: "needs_auth";
|
|
44
|
+
error: string;
|
|
45
|
+
};
|
|
46
|
+
interface OmoMcpServer {
|
|
47
|
+
name: string;
|
|
48
|
+
status?: string;
|
|
49
|
+
authStatus?: string;
|
|
50
|
+
}
|
|
51
|
+
interface RouteResult {
|
|
52
|
+
status: number;
|
|
53
|
+
body?: unknown;
|
|
54
|
+
}
|
|
55
|
+
/** OmO's loopback listener gives up after 5 minutes; leave room for the reconnect that follows. */
|
|
56
|
+
export declare const MCP_AUTH_COMMAND_TIMEOUT_MS: number;
|
|
57
|
+
/** OmO's runtime states fold onto OpenCode's; lazy servers are usable, so they read as connected. */
|
|
58
|
+
export declare function openCodeMcpStatus(server: OmoMcpServer): OCMcpStatus;
|
|
59
|
+
export declare function v2McpStatus(server: OmoMcpServer): V2McpStatus;
|
|
60
|
+
/** The URL OmO prints on its own line after naming the server (`auth` and `auth-start` both do). */
|
|
61
|
+
export declare function authorizationUrl(text: string, name: string): string | undefined;
|
|
62
|
+
/**
|
|
63
|
+
* The redirect `/mcp auth-complete` expects. OpenChamber sends either the bare code (callback
|
|
64
|
+
* page, v1 paste box) or the whole redirect address; a bare code is rebuilt from the
|
|
65
|
+
* authorization request's own `redirect_uri` and `state`.
|
|
66
|
+
*/
|
|
67
|
+
export declare function redirectInput(authorization: string, input: string): string | undefined;
|
|
68
|
+
export declare function mcpRoute(services: RouteServices, method: string, path: string, directory: string, body: () => Promise<unknown>): Promise<RouteResult | undefined>;
|
|
69
|
+
export declare function mcpRouteV2(services: RouteServices, method: string, path: string, directory: string, body: () => Promise<unknown>): Promise<RouteResult | undefined>;
|
|
70
|
+
export {};
|