@relayfile/adapter-linear 0.3.12 → 0.3.15

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 (58) hide show
  1. package/discovery/linear/.adapter.md +62 -1
  2. package/discovery/linear/projects/.create.example.json +6 -0
  3. package/discovery/linear/projects/.schema.json +147 -0
  4. package/discovery/linear/projects/{projectId}/add-issues.json/.create.example.json +5 -0
  5. package/discovery/linear/projects/{projectId}/add-issues.json/.schema.json +88 -0
  6. package/discovery/linear/projects/{projectId}/meta.json/.create.example.json +3 -0
  7. package/discovery/linear/projects/{projectId}/meta.json/.schema.json +121 -0
  8. package/dist/__tests__/aliases.test.js +8 -8
  9. package/dist/__tests__/aliases.test.js.map +1 -1
  10. package/dist/__tests__/emit-auxiliary-files.test.js +144 -9
  11. package/dist/__tests__/emit-auxiliary-files.test.js.map +1 -1
  12. package/dist/__tests__/index-emission.test.js +16 -4
  13. package/dist/__tests__/index-emission.test.js.map +1 -1
  14. package/dist/__tests__/linear-adapter.test.js +7 -7
  15. package/dist/__tests__/linear-adapter.test.js.map +1 -1
  16. package/dist/__tests__/path-mapper.test.js +12 -1
  17. package/dist/__tests__/path-mapper.test.js.map +1 -1
  18. package/dist/emit-auxiliary-files.d.ts +16 -7
  19. package/dist/emit-auxiliary-files.d.ts.map +1 -1
  20. package/dist/emit-auxiliary-files.js +113 -13
  21. package/dist/emit-auxiliary-files.js.map +1 -1
  22. package/dist/index-emitter.d.ts +2 -1
  23. package/dist/index-emitter.d.ts.map +1 -1
  24. package/dist/index-emitter.js +4 -1
  25. package/dist/index-emitter.js.map +1 -1
  26. package/dist/layout-prompt.d.ts +1 -1
  27. package/dist/layout-prompt.d.ts.map +1 -1
  28. package/dist/layout-prompt.js +13 -3
  29. package/dist/layout-prompt.js.map +1 -1
  30. package/dist/layout.d.ts.map +1 -1
  31. package/dist/layout.js +15 -3
  32. package/dist/layout.js.map +1 -1
  33. package/dist/layout.test.js +3 -0
  34. package/dist/layout.test.js.map +1 -1
  35. package/dist/linear-adapter.d.ts.map +1 -1
  36. package/dist/linear-adapter.js +58 -9
  37. package/dist/linear-adapter.js.map +1 -1
  38. package/dist/path-mapper.d.ts +15 -1
  39. package/dist/path-mapper.d.ts.map +1 -1
  40. package/dist/path-mapper.js +39 -0
  41. package/dist/path-mapper.js.map +1 -1
  42. package/dist/queries.d.ts +15 -7
  43. package/dist/queries.d.ts.map +1 -1
  44. package/dist/queries.js +14 -0
  45. package/dist/queries.js.map +1 -1
  46. package/dist/resources.d.ts +21 -0
  47. package/dist/resources.d.ts.map +1 -1
  48. package/dist/resources.js +24 -0
  49. package/dist/resources.js.map +1 -1
  50. package/dist/types.d.ts +34 -8
  51. package/dist/types.d.ts.map +1 -1
  52. package/dist/writeback.d.ts +4 -1
  53. package/dist/writeback.d.ts.map +1 -1
  54. package/dist/writeback.js +145 -6
  55. package/dist/writeback.js.map +1 -1
  56. package/dist/writeback.test.js +122 -5
  57. package/dist/writeback.test.js.map +1 -1
  58. package/package.json +2 -2
