@grigoreo-dev/otask-mcp 1.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 (142) hide show
  1. package/README.md +168 -0
  2. package/dist/constants.d.ts +3 -0
  3. package/dist/constants.d.ts.map +1 -0
  4. package/dist/constants.js +3 -0
  5. package/dist/constants.js.map +1 -0
  6. package/dist/docs/parser.d.ts +3 -0
  7. package/dist/docs/parser.d.ts.map +1 -0
  8. package/dist/docs/parser.js +123 -0
  9. package/dist/docs/parser.js.map +1 -0
  10. package/dist/docs/types.d.ts +29 -0
  11. package/dist/docs/types.d.ts.map +1 -0
  12. package/dist/docs/types.js +2 -0
  13. package/dist/docs/types.js.map +1 -0
  14. package/dist/http-server.d.ts +3 -0
  15. package/dist/http-server.d.ts.map +1 -0
  16. package/dist/http-server.js +92 -0
  17. package/dist/http-server.js.map +1 -0
  18. package/dist/index.d.ts +3 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +23 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/mcp-http.d.ts +3 -0
  23. package/dist/mcp-http.d.ts.map +1 -0
  24. package/dist/mcp-http.js +98 -0
  25. package/dist/mcp-http.js.map +1 -0
  26. package/dist/proxy/headers.d.ts +3 -0
  27. package/dist/proxy/headers.d.ts.map +1 -0
  28. package/dist/proxy/headers.js +37 -0
  29. package/dist/proxy/headers.js.map +1 -0
  30. package/dist/proxy/read-body.d.ts +3 -0
  31. package/dist/proxy/read-body.d.ts.map +1 -0
  32. package/dist/proxy/read-body.js +18 -0
  33. package/dist/proxy/read-body.js.map +1 -0
  34. package/dist/schemas/task.d.ts +241 -0
  35. package/dist/schemas/task.d.ts.map +1 -0
  36. package/dist/schemas/task.js +95 -0
  37. package/dist/schemas/task.js.map +1 -0
  38. package/dist/schemas/workspace.d.ts +66 -0
  39. package/dist/schemas/workspace.d.ts.map +1 -0
  40. package/dist/schemas/workspace.js +30 -0
  41. package/dist/schemas/workspace.js.map +1 -0
  42. package/dist/server.d.ts +5 -0
  43. package/dist/server.d.ts.map +1 -0
  44. package/dist/server.js +13 -0
  45. package/dist/server.js.map +1 -0
  46. package/dist/services/api.d.ts +23 -0
  47. package/dist/services/api.d.ts.map +1 -0
  48. package/dist/services/api.js +215 -0
  49. package/dist/services/api.js.map +1 -0
  50. package/dist/services/auth.d.ts +23 -0
  51. package/dist/services/auth.d.ts.map +1 -0
  52. package/dist/services/auth.js +122 -0
  53. package/dist/services/auth.js.map +1 -0
  54. package/dist/services/client.d.ts +21 -0
  55. package/dist/services/client.d.ts.map +1 -0
  56. package/dist/services/client.js +17 -0
  57. package/dist/services/client.js.map +1 -0
  58. package/dist/services/format.d.ts +6 -0
  59. package/dist/services/format.d.ts.map +1 -0
  60. package/dist/services/format.js +8 -0
  61. package/dist/services/format.js.map +1 -0
  62. package/dist/services/http-auth-context.d.ts +7 -0
  63. package/dist/services/http-auth-context.d.ts.map +1 -0
  64. package/dist/services/http-auth-context.js +9 -0
  65. package/dist/services/http-auth-context.js.map +1 -0
  66. package/dist/services/project-guard.d.ts +35 -0
  67. package/dist/services/project-guard.d.ts.map +1 -0
  68. package/dist/services/project-guard.js +85 -0
  69. package/dist/services/project-guard.js.map +1 -0
  70. package/dist/services/task-mapper.d.ts +90 -0
  71. package/dist/services/task-mapper.d.ts.map +1 -0
  72. package/dist/services/task-mapper.js +148 -0
  73. package/dist/services/task-mapper.js.map +1 -0
  74. package/dist/tools/add-comment.d.ts +4 -0
  75. package/dist/tools/add-comment.d.ts.map +1 -0
  76. package/dist/tools/add-comment.js +43 -0
  77. package/dist/tools/add-comment.js.map +1 -0
  78. package/dist/tools/archive-task.d.ts +4 -0
  79. package/dist/tools/archive-task.d.ts.map +1 -0
  80. package/dist/tools/archive-task.js +43 -0
  81. package/dist/tools/archive-task.js.map +1 -0
  82. package/dist/tools/create-task.d.ts +4 -0
  83. package/dist/tools/create-task.d.ts.map +1 -0
  84. package/dist/tools/create-task.js +45 -0
  85. package/dist/tools/create-task.js.map +1 -0
  86. package/dist/tools/get-task.d.ts +4 -0
  87. package/dist/tools/get-task.d.ts.map +1 -0
  88. package/dist/tools/get-task.js +44 -0
  89. package/dist/tools/get-task.js.map +1 -0
  90. package/dist/tools/helpers.d.ts +15 -0
  91. package/dist/tools/helpers.d.ts.map +1 -0
  92. package/dist/tools/helpers.js +19 -0
  93. package/dist/tools/helpers.js.map +1 -0
  94. package/dist/tools/list-board.d.ts +4 -0
  95. package/dist/tools/list-board.d.ts.map +1 -0
  96. package/dist/tools/list-board.js +52 -0
  97. package/dist/tools/list-board.js.map +1 -0
  98. package/dist/tools/list-comments.d.ts +4 -0
  99. package/dist/tools/list-comments.d.ts.map +1 -0
  100. package/dist/tools/list-comments.js +41 -0
  101. package/dist/tools/list-comments.js.map +1 -0
  102. package/dist/tools/list-members.d.ts +4 -0
  103. package/dist/tools/list-members.d.ts.map +1 -0
  104. package/dist/tools/list-members.js +39 -0
  105. package/dist/tools/list-members.js.map +1 -0
  106. package/dist/tools/list-project-tasks.d.ts +4 -0
  107. package/dist/tools/list-project-tasks.d.ts.map +1 -0
  108. package/dist/tools/list-project-tasks.js +52 -0
  109. package/dist/tools/list-project-tasks.js.map +1 -0
  110. package/dist/tools/list-projects.d.ts +4 -0
  111. package/dist/tools/list-projects.d.ts.map +1 -0
  112. package/dist/tools/list-projects.js +40 -0
  113. package/dist/tools/list-projects.js.map +1 -0
  114. package/dist/tools/list-tags.d.ts +4 -0
  115. package/dist/tools/list-tags.d.ts.map +1 -0
  116. package/dist/tools/list-tags.js +39 -0
  117. package/dist/tools/list-tags.js.map +1 -0
  118. package/dist/tools/move-task.d.ts +4 -0
  119. package/dist/tools/move-task.d.ts.map +1 -0
  120. package/dist/tools/move-task.js +59 -0
  121. package/dist/tools/move-task.js.map +1 -0
  122. package/dist/tools/register.d.ts +4 -0
  123. package/dist/tools/register.d.ts.map +1 -0
  124. package/dist/tools/register.js +8 -0
  125. package/dist/tools/register.js.map +1 -0
  126. package/dist/tools/registry.d.ts +15 -0
  127. package/dist/tools/registry.d.ts.map +1 -0
  128. package/dist/tools/registry.js +28 -0
  129. package/dist/tools/registry.js.map +1 -0
  130. package/dist/tools/types.d.ts +29 -0
  131. package/dist/tools/types.d.ts.map +1 -0
  132. package/dist/tools/types.js +2 -0
  133. package/dist/tools/types.js.map +1 -0
  134. package/dist/tools/update-task.d.ts +4 -0
  135. package/dist/tools/update-task.d.ts.map +1 -0
  136. package/dist/tools/update-task.js +96 -0
  137. package/dist/tools/update-task.js.map +1 -0
  138. package/dist/types.d.ts +92 -0
  139. package/dist/types.d.ts.map +1 -0
  140. package/dist/types.js +2 -0
  141. package/dist/types.js.map +1 -0
  142. package/package.json +44 -0
