antechamber 1.0.41 → 2.0.1

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.
Files changed (52) hide show
  1. package/CHANGELOG.md +97 -0
  2. package/README.md +88 -141
  3. package/bin/opencode-antechamber +14 -4
  4. package/dist/cli.d.ts +1 -1
  5. package/dist/cli.js +1 -1
  6. package/dist/commands/context.d.ts +5 -2
  7. package/dist/commands/context.js +8 -4
  8. package/dist/commands/doctor.js +4 -3
  9. package/dist/commands/setup.js +9 -28
  10. package/dist/config.d.ts +6 -2
  11. package/dist/config.js +18 -4
  12. package/dist/latency.d.ts +10 -0
  13. package/dist/latency.js +115 -0
  14. package/dist/misc-routes.js +2 -10
  15. package/dist/route-services.d.ts +0 -2
  16. package/dist/routes-v1.d.ts +1 -1
  17. package/dist/routes-v1.js +29 -418
  18. package/dist/routes-v2.js +1 -1
  19. package/dist/self-update.d.ts +2 -1
  20. package/dist/self-update.js +5 -1
  21. package/dist/server.d.ts +1 -3
  22. package/dist/server.js +9 -12
  23. package/dist/session-store.d.ts +12 -10
  24. package/dist/session-store.js +238 -128
  25. package/dist/session-tree.js +2 -2
  26. package/dist/sse.d.ts +0 -2
  27. package/dist/sse.js +13 -46
  28. package/dist/tool-map.js +1 -3
  29. package/dist/work-status.js +1 -1
  30. package/extensions/antechamber/README.md +100 -0
  31. package/extensions/antechamber/bin/opencode-antechamber +42 -0
  32. package/extensions/{omo-dag/docs/DESIGN.md → antechamber/docs/GRAPH.md} +5 -5
  33. package/extensions/{omo-work/docs/DESIGN.md → antechamber/docs/WORK.md} +3 -3
  34. package/extensions/antechamber/package.json +60 -0
  35. package/extensions/{omo-dag → antechamber}/panel/index.html +8 -1
  36. package/extensions/antechamber/panel/main.js +261 -0
  37. package/extensions/antechamber/runtime/launcher.js +201 -0
  38. package/extensions/antechamber/service/main.js +884 -0
  39. package/package.json +75 -26
  40. package/extensions/omo-compat/README.md +0 -48
  41. package/extensions/omo-compat/icon.svg +0 -1
  42. package/extensions/omo-compat/package.json +0 -43
  43. package/extensions/omo-dag/README.md +0 -167
  44. package/extensions/omo-dag/package.json +0 -33
  45. package/extensions/omo-dag/panel/main.js +0 -176
  46. package/extensions/omo-dag/service/main.js +0 -457
  47. package/extensions/omo-work/README.md +0 -88
  48. package/extensions/omo-work/package.json +0 -30
  49. package/extensions/omo-work/service/main.js +0 -149
  50. /package/extensions/{omo-dag → antechamber}/icon.svg +0 -0
  51. /package/extensions/{omo-work → antechamber}/status/index.html +0 -0
  52. /package/extensions/{omo-work → antechamber}/status/main.js +0 -0
package/dist/config.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { existsSync } from "node:fs";
2
+ import { createRequire } from "node:module";
2
3
  import { homedir } from "node:os";
3
- import { basename, join } from "node:path";
4
+ import { basename, dirname, join } from "node:path";
4
5
  /** Environment variable prefix for all antechamber settings. */
5
6
  export const ENV_PREFIX = "ANTECHAMBER_";
6
7
  /** Prefix used before the project was renamed; still honoured as a fallback. */
@@ -30,9 +31,22 @@ export function defaultStateDir(home = homedir(), exists = existsSync) {
30
31
  return legacy;
31
32
  return current;
32
33
  }
