@esaio/esa-mcp-server 0.2.0 → 0.2.2

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 (78) hide show
  1. package/README.en.md +10 -6
  2. package/README.md +16 -12
  3. package/bin/{index.js → index.mjs} +1 -1
  4. package/package.json +22 -3
  5. package/.dockerignore +0 -36
  6. package/.github/dependabot.yml +0 -23
  7. package/.github/workflows/docker-publish.yml +0 -120
  8. package/.github/workflows/main.yml +0 -41
  9. package/CLAUDE.md +0 -94
  10. package/Dockerfile +0 -34
  11. package/biome.json +0 -57
  12. package/src/__tests__/fixtures/mock-comment.ts +0 -90
  13. package/src/__tests__/fixtures/mock-post.ts +0 -79
  14. package/src/__tests__/index.test.ts +0 -216
  15. package/src/api_client/__tests__/index.test.ts +0 -149
  16. package/src/api_client/__tests__/middleware.test.ts +0 -120
  17. package/src/api_client/__tests__/with-context.test.ts +0 -98
  18. package/src/api_client/index.ts +0 -29
  19. package/src/api_client/middleware.ts +0 -21
  20. package/src/api_client/with-context.ts +0 -26
  21. package/src/config/__tests__/index.test.ts +0 -65
  22. package/src/config/index.ts +0 -20
  23. package/src/context/mcp-context.ts +0 -1
  24. package/src/context/stdio-context.ts +0 -6
  25. package/src/errors/missing-team-name-error.ts +0 -8
  26. package/src/formatters/__tests__/mcp-response.test.ts +0 -106
  27. package/src/formatters/mcp-response.ts +0 -95
  28. package/src/generated/api-types.ts +0 -2968
  29. package/src/i18n/__tests__/index.test.ts +0 -53
  30. package/src/i18n/index.ts +0 -39
  31. package/src/index.ts +0 -47
  32. package/src/locales/en.json +0 -13
  33. package/src/locales/ja.json +0 -13
  34. package/src/prompts/__tests__/index.test.ts +0 -48
  35. package/src/prompts/__tests__/summarize-post.test.ts +0 -291
  36. package/src/prompts/index.ts +0 -21
  37. package/src/prompts/summarize-post.ts +0 -94
  38. package/src/resources/__tests__/index.test.ts +0 -50
  39. package/src/resources/__tests__/recent-posts-list.test.ts +0 -92
  40. package/src/resources/__tests__/recent-posts.test.ts +0 -270
  41. package/src/resources/index.ts +0 -33
  42. package/src/resources/recent-posts-list.ts +0 -22
  43. package/src/resources/recent-posts.ts +0 -45
  44. package/src/schemas/team-name-schema.ts +0 -19
  45. package/src/tools/__tests__/attachments.test.ts +0 -460
  46. package/src/tools/__tests__/categories.test.ts +0 -402
  47. package/src/tools/__tests__/comments.test.ts +0 -970
  48. package/src/tools/__tests__/helps.test.ts +0 -222
  49. package/src/tools/__tests__/index.test.ts +0 -48
  50. package/src/tools/__tests__/post-actions.test.ts +0 -445
  51. package/src/tools/__tests__/posts.test.ts +0 -917
  52. package/src/tools/__tests__/search.test.ts +0 -339
  53. package/src/tools/__tests__/teams.test.ts +0 -615
  54. package/src/tools/attachments.ts +0 -167
  55. package/src/tools/categories.ts +0 -153
  56. package/src/tools/comments.ts +0 -258
  57. package/src/tools/helps.ts +0 -50
  58. package/src/tools/index.ts +0 -351
  59. package/src/tools/post-actions.ts +0 -132
  60. package/src/tools/posts.ts +0 -179
  61. package/src/tools/search.ts +0 -98
  62. package/src/tools/teams.ts +0 -157
  63. package/src/transformers/__tests__/category-transformer.test.ts +0 -161
  64. package/src/transformers/__tests__/comment-transformer.test.ts +0 -129
  65. package/src/transformers/__tests__/post-name-normalizer.test.ts +0 -53
  66. package/src/transformers/__tests__/post-transformer.test.ts +0 -70
  67. package/src/transformers/__tests__/query-normalizer.test.ts +0 -98
  68. package/src/transformers/__tests__/team-name-normalizer.test.ts +0 -21
  69. package/src/transformers/category-transformer.ts +0 -36
  70. package/src/transformers/comment-transformer.ts +0 -34
  71. package/src/transformers/post-name-normalizer.ts +0 -30
  72. package/src/transformers/post-transformer.ts +0 -38
  73. package/src/transformers/query-normalizer.ts +0 -36
  74. package/src/transformers/team-name-normalizer.ts +0 -7
  75. package/tsconfig.build.json +0 -4
  76. package/tsconfig.json +0 -30
  77. package/tsdown.config.ts +0 -13
  78. package/vitest.config.ts +0 -24
