@projitive/mcp 2.0.2 → 2.0.4

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 (41) hide show
  1. package/README.md +14 -1
  2. package/output/package.json +8 -2
  3. package/output/source/common/artifacts.js +1 -1
  4. package/output/source/common/artifacts.test.js +11 -11
  5. package/output/source/common/errors.js +19 -19
  6. package/output/source/common/files.js +11 -11
  7. package/output/source/common/files.test.js +14 -14
  8. package/output/source/common/index.js +10 -10
  9. package/output/source/common/linter.js +27 -27
  10. package/output/source/common/linter.test.js +9 -9
  11. package/output/source/common/markdown.js +3 -3
  12. package/output/source/common/markdown.test.js +15 -15
  13. package/output/source/common/response.js +74 -74
  14. package/output/source/common/response.test.js +30 -30
  15. package/output/source/common/store.js +40 -40
  16. package/output/source/common/store.test.js +72 -72
  17. package/output/source/common/types.js +3 -3
  18. package/output/source/common/utils.js +8 -8
  19. package/output/source/index.js +16 -16
  20. package/output/source/index.test.js +64 -64
  21. package/output/source/prompts/index.js +3 -3
  22. package/output/source/prompts/quickStart.js +96 -96
  23. package/output/source/prompts/taskDiscovery.js +184 -180
  24. package/output/source/prompts/taskExecution.js +148 -147
  25. package/output/source/resources/designs.js +26 -26
  26. package/output/source/resources/designs.test.js +88 -88
  27. package/output/source/resources/governance.js +19 -19
  28. package/output/source/resources/index.js +2 -2
  29. package/output/source/resources/readme.js +7 -7
  30. package/output/source/resources/readme.test.js +113 -113
  31. package/output/source/resources/reports.js +10 -10
  32. package/output/source/resources/reports.test.js +83 -83
  33. package/output/source/tools/index.js +3 -3
  34. package/output/source/tools/project.js +196 -191
  35. package/output/source/tools/project.test.js +187 -164
  36. package/output/source/tools/roadmap.js +173 -76
  37. package/output/source/tools/roadmap.test.js +58 -42
  38. package/output/source/tools/task.js +380 -255
  39. package/output/source/tools/task.test.js +117 -110
  40. package/output/source/types.js +22 -22
  41. package/package.json +8 -2
