@specship/specship-win32-arm64 0.13.0 → 0.14.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 (240) hide show
  1. package/lib/dist/bin/specship.js +180 -1
  2. package/lib/dist/bin/specship.js.map +1 -1
  3. package/lib/dist/jira/auth.d.ts +17 -0
  4. package/lib/dist/jira/auth.d.ts.map +1 -0
  5. package/lib/dist/jira/auth.js +33 -0
  6. package/lib/dist/jira/auth.js.map +1 -0
  7. package/lib/dist/jira/client.d.ts +120 -0
  8. package/lib/dist/jira/client.d.ts.map +1 -0
  9. package/lib/dist/jira/client.js +316 -0
  10. package/lib/dist/jira/client.js.map +1 -0
  11. package/lib/dist/jira/config.d.ts +45 -0
  12. package/lib/dist/jira/config.d.ts.map +1 -0
  13. package/lib/dist/jira/config.js +178 -0
  14. package/lib/dist/jira/config.js.map +1 -0
  15. package/lib/dist/jira/index.d.ts +8 -0
  16. package/lib/dist/jira/index.d.ts.map +1 -0
  17. package/lib/dist/jira/index.js +24 -0
  18. package/lib/dist/jira/index.js.map +1 -0
  19. package/lib/dist/jira/pull-request.d.ts +72 -0
  20. package/lib/dist/jira/pull-request.d.ts.map +1 -0
  21. package/lib/dist/jira/pull-request.js +127 -0
  22. package/lib/dist/jira/pull-request.js.map +1 -0
  23. package/lib/dist/jira/spec-generator.d.ts +34 -0
  24. package/lib/dist/jira/spec-generator.d.ts.map +1 -0
  25. package/lib/dist/jira/spec-generator.js +138 -0
  26. package/lib/dist/jira/spec-generator.js.map +1 -0
  27. package/lib/dist/jira/spec-writer.d.ts +36 -0
  28. package/lib/dist/jira/spec-writer.d.ts.map +1 -0
  29. package/lib/dist/jira/spec-writer.js +143 -0
  30. package/lib/dist/jira/spec-writer.js.map +1 -0
  31. package/lib/dist/jira/types.d.ts +174 -0
  32. package/lib/dist/jira/types.d.ts.map +1 -0
  33. package/lib/dist/jira/types.js +60 -0
  34. package/lib/dist/jira/types.js.map +1 -0
  35. package/lib/dist/mcp/jira-tools.d.ts +234 -0
  36. package/lib/dist/mcp/jira-tools.d.ts.map +1 -0
  37. package/lib/dist/mcp/jira-tools.js +787 -0
  38. package/lib/dist/mcp/jira-tools.js.map +1 -0
  39. package/lib/dist/mcp/server-instructions.d.ts +1 -1
  40. package/lib/dist/mcp/server-instructions.d.ts.map +1 -1
  41. package/lib/dist/mcp/server-instructions.js +10 -0
  42. package/lib/dist/mcp/server-instructions.js.map +1 -1
  43. package/lib/dist/mcp/tools.d.ts.map +1 -1
  44. package/lib/dist/mcp/tools.js +32 -0
  45. package/lib/dist/mcp/tools.js.map +1 -1
  46. package/lib/dist/server/cli.js +1 -1
  47. package/lib/dist/server/routes/sse.js +1 -1
  48. package/lib/dist/server/server.js +1 -1
  49. package/lib/dist/statusline/index.d.ts +19 -0
  50. package/lib/dist/statusline/index.d.ts.map +1 -1
  51. package/lib/dist/statusline/index.js +96 -3
  52. package/lib/dist/statusline/index.js.map +1 -1
  53. package/lib/dist/statusline/render.d.ts +24 -0
  54. package/lib/dist/statusline/render.d.ts.map +1 -1
  55. package/lib/dist/statusline/render.js +26 -5
  56. package/lib/dist/statusline/render.js.map +1 -1
  57. package/lib/dist/workflows/executor.d.ts +25 -1
  58. package/lib/dist/workflows/executor.d.ts.map +1 -1
  59. package/lib/dist/workflows/executor.js +28 -3
  60. package/lib/dist/workflows/executor.js.map +1 -1
  61. package/lib/node_modules/.package-lock.json +11 -20
  62. package/lib/node_modules/ajv/node_modules/fast-uri/index.js +1 -1
  63. package/lib/node_modules/ajv/node_modules/fast-uri/package.json +1 -1
  64. package/lib/node_modules/ajv/node_modules/fast-uri/test/security.test.js +28 -0
  65. package/lib/node_modules/toad-cache/README.md +10 -9
  66. package/lib/node_modules/toad-cache/dist/toad-cache.cjs +139 -139
  67. package/lib/node_modules/toad-cache/dist/toad-cache.mjs +136 -140
  68. package/lib/node_modules/toad-cache/package.json +8 -8
  69. package/lib/node_modules/toad-cache/toad-cache.d.cts +20 -14
  70. package/lib/node_modules/toad-cache/toad-cache.d.ts +18 -14
  71. package/lib/node_modules/yaml/README.md +14 -31
  72. package/lib/node_modules/yaml/browser/dist/compose/compose-collection.js +3 -3
  73. package/lib/node_modules/yaml/browser/dist/compose/compose-doc.js +0 -1
  74. package/lib/node_modules/yaml/browser/dist/compose/compose-node.js +4 -21
  75. package/lib/node_modules/yaml/browser/dist/compose/compose-scalar.js +8 -14
  76. package/lib/node_modules/yaml/browser/dist/compose/composer.js +2 -4
  77. package/lib/node_modules/yaml/browser/dist/compose/resolve-block-map.js +0 -2
  78. package/lib/node_modules/yaml/browser/dist/compose/resolve-block-seq.js +1 -3
  79. package/lib/node_modules/yaml/browser/dist/compose/resolve-flow-collection.js +2 -8
  80. package/lib/node_modules/yaml/browser/dist/compose/resolve-flow-scalar.js +4 -6
  81. package/lib/node_modules/yaml/browser/dist/compose/resolve-props.js +5 -3
  82. package/lib/node_modules/yaml/browser/dist/compose/util-empty-scalar-position.js +2 -1
  83. package/lib/node_modules/yaml/browser/dist/compose/util-map-includes.js +5 -1
  84. package/lib/node_modules/yaml/browser/dist/doc/Document.js +2 -3
  85. package/lib/node_modules/yaml/browser/dist/doc/anchors.js +2 -1
  86. package/lib/node_modules/yaml/browser/dist/doc/applyReviver.js +0 -1
  87. package/lib/node_modules/yaml/browser/dist/doc/createNode.js +2 -1
  88. package/lib/node_modules/yaml/browser/dist/errors.js +1 -1
  89. package/lib/node_modules/yaml/browser/dist/log.js +6 -1
  90. package/lib/node_modules/yaml/browser/dist/node_modules/tslib/tslib.es6.js +21 -0
  91. package/lib/node_modules/yaml/browser/dist/nodes/Alias.js +12 -27
  92. package/lib/node_modules/yaml/browser/dist/nodes/YAMLMap.js +1 -1
  93. package/lib/node_modules/yaml/browser/dist/nodes/addPairToJSMap.js +49 -8
  94. package/lib/node_modules/yaml/browser/dist/parse/lexer.js +24 -28
  95. package/lib/node_modules/yaml/browser/dist/parse/parser.js +8 -31
  96. package/lib/node_modules/yaml/browser/dist/public-api.js +0 -3
  97. package/lib/node_modules/yaml/browser/dist/schema/Schema.js +2 -1
  98. package/lib/node_modules/yaml/browser/dist/schema/json/schema.js +1 -1
  99. package/lib/node_modules/yaml/browser/dist/schema/tags.js +16 -29
  100. package/lib/node_modules/yaml/browser/dist/schema/yaml-1.1/binary.js +13 -5
  101. package/lib/node_modules/yaml/browser/dist/schema/yaml-1.1/pairs.js +1 -1
  102. package/lib/node_modules/yaml/browser/dist/schema/yaml-1.1/schema.js +0 -2
  103. package/lib/node_modules/yaml/browser/dist/schema/yaml-1.1/timestamp.js +1 -1
  104. package/lib/node_modules/yaml/browser/dist/stringify/stringify.js +5 -10
  105. package/lib/node_modules/yaml/browser/dist/stringify/stringifyCollection.js +3 -13
  106. package/lib/node_modules/yaml/browser/dist/stringify/stringifyNumber.js +2 -3
  107. package/lib/node_modules/yaml/browser/dist/stringify/stringifyPair.js +1 -1
  108. package/lib/node_modules/yaml/browser/dist/stringify/stringifyString.js +16 -24
  109. package/lib/node_modules/yaml/browser/dist/util.js +1 -1
  110. package/lib/node_modules/yaml/dist/cli.d.ts +1 -1
  111. package/lib/node_modules/yaml/dist/cli.mjs +3 -5
  112. package/lib/node_modules/yaml/dist/compose/compose-collection.d.ts +4 -4
  113. package/lib/node_modules/yaml/dist/compose/compose-collection.js +3 -3
  114. package/lib/node_modules/yaml/dist/compose/compose-doc.d.ts +6 -6
  115. package/lib/node_modules/yaml/dist/compose/compose-doc.js +0 -1
  116. package/lib/node_modules/yaml/dist/compose/compose-node.d.ts +7 -8
  117. package/lib/node_modules/yaml/dist/compose/compose-node.js +4 -21
  118. package/lib/node_modules/yaml/dist/compose/compose-scalar.d.ts +4 -4
  119. package/lib/node_modules/yaml/dist/compose/compose-scalar.js +7 -13
  120. package/lib/node_modules/yaml/dist/compose/composer.d.ts +6 -7
  121. package/lib/node_modules/yaml/dist/compose/composer.js +3 -6
  122. package/lib/node_modules/yaml/dist/compose/resolve-block-map.d.ts +5 -5
  123. package/lib/node_modules/yaml/dist/compose/resolve-block-map.js +0 -2
  124. package/lib/node_modules/yaml/dist/compose/resolve-block-scalar.d.ts +5 -5
  125. package/lib/node_modules/yaml/dist/compose/resolve-block-seq.d.ts +5 -5
  126. package/lib/node_modules/yaml/dist/compose/resolve-block-seq.js +1 -3
  127. package/lib/node_modules/yaml/dist/compose/resolve-end.d.ts +2 -2
  128. package/lib/node_modules/yaml/dist/compose/resolve-flow-collection.d.ts +7 -7
  129. package/lib/node_modules/yaml/dist/compose/resolve-flow-collection.js +2 -8
  130. package/lib/node_modules/yaml/dist/compose/resolve-flow-scalar.d.ts +4 -4
  131. package/lib/node_modules/yaml/dist/compose/resolve-flow-scalar.js +4 -6
  132. package/lib/node_modules/yaml/dist/compose/resolve-props.d.ts +2 -2
  133. package/lib/node_modules/yaml/dist/compose/resolve-props.js +5 -3
  134. package/lib/node_modules/yaml/dist/compose/util-contains-newline.d.ts +1 -1
  135. package/lib/node_modules/yaml/dist/compose/util-empty-scalar-position.d.ts +1 -1
  136. package/lib/node_modules/yaml/dist/compose/util-empty-scalar-position.js +2 -1
  137. package/lib/node_modules/yaml/dist/compose/util-flow-indent-check.d.ts +2 -2
  138. package/lib/node_modules/yaml/dist/compose/util-map-includes.d.ts +3 -3
  139. package/lib/node_modules/yaml/dist/compose/util-map-includes.js +5 -1
  140. package/lib/node_modules/yaml/dist/doc/Document.d.ts +11 -11
  141. package/lib/node_modules/yaml/dist/doc/Document.js +2 -3
  142. package/lib/node_modules/yaml/dist/doc/anchors.d.ts +2 -2
  143. package/lib/node_modules/yaml/dist/doc/anchors.js +2 -1
  144. package/lib/node_modules/yaml/dist/doc/applyReviver.js +0 -1
  145. package/lib/node_modules/yaml/dist/doc/createNode.d.ts +4 -4
  146. package/lib/node_modules/yaml/dist/doc/createNode.js +2 -1
  147. package/lib/node_modules/yaml/dist/doc/directives.d.ts +1 -1
  148. package/lib/node_modules/yaml/dist/errors.d.ts +1 -1
  149. package/lib/node_modules/yaml/dist/errors.js +1 -1
  150. package/lib/node_modules/yaml/dist/index.d.ts +18 -21
  151. package/lib/node_modules/yaml/dist/log.js +4 -4
  152. package/lib/node_modules/yaml/dist/nodes/Alias.d.ts +9 -10
  153. package/lib/node_modules/yaml/dist/nodes/Alias.js +11 -26
  154. package/lib/node_modules/yaml/dist/nodes/Collection.d.ts +4 -4
  155. package/lib/node_modules/yaml/dist/nodes/Node.d.ts +9 -16
  156. package/lib/node_modules/yaml/dist/nodes/Pair.d.ts +8 -9
  157. package/lib/node_modules/yaml/dist/nodes/Scalar.d.ts +4 -9
  158. package/lib/node_modules/yaml/dist/nodes/YAMLMap.d.ts +10 -10
  159. package/lib/node_modules/yaml/dist/nodes/YAMLSeq.d.ts +10 -10
  160. package/lib/node_modules/yaml/dist/nodes/addPairToJSMap.d.ts +3 -3
  161. package/lib/node_modules/yaml/dist/nodes/addPairToJSMap.js +48 -7
  162. package/lib/node_modules/yaml/dist/nodes/identity.d.ts +7 -7
  163. package/lib/node_modules/yaml/dist/nodes/toJS.d.ts +2 -4
  164. package/lib/node_modules/yaml/dist/options.d.ts +10 -22
  165. package/lib/node_modules/yaml/dist/parse/cst-scalar.d.ts +4 -4
  166. package/lib/node_modules/yaml/dist/parse/cst-stringify.d.ts +1 -1
  167. package/lib/node_modules/yaml/dist/parse/cst-visit.d.ts +2 -2
  168. package/lib/node_modules/yaml/dist/parse/cst.d.ts +3 -4
  169. package/lib/node_modules/yaml/dist/parse/lexer.d.ts +1 -1
  170. package/lib/node_modules/yaml/dist/parse/lexer.js +24 -28
  171. package/lib/node_modules/yaml/dist/parse/parser.d.ts +4 -4
  172. package/lib/node_modules/yaml/dist/parse/parser.js +9 -33
  173. package/lib/node_modules/yaml/dist/public-api.d.ts +5 -6
  174. package/lib/node_modules/yaml/dist/public-api.js +0 -3
  175. package/lib/node_modules/yaml/dist/schema/Schema.d.ts +5 -4
  176. package/lib/node_modules/yaml/dist/schema/Schema.js +2 -1
  177. package/lib/node_modules/yaml/dist/schema/common/map.d.ts +1 -1
  178. package/lib/node_modules/yaml/dist/schema/common/null.d.ts +1 -1
  179. package/lib/node_modules/yaml/dist/schema/common/seq.d.ts +1 -1
  180. package/lib/node_modules/yaml/dist/schema/common/string.d.ts +1 -1
  181. package/lib/node_modules/yaml/dist/schema/core/bool.d.ts +1 -1
  182. package/lib/node_modules/yaml/dist/schema/core/float.d.ts +1 -1
  183. package/lib/node_modules/yaml/dist/schema/core/int.d.ts +1 -1
  184. package/lib/node_modules/yaml/dist/schema/core/schema.d.ts +1 -1
  185. package/lib/node_modules/yaml/dist/schema/json/schema.d.ts +1 -1
  186. package/lib/node_modules/yaml/dist/schema/json/schema.js +1 -1
  187. package/lib/node_modules/yaml/dist/schema/tags.d.ts +3 -11
  188. package/lib/node_modules/yaml/dist/schema/tags.js +13 -26
  189. package/lib/node_modules/yaml/dist/schema/types.d.ts +12 -14
  190. package/lib/node_modules/yaml/dist/schema/yaml-1.1/binary.d.ts +1 -1
  191. package/lib/node_modules/yaml/dist/schema/yaml-1.1/binary.js +7 -9
  192. package/lib/node_modules/yaml/dist/schema/yaml-1.1/bool.d.ts +1 -1
  193. package/lib/node_modules/yaml/dist/schema/yaml-1.1/float.d.ts +1 -1
  194. package/lib/node_modules/yaml/dist/schema/yaml-1.1/int.d.ts +1 -1
  195. package/lib/node_modules/yaml/dist/schema/yaml-1.1/omap.d.ts +17 -11
  196. package/lib/node_modules/yaml/dist/schema/yaml-1.1/pairs.d.ts +7 -7
  197. package/lib/node_modules/yaml/dist/schema/yaml-1.1/schema.d.ts +1 -1
  198. package/lib/node_modules/yaml/dist/schema/yaml-1.1/schema.js +0 -2
  199. package/lib/node_modules/yaml/dist/schema/yaml-1.1/set.d.ts +9 -9
  200. package/lib/node_modules/yaml/dist/schema/yaml-1.1/timestamp.d.ts +1 -1
  201. package/lib/node_modules/yaml/dist/schema/yaml-1.1/timestamp.js +1 -1
  202. package/lib/node_modules/yaml/dist/stringify/stringify.d.ts +3 -3
  203. package/lib/node_modules/yaml/dist/stringify/stringify.js +5 -10
  204. package/lib/node_modules/yaml/dist/stringify/stringifyCollection.d.ts +2 -2
  205. package/lib/node_modules/yaml/dist/stringify/stringifyCollection.js +3 -13
  206. package/lib/node_modules/yaml/dist/stringify/stringifyDocument.d.ts +3 -3
  207. package/lib/node_modules/yaml/dist/stringify/stringifyNumber.d.ts +1 -1
  208. package/lib/node_modules/yaml/dist/stringify/stringifyNumber.js +2 -3
  209. package/lib/node_modules/yaml/dist/stringify/stringifyPair.d.ts +2 -2
  210. package/lib/node_modules/yaml/dist/stringify/stringifyPair.js +1 -1
  211. package/lib/node_modules/yaml/dist/stringify/stringifyString.d.ts +2 -2
  212. package/lib/node_modules/yaml/dist/stringify/stringifyString.js +15 -23
  213. package/lib/node_modules/yaml/dist/util.d.ts +12 -16
  214. package/lib/node_modules/yaml/dist/util.js +2 -2
  215. package/lib/node_modules/yaml/dist/visit.d.ts +7 -7
  216. package/lib/node_modules/yaml/package.json +14 -13
  217. package/lib/package.json +5 -6
  218. package/package.json +1 -1
  219. package/lib/node_modules/jsonc-parser/CHANGELOG.md +0 -76
  220. package/lib/node_modules/jsonc-parser/LICENSE.md +0 -21
  221. package/lib/node_modules/jsonc-parser/README.md +0 -364
  222. package/lib/node_modules/jsonc-parser/SECURITY.md +0 -41
  223. package/lib/node_modules/jsonc-parser/lib/esm/impl/edit.js +0 -185
  224. package/lib/node_modules/jsonc-parser/lib/esm/impl/format.js +0 -261
  225. package/lib/node_modules/jsonc-parser/lib/esm/impl/parser.js +0 -659
  226. package/lib/node_modules/jsonc-parser/lib/esm/impl/scanner.js +0 -443
  227. package/lib/node_modules/jsonc-parser/lib/esm/impl/string-intern.js +0 -29
  228. package/lib/node_modules/jsonc-parser/lib/esm/main.d.ts +0 -351
  229. package/lib/node_modules/jsonc-parser/lib/esm/main.js +0 -178
  230. package/lib/node_modules/jsonc-parser/lib/umd/impl/edit.js +0 -201
  231. package/lib/node_modules/jsonc-parser/lib/umd/impl/format.js +0 -275
  232. package/lib/node_modules/jsonc-parser/lib/umd/impl/parser.js +0 -682
  233. package/lib/node_modules/jsonc-parser/lib/umd/impl/scanner.js +0 -456
  234. package/lib/node_modules/jsonc-parser/lib/umd/impl/string-intern.js +0 -42
  235. package/lib/node_modules/jsonc-parser/lib/umd/main.d.ts +0 -351
  236. package/lib/node_modules/jsonc-parser/lib/umd/main.js +0 -194
  237. package/lib/node_modules/jsonc-parser/package.json +0 -37
  238. package/lib/node_modules/yaml/browser/dist/schema/yaml-1.1/merge.js +0 -67
  239. package/lib/node_modules/yaml/dist/schema/yaml-1.1/merge.d.ts +0 -9
  240. package/lib/node_modules/yaml/dist/schema/yaml-1.1/merge.js +0 -71
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Minimal JIRA REST client (REQ-JIRA-001, A3).
3
+ *
4
+ * Wraps `fetch` with the base URL + auth header. `testConnection()` probes
5
+ * `/rest/api/2/myself` (available on both Cloud and Data Center);
6
+ * `listMyIssues()` (REQ-JIRA-002) searches the current user's issues. Both
7
+ * go through the private `request()` helper so the security guards below
8
+ * apply to every credentialed call.
9
+ *
10
+ * SECURITY (foundation for REQ-JIRA-009):
11
+ * - `redirect: 'manual'` — we never auto-follow a redirect, so the
12
+ * `Authorization` header can't be replayed to a different host.
13
+ * - We only ever talk to the configured base URL's host; a cross-host
14
+ * (or any) redirect is refused, not followed.
15
+ * - No thrown error or result field ever contains the credential.
16
+ */
17
+ import { JiraCredentials, JiraConnectionResult, JiraIssueListResult, JiraIssueResult, JiraTransition, JiraTransitionResult } from './types';
18
+ export declare class JiraClient {
19
+ private readonly baseUrl;
20
+ private readonly host;
21
+ private readonly authHeader;
22
+ private readonly deployment;
23
+ constructor(creds: JiraCredentials);
24
+ /**
25
+ * Probe the instance's `/myself` endpoint.
26
+ * - 200 → `{ ok: true, accountId, displayName }`.
27
+ * - 401 / 403 → `JiraAuthError`.
28
+ * - 3xx redirect → `JiraConfigError` (refused, never followed).
29
+ * - network / DNS failure → `JiraConfigError`.
30
+ */
31
+ testConnection(): Promise<JiraConnectionResult>;
32
+ /**
33
+ * List the issues assigned to the authenticated user (REQ-JIRA-002).
34
+ * Identity comes from the token via JQL `currentUser()` — the user never
35
+ * types their own name (A1). An optional `project` narrows the search
36
+ * (A2); the value is quote-escaped to prevent JQL injection. Ordered
37
+ * most-actionable-first (recently updated). Bounded by `MAX_ISSUE_RESULTS`.
38
+ *
39
+ * - 200 → `{ ok: true, issues }`; an empty list is a valid success (A3).
40
+ * - 401 / 403 → `JiraAuthError`; redirect / network / non-200 →
41
+ * `JiraConfigError` (A4) — never a partial or fabricated list.
42
+ */
43
+ listMyIssues(opts?: {
44
+ project?: string;
45
+ }): Promise<JiraIssueListResult>;
46
+ /**
47
+ * Fetch a single issue by its key (REQ-JIRA-003). Identity/authorization
48
+ * ride the token — a key the user can't see is indistinguishable from a
49
+ * missing one and both surface as `JiraNotFoundError` (A2). The key is
50
+ * URL-encoded before it enters the path so a slash/space can't traverse or
51
+ * inject into the request line.
52
+ *
53
+ * - 200 → `{ ok: true, issue }` with summary/description/status/type/subtasks.
54
+ * - 404 → `JiraNotFoundError` (no such issue, or no access).
55
+ * - 401 / 403 → `JiraAuthError`; redirect / network / non-200 →
56
+ * `JiraConfigError`. Never a partial or fabricated issue.
57
+ */
58
+ getIssue(key: string): Promise<JiraIssueResult>;
59
+ /**
60
+ * List the transitions the issue's current workflow state offers
61
+ * (REQ-JIRA-007). `GET /issue/{key}/transitions`. Used to resolve a
62
+ * configured transition name/id to an executable id before writing.
63
+ */
64
+ listTransitions(key: string): Promise<JiraTransition[]>;
65
+ /**
66
+ * Drive the issue toward a target state (REQ-JIRA-007). `nameOrId` is
67
+ * matched against the issue's available transitions by exact id first, then
68
+ * case-insensitively by name. On a match it POSTs `/transitions`. When NO
69
+ * transition matches — because this project's workflow doesn't offer it —
70
+ * it returns `{ ok, skipped, reason }` and NEVER throws (A3): a missing
71
+ * transition is an expected, recoverable state, and the caller still
72
+ * comments the PR link and reports the skip. Auth/network faults on the
73
+ * write still throw like any other credentialed call.
74
+ */
75
+ transitionIssue(key: string, nameOrId: string): Promise<JiraTransitionResult>;
76
+ /**
77
+ * Assign the issue (REQ-JIRA-007). Cloud keys assignment by `accountId`;
78
+ * Data Center by `name`. `PUT /issue/{key}/assignee`. A 204 (no body) is the
79
+ * success shape — the `write` helper tolerates an empty response.
80
+ */
81
+ assignIssue(key: string, accountId: string): Promise<void>;
82
+ /**
83
+ * Add a comment to the issue (REQ-JIRA-007) — used to record the PR link.
84
+ * `POST /issue/{key}/comment`. api/2 takes a plain-string body.
85
+ *
86
+ * SECURITY: the caller only ever passes the public PR URL / issue key here,
87
+ * never a credential (REQ-JIRA-009).
88
+ */
89
+ addComment(key: string, body: string): Promise<void>;
90
+ /**
91
+ * Shared, credentialed GET against the configured host. Delegates to
92
+ * `send()` for the security guards, then parses JSON. Returns the parsed
93
+ * JSON body on success; a non-JSON body is a `JiraConfigError`.
94
+ */
95
+ private request;
96
+ /**
97
+ * Shared, credentialed write (POST/PUT) against the configured host
98
+ * (REQ-JIRA-007). Carries EVERY guard `request()` does via `send()` —
99
+ * `redirect: 'manual'`, host-lock, 401/403 → auth, 404 → not-found,
100
+ * non-2xx → config, credential-free messages. A JSON body is sent with
101
+ * `Content-Type: application/json`; a success with no/empty body (204, the
102
+ * common transition/assignee shape) resolves to `null` rather than erroring
103
+ * on the missing JSON.
104
+ */
105
+ private write;
106
+ /**
107
+ * The single fetch + guard chokepoint shared by `request` and `write`. Every
108
+ * security guard lives here so no call path can skip one:
109
+ * - `redirect: 'manual'` — the `Authorization` header is never replayed
110
+ * across a redirect; any 3xx / opaqueredirect is refused, not followed.
111
+ * - only ever talks to the configured host.
112
+ * - 401 / 403 → `JiraAuthError`; 404 → `JiraNotFoundError`; network /
113
+ * non-2xx → `JiraConfigError`.
114
+ * - No thrown message ever contains the credential — only the host.
115
+ *
116
+ * Returns the raw `Response` on a 2xx; the caller parses the body.
117
+ */
118
+ private send;
119
+ }
120
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/jira/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EACL,eAAe,EACf,oBAAoB,EAEpB,mBAAmB,EACnB,eAAe,EACf,cAAc,EACd,oBAAoB,EAIrB,MAAM,SAAS,CAAC;AAKjB,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgC;gBAE/C,KAAK,EAAE,eAAe;IAclC;;;;;;OAMG;IACG,cAAc,IAAI,OAAO,CAAC,oBAAoB,CAAC;IAUrD;;;;;;;;;;OAUG;IACG,YAAY,CAAC,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,mBAAmB,CAAC;IA6B7E;;;;;;;;;;;OAWG;IACG,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IA2CrD;;;;OAIG;IACG,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAY7D;;;;;;;;;OASG;IACG,eAAe,CACnB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,oBAAoB,CAAC;IAmChC;;;;OAIG;IACG,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBhE;;;;;;OAMG;IACG,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAW1D;;;;OAIG;YACW,OAAO;IAWrB;;;;;;;;OAQG;YACW,KAAK;IAgBnB;;;;;;;;;;;OAWG;YACW,IAAI;CAoEnB"}
@@ -0,0 +1,316 @@
1
+ "use strict";
2
+ /**
3
+ * Minimal JIRA REST client (REQ-JIRA-001, A3).
4
+ *
5
+ * Wraps `fetch` with the base URL + auth header. `testConnection()` probes
6
+ * `/rest/api/2/myself` (available on both Cloud and Data Center);
7
+ * `listMyIssues()` (REQ-JIRA-002) searches the current user's issues. Both
8
+ * go through the private `request()` helper so the security guards below
9
+ * apply to every credentialed call.
10
+ *
11
+ * SECURITY (foundation for REQ-JIRA-009):
12
+ * - `redirect: 'manual'` — we never auto-follow a redirect, so the
13
+ * `Authorization` header can't be replayed to a different host.
14
+ * - We only ever talk to the configured base URL's host; a cross-host
15
+ * (or any) redirect is refused, not followed.
16
+ * - No thrown error or result field ever contains the credential.
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.JiraClient = void 0;
20
+ const auth_1 = require("./auth");
21
+ const types_1 = require("./types");
22
+ /** Upper bound on issues fetched in one list call — never unbounded. */
23
+ const MAX_ISSUE_RESULTS = 50;
24
+ class JiraClient {
25
+ baseUrl;
26
+ host;
27
+ authHeader;
28
+ deployment;
29
+ constructor(creds) {
30
+ // Normalize: strip trailing slashes so path joins are clean.
31
+ this.baseUrl = creds.baseUrl.replace(/\/+$/, '');
32
+ try {
33
+ this.host = new URL(this.baseUrl).host;
34
+ }
35
+ catch {
36
+ throw new types_1.JiraConfigError(`Invalid JIRA base URL: ${creds.baseUrl}`);
37
+ }
38
+ this.authHeader = (0, auth_1.buildAuthHeader)(creds);
39
+ this.deployment = creds.deployment;
40
+ }
41
+ /**
42
+ * Probe the instance's `/myself` endpoint.
43
+ * - 200 → `{ ok: true, accountId, displayName }`.
44
+ * - 401 / 403 → `JiraAuthError`.
45
+ * - 3xx redirect → `JiraConfigError` (refused, never followed).
46
+ * - network / DNS failure → `JiraConfigError`.
47
+ */
48
+ async testConnection() {
49
+ const body = await this.request('/rest/api/2/myself');
50
+ return {
51
+ ok: true,
52
+ // Cloud → accountId; Data Center → key/name. Prefer the most stable.
53
+ accountId: body?.accountId ?? body?.key ?? body?.name,
54
+ displayName: body?.displayName ?? body?.name,
55
+ };
56
+ }
57
+ /**
58
+ * List the issues assigned to the authenticated user (REQ-JIRA-002).
59
+ * Identity comes from the token via JQL `currentUser()` — the user never
60
+ * types their own name (A1). An optional `project` narrows the search
61
+ * (A2); the value is quote-escaped to prevent JQL injection. Ordered
62
+ * most-actionable-first (recently updated). Bounded by `MAX_ISSUE_RESULTS`.
63
+ *
64
+ * - 200 → `{ ok: true, issues }`; an empty list is a valid success (A3).
65
+ * - 401 / 403 → `JiraAuthError`; redirect / network / non-200 →
66
+ * `JiraConfigError` (A4) — never a partial or fabricated list.
67
+ */
68
+ async listMyIssues(opts) {
69
+ let jql = 'assignee = currentUser()';
70
+ if (opts?.project && opts.project.trim()) {
71
+ // Quote-escape the project so an embedded quote can't break out of the
72
+ // JQL string literal (injection guard). JQL escapes `"` as `\"`.
73
+ const escaped = opts.project.trim().replace(/\\/g, '\\\\').replace(/"/g, '\\"');
74
+ jql = `project = "${escaped}" AND ${jql}`;
75
+ }
76
+ jql += ' ORDER BY updated DESC';
77
+ const params = new URLSearchParams({
78
+ jql,
79
+ fields: 'summary,status,issuetype',
80
+ maxResults: String(MAX_ISSUE_RESULTS),
81
+ });
82
+ const body = await this.request(`/rest/api/2/search?${params.toString()}`);
83
+ const rawIssues = Array.isArray(body?.issues) ? body.issues : [];
84
+ const issues = rawIssues.map(issue => ({
85
+ key: String(issue?.key ?? ''),
86
+ id: String(issue?.id ?? ''),
87
+ summary: String(issue?.fields?.summary ?? ''),
88
+ status: String(issue?.fields?.status?.name ?? ''),
89
+ issueType: String(issue?.fields?.issuetype?.name ?? ''),
90
+ }));
91
+ return { ok: true, issues };
92
+ }
93
+ /**
94
+ * Fetch a single issue by its key (REQ-JIRA-003). Identity/authorization
95
+ * ride the token — a key the user can't see is indistinguishable from a
96
+ * missing one and both surface as `JiraNotFoundError` (A2). The key is
97
+ * URL-encoded before it enters the path so a slash/space can't traverse or
98
+ * inject into the request line.
99
+ *
100
+ * - 200 → `{ ok: true, issue }` with summary/description/status/type/subtasks.
101
+ * - 404 → `JiraNotFoundError` (no such issue, or no access).
102
+ * - 401 / 403 → `JiraAuthError`; redirect / network / non-200 →
103
+ * `JiraConfigError`. Never a partial or fabricated issue.
104
+ */
105
+ async getIssue(key) {
106
+ const trimmed = (key ?? '').trim();
107
+ if (!trimmed) {
108
+ throw new types_1.JiraConfigError('An issue key is required (e.g., "PROJ-123").');
109
+ }
110
+ // URL-encode the key: a slash or space in the key must not traverse the
111
+ // path or split the request — encode it into a single path segment.
112
+ const params = new URLSearchParams({
113
+ fields: 'summary,description,status,issuetype,subtasks',
114
+ });
115
+ const body = await this.request(`/rest/api/2/issue/${encodeURIComponent(trimmed)}?${params.toString()}`);
116
+ const fields = body?.fields ?? {};
117
+ // api/2 returns `description` as a plain string. Guard the non-string case
118
+ // (null → no body; an ADF object under a future api/3 → not `[object
119
+ // Object]`) by treating anything non-string as empty.
120
+ const description = typeof fields.description === 'string' ? fields.description : '';
121
+ const rawSubtasks = Array.isArray(fields.subtasks)
122
+ ? fields.subtasks
123
+ : [];
124
+ const subtasks = rawSubtasks.map(st => ({
125
+ key: String(st?.key ?? ''),
126
+ summary: String(st?.fields?.summary ?? ''),
127
+ status: String(st?.fields?.status?.name ?? ''),
128
+ }));
129
+ const issue = {
130
+ key: String(body?.key ?? trimmed),
131
+ id: String(body?.id ?? ''),
132
+ summary: String(fields.summary ?? ''),
133
+ status: String(fields.status?.name ?? ''),
134
+ issueType: String(fields.issuetype?.name ?? ''),
135
+ description,
136
+ subtasks,
137
+ };
138
+ return { ok: true, issue };
139
+ }
140
+ /**
141
+ * List the transitions the issue's current workflow state offers
142
+ * (REQ-JIRA-007). `GET /issue/{key}/transitions`. Used to resolve a
143
+ * configured transition name/id to an executable id before writing.
144
+ */
145
+ async listTransitions(key) {
146
+ const trimmed = (key ?? '').trim();
147
+ if (!trimmed) {
148
+ throw new types_1.JiraConfigError('An issue key is required (e.g., "PROJ-123").');
149
+ }
150
+ const body = await this.request(`/rest/api/2/issue/${encodeURIComponent(trimmed)}/transitions`);
151
+ const raw = Array.isArray(body?.transitions) ? body.transitions : [];
152
+ return raw.map(t => ({ id: String(t?.id ?? ''), name: String(t?.name ?? '') }));
153
+ }
154
+ /**
155
+ * Drive the issue toward a target state (REQ-JIRA-007). `nameOrId` is
156
+ * matched against the issue's available transitions by exact id first, then
157
+ * case-insensitively by name. On a match it POSTs `/transitions`. When NO
158
+ * transition matches — because this project's workflow doesn't offer it —
159
+ * it returns `{ ok, skipped, reason }` and NEVER throws (A3): a missing
160
+ * transition is an expected, recoverable state, and the caller still
161
+ * comments the PR link and reports the skip. Auth/network faults on the
162
+ * write still throw like any other credentialed call.
163
+ */
164
+ async transitionIssue(key, nameOrId) {
165
+ const trimmed = (key ?? '').trim();
166
+ if (!trimmed) {
167
+ throw new types_1.JiraConfigError('An issue key is required (e.g., "PROJ-123").');
168
+ }
169
+ const target = (nameOrId ?? '').trim();
170
+ if (!target) {
171
+ return {
172
+ ok: true,
173
+ skipped: nameOrId,
174
+ reason: 'no transition name/id was configured',
175
+ };
176
+ }
177
+ const available = await this.listTransitions(trimmed);
178
+ const wanted = target.toLowerCase();
179
+ const match = available.find(t => t.id === target || t.name.toLowerCase() === wanted);
180
+ if (!match) {
181
+ const names = available.map(t => t.name).join(', ') || 'none';
182
+ return {
183
+ ok: true,
184
+ skipped: target,
185
+ reason: `no "${target}" transition on this issue's workflow (available: ${names})`,
186
+ };
187
+ }
188
+ await this.write(`/rest/api/2/issue/${encodeURIComponent(trimmed)}/transitions`, { transition: { id: match.id } });
189
+ return { ok: true, transitioned: match.name };
190
+ }
191
+ /**
192
+ * Assign the issue (REQ-JIRA-007). Cloud keys assignment by `accountId`;
193
+ * Data Center by `name`. `PUT /issue/{key}/assignee`. A 204 (no body) is the
194
+ * success shape — the `write` helper tolerates an empty response.
195
+ */
196
+ async assignIssue(key, accountId) {
197
+ const trimmed = (key ?? '').trim();
198
+ if (!trimmed) {
199
+ throw new types_1.JiraConfigError('An issue key is required (e.g., "PROJ-123").');
200
+ }
201
+ const body = this.deployment === 'datacenter'
202
+ ? { name: accountId }
203
+ : { accountId };
204
+ await this.write(`/rest/api/2/issue/${encodeURIComponent(trimmed)}/assignee`, body, 'PUT');
205
+ }
206
+ /**
207
+ * Add a comment to the issue (REQ-JIRA-007) — used to record the PR link.
208
+ * `POST /issue/{key}/comment`. api/2 takes a plain-string body.
209
+ *
210
+ * SECURITY: the caller only ever passes the public PR URL / issue key here,
211
+ * never a credential (REQ-JIRA-009).
212
+ */
213
+ async addComment(key, body) {
214
+ const trimmed = (key ?? '').trim();
215
+ if (!trimmed) {
216
+ throw new types_1.JiraConfigError('An issue key is required (e.g., "PROJ-123").');
217
+ }
218
+ await this.write(`/rest/api/2/issue/${encodeURIComponent(trimmed)}/comment`, { body });
219
+ }
220
+ /**
221
+ * Shared, credentialed GET against the configured host. Delegates to
222
+ * `send()` for the security guards, then parses JSON. Returns the parsed
223
+ * JSON body on success; a non-JSON body is a `JiraConfigError`.
224
+ */
225
+ async request(path) {
226
+ const res = await this.send(path, 'GET');
227
+ try {
228
+ return await res.json();
229
+ }
230
+ catch {
231
+ throw new types_1.JiraConfigError(`JIRA at ${this.host} returned a non-JSON response.`);
232
+ }
233
+ }
234
+ /**
235
+ * Shared, credentialed write (POST/PUT) against the configured host
236
+ * (REQ-JIRA-007). Carries EVERY guard `request()` does via `send()` —
237
+ * `redirect: 'manual'`, host-lock, 401/403 → auth, 404 → not-found,
238
+ * non-2xx → config, credential-free messages. A JSON body is sent with
239
+ * `Content-Type: application/json`; a success with no/empty body (204, the
240
+ * common transition/assignee shape) resolves to `null` rather than erroring
241
+ * on the missing JSON.
242
+ */
243
+ async write(path, body, method = 'POST') {
244
+ const res = await this.send(path, method, JSON.stringify(body ?? {}));
245
+ // 204 No Content (assignee/transition) has no body — don't force JSON.
246
+ if (res.status === 204)
247
+ return null;
248
+ try {
249
+ return await res.json();
250
+ }
251
+ catch {
252
+ // A 2xx write with an empty/non-JSON body is still a success.
253
+ return null;
254
+ }
255
+ }
256
+ /**
257
+ * The single fetch + guard chokepoint shared by `request` and `write`. Every
258
+ * security guard lives here so no call path can skip one:
259
+ * - `redirect: 'manual'` — the `Authorization` header is never replayed
260
+ * across a redirect; any 3xx / opaqueredirect is refused, not followed.
261
+ * - only ever talks to the configured host.
262
+ * - 401 / 403 → `JiraAuthError`; 404 → `JiraNotFoundError`; network /
263
+ * non-2xx → `JiraConfigError`.
264
+ * - No thrown message ever contains the credential — only the host.
265
+ *
266
+ * Returns the raw `Response` on a 2xx; the caller parses the body.
267
+ */
268
+ async send(path, method, jsonBody) {
269
+ const url = `${this.baseUrl}${path}`;
270
+ const headers = {
271
+ Authorization: this.authHeader,
272
+ Accept: 'application/json',
273
+ };
274
+ if (jsonBody !== undefined) {
275
+ headers['Content-Type'] = 'application/json';
276
+ }
277
+ let res;
278
+ try {
279
+ res = await fetch(url, {
280
+ method,
281
+ redirect: 'manual',
282
+ headers,
283
+ ...(jsonBody !== undefined ? { body: jsonBody } : {}),
284
+ });
285
+ }
286
+ catch (err) {
287
+ // Network / DNS — the message is fetch's own (no credential in it),
288
+ // but we prepend the host, never the header.
289
+ const msg = err instanceof Error ? err.message : String(err);
290
+ throw new types_1.JiraConfigError(`Could not reach JIRA at ${this.host}: ${msg}`);
291
+ }
292
+ // Refuse any redirect — do not follow it to another host.
293
+ if (res.type === 'opaqueredirect' ||
294
+ (res.status >= 300 && res.status < 400)) {
295
+ throw new types_1.JiraConfigError(`JIRA at ${this.host} returned an unexpected redirect; refusing to ` +
296
+ `follow it to another host.`);
297
+ }
298
+ if (res.status === 401 || res.status === 403) {
299
+ throw new types_1.JiraAuthError(`JIRA rejected the credentials (HTTP ${res.status}). ` +
300
+ `Check the email/token or PAT.`);
301
+ }
302
+ // A missing issue — or one the token can't see — is a distinct, expected
303
+ // signal (REQ-JIRA-003 A2). Must precede the generic !res.ok branch below,
304
+ // and stays credential-free like every other message here.
305
+ if (res.status === 404) {
306
+ throw new types_1.JiraNotFoundError(`JIRA at ${this.host} has no such issue, or you don't have access ` +
307
+ `to it (HTTP 404).`);
308
+ }
309
+ if (!res.ok) {
310
+ throw new types_1.JiraConfigError(`JIRA at ${this.host} returned HTTP ${res.status}.`);
311
+ }
312
+ return res;
313
+ }
314
+ }
315
+ exports.JiraClient = JiraClient;
316
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/jira/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * JIRA config load / resolve / save (REQ-JIRA-001, A2).
3
+ *
4
+ * Config lives at `~/.specship/jira.json` — **user-level only, never in
5
+ * the project tree** (not even a gitignored project file), because it
6
+ * holds a secret. The path is overridable via `SPECSHIP_JIRA_CONFIG`
7
+ * (mirrors `SPECSHIP_SERVER_CONFIG`) so tests never touch the real home.
8
+ */
9
+ import { JiraConfig, JiraCredentials, JiraDeployment } from './types';
10
+ /**
11
+ * Absolute path to the user-level JIRA config. Overridable via
12
+ * `SPECSHIP_JIRA_CONFIG` for tests. Never project-scoped.
13
+ */
14
+ export declare function jiraConfigPath(): string;
15
+ /**
16
+ * Read `~/.specship/jira.json`. Returns `null` when the file is absent.
17
+ * Throws `JiraConfigError` when it exists but is malformed — a corrupt
18
+ * secret file is a hard error, not a silent fall-through to `{}`.
19
+ */
20
+ export declare function loadJiraConfig(): JiraConfig | null;
21
+ /**
22
+ * Infer the deployment kind from which credentials are present. An
23
+ * explicit `deployment` field always wins. Otherwise: a PAT (with no
24
+ * email+token pair) ⇒ Data Center; an email+token pair ⇒ Cloud.
25
+ */
26
+ export declare function inferDeployment(creds: {
27
+ deployment?: JiraDeployment;
28
+ email?: string;
29
+ apiToken?: string;
30
+ pat?: string;
31
+ }): JiraDeployment;
32
+ /**
33
+ * Resolve effective credentials from environment (highest precedence,
34
+ * per-field) then the on-disk config. Throws `JiraConfigError` with an
35
+ * actionable message when required fields are missing or malformed.
36
+ *
37
+ * SECURITY: the thrown messages never include a token or PAT value.
38
+ */
39
+ export declare function resolveJiraCredentials(): JiraCredentials;
40
+ /**
41
+ * Persist config to `~/.specship/jira.json` with `0600` permissions —
42
+ * it holds a secret, so it must not be group/world readable.
43
+ */
44
+ export declare function saveJiraConfig(config: JiraConfig): void;
45
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/jira/config.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,EACL,UAAU,EACV,eAAe,EAEf,cAAc,EACf,MAAM,SAAS,CAAC;AAEjB;;;GAGG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAKvC;AAED;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,UAAU,GAAG,IAAI,CAsBlD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE;IACrC,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GAAG,cAAc,CAWjB;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,IAAI,eAAe,CAyDxD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAQvD"}