@@ -1,4 +1,4 @@
1
- import { linearCyclesIndexPath, linearCommentsIndexPath, linearIssuesIndexPath, linearMilestonesIndexPath, linearProjectsIndexPath, linearRootIndexPath, linearRoadmapsIndexPath, linearTeamsIndexPath, linearUsersIndexPath, } from './path-mapper.js';
1
+ import { linearCyclesIndexPath, linearCommentsIndexPath, linearIssuesIndexPath, linearMilestonesIndexPath, linearProjectsIndexPath, linearRootIndexPath, linearRoadmapsIndexPath, linearStatesIndexPath, linearTeamsIndexPath, linearUsersIndexPath, } from './path-mapper.js';
2
2
  /**
3
3
  * Build `/linear/_index.json` — a static listing of top-level resource
4
4
  * roots the Linear adapter exposes. Mirrors the slack pattern so an agent
@@ -10,6 +10,7 @@ export function buildLinearRootIndexFile(rows = [
10
10
  { id: 'teams', title: 'Teams' },
11
11
  { id: 'users', title: 'Users' },
12
12
  { id: 'projects', title: 'Projects' },
13
+ { id: 'states', title: 'Workflow States' },
13
14
  { id: 'cycles', title: 'Cycles' },
14
15
  { id: 'milestones', title: 'Milestones' },
15
16
  { id: 'roadmaps', title: 'Roadmaps' },
@@ -40,6 +41,8 @@ function indexPathForBucket(bucket) {
40
41
  return linearMilestonesIndexPath();
41
42
  case 'projects':
42
43
  return linearProjectsIndexPath();
44
+ case 'states':
45
+ return linearStatesIndexPath();
43
46
  case 'roadmaps':
44
47
  return linearRoadmapsIndexPath();
45
48
  case 'users':
@@ -1 +1 @@
1
- {"version":3,"file":"index-emitter.js","sourceRoot":"","sources":["../src/index-emitter.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,qBAAqB,EACrB,yBAAyB,EACzB,uBAAuB,EACvB,mBAAmB,EACnB,uBAAuB,EACvB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAwB1B;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CACtC,OAA6B;IAC3B,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE;IACjC,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE;IACrC,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE;IAC/B,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE;IAC/B,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE;IACrC,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE;IACjC,EAAE,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE;IACzC,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE;CACtC;IAED,OAAO;QACL,IAAI,EAAE,mBAAmB,EAAE;QAC3B,WAAW,EAAE,iCAAiC;QAC9C,OAAO,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI;KACrC,CAAC;AACJ,CAAC;AAUD,MAAM,UAAU,oBAAoB,CAClC,MAAyB,EACzB,IAAqD;IAErD,MAAM,UAAU,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC;IAC5D,OAAO;QACL,IAAI,EAAE,kBAAkB,CAAC,MAAM,CAAC;QAChC,WAAW,EAAE,iCAAiC;QAC9C,OAAO,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI;KAC3C,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CAAC,MAAyB;IACnD,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,QAAQ;YACX,OAAO,qBAAqB,EAAE,CAAC;QACjC,KAAK,UAAU;YACb,OAAO,uBAAuB,EAAE,CAAC;QACnC,KAAK,QAAQ;YACX,OAAO,qBAAqB,EAAE,CAAC;QACjC,KAAK,YAAY;YACf,OAAO,yBAAyB,EAAE,CAAC;QACrC,KAAK,UAAU;YACb,OAAO,uBAAuB,EAAE,CAAC;QACnC,KAAK,UAAU;YACb,OAAO,uBAAuB,EAAE,CAAC;QACnC,KAAK,OAAO;YACV,OAAO,oBAAoB,EAAE,CAAC;QAChC,KAAK,OAAO;YACV,OAAO,oBAAoB,EAAE,CAAC;IAClC,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,MAAyB;IACjD,OAAO,CAAC,IAA8C,EAAE,KAA+C,EAAU,EAAE;QACjH,IAAI,IAAI,CAAC,OAAO,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;YACnC,OAAO,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACnD,CAAC;QACD,OAAO,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACzC,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"index-emitter.js","sourceRoot":"","sources":["../src/index-emitter.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,qBAAqB,EACrB,yBAAyB,EACzB,uBAAuB,EACvB,mBAAmB,EACnB,uBAAuB,EACvB,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAyB1B;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CACtC,OAA6B;IAC3B,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE;IACjC,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE;IACrC,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE;IAC/B,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE;IAC/B,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE;IACrC,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,iBAAiB,EAAE;IAC1C,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE;IACjC,EAAE,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE;IACzC,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE;CACtC;IAED,OAAO;QACL,IAAI,EAAE,mBAAmB,EAAE;QAC3B,WAAW,EAAE,iCAAiC;QAC9C,OAAO,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI;KACrC,CAAC;AACJ,CAAC;AAcD,MAAM,UAAU,oBAAoB,CAClC,MAAyB,EACzB,IAAqD;IAErD,MAAM,UAAU,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC;IAC5D,OAAO;QACL,IAAI,EAAE,kBAAkB,CAAC,MAAM,CAAC;QAChC,WAAW,EAAE,iCAAiC;QAC9C,OAAO,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI;KAC3C,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CAAC,MAAyB;IACnD,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,QAAQ;YACX,OAAO,qBAAqB,EAAE,CAAC;QACjC,KAAK,UAAU;YACb,OAAO,uBAAuB,EAAE,CAAC;QACnC,KAAK,QAAQ;YACX,OAAO,qBAAqB,EAAE,CAAC;QACjC,KAAK,YAAY;YACf,OAAO,yBAAyB,EAAE,CAAC;QACrC,KAAK,UAAU;YACb,OAAO,uBAAuB,EAAE,CAAC;QACnC,KAAK,QAAQ;YACX,OAAO,qBAAqB,EAAE,CAAC;QACjC,KAAK,UAAU;YACb,OAAO,uBAAuB,EAAE,CAAC;QACnC,KAAK,OAAO;YACV,OAAO,oBAAoB,EAAE,CAAC;QAChC,KAAK,OAAO;YACV,OAAO,oBAAoB,EAAE,CAAC;IAClC,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,MAAyB;IACjD,OAAO,CAAC,IAA8C,EAAE,KAA+C,EAAU,EAAE;QACjH,IAAI,IAAI,CAAC,OAAO,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;YACnC,OAAO,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACnD,CAAC;QACD,OAAO,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACzC,CAAC,CAAC;AACJ,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/`, `/linear/teams/`, `/linear/projects/`, `/linear/cycles/`, `/linear/milestones/`, and `/linear/roadmaps/` each own their canonical JSON records plus a sibling `_index.json`.\n`/linear/comments/<name>__<id>/meta.json` is the canonical comment record (a directory record, so per-comment children such as reactions or threaded replies can nest under `comments/<name>__<id>/` without a file/directory collision).\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`, `/linear/issues/by-state/<state>/<TEAM-123>.json`, `/linear/issues/by-assignee/<user-id>/<TEAM-123>.json`, `/linear/issues/by-creator/<user-id>/<TEAM-123>.json`, `/linear/issues/by-priority/<priority>/<TEAM-123>.json`, and `/linear/issues/by-edited/YYYY-MM-DD/<issue-uuid>.json` are additional lookups. The edited-date bucket is formatted as `YYYY-MM-DD` and uses the first available timestamp in this order: `updatedAt`, `updated_at`, `completedAt`, `canceledAt`, `createdAt`, then `created_at`.\n\nWritable resources advertise sibling schemas and create examples at `discovery/linear/issues/.schema.json`, `discovery/linear/issues/.create.example.json`, `discovery/linear/issues/{issueId}/comments/.schema.json`, and `discovery/linear/issues/{issueId}/comments/.create.example.json`.\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`, `/linear/teams/_index.json`, `/linear/projects/_index.json`, `/linear/cycles/_index.json`, `/linear/milestones/_index.json`, and `/linear/roadmaps/_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 `comments/<name>__<id>/meta.json` directory 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\nls /linear/issues/by-assignee\nls /linear/issues/by-priority\nls /linear/issues/by-edited/2026-05-12\njq '.identifier' /linear/issues/by-edited/2026-05-12/11111111-1111-1111-1111-111111111111.json\njq '.required' discovery/linear/issues/.schema.json\nls discovery/linear/issues/{issueId}/comments\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/`, `/linear/teams/`, `/linear/projects/`, `/linear/states/`, `/linear/cycles/`, `/linear/milestones/`, and `/linear/roadmaps/` each own their canonical JSON records plus a sibling `_index.json`.\n`/linear/comments/<name>__<id>/meta.json` is the canonical comment record (a directory record, so per-comment children such as reactions or threaded replies can nest under `comments/<name>__<id>/` without a file/directory collision).\n`/linear/projects/<uuid>/meta.json` is the canonical project record. The legacy flat `/linear/projects/<uuid>.json` path is not written by current mirrors.\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`, `/linear/issues/by-state/<state>/<TEAM-123>.json`, `/linear/issues/by-assignee/<user-id>/<TEAM-123>.json`, `/linear/issues/by-creator/<user-id>/<TEAM-123>.json`, `/linear/issues/by-priority/<priority>/<TEAM-123>.json`, and `/linear/issues/by-edited/YYYY-MM-DD/<issue-uuid>.json` are additional lookups. The edited-date bucket is formatted as `YYYY-MM-DD` and uses the first available timestamp in this order: `updatedAt`, `updated_at`, `completedAt`, `canceledAt`, `createdAt`, then `created_at`.\n\nProject lookups: `/linear/projects/by-id/<uuid>.json` is the stable project id lookup, `/linear/projects/by-name/<slug>.json` resolves a project by name, `/linear/projects/by-state/<backlog|planned|started|paused|completed|canceled>/<uuid>.json` groups by Linear project state, and `/linear/projects/by-team/<team-uuid>/<project-uuid>.json` is emitted once per team on multi-team projects.\n\nWritable resources advertise sibling schemas and create examples at `discovery/linear/issues/.schema.json`, `discovery/linear/issues/.create.example.json`, `discovery/linear/issues/{issueId}/comments/.schema.json`, `discovery/linear/issues/{issueId}/comments/.create.example.json`, `discovery/linear/projects/.schema.json`, `discovery/linear/projects/.create.example.json`, `discovery/linear/projects/{projectId}/meta.json/.schema.json`, `discovery/linear/projects/{projectId}/meta.json/.create.example.json`, `discovery/linear/projects/{projectId}/add-issues.json/.schema.json`, and `discovery/linear/projects/{projectId}/add-issues.json/.create.example.json`.\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`, `/linear/teams/_index.json`, `/linear/projects/_index.json`, `/linear/states/_index.json`, `/linear/cycles/_index.json`, `/linear/milestones/_index.json`, and `/linear/roadmaps/_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 `comments/<name>__<id>/meta.json` directory 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\nls /linear/issues/by-assignee\nls /linear/issues/by-priority\nls /linear/issues/by-edited/2026-05-12\njq '.identifier' /linear/issues/by-edited/2026-05-12/11111111-1111-1111-1111-111111111111.json\njq '.[0]' /linear/projects/_index.json\nls /linear/projects/by-name\nls /linear/projects/by-state/started\njq '.payload.id' /linear/projects/by-team/22222222-2222-2222-2222-222222222222/11111111-1111-1111-1111-111111111111.json\njq '.[0]' /linear/states/_index.json\njq '.required' discovery/linear/issues/.schema.json\ncat discovery/linear/projects/.create.example.json\ncat discovery/linear/projects/{projectId}/add-issues.json/.create.example.json\nls discovery/linear/issues/{issueId}/comments\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,+9FA8ChC,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,6zIAwDhC,CAAC;AAEF,wBAAgB,sBAAsB;;;;EAMrC"}
@@ -5,12 +5,15 @@ Always run \`ls\` before constructing a path. PR 0 standardizes human-readable l
5
5
  ## Tree
6
6
 
7
7
  \`/linear/LAYOUT.md\` is this guide.
8
- \`/linear/issues/\`, \`/linear/comments/\`, \`/linear/users/\`, \`/linear/teams/\`, \`/linear/projects/\`, \`/linear/cycles/\`, \`/linear/milestones/\`, and \`/linear/roadmaps/\` each own their canonical JSON records plus a sibling \`_index.json\`.
8
+ \`/linear/issues/\`, \`/linear/comments/\`, \`/linear/users/\`, \`/linear/teams/\`, \`/linear/projects/\`, \`/linear/states/\`, \`/linear/cycles/\`, \`/linear/milestones/\`, and \`/linear/roadmaps/\` each own their canonical JSON records plus a sibling \`_index.json\`.
9
9
  \`/linear/comments/<name>__<id>/meta.json\` is the canonical comment record (a directory record, so per-comment children such as reactions or threaded replies can nest under \`comments/<name>__<id>/\` without a file/directory collision).
10
+ \`/linear/projects/<uuid>/meta.json\` is the canonical project record. The legacy flat \`/linear/projects/<uuid>.json\` path is not written by current mirrors.
10
11
 
11
12
  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\`, \`/linear/issues/by-state/<state>/<TEAM-123>.json\`, \`/linear/issues/by-assignee/<user-id>/<TEAM-123>.json\`, \`/linear/issues/by-creator/<user-id>/<TEAM-123>.json\`, \`/linear/issues/by-priority/<priority>/<TEAM-123>.json\`, and \`/linear/issues/by-edited/YYYY-MM-DD/<issue-uuid>.json\` are additional lookups. The edited-date bucket is formatted as \`YYYY-MM-DD\` and uses the first available timestamp in this order: \`updatedAt\`, \`updated_at\`, \`completedAt\`, \`canceledAt\`, \`createdAt\`, then \`created_at\`.
12
13
 
13
- Writable resources advertise sibling schemas and create examples at \`discovery/linear/issues/.schema.json\`, \`discovery/linear/issues/.create.example.json\`, \`discovery/linear/issues/{issueId}/comments/.schema.json\`, and \`discovery/linear/issues/{issueId}/comments/.create.example.json\`.
14
+ Project lookups: \`/linear/projects/by-id/<uuid>.json\` is the stable project id lookup, \`/linear/projects/by-name/<slug>.json\` resolves a project by name, \`/linear/projects/by-state/<backlog|planned|started|paused|completed|canceled>/<uuid>.json\` groups by Linear project state, and \`/linear/projects/by-team/<team-uuid>/<project-uuid>.json\` is emitted once per team on multi-team projects.
15
+
16
+ Writable resources advertise sibling schemas and create examples at \`discovery/linear/issues/.schema.json\`, \`discovery/linear/issues/.create.example.json\`, \`discovery/linear/issues/{issueId}/comments/.schema.json\`, \`discovery/linear/issues/{issueId}/comments/.create.example.json\`, \`discovery/linear/projects/.schema.json\`, \`discovery/linear/projects/.create.example.json\`, \`discovery/linear/projects/{projectId}/meta.json/.schema.json\`, \`discovery/linear/projects/{projectId}/meta.json/.create.example.json\`, \`discovery/linear/projects/{projectId}/add-issues.json/.schema.json\`, and \`discovery/linear/projects/{projectId}/add-issues.json/.create.example.json\`.
14
17
 
15
18
  ## Indexes
16
19
 
@@ -20,7 +23,7 @@ Writable resources advertise sibling schemas and create examples at \`discovery/
20
23
  { "id": "<id>", "title": "<human-readable>", "updated": "<iso8601>", "identifier": "<TEAM-123>", "state": "<state name>" }
21
24
  \`\`\`
22
25
 
23
- \`/linear/comments/_index.json\`, \`/linear/users/_index.json\`, \`/linear/teams/_index.json\`, \`/linear/projects/_index.json\`, \`/linear/cycles/_index.json\`, \`/linear/milestones/_index.json\`, and \`/linear/roadmaps/_index.json\` use:
26
+ \`/linear/comments/_index.json\`, \`/linear/users/_index.json\`, \`/linear/teams/_index.json\`, \`/linear/projects/_index.json\`, \`/linear/states/_index.json\`, \`/linear/cycles/_index.json\`, \`/linear/milestones/_index.json\`, and \`/linear/roadmaps/_index.json\` use:
24
27
 
25
28
  \`\`\`json
26
29
  { "id": "<id>", "title": "<human-readable>", "updated": "<iso8601>" }
@@ -40,7 +43,14 @@ ls /linear/issues/by-assignee
40
43
  ls /linear/issues/by-priority
41
44
  ls /linear/issues/by-edited/2026-05-12
42
45
  jq '.identifier' /linear/issues/by-edited/2026-05-12/11111111-1111-1111-1111-111111111111.json
46
+ jq '.[0]' /linear/projects/_index.json
47
+ ls /linear/projects/by-name
48
+ ls /linear/projects/by-state/started
49
+ jq '.payload.id' /linear/projects/by-team/22222222-2222-2222-2222-222222222222/11111111-1111-1111-1111-111111111111.json
50
+ jq '.[0]' /linear/states/_index.json
43
51
  jq '.required' discovery/linear/issues/.schema.json
52
+ cat discovery/linear/projects/.create.example.json
53
+ cat discovery/linear/projects/{projectId}/add-issues.json/.create.example.json
44
54
  ls discovery/linear/issues/{issueId}/comments
45
55
  grep -R "ENG-" /linear/comments
46
56
  \`\`\`
@@ -1 +1 @@
1
- {"version":3,"file":"layout-prompt.js","sourceRoot":"","sources":["../src/layout-prompt.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8CnC,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwDnC,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 +1 @@
1
- {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,IAAI,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AAEpG,YAAY,EACV,cAAc,EACd,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,EACnB,yBAAyB,GAC1B,MAAM,yBAAyB,CAAC;AAEjC,eAAO,MAAM,cAAc,EAAE,0BAiC3B,CAAC"}
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,IAAI,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AAEpG,YAAY,EACV,cAAc,EACd,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,EACnB,yBAAyB,GAC1B,MAAM,yBAAyB,CAAC;AAEjC,eAAO,MAAM,cAAc,EAAE,0BA6C3B,CAAC"}
package/dist/layout.js CHANGED
@@ -3,8 +3,9 @@ export const layoutManifest = () => ({
3
3
  filenameConvention: '<identifier>__<uuid>.json',
4
4
  // Top-level aliasSegments is the union of every resource's alias segments
5
5
  // so consumers that inspect only the manifest root can discover all
6
- // lookup keys. `by-name` belongs here because `linear/teams` exposes it.
7
- aliasSegments: ['by-assignee', 'by-creator', 'by-edited', 'by-id', 'by-name', 'by-priority', 'by-title', 'by-state', 'by-uuid'],
6
+ // lookup keys. `by-name` belongs here because `linear/teams` and
7
+ // `linear/projects` expose it.
8
+ aliasSegments: ['by-assignee', 'by-creator', 'by-edited', 'by-id', 'by-name', 'by-priority', 'by-title', 'by-state', 'by-team', 'by-uuid'],
8
9
  resources: [
9
10
  {
10
11
  path: 'linear/issues',
@@ -20,7 +21,18 @@ export const layoutManifest = () => ({
20
21
  path: 'linear/projects',
21
22
  title: 'Projects',
22
23
  materialization: 'eager',
23
- aliasSegments: ['by-id', 'by-title'],
24
+ aliasSegments: ['by-id', 'by-name', 'by-state', 'by-team'],
25
+ writebackResources: [
26
+ { path: 'linear/projects', schemaId: 'linear/project' },
27
+ { path: 'linear/projects/*/meta.json', schemaId: 'linear/project-update' },
28
+ { path: 'linear/projects/*/add-issues.json', schemaId: 'linear/project-issue-assignment' },
29
+ ],
30
+ },
31
+ {
32
+ path: 'linear/states',
33
+ title: 'Workflow States',
34
+ materialization: 'eager',
35
+ aliasSegments: [],
24
36
  writebackResources: [],
25
37
  },
