@mrtdown/core 2.0.0-alpha.2 → 2.0.0-alpha.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 (112) hide show
  1. package/dist/cli/commands/create.d.ts +30 -0
  2. package/dist/cli/commands/create.js +189 -0
  3. package/dist/cli/commands/create.js.map +1 -0
  4. package/dist/cli/commands/list.d.ts +6 -0
  5. package/dist/cli/commands/list.js +106 -0
  6. package/dist/cli/commands/list.js.map +1 -0
  7. package/dist/cli/commands/show.d.ts +6 -0
  8. package/dist/cli/commands/show.js +156 -0
  9. package/dist/cli/commands/show.js.map +1 -0
  10. package/dist/cli/commands/validate.d.ts +6 -0
  11. package/dist/cli/commands/validate.js +19 -0
  12. package/dist/cli/commands/validate.js.map +1 -0
  13. package/dist/cli/index.d.ts +2 -0
  14. package/dist/cli/index.js +162 -0
  15. package/dist/cli/index.js.map +1 -0
  16. package/dist/index.d.ts +20 -11
  17. package/dist/index.js +20 -11
  18. package/dist/index.js.map +1 -1
  19. package/dist/llm/client.d.ts +2 -0
  20. package/dist/llm/client.js +5 -0
  21. package/dist/llm/client.js.map +1 -0
  22. package/dist/llm/common/MemoryStore.d.ts +21 -0
  23. package/dist/llm/common/MemoryStore.js +100 -0
  24. package/dist/llm/common/MemoryStore.js.map +1 -0
  25. package/dist/llm/common/MemoryStore.test.d.ts +1 -0
  26. package/dist/llm/common/MemoryStore.test.js +225 -0
  27. package/dist/llm/common/MemoryStore.test.js.map +1 -0
  28. package/dist/llm/common/formatCurrentState.d.ts +10 -0
  29. package/dist/llm/common/formatCurrentState.js +342 -0
  30. package/dist/llm/common/formatCurrentState.js.map +1 -0
  31. package/dist/llm/common/tool.d.ts +32 -0
  32. package/dist/llm/common/tool.js +6 -0
  33. package/dist/llm/common/tool.js.map +1 -0
  34. package/dist/llm/functions/extractClaimsFromNewEvidence/eval.test.d.ts +1 -0
  35. package/dist/llm/functions/extractClaimsFromNewEvidence/eval.test.js +433 -0
  36. package/dist/llm/functions/extractClaimsFromNewEvidence/eval.test.js.map +1 -0
  37. package/dist/llm/functions/extractClaimsFromNewEvidence/index.d.ts +18 -0
  38. package/dist/llm/functions/extractClaimsFromNewEvidence/index.js +153 -0
  39. package/dist/llm/functions/extractClaimsFromNewEvidence/index.js.map +1 -0
  40. package/dist/llm/functions/extractClaimsFromNewEvidence/prompt.d.ts +1 -0
  41. package/dist/llm/functions/extractClaimsFromNewEvidence/prompt.js +168 -0
  42. package/dist/llm/functions/extractClaimsFromNewEvidence/prompt.js.map +1 -0
  43. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindLinesTool.d.ts +19 -0
  44. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindLinesTool.js +65 -0
  45. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindLinesTool.js.map +1 -0
  46. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindServicesTool.d.ts +21 -0
  47. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindServicesTool.js +115 -0
  48. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindServicesTool.js.map +1 -0
  49. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindStationsTool.d.ts +24 -0
  50. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindStationsTool.js +110 -0
  51. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindStationsTool.js.map +1 -0
  52. package/dist/llm/functions/generateIssueTitleAndSlug/index.d.ts +14 -0
  53. package/dist/llm/functions/generateIssueTitleAndSlug/index.js +38 -0
  54. package/dist/llm/functions/generateIssueTitleAndSlug/index.js.map +1 -0
  55. package/dist/llm/functions/generateIssueTitleAndSlug/prompt.d.ts +1 -0
  56. package/dist/llm/functions/generateIssueTitleAndSlug/prompt.js +23 -0
  57. package/dist/llm/functions/generateIssueTitleAndSlug/prompt.js.map +1 -0
  58. package/dist/llm/functions/translate/index.d.ts +1 -0
  59. package/dist/llm/functions/translate/index.js +59 -0
  60. package/dist/llm/functions/translate/index.js.map +1 -0
  61. package/dist/llm/functions/triageNewEvidence/eval.test.d.ts +1 -0
  62. package/dist/llm/functions/triageNewEvidence/eval.test.js +139 -0
  63. package/dist/llm/functions/triageNewEvidence/eval.test.js.map +1 -0
  64. package/dist/llm/functions/triageNewEvidence/index.d.ts +37 -0
  65. package/dist/llm/functions/triageNewEvidence/index.js +121 -0
  66. package/dist/llm/functions/triageNewEvidence/index.js.map +1 -0
  67. package/dist/llm/functions/triageNewEvidence/prompt.d.ts +1 -0
  68. package/dist/llm/functions/triageNewEvidence/prompt.js +60 -0
  69. package/dist/llm/functions/triageNewEvidence/prompt.js.map +1 -0
  70. package/dist/llm/functions/triageNewEvidence/tools/FindIssuesTool.d.ts +19 -0
  71. package/dist/llm/functions/triageNewEvidence/tools/FindIssuesTool.js +65 -0
  72. package/dist/llm/functions/triageNewEvidence/tools/FindIssuesTool.js.map +1 -0
  73. package/dist/llm/functions/triageNewEvidence/tools/GetIssueTool.d.ts +19 -0
  74. package/dist/llm/functions/triageNewEvidence/tools/GetIssueTool.js +37 -0
  75. package/dist/llm/functions/triageNewEvidence/tools/GetIssueTool.js.map +1 -0
  76. package/dist/scripts/ingestViaWebhook.d.ts +1 -0
  77. package/dist/scripts/ingestViaWebhook.js +9 -0
  78. package/dist/scripts/ingestViaWebhook.js.map +1 -0
  79. package/dist/validators/buildContext.d.ts +7 -0
  80. package/dist/validators/buildContext.js +164 -0
  81. package/dist/validators/buildContext.js.map +1 -0
  82. package/dist/validators/index.d.ts +17 -0
  83. package/dist/validators/index.js +58 -0
  84. package/dist/validators/index.js.map +1 -0
  85. package/dist/validators/issue.d.ts +13 -0
  86. package/dist/validators/issue.js +220 -0
  87. package/dist/validators/issue.js.map +1 -0
  88. package/dist/validators/landmark.d.ts +7 -0
  89. package/dist/validators/landmark.js +43 -0
  90. package/dist/validators/landmark.js.map +1 -0
  91. package/dist/validators/line.d.ts +8 -0
  92. package/dist/validators/line.js +87 -0
  93. package/dist/validators/line.js.map +1 -0
  94. package/dist/validators/operator.d.ts +7 -0
  95. package/dist/validators/operator.js +43 -0
  96. package/dist/validators/operator.js.map +1 -0
  97. package/dist/validators/service.d.ts +8 -0
  98. package/dist/validators/service.js +87 -0
  99. package/dist/validators/service.js.map +1 -0
  100. package/dist/validators/station.d.ts +8 -0
  101. package/dist/validators/station.js +93 -0
  102. package/dist/validators/station.js.map +1 -0
  103. package/dist/validators/town.d.ts +7 -0
  104. package/dist/validators/town.js +43 -0
  105. package/dist/validators/town.js.map +1 -0
  106. package/dist/validators/types.d.ts +19 -0
  107. package/dist/validators/types.js +2 -0
  108. package/dist/validators/types.js.map +1 -0
  109. package/dist/validators/utils.d.ts +2 -0
  110. package/dist/validators/utils.js +9 -0
  111. package/dist/validators/utils.js.map +1 -0
  112. package/package.json +11 -7
