@relayfile/adapter-linear 0.1.21 → 0.1.22

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 (70) hide show
  1. package/discovery/linear/.adapter.md +71 -0
  2. package/discovery/linear/issues/.create.example.json +6 -0
  3. package/discovery/linear/issues/.schema.json +145 -0
  4. package/discovery/linear/issues/{issueId}/comments/.create.example.json +3 -0
  5. package/discovery/linear/issues/{issueId}/comments/.schema.json +91 -0
  6. package/dist/__tests__/aliases.test.d.ts +2 -0
  7. package/dist/__tests__/aliases.test.d.ts.map +1 -0
  8. package/dist/__tests__/aliases.test.js +184 -0
  9. package/dist/__tests__/aliases.test.js.map +1 -0
  10. package/dist/__tests__/by-state.test.d.ts +2 -0
  11. package/dist/__tests__/by-state.test.d.ts.map +1 -0
  12. package/dist/__tests__/by-state.test.js +282 -0
  13. package/dist/__tests__/by-state.test.js.map +1 -0
  14. package/dist/__tests__/index-emission.test.d.ts +2 -0
  15. package/dist/__tests__/index-emission.test.d.ts.map +1 -0
  16. package/dist/__tests__/index-emission.test.js +118 -0
  17. package/dist/__tests__/index-emission.test.js.map +1 -0
  18. package/dist/__tests__/layout-prompt.test.d.ts +2 -0
  19. package/dist/__tests__/layout-prompt.test.d.ts.map +1 -0
  20. package/dist/__tests__/layout-prompt.test.js +14 -0
  21. package/dist/__tests__/layout-prompt.test.js.map +1 -0
  22. package/dist/__tests__/linear-adapter.test.js +241 -7
  23. package/dist/__tests__/linear-adapter.test.js.map +1 -1
  24. package/dist/__tests__/name-id-convention.test.d.ts +2 -0
  25. package/dist/__tests__/name-id-convention.test.d.ts.map +1 -0
  26. package/dist/__tests__/name-id-convention.test.js +50 -0
  27. package/dist/__tests__/name-id-convention.test.js.map +1 -0
  28. package/dist/__tests__/path-mapper.test.js +5 -1
  29. package/dist/__tests__/path-mapper.test.js.map +1 -1
  30. package/dist/alias-slug.d.ts +3 -0
  31. package/dist/alias-slug.d.ts.map +1 -0
  32. package/dist/alias-slug.js +17 -0
  33. package/dist/alias-slug.js.map +1 -0
  34. package/dist/index-emitter.d.ts +10 -0
  35. package/dist/index-emitter.d.ts.map +1 -0
  36. package/dist/index-emitter.js +30 -0
  37. package/dist/index-emitter.js.map +1 -0
  38. package/dist/index.d.ts +3 -0
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +3 -0
  41. package/dist/index.js.map +1 -1
  42. package/dist/layout-prompt.d.ts +7 -0
  43. package/dist/layout-prompt.d.ts.map +1 -0
  44. package/dist/layout-prompt.js +45 -0
  45. package/dist/layout-prompt.js.map +1 -0
  46. package/dist/linear-adapter.d.ts +11 -0
  47. package/dist/linear-adapter.d.ts.map +1 -1
  48. package/dist/linear-adapter.js +403 -33
  49. package/dist/linear-adapter.js.map +1 -1
  50. package/dist/path-mapper.d.ts +22 -3
  51. package/dist/path-mapper.d.ts.map +1 -1
  52. package/dist/path-mapper.js +133 -21
  53. package/dist/path-mapper.js.map +1 -1
  54. package/dist/queries.d.ts +24 -0
  55. package/dist/queries.d.ts.map +1 -1
  56. package/dist/queries.js +50 -0
  57. package/dist/queries.js.map +1 -1
  58. package/dist/resources.d.ts +25 -0
  59. package/dist/resources.d.ts.map +1 -0
  60. package/dist/resources.js +23 -0
  61. package/dist/resources.js.map +1 -0
  62. package/dist/types.d.ts +2 -0
  63. package/dist/types.d.ts.map +1 -1
  64. package/dist/writeback.d.ts +7 -3
  65. package/dist/writeback.d.ts.map +1 -1
  66. package/dist/writeback.js +52 -14
  67. package/dist/writeback.js.map +1 -1
  68. package/dist/writeback.test.js +15 -43
  69. package/dist/writeback.test.js.map +1 -1
  70. package/package.json +3 -2
