@relayfile/adapter-linear 0.2.3 → 0.2.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.
@@ -0,0 +1,482 @@
1
+ /**
2
+ * Adapter-owned auxiliary-file emission for Linear.
3
+ *
4
+ * Phase 2 port of the `emitAuxiliaryFiles` contract introduced by
5
+ * `@relayfile/adapter-core` and exercised by `@relayfile/adapter-confluence`
6
+ * in PR #78. Generalizes the Linear branch of cloud's
7
+ * `record-writer.ts::writeLinearAuxiliaryFiles` (plus
8
+ * `readLinearIssueAliasContext`) so cloud's Phase-3 dispatcher can collapse
9
+ * to a per-provider switch.
10
+ *
11
+ * Per-resource emission:
12
+ *
13
+ * * **issue** — canonical `/linear/issues/<identifier-or-title-slug>__<id>.json`,
14
+ * plus a by-uuid alias keyed on the Linear UUID (always emitted — the
15
+ * stable reconciliation anchor), a by-id alias keyed on the Linear
16
+ * `TEAM-123` identifier when present (human-readable lookup), a by-title
17
+ * alias when the title slugs to non-empty, and a by-state alias when both
18
+ * `state.name` and `identifier` are present. Index row carries
19
+ * `{ id, title, updated, identifier, state }`.
20
+ *
21
+ * * **comment** — canonical `/linear/comments/<slug>__<id>.json`, no
22
+ * subtree aliases (current cloud + adapter shape only writes the
23
+ * canonical record and the index row). Index row
24
+ * `{ id, title, updated }`.
25
+ *
26
+ * * **user**, **team** — canonical `/linear/users/<id>.json` /
27
+ * `/linear/teams/<id>.json`, index row `{ id, title, updated }`.
28
+ *
29
+ * * **project** — canonical `/linear/projects/<id>.json`. No index file
30
+ * today; the helper exists in the path-mapper but no `_index.json`
31
+ * emitter is wired in. We still emit the canonical file so cloud's
32
+ * existing project sync surfaces survive the port.
33
+ *
34
+ * * **cycle**, **milestone**, **roadmap** — canonical paths only. Same
35
+ * rationale as projects.
36
+ *
37
+ * Reconciliation: every issue write reads the prior by-uuid alias (the
38
+ * stable anchor keyed on `issue.id`, always emitted) to recover the
39
+ * previous identifier / title / state, then deletes whichever alias and
40
+ * canonical paths no longer apply. User/team writes reconcile against the
41
+ * prior index row. Reads degrade to "no reconciliation" when the client
42
+ * lacks `readFile` — same back-compat we shipped in #78.
43
+ *
44
+ * Delete tombstones: `{ id, _deleted: true }`. For issues we read the
45
+ * prior by-uuid alias to recover the identifier, title, and state — the
46
+ * UUID is always present on a tombstone (it's the only field), so the
47
+ * lookup key is guaranteed even when the original write predated the
48
+ * identifier. For all resource types, `IndexFileReconciler.remove(id)` is
49
+ * called on the delete branch so `_index.json` doesn't accumulate ghost
50
+ * rows (the Devin regression on #78 — see
51
+ * `packages/confluence/src/emit-auxiliary-files.ts`).
52
+ */
53
+ import { PriorAliasReader, IndexFileReconciler, runEmitBatch, EMIT_AUXILIARY_JSON_CONTENT_TYPE, } from '@relayfile/adapter-core';
54
+ import { slugifyAlias } from './alias-slug.js';
55
+ import { LINEAR_PATH_ROOT, linearByIdAliasPath, linearByTitleAliasPath, linearByUuidAliasPath, linearCommentPath, linearCommentsIndexPath, linearCyclePath, linearIssueByStatePath, linearIssuePath, linearIssuesIndexPath, linearMilestonePath, linearProjectPath, linearRoadmapPath, linearTeamPath, linearTeamsIndexPath, linearUserPath, linearUsersIndexPath, } from './path-mapper.js';
56
+ import { linearCommentIndexRow, linearIssueIndexRow, linearTeamIndexRow, linearUserIndexRow, } from './queries.js';
57
+ const LINEAR_PROVIDER_NAME = 'linear';
58
+ const JSON_CONTENT_TYPE = EMIT_AUXILIARY_JSON_CONTENT_TYPE;
59
+ const ISSUES_SCOPE = `${LINEAR_PATH_ROOT}/issues`;
60
+ /**
61
+ * Phase-2 entry point. Cloud's Phase-3 dispatcher iterates
62
+ * `(provider, records)` and calls this with a shimmed
63
+ * `AuxiliaryEmitterClient`.
64
+ */
65
+ export async function emitLinearAuxiliaryFiles(client, input) {
66
+ const workspaceId = input.workspaceId;
67
+ const aggregate = { written: 0, deleted: 0, errors: [] };
68
+ const issues = input.issues ?? [];
69
+ const comments = input.comments ?? [];
70
+ const users = input.users ?? [];
71
+ const teams = input.teams ?? [];
72
+ const projects = input.projects ?? [];
73
+ const cycles = input.cycles ?? [];
74
+ const milestones = input.milestones ?? [];
75
+ const roadmaps = input.roadmaps ?? [];
76
+ if (issues.length === 0 &&
77
+ comments.length === 0 &&
78
+ users.length === 0 &&
79
+ teams.length === 0 &&
80
+ projects.length === 0 &&
81
+ cycles.length === 0 &&
82
+ milestones.length === 0 &&
83
+ roadmaps.length === 0) {
84
+ return aggregate;
85
+ }
86
+ if (issues.length > 0) {
87
+ accumulate(aggregate, await emitIssues(client, workspaceId, issues, input.connectionId));
88
+ }
89
+ if (comments.length > 0) {
90
+ accumulate(aggregate, await emitComments(client, workspaceId, comments, input.connectionId));
91
+ }
92
+ if (users.length > 0) {
93
+ accumulate(aggregate, await emitUsers(client, workspaceId, users, input.connectionId));
94
+ }
95
+ if (teams.length > 0) {
96
+ accumulate(aggregate, await emitTeams(client, workspaceId, teams, input.connectionId));
97
+ }
98
+ if (projects.length > 0) {
99
+ accumulate(aggregate, await emitProjects(client, workspaceId, projects, input.connectionId));
100
+ }
101
+ if (cycles.length > 0) {
102
+ accumulate(aggregate, await emitCycles(client, workspaceId, cycles, input.connectionId));
103
+ }
104
+ if (milestones.length > 0) {
105
+ accumulate(aggregate, await emitMilestones(client, workspaceId, milestones, input.connectionId));
106
+ }
107
+ if (roadmaps.length > 0) {
108
+ accumulate(aggregate, await emitRoadmaps(client, workspaceId, roadmaps, input.connectionId));
109
+ }
110
+ return aggregate;
111
+ }
112
+ // -- issues -----------------------------------------------------------------
113
+ async function emitIssues(client, workspaceId, records, connectionId) {
114
+ const indexReconciler = new IndexFileReconciler({
115
+ client,
116
+ workspaceId,
117
+ path: linearIssuesIndexPath(),
118
+ builder: (rows) => ({
119
+ path: linearIssuesIndexPath(),
120
+ content: `${JSON.stringify([...rows].sort(compareIndexRows))}\n`,
121
+ contentType: JSON_CONTENT_TYPE,
122
+ }),
123
+ });
124
+ const priorReader = new PriorAliasReader(client, workspaceId);
125
+ const fanOut = await runEmitBatch(client, workspaceId, records, async (record) => {
126
+ if (isDeleteRecord(record)) {
127
+ return planIssueDelete(record.id, priorReader, indexReconciler);
128
+ }
129
+ return planIssueWrite(record, priorReader, indexReconciler, connectionId);
130
+ });
131
+ const indexResult = await indexReconciler.flush();
132
+ fanOut.written += indexResult.written;
133
+ fanOut.errors.push(...indexResult.errors);
134
+ return fanOut;
135
+ }
136
+ async function planIssueWrite(issue, priorReader, indexReconciler, connectionId) {
137
+ const id = readNonEmptyString(issue.id);
138
+ if (!id) {
139
+ return {};
140
+ }
141
+ const identifier = readNonEmptyString(issue.identifier);
142
+ const title = readNonEmptyString(issue.title);
143
+ const stateName = readIssueStateName(issue);
144
+ const content = renderContent('issue', issue, connectionId, false);
145
+ const newPaths = issuePathsFor({ id, identifier, title, stateName });
146
+ // Reconciliation: the by-uuid alias is the stable anchor — it's always
147
+ // emitted (keyed on the UUID, which is always present) so a prior write
148
+ // is guaranteed to have produced it. This resolves the
149
+ // identifier-transition gap CodeRabbit caught: an issue going from
150
+ // identifier-less to identifier-bearing previously left a stale
151
+ // UUID-keyed by-id alias behind because the fallback in this lookup
152
+ // recomputed the new identifier-keyed path.
153
+ const prior = await priorReader.read(linearByUuidAliasPath(ISSUES_SCOPE, id), extractPriorIssueState);
154
+ const stalePaths = prior
155
+ ? diffPaths(issuePathsFor({
156
+ id,
157
+ // IMPORTANT: do NOT fall back to the current identifier here. If
158
+ // the prior payload had no identifier, the prior by-id alias was
159
+ // never written (we only emit by-id when identifier is present),
160
+ // so there's nothing stale to clean up on that path. Passing the
161
+ // current identifier would synthesize a phantom prior path.
162
+ identifier: prior.identifier,
163
+ title: prior.title,
164
+ stateName: prior.stateName,
165
+ }), newPaths)
166
+ : [];
167
+ const writes = newPaths.map((path) => ({
168
+ path,
169
+ content,
170
+ contentType: JSON_CONTENT_TYPE,
171
+ }));
172
+ const deletes = stalePaths.map((path) => ({ path }));
173
+ indexReconciler.upsert(linearIssueIndexRow(toIssueNode(issue)));
174
+ return { writes, deletes };
175
+ }
176
+ async function planIssueDelete(id, priorReader, indexReconciler) {
177
+ // Bare tombstones carry only the UUID, so we read the by-uuid alias —
178
+ // the stable anchor keyed on `issue.id`, always written alongside every
179
+ // prior issue emit. This is the fix for the Devin finding: the previous
180
+ // implementation read `linearByIdAliasPath(scope, id)` (UUID), but
181
+ // `issuePathsFor` writes by-id keyed on the identifier (e.g. AGE-8),
182
+ // not the UUID, so the lookup never matched and no alias paths got
183
+ // computed → none of the 4 stale files got deleted on tombstone.
184
+ const prior = (await priorReader.read(linearByUuidAliasPath(ISSUES_SCOPE, id), extractPriorIssueState)) ?? null;
185
+ const paths = issuePathsFor({
186
+ id,
187
+ identifier: prior?.identifier,
188
+ title: prior?.title,
189
+ stateName: prior?.stateName,
190
+ });
191
+ // See planPageDelete in the confluence port — index row must drop too.
192
+ indexReconciler.remove(id);
193
+ return { deletes: paths.map((path) => ({ path })) };
194
+ }
195
+ function extractPriorIssueState(parsed) {
196
+ const payload = pickPayload(parsed);
197
+ if (!payload)
198
+ return null;
199
+ return {
200
+ identifier: readNonEmptyString(payload.identifier),
201
+ title: readNonEmptyString(payload.title),
202
+ stateName: readPriorStateName(payload),
203
+ };
204
+ }
205
+ function readPriorStateName(payload) {
206
+ const stateRecord = isRecord(payload.state) ? payload.state : undefined;
207
+ return (readNonEmptyString(stateRecord?.name) ??
208
+ readNonEmptyString(payload.state_name) ??
209
+ readNonEmptyString(payload.state_type));
210
+ }
211
+ function issuePathsFor(args) {
212
+ const { id, identifier, title, stateName } = args;
213
+ const humanReadable = identifier ?? title;
214
+ const paths = [];
215
+ // Canonical path.
216
+ paths.push(linearIssuePath(id, humanReadable));
217
+ // by-uuid alias — the stable reconciliation anchor, always emitted.
218
+ // Keyed on the Linear UUID (`issue.id`), which is always present even on
219
+ // bare delete tombstones. Subsequent emits read prior state from this
220
+ // path to discover the previous identifier/title/state.
221
+ paths.push(linearByUuidAliasPath(ISSUES_SCOPE, id));
222
+ // by-id alias — human-readable lookup keyed on the Linear identifier
223
+ // (e.g. `TEAM-123`). Only emitted when the identifier is present, so we
224
+ // don't pollute `/linear/issues/by-id/` with UUID-keyed entries that
225
+ // duplicate the by-uuid subtree.
226
+ if (identifier) {
227
+ paths.push(linearByIdAliasPath(ISSUES_SCOPE, identifier));
228
+ }
229
+ // by-title alias — skip when title slugs to empty (`slugifyAlias` returns
230
+ // the literal `'untitled'` sentinel in that case).
231
+ if (title && slugifies(title)) {
232
+ paths.push(linearByTitleAliasPath(ISSUES_SCOPE, title, id));
233
+ }
234
+ // by-state alias — only when both state and identifier are present, since
235
+ // the alias filename is the identifier (Linear's `slugifyStateName`
236
+ // helper throws on empty input).
237
+ if (stateName && identifier) {
238
+ paths.push(linearIssueByStatePath(stateName, identifier));
239
+ }
240
+ return paths;
241
+ }
242
+ function readIssueStateName(issue) {
243
+ return readNonEmptyString(issue.state?.name);
244
+ }
245
+ function toIssueNode(issue) {
246
+ return {
247
+ id: issue.id,
248
+ identifier: issue.identifier ?? null,
249
+ title: issue.title ?? null,
250
+ state: issue.state
251
+ ? { name: issue.state.name ?? null, type: issue.state.type ?? null }
252
+ : null,
253
+ updatedAt: issue.updatedAt ?? null,
254
+ createdAt: issue.createdAt ?? null,
255
+ };
256
+ }
257
+ // -- comments ---------------------------------------------------------------
258
+ async function emitComments(client, workspaceId, records, connectionId) {
259
+ const indexReconciler = new IndexFileReconciler({
260
+ client,
261
+ workspaceId,
262
+ path: linearCommentsIndexPath(),
263
+ builder: (rows) => ({
264
+ path: linearCommentsIndexPath(),
265
+ content: `${JSON.stringify([...rows].sort(compareIndexRows))}\n`,
266
+ contentType: JSON_CONTENT_TYPE,
267
+ }),
268
+ });
269
+ const fanOut = await runEmitBatch(client, workspaceId, records, async (record) => {
270
+ if (isDeleteRecord(record)) {
271
+ indexReconciler.remove(record.id);
272
+ return { deletes: [{ path: linearCommentPath(record.id) }] };
273
+ }
274
+ const id = readNonEmptyString(record.id);
275
+ if (!id)
276
+ return {};
277
+ const humanReadable = readNonEmptyString(record.issue?.identifier) ?? readNonEmptyString(record.body ?? undefined);
278
+ const path = linearCommentPath(id, humanReadable);
279
+ indexReconciler.upsert(linearCommentIndexRow(toCommentNode(record)));
280
+ return {
281
+ writes: [
282
+ {
283
+ path,
284
+ content: renderContent('comment', record, connectionId, false),
285
+ contentType: JSON_CONTENT_TYPE,
286
+ },
287
+ ],
288
+ };
289
+ });
290
+ const indexResult = await indexReconciler.flush();
291
+ fanOut.written += indexResult.written;
292
+ fanOut.errors.push(...indexResult.errors);
293
+ return fanOut;
294
+ }
295
+ function toCommentNode(comment) {
296
+ return {
297
+ id: comment.id,
298
+ body: comment.body ?? null,
299
+ issue: comment.issue
300
+ ? {
301
+ id: comment.issue.id ?? null,
302
+ identifier: comment.issue.identifier ?? null,
303
+ title: comment.issue.title ?? null,
304
+ url: comment.issue.url ?? null,
305
+ }
306
+ : null,
307
+ updatedAt: comment.updatedAt ?? null,
308
+ createdAt: comment.createdAt ?? null,
309
+ };
310
+ }
311
+ // -- users / teams / projects / cycles / milestones / roadmaps -------------
312
+ async function emitUsers(client, workspaceId, records, connectionId) {
313
+ return emitFlatResource(client, workspaceId, records, {
314
+ indexPath: linearUsersIndexPath(),
315
+ canonicalPath: (id) => linearUserPath(id),
316
+ indexRow: (record) => linearUserIndexRow(record),
317
+ objectType: 'user',
318
+ connectionId,
319
+ });
320
+ }
321
+ async function emitTeams(client, workspaceId, records, connectionId) {
322
+ return emitFlatResource(client, workspaceId, records, {
323
+ indexPath: linearTeamsIndexPath(),
324
+ canonicalPath: (id) => linearTeamPath(id),
325
+ indexRow: (record) => linearTeamIndexRow(record),
326
+ objectType: 'team',
327
+ connectionId,
328
+ });
329
+ }
330
+ async function emitProjects(client, workspaceId, records, connectionId) {
331
+ // Projects don't ship an `_index.json` in the current adapter (no
332
+ // index-emitter bucket), so we only emit the canonical record.
333
+ return emitCanonicalOnlyResource(client, workspaceId, records, {
334
+ canonicalPath: (id) => linearProjectPath(id),
335
+ objectType: 'project',
336
+ connectionId,
337
+ });
338
+ }
339
+ async function emitCycles(client, workspaceId, records, connectionId) {
340
+ return emitCanonicalOnlyResource(client, workspaceId, records, {
341
+ canonicalPath: (id) => linearCyclePath(id),
342
+ objectType: 'cycle',
343
+ connectionId,
344
+ });
345
+ }
346
+ async function emitMilestones(client, workspaceId, records, connectionId) {
347
+ return emitCanonicalOnlyResource(client, workspaceId, records, {
348
+ canonicalPath: (id) => linearMilestonePath(id),
349
+ objectType: 'milestone',
350
+ connectionId,
351
+ });
352
+ }
353
+ async function emitRoadmaps(client, workspaceId, records, connectionId) {
354
+ return emitCanonicalOnlyResource(client, workspaceId, records, {
355
+ canonicalPath: (id) => linearRoadmapPath(id),
356
+ objectType: 'roadmap',
357
+ connectionId,
358
+ });
359
+ }
360
+ async function emitFlatResource(client, workspaceId, records, opts) {
361
+ const indexReconciler = new IndexFileReconciler({
362
+ client,
363
+ workspaceId,
364
+ path: opts.indexPath,
365
+ builder: (rows) => ({
366
+ path: opts.indexPath,
367
+ content: `${JSON.stringify([...rows].sort(compareIndexRows))}\n`,
368
+ contentType: JSON_CONTENT_TYPE,
369
+ }),
370
+ });
371
+ const fanOut = await runEmitBatch(client, workspaceId, records, async (record) => {
372
+ if (isDeleteRecord(record)) {
373
+ indexReconciler.remove(record.id);
374
+ return { deletes: [{ path: opts.canonicalPath(record.id) }] };
375
+ }
376
+ const id = readNonEmptyString(record.id);
377
+ if (!id)
378
+ return {};
379
+ indexReconciler.upsert(opts.indexRow(record));
380
+ return {
381
+ writes: [
382
+ {
383
+ path: opts.canonicalPath(id),
384
+ content: renderContent(opts.objectType, record, opts.connectionId, false),
385
+ contentType: JSON_CONTENT_TYPE,
386
+ },
387
+ ],
388
+ };
389
+ });
390
+ const indexResult = await indexReconciler.flush();
391
+ fanOut.written += indexResult.written;
392
+ fanOut.errors.push(...indexResult.errors);
393
+ return fanOut;
394
+ }
395
+ async function emitCanonicalOnlyResource(client, workspaceId, records, opts) {
396
+ return runEmitBatch(client, workspaceId, records, async (record) => {
397
+ if (isDeleteRecord(record)) {
398
+ return { deletes: [{ path: opts.canonicalPath(record.id) }] };
399
+ }
400
+ const id = readNonEmptyString(record.id);
401
+ if (!id)
402
+ return {};
403
+ return {
404
+ writes: [
405
+ {
406
+ path: opts.canonicalPath(id),
407
+ content: renderContent(opts.objectType, record, opts.connectionId, false),
408
+ contentType: JSON_CONTENT_TYPE,
409
+ },
410
+ ],
411
+ };
412
+ });
413
+ }
414
+ // -- shared helpers ---------------------------------------------------------
415
+ function renderContent(objectType, payload, connectionId, deleted) {
416
+ return JSON.stringify({
417
+ provider: LINEAR_PROVIDER_NAME,
418
+ objectType,
419
+ objectId: payload.id,
420
+ deleted,
421
+ payload,
422
+ ...(connectionId ? { connectionId } : {}),
423
+ }, null, 2);
424
+ }
425
+ function compareIndexRows(left, right) {
426
+ if (left.updated !== right.updated) {
427
+ return right.updated.localeCompare(left.updated);
428
+ }
429
+ return left.id.localeCompare(right.id);
430
+ }
431
+ function diffPaths(prior, next) {
432
+ const nextSet = new Set(next);
433
+ const seen = new Set();
434
+ const stale = [];
435
+ for (const p of prior) {
436
+ if (!nextSet.has(p) && !seen.has(p)) {
437
+ seen.add(p);
438
+ stale.push(p);
439
+ }
440
+ }
441
+ return stale;
442
+ }
443
+ function pickPayload(parsed) {
444
+ const wrapped = parsed.payload;
445
+ if (isRecord(wrapped)) {
446
+ return wrapped;
447
+ }
448
+ return parsed;
449
+ }
450
+ function isDeleteRecord(record) {
451
+ return (isRecord(record) &&
452
+ record._deleted === true &&
453
+ typeof record.id === 'string');
454
+ }
455
+ function readNonEmptyString(value) {
456
+ if (typeof value !== 'string')
457
+ return undefined;
458
+ const trimmed = value.trim();
459
+ return trimmed.length > 0 ? trimmed : undefined;
460
+ }
461
+ function isRecord(value) {
462
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
463
+ }
464
+ /**
465
+ * Skip by-title aliases for titles that slug to nothing (emoji-only /
466
+ * punctuation-only). The by-id alias still resolves those records.
467
+ *
468
+ * Delegates to the shared `slugifyAlias` per AGENTS.md "NEVER write a
469
+ * new slugifier" rule. `slugifyAlias` returns the literal string
470
+ * `'untitled'` as its empty-slug sentinel.
471
+ */
472
+ function slugifies(value) {
473
+ return slugifyAlias(value) !== 'untitled';
474
+ }
475
+ function accumulate(aggregate, partial) {
476
+ aggregate.written += partial.written;
477
+ aggregate.deleted += partial.deleted;
478
+ if (partial.errors.length > 0) {
479
+ aggregate.errors.push(...partial.errors);
480
+ }
481
+ }
482
+ //# sourceMappingURL=emit-auxiliary-files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit-auxiliary-files.js","sourceRoot":"","sources":["../src/emit-auxiliary-files.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -6,5 +6,6 @@ export * from './webhook-normalizer.js';
6
6
  export * from './types.js';
