Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions GLOSSARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
Canonical terms for the toolboxmd fork. Names follow the Lightbringer series
by Brent Weeks, the source of the company name.

| Term | Meaning | Avoid |
| --- | --- | --- |
| Luxin | The company; also the work agents produce (code, PRs). | |
| Chromeria | This app: the gateway where the user directs every agent across harnesses, with more interfaces (such as the OpenBot mode) over time. Built from the T3 Code fork. | T3 Code Fork, Bridge |
| Drafter | An agent working for the user on one harness and model. | bot (reserved for OpenBot's named Bots) |
| Prism | Planned product name for Model Router: splits work across models and balances capacity. Not renamed yet. | |
| Toolbox | Planned name for the user's own future harness. | |
| T3 Code | The upstream project this fork tracks (`pingdotgg/t3code`). | |
| Term | Meaning | Avoid |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------- |
| Luxin | The company; also the work agents produce (code, PRs). | |
| Chromeria | This app: the gateway where the user directs every agent across harnesses, with more interfaces (such as the OpenBot mode) over time. Built from the T3 Code fork. | T3 Code Fork, Bridge |
| Drafter | An agent working for the user on one harness and model. | bot (reserved for OpenBot's named Bots) |
| Prism | Planned product name for Model Router: splits work across models and balances capacity. Not renamed yet. | |
| Toolbox | Planned name for the user's own future harness. | |
| T3 Code | The upstream project this fork tracks (`pingdotgg/t3code`). | |
5 changes: 4 additions & 1 deletion apps/server/src/entrypoint.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ describe("isEntrypoint", () => {
it.skipIf(!symlinksSupported)(
"matches through a symlinked entrypoint, as npm and npx install it",
() => {
const dir = makeTempDir();
// Node reports the entry module URL fully resolved, so resolve the
// fixture dir too: under a symlinked TMPDIR (macOS /var -> /private/var)
// an unresolved dir would test a URL Node never produces.
const dir = NodeFS.realpathSync(makeTempDir());
const real = NodePath.join(dir, "bin.mjs");
const link = NodePath.join(dir, "t3");
NodeFS.writeFileSync(real, "");
Expand Down
7 changes: 7 additions & 0 deletions apps/server/src/mcp/McpHttpServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import {
} from "./toolkits/preview/tools.ts";
import { PullRequestsToolkitHandlersLive } from "./toolkits/pullRequests/handlers.ts";
import { PullRequestsToolkit } from "./toolkits/pullRequests/tools.ts";
import { ThreadsToolkitHandlersLive } from "./toolkits/threads/handlers.ts";
import { ThreadsToolkit } from "./toolkits/threads/tools.ts";
import {
DeviceScreenshotToolkitHandlersLive,
DeviceStandardToolkitHandlersLive,
Expand Down Expand Up @@ -608,6 +610,10 @@ export const PullRequestsToolkitRegistrationLive = McpServer.toolkit(PullRequest
Layer.provide(PullRequestsToolkitHandlersLive),
);

export const ThreadsToolkitRegistrationLive = McpServer.toolkit(ThreadsToolkit).pipe(
Layer.provide(ThreadsToolkitHandlersLive),
);

const DeviceStandardToolkitRegistrationLive = McpServer.toolkit(DeviceStandardToolkit).pipe(
Layer.provide(DeviceStandardToolkitHandlersLive),
);
Expand All @@ -631,5 +637,6 @@ const McpTransportLive = McpServer.layerHttp({
export const layer = Layer.mergeAll(
PreviewToolkitRegistrationLive,
PullRequestsToolkitRegistrationLive,
ThreadsToolkitRegistrationLive,
DeviceToolkitRegistrationLive,
).pipe(Layer.provideMerge(McpTransportLive));
52 changes: 52 additions & 0 deletions apps/server/src/mcp/toolkits/threads/childThreads.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { describe, expect, it } from "vite-plus/test";

import { deliveryOf, effortOptionId, subagentStatusOf } from "./handlers.ts";

const session = (status: string) =>
({
status,
providerInstanceId: "codex",
activeTurnId: null,
lastError: null,
}) as unknown as Parameters<typeof subagentStatusOf>[0];

describe("child thread status vocabulary", () => {
it("maps a missing session to starting so the message guard holds", () => {
expect(subagentStatusOf(null)).toBe("starting");
});

it("collapses provider session states onto the toolkit vocabulary", () => {
expect(subagentStatusOf(session("starting"))).toBe("starting");
expect(subagentStatusOf(session("running"))).toBe("running");
expect(subagentStatusOf(session("idle"))).toBe("idle");
expect(subagentStatusOf(session("ready"))).toBe("idle");
expect(subagentStatusOf(session("error"))).toBe("failed");
expect(subagentStatusOf(session("interrupted"))).toBe("stopped");
expect(subagentStatusOf(session("stopped"))).toBe("stopped");
});
});

describe("child thread effort routing", () => {
it("uses each driver's advertised reasoning-effort option", () => {
expect(effortOptionId("codex")).toBe("reasoningEffort");
expect(effortOptionId("grok")).toBe("reasoningEffort");
expect(effortOptionId("opencode")).toBe("variant");
});

it("falls back to effort for Claude, Cursor and Antigravity", () => {
expect(effortOptionId("claudeAgent")).toBe("effort");
expect(effortOptionId("cursor")).toBe("effort");
expect(effortOptionId("antigravity")).toBe("effort");
});
});

describe("child thread message delivery", () => {
it("steers a running child and opens a turn everywhere else", () => {
expect(deliveryOf("running")).toBe("steer");
expect(deliveryOf("idle")).toBe("new-turn");
expect(deliveryOf("failed")).toBe("new-turn");
expect(deliveryOf("stopped")).toBe("new-turn");
// starting never reaches deliveryOf: the message tool refuses it first.
expect(deliveryOf("starting")).toBe("new-turn");
});
});
Loading
Loading