@@ -0,0 +1,225 @@
1
+ import { describe, expect, test } from 'vitest';
2
+ import { MemoryStore } from './MemoryStore.js';
3
+ describe('MemoryStore', () => {
4
+ describe('constructor', () => {
5
+ test('creates empty store by default', () => {
6
+ const store = new MemoryStore();
7
+ expect(store.dumpFiles()).toEqual({});
8
+ expect(store.listDir('')).toEqual([]);
9
+ });
10
+ test('seeds store with files from seed object', () => {
11
+ const store = new MemoryStore({
12
+ files: {
13
+ 'foo.txt': 'hello',
14
+ 'bar/baz.json': '{"x":1}',
15
+ },
16
+ });
17
+ expect(store.readText('foo.txt')).toBe('hello');
18
+ expect(store.readText('bar/baz.json')).toBe('{"x":1}');
19
+ expect(store.listDir('')).toEqual(['bar', 'foo.txt']);
20
+ expect(store.listDir('bar')).toEqual(['baz.json']);
21
+ });
22
+ });
23
+ describe('exists', () => {
24
+ test('returns false for non-existent path', () => {
25
+ const store = new MemoryStore();
26
+ expect(store.exists('missing')).toBe(false);
27
+ expect(store.exists('a/b/c')).toBe(false);
28
+ });
29
+ test('returns true for root directory', () => {
30
+ const store = new MemoryStore();
31
+ expect(store.exists('')).toBe(true);
32
+ });
33
+ test('returns true for existing file', () => {
34
+ const store = new MemoryStore({ files: { 'foo.txt': 'hi' } });
35
+ expect(store.exists('foo.txt')).toBe(true);
36
+ });
37
+ test('returns true for existing directory', () => {
38
+ const store = new MemoryStore({ files: { 'dir/file.txt': 'hi' } });
39
+ expect(store.exists('dir')).toBe(true);
40
+ });
41
+ test('normalizes path when checking', () => {
42
+ const store = new MemoryStore({ files: { 'foo.txt': 'hi' } });
43
+ expect(store.exists('foo.txt')).toBe(true);
44
+ expect(store.exists('./foo.txt')).toBe(true);
45
+ });
46
+ });
47
+ describe('readText', () => {
48
+ test('returns content of existing file', () => {
49
+ const store = new MemoryStore({ files: { 'foo.txt': 'hello world' } });
50
+ expect(store.readText('foo.txt')).toBe('hello world');
51
+ });
52
+ test('throws for non-existent file', () => {
53
+ const store = new MemoryStore();
54
+ expect(() => store.readText('missing.txt')).toThrow('MemoryStore: File not found: missing.txt');
55
+ });
56
+ test('normalizes path when reading', () => {
57
+ const store = new MemoryStore({ files: { 'a/b.txt': 'content' } });
58
+ expect(store.readText('./a/b.txt')).toBe('content');
59
+ });
60
+ });
61
+ describe('readJson', () => {
62
+ test('parses and returns JSON', () => {
63
+ const store = new MemoryStore({
64
+ files: { 'data.json': '{"name":"test","count":42}' },
65
+ });
66
+ const data = store.readJson('data.json');
67
+ expect(data).toEqual({ name: 'test', count: 42 });
68
+ });
69
+ test('throws for invalid JSON', () => {
70
+ const store = new MemoryStore({ files: { 'bad.json': 'not json' } });
71
+ expect(() => store.readJson('bad.json')).toThrow();
72
+ });
73
+ });
74
+ describe('listDir', () => {
75
+ test('returns sorted list of children for root', () => {
76
+ const store = new MemoryStore({
77
+ files: {
78
+ 'a.txt': 'a',
79
+ 'z.txt': 'z',
80
+ 'm.txt': 'm',
81
+ 'dir/file.txt': 'f',
82
+ },
83
+ });
84
+ expect(store.listDir('')).toEqual(['a.txt', 'dir', 'm.txt', 'z.txt']);
85
+ });
86
+ test('returns sorted list of children for nested dir', () => {
87
+ const store = new MemoryStore({
88
+ files: {
89
+ 'parent/child1.txt': '1',
90
+ 'parent/child2.txt': '2',
91
+ 'parent/subdir/file.txt': '3',
92
+ },
93
+ });
94
+ expect(store.listDir('parent')).toEqual(['child1.txt', 'child2.txt', 'subdir']);
95
+ });
96
+ test('returns empty array for empty directory', () => {
97
+ const store = new MemoryStore();
98
+ expect(store.listDir('')).toEqual([]);
99
+ });
100
+ test('throws for non-existent directory', () => {
101
+ const store = new MemoryStore();
102
+ expect(() => store.listDir('missing')).toThrow('MemoryStore: Directory not found: missing');
103
+ });
104
+ });
105
+ describe('ensureDir', () => {
106
+ test('creates nested directories recursively', () => {
107
+ const store = new MemoryStore();
108
+ store.ensureDir('a/b/c');
109
+ expect(store.exists('a')).toBe(true);
110
+ expect(store.exists('a/b')).toBe(true);
111
+ expect(store.exists('a/b/c')).toBe(true);
112
+ expect(store.listDir('a')).toEqual(['b']);
113
+ expect(store.listDir('a/b')).toEqual(['c']);
114
+ expect(store.listDir('a/b/c')).toEqual([]);
115
+ });
116
+ test('is idempotent for existing directory', () => {
117
+ const store = new MemoryStore();
118
+ store.ensureDir('x');
119
+ store.ensureDir('x');
120
+ expect(store.listDir('x')).toEqual([]);
121
+ });
122
+ });
123
+ describe('writeText', () => {
124
+ test('writes file and creates parent directories', () => {
125
+ const store = new MemoryStore();
126
+ store.writeText('deep/path/file.txt', 'content');
127
+ expect(store.readText('deep/path/file.txt')).toBe('content');
128
+ expect(store.listDir('deep')).toEqual(['path']);
129
+ expect(store.listDir('deep/path')).toEqual(['file.txt']);
130
+ });
131
+ test('overwrites existing file', () => {
132
+ const store = new MemoryStore({ files: { 'foo.txt': 'old' } });
133
+ store.writeText('foo.txt', 'new');
134
+ expect(store.readText('foo.txt')).toBe('new');
135
+ });
136
+ });
137
+ describe('writeJson', () => {
138
+ test('writes JSON-serialized data', () => {
139
+ const store = new MemoryStore();
140
+ store.writeJson('data.json', { foo: 'bar', num: 123 });
141
+ expect(store.readText('data.json')).toBe('{"foo":"bar","num":123}');
142
+ expect(store.readJson('data.json')).toEqual({ foo: 'bar', num: 123 });
143
+ });
144
+ });
145
+ describe('appendText', () => {
146
+ test('creates new file when path does not exist', () => {
147
+ const store = new MemoryStore();
148
+ store.appendText('log.txt', 'line1\n');
149
+ expect(store.readText('log.txt')).toBe('line1\n');
150
+ });
151
+ test('appends to existing file', () => {
152
+ const store = new MemoryStore({ files: { 'log.txt': 'line1\n' } });
153
+ store.appendText('log.txt', 'line2\n');
154
+ store.appendText('log.txt', 'line3\n');
155
+ expect(store.readText('log.txt')).toBe('line1\nline2\nline3\n');
156
+ });
157
+ test('creates parent directories when needed', () => {
158
+ const store = new MemoryStore();
159
+ store.appendText('logs/2025/app.log', 'entry\n');
160
+ expect(store.readText('logs/2025/app.log')).toBe('entry\n');
161
+ });
162
+ });
163
+ describe('delete', () => {
164
+ test('removes file', () => {
165
+ const store = new MemoryStore({ files: { 'foo.txt': 'hi' } });
166
+ store.delete('foo.txt');
167
+ expect(store.exists('foo.txt')).toBe(false);
168
+ expect(() => store.readText('foo.txt')).toThrow();
169
+ });
170
+ test('removes directory', () => {
171
+ const store = new MemoryStore({ files: { 'dir/file.txt': 'hi' } });
172
+ store.delete('dir');
173
+ expect(store.exists('dir')).toBe(false);
174
+ expect(() => store.listDir('dir')).toThrow();
175
+ });
176
+ test('removes both normalized and original path', () => {
177
+ const store = new MemoryStore({ files: { 'foo.txt': 'hi' } });
178
+ store.delete('./foo.txt');
179
+ expect(store.exists('foo.txt')).toBe(false);
180
+ });
181
+ });
182
+ describe('dumpFiles', () => {
183
+ test('returns copy of all files', () => {
184
+ const store = new MemoryStore({
185
+ files: {
186
+ 'a.txt': 'a',
187
+ 'b/c.txt': 'c',
188
+ },
189
+ });
190
+ const dumped = store.dumpFiles();
191
+ expect(dumped).toEqual({
192
+ 'a.txt': 'a',
193
+ 'b/c.txt': 'c',
194
+ });
195
+ });
196
+ test('returns empty object for empty store', () => {
197
+ const store = new MemoryStore();
198
+ expect(store.dumpFiles()).toEqual({});
199
+ });
200
+ });
201
+ describe('full workflow', () => {
202
+ test('write → read → append → read → delete cycle', () => {
203
+ const store = new MemoryStore();
204
+ store.writeText('notes.txt', 'First note\n');
205
+ expect(store.readText('notes.txt')).toBe('First note\n');
206
+ store.appendText('notes.txt', 'Second note\n');
207
+ expect(store.readText('notes.txt')).toBe('First note\nSecond note\n');
208
+ store.delete('notes.txt');
209
+ expect(store.exists('notes.txt')).toBe(false);
210
+ });
211
+ test('nested structure with multiple operations', () => {
212
+ const store = new MemoryStore();
213
+ store.writeText('issues/2025-01-01-disruption.json', '{}');
214
+ store.writeText('issues/2025-01-02-maintenance.json', '{}');
215
+ store.writeJson('config.json', { version: 1 });
216
+ expect(store.listDir('')).toEqual(['config.json', 'issues']);
217
+ expect(store.listDir('issues')).toEqual([
218
+ '2025-01-01-disruption.json',
219
+ '2025-01-02-maintenance.json',
220
+ ]);
221
+ expect(store.readJson('config.json')).toEqual({ version: 1 });
222
+ });
223
+ });
224
+ });
225
+ //# sourceMappingURL=MemoryStore.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MemoryStore.test.js","sourceRoot":"/","sources":["llm/common/MemoryStore.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, test } from 'vitest';\nimport { MemoryStore } from './MemoryStore.js';\n\ndescribe('MemoryStore', () => {\n describe('constructor', () => {\n test('creates empty store by default', () => {\n const store = new MemoryStore();\n expect(store.dumpFiles()).toEqual({});\n expect(store.listDir('')).toEqual([]);\n });\n\n test('seeds store with files from seed object', () => {\n const store = new MemoryStore({\n files: {\n 'foo.txt': 'hello',\n 'bar/baz.json': '{\"x\":1}',\n },\n });\n expect(store.readText('foo.txt')).toBe('hello');\n expect(store.readText('bar/baz.json')).toBe('{\"x\":1}');\n expect(store.listDir('')).toEqual(['bar', 'foo.txt']);\n expect(store.listDir('bar')).toEqual(['baz.json']);\n });\n });\n\n describe('exists', () => {\n test('returns false for non-existent path', () => {\n const store = new MemoryStore();\n expect(store.exists('missing')).toBe(false);\n expect(store.exists('a/b/c')).toBe(false);\n });\n\n test('returns true for root directory', () => {\n const store = new MemoryStore();\n expect(store.exists('')).toBe(true);\n });\n\n test('returns true for existing file', () => {\n const store = new MemoryStore({ files: { 'foo.txt': 'hi' } });\n expect(store.exists('foo.txt')).toBe(true);\n });\n\n test('returns true for existing directory', () => {\n const store = new MemoryStore({ files: { 'dir/file.txt': 'hi' } });\n expect(store.exists('dir')).toBe(true);\n });\n\n test('normalizes path when checking', () => {\n const store = new MemoryStore({ files: { 'foo.txt': 'hi' } });\n expect(store.exists('foo.txt')).toBe(true);\n expect(store.exists('./foo.txt')).toBe(true);\n });\n });\n\n describe('readText', () => {\n test('returns content of existing file', () => {\n const store = new MemoryStore({ files: { 'foo.txt': 'hello world' } });\n expect(store.readText('foo.txt')).toBe('hello world');\n });\n\n test('throws for non-existent file', () => {\n const store = new MemoryStore();\n expect(() => store.readText('missing.txt')).toThrow(\n 'MemoryStore: File not found: missing.txt'\n );\n });\n\n test('normalizes path when reading', () => {\n const store = new MemoryStore({ files: { 'a/b.txt': 'content' } });\n expect(store.readText('./a/b.txt')).toBe('content');\n });\n });\n\n describe('readJson', () => {\n test('parses and returns JSON', () => {\n const store = new MemoryStore({\n files: { 'data.json': '{\"name\":\"test\",\"count\":42}' },\n });\n const data = store.readJson<{ name: string; count: number }>('data.json');\n expect(data).toEqual({ name: 'test', count: 42 });\n });\n\n test('throws for invalid JSON', () => {\n const store = new MemoryStore({ files: { 'bad.json': 'not json' } });\n expect(() => store.readJson('bad.json')).toThrow();\n });\n });\n\n describe('listDir', () => {\n test('returns sorted list of children for root', () => {\n const store = new MemoryStore({\n files: {\n 'a.txt': 'a',\n 'z.txt': 'z',\n 'm.txt': 'm',\n 'dir/file.txt': 'f',\n },\n });\n expect(store.listDir('')).toEqual(['a.txt', 'dir', 'm.txt', 'z.txt']);\n });\n\n test('returns sorted list of children for nested dir', () => {\n const store = new MemoryStore({\n files: {\n 'parent/child1.txt': '1',\n 'parent/child2.txt': '2',\n 'parent/subdir/file.txt': '3',\n },\n });\n expect(store.listDir('parent')).toEqual(['child1.txt', 'child2.txt', 'subdir']);\n });\n\n test('returns empty array for empty directory', () => {\n const store = new MemoryStore();\n expect(store.listDir('')).toEqual([]);\n });\n\n test('throws for non-existent directory', () => {\n const store = new MemoryStore();\n expect(() => store.listDir('missing')).toThrow(\n 'MemoryStore: Directory not found: missing'\n );\n });\n });\n\n describe('ensureDir', () => {\n test('creates nested directories recursively', () => {\n const store = new MemoryStore();\n store.ensureDir('a/b/c');\n expect(store.exists('a')).toBe(true);\n expect(store.exists('a/b')).toBe(true);\n expect(store.exists('a/b/c')).toBe(true);\n expect(store.listDir('a')).toEqual(['b']);\n expect(store.listDir('a/b')).toEqual(['c']);\n expect(store.listDir('a/b/c')).toEqual([]);\n });\n\n test('is idempotent for existing directory', () => {\n const store = new MemoryStore();\n store.ensureDir('x');\n store.ensureDir('x');\n expect(store.listDir('x')).toEqual([]);\n });\n });\n\n describe('writeText', () => {\n test('writes file and creates parent directories', () => {\n const store = new MemoryStore();\n store.writeText('deep/path/file.txt', 'content');\n expect(store.readText('deep/path/file.txt')).toBe('content');\n expect(store.listDir('deep')).toEqual(['path']);\n expect(store.listDir('deep/path')).toEqual(['file.txt']);\n });\n\n test('overwrites existing file', () => {\n const store = new MemoryStore({ files: { 'foo.txt': 'old' } });\n store.writeText('foo.txt', 'new');\n expect(store.readText('foo.txt')).toBe('new');\n });\n });\n\n describe('writeJson', () => {\n test('writes JSON-serialized data', () => {\n const store = new MemoryStore();\n store.writeJson('data.json', { foo: 'bar', num: 123 });\n expect(store.readText('data.json')).toBe('{\"foo\":\"bar\",\"num\":123}');\n expect(store.readJson('data.json')).toEqual({ foo: 'bar', num: 123 });\n });\n });\n\n describe('appendText', () => {\n test('creates new file when path does not exist', () => {\n const store = new MemoryStore();\n store.appendText('log.txt', 'line1\\n');\n expect(store.readText('log.txt')).toBe('line1\\n');\n });\n\n test('appends to existing file', () => {\n const store = new MemoryStore({ files: { 'log.txt': 'line1\\n' } });\n store.appendText('log.txt', 'line2\\n');\n store.appendText('log.txt', 'line3\\n');\n expect(store.readText('log.txt')).toBe('line1\\nline2\\nline3\\n');\n });\n\n test('creates parent directories when needed', () => {\n const store = new MemoryStore();\n store.appendText('logs/2025/app.log', 'entry\\n');\n expect(store.readText('logs/2025/app.log')).toBe('entry\\n');\n });\n });\n\n describe('delete', () => {\n test('removes file', () => {\n const store = new MemoryStore({ files: { 'foo.txt': 'hi' } });\n store.delete('foo.txt');\n expect(store.exists('foo.txt')).toBe(false);\n expect(() => store.readText('foo.txt')).toThrow();\n });\n\n test('removes directory', () => {\n const store = new MemoryStore({ files: { 'dir/file.txt': 'hi' } });\n store.delete('dir');\n expect(store.exists('dir')).toBe(false);\n expect(() => store.listDir('dir')).toThrow();\n });\n\n test('removes both normalized and original path', () => {\n const store = new MemoryStore({ files: { 'foo.txt': 'hi' } });\n store.delete('./foo.txt');\n expect(store.exists('foo.txt')).toBe(false);\n });\n });\n\n describe('dumpFiles', () => {\n test('returns copy of all files', () => {\n const store = new MemoryStore({\n files: {\n 'a.txt': 'a',\n 'b/c.txt': 'c',\n },\n });\n const dumped = store.dumpFiles();\n expect(dumped).toEqual({\n 'a.txt': 'a',\n 'b/c.txt': 'c',\n });\n });\n\n test('returns empty object for empty store', () => {\n const store = new MemoryStore();\n expect(store.dumpFiles()).toEqual({});\n });\n });\n\n describe('full workflow', () => {\n test('write → read → append → read → delete cycle', () => {\n const store = new MemoryStore();\n store.writeText('notes.txt', 'First note\\n');\n expect(store.readText('notes.txt')).toBe('First note\\n');\n\n store.appendText('notes.txt', 'Second note\\n');\n expect(store.readText('notes.txt')).toBe('First note\\nSecond note\\n');\n\n store.delete('notes.txt');\n expect(store.exists('notes.txt')).toBe(false);\n });\n\n test('nested structure with multiple operations', () => {\n const store = new MemoryStore();\n store.writeText('issues/2025-01-01-disruption.json', '{}');\n store.writeText('issues/2025-01-02-maintenance.json', '{}');\n store.writeJson('config.json', { version: 1 });\n\n expect(store.listDir('')).toEqual(['config.json', 'issues']);\n expect(store.listDir('issues')).toEqual([\n '2025-01-01-disruption.json',\n '2025-01-02-maintenance.json',\n ]);\n expect(store.readJson('config.json')).toEqual({ version: 1 });\n });\n });\n});\n"]}
@@ -0,0 +1,10 @@
1
+ import type { IssueBundleState } from '#repo/issue/helpers/deriveCurrentState.js';
2
+ import type { Evidence } from '#schema/issue/evidence.js';
3
+ export type FormatCurrentStateOptions = {
4
+ state: IssueBundleState | null;
5
+ evidence?: Evidence[];
6
+ };
7
+ /**
8
+ * Format the current state as markdown for better LLM readability
9
+ */
10
+ export declare function formatCurrentState(stateOrOptions: IssueBundleState | null | FormatCurrentStateOptions): string;
@@ -0,0 +1,342 @@
1
+ import { gfmToMarkdown } from 'mdast-util-gfm';
2
+ import { toMarkdown } from 'mdast-util-to-markdown';
3
+ /**
4
+ * Format the current state as markdown for better LLM readability
5
+ */
6
+ export function formatCurrentState(stateOrOptions) {
7
+ const options = stateOrOptions != null &&
8
+ typeof stateOrOptions === 'object' &&
9
+ 'state' in stateOrOptions
10
+ ? stateOrOptions
11
+ : { state: stateOrOptions };
12
+ const state = options.state;
13
+ const evidence = options.evidence ?? [];
14
+ if (state == null && evidence.length === 0) {
15
+ return 'No state';
16
+ }
17
+ const services = state?.services ?? {};
18
+ const facilities = state?.facilities ?? {};
19
+ const impactEventIds = state?.impactEventIds ?? [];
20
+ const relevantEvidenceIds = state != null ? collectEvidenceIds(state) : [];
21
+ const root = {
22
+ type: 'root',
23
+ children: [],
24
+ };
25
+ // Evidence Section
26
+ root.children.push({
27
+ type: 'heading',
28
+ depth: 2,
29
+ children: [{ type: 'text', value: 'Evidence' }],
30
+ });
31
+ if (evidence.length === 0) {
32
+ root.children.push({
33
+ type: 'paragraph',
34
+ children: [{ type: 'text', value: 'None' }],
35
+ });
36
+ }
37
+ else {
38
+ for (const ev of evidence) {
39
+ root.children.push(...formatEvidenceItem(ev));
40
+ }
41
+ }
42
+ // Services Section
43
+ root.children.push({
44
+ type: 'heading',
45
+ depth: 2,
46
+ children: [{ type: 'text', value: 'Services' }],
47
+ });
48
+ const serviceKeys = Object.keys(services);
49
+ if (serviceKeys.length === 0) {
50
+ root.children.push({
51
+ type: 'paragraph',
52
+ children: [{ type: 'text', value: 'None' }],
53
+ });
54
+ }
55
+ else {
56
+ for (const key of serviceKeys) {
57
+ const svc = services[key];
58
+ root.children.push(...formatServiceSection(key, svc.serviceId, svc.effect, svc.scopes, svc.periods, svc.causes));
59
+ }
60
+ }
61
+ // Facilities Section
62
+ const facilitiesHeading = {
63
+ type: 'heading',
64
+ depth: 2,
65
+ children: [{ type: 'text', value: 'Facilities' }],
66
+ };
67
+ root.children.push(facilitiesHeading);
68
+ const facilityKeys = Object.keys(facilities);
69
+ if (facilityKeys.length === 0) {
70
+ root.children.push({
71
+ type: 'paragraph',
72
+ children: [{ type: 'text', value: 'None' }],
73
+ });
74
+ }
75
+ else {
76
+ for (const key of facilityKeys) {
77
+ const fac = facilities[key];
78
+ root.children.push(...formatFacilitySection(key, fac.stationId, fac.kind, fac.effect, fac.periods));
79
+ }
80
+ }
81
+ // Impact Event IDs Section
82
+ root.children.push({
83
+ type: 'heading',
84
+ depth: 2,
85
+ children: [{ type: 'text', value: 'Impact Event IDs' }],
86
+ });
87
+ if (impactEventIds.length === 0) {
88
+ root.children.push({
89
+ type: 'paragraph',
90
+ children: [{ type: 'text', value: 'None' }],
91
+ });
92
+ }
93
+ else {
94
+ root.children.push({
95
+ type: 'list',
96
+ ordered: false,
97
+ children: impactEventIds.map((id) => ({
98
+ type: 'listItem',
99
+ children: [
100
+ {
101
+ type: 'paragraph',
102
+ children: [{ type: 'inlineCode', value: id }],
103
+ },
104
+ ],
105
+ })),
106
+ });
107
+ }
108
+ // Relevant Evidence IDs Section
109
+ const evidenceHeading = {
110
+ type: 'heading',
111
+ depth: 2,
112
+ children: [{ type: 'text', value: 'Relevant Evidence IDs' }],
113
+ };
114
+ root.children.push(evidenceHeading);
115
+ if (relevantEvidenceIds.length === 0) {
116
+ root.children.push({
117
+ type: 'paragraph',
118
+ children: [{ type: 'text', value: 'None' }],
119
+ });
120
+ }
121
+ else {
122
+ root.children.push({
123
+ type: 'list',
124
+ ordered: false,
125
+ children: relevantEvidenceIds.map((id) => ({
126
+ type: 'listItem',
127
+ children: [
128
+ {
129
+ type: 'paragraph',
130
+ children: [{ type: 'inlineCode', value: id }],
131
+ },
132
+ ],
133
+ })),
134
+ });
135
+ }
136
+ return toMarkdown(root, { extensions: [gfmToMarkdown()] });
137
+ }
138
+ function formatEvidenceItem(ev) {
139
+ const children = [];
140
+ children.push({
141
+ type: 'heading',
142
+ depth: 3,
143
+ children: [
144
+ { type: 'inlineCode', value: ev.id },
145
+ { type: 'text', value: ` (${ev.type})` },
146
+ ],
147
+ });
148
+ children.push({
149
+ type: 'paragraph',
150
+ children: [
151
+ { type: 'text', value: 'Timestamp: ' },
152
+ { type: 'inlineCode', value: ev.ts },
153
+ ],
154
+ });
155
+ children.push({
156
+ type: 'paragraph',
157
+ children: [
158
+ { type: 'text', value: 'Source: ' },
159
+ { type: 'inlineCode', value: ev.render?.source ?? '—' },
160
+ ],
161
+ });
162
+ if ('sourceUrl' in ev) {
163
+ children.push({
164
+ type: 'paragraph',
165
+ children: [
166
+ { type: 'text', value: 'URL: ' },
167
+ {
168
+ type: 'link',
169
+ url: ev.sourceUrl,
170
+ children: [{ type: 'text', value: ev.sourceUrl }],
171
+ },
172
+ ],
173
+ });
174
+ }
175
+ children.push({
176
+ type: 'paragraph',
177
+ children: [{ type: 'text', value: 'Text:' }],
178
+ });
179
+ children.push({
180
+ type: 'blockquote',
181
+ children: [
182
+ {
183
+ type: 'paragraph',
184
+ children: [{ type: 'text', value: ev.text }],
185
+ },
186
+ ],
187
+ });
188
+ return children;
189
+ }
190
+ function collectEvidenceIds(state) {
191
+ const ids = new Set();
192
+ for (const prov of Object.values(state.servicesProvenance)) {
193
+ if (prov.effect?.evidenceId)
194
+ ids.add(prov.effect.evidenceId);
195
+ if (prov.scopes?.evidenceId)
196
+ ids.add(prov.scopes.evidenceId);
197
+ if (prov.periods?.evidenceId)
198
+ ids.add(prov.periods.evidenceId);
199
+ if (prov.causes?.evidenceId)
200
+ ids.add(prov.causes.evidenceId);
201
+ }
202
+ for (const prov of Object.values(state.facilitiesProvenance)) {
203
+ if (prov.effect?.evidenceId)
204
+ ids.add(prov.effect.evidenceId);
205
+ if (prov.periods?.evidenceId)
206
+ ids.add(prov.periods.evidenceId);
207
+ }
208
+ return [...ids];
209
+ }
210
+ function formatServiceSection(key, serviceId, effect, scopes, periods, causes) {
211
+ const children = [];
212
+ children.push({
213
+ type: 'heading',
214
+ depth: 3,
215
+ children: [{ type: 'text', value: key }],
216
+ });
217
+ children.push({
218
+ type: 'paragraph',
219
+ children: [
220
+ { type: 'text', value: 'Service ID: ' },
221
+ { type: 'inlineCode', value: serviceId },
222
+ ],
223
+ });
224
+ children.push({
225
+ type: 'paragraph',
226
+ children: [
227
+ { type: 'text', value: 'Effect: ' },
228
+ { type: 'inlineCode', value: effect?.kind ?? 'null' },
229
+ ],
230
+ });
231
+ if (scopes.length > 0) {
232
+ children.push({
233
+ type: 'paragraph',
234
+ children: [{ type: 'text', value: 'Scopes:' }],
235
+ });
236
+ children.push({
237
+ type: 'list',
238
+ ordered: false,
239
+ children: scopes.map((scope) => ({
240
+ type: 'listItem',
241
+ children: [
242
+ {
243
+ type: 'paragraph',
244
+ children: [{ type: 'inlineCode', value: formatScope(scope) }],
245
+ },
246
+ ],
247
+ })),
248
+ });
249
+ }
250
+ if (periods.length > 0) {
251
+ children.push({
252
+ type: 'paragraph',
253
+ children: [{ type: 'text', value: 'Periods:' }],
254
+ });
255
+ children.push({
256
+ type: 'list',
257
+ ordered: false,
258
+ children: periods.map((period, i) => ({
259
+ type: 'listItem',
260
+ children: [
261
+ {
262
+ type: 'paragraph',
263
+ children: [{ type: 'text', value: formatPeriod(period, i) }],
264
+ },
265
+ ],
266
+ })),
267
+ });
268
+ }
269
+ if (causes.length > 0) {
270
+ children.push({
271
+ type: 'paragraph',
272
+ children: [
273
+ { type: 'text', value: 'Causes: ' },
274
+ { type: 'inlineCode', value: causes.join(', ') },
275
+ ],
276
+ });
277
+ }
278
+ return children;
279
+ }
280
+ function formatFacilitySection(key, stationId, kind, effect, periods) {
281
+ const children = [];
282
+ children.push({
283
+ type: 'heading',
284
+ depth: 3,
285
+ children: [{ type: 'text', value: key }],
286
+ });
287
+ children.push({
288
+ type: 'paragraph',
289
+ children: [
290
+ { type: 'text', value: 'Station: ' },
291
+ { type: 'inlineCode', value: stationId },
292
+ { type: 'text', value: ', Kind: ' },
293
+ { type: 'inlineCode', value: kind },
294
+ ],
295
+ });
296
+ children.push({
297
+ type: 'paragraph',
298
+ children: [
299
+ { type: 'text', value: 'Effect: ' },
300
+ { type: 'inlineCode', value: effect?.kind ?? 'null' },
301
+ ],
302
+ });
303
+ if (periods.length > 0) {
304
+ children.push({
305
+ type: 'paragraph',
306
+ children: [{ type: 'text', value: 'Periods:' }],
307
+ });
308
+ children.push({
309
+ type: 'list',
310
+ ordered: false,
311
+ children: periods.map((period, i) => ({
312
+ type: 'listItem',
313
+ children: [
314
+ {
315
+ type: 'paragraph',
316
+ children: [{ type: 'text', value: formatPeriod(period, i) }],
317
+ },
318
+ ],
319
+ })),
320
+ });
321
+ }
322
+ return children;
323
+ }
324
+ function formatScope(scope) {
325
+ switch (scope.type) {
326
+ case 'service.whole':
327
+ return scope.type;
328
+ case 'service.segment':
329
+ return `${scope.type} (${scope.fromStationId} → ${scope.toStationId})`;
330
+ case 'service.point':
331
+ return `${scope.type} (${scope.stationId})`;
332
+ }
333
+ }
334
+ function formatPeriod(period, index) {
335
+ switch (period.kind) {
336
+ case 'fixed':
337
+ return `[${index}] fixed: ${period.startAt} → ${period.endAt ?? 'ongoing'}`;
338
+ case 'recurring':
339
+ return `[${index}] recurring ${period.frequency}: ${period.startAt}–${period.endAt} ${period.timeWindow.startAt}–${period.timeWindow.endAt}`;
340
+ }
341
+ }
342
+ //# sourceMappingURL=formatCurrentState.js.map