@elnora-ai/linear 1.0.1 → 2.0.0

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 (302) hide show
  1. package/.claude-plugin/marketplace.json +7 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +25 -1
  4. package/README.md +275 -25
  5. package/agents/linear-issue-creator.md +135 -17
  6. package/agents/linear-issue-reviewer.md +122 -23
  7. package/agents/linear-issue-updater.md +137 -25
  8. package/agents/linear-state-curator.md +173 -0
  9. package/agents/linear-url-to-issues.md +190 -26
  10. package/commands/linear-cleanup.md +64 -29
  11. package/dist/cli.js +69 -1
  12. package/dist/cli.js.map +1 -1
  13. package/dist/client/auth.d.ts +10 -0
  14. package/dist/client/auth.d.ts.map +1 -1
  15. package/dist/client/auth.js +50 -3
  16. package/dist/client/auth.js.map +1 -1
  17. package/dist/client/linear-client.d.ts +7 -0
  18. package/dist/client/linear-client.d.ts.map +1 -1
  19. package/dist/client/linear-client.js +13 -1
  20. package/dist/client/linear-client.js.map +1 -1
  21. package/dist/commands/agent-activities.d.ts +3 -0
  22. package/dist/commands/agent-activities.d.ts.map +1 -0
  23. package/dist/commands/agent-activities.js +144 -0
  24. package/dist/commands/agent-activities.js.map +1 -0
  25. package/dist/commands/agent-sessions.d.ts +3 -0
  26. package/dist/commands/agent-sessions.d.ts.map +1 -0
  27. package/dist/commands/agent-sessions.js +132 -0
  28. package/dist/commands/agent-sessions.js.map +1 -0
  29. package/dist/commands/attachments.d.ts +3 -0
  30. package/dist/commands/attachments.d.ts.map +1 -0
  31. package/dist/commands/attachments.js +265 -0
  32. package/dist/commands/attachments.js.map +1 -0
  33. package/dist/commands/audit.d.ts +3 -0
  34. package/dist/commands/audit.d.ts.map +1 -0
  35. package/dist/commands/audit.js +73 -0
  36. package/dist/commands/audit.js.map +1 -0
  37. package/dist/commands/comments.d.ts +3 -0
  38. package/dist/commands/comments.d.ts.map +1 -0
  39. package/dist/commands/comments.js +107 -0
  40. package/dist/commands/comments.js.map +1 -0
  41. package/dist/commands/completion.d.ts +3 -0
  42. package/dist/commands/completion.d.ts.map +1 -0
  43. package/dist/commands/completion.js +62 -0
  44. package/dist/commands/completion.js.map +1 -0
  45. package/dist/commands/context.d.ts +3 -0
  46. package/dist/commands/context.d.ts.map +1 -0
  47. package/dist/commands/context.js +94 -0
  48. package/dist/commands/context.js.map +1 -0
  49. package/dist/commands/curator.d.ts +14 -0
  50. package/dist/commands/curator.d.ts.map +1 -1
  51. package/dist/commands/curator.js +97 -19
  52. package/dist/commands/curator.js.map +1 -1
  53. package/dist/commands/customer-needs.d.ts +3 -0
  54. package/dist/commands/customer-needs.d.ts.map +1 -0
  55. package/dist/commands/customer-needs.js +198 -0
  56. package/dist/commands/customer-needs.js.map +1 -0
  57. package/dist/commands/customers.d.ts +5 -0
  58. package/dist/commands/customers.d.ts.map +1 -0
  59. package/dist/commands/customers.js +201 -0
  60. package/dist/commands/customers.js.map +1 -0
  61. package/dist/commands/cycles.d.ts +3 -0
  62. package/dist/commands/cycles.d.ts.map +1 -0
  63. package/dist/commands/cycles.js +67 -0
  64. package/dist/commands/cycles.js.map +1 -0
  65. package/dist/commands/documents.d.ts +3 -0
  66. package/dist/commands/documents.d.ts.map +1 -0
  67. package/dist/commands/documents.js +105 -0
  68. package/dist/commands/documents.js.map +1 -0
  69. package/dist/commands/favorites.d.ts +3 -0
  70. package/dist/commands/favorites.d.ts.map +1 -0
  71. package/dist/commands/favorites.js +101 -0
  72. package/dist/commands/favorites.js.map +1 -0
  73. package/dist/commands/index.d.ts +30 -0
  74. package/dist/commands/index.d.ts.map +1 -1
  75. package/dist/commands/index.js +30 -0
  76. package/dist/commands/index.js.map +1 -1
  77. package/dist/commands/initiatives.d.ts +3 -0
  78. package/dist/commands/initiatives.d.ts.map +1 -0
  79. package/dist/commands/initiatives.js +106 -0
  80. package/dist/commands/initiatives.js.map +1 -0
  81. package/dist/commands/issues.d.ts +21 -0
  82. package/dist/commands/issues.d.ts.map +1 -0
  83. package/dist/commands/issues.js +1083 -0
  84. package/dist/commands/issues.js.map +1 -0
  85. package/dist/commands/labels.d.ts +3 -0
  86. package/dist/commands/labels.d.ts.map +1 -0
  87. package/dist/commands/labels.js +111 -0
  88. package/dist/commands/labels.js.map +1 -0
  89. package/dist/commands/milestones.d.ts +3 -0
  90. package/dist/commands/milestones.d.ts.map +1 -0
  91. package/dist/commands/milestones.js +94 -0
  92. package/dist/commands/milestones.js.map +1 -0
  93. package/dist/commands/notifications.d.ts +3 -0
  94. package/dist/commands/notifications.d.ts.map +1 -0
  95. package/dist/commands/notifications.js +130 -0
  96. package/dist/commands/notifications.js.map +1 -0
  97. package/dist/commands/project-labels.d.ts +3 -0
  98. package/dist/commands/project-labels.d.ts.map +1 -0
  99. package/dist/commands/project-labels.js +80 -0
  100. package/dist/commands/project-labels.js.map +1 -0
  101. package/dist/commands/project-relations.d.ts +3 -0
  102. package/dist/commands/project-relations.d.ts.map +1 -0
  103. package/dist/commands/project-relations.js +96 -0
  104. package/dist/commands/project-relations.js.map +1 -0
  105. package/dist/commands/projects.d.ts +3 -0
  106. package/dist/commands/projects.d.ts.map +1 -0
  107. package/dist/commands/projects.js +263 -0
  108. package/dist/commands/projects.js.map +1 -0
  109. package/dist/commands/quota.d.ts +3 -0
  110. package/dist/commands/quota.d.ts.map +1 -0
  111. package/dist/commands/quota.js +28 -0
  112. package/dist/commands/quota.js.map +1 -0
  113. package/dist/commands/reactions.d.ts +7 -0
  114. package/dist/commands/reactions.d.ts.map +1 -0
  115. package/dist/commands/reactions.js +53 -0
  116. package/dist/commands/reactions.js.map +1 -0
  117. package/dist/commands/relations.d.ts +3 -0
  118. package/dist/commands/relations.d.ts.map +1 -0
  119. package/dist/commands/relations.js +73 -0
  120. package/dist/commands/relations.js.map +1 -0
  121. package/dist/commands/states.d.ts +3 -0
  122. package/dist/commands/states.d.ts.map +1 -0
  123. package/dist/commands/states.js +52 -0
  124. package/dist/commands/states.js.map +1 -0
  125. package/dist/commands/status-updates.d.ts +3 -0
  126. package/dist/commands/status-updates.d.ts.map +1 -0
  127. package/dist/commands/status-updates.js +117 -0
  128. package/dist/commands/status-updates.js.map +1 -0
  129. package/dist/commands/sync.d.ts.map +1 -1
  130. package/dist/commands/sync.js +58 -18
  131. package/dist/commands/sync.js.map +1 -1
  132. package/dist/commands/teams.d.ts +3 -0
  133. package/dist/commands/teams.d.ts.map +1 -0
  134. package/dist/commands/teams.js +135 -0
  135. package/dist/commands/teams.js.map +1 -0
  136. package/dist/commands/templates.d.ts +3 -0
  137. package/dist/commands/templates.d.ts.map +1 -0
  138. package/dist/commands/templates.js +76 -0
  139. package/dist/commands/templates.js.map +1 -0
  140. package/dist/commands/users.d.ts +3 -0
  141. package/dist/commands/users.d.ts.map +1 -0
  142. package/dist/commands/users.js +40 -0
  143. package/dist/commands/users.js.map +1 -0
  144. package/dist/commands/views.d.ts +3 -0
  145. package/dist/commands/views.d.ts.map +1 -0
  146. package/dist/commands/views.js +177 -0
  147. package/dist/commands/views.js.map +1 -0
  148. package/dist/commands/webhooks.d.ts +3 -0
  149. package/dist/commands/webhooks.d.ts.map +1 -0
  150. package/dist/commands/webhooks.js +234 -0
  151. package/dist/commands/webhooks.js.map +1 -0
  152. package/dist/config/loader.d.ts.map +1 -1
  153. package/dist/config/loader.js +3 -0
  154. package/dist/config/loader.js.map +1 -1
  155. package/dist/config/types.d.ts +15 -1
  156. package/dist/config/types.d.ts.map +1 -1
  157. package/dist/config/types.js +1 -0
  158. package/dist/config/types.js.map +1 -1
  159. package/dist/curator/dispatch.d.ts +52 -0
  160. package/dist/curator/dispatch.d.ts.map +1 -0
  161. package/dist/curator/dispatch.js +144 -0
  162. package/dist/curator/dispatch.js.map +1 -0
  163. package/dist/curator/index.d.ts +5 -0
  164. package/dist/curator/index.d.ts.map +1 -0
  165. package/dist/curator/index.js +5 -0
  166. package/dist/curator/index.js.map +1 -0
  167. package/dist/curator/llm.d.ts +70 -0
  168. package/dist/curator/llm.d.ts.map +1 -0
  169. package/dist/curator/llm.js +107 -0
  170. package/dist/curator/llm.js.map +1 -0
  171. package/dist/curator/snapshot.d.ts +34 -0
  172. package/dist/curator/snapshot.d.ts.map +1 -0
  173. package/dist/curator/snapshot.js +127 -0
  174. package/dist/curator/snapshot.js.map +1 -0
  175. package/dist/curator/state.d.ts +50 -0
  176. package/dist/curator/state.d.ts.map +1 -0
  177. package/dist/curator/state.js +125 -0
  178. package/dist/curator/state.js.map +1 -0
  179. package/dist/lib/bulk-graphql.d.ts +144 -0
  180. package/dist/lib/bulk-graphql.d.ts.map +1 -0
  181. package/dist/lib/bulk-graphql.js +380 -0
  182. package/dist/lib/bulk-graphql.js.map +1 -0
  183. package/dist/lib/index.d.ts +2 -0
  184. package/dist/lib/index.d.ts.map +1 -0
  185. package/dist/lib/index.js +2 -0
  186. package/dist/lib/index.js.map +1 -0
  187. package/dist/output/cli.d.ts +17 -0
  188. package/dist/output/cli.d.ts.map +1 -0
  189. package/dist/output/cli.js +252 -0
  190. package/dist/output/cli.js.map +1 -0
  191. package/dist/output/formatter.d.ts +6 -0
  192. package/dist/output/formatter.d.ts.map +1 -1
  193. package/dist/output/formatter.js +10 -0
  194. package/dist/output/formatter.js.map +1 -1
  195. package/dist/output/index.d.ts +1 -0
  196. package/dist/output/index.d.ts.map +1 -1
  197. package/dist/output/index.js +1 -0
  198. package/dist/output/index.js.map +1 -1
  199. package/dist/scripts/sync-linear-templates.d.ts +26 -0
  200. package/dist/scripts/sync-linear-templates.d.ts.map +1 -0
  201. package/dist/scripts/sync-linear-templates.js +115 -0
  202. package/dist/scripts/sync-linear-templates.js.map +1 -0
  203. package/dist/signals/github-commits.d.ts +31 -0
  204. package/dist/signals/github-commits.d.ts.map +1 -0
  205. package/dist/signals/github-commits.js +127 -0
  206. package/dist/signals/github-commits.js.map +1 -0
  207. package/dist/signals/github-pr.d.ts +16 -0
  208. package/dist/signals/github-pr.d.ts.map +1 -0
  209. package/dist/signals/github-pr.js +98 -0
  210. package/dist/signals/github-pr.js.map +1 -0
  211. package/dist/signals/index.d.ts +4 -0
  212. package/dist/signals/index.d.ts.map +1 -1
  213. package/dist/signals/index.js +4 -0
  214. package/dist/signals/index.js.map +1 -1
  215. package/dist/signals/linear-issues.d.ts +20 -0
  216. package/dist/signals/linear-issues.d.ts.map +1 -0
  217. package/dist/signals/linear-issues.js +115 -0
  218. package/dist/signals/linear-issues.js.map +1 -0
  219. package/dist/signals/registry.d.ts +4 -3
  220. package/dist/signals/registry.d.ts.map +1 -1
  221. package/dist/signals/registry.js +33 -11
  222. package/dist/signals/registry.js.map +1 -1
  223. package/dist/signals/slack-messages.d.ts +20 -0
  224. package/dist/signals/slack-messages.d.ts.map +1 -0
  225. package/dist/signals/slack-messages.js +129 -0
  226. package/dist/signals/slack-messages.js.map +1 -0
  227. package/dist/utils/errors.d.ts +81 -0
  228. package/dist/utils/errors.d.ts.map +1 -0
  229. package/dist/utils/errors.js +110 -0
  230. package/dist/utils/errors.js.map +1 -0
  231. package/dist/utils/index.d.ts +9 -0
  232. package/dist/utils/index.d.ts.map +1 -0
  233. package/dist/utils/index.js +9 -0
  234. package/dist/utils/index.js.map +1 -0
  235. package/dist/utils/label-policy.d.ts +60 -0
  236. package/dist/utils/label-policy.d.ts.map +1 -0
  237. package/dist/utils/label-policy.js +103 -0
  238. package/dist/utils/label-policy.js.map +1 -0
  239. package/dist/utils/parse.d.ts +48 -0
  240. package/dist/utils/parse.d.ts.map +1 -0
  241. package/dist/utils/parse.js +133 -0
  242. package/dist/utils/parse.js.map +1 -0
  243. package/dist/utils/project-status.d.ts +6 -0
  244. package/dist/utils/project-status.d.ts.map +1 -0
  245. package/dist/utils/project-status.js +33 -0
  246. package/dist/utils/project-status.js.map +1 -0
  247. package/dist/utils/rate-limit.d.ts +24 -0
  248. package/dist/utils/rate-limit.d.ts.map +1 -0
  249. package/dist/utils/rate-limit.js +89 -0
  250. package/dist/utils/rate-limit.js.map +1 -0
  251. package/dist/utils/resolve.d.ts +84 -0
  252. package/dist/utils/resolve.d.ts.map +1 -0
  253. package/dist/utils/resolve.js +172 -0
  254. package/dist/utils/resolve.js.map +1 -0
  255. package/dist/utils/sleep.d.ts +2 -0
  256. package/dist/utils/sleep.d.ts.map +1 -0
  257. package/dist/utils/sleep.js +4 -0
  258. package/dist/utils/sleep.js.map +1 -0
  259. package/dist/utils/webhook-verify.d.ts +42 -0
  260. package/dist/utils/webhook-verify.d.ts.map +1 -0
  261. package/dist/utils/webhook-verify.js +65 -0
  262. package/dist/utils/webhook-verify.js.map +1 -0
  263. package/package.json +7 -2
  264. package/references/agent-description-template.md +31 -0
  265. package/references/cli-reference.md +227 -0
  266. package/references/curator-tiering-rules.md +78 -0
  267. package/references/label-policy.example.json +37 -0
  268. package/references/label-policy.placeholder.json +6 -0
  269. package/references/settings-template.md +30 -0
  270. package/references/signal-sources.example.json +0 -8
  271. package/references/sla-reference.md +70 -0
  272. package/references/template-index.md +34 -0
  273. package/references/workspace-labels.md +124 -0
  274. package/references/workspace-projects.md +56 -0
  275. package/references/workspace-routing.md +58 -0
  276. package/schemas/label-policy.json +72 -0
  277. package/scripts/postinstall.mjs +195 -0
  278. package/skills/linear-workspace/SKILL.md +65 -4
  279. package/templates/ACC-PRO-provision.md +74 -0
  280. package/templates/ACC-PRV-privileged.md +66 -0
  281. package/templates/ACC-QTR-review.md +77 -0
  282. package/templates/ACC-REV-revoke.md +67 -0
  283. package/templates/AI-USE-capability.md +111 -0
  284. package/templates/AUD-CAP-corrective.md +89 -0
  285. package/templates/AUD-INT-internal.md +92 -0
  286. package/templates/AUD-MGT-management.md +110 -0
  287. package/templates/CHG-MAJ-major.md +110 -0
  288. package/templates/CHG-SIG-significant.md +83 -0
  289. package/templates/CHG-STD-standard.md +47 -0
  290. package/templates/LRN-DOC-lessons.md +75 -0
  291. package/templates/OPS-BCK-backup.md +99 -0
  292. package/templates/OPS-DAT-data-mod.md +98 -0
  293. package/templates/RCA-DOC-root-cause.md +105 -0
  294. package/templates/RSK-ASS-assessment.md +87 -0
  295. package/templates/RSK-VND-vendor.md +113 -0
  296. package/templates/SEC-INC-incident.md +76 -0
  297. package/templates/SEC-PEN-pentest.md +58 -0
  298. package/templates/SEC-VLN-vulnerability.md +69 -0
  299. package/templates/SLA-AVL-availability.md +86 -0
  300. package/templates/SLA-OPS-operational.md +70 -0
  301. package/templates/agent-server-template/README.md +88 -0
  302. package/templates/agent-server-template/server.example.ts +185 -0
