@typelets/mcp 0.2.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 (66) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +148 -0
  3. package/dist/client.d.ts +23 -0
  4. package/dist/client.js +58 -0
  5. package/dist/client.js.map +1 -0
  6. package/dist/env.d.ts +6 -0
  7. package/dist/env.js +36 -0
  8. package/dist/env.js.map +1 -0
  9. package/dist/index.d.ts +2 -0
  10. package/dist/index.js +77 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/profile.d.ts +50 -0
  13. package/dist/profile.js +35 -0
  14. package/dist/profile.js.map +1 -0
  15. package/dist/tools/_shared.d.ts +17 -0
  16. package/dist/tools/_shared.js +55 -0
  17. package/dist/tools/_shared.js.map +1 -0
  18. package/dist/tools/apply_problem_to_workspace.d.ts +12 -0
  19. package/dist/tools/apply_problem_to_workspace.js +31 -0
  20. package/dist/tools/apply_problem_to_workspace.js.map +1 -0
  21. package/dist/tools/create_file.d.ts +11 -0
  22. package/dist/tools/create_file.js +29 -0
  23. package/dist/tools/create_file.js.map +1 -0
  24. package/dist/tools/create_workspace.d.ts +11 -0
  25. package/dist/tools/create_workspace.js +33 -0
  26. package/dist/tools/create_workspace.js.map +1 -0
  27. package/dist/tools/delete_file.d.ts +12 -0
  28. package/dist/tools/delete_file.js +26 -0
  29. package/dist/tools/delete_file.js.map +1 -0
  30. package/dist/tools/delete_problem.d.ts +11 -0
  31. package/dist/tools/delete_problem.js +29 -0
  32. package/dist/tools/delete_problem.js.map +1 -0
  33. package/dist/tools/edit_problem.d.ts +11 -0
  34. package/dist/tools/edit_problem.js +87 -0
  35. package/dist/tools/edit_problem.js.map +1 -0
  36. package/dist/tools/get_problem.d.ts +13 -0
  37. package/dist/tools/get_problem.js +27 -0
  38. package/dist/tools/get_problem.js.map +1 -0
  39. package/dist/tools/get_workspace.d.ts +12 -0
  40. package/dist/tools/get_workspace.js +23 -0
  41. package/dist/tools/get_workspace.js.map +1 -0
  42. package/dist/tools/list_pending_invites.d.ts +12 -0
  43. package/dist/tools/list_pending_invites.js +39 -0
  44. package/dist/tools/list_pending_invites.js.map +1 -0
  45. package/dist/tools/list_problems.d.ts +15 -0
  46. package/dist/tools/list_problems.js +38 -0
  47. package/dist/tools/list_problems.js.map +1 -0
  48. package/dist/tools/list_recordings.d.ts +12 -0
  49. package/dist/tools/list_recordings.js +20 -0
  50. package/dist/tools/list_recordings.js.map +1 -0
  51. package/dist/tools/list_workspace_files.d.ts +15 -0
  52. package/dist/tools/list_workspace_files.js +25 -0
  53. package/dist/tools/list_workspace_files.js.map +1 -0
  54. package/dist/tools/list_workspaces.d.ts +11 -0
  55. package/dist/tools/list_workspaces.js +20 -0
  56. package/dist/tools/list_workspaces.js.map +1 -0
  57. package/dist/tools/read_workspace_file.d.ts +16 -0
  58. package/dist/tools/read_workspace_file.js +24 -0
  59. package/dist/tools/read_workspace_file.js.map +1 -0
  60. package/dist/tools/save_problem_to_library.d.ts +11 -0
  61. package/dist/tools/save_problem_to_library.js +83 -0
  62. package/dist/tools/save_problem_to_library.js.map +1 -0
  63. package/dist/tools/update_file.d.ts +12 -0
  64. package/dist/tools/update_file.js +27 -0
  65. package/dist/tools/update_file.js.map +1 -0
  66. package/package.json +50 -0