33
- /** Agent executable spawned per session: OmO by default, plain pi when configured. */
34
- export function agentBinary(env = process.env) {
35
- return envSetting("PI_BINARY", env) ?? "omo";
34
+ /** The OmO that antechamber's package.json pins, when it is installed beside antechamber. */
35
+ export function bundledOmo() {
36
+ try {
37
+ return join(dirname(createRequire(import.meta.url).resolve("omo-ai/package.json")), "bin", "omo.js");
38
+ }
39
+ catch {
40
+ return undefined;
41
+ }
42
+ }
43
+ /** Agent executable spawned per session: the pinned OmO by default, else `omo` on PATH, plain pi when configured. */
44
+ export function agentBinary(env = process.env, bundled = bundledOmo) {
45
+ return envSetting("PI_BINARY", env) ?? bundled() ?? "omo";
46
+ }
47
+ /** Set by the OpenChamber extension's launcher: the extension, not npm, installs and updates antechamber. */
48
+ export function managedByExtension(env = process.env) {
49
+ return envSetting("MANAGED", env) === "openchamber-extension";
36
50
  }
37
51
  /** True when the configured backend is upstream pi rather than OmO. */
38
52
  export function isPlainPi(env = process.env) {
@@ -0,0 +1,10 @@
1
+ /** Operator diagnostics. Route labels contain only literals and parameter names. */
2
+ import type { IncomingMessage, ServerResponse } from "node:http";
3
+ export declare class LatencyMonitor {
4
+ private readonly lagThreshold;
5
+ private readonly requestThreshold;
6
+ private timer;
7
+ start(): void;
8
+ stop(): void;
9
+ request(req: IncomingMessage, res: ServerResponse, handle: () => Promise<void>): Promise<void>;
10
+ }
@@ -0,0 +1,115 @@
1
+ import { performance } from "node:perf_hooks";
2
+ import { envSetting } from "./config.js";
3
+ const SAMPLE_MS = 100;
4
+ // The router uses explicit path comparisons rather than a routing framework. Unknown
5
+ // paths get a constant label so neither identifiers nor query credentials enter logs.
6
+ const ROUTE_PATTERNS = `
7
+ / /health /global/health /global/upgrade /event /global/event
8
+ /session /session/status /project /project/current /config /global/config /provider
9
+ /config/providers /experimental/session /question /permission /lsp /formatter
10
+ /command /path /vcs /agent /file /file/content /file/status /find /find/file /find/symbol
11
+ /provider/auth /auth/:providerID /provider/:providerID/oauth/authorize /provider/:providerID/oauth/callback
12
+ /question/:requestID/reply /question/:requestID/reject /permission/:requestID/reply
13
+ /api/info /api/location /api/config /api/provider /api/model /api/model/default
14
+ /api/agent /api/agent/:agentID /api/command /api/skill /api/debug/location
15
+ /api/credential /api/credential/:credentialID /api/credential/:credentialID/activate
16
+ /api/integration/:integrationID /api/integration/:integrationID/connect/key
17
+ /api/integration/:integrationID/connect/external /api/integration/:integrationID/connect/oauth
18
+ /api/integration/:integrationID/connect/command /api/integration/:integrationID/connect/oauth/:flowID
19
+ /api/integration/:integrationID/connect/command/:flowID
20
+ /api/integration/:integrationID/connect/oauth/:flowID/complete
21
+ /api/plugin /api/plugin/check /api/plugin/update /api/experimental/generate /api/experimental/generate/text
22
+ /api/shell /api/shell/:shellID /api/shell/:shellID/output /api/websearch/provider
23
+ /api/experimental/session/stats /api/experimental/usage/limits /api/experimental/fs/watch
24
+ /api/fs/find /api/project /api/project/:projectID /api/permission/request /api/question/request
25
+ /api/permission/saved /api/permission/saved/:permissionID /api/form /api/vcs/init /api/vcs
26
+ /api/session /api/session/active /api/event /api/global/event/ws
27
+ /api/experimental/session/:sessionID/instructions/entries/:entryID
28
+ /antechamber/work-status/:sessionID
29
+ `
30
+ .trim()
31
+ .split(/\s+/);
32
+ for (const prefix of ["", "/api"]) {
33
+ const base = `${prefix}/session/:sessionID`;
34
+ ROUTE_PATTERNS.push(base, `${base}/message/:messageID`);
35
+ for (const action of [
36
+ "diff",
37
+ "children",
38
+ "todo",
39
+ "message",
40
+ "prompt_async",
41
+ "abort",
42
+ "fork",
43
+ "revert",
44
+ "unrevert",
45
+ "summarize",
46
+ "shell",
47
+ "command",
48
+ "share",
49
+ "generate",
50
+ "background",
51
+ "move",
52
+ "view",
53
+ "compact",
54
+ "prompt",
55
+ "synthetic",
56
+ "context",
57
+ "interrupt",
58
+ "revert/stage",
59
+ "revert/commit",
60
+ "agent",
61
+ "model",
62
+ "form",
63
+ "question",
64
+ "permission",
65
+ "inbox",
66
+ ])
67
+ ROUTE_PATTERNS.push(`${base}/${action}`);
68
+ for (const resource of ["form", "question", "permission"])
69
+ for (const suffix of ["", "/reply", "/reject"])
70
+ ROUTE_PATTERNS.push(`${base}/${resource}/:requestID${suffix}`);
71
+ }
72
+ const routes = ROUTE_PATTERNS.map((pattern) => ({
73
+ pattern,
74
+ match: new RegExp(`^${pattern.replace(/:[A-Za-z]+/g, "[^/]+")}$`),
75
+ }));
76
+ function routePattern(req) {
77
+ const path = new URL(req.url ?? "/", "http://localhost").pathname.replace(/\/+$/, "") || "/";
78
+ return routes.find((route) => route.match.test(path))?.pattern ?? "unmatched";
79
+ }
80
+ function threshold(name, fallback) {
81
+ const value = Number(envSetting(name));
82
+ return Number.isFinite(value) && value > 0 ? value : fallback;
83
+ }
84
+ export class LatencyMonitor {
85
+ lagThreshold = threshold("EVENT_LOOP_LAG_MS", 250);
86
+ requestThreshold = threshold("SLOW_REQUEST_MS", 1000);
87
+ timer;
88
+ start() {
89
+ let expected = performance.now() + SAMPLE_MS;
90
+ this.timer = setInterval(() => {
91
+ const now = performance.now();
92
+ const lag = now - expected;
93
+ expected = now + SAMPLE_MS;
94
+ if (lag > this.lagThreshold)
95
+ console.warn(`[latency] event-loop-lag duration_ms=${Math.round(lag)} threshold_ms=${this.lagThreshold}`);
96
+ }, SAMPLE_MS);
97
+ this.timer.unref();
98
+ }
99
+ stop() {
100
+ clearInterval(this.timer);
101
+ this.timer = undefined;
102
+ }
103
+ async request(req, res, handle) {
104
+ const start = performance.now();
105
+ try {
106
+ await handle();
107
+ }
108
+ finally {
109
+ // SSE handlers return after setup; connection lifetime is not request latency.
110
+ const duration = performance.now() - start;
111
+ if (duration > this.requestThreshold)
112
+ console.warn(`[latency] slow-request method=${req.method ?? "GET"} route=${routePattern(req)} status=${res.statusCode} duration_ms=${Math.round(duration)}`);
113
+ }
114
+ }
115
+ }
@@ -42,18 +42,10 @@ async function confinedDirectory(root, path) {
42
42
  }
43
43
  }
44
44
  export async function miscRoute(method, path, url, directory) {
45
- if (method === "GET" && ["/skill", "/lsp", "/formatter", "/experimental/tool/ids"].includes(path)) {
45
+ if (method === "GET" && ["/skill", "/formatter"].includes(path)) {
46
46
  return { status: 200, body: [] };
47
47
  }
48
- if (method === "GET" && path === "/provider/auth")
49
- return { status: 200, body: {} };
50
- if ((method === "PUT" && /^\/auth\/[^/]+$/.test(path)) ||
51
- (method === "POST" && /^\/provider\/[^/]+\/oauth\/(authorize|callback)$/.test(path)) ||
52
- (method === "PATCH" && path === "/config")) {
53
- return unsupported("Not supported with OmO; configure providers in OmO");
54
- }
55
- if ((["POST", "DELETE"].includes(method) && /^\/mcp\/[^/]+\/(connect|disconnect|auth)$/.test(path)) ||
56
- (method === "POST" && path === "/experimental/control-plane/move-session")) {
48
+ if (["POST", "DELETE"].includes(method) && /^\/mcp\/[^/]+\/(connect|disconnect|auth)$/.test(path)) {
57
49
  return unsupported("Not supported with OmO; configure MCP and session directories in OmO");
58
50
  }
59
51
  if (method !== "GET" || !["/file", "/find/file"].includes(path))
@@ -5,7 +5,6 @@ import type { Catalog } from "./catalog.js";
5
5
  import type { ModelSelection } from "./thinking-levels.js";
6
6
  import type { OCEvent, OCMessageWithParts, OCPromptPart } from "./types.js";
7
7
  import type { TodoUpdated } from "./todo-bridge.js";
8
- import type { SelfUpdateResult } from "./self-update.js";
9
8
  import type { FileWatchRegistry } from "./file-watch.js";
10
9
  import type { getCommands } from "./session-commands.js";
11
10
  import type { TextGeneration } from "./text-generation.js";
@@ -16,7 +15,6 @@ export interface RouteServices {
16
15
  readonly body: (req: IncomingMessage) => Promise<unknown>;
17
16
  readonly catalog: (directory?: string, refresh?: boolean) => Promise<Catalog>;
18
17
  readonly broadcast: (directory: string, event: OCEvent | TodoUpdated) => void;
19
- readonly selfUpdate: () => Promise<SelfUpdateResult>;
20
18
  readonly fileWatches: FileWatchRegistry;
21
19
  readonly commands: (directory: string) => ReturnType<typeof getCommands>;
22
20
  readonly vcsBranch: (directory: string) => Promise<string | undefined>;
@@ -1,4 +1,4 @@
1
- /** OpenCode v1 routes, using the services composed by AdapterServer. */
1
+ /** Unprefixed compatibility routes retained for evidenced or uncertain callers. */
2
2
  import type { IncomingMessage, ServerResponse } from "node:http";
3
3
  import { type RouteServices } from "./route-services.js";
4
4
  export declare function handleV1(services: RouteServices, req: IncomingMessage, res: ServerResponse, url: URL, path: string, method: string, directory: string): Promise<void>;