26
38
  {
@@ -1 +1 @@
1
- {"version":3,"file":"layout.js","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"AAUA,MAAM,CAAC,MAAM,cAAc,GAA+B,GAAG,EAAE,CAAC,CAAC;IAC/D,QAAQ,EAAE,QAAQ;IAClB,kBAAkB,EAAE,2BAA2B;IAC/C,0EAA0E;IAC1E,oEAAoE;IACpE,yEAAyE;IACzE,aAAa,EAAE,CAAC,aAAa,EAAE,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,CAAC;IAC/H,SAAS,EAAE;QACT;YACE,IAAI,EAAE,eAAe;YACrB,KAAK,EAAE,QAAQ;YACf,eAAe,EAAE,OAAO;YACxB,aAAa,EAAE,CAAC,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,CAAC;YACpH,kBAAkB,EAAE;gBAClB,EAAE,IAAI,EAAE,eAAe,EAAE,QAAQ,EAAE,cAAc,EAAE;gBACnD,EAAE,IAAI,EAAE,wBAAwB,EAAE,QAAQ,EAAE,gBAAgB,EAAE;aAC/D;SACF;QACD;YACE,IAAI,EAAE,iBAAiB;YACvB,KAAK,EAAE,UAAU;YACjB,eAAe,EAAE,OAAO;YACxB,aAAa,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC;YACpC,kBAAkB,EAAE,EAAE;SACvB;QACD;YACE,IAAI,EAAE,cAAc;YACpB,KAAK,EAAE,OAAO;YACd,eAAe,EAAE,OAAO;YACxB,aAAa,EAAE,CAAC,OAAO,EAAE,SAAS,CAAC;YACnC,kBAAkB,EAAE,EAAE;SACvB;KACF;CACF,CAAC,CAAC"}
1
+ {"version":3,"file":"layout.js","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"AAUA,MAAM,CAAC,MAAM,cAAc,GAA+B,GAAG,EAAE,CAAC,CAAC;IAC/D,QAAQ,EAAE,QAAQ;IAClB,kBAAkB,EAAE,2BAA2B;IAC/C,0EAA0E;IAC1E,oEAAoE;IACpE,iEAAiE;IACjE,+BAA+B;IAC/B,aAAa,EAAE,CAAC,aAAa,EAAE,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,CAAC;IAC1I,SAAS,EAAE;QACT;YACE,IAAI,EAAE,eAAe;YACrB,KAAK,EAAE,QAAQ;YACf,eAAe,EAAE,OAAO;YACxB,aAAa,EAAE,CAAC,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,CAAC;YACpH,kBAAkB,EAAE;gBAClB,EAAE,IAAI,EAAE,eAAe,EAAE,QAAQ,EAAE,cAAc,EAAE;gBACnD,EAAE,IAAI,EAAE,wBAAwB,EAAE,QAAQ,EAAE,gBAAgB,EAAE;aAC/D;SACF;QACD;YACE,IAAI,EAAE,iBAAiB;YACvB,KAAK,EAAE,UAAU;YACjB,eAAe,EAAE,OAAO;YACxB,aAAa,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,CAAC;YAC1D,kBAAkB,EAAE;gBAClB,EAAE,IAAI,EAAE,iBAAiB,EAAE,QAAQ,EAAE,gBAAgB,EAAE;gBACvD,EAAE,IAAI,EAAE,6BAA6B,EAAE,QAAQ,EAAE,uBAAuB,EAAE;gBAC1E,EAAE,IAAI,EAAE,mCAAmC,EAAE,QAAQ,EAAE,iCAAiC,EAAE;aAC3F;SACF;QACD;YACE,IAAI,EAAE,eAAe;YACrB,KAAK,EAAE,iBAAiB;YACxB,eAAe,EAAE,OAAO;YACxB,aAAa,EAAE,EAAE;YACjB,kBAAkB,EAAE,EAAE;SACvB;QACD;YACE,IAAI,EAAE,cAAc;YACpB,KAAK,EAAE,OAAO;YACd,eAAe,EAAE,OAAO;YACxB,aAAa,EAAE,CAAC,OAAO,EAAE,SAAS,CAAC;YACnC,kBAAkB,EAAE,EAAE;SACvB;KACF;CACF,CAAC,CAAC"}
@@ -9,6 +9,7 @@ const CANONICAL_ALIAS_SEGMENTS = new Set([
9
9
  'by-name',
10
10
  'by-priority',
11
11
  'by-state',
12
+ 'by-team',
12
13
  'by-title',
13
14
  'by-uuid',
14
15
  ]);
@@ -24,9 +25,11 @@ test('layoutManifest exposes Linear resources with canonical aliases and writeba
24
25
  'by-priority',
25
26
  'by-title',
26
27
  'by-state',
28
+ 'by-team',
27
29
  'by-uuid',
28
30
  ]);
29
31
  assert.ok(manifest.resources.length > 0);
32
+ assert.ok(manifest.resources.some((resource) => resource.path === 'linear/states'));
30
33
  for (const resource of manifest.resources) {
31
34
  assert.ok(resource.path.startsWith('linear/'));
32
35
  assert.doesNotMatch(resource.path, /^\//u);
@@ -1 +1 @@
1
- {"version":3,"file":"layout.test.js","sourceRoot":"","sources":["../src/layout.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,wBAAwB,GAAG,IAAI,GAAG,CAAC;IACvC,aAAa;IACb,YAAY;IACZ,WAAW;IACX,OAAO;IACP,SAAS;IACT,aAAa;IACb,UAAU;IACV,UAAU;IACV,SAAS;CACV,CAAC,CAAC;AAEH,IAAI,CAAC,8FAA8F,EAAE,GAAG,EAAE;IACxG,MAAM,QAAQ,GAAG,cAAc,EAAE,CAAC;IAElC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC1C,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,aAAa,EAAE;QACvC,aAAa;QACb,YAAY;QACZ,WAAW;QACX,OAAO;QACP,SAAS;QACT,aAAa;QACb,UAAU;QACV,UAAU;QACV,SAAS;KACV,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAEzC,KAAK,MAAM,QAAQ,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;QAC1C,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC;QAC/C,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC3C,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,aAAa,EAAE,CAAC;YAC3C,MAAM,CAAC,EAAE,CAAC,wBAAwB,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,4BAA4B,KAAK,EAAE,CAAC,CAAC;QACtF,CAAC;QACD,KAAK,MAAM,SAAS,IAAI,QAAQ,CAAC,kBAAkB,EAAE,CAAC;YACpD,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC;YAChD,MAAM,CAAC,YAAY,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAC5C,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,oBAAoB,CAAC,CAAC;QACzD,CAAC;IACH,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,0FAA0F,EAAE,GAAG,EAAE;IACpG,MAAM,QAAQ,GAAG,cAAc,EAAE,CAAC;IAClC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;IACjD,KAAK,MAAM,QAAQ,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;QAC1C,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,aAAa,EAAE,CAAC;YAC3C,MAAM,CAAC,EAAE,CACP,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,EACnB,mCAAmC,KAAK,yBAAyB,QAAQ,CAAC,IAAI,EAAE,CACjF,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"layout.test.js","sourceRoot":"","sources":["../src/layout.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,wBAAwB,GAAG,IAAI,GAAG,CAAC;IACvC,aAAa;IACb,YAAY;IACZ,WAAW;IACX,OAAO;IACP,SAAS;IACT,aAAa;IACb,UAAU;IACV,SAAS;IACT,UAAU;IACV,SAAS;CACV,CAAC,CAAC;AAEH,IAAI,CAAC,8FAA8F,EAAE,GAAG,EAAE;IACxG,MAAM,QAAQ,GAAG,cAAc,EAAE,CAAC;IAElC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC1C,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,aAAa,EAAE;QACvC,aAAa;QACb,YAAY;QACZ,WAAW;QACX,OAAO;QACP,SAAS;QACT,aAAa;QACb,UAAU;QACV,UAAU;QACV,SAAS;QACT,SAAS;KACV,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACzC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,KAAK,eAAe,CAAC,CAAC,CAAC;IAEpF,KAAK,MAAM,QAAQ,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;QAC1C,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC;QAC/C,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC3C,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,aAAa,EAAE,CAAC;YAC3C,MAAM,CAAC,EAAE,CAAC,wBAAwB,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,4BAA4B,KAAK,EAAE,CAAC,CAAC;QACtF,CAAC;QACD,KAAK,MAAM,SAAS,IAAI,QAAQ,CAAC,kBAAkB,EAAE,CAAC;YACpD,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC;YAChD,MAAM,CAAC,YAAY,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAC5C,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,oBAAoB,CAAC,CAAC;QACzD,CAAC;IACH,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,0FAA0F,EAAE,GAAG,EAAE;IACpG,MAAM,QAAQ,GAAG,cAAc,EAAE,CAAC;IAClC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;IACjD,KAAK,MAAM,QAAQ,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;QAC1C,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,aAAa,EAAE,CAAC;YAC3C,MAAM,CAAC,EAAE,CACP,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,EACnB,mCAAmC,KAAK,yBAAyB,QAAQ,CAAC,IAAI,EAAE,CACjF,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"linear-adapter.d.ts","sourceRoot":"","sources":["../src/linear-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAQzD,YAAY,EAAE,kBAAkB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAmCtF,OAAO,KAAK,EACV,mBAAmB,EAYnB,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAGpB,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;CACvD;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;IAClE,UAAU,CAAC,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1D,QAAQ,CAAC,CACP,kBAAkB,EAAE,aAAa,GAAG,MAAM,EAC1C,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,cAAc,GAAG,MAAM,GAAG,SAAS,CAAC,GAAG,cAAc,GAAG,MAAM,GAAG,SAAS,CAAC;CACvF;AAED,8BAAsB,kBAAkB;IACtC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;IAC/C,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;IAEhD,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;gBAEtB,MAAM,EAAE,mBAAmB,EAAE,QAAQ,EAAE,kBAAkB;IAKrE,QAAQ,CAAC,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,GAAG,oBAAoB,GAAG,OAAO,CAAC,YAAY,CAAC;IAEnH,QAAQ,CAAC,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAElE,QAAQ,CAAC,gBAAgB,CACvB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,aAAa;IAEhB,eAAe,CAAC,IAAI,MAAM,EAAE;CAC7B;AASD,qBAAa,aAAc,SAAQ,kBAAkB;IACnD,SAAkB,IAAI,YAAwB;IAC9C,SAAkB,OAAO,WAAW;IAEpC,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;gBAGnC,MAAM,EAAE,mBAAmB,EAC3B,QAAQ,EAAE,kBAAkB,EAC5B,MAAM,GAAE,mBAAwB;IAMzB,eAAe,IAAI,MAAM,EAAE;IASrB,aAAa,CAC1B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,iBAAiB,GAAG,oBAAoB,GAC9C,OAAO,CAAC,YAAY,CAAC;IA4Kf,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM;YAIpE,kBAAkB;IAiChC,OAAO,CAAC,0BAA0B;IAwBzB,gBAAgB,CACvB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,aAAa;IA2DhB,OAAO,CAAC,cAAc;IAqCtB,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,aAAa;YAaP,mBAAmB;YAuCnB,aAAa;YAuBb,oBAAoB;CAyBnC"}
1
+ {"version":3,"file":"linear-adapter.d.ts","sourceRoot":"","sources":["../src/linear-adapter.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import { cleanupStaleAliases, readAliasKeyFromContent, upsertIndexAtomic, } from '@relayfile/adapter-core';
2
- import { computeLinearPath, LINEAR_PATH_ROOT, linearAgentWebhookEventPath, linearByIdAliasPath, linearByTitleAliasPath, linearCyclePath, linearIssueByStatePath, linearIssuePath, linearMilestonePath, linearProjectPath, linearRoadmapPath, linearTeamPath, linearUserPath, normalizeLinearObjectType, } from './path-mapper.js';
2
+ import { computeLinearPath, LINEAR_PATH_ROOT, linearAgentWebhookEventPath, linearByIdAliasPath, linearByNameAliasPath, linearByTitleAliasPath, linearCyclePath, linearIssueByStatePath, linearIssuePath, linearMilestonePath, linearProjectByStatePath, linearProjectByTeamPath, linearProjectPath, linearRoadmapPath, linearTeamPath, linearUserPath, normalizeLinearObjectType, } from './path-mapper.js';
3
3
  import { buildLinearIndexFile } from './index-emitter.js';
4
4
  import { linearLayoutPromptFile } from './layout-prompt.js';
5
- import { getLinearCommentHumanReadable, getLinearIssueHumanReadable, linearCommentIndexRow, linearCycleIndexRow, linearIssueIndexRow, linearMilestoneIndexRow, linearProjectIndexRow, linearRoadmapIndexRow, linearTeamIndexRow, linearUserIndexRow, } from './queries.js';
5
+ import { getLinearCommentHumanReadable, getLinearIssueHumanReadable, linearCommentIndexRow, linearCycleIndexRow, linearIssueIndexRow, linearMilestoneIndexRow, linearProjectIndexRow, linearRoadmapIndexRow, linearStateIndexRow, linearTeamIndexRow, linearUserIndexRow, } from './queries.js';
6
6
  import { LINEAR_AGENT_WEBHOOK_EVENTS, LINEAR_WEBHOOK_OBJECT_TYPES } from './types.js';
7
7
  import { normalizeLinearWebhook } from './webhook-normalizer.js';
8
8
  export class IntegrationAdapter {
@@ -461,7 +461,9 @@ function applyIssueSemantics(properties, relations, payload) {
461
461
  relations.add(linearProjectPath(issue.project.id));
462
462
  addStringProperty(properties, 'linear.project_id', issue.project.id);
463
463
  addStringProperty(properties, 'linear.project_name', issue.project.name);
464
+ addFirstStringProperty(properties, 'linear.project_slug', issue.project.slug, issue.project.slugId);
464
465
  addStringProperty(properties, 'linear.project_state', issue.project.state);
466
+ addFirstStringProperty(properties, 'linear.project_lead_id', issue.project.lead?.id, issue.project.leadId);
465
467
  addStringProperty(properties, 'linear.project_url', issue.project.url);
466
468
  }
467
469
  const projectId = asString(issue.project_id);
@@ -564,12 +566,17 @@ function applyProjectSemantics(properties, relations, payload) {
564
566
  const project = payload;
565
567
  addStringProperty(properties, 'linear.name', project.name);
566
568
  addStringProperty(properties, 'linear.state', project.state);
569
+ addFirstStringProperty(properties, 'linear.slug', project.slug, project.slugId);
567
570
  addFirstStringProperty(properties, 'linear.description', project.description);
571
+ addFirstStringProperty(properties, 'linear.start_date', project.startDate, project.start_date);
568
572
  addFirstStringProperty(properties, 'linear.target_date', project.targetDate, project.target_date);
569
573
  addFirstStringProperty(properties, 'linear.started_at', project.startedAt, project.started_at);
570
574
  addFirstStringProperty(properties, 'linear.completed_at', project.completedAt, project.completed_at);
571
575
  addFirstStringProperty(properties, 'linear.created_at', project.createdAt, project.created_at);
572
576
  addFirstStringProperty(properties, 'linear.updated_at', project.updatedAt, project.updated_at);
577
+ addFirstStringProperty(properties, 'linear.lead_id', project.lead?.id, project.leadId, project.lead_id);
578
+ addFirstStringProperty(properties, 'linear.color', project.color);
579
+ addFirstStringProperty(properties, 'linear.icon', project.icon);
573
580
  const progress = asNumber(project.progress);
574
581
  if (progress !== undefined) {
575
582
  properties['linear.progress'] = String(progress);
@@ -586,6 +593,12 @@ function applyProjectSemantics(properties, relations, payload) {
586
593
  }
587
594
  }
588
595
  }
596
+ function readProjectTeamIdsFromPayload(payload) {
597
+ return uniqueStrings([
598
+ ...asStringArray(payload.team_ids),
599
+ ...asLinearReferenceIds(payload.teams),
600
+ ]);
601
+ }
589
602
  function buildLinearIssueReferencePath(issue) {
590
603
  return linearIssuePath(issue.id, getLinearIssueHumanReadable(issue));
591
604
  }
@@ -747,10 +760,14 @@ function buildIndexRow(bucket, event) {
747
760
  return linearProjectIndexRow(payload);
748
761
  case 'roadmaps':
749
762
  return linearRoadmapIndexRow(payload);
763
+ case 'states':
764
+ return linearStateIndexRow(payload);
750
765
  case 'teams':
751
766
  return linearTeamIndexRow(payload);
752
767
  case 'users':
753
768
  return linearUserIndexRow(payload);
769
+ default:
770
+ throw new Error(`Unsupported Linear index bucket: ${bucket}`);
754
771
  }
755
772
  }
756
773
  function buildIndexFileForBucket(bucket, rows) {
@@ -767,10 +784,14 @@ function buildIndexFileForBucket(bucket, rows) {
767
784
  return buildLinearIndexFile('projects', rows);
768
785
  case 'roadmaps':
769
786
  return buildLinearIndexFile('roadmaps', rows);
787
+ case 'states':
788
+ return buildLinearIndexFile('states', rows);
770
789
  case 'teams':
771
790
  return buildLinearIndexFile('teams', rows);
772
791
  case 'users':
773
792
  return buildLinearIndexFile('users', rows);
793
+ default:
794
+ throw new Error(`Unsupported Linear index bucket: ${bucket}`);
774
795
  }
775
796
  }
776
797
  function buildIndexPathForBucket(bucket) {
@@ -955,21 +976,34 @@ async function writeLinearAliases(client, workspaceId, event, canonicalPath, con
955
976
  // Snapshot the previous record version before the by-id alias is
956
977
  // overwritten — it carries the prior title/name for stale alias cleanup.
957
978
  const previousContent = await readLinearFile(client, byIdAliasPath, workspaceId);
958
- await writeLinearIndex(client, workspaceId, scope);
979
+ await writeLinearIndex(client, workspaceId, scope, { objectType: normalizedType });
959
980
  await writeLinearFile(client, workspaceId, byIdAliasPath, content, semantics);
960
981
  let writtenAliasPath;
961
982
  if (title) {
962
- const baseAliasPath = linearByTitleAliasPath(scope, title, event.objectId);
983
+ const baseAliasPath = normalizedType === 'issue'
984
+ ? linearByTitleAliasPath(scope, title, event.objectId)
985
+ : linearByNameAliasPath(scope, title, event.objectId);
963
986
  const existingBaseContent = await readLinearFile(client, baseAliasPath, workspaceId);
964
987
  // A base alias holding this record's previous bytes is ours — overwrite
965
988
  // it in place instead of forking to the collision variant.
966
989
  const ownsBaseAlias = existingBaseContent !== undefined && existingBaseContent === previousContent;
967
990
  const aliasPath = existingBaseContent !== undefined && existingBaseContent !== content && !ownsBaseAlias
968
- ? linearByTitleAliasPath(scope, title, event.objectId, true)
991
+ ? normalizedType === 'issue'
992
+ ? linearByTitleAliasPath(scope, title, event.objectId, true)
993
+ : linearByNameAliasPath(scope, title, event.objectId, true)
969
994
  : baseAliasPath;
970
995
  await writeLinearFile(client, workspaceId, aliasPath, content, semantics);
971
996
  writtenAliasPath = aliasPath;
972
997
  }
998
+ if (normalizedType === 'project') {
999
+ const state = asString(event.payload.state);
1000
+ if (state) {
1001
+ await writeLinearFile(client, workspaceId, linearProjectByStatePath(state, event.objectId), content, semantics);
1002
+ }
1003
+ for (const teamId of readProjectTeamIdsFromPayload(event.payload)) {
1004
+ await writeLinearFile(client, workspaceId, linearProjectByTeamPath(teamId, event.objectId), content, semantics);
1005
+ }
1006
+ }
973
1007
  // Stale alias lifecycle (issue #106): delete the previous by-title alias
974
1008
  // when the record's title/name changed. Only the stale alias file is
975
1009
  // removed — the canonical record file is never touched.
@@ -982,7 +1016,7 @@ async function writeLinearAliases(client, workspaceId, event, canonicalPath, con
982
1016
  });
983
1017
  }
984
1018
  /**
985
- * Removes the stale `by-title` alias left behind when an issue title or
1019
+ * Removes the stale human-readable alias left behind when an issue title or
986
1020
  * project name changes between ingests (issue #106).
987
1021
  *
988
1022
  * Prior state comes from the mirror itself: the title-independent `by-id`
@@ -1016,7 +1050,11 @@ async function cleanupStaleLinearTitleAliases(client, workspaceId, options) {
1016
1050
  }
1017
1051
  const candidatePaths = [];
1018
1052
  try {
1019
- candidatePaths.push(linearByTitleAliasPath(scope, previousTitle, objectId), linearByTitleAliasPath(scope, previousTitle, objectId, true));
1053
+ candidatePaths.push(objectType === 'issue'
1054
+ ? linearByTitleAliasPath(scope, previousTitle, objectId)
1055
+ : linearByNameAliasPath(scope, previousTitle, objectId), objectType === 'issue'
1056
+ ? linearByTitleAliasPath(scope, previousTitle, objectId, true)
1057
+ : linearByNameAliasPath(scope, previousTitle, objectId, true));
1020
1058
  }
1021
1059
  catch {
1022
1060
  // Previous title slugs to an empty string — no alias was emitted for it.
@@ -1034,10 +1072,21 @@ async function cleanupStaleLinearTitleAliases(client, workspaceId, options) {
1034
1072
  async function writeLinearIndex(client, workspaceId, scope, options) {
1035
1073
  const indexPath = `${scope}/_index.json`;
1036
1074
  const vfs = linearClientToVfs(client, workspaceId);
1037
- await upsertIndexAtomic(vfs, indexPath, parseLinearIndexRows, (rows) => mergeLinearIndexRowsList(rows, [
1075
+ await upsertIndexAtomic(vfs, indexPath, parseLinearIndexRows, (rows) => mergeLinearIndexRowsList(rows, indexAliasRows(options?.objectType)), (rows) => stableJson({ rows }), options);
1076
+ }
1077
+ function indexAliasRows(objectType) {
1078
+ if (objectType === 'project') {
1079
+ return [
1080
+ { title: 'by-id', file: 'by-id/' },
1081
+ { title: 'by-name', file: 'by-name/' },
1082
+ { title: 'by-state', file: 'by-state/' },
1083
+ { title: 'by-team', file: 'by-team/' },
1084
+ ];
1085
+ }
1086
+ return [
1038
1087
  { title: 'by-id', file: 'by-id/' },
1039
1088
  { title: 'by-title', file: 'by-title/' },
1040
- ]), (rows) => stableJson({ rows }), options);
1089
+ ];
1041
1090
  }
1042
1091
  /**
1043
1092
  * Wrap the linear `RelayFileClientLike` (single-input WriteFileInput shape)