@@ -1,98 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { normalizeSearchQuery } from "../query-normalizer.js";
3
-
4
- describe("normalizeSearchQuery", () => {
5
- describe("wildcard normalization", () => {
6
- it("should convert * to empty string", () => {
7
- expect(normalizeSearchQuery("*")).toBe("");
8
- });
9
-
10
- it("should not convert * when part of a larger query", () => {
11
- expect(normalizeSearchQuery("user:* tag:release")).toBe(
12
- "user:* tag:release",
13
- );
14
- });
15
- });
16
-
17
- describe("date syntax normalization", () => {
18
- it("should convert after: to created:>", () => {
19
- expect(normalizeSearchQuery("after:2025-08-16")).toBe(
20
- "created:>2025-08-16",
21
- );
22
- });
23
-
24
- it("should convert before: to created:<", () => {
25
- expect(normalizeSearchQuery("before:2025-08-16")).toBe(
26
- "created:<2025-08-16",
27
- );
28
- });
29
-
30
- it("should convert since: to created:>", () => {
31
- expect(normalizeSearchQuery("since:2025-08-16")).toBe(
32
- "created:>2025-08-16",
33
- );
34
- });
35
-
36
- it("should convert until: to created:<", () => {
37
- expect(normalizeSearchQuery("until:2025-08-16")).toBe(
38
- "created:<2025-08-16",
39
- );
40
- });
41
-
42
- it("should handle case-insensitive matching", () => {
43
- expect(normalizeSearchQuery("AFTER:2025-08-16")).toBe(
44
- "created:>2025-08-16",
45
- );
46
- expect(normalizeSearchQuery("After:2025-08-16")).toBe(
47
- "created:>2025-08-16",
48
- );
49
- });
50
-
51
- it("should handle multiple date patterns in one query", () => {
52
- expect(
53
- normalizeSearchQuery(
54
- "user:fukayatsu after:2025-08-16 before:2025-08-22",
55
- ),
56
- ).toBe("user:fukayatsu created:>2025-08-16 created:<2025-08-22");
57
- });
58
-
59
- it("should not convert partial matches", () => {
60
- expect(normalizeSearchQuery("notafter:2025-08-16")).toBe(
61
- "notafter:2025-08-16",
62
- );
63
- expect(normalizeSearchQuery("after:notadate")).toBe("after:notadate");
64
- });
65
-
66
- it("should handle complex queries with mixed syntax", () => {
67
- expect(
68
- normalizeSearchQuery(
69
- "user:fukayatsu after:2025-08-01 tag:release wip:false",
70
- ),
71
- ).toBe("user:fukayatsu created:>2025-08-01 tag:release wip:false");
72
- });
73
- });
74
-
75
- describe("no transformation needed", () => {
76
- it("should not modify valid esa syntax", () => {
77
- expect(normalizeSearchQuery("created:>2025-08-16")).toBe(
78
- "created:>2025-08-16",
79
- );
80
- expect(normalizeSearchQuery("updated:<2025-08-16")).toBe(
81
- "updated:<2025-08-16",
82
- );
83
- });
84
-
85
- it("should preserve normal search queries", () => {
86
- expect(normalizeSearchQuery("user:fukayatsu tag:release")).toBe(
87
- "user:fukayatsu tag:release",
88
- );
89
- expect(normalizeSearchQuery("category:dev wip:false")).toBe(
90
- "category:dev wip:false",
91
- );
92
- });
93
-
94
- it("should handle empty string", () => {
95
- expect(normalizeSearchQuery("")).toBe("");
96
- });
97
- });
98
- });
@@ -1,21 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { normalizeTeamName } from "../team-name-normalizer.js";
3
-
4
- describe("normalizeTeamName", () => {
5
- it("should extract team name from URL-like input", () => {
6
- expect(normalizeTeamName("docs.example.com")).toBe("docs");
7
- expect(normalizeTeamName("my-team.example.com")).toBe("my-team");
8
- expect(normalizeTeamName("company.example.com")).toBe("company");
9
- });
10
-
11
- it("should leave normal team names unchanged", () => {
12
- expect(normalizeTeamName("docs")).toBe("docs");
13
- expect(normalizeTeamName("my-team")).toBe("my-team");
14
- });
15
-
16
- it("should handle edge cases", () => {
17
- expect(normalizeTeamName("")).toBe("");
18
- expect(normalizeTeamName(".")).toBe("");
19
- expect(normalizeTeamName("team.")).toBe("team");
20
- });
21
- });
@@ -1,36 +0,0 @@
1
- import type { components } from "../generated/api-types.js";
2
-
3
- export function transformCategory(category: components["schemas"]["Category"]) {
4
- return {
5
- full_name: category.full_name,
6
- count: category.count,
7
- has_child: category.has_child || false,
8
- };
9
- }
10
-
11
- export function transformCategoryList(
12
- categoryList: components["schemas"]["CategoryList"],
13
- ) {
14
- return {
15
- current_category: categoryList.current_category,
16
- categories: categoryList.categories?.map(transformCategory) || [],
17
- parent_categories: categoryList.parent_categories?.map(
18
- (parentCategory) => ({
19
- current_category: parentCategory.current_category,
20
- categories: parentCategory.categories?.map(transformCategory) || [],
21
- }),
22
- ),
23
- readme: categoryList.readme,
24
- no_category: categoryList.no_category
25
- ? transformCategory(categoryList.no_category)
26
- : undefined,
27
- descendant_posts: categoryList.descendant_posts,
28
- posts: categoryList.posts,
29
- total_count: categoryList.total_count,
30
- per_page: categoryList.per_page,
31
- page: categoryList.page,
32
- prev_page: categoryList.prev_page,
33
- next_page: categoryList.next_page,
34
- max_per_page: categoryList.max_per_page,
35
- };
36
- }
@@ -1,34 +0,0 @@
1
- import type { components } from "../generated/api-types.js";
2
-
3
- export interface CommentTransformOptions {
4
- truncateBody?: number;
5
- }
6
-
7
- export function transformComment(
8
- comment: components["schemas"]["Comment"],
9
- options: CommentTransformOptions = {},
10
- ) {
11
- const { truncateBody } = options;
12
-
13
- let bodyMd = comment.body_md;
14
- if (truncateBody && bodyMd && bodyMd.length > truncateBody) {
15
- bodyMd = `${bodyMd.slice(0, truncateBody)}...`;
16
- }
17
-
18
- return {
19
- id: comment.id,
20
- post_number: comment.post_number,
21
- url: comment.url,
22
- body_md: bodyMd,
23
- created_at: comment.created_at,
24
- updated_at: comment.updated_at,
25
- created_by: comment.created_by,
26
- stats: {
27
- stargazers_count: comment.stargazers_count,
28
- star: comment.star,
29
- },
30
- stargazers: comment.stargazers,
31
- };
32
- }
33
-
34
- export type TransformedComment = ReturnType<typeof transformComment>;
@@ -1,30 +0,0 @@
1
- export interface PostNameParts {
2
- name?: string;
3
- category?: string;
4
- }
5
-
6
- export function normalizePostName(
7
- name?: string,
8
- category?: string,
9
- ): PostNameParts {
10
- if (!name) {
11
- return { name, category };
12
- }
13
-
14
- if (category !== undefined) {
15
- return { name, category };
16
- }
17
-
18
- if (name.includes("/")) {
19
- const parts = name.split("/");
20
- const extractedName = parts.pop();
21
- const extractedCategory = parts.join("/");
22
-
23
- return {
24
- name: extractedName || undefined,
25
- category: extractedCategory,
26
- };
27
- }
28
-
29
- return { name, category };
30
- }
@@ -1,38 +0,0 @@
1
- import type { components } from "../generated/api-types.js";
2
-
3
- export interface PostTransformOptions {
4
- truncateBody?: number;
5
- }
6
-
7
- export function transformPost(
8
- post: components["schemas"]["Post"],
9
- options: PostTransformOptions = {},
10
- ) {
11
- const { truncateBody } = options;
12
-
13
- let bodyMd = post.body_md;
14
- if (truncateBody && bodyMd && bodyMd.length > truncateBody) {
15
- bodyMd = `${bodyMd.slice(0, truncateBody)}...`;
16
- }
17
-
18
- return {
19
- url: post.url,
20
- wip: post.wip ? "WIP" : ("Shipped" as const),
21
- kind: post.kind,
22
- category_and_title_and_tags: post.full_name,
23
- body_md: bodyMd,
24
- created_at: post.created_at,
25
- updated_at: post.updated_at,
26
- created_by: post.created_by,
27
- updated_by: post.updated_by,
28
- stats: {
29
- tasks_count: post.tasks_count,
30
- done_tasks_count: post.done_tasks_count,
31
- comments_count: post.comments_count,
32
- stargazers_count: post.stargazers_count,
33
- watchers_count: post.watchers_count,
34
- },
35
- };
36
- }
37
-
38
- export type TransformedPost = ReturnType<typeof transformPost>;
@@ -1,36 +0,0 @@
1
- export function normalizeSearchQuery(query: string): string {
2
- let normalized = query;
3
-
4
- // Convert wildcard "*" to empty string (for "all posts" queries)
5
- if (normalized === "*") {
6
- normalized = "";
7
- }
8
-
9
- // Convert common date syntax patterns from other services to esa format
10
- // GitHub/Gmail style: after:YYYY-MM-DD -> created:>YYYY-MM-DD
11
- normalized = normalized.replace(
12
- /\bafter:(\d{4}-\d{2}-\d{2})\b/gi,
13
- "created:>$1",
14
- );
15
-
16
- // GitHub/Gmail style: before:YYYY-MM-DD -> created:<YYYY-MM-DD
17
- normalized = normalized.replace(
18
- /\bbefore:(\d{4}-\d{2}-\d{2})\b/gi,
19
- "created:<$1",
20
- );
21
-
22
- // Alternative patterns that might be used
23
- // since:YYYY-MM-DD -> created:>YYYY-MM-DD
24
- normalized = normalized.replace(
25
- /\bsince:(\d{4}-\d{2}-\d{2})\b/gi,
26
- "created:>$1",
27
- );
28
-
29
- // until:YYYY-MM-DD -> created:<YYYY-MM-DD
30
- normalized = normalized.replace(
31
- /\buntil:(\d{4}-\d{2}-\d{2})\b/gi,
32
- "created:<$1",
33
- );
34
-
35
- return normalized;
36
- }
@@ -1,7 +0,0 @@
1
- export function normalizeTeamName(teamName: string): string {
2
- const dotIndex = teamName.indexOf(".");
3
- if (dotIndex >= 0) {
4
- return teamName.substring(0, dotIndex);
5
- }
6
- return teamName;
7
- }
@@ -1,4 +0,0 @@
1
- {
2
- "extends": "./tsconfig.json",
3
- "exclude": ["**/__tests__/**"]
4
- }
package/tsconfig.json DELETED
@@ -1,30 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "NodeNext",
5
- "lib": ["ES2022"],
6
- "moduleResolution": "nodenext",
7
- "outDir": "./bin",
8
- "rootDir": "./src",
9
- "strict": true,
10
- "esModuleInterop": true,
11
- "skipLibCheck": true,
12
- "forceConsistentCasingInFileNames": true,
13
- "resolveJsonModule": true,
14
- "declaration": true,
15
- "declarationMap": true,
16
- "sourceMap": true,
17
- "removeComments": true,
18
- "noImplicitAny": true,
19
- "strictNullChecks": true,
20
- "strictFunctionTypes": true,
21
- "noImplicitThis": true,
22
- "noUnusedLocals": true,
23
- "noUnusedParameters": true,
24
- "noImplicitReturns": true,
25
- "noFallthroughCasesInSwitch": true,
26
- "allowSyntheticDefaultImports": true,
27
- "isolatedModules": true
28
- },
29
- "include": ["src/**/*"]
30
- }
package/tsdown.config.ts DELETED
@@ -1,13 +0,0 @@
1
- import { defineConfig } from "tsdown";
2
-
3
- export default defineConfig({
4
- entry: "src/index.ts",
5
- outDir: "bin",
6
- format: "es",
7
- platform: "node",
8
- target: "node20",
9
- clean: true,
10
- dts: false,
11
- tsconfig: "tsconfig.build.json",
12
- minify: true,
13
- });
package/vitest.config.ts DELETED
@@ -1,24 +0,0 @@
1
- import { defineConfig } from "vitest/config";
2
-
3
- export default defineConfig({
4
- test: {
5
- globals: false,
6
- environment: "node",
7
- include: ["**/__tests__/**/*.{test,spec}.{js,ts,jsx,tsx}"],
8
- coverage: {
9
- provider: "v8",
10
- reporter: ["text", "json", "html"],
11
- exclude: [
12
- "node_modules/",
13
- "bin/",
14
- "**/*.config.ts",
15
- "**/*.config.js",
16
- "**/context/**",
17
- "**/generated/**",
18
- ],
19
- },
20
- },
21
- resolve: {
22
- extensions: [".ts", ".js"],
23
- },
24
- });