@@ -0,0 +1,282 @@
1
+ import assert from 'node:assert/strict';
2
+ import test from 'node:test';
3
+ import { LINEAR_CANONICAL_STATES, LinearAdapter, linearIssueByStatePath, linearIssuePath, slugifyStateName, } from '../index.js';
4
+ class RecordingClient {
5
+ writes = [];
6
+ deletes = [];
7
+ files = new Map();
8
+ async writeFile(input) {
9
+ const existed = this.files.has(input.path);
10
+ this.writes.push(input);
11
+ this.files.set(input.path, input);
12
+ return existed ? { updated: true } : { created: true };
13
+ }
14
+ async deleteFile(input) {
15
+ void input.workspaceId;
16
+ this.deletes.push(input.path);
17
+ this.files.delete(input.path);
18
+ }
19
+ }
20
+ class TombstoneOnlyClient {
21
+ writes = [];
22
+ files = new Map();
23
+ async writeFile(input) {
24
+ const existed = this.files.has(input.path);
25
+ this.writes.push(input);
26
+ this.files.set(input.path, input);
27
+ return existed ? { updated: true } : { created: true };
28
+ }
29
+ }
30
+ function createProvider() {
31
+ return {
32
+ name: 'relayfile-test-provider',
33
+ async proxy(_request) {
34
+ return {
35
+ status: 200,
36
+ headers: {},
37
+ data: null,
38
+ };
39
+ },
40
+ async healthCheck() {
41
+ return true;
42
+ },
43
+ };
44
+ }
45
+ function createAdapter(client, config = {}) {
46
+ return new LinearAdapter(client, createProvider(), config);
47
+ }
48
+ function createIssuePayload(overrides = {}) {
49
+ return {
50
+ id: 'issue_123',
51
+ identifier: 'ENG-123',
52
+ title: 'Ship state aliases',
53
+ state_name: 'Todo',
54
+ state: {
55
+ id: 'state_todo',
56
+ name: 'Todo',
57
+ type: 'unstarted',
58
+ },
59
+ _webhook: {
60
+ action: 'create',
61
+ },
62
+ ...overrides,
63
+ };
64
+ }
65
+ test('Linear issue ingest writes canonical and by-state files with identical bytes', async () => {
66
+ const client = new RecordingClient();
67
+ const adapter = createAdapter(client);
68
+ const result = await adapter.ingestWebhook('workspace-1', {
69
+ provider: 'linear',
70
+ eventType: 'issue.create',
71
+ objectType: 'issue',
72
+ objectId: 'issue_123',
73
+ payload: createIssuePayload(),
74
+ });
75
+ // Adapter prefers `identifier` (ENG-123) over the title via
76
+ // getLinearIssueHumanReadable when computing the canonical path.
77
+ const canonicalPath = linearIssuePath('issue_123', 'ENG-123');
78
+ const aliasPath = linearIssueByStatePath('Todo', 'ENG-123');
79
+ const canonicalWrite = client.files.get(canonicalPath);
80
+ const aliasWrite = client.files.get(aliasPath);
81
+ assert.ok(canonicalWrite);
82
+ assert.ok(aliasWrite);
83
+ assert.strictEqual(canonicalWrite?.content, aliasWrite?.content);
84
+ assert.strictEqual(canonicalWrite?.contentType, aliasWrite?.contentType);
85
+ // Auxiliary writes (LAYOUT.md, _index.json) appear in result.paths after the
86
+ // canonical and by-state alias entries; this test only asserts the canonical
87
+ // and alias positions and lets the auxiliary writes follow.
88
+ assert.strictEqual(result.paths[0], canonicalPath);
89
+ assert.ok(result.paths.includes(aliasPath));
90
+ assert.deepStrictEqual(result.errors, []);
91
+ assert.ok(result.filesWritten >= 2);
92
+ });
93
+ test('slugifyStateName keeps canonical Linear state directories stable', () => {
94
+ const expected = ['todo', 'in-progress', 'done', 'backlog', 'canceled'];
95
+ assert.deepStrictEqual(LINEAR_CANONICAL_STATES.map((state) => slugifyStateName(state)), expected);
96
+ });
97
+ test('Linear issue ingest without state_name skips by-state alias and records one error', async () => {
98
+ const client = new RecordingClient();
99
+ const adapter = createAdapter(client);
100
+ const result = await adapter.ingestWebhook('workspace-1', {
101
+ provider: 'linear',
102
+ eventType: 'issue.create',
103
+ objectType: 'issue',
104
+ objectId: 'issue_123',
105
+ payload: createIssuePayload({
106
+ state_name: undefined,
107
+ state: { id: 'state_missing_name' },
108
+ }),
109
+ });
110
+ const canonicalPath = linearIssuePath('issue_123', 'ENG-123');
111
+ assert.ok(client.files.has(canonicalPath));
112
+ assert.strictEqual(Array.from(client.files.keys()).some((path) => path.includes('/by-state/')), false);
113
+ // The PR 1 auxiliary writer emits LAYOUT.md alongside the canonical path.
114
+ // We assert canonical leads and that no by-state alias is reported, while
115
+ // tolerating the trailing LAYOUT.md auxiliary entry.
116
+ assert.strictEqual(result.paths[0], canonicalPath);
117
+ assert.equal(result.paths.some((path) => path.includes('/by-state/')), false);
118
+ assert.strictEqual(result.errors.length, 1);
119
+ assert.match(result.errors[0]?.path ?? '', /\/linear\/issues\/by-state/);
120
+ });
121
+ test('Linear by-state subtree is omitted entirely when an issue has no state', async () => {
122
+ const client = new RecordingClient();
123
+ const adapter = createAdapter(client);
124
+ await adapter.ingestWebhook('workspace-1', {
125
+ provider: 'linear',
126
+ eventType: 'issue.create',
127
+ objectType: 'issue',
128
+ objectId: 'issue_123',
129
+ payload: createIssuePayload({
130
+ state_name: undefined,
131
+ state: undefined,
132
+ }),
133
+ });
134
+ assert.deepStrictEqual(Array.from(client.files.keys()).filter((path) => path.includes('/linear/issues/by-state/')), []);
135
+ });
136
+ test('Linear issue remove deletes the canonical file and every known by-state alias', async () => {
137
+ const client = new RecordingClient();
138
+ const adapter = createAdapter(client);
139
+ const canonicalPath = linearIssuePath('issue_123', 'ENG-123');
140
+ const aliasPath = linearIssueByStatePath('Todo', 'ENG-123');
141
+ await adapter.ingestWebhook('workspace-1', {
142
+ provider: 'linear',
143
+ eventType: 'issue.create',
144
+ objectType: 'issue',
145
+ objectId: 'issue_123',
146
+ payload: createIssuePayload(),
147
+ });
148
+ const result = await adapter.ingestWebhook('workspace-1', {
149
+ provider: 'linear',
150
+ eventType: 'issue.remove',
151
+ objectType: 'issue',
152
+ objectId: 'issue_123',
153
+ payload: createIssuePayload({
154
+ _webhook: {
155
+ action: 'remove',
156
+ previousData: {
157
+ identifier: 'ENG-123',
158
+ state_name: 'Todo',
159
+ },
160
+ },
161
+ }),
162
+ });
163
+ assert.strictEqual(client.files.has(canonicalPath), false);
164
+ assert.strictEqual(client.files.has(aliasPath), false);
165
+ assert.deepStrictEqual(client.deletes.sort(), [aliasPath, canonicalPath].sort());
166
+ assert.strictEqual(result.filesDeleted, 2);
167
+ assert.deepStrictEqual(result.errors, []);
168
+ });
169
+ test('Linear issue remove falls back to tombstone writes when deleteFile is unavailable', async () => {
170
+ const client = new TombstoneOnlyClient();
171
+ const adapter = createAdapter(client);
172
+ const canonicalPath = linearIssuePath('issue_123', 'ENG-123');
173
+ const aliasPath = linearIssueByStatePath('Todo', 'ENG-123');
174
+ await adapter.ingestWebhook('workspace-1', {
175
+ provider: 'linear',
176
+ eventType: 'issue.create',
177
+ objectType: 'issue',
178
+ objectId: 'issue_123',
179
+ payload: createIssuePayload(),
180
+ });
181
+ const result = await adapter.ingestWebhook('workspace-1', {
182
+ provider: 'linear',
183
+ eventType: 'issue.remove',
184
+ objectType: 'issue',
185
+ objectId: 'issue_123',
186
+ payload: createIssuePayload({
187
+ _webhook: {
188
+ action: 'remove',
189
+ previousData: {
190
+ identifier: 'ENG-123',
191
+ state_name: 'Todo',
192
+ },
193
+ },
194
+ }),
195
+ });
196
+ // Auxiliary writes (LAYOUT.md, _index.json, by-id/by-title aliases) inflate
197
+ // the raw write count; we still verify the canonical and by-state alias
198
+ // were tombstoned and that the result counts reflect only those two deletions.
199
+ assert.ok(client.writes.length >= 4);
200
+ assert.strictEqual(JSON.parse(client.files.get(canonicalPath)?.content).deleted, true);
201
+ assert.strictEqual(JSON.parse(client.files.get(aliasPath)?.content).deleted, true);
202
+ assert.strictEqual(result.filesDeleted, 2);
203
+ assert.ok(result.paths.includes(canonicalPath));
204
+ assert.ok(result.paths.includes(aliasPath));
205
+ });
206
+ test('Linear issue state transitions delete the old by-state alias before writing the new one', async () => {
207
+ const client = new RecordingClient();
208
+ const adapter = createAdapter(client);
209
+ const todoAliasPath = linearIssueByStatePath('Todo', 'ENG-123');
210
+ const inProgressAliasPath = linearIssueByStatePath('In Progress', 'ENG-123');
211
+ await adapter.ingestWebhook('workspace-1', {
212
+ provider: 'linear',
213
+ eventType: 'issue.create',
214
+ objectType: 'issue',
215
+ objectId: 'issue_123',
216
+ payload: createIssuePayload(),
217
+ });
218
+ const result = await adapter.ingestWebhook('workspace-1', {
219
+ provider: 'linear',
220
+ eventType: 'issue.update',
221
+ objectType: 'issue',
222
+ objectId: 'issue_123',
223
+ payload: createIssuePayload({
224
+ state_name: 'In Progress',
225
+ state: {
226
+ id: 'state_in_progress',
227
+ name: 'In Progress',
228
+ type: 'started',
229
+ },
230
+ _webhook: {
231
+ action: 'update',
232
+ previousData: {
233
+ identifier: 'ENG-123',
234
+ state_name: 'Todo',
235
+ },
236
+ },
237
+ }),
238
+ });
239
+ assert.strictEqual(client.files.has(todoAliasPath), false);
240
+ assert.ok(client.files.has(inProgressAliasPath));
241
+ assert.ok(client.deletes.includes(todoAliasPath));
242
+ // The auxiliary writer interleaves LAYOUT.md/_index.json writes; assert
243
+ // canonical/aliases appear in order regardless of the auxiliary positions.
244
+ const expectedPositions = [
245
+ linearIssuePath('issue_123', 'ENG-123'),
246
+ todoAliasPath,
247
+ inProgressAliasPath,
248
+ ];
249
+ for (const path of expectedPositions) {
250
+ assert.ok(result.paths.includes(path), `expected result.paths to contain ${path}`);
251
+ }
252
+ assert.strictEqual(result.filesDeleted, 1);
253
+ });
254
+ test('Linear by-state aliases preserve mixed-case identifiers exactly', async () => {
255
+ const client = new RecordingClient();
256
+ const adapter = createAdapter(client);
257
+ const identifier = 'Eng-Api-7B';
258
+ const aliasPath = linearIssueByStatePath('Todo', identifier);
259
+ await adapter.ingestWebhook('workspace-1', {
260
+ provider: 'linear',
261
+ eventType: 'issue.create',
262
+ objectType: 'issue',
263
+ objectId: 'issue_mixed_case',
264
+ payload: createIssuePayload({
265
+ id: 'issue_mixed_case',
266
+ identifier,
267
+ title: 'Preserve identifier bytes',
268
+ }),
269
+ });
270
+ assert.ok(client.files.has(aliasPath));
271
+ assert.strictEqual(aliasPath.endsWith(`/${identifier}.json`), true);
272
+ });
273
+ test('Linear custom state aliases keep Unicode reversible and avoid slug collisions with literal hyphens', () => {
274
+ const unicodeAliasPath = linearIssueByStatePath('Révision - β', 'ENG-123');
275
+ const hyphenAliasPath = linearIssueByStatePath('QA-QC', 'ENG-123');
276
+ const whitespaceAliasPath = linearIssueByStatePath('QA QC', 'ENG-123');
277
+ assert.ok(unicodeAliasPath.includes('/r%C3%A9vision-%2D-%CE%B2/'));
278
+ assert.ok(hyphenAliasPath.includes('/qa%2Dqc/'));
279
+ assert.ok(whitespaceAliasPath.includes('/qa-qc/'));
280
+ assert.notStrictEqual(hyphenAliasPath, whitespaceAliasPath);
281
+ });
282
+ //# sourceMappingURL=by-state.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"by-state.test.js","sourceRoot":"","sources":["../../src/__tests__/by-state.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index-emission.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-emission.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/index-emission.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,118 @@
1
+ import assert from 'node:assert/strict';
2
+ import { describe, it } from 'node:test';
3
+ import { buildLinearIndexFile } from '../index-emitter.js';
4
+ import { linearCommentPath, linearIssuePath, linearTeamPath, linearUserPath, } from '../path-mapper.js';
5
+ import { linearCommentIndexRow, linearIssueIndexRow, linearTeamIndexRow, linearUserIndexRow, } from '../queries.js';
6
+ describe('linear index emission', () => {
7
+ it('emits deterministic issue, comment, user, and team indexes', () => {
8
+ const issueRows = [
9
+ linearIssueIndexRow({
10
+ id: 'issue-2',
11
+ identifier: 'AGE-1',
12
+ title: 'Second issue',
13
+ createdAt: '2026-04-01T09:00:00.000Z',
14
+ updatedAt: '2026-04-03T10:00:00.000Z',
15
+ state: { name: 'In Progress' },
16
+ }),
17
+ linearIssueIndexRow({
18
+ id: 'issue-1',
19
+ identifier: 'AGE-8',
20
+ title: 'First issue',
21
+ createdAt: '2026-04-01T08:00:00.000Z',
22
+ updatedAt: '2026-04-03T10:00:00.000Z',
23
+ state: null,
24
+ }),
25
+ ];
26
+ const commentRows = [
27
+ linearCommentIndexRow({
28
+ id: 'comment-2',
29
+ body: 'Second comment',
30
+ createdAt: '2026-04-01T07:00:00.000Z',
31
+ updatedAt: '2026-04-02T07:00:00.000Z',
32
+ }),
33
+ linearCommentIndexRow({
34
+ id: 'comment-1',
35
+ issue: { title: 'Fallback title' },
36
+ createdAt: '2026-04-01T06:00:00.000Z',
37
+ }),
38
+ ];
39
+ const userRows = [
40
+ linearUserIndexRow({
41
+ id: 'user-2',
42
+ displayName: 'Taylor',
43
+ updatedAt: '2026-04-03T11:00:00.000Z',
44
+ }),
45
+ linearUserIndexRow({
46
+ id: 'user-1',
47
+ email: 'agent@example.com',
48
+ createdAt: '2026-04-01T04:00:00.000Z',
49
+ }),
50
+ ];
51
+ const teamRows = [
52
+ linearTeamIndexRow({
53
+ id: 'team-2',
54
+ name: 'Infrastructure',
55
+ updatedAt: '2026-04-03T12:00:00.000Z',
56
+ }),
57
+ linearTeamIndexRow({
58
+ id: 'team-1',
59
+ key: 'CORE',
60
+ createdAt: '2026-04-01T05:00:00.000Z',
61
+ }),
62
+ ];
63
+ const issueIndex = buildLinearIndexFile('issues', issueRows);
64
+ const issueIndexAgain = buildLinearIndexFile('issues', [...issueRows].reverse());
65
+ const commentIndex = buildLinearIndexFile('comments', commentRows);
66
+ const userIndex = buildLinearIndexFile('users', userRows);
67
+ const teamIndex = buildLinearIndexFile('teams', teamRows);
68
+ assert.deepEqual(issueIndex, issueIndexAgain);
69
+ assert.equal(issueIndex.path, '/linear/issues/_index.json');
70
+ assert.equal(commentIndex.path, '/linear/comments/_index.json');
71
+ assert.equal(userIndex.path, '/linear/users/_index.json');
72
+ assert.equal(teamIndex.path, '/linear/teams/_index.json');
73
+ assert.equal(issueIndex.contentType, 'application/json; charset=utf-8');
74
+ assert.deepEqual(JSON.parse(issueIndex.content), [
75
+ {
76
+ id: 'issue-1',
77
+ title: 'First issue',
78
+ updated: '2026-04-03T10:00:00.000Z',
79
+ identifier: 'AGE-8',
80
+ state: '',
81
+ },
82
+ {
83
+ id: 'issue-2',
84
+ title: 'Second issue',
85
+ updated: '2026-04-03T10:00:00.000Z',
86
+ identifier: 'AGE-1',
87
+ state: 'In Progress',
88
+ },
89
+ ]);
90
+ assert.deepEqual(JSON.parse(commentIndex.content), [
91
+ { id: 'comment-2', title: 'Second comment', updated: '2026-04-02T07:00:00.000Z' },
92
+ { id: 'comment-1', title: 'Fallback title', updated: '2026-04-01T06:00:00.000Z' },
93
+ ]);
94
+ assert.deepEqual(JSON.parse(userIndex.content), [
95
+ { id: 'user-2', title: 'Taylor', updated: '2026-04-03T11:00:00.000Z' },
96
+ { id: 'user-1', title: 'agent@example.com', updated: '2026-04-01T04:00:00.000Z' },
97
+ ]);
98
+ assert.deepEqual(JSON.parse(teamIndex.content), [
99
+ { id: 'team-2', title: 'Infrastructure', updated: '2026-04-03T12:00:00.000Z' },
100
+ { id: 'team-1', title: 'CORE', updated: '2026-04-01T05:00:00.000Z' },
101
+ ]);
102
+ assert.equal(linearIssuePath('issue-1'), '/linear/issues/issue-1.json');
103
+ assert.equal(linearCommentPath('comment-1'), '/linear/comments/comment-1.json');
104
+ assert.equal(linearUserPath('user-1'), '/linear/users/user-1.json');
105
+ assert.equal(linearTeamPath('team-1'), '/linear/teams/team-1.json');
106
+ });
107
+ it('emits an empty index when a linear bucket has no records', () => {
108
+ const file = buildLinearIndexFile('comments', []);
109
+ assert.equal(file.path, '/linear/comments/_index.json');
110
+ assert.deepEqual(JSON.parse(file.content), []);
111
+ });
112
+ it('re-exports the index and layout helpers from the barrel', async () => {
113
+ const barrel = await import('../index.js');
114
+ assert.equal(barrel.buildLinearIndexFile, buildLinearIndexFile);
115
+ assert.equal(typeof barrel.linearLayoutPromptFile, 'function');
116
+ });
117
+ });
118
+ //# sourceMappingURL=index-emission.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-emission.test.js","sourceRoot":"","sources":["../../src/__tests__/index-emission.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=layout-prompt.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout-prompt.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/layout-prompt.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,14 @@
1
+ import assert from 'node:assert/strict';
2
+ import { describe, it } from 'node:test';
3
+ import { linearLayoutPromptFile } from '../layout-prompt.js';
4
+ describe('linear layout prompt', () => {
5
+ it('emits the integration layout guide at the linear root', () => {
6
+ const file = linearLayoutPromptFile();
7
+ assert.equal(file.path, '/linear/LAYOUT.md');
8
+ assert.equal(file.contentType, 'text/markdown; charset=utf-8');
9
+ assert.match(file.content, /\bls\b/u);
10
+ assert.match(file.content, /__/u);
11
+ assert.match(file.content, /_index\.json/u);
12
+ });
13
+ });
14
+ //# sourceMappingURL=layout-prompt.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout-prompt.test.js","sourceRoot":"","sources":["../../src/__tests__/layout-prompt.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAE7D,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,IAAI,GAAG,sBAAsB,EAAE,CAAC;QAEtC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC;QAC7C,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,8BAA8B,CAAC,CAAC;QAC/D,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QACtC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAClC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}