@zhanguym/chatroom 1.0.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.
Files changed (223) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +52 -0
  3. package/assets/chatroom.svg +15 -0
  4. package/chatroom.config.example.json +24 -0
  5. package/dist/app/application.d.ts +20 -0
  6. package/dist/app/application.js +75 -0
  7. package/dist/app/event-bus.d.ts +25 -0
  8. package/dist/app/event-bus.js +11 -0
  9. package/dist/app/external-access-registry.d.ts +17 -0
  10. package/dist/app/external-access-registry.js +41 -0
  11. package/dist/app/lifecycle.d.ts +14 -0
  12. package/dist/app/lifecycle.js +130 -0
  13. package/dist/auth/auth-service.d.ts +88 -0
  14. package/dist/auth/auth-service.js +221 -0
  15. package/dist/auth/ingress-policy.d.ts +23 -0
  16. package/dist/auth/ingress-policy.js +61 -0
  17. package/dist/auth/passkey-service.d.ts +39 -0
  18. package/dist/auth/passkey-service.js +145 -0
  19. package/dist/cli/index.d.ts +2 -0
  20. package/dist/cli/index.js +10 -0
  21. package/dist/cli/run-cli.d.ts +1 -0
  22. package/dist/cli/run-cli.js +41 -0
  23. package/dist/config/load-config.d.ts +7 -0
  24. package/dist/config/load-config.js +197 -0
  25. package/dist/config/platform-paths.d.ts +7 -0
  26. package/dist/config/platform-paths.js +34 -0
  27. package/dist/config/types.d.ts +24 -0
  28. package/dist/config/types.js +1 -0
  29. package/dist/core/auth/passkey-repository.d.ts +18 -0
  30. package/dist/core/auth/passkey-repository.js +1 -0
  31. package/dist/core/auth/repository.d.ts +36 -0
  32. package/dist/core/auth/repository.js +1 -0
  33. package/dist/core/auth/session-repository.d.ts +6 -0
  34. package/dist/core/auth/session-repository.js +1 -0
  35. package/dist/core/errors/chatroom-error.d.ts +9 -0
  36. package/dist/core/errors/chatroom-error.js +31 -0
  37. package/dist/core/logging/types.d.ts +31 -0
  38. package/dist/core/logging/types.js +1 -0
  39. package/dist/core/operations/bounded-value.d.ts +6 -0
  40. package/dist/core/operations/bounded-value.js +57 -0
  41. package/dist/core/operations/redactor.d.ts +4 -0
  42. package/dist/core/operations/redactor.js +69 -0
  43. package/dist/core/operations/repository.d.ts +18 -0
  44. package/dist/core/operations/repository.js +1 -0
  45. package/dist/core/operations/types.d.ts +28 -0
  46. package/dist/core/operations/types.js +8 -0
  47. package/dist/core/runtime/child-environment.d.ts +1 -0
  48. package/dist/core/runtime/child-environment.js +39 -0
  49. package/dist/core/runtime/command-runner.d.ts +16 -0
  50. package/dist/core/runtime/command-runner.js +48 -0
  51. package/dist/core/runtime/identity.d.ts +2 -0
  52. package/dist/core/runtime/identity.js +9 -0
  53. package/dist/infrastructure/database/app-database.d.ts +6 -0
  54. package/dist/infrastructure/database/app-database.js +22 -0
  55. package/dist/infrastructure/database/mcp-tool-settings-repository.d.ts +8 -0
  56. package/dist/infrastructure/database/mcp-tool-settings-repository.js +22 -0
  57. package/dist/infrastructure/database/oauth-repository.d.ts +20 -0
  58. package/dist/infrastructure/database/oauth-repository.js +140 -0
  59. package/dist/infrastructure/database/operation-repository.d.ts +16 -0
  60. package/dist/infrastructure/database/operation-repository.js +120 -0
  61. package/dist/infrastructure/database/passkey-repository.d.ts +11 -0
  62. package/dist/infrastructure/database/passkey-repository.js +57 -0
  63. package/dist/infrastructure/database/schema.d.ts +1 -0
  64. package/dist/infrastructure/database/schema.js +90 -0
  65. package/dist/infrastructure/database/web-session-repository.d.ts +10 -0
  66. package/dist/infrastructure/database/web-session-repository.js +26 -0
  67. package/dist/infrastructure/http/http-server.d.ts +28 -0
  68. package/dist/infrastructure/http/http-server.js +146 -0
  69. package/dist/infrastructure/http/ingress-middleware.d.ts +6 -0
  70. package/dist/infrastructure/http/ingress-middleware.js +58 -0
  71. package/dist/infrastructure/logging/file-log-store.d.ts +9 -0
  72. package/dist/infrastructure/logging/file-log-store.js +173 -0
  73. package/dist/infrastructure/logging/system-log.d.ts +22 -0
  74. package/dist/infrastructure/logging/system-log.js +117 -0
  75. package/dist/mcp/server/create-mcp-server.d.ts +3 -0
  76. package/dist/mcp/server/create-mcp-server.js +16 -0
  77. package/dist/mcp/server/plugin-mcp-registrar.d.ts +31 -0
  78. package/dist/mcp/server/plugin-mcp-registrar.js +70 -0
  79. package/dist/mcp/server/request-context.d.ts +3 -0
  80. package/dist/mcp/server/request-context.js +8 -0
  81. package/dist/mcp/server/tool-control.d.ts +31 -0
  82. package/dist/mcp/server/tool-control.js +76 -0
  83. package/dist/mcp/server/tool-support.d.ts +44 -0
  84. package/dist/mcp/server/tool-support.js +72 -0
  85. package/dist/native/linux/chatroom-computer-helper +0 -0
  86. package/dist/native/macos/ChatRoomComputerHelper.app/Contents/Info.plist +14 -0
  87. package/dist/native/macos/ChatRoomComputerHelper.app/Contents/MacOS/chatroom-computer-helper +0 -0
  88. package/dist/native/macos/ChatRoomComputerHelper.app/Contents/_CodeSignature/CodeResources +115 -0
  89. package/dist/native/windows/chatroom-computer-helper.exe +0 -0
  90. package/dist/operations/operation-log.d.ts +24 -0
  91. package/dist/operations/operation-log.js +98 -0
  92. package/dist/plugins/cloud/api-client.d.ts +50 -0
  93. package/dist/plugins/cloud/api-client.js +112 -0
  94. package/dist/plugins/cloud/controller.d.ts +58 -0
  95. package/dist/plugins/cloud/controller.js +425 -0
  96. package/dist/plugins/cloud/device-proof.d.ts +9 -0
  97. package/dist/plugins/cloud/device-proof.js +17 -0
  98. package/dist/plugins/cloud/plugin.d.ts +4 -0
  99. package/dist/plugins/cloud/plugin.js +17 -0
  100. package/dist/plugins/cloud/state-store.d.ts +7 -0
  101. package/dist/plugins/cloud/state-store.js +79 -0
  102. package/dist/plugins/cloud/tunnel-client.d.ts +84 -0
  103. package/dist/plugins/cloud/tunnel-client.js +427 -0
  104. package/dist/plugins/cloud/types.d.ts +72 -0
  105. package/dist/plugins/cloud/types.js +60 -0
  106. package/dist/plugins/computer/audit.d.ts +34 -0
  107. package/dist/plugins/computer/audit.js +42 -0
  108. package/dist/plugins/computer/computer-native-backend.d.ts +11 -0
  109. package/dist/plugins/computer/computer-native-backend.js +58 -0
  110. package/dist/plugins/computer/computer-native-host.d.ts +30 -0
  111. package/dist/plugins/computer/computer-native-host.js +411 -0
  112. package/dist/plugins/computer/computer-protocol.d.ts +22 -0
  113. package/dist/plugins/computer/computer-protocol.js +74 -0
  114. package/dist/plugins/computer/computer-schemas.d.ts +285 -0
  115. package/dist/plugins/computer/computer-schemas.js +152 -0
  116. package/dist/plugins/computer/computer-service.d.ts +29 -0
  117. package/dist/plugins/computer/computer-service.js +117 -0
  118. package/dist/plugins/computer/computer-settings-repository.d.ts +8 -0
  119. package/dist/plugins/computer/computer-settings-repository.js +41 -0
  120. package/dist/plugins/computer/mcp.d.ts +3 -0
  121. package/dist/plugins/computer/mcp.js +126 -0
  122. package/dist/plugins/computer/plugin.d.ts +4 -0
  123. package/dist/plugins/computer/plugin.js +29 -0
  124. package/dist/plugins/computer/types.d.ts +174 -0
  125. package/dist/plugins/computer/types.js +1 -0
  126. package/dist/plugins/git/git-service.d.ts +30 -0
  127. package/dist/plugins/git/git-service.js +428 -0
  128. package/dist/plugins/git/plugin.d.ts +4 -0
  129. package/dist/plugins/git/plugin.js +12 -0
  130. package/dist/plugins/git/types.d.ts +32 -0
  131. package/dist/plugins/git/types.js +1 -0
  132. package/dist/plugins/plugin-manager.d.ts +11 -0
  133. package/dist/plugins/plugin-manager.js +63 -0
  134. package/dist/plugins/process/backend.d.ts +18 -0
  135. package/dist/plugins/process/backend.js +1 -0
  136. package/dist/plugins/process/head-tail-buffer.d.ts +17 -0
  137. package/dist/plugins/process/head-tail-buffer.js +49 -0
  138. package/dist/plugins/process/infrastructure/pipe-process-backend.d.ts +8 -0
  139. package/dist/plugins/process/infrastructure/pipe-process-backend.js +71 -0
  140. package/dist/plugins/process/infrastructure/pty-process-backend.d.ts +8 -0
  141. package/dist/plugins/process/infrastructure/pty-process-backend.js +51 -0
  142. package/dist/plugins/process/mcp.d.ts +3 -0
  143. package/dist/plugins/process/mcp.js +58 -0
  144. package/dist/plugins/process/plugin.d.ts +4 -0
  145. package/dist/plugins/process/plugin.js +25 -0
  146. package/dist/plugins/process/process-supervisor.d.ts +39 -0
  147. package/dist/plugins/process/process-supervisor.js +244 -0
  148. package/dist/plugins/process/types.d.ts +30 -0
  149. package/dist/plugins/process/types.js +1 -0
  150. package/dist/plugins/types.d.ts +35 -0
  151. package/dist/plugins/types.js +17 -0
  152. package/dist/plugins/web/api-types.d.ts +56 -0
  153. package/dist/plugins/web/api-types.js +1 -0
  154. package/dist/plugins/web/http/api-router.d.ts +13 -0
  155. package/dist/plugins/web/http/api-router.js +47 -0
  156. package/dist/plugins/web/http/auth-api-router.d.ts +8 -0
  157. package/dist/plugins/web/http/auth-api-router.js +123 -0
  158. package/dist/plugins/web/http/cloud-api-router.d.ts +4 -0
  159. package/dist/plugins/web/http/cloud-api-router.js +29 -0
  160. package/dist/plugins/web/http/computer-api-router.d.ts +5 -0
  161. package/dist/plugins/web/http/computer-api-router.js +69 -0
  162. package/dist/plugins/web/http/git-api-router.d.ts +3 -0
  163. package/dist/plugins/web/http/git-api-router.js +85 -0
  164. package/dist/plugins/web/http/logs-api-router.d.ts +3 -0
  165. package/dist/plugins/web/http/logs-api-router.js +49 -0
  166. package/dist/plugins/web/http/process-api-router.d.ts +3 -0
  167. package/dist/plugins/web/http/process-api-router.js +16 -0
  168. package/dist/plugins/web/http/runtime-api-router.d.ts +10 -0
  169. package/dist/plugins/web/http/runtime-api-router.js +34 -0
  170. package/dist/plugins/web/http/workspace-api-router.d.ts +3 -0
  171. package/dist/plugins/web/http/workspace-api-router.js +91 -0
  172. package/dist/plugins/web/plugin.d.ts +8 -0
  173. package/dist/plugins/web/plugin.js +17 -0
  174. package/dist/plugins/web/runtime.d.ts +18 -0
  175. package/dist/plugins/web/runtime.js +31 -0
  176. package/dist/plugins/workspace/mcp.d.ts +3 -0
  177. package/dist/plugins/workspace/mcp.js +24 -0
  178. package/dist/plugins/workspace/metadata.d.ts +6 -0
  179. package/dist/plugins/workspace/metadata.js +111 -0
  180. package/dist/plugins/workspace/plugin.d.ts +4 -0
  181. package/dist/plugins/workspace/plugin.js +22 -0
  182. package/dist/plugins/workspace/types.d.ts +23 -0
  183. package/dist/plugins/workspace/types.js +1 -0
  184. package/dist/plugins/workspace/workspace-fs.d.ts +28 -0
  185. package/dist/plugins/workspace/workspace-fs.js +200 -0
  186. package/dist/plugins/workspace/workspace-service.d.ts +15 -0
  187. package/dist/plugins/workspace/workspace-service.js +140 -0
  188. package/dist/presentation/http/http-utils.d.ts +9 -0
  189. package/dist/presentation/http/http-utils.js +89 -0
  190. package/dist/presentation/http/oauth-router.d.ts +5 -0
  191. package/dist/presentation/http/oauth-router.js +172 -0
  192. package/dist/web/assets/CloudView-CHjVbp-5.css +1 -0
  193. package/dist/web/assets/CloudView-CvX0dkgu.js +1 -0
  194. package/dist/web/assets/CodeViewer-CH1DEJge.css +1 -0
  195. package/dist/web/assets/CodeViewer.vue_vue_type_script_setup_true_lang-B5TxGkUW.js +3 -0
  196. package/dist/web/assets/ComputerView-91Z9Cefw.css +1 -0
  197. package/dist/web/assets/ComputerView-OOyEqWml.js +1 -0
  198. package/dist/web/assets/McpToolsView-BTnolyS6.css +1 -0
  199. package/dist/web/assets/McpToolsView-DjXWTKrZ.js +1 -0
  200. package/dist/web/assets/OperationsView-DqTY51Cr.js +4 -0
  201. package/dist/web/assets/ProcessesView-C13BykIa.js +4 -0
  202. package/dist/web/assets/StateChip.vue_vue_type_script_setup_true_lang-DyOhJmR6.js +1 -0
  203. package/dist/web/assets/SystemLogsView-Ci0u4BTb.js +1 -0
  204. package/dist/web/assets/VSelect-CAxEESw-.css +1 -0
  205. package/dist/web/assets/VSelect-DrRpKyYI.js +1 -0
  206. package/dist/web/assets/VSpacer-C3wAY3F0.js +1 -0
  207. package/dist/web/assets/VSpacer-DfbUir7X.css +1 -0
  208. package/dist/web/assets/VSwitch-Cos8PNSP.css +1 -0
  209. package/dist/web/assets/VSwitch-CxusR4iO.js +1 -0
  210. package/dist/web/assets/VTabs-DSWgbwhc.css +1 -0
  211. package/dist/web/assets/VTabs-qBcuuXh3.js +1 -0
  212. package/dist/web/assets/WorkspacesView-BzQ0aH74.css +1 -0
  213. package/dist/web/assets/WorkspacesView-CijIvfsp.js +2 -0
  214. package/dist/web/assets/_plugin-vue_export-helper-DlAUqK2U.js +1 -0
  215. package/dist/web/assets/chatroom-B5p-5n3y.svg +15 -0
  216. package/dist/web/assets/index-BDkarAkX.js +2 -0
  217. package/dist/web/assets/index-BegKQ3Yd.js +19 -0
  218. package/dist/web/assets/index-CkjqXRSj.css +1 -0
  219. package/dist/web/assets/syntax-highlight-B5ArnyrC.js +3 -0
  220. package/dist/web/assets/useOperationLabels-BDjzGDkT.js +1 -0
  221. package/dist/web/assets/utils-rtPwWNel.js +1 -0
  222. package/dist/web/index.html +19 -0
  223. package/package.json +125 -0
