@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,56 @@
1
+ # Workspace Projects — Documentation Template
2
+
3
+ A schema you can fill in to document your projects per team. Pair this with `projects.json` (the machine-readable copy that the CLI consumes via `sync` and `context`).
4
+
5
+ Load this file when you need full project context that doesn't fit on a `context --team` summary. Agents normally do not read it.
6
+
7
+ ## Projects by Team and Status
8
+
9
+ ### `<Team-1>`
10
+
11
+ #### In Progress
12
+ | Project | Priority | Lead | Purpose |
13
+ |---------|----------|------|---------|
14
+ | `<Project name>` | `<Urgent|High|Normal|Low>` | `<lead>` | `<one-line purpose>` |
15
+
16
+ #### Planned
17
+ | Project | Priority | Lead | Purpose |
18
+ |---------|----------|------|---------|
19
+
20
+ #### Backlog
21
+ | Project | Priority | Lead | Purpose |
22
+ |---------|----------|------|---------|
23
+
24
+ #### Completed
25
+ | Project | Priority | Lead | Purpose |
26
+ |---------|----------|------|---------|
27
+
28
+ #### Canceled
29
+ | Project | Priority | Lead | Purpose |
30
+ |---------|----------|------|---------|
31
+
32
+ ---
33
+
34
+ ### `<Team-2>`
35
+
36
+ (same structure)
37
+
38
+ ---
39
+
40
+ ## Compliance workflow projects
41
+
42
+ If you use the bundled compliance templates (see `template-index.md`), each template usually maps to its own project so the audit trail is easy to find. Typical names:
43
+
44
+ - User Onboarding / Offboarding
45
+ - Access Provisioning / Revocation / Reviews / Privileged Access
46
+ - Standard / Significant / Major Changes
47
+ - Security Incidents / Vulnerability Management / Pentest Remediation
48
+ - Availability Incidents / Operational Requests
49
+ - Root Cause Analysis / Lessons Learned / Corrective Actions
50
+ - Internal Audits / Management Reviews
51
+ - Risk Assessments / Vendor Assessments
52
+ - AI Governance / Backup & DR Testing / Data Modifications
53
+
54
+ ---
55
+
56
+ *Routing keywords: `workspace-routing.md` | Labels: `workspace-labels.md` | Run `elnora-linear sync all` to refresh the JSON references from Linear.*
@@ -0,0 +1,58 @@
1
+ # Workspace Routing
2
+
3
+ Schema/template for documenting how your workspace's teams + projects + labels map to your work intake. Replace the examples below with your own workspace structure; populate `teams.json`, `projects.json`, and `label-policy.json` with the underlying machine-readable data.
4
+
5
+ ## Teams (example)
6
+
7
+ | Team | Prefix | Use For |
8
+ |------|--------|---------|
9
+ | **Engineering** | ENG- | Customer-facing product code, features, bugs |
10
+ | **Operations** | OPS- | Internal: tooling, compliance docs, HR, access management |
11
+ | **Security** | SEC- | CVE/vulnerability remediation, pentest findings, incidents (not security features) |
12
+ | **Customer Success** | CUS- | Customer support, onboarding, client feedback |
13
+
14
+ ## Routing Keywords (example)
15
+
16
+ | Keywords | Route To |
17
+ |----------|----------|
18
+ | feature, bug, build, implement, develop, code, product, ship, api, ui | **Engineering** |
19
+ | vulnerability, CVE, CodeQL, dependabot, pentest finding, patch, security incident | **Security** |
20
+ | internal tooling, internal infrastructure, dev environment, plugin, marketplace, cli setup | **Operations** |
21
+ | document, record, audit, review completed, change approved, compliance | **Operations** |
22
+ | onboarding, offboarding, access provision, access revoke, quarterly review | **Operations** |
23
+ | change request, policy change, procedure change, ISMS change | **Operations** |
24
+ | internal audit, management review, corrective action, risk assessment | **Operations** |
25
+ | AI use case, AI capability scope, model family change, foundation model swap, AI governance | **Operations** |
26
+ | hr, admin, process improvement, team operations, company operations | **Operations** |
27
+ | customer, support request, user reported, client feedback, customer onboarding | **Customer Success** |
28
+
29
+ **Default:** Engineering
30
+
31
+ ## Project Keywords (schema)
32
+
33
+ Each project belongs to a specific team. Document yours in `workspace-projects.md` and keep the underlying mapping in `projects.json`.
34
+
35
+ | Project | Keywords | Team |
36
+ |---------|----------|------|
37
+ | `<Project name>` | `<keyword1>, <keyword2>, ...` | `<team>` |
38
+
39
+ ## State Mapping (example)
40
+
41
+ | Project Status | Issue State |
42
+ |----------------|-------------|
43
+ | In Progress | Todo |
44
+ | Planned | Todo |
45
+ | Backlog | Backlog |
46
+
47
+ (see `recommendedStateForStatus` in the CLI; this table is the human-readable version of that logic.)
48
+
49
+ ## Assignees
50
+
51
+ Document your team's assignment rules here. Common patterns:
52
+
53
+ - Map roles to default assignees (e.g. "platform code → Platform lead").
54
+ - Rule of thumb: ASK the user for an assignee if not specified — defaults can silently route to the wrong person.
55
+
56
+ ---
57
+
58
+ *Projects: `workspace-projects.md` | Labels: `workspace-labels.md` | Run `elnora-linear sync all` to refresh JSON references from Linear.*
@@ -0,0 +1,72 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/Elnora-AI/elnora-linear/blob/main/schemas/label-policy.json",
4
+ "title": "Label Policy",
5
+ "description": "Per-team required-label rules. Read by `issues create`, `issues update`, and `context` to surface required labels + enforce them at write time. Keyed by team key.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "$schema": { "type": "string" },
10
+ "_placeholder": { "type": "boolean", "const": true },
11
+ "_example": { "type": "boolean", "const": true },
12
+ "_populated_by": { "type": "string" },
13
+ "policies": {
14
+ "type": "object",
15
+ "description": "Map of team key → policy. Keys are uppercase Linear team keys (e.g. ENG).",
16
+ "patternProperties": {
17
+ "^[A-Z][A-Z0-9]*$": {
18
+ "type": "object",
19
+ "additionalProperties": false,
20
+ "required": ["name", "required", "allowedPrefixes"],
21
+ "properties": {
22
+ "name": {
23
+ "type": "string",
24
+ "minLength": 1,
25
+ "description": "Human-readable team name (informational; the key is canonical)."
26
+ },
27
+ "required": {
28
+ "type": "array",
29
+ "description": "List of required label-prefix groups; each group must be satisfied for a write to succeed.",
30
+ "items": {
31
+ "type": "object",
32
+ "additionalProperties": false,
33
+ "required": ["prefixes", "min"],
34
+ "properties": {
35
+ "prefixes": {
36
+ "type": "array",
37
+ "items": { "type": "string", "minLength": 1 },
38
+ "description": "Any label whose name starts with one of these prefixes counts toward this group."
39
+ },
40
+ "min": {
41
+ "type": "integer",
42
+ "minimum": 0,
43
+ "description": "Minimum total label count across the listed prefixes."
44
+ },
45
+ "max": {
46
+ "type": ["integer", "null"],
47
+ "description": "Maximum total count, or null for no upper bound."
48
+ },
49
+ "description": {
50
+ "type": "string",
51
+ "description": "Human-readable hint surfaced in error responses."
52
+ }
53
+ }
54
+ }
55
+ },
56
+ "allowedPrefixes": {
57
+ "type": "array",
58
+ "items": { "type": "string" },
59
+ "description": "Master list of label prefixes valid for this team. Used for grouping in context responses."
60
+ },
61
+ "requiresProject": {
62
+ "type": "boolean",
63
+ "description": "If true (default), every new issue on this team must have a project set; `issues create` exits 2 with a structured ProjectValidationError when --project is omitted. Set false to allow issues without a project. Teams with zero projects available auto-pass regardless. Bypass per-call with --skip-project-check."
64
+ }
65
+ }
66
+ }
67
+ },
68
+ "additionalProperties": false
69
+ }
70
+ },
71
+ "required": ["policies"]
72
+ }
@@ -0,0 +1,195 @@
1
+ #!/usr/bin/env node
2
+ // Postinstall hook for @elnora-ai/linear.
3
+ //
4
+ // Goal: after the user installs the package, automatically populate the
5
+ // reference files (teams/projects/users/workflows) from their Linear workspace
6
+ // so the agents and slash commands are personalised on first use — without
7
+ // requiring a manual `elnora-linear sync all` step.
8
+ //
9
+ // Behaviour:
10
+ // - If no API key is reachable, print a friendly notice telling the user how
11
+ // to enable the sync. Never block the install.
12
+ // - If a key is reachable (LINEAR_API_KEY env var, or already saved in
13
+ // ~/.config/elnora-linear/.env), run `sync all` with a hard timeout.
14
+ // Network/API failures degrade to a printed notice.
15
+ // - Always exits 0. A postinstall hook that fails the install is worse than
16
+ // no postinstall hook at all.
17
+ //
18
+ // Escape hatches (set any of these to skip the auto-sync entirely):
19
+ // - ELNORA_LINEAR_SKIP_POSTINSTALL=1
20
+ // - CI=true (most CI systems set this)
21
+ // - npm_config_global=false (local installs in a project)
22
+ //
23
+ // The "local install" skip prevents this from firing on every fresh
24
+ // node_modules in CI builds, monorepo workspaces, Docker layer caches, etc.
25
+ // Global installs (`npm install -g @elnora-ai/linear`) are the user-facing
26
+ // path we want to personalise.
27
+
28
+ import { spawn } from "node:child_process";
29
+ import { existsSync, readFileSync } from "node:fs";
30
+ import { homedir } from "node:os";
31
+ import { dirname, join } from "node:path";
32
+ import { fileURLToPath } from "node:url";
33
+
34
+ const __filename = fileURLToPath(import.meta.url);
35
+ const __dirname = dirname(__filename);
36
+ const PACKAGE_ROOT = dirname(__dirname);
37
+ const CLI_ENTRY = join(PACKAGE_ROOT, "dist", "cli.js");
38
+ const ENV_FILE = join(homedir(), ".config", "elnora-linear", ".env");
39
+
40
+ const SYNC_TIMEOUT_MS = 60_000;
41
+
42
+ const ESC = "\x1b[";
43
+ const useColor = () => process.stdout.isTTY && !process.env.NO_COLOR;
44
+ const COLORS = {
45
+ dim: (s) => (useColor() ? `${ESC}2m${s}${ESC}0m` : s),
46
+ yellow: (s) => (useColor() ? `${ESC}33m${s}${ESC}0m` : s),
47
+ green: (s) => (useColor() ? `${ESC}32m${s}${ESC}0m` : s),
48
+ cyan: (s) => (useColor() ? `${ESC}36m${s}${ESC}0m` : s),
49
+ };
50
+
51
+ function log(line) {
52
+ process.stdout.write(`${line}\n`);
53
+ }
54
+
55
+ export function shouldSkip(env = process.env) {
56
+ if (env.ELNORA_LINEAR_SKIP_POSTINSTALL === "1") {
57
+ return "ELNORA_LINEAR_SKIP_POSTINSTALL=1 is set";
58
+ }
59
+ if (env.CI === "true" || env.CI === "1") {
60
+ return "running in CI";
61
+ }
62
+ // npm sets npm_config_global=true for `-g` installs. Anything else (a local
63
+ // install, a yarn workspace, a pnpm dep resolution) skips. Note: npm sets
64
+ // the env var as a literal string.
65
+ if (env.npm_config_global !== undefined && env.npm_config_global !== "true") {
66
+ return "not a global install";
67
+ }
68
+ return null;
69
+ }
70
+
71
+ export function findApiKey(env = process.env, envFile = ENV_FILE) {
72
+ const raw = env.LINEAR_API_KEY?.trim().replace(/^["']|["']$/g, "");
73
+ if (raw?.startsWith("lin_api_")) {
74
+ return { source: "env", value: raw };
75
+ }
76
+ if (existsSync(envFile)) {
77
+ try {
78
+ const content = readFileSync(envFile, "utf8");
79
+ for (const line of content.split("\n")) {
80
+ const match = line.match(/^LINEAR_API_KEY\s*=\s*(.+?)\s*$/);
81
+ if (match) {
82
+ const value = match[1].replace(/^["']|["']$/g, "");
83
+ if (value.startsWith("lin_api_")) {
84
+ return { source: envFile, value };
85
+ }
86
+ }
87
+ }
88
+ } catch {
89
+ // Unreadable env file — fall through to no-key.
90
+ }
91
+ }
92
+ return null;
93
+ }
94
+
95
+ function printNoKeyNotice() {
96
+ log("");
97
+ log(COLORS.yellow("⚠ elnora-linear: could not personalise your Linear agents."));
98
+ log("");
99
+ log(" No Linear API key was found, so the reference files");
100
+ log(" (teams, projects, users, workflows) were not populated from");
101
+ log(" your Linear workspace.");
102
+ log("");
103
+ log(" To finish setup:");
104
+ log(` 1. Get a key at ${COLORS.cyan("https://linear.app/settings/api")}`);
105
+ log(` 2. ${COLORS.cyan("export LINEAR_API_KEY=lin_api_...")}`);
106
+ log(` 3. ${COLORS.cyan("elnora-linear sync all")}`);
107
+ log("");
108
+ log(COLORS.dim(" (Skip this notice with ELNORA_LINEAR_SKIP_POSTINSTALL=1.)"));
109
+ log("");
110
+ }
111
+
112
+ function printFailureNotice(reason) {
113
+ log("");
114
+ log(COLORS.yellow("⚠ elnora-linear: auto-sync did not complete."));
115
+ log(` ${reason}`);
116
+ log("");
117
+ log(` You can rerun it any time: ${COLORS.cyan("elnora-linear sync all")}`);
118
+ log("");
119
+ }
120
+
121
+ function printSuccessNotice() {
122
+ log("");
123
+ log(COLORS.green("✓ elnora-linear: reference files populated from your Linear workspace."));
124
+ log(COLORS.dim(" (teams, projects, users, workflows — refresh any time with `elnora-linear sync all`.)"));
125
+ log("");
126
+ }
127
+
128
+ function runSync(apiKey, cliEntry = CLI_ENTRY, timeoutMs = SYNC_TIMEOUT_MS) {
129
+ return new Promise((resolve) => {
130
+ if (!existsSync(cliEntry)) {
131
+ resolve({ ok: false, reason: `CLI entry not found at ${cliEntry}` });
132
+ return;
133
+ }
134
+ const child = spawn(process.execPath, [cliEntry, "sync", "all", "--output", "json"], {
135
+ env: { ...process.env, LINEAR_API_KEY: apiKey },
136
+ stdio: ["ignore", "pipe", "pipe"],
137
+ });
138
+ let stderr = "";
139
+ child.stderr.on("data", (chunk) => {
140
+ stderr += chunk.toString();
141
+ });
142
+ // Drain stdout so the child doesn't block on a full pipe buffer.
143
+ child.stdout.on("data", () => {});
144
+
145
+ const timer = setTimeout(() => {
146
+ child.kill("SIGTERM");
147
+ resolve({ ok: false, reason: `sync timed out after ${timeoutMs / 1000}s` });
148
+ }, timeoutMs);
149
+
150
+ child.on("error", (err) => {
151
+ clearTimeout(timer);
152
+ resolve({ ok: false, reason: err.message });
153
+ });
154
+ child.on("exit", (code) => {
155
+ clearTimeout(timer);
156
+ if (code === 0) {
157
+ resolve({ ok: true });
158
+ } else {
159
+ const tail = stderr.trim().split("\n").slice(-3).join(" | ") || `exit ${code}`;
160
+ resolve({ ok: false, reason: tail });
161
+ }
162
+ });
163
+ });
164
+ }
165
+
166
+ async function main() {
167
+ if (shouldSkip()) {
168
+ // Silent on skip — postinstall noise during CI/local installs is annoying.
169
+ return;
170
+ }
171
+
172
+ const key = findApiKey();
173
+ if (!key) {
174
+ printNoKeyNotice();
175
+ return;
176
+ }
177
+
178
+ const result = await runSync(key.value);
179
+ if (result.ok) {
180
+ printSuccessNotice();
181
+ } else {
182
+ printFailureNotice(result.reason);
183
+ }
184
+ }
185
+
186
+ // Only run when invoked directly (not when imported by tests).
187
+ const invokedDirectly = process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1];
188
+ if (invokedDirectly) {
189
+ main().catch((err) => {
190
+ // Truly defensive: any uncaught error must not fail the install.
191
+ printFailureNotice(err?.message ?? String(err));
192
+ });
193
+ }
194
+
195
+ export const _internal = { runSync, ENV_FILE, CLI_ENTRY };
@@ -28,9 +28,11 @@ Router for Linear work. Dispatches to specialized agents or slash commands rathe
28
28
  | Refresh reference data from Linear | Slash command: `/linear-sync` |
29
29
  | Run the curator (collect signals from external sources) | Slash command: `/linear-curator-run` |
30
30
 
31
+ For parallel work (e.g. 5 issues from 5 URLs), dispatch multiple agents in a single message — that's why they exist.
32
+
31
33
  ## First-run install
32
34
 
33
- 1. Install the plugin: `/plugin marketplace add Elnora-AI/elnora-linear` then `/plugin install linear-workspace@elnora-linear`
35
+ 1. `/plugin marketplace add Elnora-AI/elnora-linear` then `/plugin install linear-workspace@elnora-linear`
34
36
  2. Make sure the `elnora-linear` CLI is on your PATH: `npm install -g @elnora-ai/linear`
35
37
  3. On your first Linear command, you'll be prompted for your Linear API key (get one at https://linear.app/settings/api). It's saved to `~/.config/elnora-linear/.env` (mode 0600).
36
38
  4. Populate the reference files: `/linear-sync` (runs `elnora-linear sync all` — fetches teams, projects, users, workflows in one batch).
@@ -40,13 +42,72 @@ Router for Linear work. Dispatches to specialized agents or slash commands rathe
40
42
  The plugin reads user-specific config from `~/.config/elnora-linear/` by default (override via `LINEAR_REFERENCES_DIR`):
41
43
 
42
44
  - `teams.json`, `projects.json`, `users.json`, `workflows.json` — populated by `/linear-sync`
43
- - `slack.json`, `repos.json`, `signal-sources.json` — populated manually in v0; interactive prompts coming in a future release
45
+ - `slack.json`, `repos.json`, `signal-sources.json`, `label-policy.json` — populated manually (schemas in [`schemas/`](../../schemas/), examples in [`references/*.example.json`](../../references/))
44
46
 
45
47
  Run `elnora-linear sync verify` to see which are populated vs placeholder.
46
48
 
49
+ ## Dispatch prompt — what to include
50
+
51
+ 1. The user's raw request, verbatim
52
+ 2. Suspected team (let the agent confirm via `elnora-linear teams list`)
53
+ 3. Compliance flag (see below), if any
54
+ 4. Anything the user already specified (project, priority, assignee, due date)
55
+ 5. **If a URL appears anywhere in the request → dispatch to `linear-url-to-issues`**, not `linear-issue-creator`
56
+
57
+ The agent handles searching for duplicates, label requirements, state matching, and asking the user about anything unclear.
58
+
59
+ ### Fast-path saves tokens
60
+
61
+ The creator agent has a fast path that skips the dupe scan, project-status check, and reference reads when the dispatch already specifies team + project + priority + assignee + a clear novel title (and no compliance keywords). When you have all five, write them out explicitly in the prompt — the agent will detect the fast path and complete in roughly one CLI call instead of three.
62
+
63
+ ### Compliance flag
64
+
65
+ If the request mentions any of: **incident, breach, vulnerability, CVE, pentest, penetration test, onboarding, offboarding, access provision/revoke, audit, SOC 2, change request, risk assessment, vendor review, backup test, RCA, lessons learned, DPA, DSR / data subject request** — say so in the dispatch prompt. The agent will load `references/template-index.md` and apply the matching template (`SEC-*`, `CHG-*`, `ACC-*`, `AUD-*`, `RSK-*`, `OPS-*`, `SLA-*`, `RCA-*`, `LRN-*`).
66
+
67
+ ### Model tiering — pass `model:` on the Agent dispatch
68
+
69
+ Match the model to task complexity. The agent frontmatter sets the default; override per-dispatch when the task is clearly easier or harder. Haiku < Sonnet < Opus on cost AND token usage — Opus uses **more** tokens than Sonnet for the same task, not fewer. It's a quality escalation, never a token-saving move.
70
+
71
+ | Task | Agent | Model | Why |
72
+ |---|---|---|---|
73
+ | Fast-path create (all fields explicit, no compliance) | `linear-issue-creator` | `haiku` | Mechanical CRUD, single CLI call |
74
+ | Full-path create (ambiguous routing, dupe scan, compliance template) | `linear-issue-creator` | `sonnet` | Branching + judgment |
75
+ | Single-field update (state, assignee, priority, label add) | `linear-issue-updater` | `haiku` | One CLI call, fixed flag |
76
+ | Cross-team move, full description rewrite | `linear-issue-updater` | `sonnet` | Validates required labels across teams |
77
+ | URL → issues extraction | `linear-url-to-issues` | `sonnet` | Real synthesis from unstructured content |
78
+ | Issue completeness review | `linear-issue-reviewer` | `sonnet` | Reads description + comments + acceptance criteria |
79
+ | Headless curator pass (scheduled) | `linear-state-curator` | `haiku` | Mechanical signal collection + tier dispatch |
80
+ | Interactive curator dry-run / triage | `linear-state-curator` | `sonnet` | Reading curator-report.jsonl + judgment calls on MEDIUM queue |
81
+
82
+ Don't reach for Opus by default. Sonnet handles every Linear task cleanly. Only escalate to Opus if Sonnet has *actually failed* on this task type (looped, produced wrong output, gave up). If the request mentions a compliance keyword, upgrade the creator to Sonnet automatically.
83
+
84
+ ### Dispatch prompt budget
85
+
86
+ When the user request is fully specified, keep the dispatch prompt short — the agent already knows the playbook. Pass through:
87
+
88
+ - The user's raw request, verbatim
89
+ - Team / project / priority / assignee if explicit
90
+ - Compliance flag if relevant
91
+
92
+ Don't re-format the description, don't restate the playbook, don't tell the agent how to structure its output. A 100-token dispatch prompt is fine; a 500-token one wastes tokens with no quality gain.
93
+
94
+ ## Cold-start primitive
95
+
96
+ For workflows that need team metadata up front (e.g. extracting N issues from a URL into one team), the parent should suggest the agent call `elnora-linear context --team "<Team>"` ONCE before iterating. The response contains projects with statuses, workflow states, the full label catalog grouped by prefix, the required-label policy, and active members — replacing four separate calls (`teams get` + `projects list --team` + `states list --team` + `labels list --team`) and eliminating every reference-file read.
97
+
98
+ The CLI is the source of truth for label policy: `elnora-linear projects get` and `elnora-linear teams get` both return `requiredLabels` and `validStates` directly. `elnora-linear issues create` rejects invalid label combinations with a structured error (`missing`, `availableForPrefix`, `suggestedRetry`) so the agent can self-correct in one retry without reading any reference file.
99
+
47
100
  ## Safety guardrails
48
101
 
49
- - `bulk` and `cleanup` default to **dry-run**; they print what would change and require explicit `--yes` to commit
102
+ - `bulk` and `cleanup` default to **dry-run** they print what would change and require `--yes` to commit
50
103
  - `bulk` requires at least one of `--set-state` or `--add-comment` — refuses no-op invocations
51
104
  - `cleanup` defaults to `comment` action (least destructive); `close` / `cancel` are explicit opt-ins
52
- - `external_command` signal sources run user-configured commands with the user's privileges — only configure commands from sources the user trusts
105
+ - `external_command` signal sources run user-configured commands with the user's privileges — only configure commands from sources you trust
106
+ - Permanent deletes need an explicit `--yes` at the CLI layer — a prompt-injected agent cannot bypass it
107
+ - Full guarantees and gated commands documented in [SAFETY.md](../../SAFETY.md)
108
+
109
+ ## Don't
110
+
111
+ - Don't read reference `.md` files for label requirements — required-label policy is enforced server-side by the CLI
112
+ - Don't run the create/update workflow inline. The agent owns it.
113
+ - Don't pick a team without confirming via `elnora-linear teams list` or `references/teams.json`
@@ -0,0 +1,74 @@
1
+ # ACC-PRO: Access Provisioning
2
+
3
+ ## Quick Reference
4
+ - **SLA:** Same day
5
+ - **Team:** *the team that owns this workflow in your workspace*
6
+ - **Project:** Access Provisioning
7
+
8
+ ## Required Labels
9
+ - `Type: feature`
10
+ - `Account Setup` (7-day SLA)
11
+ - `Layer: devops`
12
+
13
+ ## Issue Template
14
+ ```markdown
15
+ ## Access Provisioning Request
16
+
17
+ **Request ID:** ACC-PRO-YYYY-XXX
18
+ **Request Date:** [YYYY-MM-DD]
19
+ **Required By Date:** [Start date - access cannot be granted earlier]
20
+
21
+ ## Employee/Contractor Information
22
+ - **Name:** [Full name]
23
+ - **Role/Title:** [Job title]
24
+ - **Department:** [Department/Team]
25
+ - **Manager:** [Manager name]
26
+ - **Employment Type:** [Employee / Contractor]
27
+ - **Start Date:** [YYYY-MM-DD]
28
+ - **End Date:** [If contractor - YYYY-MM-DD]
29
+
30
+ ## HR Verification Checklist
31
+ - [ ] Signed employment/contractor agreement received
32
+ - [ ] IP agreement signed
33
+ - [ ] Security policy acknowledgment signed
34
+ - [ ] Background check complete (if applicable)
35
+
36
+ ## Access Requirements
37
+
38
+ ### System Access
39
+ | System | Access Level | Justification | Data Owner Approval |
40
+ |--------|--------------|---------------|---------------------|
41
+ | Google Workspace | [Standard/Admin] | | [ ] |
42
+ | GitHub | [Read/Write/Admin] | | [ ] |
43
+ | AWS | [Specific roles] | | [ ] |
44
+ | Linear | [Member/Admin] | | [ ] |
45
+ | Slack | [Member] | | [ ] |
46
+ | [Other] | | | [ ] |
47
+
48
+ ### Privileged Access (if any)
49
+ [If elevated access needed, create linked ACC-PRV issue]
50
+
51
+ ## Segregation of Duties Check
52
+ - [ ] Verified no conflicting access combinations
53
+ - [ ] No violations of separation of duties policy
54
+
55
+ ## Approvals
56
+ - [ ] HR verification complete: _________________ Date: _______
57
+ - [ ] Manager approval: _________________ Date: _______
58
+ - [ ] System owner approval(s) obtained
59
+
60
+ ## Provisioning Checklist
61
+ - [ ] Google Workspace account created
62
+ - [ ] Added to appropriate Google Groups
63
+ - [ ] GitHub organization membership
64
+ - [ ] AWS IAM user/role configured
65
+ - [ ] MFA enrollment required/verified
66
+ - [ ] Linear workspace access
67
+ - [ ] Slack workspace access
68
+ - [ ] Welcome email sent with access instructions
69
+ - [ ] Security training assigned
70
+
71
+ ## Verification
72
+ - [ ] User confirmed access working
73
+ - [ ] Access logged in provisioning records
74
+ ```
@@ -0,0 +1,66 @@
1
+ # ACC-PRV: Privileged Access Request
2
+
3
+ ## Quick Reference
4
+ - **SLA:** Same day
5
+ - **Team:** *the team that owns this workflow in your workspace*
6
+ - **Project:** Privileged Access
7
+
8
+ ## Required Labels
9
+ - `Type: feature`
10
+ - `Flag: security`
11
+ - `Layer: devops`
12
+ - `Access Request`
13
+
14
+ ## Issue Template
15
+ ```markdown
16
+ ## Privileged Access Request
17
+
18
+ **Request ID:** ACC-PRV-YYYY-XXX
19
+ **Request Date:** [YYYY-MM-DD]
20
+ **Urgency:** [Urgent / Standard]
21
+
22
+ ## Requestor Information
23
+ - **Name:** [Full name]
24
+ - **Role:** [Job title]
25
+ - **Department:** [Team]
26
+ - **Manager:** [Manager name]
27
+
28
+ ## Access Details
29
+ - **System:** [System requiring privileged access]
30
+ - **Privilege Level:** [Specific privilege - admin, root, etc.]
31
+ - **Current Access:** [What access user currently has]
32
+ - **Requested Access:** [Specific new privileges needed]
33
+
34
+ ## Business Justification
35
+ [Detailed explanation of why privileged access is needed]
36
+
37
+ ## Duration
38
+ - **Access Type:** [Temporary / Permanent]
39
+ - **Start Date:** [YYYY-MM-DD]
40
+ - **End Date:** [YYYY-MM-DD or "Ongoing until role change"]
41
+ - **Revocation Trigger:** [What event should trigger access removal]
42
+
43
+ ## Competency Verification
44
+ - [ ] User has completed security training
45
+ - [ ] User understands privileged access responsibilities
46
+ - [ ] User acknowledges logging of all privileged actions
47
+
48
+ ## Security Requirements
49
+ - [ ] MFA will be configured for privileged access
50
+ - [ ] Access will be time-bound when possible
51
+ - [ ] All privileged actions will be logged
52
+
53
+ ## Approvals
54
+ - [ ] Manager approval: _________________ Date: _______
55
+ - [ ] System owner approval: _________________ Date: _______
56
+ - [ ] Security review (for admin/root): _________________ Date: _______
57
+
58
+ ## Provisioning
59
+ - [ ] Privileged access configured
60
+ - [ ] MFA verified active
61
+ - [ ] User notified of access and responsibilities
62
+ - [ ] Access logged in privileged account register
63
+
64
+ ## Review Schedule
65
+ Next review date: [Date - privileged access reviewed quarterly]
66
+ ```