@@ -0,0 +1,215 @@
1
+ import { API_BASE_URL } from "../constants.js";
2
+ export class OtaskApiError extends Error {
3
+ status;
4
+ body;
5
+ constructor(message, status, body) {
6
+ super(message);
7
+ this.status = status;
8
+ this.body = body;
9
+ this.name = "OtaskApiError";
10
+ }
11
+ }
12
+ async function parseResponse(response) {
13
+ const body = await response.json().catch(() => ({}));
14
+ if (!response.ok) {
15
+ const detail = typeof body === "object" && body !== null && "message" in body
16
+ ? String(body.message)
17
+ : JSON.stringify(body).slice(0, 500);
18
+ throw new OtaskApiError(`O!task API error (${response.status}): ${detail}`, response.status, body);
19
+ }
20
+ return body;
21
+ }
22
+ async function headersFor(auth) {
23
+ return auth();
24
+ }
25
+ function wsUrl(wsSlug, path) {
26
+ return `${API_BASE_URL}/api/v1/ws/${encodeURIComponent(wsSlug)}${path}`;
27
+ }
28
+ function withQuery(url, query) {
29
+ if (!query)
30
+ return url;
31
+ const params = new URLSearchParams();
32
+ for (const [key, value] of Object.entries(query)) {
33
+ if (value === undefined)
34
+ continue;
35
+ params.set(key, String(value));
36
+ }
37
+ const qs = params.toString();
38
+ return qs ? `${url}?${qs}` : url;
39
+ }
40
+ function assertSuccess(result, status, fallback) {
41
+ if (!result.success) {
42
+ throw new OtaskApiError(result.message ?? fallback, status, result);
43
+ }
44
+ return result.data;
45
+ }
46
+ function asRecord(value) {
47
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
48
+ return value;
49
+ }
50
+ return null;
51
+ }
52
+ function pickArray(data, key, status = 200) {
53
+ if (Array.isArray(data))
54
+ return data;
55
+ const obj = asRecord(data);
56
+ if (obj && Array.isArray(obj[key]))
57
+ return obj[key];
58
+ throw new OtaskApiError(`Unexpected API response: missing array field "${key}"`, status, data);
59
+ }
60
+ function pickTask(data) {
61
+ const obj = asRecord(data);
62
+ if (obj && obj.task && typeof obj.task === "object") {
63
+ return obj.task;
64
+ }
65
+ return data;
66
+ }
67
+ export async function getTask(wsSlug, taskSlug, auth) {
68
+ const headers = await headersFor(auth);
69
+ const response = await fetch(wsUrl(wsSlug, `/tasks/${encodeURIComponent(taskSlug)}`), { method: "GET", headers });
70
+ const result = await parseResponse(response);
71
+ return assertSuccess(result, response.status, "Failed to get task");
72
+ }
73
+ export async function updateTask(wsSlug, taskSlug, body, auth) {
74
+ const headers = await headersFor(auth);
75
+ const response = await fetch(wsUrl(wsSlug, `/tasks/${encodeURIComponent(taskSlug)}/update`), {
76
+ method: "POST",
77
+ headers,
78
+ body: JSON.stringify(body),
79
+ });
80
+ const result = await parseResponse(response);
81
+ const data = assertSuccess(result, response.status, "Failed to update task");
82
+ return {
83
+ success: true,
84
+ message: result.message,
85
+ task: data.task,
86
+ is_recovery: data.is_recovery,
87
+ is_detach_parent: data.is_detach_parent,
88
+ };
89
+ }
90
+ export async function listProjects(wsSlug, auth) {
91
+ const headers = await headersFor(auth);
92
+ const response = await fetch(wsUrl(wsSlug, "/projects/list"), {
93
+ method: "GET",
94
+ headers,
95
+ });
96
+ const result = await parseResponse(response);
97
+ const data = assertSuccess(result, response.status, "Failed to list projects");
98
+ return pickArray(data, "projects", response.status);
99
+ }
100
+ export async function listProjectTasks(wsSlug, projectSlug, query, auth) {
101
+ const headers = await headersFor(auth);
102
+ const url = withQuery(wsUrl(wsSlug, `/projects/${encodeURIComponent(projectSlug)}/tasks`), query);
103
+ const response = await fetch(url, { method: "GET", headers });
104
+ const result = await parseResponse(response);
105
+ const data = assertSuccess(result, response.status, "Failed to list project tasks");
106
+ if (Array.isArray(data)) {
107
+ return { tasks: data };
108
+ }
109
+ const obj = asRecord(data);
110
+ if (obj && Array.isArray(obj.tasks)) {
111
+ return { tasks: obj.tasks, meta: obj.meta };
112
+ }
113
+ throw new OtaskApiError('Unexpected API response: missing array field "tasks"', response.status, data);
114
+ }
115
+ export async function listBoard(wsSlug, projectSlug, query, auth) {
116
+ const headers = await headersFor(auth);
117
+ const url = withQuery(wsUrl(wsSlug, `/projects/${encodeURIComponent(projectSlug)}/boards`), query);
118
+ const response = await fetch(url, { method: "GET", headers });
119
+ const result = await parseResponse(response);
120
+ const data = assertSuccess(result, response.status, "Failed to list board");
121
+ const obj = asRecord(data);
122
+ const hasBoards = obj !== null && Array.isArray(obj.boards);
123
+ const hasColumns = obj !== null && Array.isArray(obj.columns);
124
+ if (!hasBoards && !hasColumns) {
125
+ throw new OtaskApiError('Unexpected API response: missing board envelope (boards/columns)', response.status, data);
126
+ }
127
+ return {
128
+ boards: hasBoards ? obj.boards : [],
129
+ columns: hasColumns ? obj.columns : [],
130
+ };
131
+ }
132
+ export async function listMembers(wsSlug, auth) {
133
+ const headers = await headersFor(auth);
134
+ const response = await fetch(wsUrl(wsSlug, "/members/list"), {
135
+ method: "GET",
136
+ headers,
137
+ });
138
+ const result = await parseResponse(response);
139
+ const data = assertSuccess(result, response.status, "Failed to list members");
140
+ return pickArray(data, "members", response.status);
141
+ }
142
+ export async function listTags(wsSlug, auth) {
143
+ const headers = await headersFor(auth);
144
+ const response = await fetch(wsUrl(wsSlug, "/kanbans/tags"), {
145
+ method: "GET",
146
+ headers,
147
+ });
148
+ const result = await parseResponse(response);
149
+ const data = assertSuccess(result, response.status, "Failed to list tags");
150
+ return pickArray(data, "tags", response.status);
151
+ }
152
+ export async function listComments(wsSlug, taskSlug, body, auth) {
153
+ const headers = await headersFor(auth);
154
+ const response = await fetch(wsUrl(wsSlug, `/tasks/${encodeURIComponent(taskSlug)}/comments/get`), {
155
+ method: "POST",
156
+ headers,
157
+ body: JSON.stringify(body ?? {}),
158
+ });
159
+ const result = await parseResponse(response);
160
+ return assertSuccess(result, response.status, "Failed to list comments");
161
+ }
162
+ export async function addComment(wsSlug, taskSlug, comment, parentId, auth) {
163
+ const headers = await headersFor(auth);
164
+ const payload = { comment };
165
+ if (parentId !== undefined) {
166
+ payload.parent_id = parentId;
167
+ }
168
+ const response = await fetch(wsUrl(wsSlug, `/tasks/${encodeURIComponent(taskSlug)}/comments/store`), {
169
+ method: "POST",
170
+ headers,
171
+ body: JSON.stringify(payload),
172
+ });
173
+ const result = await parseResponse(response);
174
+ return assertSuccess(result, response.status, "Failed to add comment");
175
+ }
176
+ export async function createTask(wsSlug, body, auth) {
177
+ const headers = await headersFor(auth);
178
+ const response = await fetch(wsUrl(wsSlug, "/tasks/create"), {
179
+ method: "POST",
180
+ headers,
181
+ body: JSON.stringify(body),
182
+ });
183
+ const result = await parseResponse(response);
184
+ const data = assertSuccess(result, response.status, "Failed to create task");
185
+ return pickTask(data);
186
+ }
187
+ export async function archiveTask(wsSlug, taskSlug, auth) {
188
+ const headers = await headersFor(auth);
189
+ const response = await fetch(wsUrl(wsSlug, `/tasks/${encodeURIComponent(taskSlug)}/in-archive`), {
190
+ method: "POST",
191
+ headers,
192
+ });
193
+ const result = await parseResponse(response);
194
+ const data = assertSuccess(result, response.status, "Failed to archive task");
195
+ return pickTask(data);
196
+ }
197
+ export function formatApiError(error) {
198
+ if (error instanceof OtaskApiError) {
199
+ if (error.status === 404) {
200
+ return `Error: Task or workspace not found. Check ws_slug and task_slug. ${error.message}`;
201
+ }
202
+ if (error.status === 401 || error.status === 403) {
203
+ return `Error: O!task auth failed. Check Bearer token. ${error.message}`;
204
+ }
205
+ if (error.status === 429) {
206
+ return "Error: Rate limit exceeded. Wait before retrying.";
207
+ }
208
+ return error.message;
209
+ }
210
+ if (error instanceof Error) {
211
+ return `Error: ${error.message}`;
212
+ }
213
+ return `Error: ${String(error)}`;
214
+ }
215
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/services/api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ export type HttpAuthMode = "gateway" | "passthrough";
2
+ /** Resolves headers for O!task API calls (per MCP request in HTTP mode). */
3
+ export type OtaskAuthResolver = () => Promise<Record<string, string>>;
4
+ export declare function hasServerOtaskCredentials(): boolean;
5
+ export declare function getHttpAuthMode(): HttpAuthMode;
6
+ export declare function validateStdioAuthConfig(): void;
7
+ export declare function validateHttpAuthConfig(): void;
8
+ export declare function extractBearerToken(authorizationHeader: string | undefined): string | undefined;
9
+ export declare function extractProjectAllowListHeader(headers: {
10
+ [k: string]: string | string[] | undefined;
11
+ }): string | undefined;
12
+ export declare function authorizeHttpMcpRequest(clientBearer: string | undefined): {
13
+ ok: true;
14
+ otaskBearer?: string;
15
+ } | {
16
+ ok: false;
17
+ status: number;
18
+ error: string;
19
+ hint: string;
20
+ };
21
+ export declare function createPassthroughAuthResolver(otaskBearer: string): OtaskAuthResolver;
22
+ export declare function createEnvAuthResolver(): OtaskAuthResolver;
23
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/services/auth.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,aAAa,CAAC;AAErD,4EAA4E;AAC5E,MAAM,MAAM,iBAAiB,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAetE,wBAAgB,yBAAyB,IAAI,OAAO,CAEnD;AAED,wBAAgB,eAAe,IAAI,YAAY,CAE9C;AAED,wBAAgB,uBAAuB,IAAI,IAAI,CAM9C;AAED,wBAAgB,sBAAsB,IAAI,IAAI,CAM7C;AAED,wBAAgB,kBAAkB,CAChC,mBAAmB,EAAE,MAAM,GAAG,SAAS,GACtC,MAAM,GAAG,SAAS,CAMpB;AAED,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE;IAAE,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAA;CAAE,GACtD,MAAM,GAAG,SAAS,CAKpB;AAED,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG;IACzE,EAAE,EAAE,IAAI,CAAC;IACT,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG;IACF,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd,CAwBA;AAED,wBAAgB,6BAA6B,CAC3C,WAAW,EAAE,MAAM,GAClB,iBAAiB,CAMnB;AAmDD,wBAAgB,qBAAqB,IAAI,iBAAiB,CASzD"}
@@ -0,0 +1,122 @@
1
+ import { API_BASE_URL } from "../constants.js";
2
+ let cachedToken = null;
3
+ function getStaticAuthKey() {
4
+ return process.env.OTASK_AUTH_KEY?.trim() || undefined;
5
+ }
6
+ function getEmailPassword() {
7
+ const email = process.env.OTASK_EMAIL?.trim();
8
+ const password = process.env.OTASK_PASSWORD?.trim();
9
+ if (email && password) {
10
+ return { email, password };
11
+ }
12
+ return undefined;
13
+ }
14
+ export function hasServerOtaskCredentials() {
15
+ return Boolean(getStaticAuthKey() || getEmailPassword());
16
+ }
17
+ export function getHttpAuthMode() {
18
+ return hasServerOtaskCredentials() ? "gateway" : "passthrough";
19
+ }
20
+ export function validateStdioAuthConfig() {
21
+ if (!hasServerOtaskCredentials()) {
22
+ throw new Error("Set OTASK_AUTH_KEY or OTASK_EMAIL + OTASK_PASSWORD for stdio MCP");
23
+ }
24
+ }
25
+ export function validateHttpAuthConfig() {
26
+ if (hasServerOtaskCredentials() && !process.env.MCP_AUTH_TOKEN?.trim()) {
27
+ throw new Error("MCP_AUTH_TOKEN is required when OTASK_* credentials are set in env");
28
+ }
29
+ }
30
+ export function extractBearerToken(authorizationHeader) {
31
+ if (!authorizationHeader?.startsWith("Bearer ")) {
32
+ return undefined;
33
+ }
34
+ const token = authorizationHeader.slice("Bearer ".length).trim();
35
+ return token || undefined;
36
+ }
37
+ export function extractProjectAllowListHeader(headers) {
38
+ const raw = headers["x-otask-allowed-projects"];
39
+ if (typeof raw === "string")
40
+ return raw;
41
+ if (Array.isArray(raw) && typeof raw[0] === "string")
42
+ return raw[0];
43
+ return undefined;
44
+ }
45
+ export function authorizeHttpMcpRequest(clientBearer) {
46
+ if (hasServerOtaskCredentials()) {
47
+ const mcpToken = process.env.MCP_AUTH_TOKEN?.trim();
48
+ if (!clientBearer || clientBearer !== mcpToken) {
49
+ return {
50
+ ok: false,
51
+ status: 401,
52
+ error: "Unauthorized",
53
+ hint: "Gateway: Authorization: Bearer <MCP_AUTH_TOKEN>",
54
+ };
55
+ }
56
+ return { ok: true };
57
+ }
58
+ if (!clientBearer) {
59
+ return {
60
+ ok: false,
61
+ status: 401,
62
+ error: "Unauthorized",
63
+ hint: "Passthrough: Authorization: Bearer <O!task token>",
64
+ };
65
+ }
66
+ return { ok: true, otaskBearer: clientBearer };
67
+ }
68
+ export function createPassthroughAuthResolver(otaskBearer) {
69
+ return async () => ({
70
+ Authorization: `Bearer ${otaskBearer}`,
71
+ "Content-Type": "application/json",
72
+ Accept: "application/json",
73
+ });
74
+ }
75
+ async function loginWithPassword(email, password) {
76
+ const response = await fetch(`${API_BASE_URL}/api/v1/auth/login`, {
77
+ method: "POST",
78
+ headers: {
79
+ "Content-Type": "application/json",
80
+ Accept: "application/json",
81
+ },
82
+ body: JSON.stringify({ email, password }),
83
+ });
84
+ const body = (await response.json().catch(() => ({})));
85
+ if (!response.ok || !body.token) {
86
+ const detail = typeof body.message === "string"
87
+ ? body.message
88
+ : JSON.stringify(body).slice(0, 500);
89
+ throw new Error(`O!task login failed (${response.status}): ${detail}`);
90
+ }
91
+ const expiresInMinutes = body.expires_in ?? 1_000_000;
92
+ cachedToken = {
93
+ token: body.token,
94
+ expiresAt: Date.now() + expiresInMinutes * 60 * 1000,
95
+ };
96
+ return body.token;
97
+ }
98
+ async function getServerAuthToken() {
99
+ const staticKey = getStaticAuthKey();
100
+ if (staticKey) {
101
+ return staticKey;
102
+ }
103
+ if (cachedToken && cachedToken.expiresAt > Date.now() + 60_000) {
104
+ return cachedToken.token;
105
+ }
106
+ const credentials = getEmailPassword();
107
+ if (!credentials) {
108
+ throw new Error("No OTASK_* credentials in env");
109
+ }
110
+ return loginWithPassword(credentials.email, credentials.password);
111
+ }
112
+ export function createEnvAuthResolver() {
113
+ return async () => {
114
+ const token = await getServerAuthToken();
115
+ return {
116
+ Authorization: `Bearer ${token}`,
117
+ "Content-Type": "application/json",
118
+ Accept: "application/json",
119
+ };
120
+ };
121
+ }
122
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/services/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { OtaskAuthResolver } from "./auth.js";
2
+ import type { CreateTaskBody, ListBoardResult, ListProjectTasksResult, OtaskProjectSummary, OtaskTask, UpdateTaskBody, UpdateTaskResult } from "../types.js";
3
+ /** O!task API bound to a single auth resolver (per MCP server / HTTP request). */
4
+ export interface OtaskClient {
5
+ getTask(wsSlug: string, taskSlug: string): Promise<OtaskTask>;
6
+ updateTask(wsSlug: string, taskSlug: string, body: UpdateTaskBody): Promise<UpdateTaskResult>;
7
+ listProjects(wsSlug: string): Promise<OtaskProjectSummary[]>;
8
+ listProjectTasks(wsSlug: string, projectSlug: string, query?: Record<string, string | number | undefined>): Promise<ListProjectTasksResult>;
9
+ listBoard(wsSlug: string, projectSlug: string, query?: {
10
+ type?: string;
11
+ board_slug?: string;
12
+ }): Promise<ListBoardResult>;
13
+ listMembers(wsSlug: string): Promise<unknown[]>;
14
+ listTags(wsSlug: string): Promise<unknown[]>;
15
+ listComments(wsSlug: string, taskSlug: string, body?: object): Promise<unknown>;
16
+ addComment(wsSlug: string, taskSlug: string, comment: string, parentId?: number): Promise<unknown>;
17
+ createTask(wsSlug: string, body: CreateTaskBody): Promise<OtaskTask>;
18
+ archiveTask(wsSlug: string, taskSlug: string): Promise<OtaskTask>;
19
+ }
20
+ export declare function createOtaskClient(auth: OtaskAuthResolver): OtaskClient;
21
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/services/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAcnD,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EACf,sBAAsB,EACtB,mBAAmB,EACnB,SAAS,EACT,cAAc,EACd,gBAAgB,EACjB,MAAM,aAAa,CAAC;AAErB,kFAAkF;AAClF,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAC9D,UAAU,CACR,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC7B,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAC;IAC7D,gBAAgB,CACd,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,GAClD,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACnC,SAAS,CACP,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,KAAK,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GAC7C,OAAO,CAAC,eAAe,CAAC,CAAC;IAC5B,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAChD,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAC7C,YAAY,CACV,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,OAAO,CAAC,CAAC;IACpB,UAAU,CACR,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC,CAAC;IACpB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IACrE,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;CACnE;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,iBAAiB,GAAG,WAAW,CAmBtE"}
@@ -0,0 +1,17 @@
1
+ import { addComment, archiveTask, createTask, getTask, listBoard, listComments, listMembers, listProjects, listProjectTasks, listTags, updateTask, } from "./api.js";
2
+ export function createOtaskClient(auth) {
3
+ return {
4
+ getTask: (wsSlug, taskSlug) => getTask(wsSlug, taskSlug, auth),
5
+ updateTask: (wsSlug, taskSlug, body) => updateTask(wsSlug, taskSlug, body, auth),
6
+ listProjects: (wsSlug) => listProjects(wsSlug, auth),
7
+ listProjectTasks: (wsSlug, projectSlug, query) => listProjectTasks(wsSlug, projectSlug, query, auth),
8
+ listBoard: (wsSlug, projectSlug, query) => listBoard(wsSlug, projectSlug, query, auth),
9
+ listMembers: (wsSlug) => listMembers(wsSlug, auth),
10
+ listTags: (wsSlug) => listTags(wsSlug, auth),
11
+ listComments: (wsSlug, taskSlug, body) => listComments(wsSlug, taskSlug, body, auth),
12
+ addComment: (wsSlug, taskSlug, comment, parentId) => addComment(wsSlug, taskSlug, comment, parentId, auth),
13
+ createTask: (wsSlug, body) => createTask(wsSlug, body, auth),
14
+ archiveTask: (wsSlug, taskSlug) => archiveTask(wsSlug, taskSlug, auth),
15
+ };
16
+ }
17
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/services/client.ts"],"names":[],"mappings":"AACA,OAAO,EACL,UAAU,EACV,WAAW,EACX,UAAU,EACV,OAAO,EACP,SAAS,EACT,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,QAAQ,EACR,UAAU,GACX,MAAM,UAAU,CAAC;AA+ClB,MAAM,UAAU,iBAAiB,CAAC,IAAuB;IACvD,OAAO;QACL,OAAO,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC;QAC9D,UAAU,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,CACrC,UAAU,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC;QAC1C,YAAY,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC;QACpD,gBAAgB,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,CAC/C,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,IAAI,CAAC;QACpD,SAAS,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,CACxC,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,IAAI,CAAC;QAC7C,WAAW,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC;QAClD,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC;QAC5C,YAAY,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,CACvC,YAAY,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC;QAC5C,UAAU,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,CAClD,UAAU,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC;QACvD,UAAU,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC;QAC5D,WAAW,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC,WAAW,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC;KACvE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,6 @@
1
+ export declare function agentListResult(summary: string, items: unknown[], next?: unknown): {
2
+ summary: string;
3
+ items: unknown[];
4
+ next: unknown;
5
+ };
6
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/services/format.ts"],"names":[],"mappings":"AAAA,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,OAAO,EAAE,EAChB,IAAI,CAAC,EAAE,OAAO,GACb;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,EAAE,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAMtD"}
@@ -0,0 +1,8 @@
1
+ export function agentListResult(summary, items, next) {
2
+ return {
3
+ summary,
4
+ items,
5
+ next: next === undefined ? null : next,
6
+ };
7
+ }
8
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/services/format.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,eAAe,CAC7B,OAAe,EACf,KAAgB,EAChB,IAAc;IAEd,OAAO;QACL,OAAO;QACP,KAAK;QACL,IAAI,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;KACvC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ export interface HttpAuthContext {
2
+ /** O!task Bearer from client — passthrough mode only */
3
+ passthroughToken: string;
4
+ }
5
+ export declare function runWithHttpAuthContext<T>(context: HttpAuthContext, fn: () => T | Promise<T>): Promise<T>;
6
+ export declare function getPassthroughToken(): string | undefined;
7
+ //# sourceMappingURL=http-auth-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-auth-context.d.ts","sourceRoot":"","sources":["../../src/services/http-auth-context.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,eAAe;IAC9B,wDAAwD;IACxD,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAID,wBAAgB,sBAAsB,CAAC,CAAC,EACtC,OAAO,EAAE,eAAe,EACxB,EAAE,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GACvB,OAAO,CAAC,CAAC,CAAC,CAEZ;AAED,wBAAgB,mBAAmB,IAAI,MAAM,GAAG,SAAS,CAExD"}
@@ -0,0 +1,9 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ const storage = new AsyncLocalStorage();
3
+ export function runWithHttpAuthContext(context, fn) {
4
+ return Promise.resolve(storage.run(context, fn));
5
+ }
6
+ export function getPassthroughToken() {
7
+ return storage.getStore()?.passthroughToken;
8
+ }
9
+ //# sourceMappingURL=http-auth-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-auth-context.js","sourceRoot":"","sources":["../../src/services/http-auth-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAOrD,MAAM,OAAO,GAAG,IAAI,iBAAiB,EAAmB,CAAC;AAEzD,MAAM,UAAU,sBAAsB,CACpC,OAAwB,EACxB,EAAwB;IAExB,OAAO,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,OAAO,OAAO,CAAC,QAAQ,EAAE,EAAE,gBAAgB,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,35 @@
1
+ export interface ProjectAllowList {
2
+ slugs: Set<string>;
3
+ ids: Set<number>;
4
+ isEmpty: boolean;
5
+ }
6
+ export interface ProjectRef {
7
+ slug?: string | null;
8
+ id?: number | null;
9
+ }
10
+ export interface ProjectGuard {
11
+ allows(ref: ProjectRef): boolean;
12
+ assertAllowed(ref: ProjectRef): void;
13
+ filterProjects<T extends ProjectRef>(items: T[]): T[];
14
+ readonly list: ProjectAllowList;
15
+ }
16
+ export declare function parseProjectAllowList(raw: string | undefined | null): ProjectAllowList;
17
+ export declare function createProjectGuard(list: ProjectAllowList): ProjectGuard;
18
+ /** Resolve project by slug (for id), then assert allow-list. */
19
+ export declare function assertProjectSlugAllowed(guard: ProjectGuard, listProjects: () => Promise<Array<{
20
+ id: number;
21
+ slug: string;
22
+ }>>, project_slug: string): Promise<void>;
23
+ /** Resolve project by id (for slug), then assert allow-list. */
24
+ export declare function assertProjectIdAllowed(guard: ProjectGuard, listProjects: () => Promise<Array<{
25
+ id: number;
26
+ slug: string;
27
+ }>>, project_id: number, knownSlug?: string | null): Promise<void>;
28
+ export declare function projectGuardFromEnv(env?: NodeJS.ProcessEnv): ProjectGuard;
29
+ export declare function resolveHttpProjectGuard(opts: {
30
+ authMode: "gateway" | "passthrough";
31
+ env: NodeJS.ProcessEnv;
32
+ headerRaw: string | undefined;
33
+ }): ProjectGuard;
34
+ export declare function projectGuardMode(authMode: "gateway" | "passthrough", guard: ProjectGuard): "env" | "header" | "off";
35
+ //# sourceMappingURL=project-guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-guard.d.ts","sourceRoot":"","sources":["../../src/services/project-guard.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACnB,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC;IACjC,aAAa,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CAAC;IACrC,cAAc,CAAC,CAAC,SAAS,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;IACtD,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;CACjC;AAED,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAC7B,gBAAgB,CAgBlB;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,GAAG,YAAY,CAoBvE;AAED,gEAAgE;AAChE,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,YAAY,EACnB,YAAY,EAAE,MAAM,OAAO,CAAC,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,EAChE,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAQf;AAED,gEAAgE;AAChE,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,YAAY,EACnB,YAAY,EAAE,MAAM,OAAO,CAAC,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,EAChE,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GACxB,OAAO,CAAC,IAAI,CAAC,CAYf;AAED,wBAAgB,mBAAmB,CACjC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,YAAY,CAEd;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE;IAC5C,QAAQ,EAAE,SAAS,GAAG,aAAa,CAAC;IACpC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B,GAAG,YAAY,CAOf;AAED,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,SAAS,GAAG,aAAa,EACnC,KAAK,EAAE,YAAY,GAClB,KAAK,GAAG,QAAQ,GAAG,KAAK,CAG1B"}
@@ -0,0 +1,85 @@
1
+ export function parseProjectAllowList(raw) {
2
+ const slugs = new Set();
3
+ const ids = new Set();
4
+ if (!raw?.trim()) {
5
+ return { slugs, ids, isEmpty: true };
6
+ }
7
+ for (const part of raw.split(",")) {
8
+ const token = part.trim();
9
+ if (!token)
10
+ continue;
11
+ if (/^\d+$/.test(token)) {
12
+ ids.add(Number(token));
13
+ }
14
+ else {
15
+ slugs.add(token);
16
+ }
17
+ }
18
+ return { slugs, ids, isEmpty: slugs.size === 0 && ids.size === 0 };
19
+ }
20
+ export function createProjectGuard(list) {
21
+ return {
22
+ list,
23
+ allows(ref) {
24
+ if (list.isEmpty)
25
+ return true;
26
+ if (ref.slug && list.slugs.has(ref.slug))
27
+ return true;
28
+ if (ref.id != null && list.ids.has(ref.id))
29
+ return true;
30
+ return false;
31
+ },
32
+ assertAllowed(ref) {
33
+ if (!this.allows(ref)) {
34
+ const label = ref.slug ?? ref.id ?? "unknown";
35
+ throw new Error(`Project not allowed: ${label}`);
36
+ }
37
+ },
38
+ filterProjects(items) {
39
+ if (list.isEmpty)
40
+ return items;
41
+ return items.filter((item) => this.allows(item));
42
+ },
43
+ };
44
+ }
45
+ /** Resolve project by slug (for id), then assert allow-list. */
46
+ export async function assertProjectSlugAllowed(guard, listProjects, project_slug) {
47
+ const projects = await listProjects();
48
+ const project = projects.find((p) => p.slug === project_slug);
49
+ if (project) {
50
+ guard.assertAllowed({ slug: project.slug, id: project.id });
51
+ }
52
+ else {
53
+ guard.assertAllowed({ slug: project_slug });
54
+ }
55
+ }
56
+ /** Resolve project by id (for slug), then assert allow-list. */
57
+ export async function assertProjectIdAllowed(guard, listProjects, project_id, knownSlug) {
58
+ if (knownSlug) {
59
+ guard.assertAllowed({ id: project_id, slug: knownSlug });
60
+ return;
61
+ }
62
+ const projects = await listProjects();
63
+ const project = projects.find((p) => p.id === project_id);
64
+ if (project) {
65
+ guard.assertAllowed({ id: project.id, slug: project.slug });
66
+ }
67
+ else {
68
+ guard.assertAllowed({ id: project_id });
69
+ }
70
+ }
71
+ export function projectGuardFromEnv(env = process.env) {
72
+ return createProjectGuard(parseProjectAllowList(env.OTASK_ALLOWED_PROJECTS));
73
+ }
74
+ export function resolveHttpProjectGuard(opts) {
75
+ if (opts.authMode === "gateway") {
76
+ return createProjectGuard(parseProjectAllowList(opts.env.OTASK_ALLOWED_PROJECTS));
77
+ }
78
+ return createProjectGuard(parseProjectAllowList(opts.headerRaw));
79
+ }
80
+ export function projectGuardMode(authMode, guard) {
81
+ if (guard.list.isEmpty)
82
+ return "off";
83
+ return authMode === "gateway" ? "env" : "header";
84
+ }
85
+ //# sourceMappingURL=project-guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-guard.js","sourceRoot":"","sources":["../../src/services/project-guard.ts"],"names":[],"mappings":"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"}