@@ -0,0 +1,96 @@
1
+ // `elnora-linear project-relations` — project-to-project dependency edges.
2
+ //
3
+ // Distinct from `relations` (which is IssueRelation between issues). Linear's
4
+ // current schema accepts these enum-ish strings (verified live):
5
+ // --type: "dependency" (only currently-valid value)
6
+ // --anchor: "start" | "end" | "milestone"
7
+ // Defaults model the common "B blocks A" case: A's end gated by B's start.
8
+ import { getClient } from "../client/index.js";
9
+ import { handleAsyncCommand, outputSuccess } from "../output/index.js";
10
+ import { CliError, requireYes, resolveProject } from "../utils/index.js";
11
+ export function setupProjectRelationsCommand(program) {
12
+ const relations = program
13
+ .command("project-relations")
14
+ .description("Manage project-to-project dependency relations (blocks, related)");
15
+ relations
16
+ .command("create <project> <relatedProject>")
17
+ .description("Create a dependency relation between two projects")
18
+ .option("--type <type>", "Relation type (Linear currently only accepts 'dependency')", "dependency")
19
+ .option("--anchor <type>", "Anchor on source project: start|end|milestone", "end")
20
+ .option("--related-anchor <type>", "Anchor on related project: start|end|milestone", "start")
21
+ .option("--milestone-id <id>", "Source project milestone UUID (when anchor=milestone)")
22
+ .option("--related-milestone-id <id>", "Related project milestone UUID (when related-anchor=milestone)")
23
+ .action(handleAsyncCommand(async (projectArg, relatedArg, opts) => {
24
+ const client = await getClient();
25
+ const [project, related] = await Promise.all([
26
+ resolveProject(client, projectArg),
27
+ resolveProject(client, relatedArg),
28
+ ]);
29
+ const input = {
30
+ projectId: project.id,
31
+ relatedProjectId: related.id,
32
+ type: opts.type,
33
+ anchorType: opts.anchor,
34
+ relatedAnchorType: opts.relatedAnchor,
35
+ };
36
+ if (opts.milestoneId)
37
+ input.projectMilestoneId = opts.milestoneId;
38
+ if (opts.relatedMilestoneId)
39
+ input.relatedProjectMilestoneId = opts.relatedMilestoneId;
40
+ const payload = await client.createProjectRelation(input);
41
+ if (!payload.success)
42
+ throw new CliError("Failed to create project relation");
43
+ const relation = await payload.projectRelation;
44
+ outputSuccess({
45
+ created: true,
46
+ relation: relation
47
+ ? {
48
+ id: relation.id,
49
+ type: relation.type,
50
+ anchorType: relation.anchorType,
51
+ relatedAnchorType: relation.relatedAnchorType,
52
+ project: project.name,
53
+ relatedProject: related.name,
54
+ }
55
+ : null,
56
+ });
57
+ }));
58
+ relations
59
+ .command("list <project>")
60
+ .description("List dependency relations for a project (forward and inverse)")
61
+ .option("--inverse", "Show inverse relations (projects that point at this one) instead of forward")
62
+ .action(handleAsyncCommand(async (projectArg, opts) => {
63
+ const client = await getClient();
64
+ const project = await resolveProject(client, projectArg);
65
+ const fullProject = await client.project(project.id);
66
+ const connection = opts.inverse ? await fullProject.inverseRelations() : await fullProject.relations();
67
+ const result = await Promise.all(connection.nodes.map(async (r) => {
68
+ const related = await r.relatedProject;
69
+ const source = await r.project;
70
+ return {
71
+ id: r.id,
72
+ type: r.type,
73
+ anchorType: r.anchorType,
74
+ relatedAnchorType: r.relatedAnchorType,
75
+ project: source ? { id: source.id, name: source.name } : null,
76
+ relatedProject: related ? { id: related.id, name: related.name } : null,
77
+ };
78
+ }));
79
+ outputSuccess({
80
+ relations: result,
81
+ count: result.length,
82
+ direction: opts.inverse ? "inverse" : "forward",
83
+ });
84
+ }));
85
+ relations
86
+ .command("delete <relationId>")
87
+ .description("Delete a project relation by its UUID (irreversible — requires --yes)")
88
+ .option("--yes", "Confirm deletion")
89
+ .action(handleAsyncCommand(async (relationId, opts) => {
90
+ requireYes(opts, `delete project relation ${relationId}`);
91
+ const client = await getClient();
92
+ const payload = await client.deleteProjectRelation(relationId);
93
+ outputSuccess({ deleted: payload.success });
94
+ }));
95
+ }
96
+ //# sourceMappingURL=project-relations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-relations.js","sourceRoot":"","sources":["../../src/commands/project-relations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from "commander";
2
+ export declare function setupProjectsCommand(program: Command): void;
3
+ //# sourceMappingURL=projects.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/commands/projects.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAwBzC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA0Q3D"}
@@ -0,0 +1,263 @@
1
+ // `elnora-linear projects` — manage Linear projects.
2
+ //
3
+ // `list` uses raw GraphQL with lead{name} embedded to avoid N+1 round-trips.
4
+ // `get` parallelizes lead + status + teams + workflow states so an agent can
5
+ // plan an issue create against the project without follow-up calls. Includes
6
+ // label policy + recommended issue state for the project's current status.
7
+ import { getClient } from "../client/index.js";
8
+ import { gqlRequest } from "../lib/bulk-graphql.js";
9
+ import { handleAsyncCommand, outputSuccess } from "../output/index.js";
10
+ import { CliError, getTeamLabelPolicy, parseColor, parseDate, parseLimit, parsePriority, parseProjectState, recommendedStateForStatus, requireNonEmptyUpdate, requireYes, resolveProject, resolveProjectStatus, resolveTeam, resolveUser, } from "../utils/index.js";
11
+ export function setupProjectsCommand(program) {
12
+ const projects = program.command("projects").description("Manage Linear projects");
13
+ projects
14
+ .command("list")
15
+ .description("List projects")
16
+ .option("--team <team>", "Filter by team")
17
+ .option("--state <state>", "Filter by project state (planned, started, paused, completed, canceled)")
18
+ .option("--limit <n>", "Max results", "250")
19
+ .action(handleAsyncCommand(async (opts) => {
20
+ const client = await getClient();
21
+ const filter = {};
22
+ if (opts.state) {
23
+ parseProjectState(opts.state);
24
+ filter.status = { type: { eq: opts.state } };
25
+ }
26
+ if (opts.team) {
27
+ const team = await resolveTeam(client, opts.team);
28
+ filter.accessibleTeams = { id: { eq: team.id } };
29
+ }
30
+ const res = await gqlRequest(`query($filter: ProjectFilter, $first: Int!) {
31
+ projects(first: $first, filter: $filter) {
32
+ nodes {
33
+ id name state priority
34
+ lead { name }
35
+ startDate targetDate url
36
+ }
37
+ }
38
+ }`, { filter, first: parseLimit(opts.limit, 250) });
39
+ if (res.errors) {
40
+ throw new CliError(`projects list: ${res.errors.map((e) => e.message).join("; ")}`);
41
+ }
42
+ const rows = (res.data?.projects.nodes ?? []).map((p) => ({
43
+ id: p.id,
44
+ name: p.name,
45
+ state: p.state,
46
+ priority: p.priority,
47
+ lead: p.lead?.name ?? null,
48
+ startDate: p.startDate,
49
+ targetDate: p.targetDate,
50
+ url: p.url,
51
+ }));
52
+ outputSuccess({ projects: rows, count: rows.length });
53
+ }));
54
+ projects
55
+ .command("get <nameOrId>")
56
+ .description("Get project details. Includes label policy, validStates, and currentStatus for the project's primary team.")
57
+ .action(handleAsyncCommand(async (nameOrId) => {
58
+ const client = await getClient();
59
+ const project = await resolveProject(client, nameOrId);
60
+ const full = await client.project(project.id);
61
+ const [lead, status, teamsConn] = await Promise.all([full.lead, full.status, full.teams()]);
62
+ const primaryTeam = teamsConn?.nodes?.[0] ?? null;
63
+ const statesConn = primaryTeam
64
+ ? await client.workflowStates({ first: 100, filter: { team: { id: { eq: primaryTeam.id } } } })
65
+ : null;
66
+ const validStates = statesConn?.nodes?.map((s) => ({ name: s.name, type: s.type })) ?? [];
67
+ const labelPolicy = primaryTeam ? getTeamLabelPolicy(primaryTeam.key) : null;
68
+ const requiredLabels = labelPolicy?.required ?? [];
69
+ const allowedPrefixes = labelPolicy?.allowedPrefixes ?? [];
70
+ const recommended = recommendedStateForStatus(status?.type);
71
+ outputSuccess({
72
+ id: full.id,
73
+ name: full.name,
74
+ description: full.description ?? null,
75
+ state: full.state,
76
+ priority: full.priority,
77
+ lead: lead?.name ?? null,
78
+ startDate: full.startDate ?? null,
79
+ targetDate: full.targetDate ?? null,
80
+ url: full.url,
81
+ primaryTeam: primaryTeam ? { key: primaryTeam.key, name: primaryTeam.name } : null,
82
+ currentStatus: status
83
+ ? {
84
+ name: status.name,
85
+ type: status.type,
86
+ recommendedIssueState: recommended.state,
87
+ ...(recommended.warning ? { warning: recommended.warning } : {}),
88
+ }
89
+ : null,
90
+ validStates,
91
+ requiredLabels,
92
+ allowedLabelPrefixes: allowedPrefixes,
93
+ });
94
+ }));
95
+ projects
96
+ .command("create <name>")
97
+ .description("Create a new project")
98
+ .requiredOption("--team <team>", "Team name or key")
99
+ .option("--description <desc>", "Project description (markdown)")
100
+ .option("--priority <priority>", "Priority: 0=None, 1=Urgent, 2=High, 3=Medium, 4=Low")
101
+ .option("--lead <lead>", "Lead (name, email, or 'me')")
102
+ .option("--start-date <date>", "Start date (YYYY-MM-DD)")
103
+ .option("--target-date <date>", "Target date (YYYY-MM-DD)")
104
+ .option("--color <hex>", "Project color (hex)")
105
+ .option("--icon <emoji>", "Project icon (emoji)")
106
+ .action(handleAsyncCommand(async (name, opts) => {
107
+ const client = await getClient();
108
+ const [teamResult, leadResult] = await Promise.all([
109
+ resolveTeam(client, opts.team),
110
+ opts.lead ? resolveUser(client, opts.lead) : undefined,
111
+ ]);
112
+ const input = { name, teamIds: [teamResult.id] };
113
+ if (opts.description)
114
+ input.description = opts.description;
115
+ if (opts.priority) {
116
+ const priority = parsePriority(opts.priority);
117
+ if (priority !== undefined)
118
+ input.priority = priority;
119
+ }
120
+ if (leadResult)
121
+ input.leadId = leadResult.id;
122
+ if (opts.startDate)
123
+ input.startDate = parseDate(opts.startDate);
124
+ if (opts.targetDate)
125
+ input.targetDate = parseDate(opts.targetDate);
126
+ if (opts.color)
127
+ input.color = parseColor(opts.color);
128
+ if (opts.icon)
129
+ input.icon = opts.icon;
130
+ const payload = await client.createProject(input);
131
+ if (!payload.success)
132
+ throw new CliError("Failed to create project");
133
+ const created = await payload.project;
134
+ outputSuccess({
135
+ created: true,
136
+ project: created ? { id: created.id, name: created.name, url: created.url } : null,
137
+ });
138
+ }));
139
+ projects
140
+ .command("update <nameOrId>")
141
+ .description("Update an existing project")
142
+ .option("--name <name>", "New name")
143
+ .option("--description <desc>", "New description (markdown)")
144
+ .option("--priority <priority>", "New priority: 0-4")
145
+ .option("--lead <lead>", "New lead (name, email, 'me', or 'none')")
146
+ .option("--start-date <date>", "Start date (YYYY-MM-DD)")
147
+ .option("--target-date <date>", "Target date (YYYY-MM-DD)")
148
+ .option("--color <hex>", "Project color (hex)")
149
+ .option("--icon <emoji>", "Project icon (emoji)")
150
+ .option("--state <state>", "Project state (planned, started, paused, completed, canceled, backlog)")
151
+ .action(handleAsyncCommand(async (nameOrId, opts) => {
152
+ const client = await getClient();
153
+ const project = await resolveProject(client, nameOrId);
154
+ const update = {};
155
+ if (opts.name)
156
+ update.name = opts.name;
157
+ if (opts.description)
158
+ update.description = opts.description;
159
+ if (opts.priority) {
160
+ const priority = parsePriority(opts.priority);
161
+ if (priority !== undefined)
162
+ update.priority = priority;
163
+ }
164
+ if (opts.lead) {
165
+ if (opts.lead.toLowerCase() === "none") {
166
+ update.leadId = null;
167
+ }
168
+ else {
169
+ const user = await resolveUser(client, opts.lead);
170
+ update.leadId = user.id;
171
+ }
172
+ }
173
+ if (opts.startDate)
174
+ update.startDate = parseDate(opts.startDate);
175
+ if (opts.targetDate)
176
+ update.targetDate = parseDate(opts.targetDate);
177
+ if (opts.color)
178
+ update.color = parseColor(opts.color);
179
+ if (opts.icon)
180
+ update.icon = opts.icon;
181
+ if (opts.state) {
182
+ const status = await resolveProjectStatus(client, opts.state);
183
+ update.statusId = status.id;
184
+ }
185
+ requireNonEmptyUpdate(update);
186
+ const payload = await client.updateProject(project.id, update);
187
+ if (!payload.success)
188
+ throw new CliError("Failed to update project");
189
+ const updated = await payload.project;
190
+ outputSuccess({
191
+ updated: true,
192
+ project: updated ? { id: updated.id, name: updated.name, url: updated.url } : null,
193
+ });
194
+ }));
195
+ projects
196
+ .command("delete <nameOrId>")
197
+ .description("Archive a project (recoverable). Use --permanent --yes for irreversible delete.")
198
+ .option("--permanent", "Permanently delete (irreversible — requires --yes)")
199
+ .option("--yes", "Confirm permanent deletion")
200
+ .action(handleAsyncCommand(async (nameOrId, opts) => {
201
+ if (opts.permanent) {
202
+ requireYes(opts, `permanently delete project ${nameOrId}`);
203
+ }
204
+ const client = await getClient();
205
+ const project = await resolveProject(client, nameOrId);
206
+ if (opts.permanent) {
207
+ const payload = await client.deleteProject(project.id);
208
+ outputSuccess({ deleted: payload.success, name: project.name, permanent: true });
209
+ }
210
+ else {
211
+ const payload = await client.archiveProject(project.id);
212
+ outputSuccess({ archived: payload.success, name: project.name });
213
+ }
214
+ }));
215
+ projects
216
+ .command("restore <nameOrId>")
217
+ .description("Restore an archived project")
218
+ .action(handleAsyncCommand(async (nameOrId) => {
219
+ const client = await getClient();
220
+ const project = await resolveProject(client, nameOrId);
221
+ const payload = await client.unarchiveProject(project.id);
222
+ outputSuccess({ restored: payload.success, name: project.name });
223
+ }));
224
+ projects
225
+ .command("add-label <project> <label>")
226
+ .description("Attach a project label to a project (label is the ProjectLabel name or UUID)")
227
+ .action(handleAsyncCommand(async (projectArg, labelArg) => {
228
+ const client = await getClient();
229
+ const project = await resolveProject(client, projectArg);
230
+ const labelId = await resolveProjectLabelId(client, labelArg);
231
+ const payload = await client.projectAddLabel(project.id, labelId);
232
+ outputSuccess({ added: payload.success, project: project.name, labelId });
233
+ }));
234
+ projects
235
+ .command("remove-label <project> <label>")
236
+ .description("Detach a project label from a project (label is the ProjectLabel name or UUID)")
237
+ .action(handleAsyncCommand(async (projectArg, labelArg) => {
238
+ const client = await getClient();
239
+ const project = await resolveProject(client, projectArg);
240
+ const labelId = await resolveProjectLabelId(client, labelArg);
241
+ const payload = await client.projectRemoveLabel(project.id, labelId);
242
+ outputSuccess({ removed: payload.success, project: project.name, labelId });
243
+ }));
244
+ }
245
+ async function resolveProjectLabelId(client, nameOrId) {
246
+ if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(nameOrId)) {
247
+ return nameOrId;
248
+ }
249
+ const lower = nameOrId.toLowerCase();
250
+ let cursor = await client.projectLabels({ first: 250 });
251
+ while (true) {
252
+ const match = cursor.nodes.find((l) => l.name.toLowerCase() === lower);
253
+ if (match)
254
+ return match.id;
255
+ if (!cursor.pageInfo.hasNextPage)
256
+ break;
257
+ cursor = await cursor.fetchNext();
258
+ }
259
+ throw new CliError(`Project label not found: ${nameOrId}`, {
260
+ suggestion: "Run `elnora-linear project-labels list` to see available labels.",
261
+ });
262
+ }
263
+ //# sourceMappingURL=projects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/commands/projects.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,EAAE;AACF,6EAA6E;AAC7E,6EAA6E;AAC7E,6EAA6E;AAC7E,2EAA2E;AAI3E,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACvE,OAAO,EACN,QAAQ,EACR,kBAAkB,EAClB,UAAU,EACV,SAAS,EACT,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,yBAAyB,EACzB,qBAAqB,EACrB,UAAU,EACV,cAAc,EACd,oBAAoB,EACpB,WAAW,EACX,WAAW,GACX,MAAM,mBAAmB,CAAC;AAK3B,MAAM,UAAU,oBAAoB,CAAC,OAAgB;IACpD,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,WAAW,CAAC,wBAAwB,CAAC,CAAC;IAEnF,QAAQ;SACN,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,eAAe,CAAC;SAC5B,MAAM,CAAC,eAAe,EAAE,gBAAgB,CAAC;SACzC,MAAM,CAAC,iBAAiB,EAAE,yEAAyE,CAAC;SACpG,MAAM,CAAC,aAAa,EAAE,aAAa,EAAE,KAAK,CAAC;SAC3C,MAAM,CACN,kBAAkB,CAAC,KAAK,EAAE,IAA4B,EAAE,EAAE;QACzD,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,MAAM,GAA4B,EAAE,CAAC;QAE3C,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAChB,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC9B,MAAM,CAAC,MAAM,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC;QAC9C,CAAC;QAED,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACf,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;YAClD,MAAM,CAAC,eAAe,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC;QAClD,CAAC;QAYD,MAAM,GAAG,GAAG,MAAM,UAAU,CAC3B;;;;;;;;YAQO,EACP,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAC9C,CAAC;QACF,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;YAChB,MAAM,IAAI,QAAQ,CAAC,kBAAkB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrF,CAAC;QACD,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACzD,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,IAAI,IAAI;YAC1B,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,UAAU,EAAE,CAAC,CAAC,UAAU;YACxB,GAAG,EAAE,CAAC,CAAC,GAAG;SACV,CAAC,CAAC,CAAC;QACJ,aAAa,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACvD,CAAC,CAAC,CACF,CAAC;IAEH,QAAQ;SACN,OAAO,CAAC,gBAAgB,CAAC;SACzB,WAAW,CACX,4GAA4G,CAC5G;SACA,MAAM,CACN,kBAAkB,CAAC,KAAK,EAAE,QAAgB,EAAE,EAAE;QAC7C,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACvD,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAE9C,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAE5F,MAAM,WAAW,GAAG,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;QAElD,MAAM,UAAU,GAAG,WAAW;YAC7B,CAAC,CAAC,MAAM,MAAM,CAAC,cAAc,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,WAAW,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;YAC/F,CAAC,CAAC,IAAI,CAAC;QAER,MAAM,WAAW,GAAG,UAAU,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAE1F,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC,kBAAkB,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC7E,MAAM,cAAc,GAAG,WAAW,EAAE,QAAQ,IAAI,EAAE,CAAC;QACnD,MAAM,eAAe,GAAG,WAAW,EAAE,eAAe,IAAI,EAAE,CAAC;QAE3D,MAAM,WAAW,GAAG,yBAAyB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAE5D,aAAa,CAAC;YACb,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,IAAI;YACrC,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,IAAI,EAAE,IAAI,EAAE,IAAI,IAAI,IAAI;YACxB,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,IAAI;YACjC,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,IAAI;YACnC,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,WAAW,CAAC,GAAG,EAAE,IAAI,EAAE,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI;YAClF,aAAa,EAAE,MAAM;gBACpB,CAAC,CAAC;oBACA,IAAI,EAAE,MAAM,CAAC,IAAI;oBACjB,IAAI,EAAE,MAAM,CAAC,IAAI;oBACjB,qBAAqB,EAAE,WAAW,CAAC,KAAK;oBACxC,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBAChE;gBACF,CAAC,CAAC,IAAI;YACP,WAAW;YACX,cAAc;YACd,oBAAoB,EAAE,eAAe;SACrC,CAAC,CAAC;IACJ,CAAC,CAAC,CACF,CAAC;IAEH,QAAQ;SACN,OAAO,CAAC,eAAe,CAAC;SACxB,WAAW,CAAC,sBAAsB,CAAC;SACnC,cAAc,CAAC,eAAe,EAAE,kBAAkB,CAAC;SACnD,MAAM,CAAC,sBAAsB,EAAE,gCAAgC,CAAC;SAChE,MAAM,CAAC,uBAAuB,EAAE,qDAAqD,CAAC;SACtF,MAAM,CAAC,eAAe,EAAE,6BAA6B,CAAC;SACtD,MAAM,CAAC,qBAAqB,EAAE,yBAAyB,CAAC;SACxD,MAAM,CAAC,sBAAsB,EAAE,0BAA0B,CAAC;SAC1D,MAAM,CAAC,eAAe,EAAE,qBAAqB,CAAC;SAC9C,MAAM,CAAC,gBAAgB,EAAE,sBAAsB,CAAC;SAChD,MAAM,CACN,kBAAkB,CAAC,KAAK,EAAE,IAAY,EAAE,IAA4B,EAAE,EAAE;QACvE,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,CAAC,UAAU,EAAE,UAAU,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAClD,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC;YAC9B,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;SACtD,CAAC,CAAC;QAEH,MAAM,KAAK,GAAuB,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC;QACrE,IAAI,IAAI,CAAC,WAAW;YAAE,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;QAC3D,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC9C,IAAI,QAAQ,KAAK,SAAS;gBAAE,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACvD,CAAC;QACD,IAAI,UAAU;YAAE,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC,EAAE,CAAC;QAC7C,IAAI,IAAI,CAAC,SAAS;YAAE,KAAK,CAAC,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAChE,IAAI,IAAI,CAAC,UAAU;YAAE,KAAK,CAAC,UAAU,GAAG,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACnE,IAAI,IAAI,CAAC,KAAK;YAAE,KAAK,CAAC,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrD,IAAI,IAAI,CAAC,IAAI;YAAE,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QAEtC,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAClD,IAAI,CAAC,OAAO,CAAC,OAAO;YAAE,MAAM,IAAI,QAAQ,CAAC,0BAA0B,CAAC,CAAC;QACrE,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC;QACtC,aAAa,CAAC;YACb,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI;SAClF,CAAC,CAAC;IACJ,CAAC,CAAC,CACF,CAAC;IAEH,QAAQ;SACN,OAAO,CAAC,mBAAmB,CAAC;SAC5B,WAAW,CAAC,4BAA4B,CAAC;SACzC,MAAM,CAAC,eAAe,EAAE,UAAU,CAAC;SACnC,MAAM,CAAC,sBAAsB,EAAE,4BAA4B,CAAC;SAC5D,MAAM,CAAC,uBAAuB,EAAE,mBAAmB,CAAC;SACpD,MAAM,CAAC,eAAe,EAAE,yCAAyC,CAAC;SAClE,MAAM,CAAC,qBAAqB,EAAE,yBAAyB,CAAC;SACxD,MAAM,CAAC,sBAAsB,EAAE,0BAA0B,CAAC;SAC1D,MAAM,CAAC,eAAe,EAAE,qBAAqB,CAAC;SAC9C,MAAM,CAAC,gBAAgB,EAAE,sBAAsB,CAAC;SAChD,MAAM,CAAC,iBAAiB,EAAE,wEAAwE,CAAC;SACnG,MAAM,CACN,kBAAkB,CAAC,KAAK,EAAE,QAAgB,EAAE,IAA4B,EAAE,EAAE;QAC3E,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACvD,MAAM,MAAM,GAAgC,EAAE,CAAC;QAC/C,IAAI,IAAI,CAAC,IAAI;YAAE,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACvC,IAAI,IAAI,CAAC,WAAW;YAAE,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;QAC5D,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC9C,IAAI,QAAQ,KAAK,SAAS;gBAAE,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACxD,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACf,IAAI,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,MAAM,EAAE,CAAC;gBACxC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC;YACtB,CAAC;iBAAM,CAAC;gBACP,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;gBAClD,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;YACzB,CAAC;QACF,CAAC;QACD,IAAI,IAAI,CAAC,SAAS;YAAE,MAAM,CAAC,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACjE,IAAI,IAAI,CAAC,UAAU;YAAE,MAAM,CAAC,UAAU,GAAG,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACpE,IAAI,IAAI,CAAC,KAAK;YAAE,MAAM,CAAC,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtD,IAAI,IAAI,CAAC,IAAI;YAAE,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACvC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAChB,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;YAC7D,MAAkC,CAAC,QAAQ,GAAG,MAAM,CAAC,EAAE,CAAC;QAC1D,CAAC;QACD,qBAAqB,CAAC,MAAiC,CAAC,CAAC;QACzD,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,EAAE,MAA4B,CAAC,CAAC;QACrF,IAAI,CAAC,OAAO,CAAC,OAAO;YAAE,MAAM,IAAI,QAAQ,CAAC,0BAA0B,CAAC,CAAC;QACrE,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC;QACtC,aAAa,CAAC;YACb,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI;SAClF,CAAC,CAAC;IACJ,CAAC,CAAC,CACF,CAAC;IAEH,QAAQ;SACN,OAAO,CAAC,mBAAmB,CAAC;SAC5B,WAAW,CAAC,iFAAiF,CAAC;SAC9F,MAAM,CAAC,aAAa,EAAE,oDAAoD,CAAC;SAC3E,MAAM,CAAC,OAAO,EAAE,4BAA4B,CAAC;SAC7C,MAAM,CACN,kBAAkB,CAAC,KAAK,EAAE,QAAgB,EAAE,IAAsC,EAAE,EAAE;QACrF,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACpB,UAAU,CAAC,IAAI,EAAE,8BAA8B,QAAQ,EAAE,CAAC,CAAC;QAC5D,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACvD,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACpB,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YACvD,aAAa,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAClF,CAAC;aAAM,CAAC;YACP,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YACxD,aAAa,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QAClE,CAAC;IACF,CAAC,CAAC,CACF,CAAC;IAEH,QAAQ;SACN,OAAO,CAAC,oBAAoB,CAAC;SAC7B,WAAW,CAAC,6BAA6B,CAAC;SAC1C,MAAM,CACN,kBAAkB,CAAC,KAAK,EAAE,QAAgB,EAAE,EAAE;QAC7C,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACvD,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC1D,aAAa,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAClE,CAAC,CAAC,CACF,CAAC;IAEH,QAAQ;SACN,OAAO,CAAC,6BAA6B,CAAC;SACtC,WAAW,CAAC,8EAA8E,CAAC;SAC3F,MAAM,CACN,kBAAkB,CAAC,KAAK,EAAE,UAAkB,EAAE,QAAgB,EAAE,EAAE;QACjE,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QACzD,MAAM,OAAO,GAAG,MAAM,qBAAqB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC9D,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAClE,aAAa,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAC3E,CAAC,CAAC,CACF,CAAC;IAEH,QAAQ;SACN,OAAO,CAAC,gCAAgC,CAAC;SACzC,WAAW,CAAC,gFAAgF,CAAC;SAC7F,MAAM,CACN,kBAAkB,CAAC,KAAK,EAAE,UAAkB,EAAE,QAAgB,EAAE,EAAE;QACjE,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QACzD,MAAM,OAAO,GAAG,MAAM,qBAAqB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC9D,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QACrE,aAAa,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAC7E,CAAC,CAAC,CACF,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,qBAAqB,CAAC,MAAoB,EAAE,QAAgB;IAC1E,IAAI,iEAAiE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QACtF,OAAO,QAAQ,CAAC;IACjB,CAAC;IACD,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IACrC,IAAI,MAAM,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;IACxD,OAAO,IAAI,EAAE,CAAC;QACb,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC,CAAC;QACvE,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC,EAAE,CAAC;QAC3B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW;YAAE,MAAM;QACxC,MAAM,GAAG,MAAM,MAAM,CAAC,SAAS,EAAE,CAAC;IACnC,CAAC;IACD,MAAM,IAAI,QAAQ,CAAC,4BAA4B,QAAQ,EAAE,EAAE;QAC1D,UAAU,EAAE,kEAAkE;KAC9E,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from "commander";
2
+ export declare function setupQuotaCommand(program: Command): void;
3
+ //# sourceMappingURL=quota.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quota.d.ts","sourceRoot":"","sources":["../../src/commands/quota.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIzC,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsBxD"}
@@ -0,0 +1,28 @@
1
+ // `elnora-linear quota` — show remaining Linear API rate-limit budget.
2
+ //
3
+ // Wraps the SDK's rateLimitStatus query so callers can check headroom before
4
+ // running large bulk operations or long-lived scripts.
5
+ import { getClient } from "../client/index.js";
6
+ import { handleAsyncCommand, outputSuccess } from "../output/index.js";
7
+ export function setupQuotaCommand(program) {
8
+ program
9
+ .command("quota")
10
+ .description("Show remaining Linear API rate-limit budget")
11
+ .action(handleAsyncCommand(async () => {
12
+ const client = await getClient();
13
+ const payload = await client.rateLimitStatus;
14
+ outputSuccess({
15
+ identifier: payload.identifier ?? null,
16
+ kind: payload.kind,
17
+ limits: payload.limits.map((l) => ({
18
+ type: l.type,
19
+ allowed: l.allowedAmount,
20
+ remaining: l.remainingAmount,
21
+ requested: l.requestedAmount,
22
+ periodMs: l.period,
23
+ resetAt: new Date(l.reset).toISOString(),
24
+ })),
25
+ });
26
+ }));
27
+ }
28
+ //# sourceMappingURL=quota.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quota.js","sourceRoot":"","sources":["../../src/commands/quota.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,EAAE;AACF,6EAA6E;AAC7E,uDAAuD;AAGvD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEvE,MAAM,UAAU,iBAAiB,CAAC,OAAgB;IACjD,OAAO;SACL,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,6CAA6C,CAAC;SAC1D,MAAM,CACN,kBAAkB,CAAC,KAAK,IAAI,EAAE;QAC7B,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC;QAC7C,aAAa,CAAC;YACb,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,IAAI;YACtC,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAClC,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,OAAO,EAAE,CAAC,CAAC,aAAa;gBACxB,SAAS,EAAE,CAAC,CAAC,eAAe;gBAC5B,SAAS,EAAE,CAAC,CAAC,eAAe;gBAC5B,QAAQ,EAAE,CAAC,CAAC,MAAM;gBAClB,OAAO,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE;aACxC,CAAC,CAAC;SACH,CAAC,CAAC;IACJ,CAAC,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { LinearClient } from "@linear/sdk";
2
+ import type { Command } from "commander";
3
+ type ReactionCreateInput = Parameters<LinearClient["createReaction"]>[0];
4
+ export declare function buildReactionInput(target: string, emoji: string, isIssue: boolean): ReactionCreateInput;
5
+ export declare function setupReactionsCommand(program: Command): void;
6
+ export {};
7
+ //# sourceMappingURL=reactions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reactions.d.ts","sourceRoot":"","sources":["../../src/commands/reactions.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKzC,KAAK,mBAAmB,GAAG,UAAU,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAEzE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,mBAAmB,CAcvG;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAgC5D"}
@@ -0,0 +1,53 @@
1
+ // `elnora-linear react` / `unreact` — top-level emoji reaction shortcuts.
2
+ //
3
+ // Linear's ReactionCreateInput accepts issueId in either UUID or "ENG-123"
4
+ // form, so we don't need to resolve issue identifiers ourselves. Comments
5
+ // require UUIDs. Use --issue to force the issue interpretation when the
6
+ // target is a UUID (issue UUIDs and comment UUIDs share the same shape).
7
+ import { getClient } from "../client/index.js";
8
+ import { handleAsyncCommand, outputSuccess } from "../output/index.js";
9
+ import { CliError, isUUID, ValidationError } from "../utils/index.js";
10
+ export function buildReactionInput(target, emoji, isIssue) {
11
+ if (!emoji) {
12
+ throw new ValidationError("Emoji is required.");
13
+ }
14
+ if (/^[A-Za-z]+-\d+$/.test(target)) {
15
+ if (isIssue) {
16
+ process.stderr.write(`Warning: --issue is implied for issue identifier "${target}" — flag has no effect.\n`);
17
+ }
18
+ return { emoji, issueId: target };
19
+ }
20
+ if (!isUUID(target)) {
21
+ throw new ValidationError(`Invalid target: "${target}". Use an issue identifier (ENG-123) or a UUID.`);
22
+ }
23
+ return isIssue ? { emoji, issueId: target } : { emoji, commentId: target };
24
+ }
25
+ export function setupReactionsCommand(program) {
26
+ program
27
+ .command("react <target> <emoji>")
28
+ .description("Add an emoji reaction. Target = ENG-123 (issue) or comment UUID. Use --issue to force issue when target is a UUID.")
29
+ .option("--issue", "Treat the UUID target as an issue (default: comment)")
30
+ .action(handleAsyncCommand(async (target, emoji, opts) => {
31
+ const client = await getClient();
32
+ const input = buildReactionInput(target, emoji, Boolean(opts.issue));
33
+ const payload = await client.createReaction(input);
34
+ if (!payload.success)
35
+ throw new CliError("Failed to create reaction");
36
+ const reaction = await payload.reaction;
37
+ outputSuccess({
38
+ created: true,
39
+ reaction: reaction ? { id: reaction.id, emoji: reaction.emoji } : null,
40
+ });
41
+ }));
42
+ program
43
+ .command("unreact <reactionId>")
44
+ .description("Remove a reaction by its id")
45
+ .action(handleAsyncCommand(async (reactionId) => {
46
+ const client = await getClient();
47
+ const payload = await client.deleteReaction(reactionId);
48
+ if (!payload.success)
49
+ throw new CliError("Failed to delete reaction");
50
+ outputSuccess({ deleted: true, id: reactionId });
51
+ }));
52
+ }
53
+ //# sourceMappingURL=reactions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reactions.js","sourceRoot":"","sources":["../../src/commands/reactions.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,EAAE;AACF,2EAA2E;AAC3E,0EAA0E;AAC1E,wEAAwE;AACxE,yEAAyE;AAIzE,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACvE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAItE,MAAM,UAAU,kBAAkB,CAAC,MAAc,EAAE,KAAa,EAAE,OAAgB;IACjF,IAAI,CAAC,KAAK,EAAE,CAAC;QACZ,MAAM,IAAI,eAAe,CAAC,oBAAoB,CAAC,CAAC;IACjD,CAAC;IACD,IAAI,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACpC,IAAI,OAAO,EAAE,CAAC;YACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,qDAAqD,MAAM,2BAA2B,CAAC,CAAC;QAC9G,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IACnC,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,eAAe,CAAC,oBAAoB,MAAM,iDAAiD,CAAC,CAAC;IACxG,CAAC;IACD,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACrD,OAAO;SACL,OAAO,CAAC,wBAAwB,CAAC;SACjC,WAAW,CACX,oHAAoH,CACpH;SACA,MAAM,CAAC,SAAS,EAAE,sDAAsD,CAAC;SACzE,MAAM,CACN,kBAAkB,CAAC,KAAK,EAAE,MAAc,EAAE,KAAa,EAAE,IAA6B,EAAE,EAAE;QACzF,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,kBAAkB,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QACrE,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QACnD,IAAI,CAAC,OAAO,CAAC,OAAO;YAAE,MAAM,IAAI,QAAQ,CAAC,2BAA2B,CAAC,CAAC;QACtE,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC;QACxC,aAAa,CAAC;YACb,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI;SACtE,CAAC,CAAC;IACJ,CAAC,CAAC,CACF,CAAC;IAEH,OAAO;SACL,OAAO,CAAC,sBAAsB,CAAC;SAC/B,WAAW,CAAC,6BAA6B,CAAC;SAC1C,MAAM,CACN,kBAAkB,CAAC,KAAK,EAAE,UAAkB,EAAE,EAAE;QAC/C,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;QACxD,IAAI,CAAC,OAAO,CAAC,OAAO;YAAE,MAAM,IAAI,QAAQ,CAAC,2BAA2B,CAAC,CAAC;QACtE,aAAa,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;IAClD,CAAC,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from "commander";
2
+ export declare function setupRelationsCommand(program: Command): void;
3
+ //# sourceMappingURL=relations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relations.d.ts","sourceRoot":"","sources":["../../src/commands/relations.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOzC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA0E5D"}
@@ -0,0 +1,73 @@
1
+ // `elnora-linear relations` — manage IssueRelation edges between issues.
2
+ // Supports "related", "blocks", "duplicate", "similar".
3
+ import { IssueRelationType } from "@linear/sdk";
4
+ import { getClient } from "../client/index.js";
5
+ import { handleAsyncCommand, outputSuccess } from "../output/index.js";
6
+ import { CliError, findIssueByIdentifier, requireYes } from "../utils/index.js";
7
+ const VALID_TYPES = Object.values(IssueRelationType);
8
+ export function setupRelationsCommand(program) {
9
+ const relations = program
10
+ .command("relations")
11
+ .description("Manage issue relations (related, blocks, duplicate, similar)");
12
+ relations
13
+ .command("create <issueId> <relatedIssueId>")
14
+ .description("Create a relation between two issues")
15
+ .option("--type <type>", `Relation type: ${VALID_TYPES.join(", ")}`, "related")
16
+ .action(handleAsyncCommand(async (issueId, relatedIssueId, opts) => {
17
+ const client = await getClient();
18
+ if (!VALID_TYPES.includes(opts.type)) {
19
+ throw new CliError(`Invalid relation type: ${opts.type}. Valid types: ${VALID_TYPES.join(", ")}`);
20
+ }
21
+ const [issue, relatedIssue] = await Promise.all([
22
+ findIssueByIdentifier(client, issueId),
23
+ findIssueByIdentifier(client, relatedIssueId),
24
+ ]);
25
+ const payload = await client.createIssueRelation({
26
+ issueId: issue.id,
27
+ relatedIssueId: relatedIssue.id,
28
+ type: opts.type,
29
+ });
30
+ if (!payload.success)
31
+ throw new CliError("Failed to create issue relation");
32
+ const relation = await payload.issueRelation;
33
+ outputSuccess({
34
+ created: true,
35
+ relation: relation
36
+ ? {
37
+ id: relation.id,
38
+ type: relation.type,
39
+ issueId: issue.identifier,
40
+ relatedIssueId: relatedIssue.identifier,
41
+ }
42
+ : null,
43
+ });
44
+ }));
45
+ relations
46
+ .command("list <issueId>")
47
+ .description("List all relations for an issue")
48
+ .action(handleAsyncCommand(async (issueId) => {
49
+ const client = await getClient();
50
+ const issue = await findIssueByIdentifier(client, issueId);
51
+ const relationsConn = await issue.relations();
52
+ const result = await Promise.all(relationsConn.nodes.map(async (r) => {
53
+ const related = await r.relatedIssue;
54
+ return {
55
+ id: r.id,
56
+ type: r.type,
57
+ relatedIssue: related ? { identifier: related.identifier, title: related.title } : null,
58
+ };
59
+ }));
60
+ outputSuccess({ relations: result, count: result.length });
61
+ }));
62
+ relations
63
+ .command("delete <relationId>")
64
+ .description("Delete an issue relation by its UUID (irreversible — requires --yes)")
65
+ .option("--yes", "Confirm deletion")
66
+ .action(handleAsyncCommand(async (relationId, opts) => {
67
+ requireYes(opts, `delete issue relation ${relationId}`);
68
+ const client = await getClient();
69
+ const payload = await client.deleteIssueRelation(relationId);
70
+ outputSuccess({ deleted: payload.success });
71
+ }));
72
+ }
73
+ //# sourceMappingURL=relations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relations.js","sourceRoot":"","sources":["../../src/commands/relations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from "commander";
2
+ export declare function setupStatesCommand(program: Command): void;
3
+ //# sourceMappingURL=states.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"states.d.ts","sourceRoot":"","sources":["../../src/commands/states.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKzC,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAmDzD"}