7
7
  export * from './queries.js';
8
8
  export * from './writeback.js';
9
+ export * from './emit-auxiliary-files.js';
9
10
  export * from './resources.js';
10
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAE/B,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,2BAA2B,CAAC;AAE1C,cAAc,gBAAgB,CAAC"}
package/dist/index.js CHANGED
@@ -7,5 +7,6 @@ export * from './webhook-normalizer.js';
7
7
  export * from './types.js';
8
8
  export * from './queries.js';
9
9
  export * from './writeback.js';
10
+ export * from './emit-auxiliary-files.js';
10
11
  export * from './resources.js';
11
12
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAE/B,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,2BAA2B,CAAC;AAE1C,cAAc,gBAAgB,CAAC"}
@@ -1,4 +1,4 @@
1
- export declare const LINEAR_LAYOUT_PROMPT = "# Linear Mount Layout\n\nAlways run `ls` before constructing a path. PR 0 standardizes human-readable leaf names to `<sanitized-name>__<id>`, so consumers should inspect the live directory instead of guessing a filename.\n\n## Tree\n\n`/linear/LAYOUT.md` is this guide.\n`/linear/issues/`, `/linear/comments/`, `/linear/users/`, and `/linear/teams/` each own their canonical JSON records plus a sibling `_index.json`.\nOther integration-owned trees include `/linear/projects/`, `/linear/cycles/`, `/linear/milestones/`, and `/linear/roadmaps/`.\n\n## Indexes\n\n`/linear/issues/_index.json` rows use:\n\n```json\n{ \"id\": \"<id>\", \"title\": \"<human-readable>\", \"updated\": \"<iso8601>\", \"identifier\": \"<TEAM-123>\", \"state\": \"<state name>\" }\n```\n\n`/linear/comments/_index.json`, `/linear/users/_index.json`, and `/linear/teams/_index.json` use:\n\n```json\n{ \"id\": \"<id>\", \"title\": \"<human-readable>\", \"updated\": \"<iso8601>\" }\n```\n\n## JSONL And Querying\n\nLinear does not emit JSONL in this adapter today. Comments are individual `.json` records rather than `comments.jsonl`.\n\nExamples:\n\n```bash\nls /linear/issues\njq '.[0]' /linear/issues/_index.json\njq '.[] | {identifier, state, title}' /linear/issues/_index.json\ngrep -R \"ENG-\" /linear/comments\n```\n";
1
+ export declare const LINEAR_LAYOUT_PROMPT = "# Linear Mount Layout\n\nAlways run `ls` before constructing a path. PR 0 standardizes human-readable leaf names to `<sanitized-name>__<id>`, so consumers should inspect the live directory instead of guessing a filename.\n\n## Tree\n\n`/linear/LAYOUT.md` is this guide.\n`/linear/issues/`, `/linear/comments/`, `/linear/users/`, and `/linear/teams/` each own their canonical JSON records plus a sibling `_index.json`.\nOther integration-owned trees include `/linear/projects/`, `/linear/cycles/`, `/linear/milestones/`, and `/linear/roadmaps/`.\n\nIssue lookups: `/linear/issues/by-uuid/<uuid>.json` is the stable anchor (always emitted, keyed on the Linear UUID). `/linear/issues/by-id/<TEAM-123>.json` is the human-readable lookup keyed on the Linear identifier (only emitted when the issue has one). `/linear/issues/by-title/<slug>.json` and `/linear/issues/by-state/<state>/<TEAM-123>.json` are additional lookups.\n\n## Indexes\n\n`/linear/issues/_index.json` rows use:\n\n```json\n{ \"id\": \"<id>\", \"title\": \"<human-readable>\", \"updated\": \"<iso8601>\", \"identifier\": \"<TEAM-123>\", \"state\": \"<state name>\" }\n```\n\n`/linear/comments/_index.json`, `/linear/users/_index.json`, and `/linear/teams/_index.json` use:\n\n```json\n{ \"id\": \"<id>\", \"title\": \"<human-readable>\", \"updated\": \"<iso8601>\" }\n```\n\n## JSONL And Querying\n\nLinear does not emit JSONL in this adapter today. Comments are individual `.json` records rather than `comments.jsonl`.\n\nExamples:\n\n```bash\nls /linear/issues\njq '.[0]' /linear/issues/_index.json\njq '.[] | {identifier, state, title}' /linear/issues/_index.json\ngrep -R \"ENG-\" /linear/comments\n```\n";
2
2
  export declare function linearLayoutPromptFile(): {
3
3
  path: string;
4
4
  contentType: "text/markdown; charset=utf-8";
@@ -1 +1 @@
1
- {"version":3,"file":"layout-prompt.d.ts","sourceRoot":"","sources":["../src/layout-prompt.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,oBAAoB,sxCAoChC,CAAC;AAEF,wBAAgB,sBAAsB;;;;EAMrC"}
1
+ {"version":3,"file":"layout-prompt.d.ts","sourceRoot":"","sources":["../src/layout-prompt.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,oBAAoB,4oDAsChC,CAAC;AAEF,wBAAgB,sBAAsB;;;;EAMrC"}
@@ -8,6 +8,8 @@ Always run \`ls\` before constructing a path. PR 0 standardizes human-readable l
8
8
  \`/linear/issues/\`, \`/linear/comments/\`, \`/linear/users/\`, and \`/linear/teams/\` each own their canonical JSON records plus a sibling \`_index.json\`.
9
9
  Other integration-owned trees include \`/linear/projects/\`, \`/linear/cycles/\`, \`/linear/milestones/\`, and \`/linear/roadmaps/\`.
10
10
 
11
+ Issue lookups: \`/linear/issues/by-uuid/<uuid>.json\` is the stable anchor (always emitted, keyed on the Linear UUID). \`/linear/issues/by-id/<TEAM-123>.json\` is the human-readable lookup keyed on the Linear identifier (only emitted when the issue has one). \`/linear/issues/by-title/<slug>.json\` and \`/linear/issues/by-state/<state>/<TEAM-123>.json\` are additional lookups.
12
+
11
13
  ## Indexes
12
14
 
13
15
  \`/linear/issues/_index.json\` rows use:
@@ -1 +1 @@
1
- {"version":3,"file":"layout-prompt.js","sourceRoot":"","sources":["../src/layout-prompt.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoCnC,CAAC;AAEF,MAAM,UAAU,sBAAsB;IACpC,OAAO;QACL,IAAI,EAAE,mBAAmB;QACzB,WAAW,EAAE,8BAAuC;QACpD,OAAO,EAAE,oBAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,GAAG,oBAAoB,IAAI;KAClG,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"layout-prompt.js","sourceRoot":"","sources":["../src/layout-prompt.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsCnC,CAAC;AAEF,MAAM,UAAU,sBAAsB;IACpC,OAAO;QACL,IAAI,EAAE,mBAAmB;QACzB,WAAW,EAAE,8BAAuC;QACpD,OAAO,EAAE,oBAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,GAAG,oBAAoB,IAAI;KAClG,CAAC;AACJ,CAAC"}
@@ -32,5 +32,16 @@ export declare function linearMilestonePath(milestoneId: string): string;
32
32
  export declare function linearRoadmapPath(roadmapId: string): string;
33
33
  export declare function linearByTitleAliasPath(scope: string, title: string, id: string, colliding?: boolean): string;
34
34
  export declare function linearByIdAliasPath(scope: string, identifier: string): string;
35
+ /**
36
+ * Stable UUID-keyed alias for Linear records. Used as the reconciliation
37
+ * anchor when computing prior state, because the Linear UUID (`issue.id`)
38
+ * is always present even on bare delete tombstones, whereas the human-readable
39
+ * `identifier` (e.g. `TEAM-123`) may be missing on partial payloads or on
40
+ * issues that were created without one. The existing `linearByIdAliasPath`
41
+ * remains the human-readable lookup alias keyed on `identifier` when
42
+ * available — both are emitted side-by-side for issues so consumers can
43
+ * resolve a record by either key.
44
+ */
45
+ export declare function linearByUuidAliasPath(scope: string, uuid: string): string;
35
46
  export declare function computeLinearPath(objectType: string, objectId: string, humanReadable?: string): string;
36
47
  //# sourceMappingURL=path-mapper.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"path-mapper.d.ts","sourceRoot":"","sources":["../src/path-mapper.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAC1C,eAAO,MAAM,uBAAuB,iEAAkE,CAAC;AAEvG,eAAO,MAAM,mBAAmB,2FAStB,CAAC;AAEX,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AAExE,MAAM,WAAW,iBAAiB;IAChC,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC7B;AAID,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB;AAmED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE7D;AAuCD,wBAAgB,UAAU,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,GAAE,iBAAsB,GAAG,MAAM,CAa9G;AAGD,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,qBAAqB,CAmBvE;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAmC1D;AAED,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,GAAG,oBAAoB,CAOlF;AAED,wBAAgB,4BAA4B,CAAC,UAAU,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS,CAMjG;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,oBAAoB,CAI7E;AAED,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,yBAAyB,CAAC,EAAE,MAAM,EAClC,KAAK,CAAC,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,iBAAiB,GACvB,MAAM,CAGR;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAEpF;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAE7G;AAED,wBAAgB,uBAAuB,IAAI,MAAM,CAEhD;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,UAAQ,GAAG,MAAM,CAS1G;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAE7E;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAsBtG"}
1
+ {"version":3,"file":"path-mapper.d.ts","sourceRoot":"","sources":["../src/path-mapper.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAC1C,eAAO,MAAM,uBAAuB,iEAAkE,CAAC;AAEvG,eAAO,MAAM,mBAAmB,2FAStB,CAAC;AAEX,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AAExE,MAAM,WAAW,iBAAiB;IAChC,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC7B;AAID,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB;AAmED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE7D;AAuCD,wBAAgB,UAAU,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,GAAE,iBAAsB,GAAG,MAAM,CAa9G;AAGD,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,qBAAqB,CAmBvE;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAmC1D;AAED,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,GAAG,oBAAoB,CAOlF;AAED,wBAAgB,4BAA4B,CAAC,UAAU,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS,CAMjG;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,oBAAoB,CAI7E;AAED,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,yBAAyB,CAAC,EAAE,MAAM,EAClC,KAAK,CAAC,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,iBAAiB,GACvB,MAAM,CAGR;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAEpF;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAE7G;AAED,wBAAgB,uBAAuB,IAAI,MAAM,CAEhD;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,UAAQ,GAAG,MAAM,CAS1G;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAE7E;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzE;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAsBtG"}
@@ -243,6 +243,19 @@ export function linearByTitleAliasPath(scope, title, id, colliding = false) {
243
243
  export function linearByIdAliasPath(scope, identifier) {
244
244
  return `${scope}/by-id/${encodeLinearPathSegment(identifier)}.json`;
245
245
  }
246
+ /**
247
+ * Stable UUID-keyed alias for Linear records. Used as the reconciliation
248
+ * anchor when computing prior state, because the Linear UUID (`issue.id`)
249
+ * is always present even on bare delete tombstones, whereas the human-readable
250
+ * `identifier` (e.g. `TEAM-123`) may be missing on partial payloads or on
251
+ * issues that were created without one. The existing `linearByIdAliasPath`
252
+ * remains the human-readable lookup alias keyed on `identifier` when
253
+ * available — both are emitted side-by-side for issues so consumers can
254
+ * resolve a record by either key.
255
+ */
256
+ export function linearByUuidAliasPath(scope, uuid) {
257
+ return `${scope}/by-uuid/${encodeLinearPathSegment(uuid)}.json`;
258
+ }
246
259
  export function computeLinearPath(objectType, objectId, humanReadable) {
247
260
  const normalizedType = normalizeLinearObjectType(objectType);
248
261
  const normalizedId = assertNonEmptySegment(objectId, 'object id');