agentxjs 2.9.0-dev-20260317060607 → 2.9.0-dev-20260317112104

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,7 +1,7 @@
1
1
  /**
2
- * Workspace RPC Handler Tests
2
+ * OS RPC Handler Tests
3
3
  *
4
- * Verifies the server-side workspace.list/read/write handlers
4
+ * Verifies the server-side os.list/read/write handlers
5
5
  * work correctly through the RpcHandlerRegistry.
6
6
  */
7
7
 
@@ -10,23 +10,23 @@ import { mkdtemp, rm, writeFile } from "node:fs/promises";
10
10
  import { tmpdir } from "node:os";
11
11
  import { join } from "node:path";
12
12
  import { RpcHandlerRegistry } from "../../RpcHandlerRegistry";
13
- import { registerWorkspaceHandlers } from "../workspace";
13
+ import { registerOSHandlers } from "../workspace";
14
14
 
15
15
  let tempDir: string;
16
16
  let registry: RpcHandlerRegistry;
17
17
 
18
- // Minimal runtime mock with real workspace
19
- function createMockRuntime(workspacesDir: string) {
20
- const { LocalWorkspaceProvider } = require("@agentxjs/node-platform/workspace");
21
- const workspaceProvider = new LocalWorkspaceProvider(workspacesDir);
18
+ // Minimal runtime mock with real OS
19
+ function createMockRuntime(basePath: string) {
20
+ const { LocalOSProvider } = require("@agentxjs/node-platform");
21
+ const osProvider = new LocalOSProvider(basePath);
22
22
 
23
23
  return {
24
24
  platform: {
25
- workspaceProvider,
25
+ osProvider,
26
26
  imageRepository: {
27
27
  findImageById: async (imageId: string) => {
28
28
  if (imageId === "img_test") {
29
- return { imageId: "img_test", workspaceId: "ws_test" };
29
+ return { imageId: "img_test", osId: "os_test" };
30
30
  }
31
31
  return null;
32
32
  },
@@ -36,26 +36,26 @@ function createMockRuntime(workspacesDir: string) {
36
36
  }
37
37
 
38
38
  beforeEach(async () => {
39
- tempDir = await mkdtemp(join(tmpdir(), "agentx-ws-handler-test-"));
39
+ tempDir = await mkdtemp(join(tmpdir(), "agentx-os-handler-test-"));
40
40
  registry = new RpcHandlerRegistry();
41
- registerWorkspaceHandlers(registry);
41
+ registerOSHandlers(registry);
42
42
  });
43
43
 
44
44
  afterEach(async () => {
45
45
  await rm(tempDir, { recursive: true, force: true });
46
46
  });
47
47
 
48
- describe("workspace.list RPC handler", () => {
49
- test("returns files from workspace directory", async () => {
50
- // Create workspace dir and files
51
- const wsDir = join(tempDir, "ws_test");
48
+ describe("os.list RPC handler", () => {
49
+ test("returns files from OS directory", async () => {
50
+ // Create OS dir and files
51
+ const osDir = join(tempDir, "os_test");
52
52
  const { mkdir } = await import("node:fs/promises");
53
- await mkdir(wsDir, { recursive: true });
54
- await writeFile(join(wsDir, "hello.txt"), "world");
55
- await writeFile(join(wsDir, "test.js"), "console.log('hi')");
53
+ await mkdir(osDir, { recursive: true });
54
+ await writeFile(join(osDir, "hello.txt"), "world");
55
+ await writeFile(join(osDir, "test.js"), "console.log('hi')");
56
56
 
57
57
  const runtime = createMockRuntime(tempDir);
58
- const result = await registry.handle(runtime, "workspace.list", {
58
+ const result = await registry.handle(runtime, "os.list", {
59
59
  imageId: "img_test",
60
60
  path: ".",
61
61
  });
@@ -69,13 +69,13 @@ describe("workspace.list RPC handler", () => {
69
69
  }
70
70
  });
71
71
 
72
- test("returns empty array for empty workspace", async () => {
73
- const wsDir = join(tempDir, "ws_test");
72
+ test("returns empty array for empty OS directory", async () => {
73
+ const osDir = join(tempDir, "os_test");
74
74
  const { mkdir } = await import("node:fs/promises");
75
- await mkdir(wsDir, { recursive: true });
75
+ await mkdir(osDir, { recursive: true });
76
76
 
77
77
  const runtime = createMockRuntime(tempDir);
78
- const result = await registry.handle(runtime, "workspace.list", {
78
+ const result = await registry.handle(runtime, "os.list", {
79
79
  imageId: "img_test",
80
80
  });
81
81
 
@@ -87,7 +87,7 @@ describe("workspace.list RPC handler", () => {
87
87
 
88
88
  test("returns error for unknown imageId", async () => {
89
89
  const runtime = createMockRuntime(tempDir);
90
- const result = await registry.handle(runtime, "workspace.list", {
90
+ const result = await registry.handle(runtime, "os.list", {
91
91
  imageId: "img_unknown",
92
92
  });
93
93
 
@@ -95,15 +95,15 @@ describe("workspace.list RPC handler", () => {
95
95
  });
96
96
  });
97
97
 
98
- describe("workspace.read RPC handler", () => {
98
+ describe("os.read RPC handler", () => {
99
99
  test("reads file content", async () => {
100
- const wsDir = join(tempDir, "ws_test");
100
+ const osDir = join(tempDir, "os_test");
101
101
  const { mkdir } = await import("node:fs/promises");
102
- await mkdir(wsDir, { recursive: true });
103
- await writeFile(join(wsDir, "data.txt"), "hello world");
102
+ await mkdir(osDir, { recursive: true });
103
+ await writeFile(join(osDir, "data.txt"), "hello world");
104
104
 
105
105
  const runtime = createMockRuntime(tempDir);
106
- const result = await registry.handle(runtime, "workspace.read", {
106
+ const result = await registry.handle(runtime, "os.read", {
107
107
  imageId: "img_test",
108
108
  path: "data.txt",
109
109
  });
@@ -115,16 +115,16 @@ describe("workspace.read RPC handler", () => {
115
115
  });
116
116
  });
117
117
 
118
- describe("workspace.write RPC handler", () => {
118
+ describe("os.write RPC handler", () => {
119
119
  test("writes file and can read it back", async () => {
120
- const wsDir = join(tempDir, "ws_test");
120
+ const osDir = join(tempDir, "os_test");
121
121
  const { mkdir } = await import("node:fs/promises");
122
- await mkdir(wsDir, { recursive: true });
122
+ await mkdir(osDir, { recursive: true });
123
123
 
124
124
  const runtime = createMockRuntime(tempDir);
125
125
 
126
126
  // Write
127
- const writeResult = await registry.handle(runtime, "workspace.write", {
127
+ const writeResult = await registry.handle(runtime, "os.write", {
128
128
  imageId: "img_test",
129
129
  path: "output.txt",
130
130
  content: "written via RPC",
@@ -132,7 +132,7 @@ describe("workspace.write RPC handler", () => {
132
132
  expect(writeResult.success).toBe(true);
133
133
 
134
134
  // Read back
135
- const readResult = await registry.handle(runtime, "workspace.read", {
135
+ const readResult = await registry.handle(runtime, "os.read", {
136
136
  imageId: "img_test",
137
137
  path: "output.txt",
138
138
  });
@@ -12,7 +12,7 @@ import { registerImageHandlers } from "./image";
12
12
  import { registerInstanceHandlers } from "./instance";
13
13
  import { registerLLMHandlers } from "./llm";
14
14
  import { registerMessageHandlers } from "./message";
15
- import { registerWorkspaceHandlers } from "./workspace";
15
+ import { registerOSHandlers } from "./workspace";
16
16
 
17
17
  /**
18
18
  * Register all RPC handlers on the registry
@@ -22,5 +22,5 @@ export function registerAll(registry: RpcHandlerRegistry): void {
22
22
  registerInstanceHandlers(registry);
23
23
  registerMessageHandlers(registry);
24
24
  registerLLMHandlers(registry);
25
- registerWorkspaceHandlers(registry);
25
+ registerOSHandlers(registry);
26
26
  }
@@ -1,47 +1,47 @@
1
1
  /**
2
- * Workspace RPC Handlers
2
+ * OS RPC Handlers — exposes AgentOS file operations via RPC
3
3
  */
4
4
 
5
5
  import type { RpcHandlerRegistry } from "../RpcHandlerRegistry";
6
6
  import { err, ok } from "../RpcHandlerRegistry";
7
7
 
8
- export function registerWorkspaceHandlers(registry: RpcHandlerRegistry): void {
9
- registry.register("workspace.read", async (runtime, params) => {
8
+ export function registerOSHandlers(registry: RpcHandlerRegistry): void {
9
+ registry.register("os.read", async (runtime, params) => {
10
10
  const { imageId, path } = params as { imageId: string; path: string };
11
- const wp = runtime.platform.workspaceProvider;
12
- if (!wp) return err(-32000, "Workspace not available");
11
+ const op = runtime.platform.osProvider;
12
+ if (!op) return err(-32000, "OS not available");
13
13
 
14
14
  const img = await runtime.platform.imageRepository.findImageById(imageId);
15
- if (!img?.workspaceId) return err(404, "Image has no workspace");
15
+ if (!img?.osId) return err(404, "Image has no OS");
16
16
 
17
- const ws = await wp.create(img.workspaceId);
18
- const content = await ws.read(path);
17
+ const os = await op.create(img.osId);
18
+ const content = await os.fs.read(path);
19
19
  return ok({ content });
20
20
  });
21
21
 
22
- registry.register("workspace.list", async (runtime, params) => {
22
+ registry.register("os.list", async (runtime, params) => {
23
23
  const { imageId, path } = params as { imageId: string; path?: string };
24
- const wp = runtime.platform.workspaceProvider;
25
- if (!wp) return err(-32000, "Workspace not available");
24
+ const op = runtime.platform.osProvider;
25
+ if (!op) return err(-32000, "OS not available");
26
26
 
27
27
  const img = await runtime.platform.imageRepository.findImageById(imageId);
28
- if (!img?.workspaceId) return err(404, "Image has no workspace");
28
+ if (!img?.osId) return err(404, "Image has no OS");
29
29
 
30
- const ws = await wp.create(img.workspaceId);
31
- const files = await ws.list(path ?? ".");
30
+ const os = await op.create(img.osId);
31
+ const files = await os.fs.list(path ?? ".");
32
32
  return ok({ files });
33
33
  });
34
34
 
35
- registry.register("workspace.write", async (runtime, params) => {
35
+ registry.register("os.write", async (runtime, params) => {
36
36
  const { imageId, path, content } = params as { imageId: string; path: string; content: string };
37
- const wp = runtime.platform.workspaceProvider;
38
- if (!wp) return err(-32000, "Workspace not available");
37
+ const op = runtime.platform.osProvider;
38
+ if (!op) return err(-32000, "OS not available");
39
39
 
40
40
  const img = await runtime.platform.imageRepository.findImageById(imageId);
41
- if (!img?.workspaceId) return err(404, "Image has no workspace");
41
+ if (!img?.osId) return err(404, "Image has no OS");
42
42
 
43
- const ws = await wp.create(img.workspaceId);
44
- await ws.write(path, content);
43
+ const os = await op.create(img.osId);
44
+ await os.fs.write(path, content);
45
45
  return ok({ success: true });
46
46
  });
47
47
  }
package/src/index.ts CHANGED
@@ -227,16 +227,16 @@ export type {
227
227
  FileBlock,
228
228
  FileTreeEntry,
229
229
  ImageBlock,
230
+ OS,
231
+ OSState,
230
232
  PresentationMetrics,
231
233
  PresentationOptions,
234
+ PresentationOS,
232
235
  PresentationState,
233
- PresentationWorkspace,
234
236
  TextBlock,
235
237
  ThinkingBlock,
236
238
  ToolBlock,
237
239
  UserConversation,
238
- Workspace,
239
- WorkspaceState,
240
240
  } from "./presentation";
241
241
  export {
242
242
  addUserConversation,
@@ -7,19 +7,19 @@
7
7
  */
8
8
 
9
9
  import { messagesToConversations, Presentation, type PresentationOptions } from "../presentation";
10
- import type { PresentationWorkspace } from "../presentation/types";
10
+ import type { PresentationOS } from "../presentation/types";
11
11
  import type { AgentX, PresentationNamespace, SessionNamespace } from "../types";
12
12
 
13
13
  /**
14
- * Workspace resolver — given an imageId, returns a PresentationWorkspace or null.
14
+ * OS resolver — given an imageId, returns a PresentationOS or null.
15
15
  * Provided by the client (local or remote) to decouple from runtime internals.
16
16
  */
17
- export type WorkspaceResolver = (imageId: string) => Promise<PresentationWorkspace | null>;
17
+ export type OSResolver = (imageId: string) => Promise<PresentationOS | null>;
18
18
 
19
19
  export function createPresentations(
20
20
  agentx: AgentX,
21
21
  sessionNs: SessionNamespace,
22
- workspaceResolver?: WorkspaceResolver
22
+ osResolver?: OSResolver
23
23
  ): PresentationNamespace {
24
24
  const instances = new Map<string, Presentation>();
25
25
 
@@ -34,13 +34,13 @@ export function createPresentations(
34
34
  return existing;
35
35
  }
36
36
 
37
- // Resolve workspace for this image
38
- const workspace = workspaceResolver ? await workspaceResolver(imageId) : null;
37
+ // Resolve OS for this image
38
+ const os = osResolver ? await osResolver(imageId) : null;
39
39
 
40
40
  // Create new from history
41
41
  const messages = await sessionNs.getMessages(imageId);
42
42
  const conversations = messagesToConversations(messages);
43
- const presentation = new Presentation(agentx, imageId, options, conversations, workspace);
43
+ const presentation = new Presentation(agentx, imageId, options, conversations, os);
44
44
 
45
45
  instances.set(imageId, presentation);
46
46
 
@@ -9,7 +9,7 @@
9
9
  * // Read state
10
10
  * pres.conversations // message history
11
11
  * pres.status // "idle" | "submitted" | "thinking" | "responding" | "executing"
12
- * pres.workspace // { files, read, write, list } or null
12
+ * pres.os // { files, read, write, list } or null
13
13
  *
14
14
  * // Subscribe (works with useSyncExternalStore)
15
15
  * const unsub = pres.subscribe(() => rerender());
@@ -30,8 +30,8 @@ import type {
30
30
  ConnectionState,
31
31
  Conversation,
32
32
  PresentationMetrics,
33
+ PresentationOS,
33
34
  PresentationState,
34
- PresentationWorkspace,
35
35
  } from "./types";
36
36
  import { initialPresentationState } from "./types";
37
37
 
@@ -40,9 +40,9 @@ import { initialPresentationState } from "./types";
40
40
  // ============================================================================
41
41
 
42
42
  /**
43
- * Workspace — file tree + operations, unified.
43
+ * OS view — file tree + operations, unified.
44
44
  */
45
- export interface Workspace {
45
+ export interface OS {
46
46
  /** Current file tree (real-time updates) */
47
47
  readonly files: readonly import("./types").FileTreeEntry[];
48
48
  /** Read file content */
@@ -72,18 +72,18 @@ export class Presentation {
72
72
  private _listeners = new Set<() => void>();
73
73
  private _legacyHandlers = new Set<(state: PresentationState) => void>();
74
74
  private _eventUnsubscribe: (() => void) | null = null;
75
- private _workspaceOps: PresentationWorkspace | null;
75
+ private _osOps: PresentationOS | null;
76
76
 
77
77
  constructor(
78
78
  agentx: AgentX,
79
79
  instanceId: string,
80
80
  options?: PresentationOptions,
81
81
  initialConversations?: Conversation[],
82
- workspace?: PresentationWorkspace | null
82
+ os?: PresentationOS | null
83
83
  ) {
84
84
  this._agentx = agentx;
85
85
  this._instanceId = instanceId;
86
- this._workspaceOps = workspace ?? null;
86
+ this._osOps = os ?? null;
87
87
  this._state = initialConversations?.length
88
88
  ? { ...initialPresentationState, conversations: initialConversations }
89
89
  : createInitialState();
@@ -97,9 +97,9 @@ export class Presentation {
97
97
  this._subscribeToEvents();
98
98
 
99
99
  // Load initial workspace file tree
100
- if (this._workspaceOps) {
101
- this._workspaceOps.list(".").then((files) => {
102
- this._state = { ...this._state, workspace: { files } };
100
+ if (this._osOps) {
101
+ this._osOps.list(".").then((files) => {
102
+ this._state = { ...this._state, os: { files } };
103
103
  this._notify();
104
104
  });
105
105
  }
@@ -127,14 +127,14 @@ export class Presentation {
127
127
  return this._state.metrics;
128
128
  }
129
129
 
130
- /** Workspace — file tree + operations. null if agent has no workspace. */
131
- get workspace(): Workspace | null {
132
- if (!this._workspaceOps) return null;
133
- const ops = this._workspaceOps;
134
- const wsState = this._state.workspace;
130
+ /** OS — file tree + operations. null if agent has no OS. */
131
+ get os(): OS | null {
132
+ if (!this._osOps) return null;
133
+ const ops = this._osOps;
134
+ const osState = this._state.os;
135
135
  return {
136
136
  get files() {
137
- return wsState?.files ?? [];
137
+ return osState?.files ?? [];
138
138
  },
139
139
  read: (path: string) => ops.read(path),
140
140
  write: (path: string, content: string) => ops.write(path, content),
@@ -1,10 +1,10 @@
1
1
  /**
2
- * Workspace Initialization Tests — New Presentation API
2
+ * OS Initialization Tests — New Presentation API
3
3
  */
4
4
 
5
5
  import { describe, expect, mock, test } from "bun:test";
6
6
  import { Presentation } from "../Presentation";
7
- import type { PresentationWorkspace } from "../types";
7
+ import type { PresentationOS } from "../types";
8
8
 
9
9
  function createMockAgentX() {
10
10
  return {
@@ -19,41 +19,41 @@ function createMockAgentX() {
19
19
  } as any;
20
20
  }
21
21
 
22
- describe("Workspace initialization in Presentation", () => {
23
- test("constructor calls workspace.list('.') and populates workspace.files", async () => {
22
+ describe("OS initialization in Presentation", () => {
23
+ test("constructor calls os.list('.') and populates os.files", async () => {
24
24
  const mockFiles = [
25
25
  { name: "src", path: "src", type: "directory" as const },
26
26
  { name: "package.json", path: "package.json", type: "file" as const },
27
27
  ];
28
28
 
29
- const mockWorkspace: PresentationWorkspace = {
29
+ const mockOS: PresentationOS = {
30
30
  read: mock(() => Promise.resolve("")),
31
31
  write: mock(() => Promise.resolve()),
32
32
  list: mock(() => Promise.resolve(mockFiles)),
33
33
  };
34
34
 
35
35
  const ax = createMockAgentX();
36
- const pres = new Presentation(ax, "img_test", undefined, undefined, mockWorkspace);
36
+ const pres = new Presentation(ax, "img_test", undefined, undefined, mockOS);
37
37
 
38
38
  await new Promise((resolve) => setTimeout(resolve, 50));
39
39
 
40
- expect(mockWorkspace.list).toHaveBeenCalledWith(".");
41
- expect(pres.workspace).not.toBeNull();
42
- expect(pres.workspace!.files).toEqual(mockFiles);
40
+ expect(mockOS.list).toHaveBeenCalledWith(".");
41
+ expect(pres.os).not.toBeNull();
42
+ expect(pres.os!.files).toEqual(mockFiles);
43
43
  });
44
44
 
45
- test("workspace is null when no workspace provided", async () => {
45
+ test("os is null when no OS provided", async () => {
46
46
  const ax = createMockAgentX();
47
47
  const pres = new Presentation(ax, "img_test", undefined, undefined, null);
48
48
 
49
49
  await new Promise((resolve) => setTimeout(resolve, 50));
50
50
 
51
- expect(pres.workspace).toBeNull();
51
+ expect(pres.os).toBeNull();
52
52
  });
53
53
 
54
- test("subscribe fires on workspace update", async () => {
54
+ test("subscribe fires on OS update", async () => {
55
55
  const mockFiles = [{ name: "test.txt", path: "test.txt", type: "file" as const }];
56
- const mockWorkspace: PresentationWorkspace = {
56
+ const mockOS: PresentationOS = {
57
57
  read: mock(() => Promise.resolve("")),
58
58
  write: mock(() => Promise.resolve()),
59
59
  list: mock(() => Promise.resolve(mockFiles)),
@@ -61,7 +61,7 @@ describe("Workspace initialization in Presentation", () => {
61
61
 
62
62
  let notified = false;
63
63
  const ax = createMockAgentX();
64
- const pres = new Presentation(ax, "img_test", undefined, undefined, mockWorkspace);
64
+ const pres = new Presentation(ax, "img_test", undefined, undefined, mockOS);
65
65
  pres.subscribe(() => {
66
66
  notified = true;
67
67
  });
@@ -69,12 +69,12 @@ describe("Workspace initialization in Presentation", () => {
69
69
  await new Promise((resolve) => setTimeout(resolve, 50));
70
70
 
71
71
  expect(notified).toBe(true);
72
- expect(pres.workspace!.files).toEqual(mockFiles);
72
+ expect(pres.os!.files).toEqual(mockFiles);
73
73
  });
74
74
 
75
- test("workspace_tree event updates workspace.files", async () => {
75
+ test("workspace_tree event updates os.files", async () => {
76
76
  const initialFiles = [{ name: "init.txt", path: "init.txt", type: "file" as const }];
77
- const mockWorkspace: PresentationWorkspace = {
77
+ const mockOS: PresentationOS = {
78
78
  read: mock(() => Promise.resolve("")),
79
79
  write: mock(() => Promise.resolve()),
80
80
  list: mock(() => Promise.resolve(initialFiles)),
@@ -87,10 +87,10 @@ describe("Workspace initialization in Presentation", () => {
87
87
  return () => {};
88
88
  });
89
89
 
90
- const pres = new Presentation(ax, "img_test", undefined, undefined, mockWorkspace);
90
+ const pres = new Presentation(ax, "img_test", undefined, undefined, mockOS);
91
91
  await new Promise((resolve) => setTimeout(resolve, 50));
92
92
 
93
- expect(pres.workspace!.files).toEqual(initialFiles);
93
+ expect(pres.os!.files).toEqual(initialFiles);
94
94
 
95
95
  // Simulate workspace_tree event
96
96
  const updatedFiles = [
@@ -99,6 +99,6 @@ describe("Workspace initialization in Presentation", () => {
99
99
  ];
100
100
  eventHandler!({ type: "workspace_tree", timestamp: Date.now(), data: { files: updatedFiles } });
101
101
 
102
- expect(pres.workspace!.files).toEqual(updatedFiles);
102
+ expect(pres.os!.files).toEqual(updatedFiles);
103
103
  });
104
104
  });
@@ -1,10 +1,10 @@
1
1
  /**
2
- * Presentation Workspace Tests
2
+ * Presentation OS Tests
3
3
  *
4
- * Tests the workspace integration in the Presentation layer:
5
- * 1. Reducer handles workspace_tree events → updates PresentationState.workspace
6
- * 2. PresentationWorkspace operations (read/write/list)
7
- * 3. Initial state has workspace: null
4
+ * Tests the OS integration in the Presentation layer:
5
+ * 1. Reducer handles workspace_tree events → updates PresentationState.os
6
+ * 2. PresentationOS operations (read/write/list)
7
+ * 3. Initial state has os: null
8
8
  */
9
9
 
10
10
  import { describe, expect, test } from "bun:test";
@@ -15,13 +15,13 @@ import type { FileTreeEntry, PresentationState } from "../types";
15
15
  // Reducer: workspace_tree event
16
16
  // ============================================================================
17
17
 
18
- describe("Presentation Workspace Reducer", () => {
19
- test("initial state has workspace: null", () => {
18
+ describe("Presentation OS Reducer", () => {
19
+ test("initial state has os: null", () => {
20
20
  const state = createInitialState();
21
- expect(state.workspace).toBeNull();
21
+ expect(state.os).toBeNull();
22
22
  });
23
23
 
24
- test("workspace_tree event sets workspace.files", () => {
24
+ test("workspace_tree event sets os.files", () => {
25
25
  const state = createInitialState();
26
26
  const files: FileTreeEntry[] = [
27
27
  { name: "src", path: "src", type: "directory" },
@@ -35,14 +35,14 @@ describe("Presentation Workspace Reducer", () => {
35
35
  };
36
36
 
37
37
  const newState = presentationReducer(state, event as any);
38
- expect(newState.workspace).not.toBeNull();
39
- expect(newState.workspace!.files).toEqual(files);
38
+ expect(newState.os).not.toBeNull();
39
+ expect(newState.os!.files).toEqual(files);
40
40
  });
41
41
 
42
42
  test("workspace_tree event replaces previous files", () => {
43
43
  const state: PresentationState = {
44
44
  ...createInitialState(),
45
- workspace: {
45
+ os: {
46
46
  files: [{ name: "old.txt", path: "old.txt", type: "file" }],
47
47
  },
48
48
  };
@@ -59,8 +59,8 @@ describe("Presentation Workspace Reducer", () => {
59
59
  };
60
60
 
61
61
  const newState = presentationReducer(state, event as any);
62
- expect(newState.workspace!.files).toEqual(newFiles);
63
- expect(newState.workspace!.files).not.toContainEqual({
62
+ expect(newState.os!.files).toEqual(newFiles);
63
+ expect(newState.os!.files).not.toContainEqual({
64
64
  name: "old.txt",
65
65
  path: "old.txt",
66
66
  type: "file",
@@ -80,10 +80,10 @@ describe("Presentation Workspace Reducer", () => {
80
80
  const newState = presentationReducer(state, event as any);
81
81
  expect(newState.status).toBe("responding");
82
82
  expect(newState.conversations).toEqual([]);
83
- expect(newState.workspace).toEqual({ files: [] });
83
+ expect(newState.os).toEqual({ files: [] });
84
84
  });
85
85
 
86
- test("unknown event does not create workspace state", () => {
86
+ test("unknown event does not create os state", () => {
87
87
  const state = createInitialState();
88
88
  const event = {
89
89
  type: "some_unknown_event",
@@ -92,7 +92,7 @@ describe("Presentation Workspace Reducer", () => {
92
92
  };
93
93
 
94
94
  const newState = presentationReducer(state, event as any);
95
- expect(newState.workspace).toBeNull();
95
+ expect(newState.os).toBeNull();
96
96
  expect(newState).toBe(state); // Same reference = no change
97
97
  });
98
98
  });
@@ -5,9 +5,9 @@
5
5
  */
6
6
 
7
7
  export {
8
+ type OS,
8
9
  Presentation,
9
10
  type PresentationOptions,
10
- type Workspace,
11
11
  } from "./Presentation";
12
12
  export {
13
13
  addUserConversation,
@@ -24,9 +24,10 @@ export type {
24
24
  FileBlock,
25
25
  FileTreeEntry,
26
26
  ImageBlock,
27
+ OSState,
27
28
  PresentationMetrics,
29
+ PresentationOS,
28
30
  PresentationState,
29
- PresentationWorkspace,
30
31
  SessionMetrics,
31
32
  TextBlock,
32
33
  ThinkingBlock,
@@ -34,6 +35,5 @@ export type {
34
35
  ToolBlock,
35
36
  TurnMetrics,
36
37
  UserConversation,
37
- WorkspaceState,
38
38
  } from "./types";
39
39
  export { initialMetrics, initialPresentationState, initialSessionMetrics } from "./types";
@@ -490,7 +490,7 @@ function handleWorkspaceTree(
490
490
  ): PresentationState {
491
491
  return {
492
492
  ...state,
493
- workspace: { files: data.files },
493
+ os: { files: data.files },
494
494
  };
495
495
  }
496
496