@@ -0,0 +1,29 @@
1
+ import { z } from 'zod';
2
+ import { toolAllowedForProfile } from '../profile.js';
3
+ import { ok, fail } from './_shared.js';
4
+ export function registerCreateFile(server, client, env) {
5
+ // Profile gate: keep the string in sync with INTERVIEWER_ONLY_TOOLS in ../profile.ts.
6
+ if (!toolAllowedForProfile('create_file', env.profile))
7
+ return;
8
+ server.registerTool('create_file', {
9
+ title: 'Create a file in a workspace',
10
+ description: 'Create a new file at a slash-separated path in a workspace. Folders are created as needed. Returns the new file id. Errors: 409 if a file already exists at the path (use update_file instead); 413 if content exceeds 1 MiB.',
11
+ inputSchema: {
12
+ workspaceId: z.string().min(1).describe('The workspace id from list_workspaces.'),
13
+ path: z.string().min(1).describe('Slash-separated path from the workspace root (e.g. "src/lib/auth.ts"). Cannot contain ".." segments.'),
14
+ content: z.string().optional().describe('Initial UTF-8 content. Omit to create an empty placeholder file that the y-websocket server will materialise on first open.'),
15
+ },
16
+ }, async ({ workspaceId, path, content }) => {
17
+ try {
18
+ const body = { path };
19
+ if (content !== undefined)
20
+ body.content = content;
21
+ const result = await client.post(`/workspaces/${encodeURIComponent(workspaceId)}/files`, body);
22
+ return ok(`Created ${result.path} (id=${result.id}).`, { file: result });
23
+ }
24
+ catch (err) {
25
+ return fail(err);
26
+ }
27
+ });
28
+ }
29
+ //# sourceMappingURL=create_file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create_file.js","sourceRoot":"","sources":["../../src/tools/create_file.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AASxC,MAAM,UAAU,kBAAkB,CAAC,MAAiB,EAAE,MAAsB,EAAE,GAAQ;IACpF,sFAAsF;IACtF,IAAI,CAAC,qBAAqB,CAAC,aAAa,EAAE,GAAG,CAAC,OAAO,CAAC;QAAE,OAAO;IAE/D,MAAM,CAAC,YAAY,CACjB,aAAa,EACb;QACE,KAAK,EAAE,8BAA8B;QACrC,WAAW,EACT,+NAA+N;QACjO,WAAW,EAAE;YACX,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,wCAAwC,CAAC;YACjF,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,sGAAsG,CAAC;YACxI,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6HAA6H,CAAC;SACvK;KACF,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;QACvC,IAAI,CAAC;YACH,MAAM,IAAI,GAAuC,EAAE,IAAI,EAAE,CAAC;YAC1D,IAAI,OAAO,KAAK,SAAS;gBAAE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;YAClD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAC9B,eAAe,kBAAkB,CAAC,WAAW,CAAC,QAAQ,EACtD,IAAI,CACL,CAAC;YACF,OAAO,EAAE,CAAC,WAAW,MAAM,CAAC,IAAI,QAAQ,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QAC3E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * create_workspace: create a new Typelets workspace.
3
+ *
4
+ * Interviewer-only. Candidates never see this tool in listTools.
5
+ * Returns the new workspace object including its id, which the
6
+ * caller will need for subsequent tool calls (e.g. apply_problem_to_workspace).
7
+ */
8
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
9
+ import type { TypeletsClient } from '../client.js';
10
+ import type { Env } from '../env.js';
11
+ export declare function registerCreateWorkspace(server: McpServer, client: TypeletsClient, env: Env): void;
@@ -0,0 +1,33 @@
1
+ import { z } from 'zod';
2
+ import { toolAllowedForProfile } from '../profile.js';
3
+ import { ok, fail } from './_shared.js';
4
+ export function registerCreateWorkspace(server, client, env) {
5
+ // Profile gate: keep the string in sync with INTERVIEWER_ONLY_TOOLS in ../profile.ts.
6
+ if (!toolAllowedForProfile('create_workspace', env.profile))
7
+ return;
8
+ server.registerTool('create_workspace', {
9
+ title: 'Create a new workspace',
10
+ description: 'Create a new Typelets workspace. Returns the new workspace object including its id. ' +
11
+ 'Use the returned id to apply a problem (apply_problem_to_workspace) or create files. ' +
12
+ 'Errors: 409 if mode=interview and shareScope=public (interviews cannot be public).',
13
+ inputSchema: {
14
+ name: z.string().min(1).max(80).describe('Display name for the new workspace (max 80 chars).'),
15
+ mode: z.enum(['general', 'interview']).optional().describe('Workspace mode. Defaults to "general". Use "interview" for structured coding interviews.'),
16
+ shareScope: z.enum(['private', 'org', 'public']).optional().describe('Sharing scope. Defaults to "private". "interview" mode cannot be "public".'),
17
+ },
18
+ }, async ({ name, mode, shareScope }) => {
19
+ try {
20
+ const body = { name };
21
+ if (mode !== undefined)
22
+ body.mode = mode;
23
+ if (shareScope !== undefined)
24
+ body.shareScope = shareScope;
25
+ const result = await client.post('/workspaces', body);
26
+ return ok(`Created workspace "${result.workspace.name}" (id=${result.workspace.id}).`, { workspace: result.workspace });
27
+ }
28
+ catch (err) {
29
+ return fail(err);
30
+ }
31
+ });
32
+ }
33
+ //# sourceMappingURL=create_workspace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create_workspace.js","sourceRoot":"","sources":["../../src/tools/create_workspace.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAaxC,MAAM,UAAU,uBAAuB,CAAC,MAAiB,EAAE,MAAsB,EAAE,GAAQ;IACzF,sFAAsF;IACtF,IAAI,CAAC,qBAAqB,CAAC,kBAAkB,EAAE,GAAG,CAAC,OAAO,CAAC;QAAE,OAAO;IAEpE,MAAM,CAAC,YAAY,CACjB,kBAAkB,EAClB;QACE,KAAK,EAAE,wBAAwB;QAC/B,WAAW,EACT,sFAAsF;YACtF,uFAAuF;YACvF,oFAAoF;QACtF,WAAW,EAAE;YACX,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,oDAAoD,CAAC;YAC9F,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0FAA0F,CAAC;YACtJ,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4EAA4E,CAAC;SACnJ;KACF,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE;QACnC,IAAI,CAAC;YACH,MAAM,IAAI,GAAyD,EAAE,IAAI,EAAE,CAAC;YAC5E,IAAI,IAAI,KAAK,SAAS;gBAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;YACzC,IAAI,UAAU,KAAK,SAAS;gBAAE,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;YAC3D,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAA0B,aAAa,EAAE,IAAI,CAAC,CAAC;YAC/E,OAAO,EAAE,CAAC,sBAAsB,MAAM,CAAC,SAAS,CAAC,IAAI,SAAS,MAAM,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;QAC1H,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * delete_file: remove a file from a workspace.
3
+ *
4
+ * Available to both interviewer and candidate profiles. Idempotent: if the
5
+ * file id no longer exists in the workspace the server returns 204 without
6
+ * error. Marked destructive because the delete is permanent from the MCP
7
+ * server's perspective.
8
+ */
9
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
10
+ import type { TypeletsClient } from '../client.js';
11
+ import type { Env } from '../env.js';
12
+ export declare function registerDeleteFile(server: McpServer, client: TypeletsClient, env: Env): void;
@@ -0,0 +1,26 @@
1
+ import { z } from 'zod';
2
+ import { toolAllowedForProfile } from '../profile.js';
3
+ import { ok, fail } from './_shared.js';
4
+ export function registerDeleteFile(server, client, env) {
5
+ // Profile gate: keep the string in sync with INTERVIEWER_ONLY_TOOLS in ../profile.ts.
6
+ if (!toolAllowedForProfile('delete_file', env.profile))
7
+ return;
8
+ server.registerTool('delete_file', {
9
+ title: 'Delete a file from a workspace',
10
+ description: 'Permanently delete a file from a workspace. This action is idempotent: if the file id no longer exists the operation still succeeds silently. The deletion is immediate and cannot be undone via this tool.',
11
+ inputSchema: {
12
+ workspaceId: z.string().min(1).describe('The workspace id from list_workspaces.'),
13
+ fileId: z.string().min(1).describe('The file id from list_workspace_files.'),
14
+ },
15
+ annotations: { destructiveHint: true },
16
+ }, async ({ workspaceId, fileId }) => {
17
+ try {
18
+ await client.delete(`/workspaces/${encodeURIComponent(workspaceId)}/files/${encodeURIComponent(fileId)}`);
19
+ return ok(`Deleted file ${fileId} from workspace ${workspaceId}.`, { deleted: true });
20
+ }
21
+ catch (err) {
22
+ return fail(err);
23
+ }
24
+ });
25
+ }
26
+ //# sourceMappingURL=delete_file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete_file.js","sourceRoot":"","sources":["../../src/tools/delete_file.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAExC,MAAM,UAAU,kBAAkB,CAAC,MAAiB,EAAE,MAAsB,EAAE,GAAQ;IACpF,sFAAsF;IACtF,IAAI,CAAC,qBAAqB,CAAC,aAAa,EAAE,GAAG,CAAC,OAAO,CAAC;QAAE,OAAO;IAE/D,MAAM,CAAC,YAAY,CACjB,aAAa,EACb;QACE,KAAK,EAAE,gCAAgC;QACvC,WAAW,EACT,6MAA6M;QAC/M,WAAW,EAAE;YACX,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,wCAAwC,CAAC;YACjF,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,wCAAwC,CAAC;SAC7E;QACD,WAAW,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE;KACvC,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE;QAChC,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,MAAM,CACjB,eAAe,kBAAkB,CAAC,WAAW,CAAC,UAAU,kBAAkB,CAAC,MAAM,CAAC,EAAE,CACrF,CAAC;YACF,OAAO,EAAE,CAAC,gBAAgB,MAAM,mBAAmB,WAAW,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QACxF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * delete_problem: delete a problem from the library.
3
+ *
4
+ * Interviewer-only. PERMANENT: the problem is removed from the library.
5
+ * Workspaces that previously applied it keep their copy of the prompt,
6
+ * criteria, and files; the deletion only removes the library entry.
7
+ */
8
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
9
+ import type { TypeletsClient } from '../client.js';
10
+ import type { Env } from '../env.js';
11
+ export declare function registerDeleteProblem(server: McpServer, client: TypeletsClient, env: Env): void;
@@ -0,0 +1,29 @@
1
+ import { z } from 'zod';
2
+ import { toolAllowedForProfile } from '../profile.js';
3
+ import { ok, fail } from './_shared.js';
4
+ export function registerDeleteProblem(server, client, env) {
5
+ // Profile gate: keep the string in sync with INTERVIEWER_ONLY_TOOLS in ../profile.ts.
6
+ if (!toolAllowedForProfile('delete_problem', env.profile))
7
+ return;
8
+ server.registerTool('delete_problem', {
9
+ title: 'Delete a problem from the library',
10
+ description: 'Delete a problem from the Typelets library. PERMANENT: the problem is removed and cannot ' +
11
+ 'be restored. Workspaces that previously applied it keep their copy of the ' +
12
+ 'prompt, criteria, and files. ' +
13
+ 'Errors: 403 if you are not the author (or not an org admin for shared-library problems); ' +
14
+ '404 if the problem is not found.',
15
+ inputSchema: {
16
+ problemId: z.string().min(1).describe('The problem id or slug from list_problems.'),
17
+ },
18
+ annotations: { destructiveHint: true },
19
+ }, async ({ problemId }) => {
20
+ try {
21
+ await client.delete(`/problems/${encodeURIComponent(problemId)}`);
22
+ return ok(`Deleted problem ${problemId}.`, { deleted: true, problemId });
23
+ }
24
+ catch (err) {
25
+ return fail(err);
26
+ }
27
+ });
28
+ }
29
+ //# sourceMappingURL=delete_problem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete_problem.js","sourceRoot":"","sources":["../../src/tools/delete_problem.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAExC,MAAM,UAAU,qBAAqB,CAAC,MAAiB,EAAE,MAAsB,EAAE,GAAQ;IACvF,sFAAsF;IACtF,IAAI,CAAC,qBAAqB,CAAC,gBAAgB,EAAE,GAAG,CAAC,OAAO,CAAC;QAAE,OAAO;IAElE,MAAM,CAAC,YAAY,CACjB,gBAAgB,EAChB;QACE,KAAK,EAAE,mCAAmC;QAC1C,WAAW,EACT,2FAA2F;YAC3F,4EAA4E;YAC5E,+BAA+B;YAC/B,2FAA2F;YAC3F,kCAAkC;QACpC,WAAW,EAAE;YACX,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,4CAA4C,CAAC;SACpF;QACD,WAAW,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE;KACvC,EACD,KAAK,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE;QACtB,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,MAAM,CAAO,aAAa,kBAAkB,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;YACxE,OAAO,EAAE,CAAC,mBAAmB,SAAS,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;QAC3E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * edit_problem: edit an existing library problem.
3
+ *
4
+ * Interviewer-only. All fields are optional. Send only the ones you
5
+ * want to change. Workspaces that previously applied the problem keep
6
+ * their copy of the prompt/criteria/files; changes only affect future applies.
7
+ */
8
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
9
+ import type { TypeletsClient } from '../client.js';
10
+ import type { Env } from '../env.js';
11
+ export declare function registerEditProblem(server: McpServer, client: TypeletsClient, env: Env): void;
@@ -0,0 +1,87 @@
1
+ import { z } from 'zod';
2
+ import { toolAllowedForProfile } from '../profile.js';
3
+ import { ok, fail } from './_shared.js';
4
+ const criterionSchema = z.object({
5
+ name: z.string().trim().min(1).max(120),
6
+ description: z.string().max(2000),
7
+ });
8
+ const stdinTestCaseSchema = z.object({
9
+ kind: z.literal('stdin').optional(),
10
+ name: z.string().trim().min(1).max(120),
11
+ stdin: z.string().max(20000),
12
+ expectedStdout: z.string().max(20000),
13
+ visible: z.boolean().default(true),
14
+ });
15
+ const frameworkTestCaseSchema = z.object({
16
+ kind: z.literal('framework'),
17
+ name: z.string().trim().min(1).max(120),
18
+ framework: z.enum([
19
+ 'go', 'pytest', 'jest', 'vitest', 'rspec',
20
+ 'minitest', 'npm-test', 'rails', 'phpunit', 'other',
21
+ ]),
22
+ command: z.string().min(1).max(4000),
23
+ visible: z.boolean().default(true),
24
+ });
25
+ const testCaseSchema = z.union([frameworkTestCaseSchema, stdinTestCaseSchema]);
26
+ const problemFileSchema = z.object({
27
+ name: z.string().trim().min(1).max(512).describe('Slash-separated path from workspace root.'),
28
+ content: z.string().max(1_048_576),
29
+ });
30
+ const categoryEnum = z.enum([
31
+ 'arrays_strings',
32
+ 'hash_tables',
33
+ 'linked_lists',
34
+ 'stacks_queues',
35
+ 'trees',
36
+ 'graphs',
37
+ 'recursion_dp',
38
+ 'sorting_searching',
39
+ 'math_bigo',
40
+ 'design',
41
+ 'ai',
42
+ 'data',
43
+ 'frontend',
44
+ 'backend',
45
+ 'systems',
46
+ 'sql',
47
+ 'other',
48
+ ]);
49
+ export function registerEditProblem(server, client, env) {
50
+ // Profile gate: keep the string in sync with INTERVIEWER_ONLY_TOOLS in ../profile.ts.
51
+ if (!toolAllowedForProfile('edit_problem', env.profile))
52
+ return;
53
+ server.registerTool('edit_problem', {
54
+ title: 'Edit an existing library problem',
55
+ description: 'Edit an existing problem in the Typelets library. All fields are optional. Only the fields ' +
56
+ 'you provide are updated. Workspaces that previously applied this problem keep their copy of the ' +
57
+ 'prompt, criteria, and files; edits here only affect future apply_problem_to_workspace calls. ' +
58
+ 'Destructive. Changes to the library entry are immediate and cannot be undone via this tool. ' +
59
+ 'Errors: 400 if no fields are provided; 403 if you are not the author (or not an org admin ' +
60
+ 'for shared-library problems); 404 if the problem is not found.',
61
+ inputSchema: {
62
+ problemId: z.string().min(1).describe('The problem id or slug from list_problems.'),
63
+ title: z.string().trim().min(1).max(200).optional().describe('New title.'),
64
+ difficulty: z.enum(['easy', 'medium', 'hard']).optional().describe('New difficulty.'),
65
+ prompt: z.string().min(1).max(20000).optional().describe('New problem statement. Markdown supported.'),
66
+ rubric: z.string().max(20000).nullable().optional().describe('New interviewer-only rubric. Pass null to clear.'),
67
+ criteria: z.array(criterionSchema).max(20).optional().describe('Replace the full criteria list. Up to 20 entries.'),
68
+ tests: z.array(testCaseSchema).max(40).optional().describe('Replace the full test-case list. Up to 40 entries.'),
69
+ starters: z.record(z.string(), z.string()).optional().describe('Replace the legacy single-file starter map.'),
70
+ starterFiles: z.array(problemFileSchema).max(5000).optional().describe('Replace the full starter file tree. Up to 5000 files.'),
71
+ solutionFiles: z.array(problemFileSchema).max(5000).optional().describe('Replace the full solution file tree. Up to 5000 files.'),
72
+ testFiles: z.array(problemFileSchema).max(5000).optional().describe('Replace the full test file tree. Up to 5000 files.'),
73
+ tags: z.array(z.string().trim().min(1).max(40)).max(20).optional().describe('Replace the tag list. Up to 20 tags.'),
74
+ category: categoryEnum.optional().describe('New category.'),
75
+ },
76
+ annotations: { destructiveHint: true },
77
+ }, async ({ problemId, ...fields }) => {
78
+ try {
79
+ const result = await client.patch(`/problems/${encodeURIComponent(problemId)}`, fields);
80
+ return ok(`Updated problem "${result.problem.title}" (id=${result.problem.id}).`, { problem: result.problem });
81
+ }
82
+ catch (err) {
83
+ return fail(err);
84
+ }
85
+ });
86
+ }
87
+ //# sourceMappingURL=edit_problem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit_problem.js","sourceRoot":"","sources":["../../src/tools/edit_problem.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * get_problem: fetch the full detail for a single library problem.
3
+ *
4
+ * In `interviewer` profile, returns prompt + rubric + criteria + visible
5
+ * and hidden tests + solution metadata. In `candidate` profile the
6
+ * rubric, criteria, hidden tests, and solution are stripped before
7
+ * leaving this process. The LLM never sees them. The filtering is in
8
+ * `profile.ts`; this handler just forwards the result through it.
9
+ */
10
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
11
+ import type { TypeletsClient } from '../client.js';
12
+ import type { Env } from '../env.js';
13
+ export declare function registerGetProblem(server: McpServer, client: TypeletsClient, env: Env): void;
@@ -0,0 +1,27 @@
1
+ import { z } from 'zod';
2
+ import { filterProblemForProfile } from '../profile.js';
3
+ import { ok, fail } from './_shared.js';
4
+ export function registerGetProblem(server, client, env) {
5
+ server.registerTool('get_problem', {
6
+ title: 'Get library problem',
7
+ description: 'Fetch the full detail of a library problem by id. In the interviewer profile the response includes rubric, criteria, hidden tests, and solution metadata; in the candidate profile those fields are stripped before the response leaves this server.',
8
+ inputSchema: {
9
+ problemId: z.string().min(1).describe('The library problem id.'),
10
+ },
11
+ }, async ({ problemId }) => {
12
+ try {
13
+ const { problem } = await client.get(`/problems/${encodeURIComponent(problemId)}`);
14
+ const filtered = filterProblemForProfile(problem, env);
15
+ const note = env.profile === 'candidate'
16
+ ? ' (candidate profile: rubric, criteria, hidden tests, and solution stripped)'
17
+ : '';
18
+ return ok(`Problem "${filtered.title}" (${filtered.difficulty})${note}.`, {
19
+ problem: filtered,
20
+ });
21
+ }
22
+ catch (err) {
23
+ return fail(err);
24
+ }
25
+ });
26
+ }
27
+ //# sourceMappingURL=get_problem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get_problem.js","sourceRoot":"","sources":["../../src/tools/get_problem.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,uBAAuB,EAA0B,MAAM,eAAe,CAAC;AAChF,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAMxC,MAAM,UAAU,kBAAkB,CAChC,MAAiB,EACjB,MAAsB,EACtB,GAAQ;IAER,MAAM,CAAC,YAAY,CACjB,aAAa,EACb;QACE,KAAK,EAAE,qBAAqB;QAC5B,WAAW,EACT,sPAAsP;QACxP,WAAW,EAAE;YACX,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,yBAAyB,CAAC;SACjE;KACF,EACD,KAAK,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE;QACtB,IAAI,CAAC;YACH,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,GAAG,CAClC,aAAa,kBAAkB,CAAC,SAAS,CAAC,EAAE,CAC7C,CAAC;YACF,MAAM,QAAQ,GAAG,uBAAuB,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;YACvD,MAAM,IAAI,GACR,GAAG,CAAC,OAAO,KAAK,WAAW;gBACzB,CAAC,CAAC,6EAA6E;gBAC/E,CAAC,CAAC,EAAE,CAAC;YACT,OAAO,EAAE,CAAC,YAAY,QAAQ,CAAC,KAAK,MAAM,QAAQ,CAAC,UAAU,IAAI,IAAI,GAAG,EAAE;gBACxE,OAAO,EAAE,QAAQ;aAClB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * get_workspace: fetch the full summary for a single workspace.
3
+ *
4
+ * Returns the applied problem id (when any), preview configuration,
5
+ * and the candidate / interviewer membership state. Combine with
6
+ * `list_workspace_files` to surface what a candidate has actually
7
+ * been working on inside a workspace.
8
+ */
9
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
10
+ import type { TypeletsClient } from '../client.js';
11
+ import type { Env } from '../env.js';
12
+ export declare function registerGetWorkspace(server: McpServer, client: TypeletsClient, _env: Env): void;
@@ -0,0 +1,23 @@
1
+ import { z } from 'zod';
2
+ import { ok, fail } from './_shared.js';
3
+ export function registerGetWorkspace(server, client, _env) {
4
+ server.registerTool('get_workspace', {
5
+ title: 'Get workspace',
6
+ description: 'Fetch the full workspace summary for a given id (use list_workspaces to discover ids). Returns role, share scope, applied problem id, and preview settings.',
7
+ inputSchema: {
8
+ workspaceId: z
9
+ .string()
10
+ .min(1)
11
+ .describe('The workspace id, e.g. "cmpkojnzm0004iqsfa2o2z94n".'),
12
+ },
13
+ }, async ({ workspaceId }) => {
14
+ try {
15
+ const { workspace } = await client.get(`/workspaces/${encodeURIComponent(workspaceId)}`);
16
+ return ok(`Workspace "${workspace.name}" (${workspace.mode}).`, { workspace });
17
+ }
18
+ catch (err) {
19
+ return fail(err);
20
+ }
21
+ });
22
+ }
23
+ //# sourceMappingURL=get_workspace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get_workspace.js","sourceRoot":"","sources":["../../src/tools/get_workspace.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAmBxC,MAAM,UAAU,oBAAoB,CAClC,MAAiB,EACjB,MAAsB,EACtB,IAAS;IAET,MAAM,CAAC,YAAY,CACjB,eAAe,EACf;QACE,KAAK,EAAE,eAAe;QACtB,WAAW,EACT,6JAA6J;QAC/J,WAAW,EAAE;YACX,WAAW,EAAE,CAAC;iBACX,MAAM,EAAE;iBACR,GAAG,CAAC,CAAC,CAAC;iBACN,QAAQ,CAAC,qDAAqD,CAAC;SACnE;KACF,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE;QACxB,IAAI,CAAC;YACH,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,GAAG,CACpC,eAAe,kBAAkB,CAAC,WAAW,CAAC,EAAE,CACjD,CAAC;YACF,OAAO,EAAE,CAAC,cAAc,SAAS,CAAC,IAAI,MAAM,SAAS,CAAC,IAAI,IAAI,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;QACjF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * list_pending_invites: return invitations addressed to the caller.
3
+ *
4
+ * Returns both workspace-level and organization-level invites in the
5
+ * same response so the LLM can answer "what's waiting for me?" with a
6
+ * single tool call. Each entry carries an `accept` and `decline` path
7
+ * the agent could plug into a Phase 2 write tool later.
8
+ */
9
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
10
+ import type { TypeletsClient } from '../client.js';
11
+ import type { Env } from '../env.js';
12
+ export declare function registerListPendingInvites(server: McpServer, client: TypeletsClient, _env: Env): void;
@@ -0,0 +1,39 @@
1
+ import { ok, fail } from './_shared.js';
2
+ export function registerListPendingInvites(server, client, _env) {
3
+ server.registerTool('list_pending_invites', {
4
+ title: 'List pending invitations',
5
+ description: "Return every workspace + organisation invitation addressed to the caller's email. Combine the two server-side so the model sees one merged list.",
6
+ inputSchema: {},
7
+ }, async () => {
8
+ try {
9
+ const [workspaceInvites, orgInvites] = await Promise.all([
10
+ client.get('/invites'),
11
+ client.get('/invitations'),
12
+ ]);
13
+ const merged = [
14
+ ...workspaceInvites.invites.map((i) => ({
15
+ kind: 'workspace',
16
+ id: i.id,
17
+ workspaceId: i.workspaceId,
18
+ workspaceName: i.workspaceName,
19
+ role: i.role,
20
+ createdAt: i.createdAt,
21
+ })),
22
+ ...orgInvites.invitations.map((i) => ({
23
+ kind: 'organization',
24
+ id: i.id,
25
+ organizationId: i.organization.id,
26
+ organizationName: i.organization.name,
27
+ role: i.role,
28
+ createdAt: i.createdAt,
29
+ expiresAt: i.expiresAt,
30
+ })),
31
+ ];
32
+ return ok(`Found ${merged.length} pending invitation${merged.length === 1 ? '' : 's'}.`, { invites: merged });
33
+ }
34
+ catch (err) {
35
+ return fail(err);
36
+ }
37
+ });
38
+ }
39
+ //# sourceMappingURL=list_pending_invites.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list_pending_invites.js","sourceRoot":"","sources":["../../src/tools/list_pending_invites.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AA6BxC,MAAM,UAAU,0BAA0B,CACxC,MAAiB,EACjB,MAAsB,EACtB,IAAS;IAET,MAAM,CAAC,YAAY,CACjB,sBAAsB,EACtB;QACE,KAAK,EAAE,0BAA0B;QACjC,WAAW,EACT,kJAAkJ;QACpJ,WAAW,EAAE,EAAE;KAChB,EACD,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,MAAM,CAAC,gBAAgB,EAAE,UAAU,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;gBACvD,MAAM,CAAC,GAAG,CAAsB,UAAU,CAAC;gBAC3C,MAAM,CAAC,GAAG,CAA6B,cAAc,CAAC;aACvD,CAAC,CAAC;YACH,MAAM,MAAM,GAAoC;gBAC9C,GAAG,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAkB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBACvD,IAAI,EAAE,WAAW;oBACjB,EAAE,EAAE,CAAC,CAAC,EAAE;oBACR,WAAW,EAAE,CAAC,CAAC,WAAW;oBAC1B,aAAa,EAAE,CAAC,CAAC,aAAa;oBAC9B,IAAI,EAAE,CAAC,CAAC,IAAI;oBACZ,SAAS,EAAE,CAAC,CAAC,SAAS;iBACvB,CAAC,CAAC;gBACH,GAAG,UAAU,CAAC,WAAW,CAAC,GAAG,CAAY,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBAC/C,IAAI,EAAE,cAAc;oBACpB,EAAE,EAAE,CAAC,CAAC,EAAE;oBACR,cAAc,EAAE,CAAC,CAAC,YAAY,CAAC,EAAE;oBACjC,gBAAgB,EAAE,CAAC,CAAC,YAAY,CAAC,IAAI;oBACrC,IAAI,EAAE,CAAC,CAAC,IAAI;oBACZ,SAAS,EAAE,CAAC,CAAC,SAAS;oBACtB,SAAS,EAAE,CAAC,CAAC,SAAS;iBACvB,CAAC,CAAC;aACJ,CAAC;YACF,OAAO,EAAE,CACP,SAAS,MAAM,CAAC,MAAM,sBAAsB,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,EAC7E,EAAE,OAAO,EAAE,MAAM,EAAE,CACpB,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * list_problems: return library entries the caller can see.
3
+ *
4
+ * Respects the existing API-side scoping (system library vs. org
5
+ * library) plus the candidate profile when active (the profile gate is
6
+ * a list-level no-op; the per-problem filtering happens in get_problem).
7
+ *
8
+ * Optional filters mirror the in-app picker: category, difficulty,
9
+ * scope (system / org / all). The model can call this iteratively to
10
+ * narrow down before a get_problem.
11
+ */
12
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
13
+ import type { TypeletsClient } from '../client.js';
14
+ import type { Env } from '../env.js';
15
+ export declare function registerListProblems(server: McpServer, client: TypeletsClient, _env: Env): void;
@@ -0,0 +1,38 @@
1
+ import { z } from 'zod';
2
+ import { ok, fail } from './_shared.js';
3
+ const DIFFICULTY = z.enum(['easy', 'medium', 'hard']);
4
+ export function registerListProblems(server, client, _env) {
5
+ server.registerTool('list_problems', {
6
+ title: 'List library problems',
7
+ description: 'Return the problem-library entries the caller can see. Optional filters: category, difficulty, scope (system / org / all). The candidate profile sees the same listing as the interviewer profile here; rubric / hidden tests are stripped at the get_problem stage.',
8
+ inputSchema: {
9
+ difficulty: DIFFICULTY.optional().describe('Filter by difficulty.'),
10
+ category: z
11
+ .string()
12
+ .optional()
13
+ .describe('Filter by category enum (e.g. "arrays_strings", "trees").'),
14
+ scope: z
15
+ .enum(['all', 'shared', 'org'])
16
+ .optional()
17
+ .describe('"shared" = the system library; "org" = scoped to the caller\'s active org.'),
18
+ },
19
+ }, async ({ difficulty, category, scope }) => {
20
+ try {
21
+ const { problems } = await client.get('/problems');
22
+ const filtered = problems.filter((p) => {
23
+ if (difficulty !== undefined && p.difficulty !== difficulty)
24
+ return false;
25
+ if (category !== undefined && p.category !== category)
26
+ return false;
27
+ if (scope !== undefined && scope !== 'all' && p.visibility !== scope)
28
+ return false;
29
+ return true;
30
+ });
31
+ return ok(`Found ${filtered.length} problem${filtered.length === 1 ? '' : 's'} matching the filter.`, { problems: filtered });
32
+ }
33
+ catch (err) {
34
+ return fail(err);
35
+ }
36
+ });
37
+ }
38
+ //# sourceMappingURL=list_problems.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list_problems.js","sourceRoot":"","sources":["../../src/tools/list_problems.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAexC,MAAM,UAAU,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;AAEtD,MAAM,UAAU,oBAAoB,CAClC,MAAiB,EACjB,MAAsB,EACtB,IAAS;IAET,MAAM,CAAC,YAAY,CACjB,eAAe,EACf;QACE,KAAK,EAAE,uBAAuB;QAC9B,WAAW,EACT,sQAAsQ;QACxQ,WAAW,EAAE;YACX,UAAU,EAAE,UAAU,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uBAAuB,CAAC;YACnE,QAAQ,EAAE,CAAC;iBACR,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,2DAA2D,CAAC;YACxE,KAAK,EAAE,CAAC;iBACL,IAAI,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;iBAC9B,QAAQ,EAAE;iBACV,QAAQ,CAAC,4EAA4E,CAAC;SAC1F;KACF,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,EAAE;QACxC,IAAI,CAAC;YACH,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,GAAG,CAAuB,WAAW,CAAC,CAAC;YACzE,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;gBACrC,IAAI,UAAU,KAAK,SAAS,IAAI,CAAC,CAAC,UAAU,KAAK,UAAU;oBAAE,OAAO,KAAK,CAAC;gBAC1E,IAAI,QAAQ,KAAK,SAAS,IAAI,CAAC,CAAC,QAAQ,KAAK,QAAQ;oBAAE,OAAO,KAAK,CAAC;gBACpE,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,KAAK,IAAI,CAAC,CAAC,UAAU,KAAK,KAAK;oBAAE,OAAO,KAAK,CAAC;gBACnF,OAAO,IAAI,CAAC;YACd,CAAC,CAAC,CAAC;YACH,OAAO,EAAE,CACP,SAAS,QAAQ,CAAC,MAAM,WAAW,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,uBAAuB,EAC1F,EAAE,QAAQ,EAAE,QAAQ,EAAE,CACvB,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * list_recordings: return the recordings made in a workspace.
3
+ *
4
+ * Metadata only: id, label, createdAt, durationMs, and the count of
5
+ * captured events. The actual event-stream blob endpoint stays out of
6
+ * Phase 1; downloading and replaying a session is a Phase 3 concern
7
+ * because it pairs naturally with transcript summarisation tools.
8
+ */
9
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
10
+ import type { TypeletsClient } from '../client.js';
11
+ import type { Env } from '../env.js';
12
+ export declare function registerListRecordings(server: McpServer, client: TypeletsClient, _env: Env): void;
@@ -0,0 +1,20 @@
1
+ import { z } from 'zod';
2
+ import { ok, fail } from './_shared.js';
3
+ export function registerListRecordings(server, client, _env) {
4
+ server.registerTool('list_recordings', {
5
+ title: 'List session recordings',
6
+ description: "Return every saved session recording for a workspace, metadata only. The recordings themselves stay out of the Phase 1 surface. Call out to the platform to replay them.",
7
+ inputSchema: {
8
+ workspaceId: z.string().min(1).describe('The workspace id.'),
9
+ },
10
+ }, async ({ workspaceId }) => {
11
+ try {
12
+ const { recordings } = await client.get(`/workspaces/${encodeURIComponent(workspaceId)}/recordings`);
13
+ return ok(`Found ${recordings.length} recording${recordings.length === 1 ? '' : 's'}.`, { recordings });
14
+ }
15
+ catch (err) {
16
+ return fail(err);
17
+ }
18
+ });
19
+ }
20
+ //# sourceMappingURL=list_recordings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list_recordings.js","sourceRoot":"","sources":["../../src/tools/list_recordings.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAcxC,MAAM,UAAU,sBAAsB,CACpC,MAAiB,EACjB,MAAsB,EACtB,IAAS;IAET,MAAM,CAAC,YAAY,CACjB,iBAAiB,EACjB;QACE,KAAK,EAAE,yBAAyB;QAChC,WAAW,EACT,0KAA0K;QAC5K,WAAW,EAAE;YACX,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC;SAC7D;KACF,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE;QACxB,IAAI,CAAC;YACH,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,GAAG,CACrC,eAAe,kBAAkB,CAAC,WAAW,CAAC,aAAa,CAC5D,CAAC;YACF,OAAO,EAAE,CACP,SAAS,UAAU,CAAC,MAAM,aAAa,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,EAC5E,EAAE,UAAU,EAAE,CACf,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * list_workspace_files: walk a workspace's tree and return flat paths.
3
+ *
4
+ * Phase 1 calls the snapshot endpoint `GET /workspaces/:id/files` which
5
+ * the Typelets API exposes specifically for non-Yjs consumers (the
6
+ * collaborative tree is the source of truth; this endpoint returns a
7
+ * point-in-time materialised view of it).
8
+ *
9
+ * Returns file ids alongside paths so a follow-up `read_workspace_file`
10
+ * call can fetch contents by id (cheaper + immune to mid-call renames).
11
+ */
12
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
13
+ import type { TypeletsClient } from '../client.js';
14
+ import type { Env } from '../env.js';
15
+ export declare function registerListWorkspaceFiles(server: McpServer, client: TypeletsClient, _env: Env): void;
@@ -0,0 +1,25 @@
1
+ import { z } from 'zod';
2
+ import { ok, fail } from './_shared.js';
3
+ export function registerListWorkspaceFiles(server, client, _env) {
4
+ server.registerTool('list_workspace_files', {
5
+ title: 'List workspace files',
6
+ description: 'Return every file, folder, and whiteboard in a workspace as a flat list of slash-separated paths plus stable ids. Use the id with read_workspace_file to fetch contents.',
7
+ inputSchema: {
8
+ workspaceId: z.string().min(1).describe('The workspace id.'),
9
+ includeFolders: z
10
+ .boolean()
11
+ .optional()
12
+ .describe('Include folder + whiteboard entries. Default false: files only.'),
13
+ },
14
+ }, async ({ workspaceId, includeFolders }) => {
15
+ try {
16
+ const { files } = await client.get(`/workspaces/${encodeURIComponent(workspaceId)}/files`);
17
+ const filtered = includeFolders === true ? files : files.filter((f) => f.type === 'file');
18
+ return ok(`Found ${filtered.length} entr${filtered.length === 1 ? 'y' : 'ies'}.`, { files: filtered });
19
+ }
20
+ catch (err) {
21
+ return fail(err);
22
+ }
23
+ });
24
+ }
25
+ //# sourceMappingURL=list_workspace_files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list_workspace_files.js","sourceRoot":"","sources":["../../src/tools/list_workspace_files.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAaxC,MAAM,UAAU,0BAA0B,CACxC,MAAiB,EACjB,MAAsB,EACtB,IAAS;IAET,MAAM,CAAC,YAAY,CACjB,sBAAsB,EACtB;QACE,KAAK,EAAE,sBAAsB;QAC7B,WAAW,EACT,0KAA0K;QAC5K,WAAW,EAAE;YACX,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC;YAC5D,cAAc,EAAE,CAAC;iBACd,OAAO,EAAE;iBACT,QAAQ,EAAE;iBACV,QAAQ,CAAC,iEAAiE,CAAC;SAC/E;KACF,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,cAAc,EAAE,EAAE,EAAE;QACxC,IAAI,CAAC;YACH,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,GAAG,CAChC,eAAe,kBAAkB,CAAC,WAAW,CAAC,QAAQ,CACvD,CAAC;YACF,MAAM,QAAQ,GACZ,cAAc,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;YAC3E,OAAO,EAAE,CACP,SAAS,QAAQ,CAAC,MAAM,QAAQ,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,EACtE,EAAE,KAAK,EAAE,QAAQ,EAAE,CACpB,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * list_workspaces: return every workspace the caller can see.
3
+ *
4
+ * Includes the caller's role per workspace (owner/admin/editor/viewer)
5
+ * so the model can decide whether a follow-up write tool will be
6
+ * allowed before attempting it.
7
+ */
8
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
9
+ import type { TypeletsClient } from '../client.js';
10
+ import type { Env } from '../env.js';
11
+ export declare function registerListWorkspaces(server: McpServer, client: TypeletsClient, _env: Env): void;