@@ -1,153 +1,153 @@
1
- import { describe, expect, it } from "vitest";
2
- import { parseDesignMetadata, validateDesignMetadata } from "./designs.js";
3
- describe("designs module", () => {
4
- describe("parseDesignMetadata", () => {
5
- it("parses task metadata from markdown", () => {
1
+ import { describe, expect, it } from 'vitest';
2
+ import { parseDesignMetadata, validateDesignMetadata } from './designs.js';
3
+ describe('designs module', () => {
4
+ describe('parseDesignMetadata', () => {
5
+ it('parses task metadata from markdown', () => {
6
6
  const markdown = [
7
- "# Design Document",
8
- "",
9
- "**Task:** TASK-0001",
10
- "**Owner:** ai-copilot",
11
- "**Status:** Draft",
12
- "**Last Updated:** 2026-02-22",
13
- "",
14
- "Some content here",
15
- ].join("\n");
7
+ '# Design Document',
8
+ '',
9
+ '**Task:** TASK-0001',
10
+ '**Owner:** ai-copilot',
11
+ '**Status:** Draft',
12
+ '**Last Updated:** 2026-02-22',
13
+ '',
14
+ 'Some content here',
15
+ ].join('\n');
16
16
  const metadata = parseDesignMetadata(markdown);
17
- expect(metadata.task).toBe("TASK-0001");
18
- expect(metadata.owner).toBe("ai-copilot");
19
- expect(metadata.status).toBe("Draft");
20
- expect(metadata.lastUpdated).toBe("2026-02-22");
17
+ expect(metadata.task).toBe('TASK-0001');
18
+ expect(metadata.owner).toBe('ai-copilot');
19
+ expect(metadata.status).toBe('Draft');
20
+ expect(metadata.lastUpdated).toBe('2026-02-22');
21
21
  });
22
- it("parses roadmap metadata from markdown", () => {
22
+ it('parses roadmap metadata from markdown', () => {
23
23
  const markdown = [
24
- "# Design Document",
25
- "",
26
- "**Roadmap:** ROADMAP-0001",
27
- "",
28
- "Some content here",
29
- ].join("\n");
24
+ '# Design Document',
25
+ '',
26
+ '**Roadmap:** ROADMAP-0001',
27
+ '',
28
+ 'Some content here',
29
+ ].join('\n');
30
30
  const metadata = parseDesignMetadata(markdown);
31
- expect(metadata.roadmap).toBe("ROADMAP-0001");
31
+ expect(metadata.roadmap).toBe('ROADMAP-0001');
32
32
  });
33
- it("returns empty object for markdown without metadata", () => {
33
+ it('returns empty object for markdown without metadata', () => {
34
34
  const markdown = [
35
- "# Simple Design",
36
- "",
37
- "No metadata here",
38
- ].join("\n");
35
+ '# Simple Design',
36
+ '',
37
+ 'No metadata here',
38
+ ].join('\n');
39
39
  const metadata = parseDesignMetadata(markdown);
40
40
  expect(metadata).toEqual({});
41
41
  });
42
- it("handles empty string", () => {
43
- const metadata = parseDesignMetadata("");
42
+ it('handles empty string', () => {
43
+ const metadata = parseDesignMetadata('');
44
44
  expect(metadata).toEqual({});
45
45
  });
46
- it("handles malformed metadata lines", () => {
46
+ it('handles malformed metadata lines', () => {
47
47
  const markdown = [
48
- "# Report",
49
- "",
50
- "Task without colon",
51
- "Not a metadata line",
52
- ":",
53
- "Task:",
54
- ].join("\n");
48
+ '# Report',
49
+ '',
50
+ 'Task without colon',
51
+ 'Not a metadata line',
52
+ ':',
53
+ 'Task:',
54
+ ].join('\n');
55
55
  const metadata = parseDesignMetadata(markdown);
56
56
  expect(metadata).toBeDefined();
57
57
  });
58
- it("parses metadata in different formats", () => {
58
+ it('parses metadata in different formats', () => {
59
59
  const markdown = [
60
- "Task: TASK-0001",
61
- "task: TASK-0002",
62
- "TASK: TASK-0003",
63
- " task : TASK-0004 ",
64
- ].join("\n");
60
+ 'Task: TASK-0001',
61
+ 'task: TASK-0002',
62
+ 'TASK: TASK-0003',
63
+ ' task : TASK-0004 ',
64
+ ].join('\n');
65
65
  const metadata = parseDesignMetadata(markdown);
66
66
  expect(metadata.task).toBeDefined();
67
67
  });
68
68
  });
69
- describe("validateDesignMetadata", () => {
70
- it("validates correct task metadata", () => {
69
+ describe('validateDesignMetadata', () => {
70
+ it('validates correct task metadata', () => {
71
71
  const metadata = {
72
- task: "TASK-0001",
73
- owner: "ai-copilot",
74
- status: "Draft",
75
- lastUpdated: "2026-02-22",
72
+ task: 'TASK-0001',
73
+ owner: 'ai-copilot',
74
+ status: 'Draft',
75
+ lastUpdated: '2026-02-22',
76
76
  };
77
77
  const result = validateDesignMetadata(metadata);
78
78
  expect(result.ok).toBe(true);
79
79
  expect(result.errors).toEqual([]);
80
80
  });
81
- it("rejects missing task metadata", () => {
81
+ it('rejects missing task metadata', () => {
82
82
  const metadata = {
83
- owner: "ai-copilot",
83
+ owner: 'ai-copilot',
84
84
  };
85
85
  const result = validateDesignMetadata(metadata);
86
86
  expect(result.ok).toBe(false);
87
- expect(result.errors).toContain("Missing Task metadata");
87
+ expect(result.errors).toContain('Missing Task metadata');
88
88
  });
89
- it("rejects invalid task ID format", () => {
89
+ it('rejects invalid task ID format', () => {
90
90
  const metadata = {
91
- task: "invalid-format",
91
+ task: 'invalid-format',
92
92
  };
93
93
  const result = validateDesignMetadata(metadata);
94
94
  expect(result.ok).toBe(false);
95
- expect(result.errors.some((e) => e.includes("Invalid Task"))).toBe(true);
95
+ expect(result.errors.some((e) => e.includes('Invalid Task'))).toBe(true);
96
96
  });
97
- it("validates optional roadmap metadata", () => {
97
+ it('validates optional roadmap metadata', () => {
98
98
  const metadata = {
99
- task: "TASK-0001",
100
- roadmap: "ROADMAP-0001",
99
+ task: 'TASK-0001',
100
+ roadmap: 'ROADMAP-0001',
101
101
  };
102
102
  const result = validateDesignMetadata(metadata);
103
103
  expect(result.ok).toBe(true);
104
104
  });
105
- it("rejects invalid roadmap ID format", () => {
105
+ it('rejects invalid roadmap ID format', () => {
106
106
  const metadata = {
107
- task: "TASK-0001",
108
- roadmap: "invalid-roadmap",
107
+ task: 'TASK-0001',
108
+ roadmap: 'invalid-roadmap',
109
109
  };
110
110
  const result = validateDesignMetadata(metadata);
111
111
  expect(result.ok).toBe(false);
112
- expect(result.errors.some((e) => e.includes("Invalid Roadmap"))).toBe(true);
112
+ expect(result.errors.some((e) => e.includes('Invalid Roadmap'))).toBe(true);
113
113
  });
114
- it("handles empty metadata object", () => {
114
+ it('handles empty metadata object', () => {
115
115
  const metadata = {};
116
116
  const result = validateDesignMetadata(metadata);
117
117
  expect(result.ok).toBe(false);
118
118
  expect(result.errors.length).toBeGreaterThan(0);
119
119
  });
120
- it("collects multiple validation errors", () => {
120
+ it('collects multiple validation errors', () => {
121
121
  const metadata = {
122
- task: "invalid-task",
123
- roadmap: "invalid-roadmap",
122
+ task: 'invalid-task',
123
+ roadmap: 'invalid-roadmap',
124
124
  };
125
125
  const result = validateDesignMetadata(metadata);
126
126
  expect(result.ok).toBe(false);
127
127
  expect(result.errors.length).toBeGreaterThan(1);
128
128
  });
129
129
  });
130
- describe("integration", () => {
131
- it("parses and validates complete design metadata", () => {
130
+ describe('integration', () => {
131
+ it('parses and validates complete design metadata', () => {
132
132
  const markdown = [
133
- "# Design Completion Report",
134
- "",
135
- "**Task:** TASK-0001",
136
- "**Roadmap:** ROADMAP-0002",
137
- "**Owner:** ai-copilot",
138
- "**Status:** Completed",
139
- "**Last Updated:** 2026-02-22",
140
- "",
141
- "## Summary",
142
- "Design completed successfully",
143
- ].join("\n");
133
+ '# Design Completion Report',
134
+ '',
135
+ '**Task:** TASK-0001',
136
+ '**Roadmap:** ROADMAP-0002',
137
+ '**Owner:** ai-copilot',
138
+ '**Status:** Completed',
139
+ '**Last Updated:** 2026-02-22',
140
+ '',
141
+ '## Summary',
142
+ 'Design completed successfully',
143
+ ].join('\n');
144
144
  const metadata = parseDesignMetadata(markdown);
145
145
  const validation = validateDesignMetadata(metadata);
146
- expect(metadata.task).toBe("TASK-0001");
147
- expect(metadata.roadmap).toBe("ROADMAP-0002");
148
- expect(metadata.owner).toBe("ai-copilot");
149
- expect(metadata.status).toBe("Completed");
150
- expect(metadata.lastUpdated).toBe("2026-02-22");
146
+ expect(metadata.task).toBe('TASK-0001');
147
+ expect(metadata.roadmap).toBe('ROADMAP-0002');
148
+ expect(metadata.owner).toBe('ai-copilot');
149
+ expect(metadata.status).toBe('Completed');
150
+ expect(metadata.lastUpdated).toBe('2026-02-22');
151
151
  expect(validation.ok).toBe(true);
152
152
  });
153
153
  });
@@ -1,39 +1,39 @@
1
1
  // Governance resource management
2
- import { readMarkdownOrFallback } from "../common/utils.js";
2
+ import { readMarkdownOrFallback } from '../common/utils.js';
3
3
  export function registerGovernanceResources(server, repoRoot) {
4
- server.registerResource("governanceWorkspace", "projitive://governance/workspace", {
5
- title: "Governance Workspace",
6
- description: "Primary governance README under .projitive",
7
- mimeType: "text/markdown",
4
+ server.registerResource('governanceWorkspace', 'projitive://governance/workspace', {
5
+ title: 'Governance Workspace',
6
+ description: 'Primary governance README under .projitive',
7
+ mimeType: 'text/markdown',
8
8
  }, async () => ({
9
9
  contents: [
10
10
  {
11
- uri: "projitive://governance/workspace",
12
- text: await readMarkdownOrFallback(".projitive/README.md", "Governance Workspace", repoRoot),
11
+ uri: 'projitive://governance/workspace',
12
+ text: await readMarkdownOrFallback('.projitive/README.md', 'Governance Workspace', repoRoot),
13
13
  },
14
14
  ],
15
15
  }));
16
- server.registerResource("governanceTasks", "projitive://governance/tasks", {
17
- title: "Governance Tasks",
18
- description: "Current task pool markdown view generated from .projitive sqlite task table",
19
- mimeType: "text/markdown",
16
+ server.registerResource('governanceTasks', 'projitive://governance/tasks', {
17
+ title: 'Governance Tasks',
18
+ description: 'Current task pool markdown view generated from .projitive governance store',
19
+ mimeType: 'text/markdown',
20
20
  }, async () => ({
21
21
  contents: [
22
22
  {
23
- uri: "projitive://governance/tasks",
24
- text: await readMarkdownOrFallback(".projitive/tasks.md", "Governance Tasks", repoRoot),
23
+ uri: 'projitive://governance/tasks',
24
+ text: await readMarkdownOrFallback('.projitive/tasks.md', 'Governance Tasks', repoRoot),
25
25
  },
26
26
  ],
27
27
  }));
28
- server.registerResource("governanceRoadmap", "projitive://governance/roadmap", {
29
- title: "Governance Roadmap",
30
- description: "Current roadmap markdown view generated from .projitive sqlite roadmap table",
31
- mimeType: "text/markdown",
28
+ server.registerResource('governanceRoadmap', 'projitive://governance/roadmap', {
29
+ title: 'Governance Roadmap',
30
+ description: 'Current roadmap markdown view generated from .projitive governance store',
31
+ mimeType: 'text/markdown',
32
32
  }, async () => ({
33
33
  contents: [
34
34
  {
35
- uri: "projitive://governance/roadmap",
36
- text: await readMarkdownOrFallback(".projitive/roadmap.md", "Governance Roadmap", repoRoot),
35
+ uri: 'projitive://governance/roadmap',
36
+ text: await readMarkdownOrFallback('.projitive/roadmap.md', 'Governance Roadmap', repoRoot),
37
37
  },
38
38
  ],
39
39
  }));
@@ -1,5 +1,5 @@
1
- import { registerGovernanceResources } from "./governance.js";
2
- import { registerDesignFilesResources } from "./designs.js";
1
+ import { registerGovernanceResources } from './governance.js';
2
+ import { registerDesignFilesResources } from './designs.js';
3
3
  export function registerResources(server, repoRoot) {
4
4
  registerGovernanceResources(server, repoRoot);
5
5
  registerDesignFilesResources(server, repoRoot);
@@ -8,18 +8,18 @@ export function parseRequiredReading(markdown) {
8
8
  inSection = true;
9
9
  continue;
10
10
  }
11
- if (inSection && trimmed.startsWith("## ")) {
11
+ if (inSection && trimmed.startsWith('## ')) {
12
12
  break;
13
13
  }
14
- if (!inSection || !trimmed.startsWith("- ")) {
14
+ if (!inSection || !trimmed.startsWith('- ')) {
15
15
  continue;
16
16
  }
17
- const payload = trimmed.replace(/^-\s+/, "");
18
- if (payload.startsWith("Local:")) {
19
- result.push({ source: "Local", value: payload.replace("Local:", "").trim() });
17
+ const payload = trimmed.replace(/^-\s+/, '');
18
+ if (payload.startsWith('Local:')) {
19
+ result.push({ source: 'Local', value: payload.replace('Local:', '').trim() });
20
20
  }
21
- if (payload.startsWith("External:")) {
22
- result.push({ source: "External", value: payload.replace("External:", "").trim() });
21
+ if (payload.startsWith('External:')) {
22
+ result.push({ source: 'External', value: payload.replace('External:', '').trim() });
23
23
  }
24
24
  }
25
25
  return result;
@@ -1,165 +1,165 @@
1
- import { describe, expect, it } from "vitest";
2
- import { parseRequiredReading, } from "./readme.js";
3
- describe("readme module", () => {
4
- describe("parseRequiredReading", () => {
5
- it("parses local and external required reading items", () => {
1
+ import { describe, expect, it } from 'vitest';
2
+ import { parseRequiredReading, } from './readme.js';
3
+ describe('readme module', () => {
4
+ describe('parseRequiredReading', () => {
5
+ it('parses local and external required reading items', () => {
6
6
  const markdown = [
7
- "# Project README",
8
- "",
9
- "Some intro content",
10
- "",
11
- "## Required Reading for Agents",
12
- "",
13
- "- Local: ./designs/README.md",
14
- "- Local: .projitive/tasks.md",
15
- "- External: https://example.com/docs",
16
- "",
17
- "## Other Section",
18
- "",
19
- "More content here",
20
- ].join("\n");
7
+ '# Project README',
8
+ '',
9
+ 'Some intro content',
10
+ '',
11
+ '## Required Reading for Agents',
12
+ '',
13
+ '- Local: ./designs/README.md',
14
+ '- Local: .projitive/tasks.md',
15
+ '- External: https://example.com/docs',
16
+ '',
17
+ '## Other Section',
18
+ '',
19
+ 'More content here',
20
+ ].join('\n');
21
21
  const result = parseRequiredReading(markdown);
22
22
  expect(result.length).toBe(3);
23
23
  expect(result[0]).toEqual({
24
- source: "Local",
25
- value: "./designs/README.md",
24
+ source: 'Local',
25
+ value: './designs/README.md',
26
26
  });
27
27
  expect(result[1]).toEqual({
28
- source: "Local",
29
- value: ".projitive/tasks.md",
28
+ source: 'Local',
29
+ value: '.projitive/tasks.md',
30
30
  });
31
31
  expect(result[2]).toEqual({
32
- source: "External",
33
- value: "https://example.com/docs",
32
+ source: 'External',
33
+ value: 'https://example.com/docs',
34
34
  });
35
35
  });
36
- it("parses Chinese section header", () => {
36
+ it('parses Chinese section header', () => {
37
37
  const markdown = [
38
- "# 项目 README",
39
- "",
40
- "## Agent 必读",
41
- "",
42
- "- Local: ./docs/guide.md",
43
- "",
44
- "## 其他部分",
45
- ].join("\n");
38
+ '# 项目 README',
39
+ '',
40
+ '## Agent 必读',
41
+ '',
42
+ '- Local: ./docs/guide.md',
43
+ '',
44
+ '## 其他部分',
45
+ ].join('\n');
46
46
  const result = parseRequiredReading(markdown);
47
47
  expect(result.length).toBe(1);
48
- expect(result[0].source).toBe("Local");
49
- expect(result[0].value).toBe("./docs/guide.md");
48
+ expect(result[0].source).toBe('Local');
49
+ expect(result[0].value).toBe('./docs/guide.md');
50
50
  });
51
- it("returns empty array when no required reading section", () => {
51
+ it('returns empty array when no required reading section', () => {
52
52
  const markdown = [
53
- "# Simple README",
54
- "",
55
- "No required reading here",
56
- "",
57
- "## Other Section",
58
- ].join("\n");
53
+ '# Simple README',
54
+ '',
55
+ 'No required reading here',
56
+ '',
57
+ '## Other Section',
58
+ ].join('\n');
59
59
  const result = parseRequiredReading(markdown);
60
60
  expect(result).toEqual([]);
61
61
  });
62
- it("returns empty array for empty string", () => {
63
- const result = parseRequiredReading("");
62
+ it('returns empty array for empty string', () => {
63
+ const result = parseRequiredReading('');
64
64
  expect(result).toEqual([]);
65
65
  });
66
- it("ignores non-list items in required reading section", () => {
66
+ it('ignores non-list items in required reading section', () => {
67
67
  const markdown = [
68
- "## Required Reading for Agents",
69
- "",
70
- "Some paragraph text here",
71
- "- Local: valid-item.md",
72
- "Another paragraph",
73
- "- External: https://valid.com",
74
- "",
75
- "## Next Section",
76
- ].join("\n");
68
+ '## Required Reading for Agents',
69
+ '',
70
+ 'Some paragraph text here',
71
+ '- Local: valid-item.md',
72
+ 'Another paragraph',
73
+ '- External: https://valid.com',
74
+ '',
75
+ '## Next Section',
76
+ ].join('\n');
77
77
  const result = parseRequiredReading(markdown);
78
78
  expect(result.length).toBe(2);
79
- expect(result[0].value).toBe("valid-item.md");
80
- expect(result[1].value).toBe("https://valid.com");
79
+ expect(result[0].value).toBe('valid-item.md');
80
+ expect(result[1].value).toBe('https://valid.com');
81
81
  });
82
- it("handles items with whitespace variations", () => {
82
+ it('handles items with whitespace variations', () => {
83
83
  const markdown = [
84
- "## Required Reading for Agents",
85
- "",
86
- "- Local: ./path/with/spaces.md ",
87
- "- External: https://example.com ",
88
- ].join("\n");
84
+ '## Required Reading for Agents',
85
+ '',
86
+ '- Local: ./path/with/spaces.md ',
87
+ '- External: https://example.com ',
88
+ ].join('\n');
89
89
  const result = parseRequiredReading(markdown);
90
90
  expect(result.length).toBe(2);
91
- expect(result[0].value).toBe("./path/with/spaces.md");
92
- expect(result[1].value).toBe("https://example.com");
91
+ expect(result[0].value).toBe('./path/with/spaces.md');
92
+ expect(result[1].value).toBe('https://example.com');
93
93
  });
94
- it("ignores items without Local: or External: prefix", () => {
94
+ it('ignores items without Local: or External: prefix', () => {
95
95
  const markdown = [
96
- "## Required Reading for Agents",
97
- "",
98
- "- Local: valid.md",
99
- "- Invalid: this is ignored",
100
- "- Just a plain list item",
101
- "- External: https://valid.com",
102
- ].join("\n");
96
+ '## Required Reading for Agents',
97
+ '',
98
+ '- Local: valid.md',
99
+ '- Invalid: this is ignored',
100
+ '- Just a plain list item',
101
+ '- External: https://valid.com',
102
+ ].join('\n');
103
103
  const result = parseRequiredReading(markdown);
104
104
  expect(result.length).toBe(2);
105
- expect(result.every((item) => item.source === "Local" || item.source === "External")).toBe(true);
105
+ expect(result.every((item) => item.source === 'Local' || item.source === 'External')).toBe(true);
106
106
  });
107
- it("stops at next section header", () => {
107
+ it('stops at next section header', () => {
108
108
  const markdown = [
109
- "## Required Reading for Agents",
110
- "",
111
- "- Local: before.md",
112
- "",
113
- "## Another Section",
114
- "",
115
- "- Local: after.md",
116
- ].join("\n");
109
+ '## Required Reading for Agents',
110
+ '',
111
+ '- Local: before.md',
112
+ '',
113
+ '## Another Section',
114
+ '',
115
+ '- Local: after.md',
116
+ ].join('\n');
117
117
  const result = parseRequiredReading(markdown);
118
118
  expect(result.length).toBe(1);
119
- expect(result[0].value).toBe("before.md");
119
+ expect(result[0].value).toBe('before.md');
120
120
  });
121
- it("handles multiple required reading sections (takes first one)", () => {
121
+ it('handles multiple required reading sections (takes first one)', () => {
122
122
  const markdown = [
123
- "## Required Reading for Agents",
124
- "",
125
- "- Local: first.md",
126
- "",
127
- "## Other Section",
128
- "",
129
- "## Required Reading for Agents",
130
- "",
131
- "- Local: second.md",
132
- ].join("\n");
123
+ '## Required Reading for Agents',
124
+ '',
125
+ '- Local: first.md',
126
+ '',
127
+ '## Other Section',
128
+ '',
129
+ '## Required Reading for Agents',
130
+ '',
131
+ '- Local: second.md',
132
+ ].join('\n');
133
133
  const result = parseRequiredReading(markdown);
134
134
  expect(result.length).toBe(1);
135
- expect(result[0].value).toBe("first.md");
135
+ expect(result[0].value).toBe('first.md');
136
136
  });
137
137
  });
138
- describe("edge cases", () => {
139
- it("handles markdown with just the section", () => {
140
- const markdown = "## Required Reading for Agents";
138
+ describe('edge cases', () => {
139
+ it('handles markdown with just the section', () => {
140
+ const markdown = '## Required Reading for Agents';
141
141
  const result = parseRequiredReading(markdown);
142
142
  expect(result).toEqual([]);
143
143
  });
144
- it("handles section with empty lines", () => {
144
+ it('handles section with empty lines', () => {
145
145
  const markdown = [
146
- "## Required Reading for Agents",
147
- "",
148
- "",
149
- "- Local: item.md",
150
- "",
151
- "",
152
- ].join("\n");
146
+ '## Required Reading for Agents',
147
+ '',
148
+ '',
149
+ '- Local: item.md',
150
+ '',
151
+ '',
152
+ ].join('\n');
153
153
  const result = parseRequiredReading(markdown);
154
154
  expect(result.length).toBe(1);
155
- expect(result[0].value).toBe("item.md");
155
+ expect(result[0].value).toBe('item.md');
156
156
  });
157
- it("handles mixed case section headers", () => {
157
+ it('handles mixed case section headers', () => {
158
158
  const markdown = [
159
- "## required reading for agents",
160
- "",
161
- "- Local: lowercase.md",
162
- ].join("\n");
159
+ '## required reading for agents',
160
+ '',
161
+ '- Local: lowercase.md',
162
+ ].join('\n');
163
163
  const result = parseRequiredReading(markdown);
164
164
  expect(result.length).toBe(1);
165
165
  });