@@ -0,0 +1,70 @@
1
+ import { asChatRoomError } from "#core/errors/chatroom-error";
2
+ import { mcpTool } from "./tool-support.js";
3
+ export class PluginMcpRegistrar {
4
+ server;
5
+ operations;
6
+ pluginId;
7
+ toolControl;
8
+ constructor(server, operations, pluginId, toolControl) {
9
+ this.server = server;
10
+ this.operations = operations;
11
+ this.pluginId = pluginId;
12
+ this.toolControl = toolControl;
13
+ }
14
+ registerTool(name, config, handler) {
15
+ this.toolControl.define({
16
+ name,
17
+ pluginId: this.pluginId,
18
+ title: config.title,
19
+ description: config.description,
20
+ });
21
+ if (!this.server)
22
+ return;
23
+ const { action, audit, present, ...toolConfig } = config;
24
+ const callback = mcpTool(async (input) => {
25
+ const operation = this.operations.start({
26
+ pluginId: this.pluginId,
27
+ source: "mcp",
28
+ action: typeof action === "function" ? action(input) : action,
29
+ input: audit?.input ? audit.input(input) : input,
30
+ ...operationReferences(input),
31
+ });
32
+ let deferred = false;
33
+ const execution = {
34
+ operationId: operation.operationId,
35
+ deferCompletion() {
36
+ deferred = true;
37
+ },
38
+ };
39
+ try {
40
+ const result = await handler(input, execution);
41
+ if (!deferred)
42
+ this.operations.finish(operation.operationId, "success", audit?.output ? audit.output(result) : result);
43
+ return result;
44
+ }
45
+ catch (error) {
46
+ if (this.operations.get(operation.operationId)?.status === "running") {
47
+ const normalized = asChatRoomError(error);
48
+ this.operations.finish(operation.operationId, "error", null, {
49
+ code: normalized.code,
50
+ message: normalized.message,
51
+ details: normalized.details,
52
+ });
53
+ }
54
+ throw error;
55
+ }
56
+ }, present);
57
+ const registered = this.server.registerTool(name, toolConfig, callback);
58
+ this.toolControl.attach(name, registered);
59
+ }
60
+ }
61
+ function operationReferences(input) {
62
+ if (!input || typeof input !== "object" || Array.isArray(input))
63
+ return {};
64
+ const record = input;
65
+ return {
66
+ ...(typeof record.processId === "string"
67
+ ? { processId: record.processId }
68
+ : {}),
69
+ };
70
+ }
@@ -0,0 +1,3 @@
1
+ import type { ComputerAccessScope } from "#plugins/computer/types";
2
+ export declare function runWithMcpAccessScope<T>(scope: ComputerAccessScope, action: () => T): T;
3
+ export declare function currentMcpAccessScope(): ComputerAccessScope;
@@ -0,0 +1,8 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ const storage = new AsyncLocalStorage();
3
+ export function runWithMcpAccessScope(scope, action) {
4
+ return storage.run(scope, action);
5
+ }
6
+ export function currentMcpAccessScope() {
7
+ return storage.getStore() ?? "local";
8
+ }
@@ -0,0 +1,31 @@
1
+ import type { RegisteredTool } from "@modelcontextprotocol/server";
2
+ export interface McpToolSettingStore {
3
+ disabledTools(): string[];
4
+ setEnabled(name: string, enabled: boolean): void;
5
+ }
6
+ export interface McpToolSummary {
7
+ name: string;
8
+ pluginId: string;
9
+ title: string;
10
+ description: string;
11
+ enabled: boolean;
12
+ }
13
+ interface McpToolDefinition {
14
+ name: string;
15
+ pluginId: string;
16
+ title: string;
17
+ description: string;
18
+ }
19
+ export declare class McpToolControl {
20
+ private readonly store;
21
+ private readonly disabled;
22
+ private readonly definitions;
23
+ private readonly handles;
24
+ constructor(store: McpToolSettingStore);
25
+ define(definition: McpToolDefinition): void;
26
+ attach(name: string, tool: RegisteredTool): void;
27
+ list(): McpToolSummary[];
28
+ setEnabled(name: string, enabled: boolean): McpToolSummary;
29
+ private updateHandles;
30
+ }
31
+ export {};
@@ -0,0 +1,76 @@
1
+ import { ChatRoomError } from "#core/errors/chatroom-error";
2
+ export class McpToolControl {
3
+ store;
4
+ disabled = new Set();
5
+ definitions = new Map();
6
+ handles = new Map();
7
+ constructor(store) {
8
+ this.store = store;
9
+ for (const name of store.disabledTools())
10
+ this.disabled.add(name);
11
+ }
12
+ define(definition) {
13
+ const existing = this.definitions.get(definition.name);
14
+ if (existing && existing.pluginId !== definition.pluginId)
15
+ throw new Error(`MCP tool already belongs to another plugin: ${definition.name}`);
16
+ this.definitions.set(definition.name, definition);
17
+ }
18
+ attach(name, tool) {
19
+ let tools = this.handles.get(name);
20
+ if (!tools) {
21
+ tools = new Set();
22
+ this.handles.set(name, tools);
23
+ }
24
+ else {
25
+ for (const reference of tools)
26
+ if (!reference.deref())
27
+ tools.delete(reference);
28
+ }
29
+ tools.add(new WeakRef(tool));
30
+ if (this.disabled.has(name))
31
+ tool.disable();
32
+ }
33
+ list() {
34
+ return [...this.definitions.values()]
35
+ .map((definition) => ({
36
+ ...definition,
37
+ enabled: !this.disabled.has(definition.name),
38
+ }))
39
+ .sort((left, right) => left.pluginId.localeCompare(right.pluginId) ||
40
+ left.name.localeCompare(right.name));
41
+ }
42
+ setEnabled(name, enabled) {
43
+ const definition = this.definitions.get(name);
44
+ if (!definition)
45
+ throw new ChatRoomError("NOT_FOUND", `Unknown MCP tool: ${name}`);
46
+ if (enabled === !this.disabled.has(name))
47
+ return { ...definition, enabled };
48
+ this.store.setEnabled(name, enabled);
49
+ if (enabled)
50
+ this.disabled.delete(name);
51
+ else
52
+ this.disabled.add(name);
53
+ this.updateHandles(name, enabled);
54
+ return { ...definition, enabled };
55
+ }
56
+ updateHandles(name, enabled) {
57
+ const handles = this.handles.get(name);
58
+ if (!handles)
59
+ return;
60
+ for (const reference of [...handles]) {
61
+ const tool = reference.deref();
62
+ if (!tool) {
63
+ handles.delete(reference);
64
+ continue;
65
+ }
66
+ if (tool.enabled === enabled)
67
+ continue;
68
+ if (enabled)
69
+ tool.enable();
70
+ else
71
+ tool.disable();
72
+ }
73
+ if (!handles.size)
74
+ this.handles.delete(name);
75
+ }
76
+ }
@@ -0,0 +1,44 @@
1
+ import { type CallToolResult } from "@modelcontextprotocol/server";
2
+ import { z } from "zod";
3
+ export declare const closedRead: {
4
+ readOnlyHint: true;
5
+ destructiveHint: false;
6
+ idempotentHint: true;
7
+ openWorldHint: false;
8
+ };
9
+ export declare const destructiveLocalMutation: {
10
+ readOnlyHint: false;
11
+ destructiveHint: true;
12
+ idempotentHint: false;
13
+ openWorldHint: false;
14
+ };
15
+ export declare const openWorldMutation: {
16
+ readOnlyHint: false;
17
+ destructiveHint: true;
18
+ idempotentHint: false;
19
+ openWorldHint: true;
20
+ };
21
+ export declare const processSnapshotSchema: z.ZodObject<{
22
+ processId: z.ZodString;
23
+ command: z.ZodString;
24
+ args: z.ZodArray<z.ZodString>;
25
+ cwd: z.ZodString;
26
+ pid: z.ZodNullable<z.ZodNumber>;
27
+ state: z.ZodEnum<{
28
+ running: "running";
29
+ exited: "exited";
30
+ killed: "killed";
31
+ failed: "failed";
32
+ }>;
33
+ startedAt: z.ZodString;
34
+ finishedAt: z.ZodNullable<z.ZodString>;
35
+ durationMs: z.ZodNumber;
36
+ exitCode: z.ZodNullable<z.ZodNumber>;
37
+ signal: z.ZodNullable<z.ZodString>;
38
+ stdout: z.ZodString;
39
+ stderr: z.ZodString;
40
+ outputTruncated: z.ZodBoolean;
41
+ timedOut: z.ZodBoolean;
42
+ operationId: z.ZodString;
43
+ }, z.core.$strip>;
44
+ export declare function mcpTool<T>(operation: (input: T) => Promise<unknown> | unknown, present?: (value: unknown) => CallToolResult): (input: T) => Promise<CallToolResult>;
@@ -0,0 +1,72 @@
1
+ import { z } from "zod";
2
+ import { asChatRoomError } from "#core/errors/chatroom-error";
3
+ export const closedRead = {
4
+ readOnlyHint: true,
5
+ destructiveHint: false,
6
+ idempotentHint: true,
7
+ openWorldHint: false,
8
+ };
9
+ export const destructiveLocalMutation = {
10
+ readOnlyHint: false,
11
+ destructiveHint: true,
12
+ idempotentHint: false,
13
+ openWorldHint: false,
14
+ };
15
+ export const openWorldMutation = {
16
+ readOnlyHint: false,
17
+ destructiveHint: true,
18
+ idempotentHint: false,
19
+ openWorldHint: true,
20
+ };
21
+ export const processSnapshotSchema = z.object({
22
+ processId: z.string(),
23
+ command: z.string(),
24
+ args: z.array(z.string()),
25
+ cwd: z.string(),
26
+ pid: z.number().int().nullable(),
27
+ state: z.enum(["running", "exited", "killed", "failed"]),
28
+ startedAt: z.string(),
29
+ finishedAt: z.string().nullable(),
30
+ durationMs: z.number().nonnegative(),
31
+ exitCode: z.number().int().nullable(),
32
+ signal: z.string().nullable(),
33
+ stdout: z.string(),
34
+ stderr: z.string(),
35
+ outputTruncated: z.boolean(),
36
+ timedOut: z.boolean(),
37
+ operationId: z.string(),
38
+ });
39
+ export function mcpTool(operation, present) {
40
+ return async (input) => {
41
+ try {
42
+ const value = await operation(input);
43
+ if (present)
44
+ return present(value);
45
+ return {
46
+ content: [{ type: "text", text: JSON.stringify(value, null, 2) }],
47
+ structuredContent: asRecord(value),
48
+ };
49
+ }
50
+ catch (error) {
51
+ const normalized = asChatRoomError(error);
52
+ return {
53
+ isError: true,
54
+ content: [
55
+ {
56
+ type: "text",
57
+ text: JSON.stringify({
58
+ code: normalized.code,
59
+ message: normalized.message,
60
+ details: normalized.details ?? null,
61
+ }),
62
+ },
63
+ ],
64
+ };
65
+ }
66
+ };
67
+ }
68
+ function asRecord(value) {
69
+ return value && typeof value === "object" && !Array.isArray(value)
70
+ ? value
71
+ : { value };
72
+ }
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0"><dict>
4
+ <key>CFBundleIdentifier</key><string>com.chatroomcp.computer</string>
5
+ <key>CFBundleName</key><string>ChatRoom Computer Helper</string>
6
+ <key>CFBundleDisplayName</key><string>ChatRoom Computer Helper</string>
7
+ <key>CFBundleExecutable</key><string>chatroom-computer-helper</string>
8
+ <key>CFBundlePackageType</key><string>APPL</string>
9
+ <key>CFBundleVersion</key><string>1</string>
10
+ <key>CFBundleShortVersionString</key><string>1.0</string>
11
+ <key>LSMinimumSystemVersion</key><string>14.0</string>
12
+ <key>LSUIElement</key><true/>
13
+ <key>NSHumanReadableCopyright</key><string>ChatRoom</string>
14
+ </dict></plist>
@@ -0,0 +1,115 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>files</key>
6
+ <dict/>
7
+ <key>files2</key>
8
+ <dict/>
9
+ <key>rules</key>
10
+ <dict>
11
+ <key>^Resources/</key>
12
+ <true/>
13
+ <key>^Resources/.*\.lproj/</key>
14
+ <dict>
15
+ <key>optional</key>
16
+ <true/>
17
+ <key>weight</key>
18
+ <real>1000</real>
19
+ </dict>
20
+ <key>^Resources/.*\.lproj/locversion.plist$</key>
21
+ <dict>
22
+ <key>omit</key>
23
+ <true/>
24
+ <key>weight</key>
25
+ <real>1100</real>
26
+ </dict>
27
+ <key>^Resources/Base\.lproj/</key>
28
+ <dict>
29
+ <key>weight</key>
30
+ <real>1010</real>
31
+ </dict>
32
+ <key>^version.plist$</key>
33
+ <true/>
34
+ </dict>
35
+ <key>rules2</key>
36
+ <dict>
37
+ <key>.*\.dSYM($|/)</key>
38
+ <dict>
39
+ <key>weight</key>
40
+ <real>11</real>
41
+ </dict>
42
+ <key>^(.*/)?\.DS_Store$</key>
43
+ <dict>
44
+ <key>omit</key>
45
+ <true/>
46
+ <key>weight</key>
47
+ <real>2000</real>
48
+ </dict>
49
+ <key>^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/</key>
50
+ <dict>
51
+ <key>nested</key>
52
+ <true/>
53
+ <key>weight</key>
54
+ <real>10</real>
55
+ </dict>
56
+ <key>^.*</key>
57
+ <true/>
58
+ <key>^Info\.plist$</key>
59
+ <dict>
60
+ <key>omit</key>
61
+ <true/>
62
+ <key>weight</key>
63
+ <real>20</real>
64
+ </dict>
65
+ <key>^PkgInfo$</key>
66
+ <dict>
67
+ <key>omit</key>
68
+ <true/>
69
+ <key>weight</key>
70
+ <real>20</real>
71
+ </dict>
72
+ <key>^Resources/</key>
73
+ <dict>
74
+ <key>weight</key>
75
+ <real>20</real>
76
+ </dict>
77
+ <key>^Resources/.*\.lproj/</key>
78
+ <dict>
79
+ <key>optional</key>
80
+ <true/>
81
+ <key>weight</key>
82
+ <real>1000</real>
83
+ </dict>
84
+ <key>^Resources/.*\.lproj/locversion.plist$</key>
85
+ <dict>
86
+ <key>omit</key>
87
+ <true/>
88
+ <key>weight</key>
89
+ <real>1100</real>
90
+ </dict>
91
+ <key>^Resources/Base\.lproj/</key>
92
+ <dict>
93
+ <key>weight</key>
94
+ <real>1010</real>
95
+ </dict>
96
+ <key>^[^/]+$</key>
97
+ <dict>
98
+ <key>nested</key>
99
+ <true/>
100
+ <key>weight</key>
101
+ <real>10</real>
102
+ </dict>
103
+ <key>^embedded\.provisionprofile$</key>
104
+ <dict>
105
+ <key>weight</key>
106
+ <real>20</real>
107
+ </dict>
108
+ <key>^version\.plist$</key>
109
+ <dict>
110
+ <key>weight</key>
111
+ <real>20</real>
112
+ </dict>
113
+ </dict>
114
+ </dict>
115
+ </plist>
@@ -0,0 +1,24 @@
1
+ import type { Operation, OperationStart, OperationStatus } from "#core/operations/types";
2
+ import type { OperationQuery, OperationRepository } from "#core/operations/repository";
3
+ import type { RuntimeEventBus } from "#app/event-bus";
4
+ export declare class OperationLog {
5
+ private readonly repository;
6
+ private readonly eventBus;
7
+ private readonly maxPayloadBytes;
8
+ private readonly redactor;
9
+ constructor(repository: OperationRepository, eventBus: RuntimeEventBus, maxPayloadBytes: number);
10
+ start(request: OperationStart): Operation;
11
+ finish(operationId: string, status: Exclude<OperationStatus, "running">, output?: unknown, error?: unknown): Operation;
12
+ run<T>(request: OperationStart, action: () => Promise<T>): Promise<T>;
13
+ list(query?: OperationQuery): Operation[];
14
+ get(operationId: string): Operation | null;
15
+ associate(operationId: string, references: {
16
+ processId?: string | null;
17
+ }): Operation;
18
+ clearHistory(): {
19
+ deleted: number;
20
+ preserved: number;
21
+ };
22
+ reconcileInterrupted(): number;
23
+ private require;
24
+ }
@@ -0,0 +1,98 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { boundJson } from "#core/operations/bounded-value";
3
+ import { SecretRedactor } from "#core/operations/redactor";
4
+ import { asChatRoomError, ChatRoomError } from "#core/errors/chatroom-error";
5
+ export class OperationLog {
6
+ repository;
7
+ eventBus;
8
+ maxPayloadBytes;
9
+ redactor = new SecretRedactor();
10
+ constructor(repository, eventBus, maxPayloadBytes) {
11
+ this.repository = repository;
12
+ this.eventBus = eventBus;
13
+ this.maxPayloadBytes = maxPayloadBytes;
14
+ }
15
+ start(request) {
16
+ const input = boundJson(this.redactor.redact(request.input ?? null), this.maxPayloadBytes);
17
+ const operation = {
18
+ operationId: randomUUID(),
19
+ pluginId: request.pluginId,
20
+ source: request.source,
21
+ action: request.action,
22
+ status: "running",
23
+ processId: request.processId ?? null,
24
+ input: input.value,
25
+ output: null,
26
+ error: null,
27
+ inputTruncated: input.truncated,
28
+ outputTruncated: false,
29
+ startedAt: new Date().toISOString(),
30
+ finishedAt: null,
31
+ durationMs: null,
32
+ };
33
+ this.repository.insert(operation);
34
+ this.eventBus.emit({ type: "operation", operation });
35
+ return operation;
36
+ }
37
+ finish(operationId, status, output, error) {
38
+ const operation = this.require(operationId);
39
+ const finishedAt = new Date();
40
+ const bounded = boundJson(this.redactor.redact(output ?? null), this.maxPayloadBytes);
41
+ operation.status = status;
42
+ operation.output = bounded.value;
43
+ operation.outputTruncated = bounded.truncated;
44
+ operation.error = error
45
+ ? boundJson(this.redactor.redact(error), this.maxPayloadBytes).value
46
+ : null;
47
+ operation.finishedAt = finishedAt.toISOString();
48
+ operation.durationMs = Math.max(0, finishedAt.getTime() - new Date(operation.startedAt).getTime());
49
+ this.repository.update(operation);
50
+ this.eventBus.emit({ type: "operation", operation });
51
+ return operation;
52
+ }
53
+ async run(request, action) {
54
+ const operation = this.start(request);
55
+ try {
56
+ const result = await action();
57
+ this.finish(operation.operationId, "success", result);
58
+ return result;
59
+ }
60
+ catch (error) {
61
+ const normalized = asChatRoomError(error);
62
+ this.finish(operation.operationId, "error", null, {
63
+ code: normalized.code,
64
+ message: normalized.message,
65
+ details: normalized.details,
66
+ });
67
+ throw error;
68
+ }
69
+ }
70
+ list(query) {
71
+ return this.repository.list(query);
72
+ }
73
+ get(operationId) {
74
+ return this.repository.get(operationId);
75
+ }
76
+ associate(operationId, references) {
77
+ const operation = this.require(operationId);
78
+ if (references.processId !== undefined)
79
+ operation.processId = references.processId;
80
+ this.repository.update(operation);
81
+ this.eventBus.emit({ type: "operation", operation });
82
+ return operation;
83
+ }
84
+ clearHistory() {
85
+ const result = this.repository.clearHistory();
86
+ this.eventBus.emit({ type: "operations-cleared", ...result });
87
+ return result;
88
+ }
89
+ reconcileInterrupted() {
90
+ return this.repository.reconcileRunning(new Date().toISOString());
91
+ }
92
+ require(operationId) {
93
+ const operation = this.repository.get(operationId);
94
+ if (!operation)
95
+ throw new ChatRoomError("NOT_FOUND", `Operation not found: ${operationId}`);
96
+ return operation;
97
+ }
98
+ }
@@ -0,0 +1,50 @@
1
+ import { z } from "zod";
2
+ import { type CloudEntitlement, type CloudLeaseState, type CloudServiceId } from "./types.js";
3
+ declare const recoveryCredentialSchema: z.ZodObject<{
4
+ recoveryKey: z.ZodString;
5
+ }, z.core.$strict>;
6
+ declare const sessionSchema: z.ZodObject<{
7
+ purchaseToken: z.ZodString;
8
+ managementUrl: z.ZodString;
9
+ expiresAt: z.ZodString;
10
+ }, z.core.$strict>;
11
+ declare const restoreSchema: z.ZodObject<{
12
+ entitlements: z.ZodArray<z.ZodObject<{
13
+ service: z.ZodEnum<{
14
+ remote_mcp: "remote_mcp";
15
+ remote_web: "remote_web";
16
+ }>;
17
+ status: z.ZodLiteral<"active">;
18
+ sourceProvider: z.ZodString;
19
+ sourceId: z.ZodString;
20
+ validUntil: z.ZodNullable<z.ZodString>;
21
+ }, z.core.$strict>>;
22
+ customer: z.ZodObject<{
23
+ id: z.ZodString;
24
+ }, z.core.$strict>;
25
+ publicPrefix: z.ZodNullable<z.ZodString>;
26
+ recoveryKey: z.ZodString;
27
+ }, z.core.$strict>;
28
+ export declare class CloudApiClient {
29
+ private readonly baseUrl;
30
+ constructor(baseUrl: string);
31
+ createManagementSession(identity: DeviceIdentity): Promise<z.infer<typeof sessionSchema>>;
32
+ status(identity: DeviceIdentity, purchaseToken: string | null): Promise<{
33
+ managementSessionActive: boolean;
34
+ entitlements: CloudEntitlement[];
35
+ customer: {
36
+ id: string;
37
+ } | null;
38
+ publicPrefix: string | null;
39
+ }>;
40
+ restore(identity: DeviceIdentity, recoveryKey: string): Promise<z.infer<typeof restoreSchema>>;
41
+ replaceRecoveryKey(identity: DeviceIdentity): Promise<z.infer<typeof recoveryCredentialSchema>>;
42
+ lease(identity: DeviceIdentity, requestedServices: CloudServiceId[]): Promise<CloudLeaseState>;
43
+ private devicePost;
44
+ }
45
+ interface DeviceIdentity {
46
+ installationId: string;
47
+ devicePublicKey: string;
48
+ devicePrivateKey: string;
49
+ }
50
+ export {};