@knpkv/jira-cli 0.1.1 → 0.3.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 (70) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/README.md +63 -1
  3. package/dist/IssueService.d.ts +2 -2
  4. package/dist/IssueService.d.ts.map +1 -1
  5. package/dist/IssueService.js +3 -3
  6. package/dist/IssueService.js.map +1 -1
  7. package/dist/JiraAuth.d.ts +14 -14
  8. package/dist/JiraAuth.d.ts.map +1 -1
  9. package/dist/JiraAuth.js +18 -10
  10. package/dist/JiraAuth.js.map +1 -1
  11. package/dist/MarkdownWriter.d.ts +4 -4
  12. package/dist/MarkdownWriter.d.ts.map +1 -1
  13. package/dist/MarkdownWriter.js +6 -6
  14. package/dist/MarkdownWriter.js.map +1 -1
  15. package/dist/VersionService.d.ts +206 -0
  16. package/dist/VersionService.d.ts.map +1 -0
  17. package/dist/VersionService.js +426 -0
  18. package/dist/VersionService.js.map +1 -0
  19. package/dist/bin.js +28 -20
  20. package/dist/bin.js.map +1 -1
  21. package/dist/commands/auth.d.ts +2 -21
  22. package/dist/commands/auth.d.ts.map +1 -1
  23. package/dist/commands/auth.js +6 -6
  24. package/dist/commands/auth.js.map +1 -1
  25. package/dist/commands/get.d.ts +3 -8
  26. package/dist/commands/get.d.ts.map +1 -1
  27. package/dist/commands/get.js +2 -2
  28. package/dist/commands/get.js.map +1 -1
  29. package/dist/commands/index.d.ts +1 -0
  30. package/dist/commands/index.d.ts.map +1 -1
  31. package/dist/commands/index.js +1 -0
  32. package/dist/commands/index.js.map +1 -1
  33. package/dist/commands/layers.d.ts +6 -18
  34. package/dist/commands/layers.d.ts.map +1 -1
  35. package/dist/commands/layers.js +31 -23
  36. package/dist/commands/layers.js.map +1 -1
  37. package/dist/commands/search.d.ts +3 -8
  38. package/dist/commands/search.d.ts.map +1 -1
  39. package/dist/commands/search.js +4 -4
  40. package/dist/commands/search.js.map +1 -1
  41. package/dist/commands/version.d.ts +12 -0
  42. package/dist/commands/version.d.ts.map +1 -0
  43. package/dist/commands/version.js +179 -0
  44. package/dist/commands/version.js.map +1 -0
  45. package/dist/internal/oauthServer.d.ts +17 -5
  46. package/dist/internal/oauthServer.d.ts.map +1 -1
  47. package/dist/internal/oauthServer.js +23 -40
  48. package/dist/internal/oauthServer.js.map +1 -1
  49. package/dist/internal/openBrowser.d.ts +10 -0
  50. package/dist/internal/openBrowser.d.ts.map +1 -0
  51. package/dist/internal/openBrowser.js +17 -0
  52. package/dist/internal/openBrowser.js.map +1 -0
  53. package/package.json +10 -12
  54. package/skills/jira/SKILL.md +90 -0
  55. package/skills/jira/agents/openai.yaml +4 -0
  56. package/src/IssueService.ts +34 -28
  57. package/src/JiraAuth.ts +53 -39
  58. package/src/MarkdownWriter.ts +7 -11
  59. package/src/VersionService.ts +647 -0
  60. package/src/bin.ts +38 -26
  61. package/src/commands/auth.ts +6 -12
  62. package/src/commands/get.ts +2 -2
  63. package/src/commands/index.ts +1 -0
  64. package/src/commands/layers.ts +40 -25
  65. package/src/commands/search.ts +4 -4
  66. package/src/commands/version.ts +267 -0
  67. package/src/internal/oauthServer.ts +43 -70
  68. package/src/internal/openBrowser.ts +31 -0
  69. package/test/VersionService.test.ts +266 -0
  70. package/vitest.config.ts +5 -0
@@ -0,0 +1,179 @@
1
+ /**
2
+ * `jira version` command — list / view Jira project versions (releases) with
3
+ * Driver, Contributors and Approver fields resolved to display names, plus
4
+ * mutations: edit the description and manage "Related work" links (the
5
+ * Confluence pages surfaced on a release report).
6
+ *
7
+ * @internal
8
+ */
9
+ import * as Console from "effect/Console";
10
+ import * as Effect from "effect/Effect";
11
+ import * as Option from "effect/Option";
12
+ import { Argument as Args, Command, Flag as Options } from "effect/unstable/cli";
13
+ import { JiraApiError } from "../JiraCliError.js";
14
+ import { VersionService } from "../VersionService.js";
15
+ /**
16
+ * Return a copy of `version` with every resolved {@link Person.emailAddress}
17
+ * (PII) set to null — covering driver, contributors, approvers[].person and
18
+ * tickets[].assignee. Used to keep emails out of `--json` output unless the
19
+ * caller opts in with `--emails`.
20
+ */
21
+ export const stripEmails = (version) => {
22
+ const stripPerson = (person) => ({ ...person, emailAddress: null });
23
+ return {
24
+ ...version,
25
+ driver: version.driver ? stripPerson(version.driver) : null,
26
+ contributors: version.contributors.map(stripPerson),
27
+ approvers: version.approvers.map((a) => ({ ...a, person: stripPerson(a.person) })),
28
+ tickets: version.tickets.map((t) => ({
29
+ ...t,
30
+ assignee: t.assignee ? stripPerson(t.assignee) : null
31
+ }))
32
+ };
33
+ };
34
+ /**
35
+ * Jira version ids are numeric (e.g. `10042`). Passing a name/key 404s with an
36
+ * opaque error, so validate early and emit a hint pointing at `version list`.
37
+ */
38
+ const ensureNumericId = (id) => /^\d+$/.test(id)
39
+ ? Effect.void
40
+ : Effect.fail(new JiraApiError({
41
+ message: `Invalid version id "${id}". The version id is numeric (e.g. 10042); ` +
42
+ `use 'jira version list --project <KEY>' to find it.`
43
+ }));
44
+ const projectOption = Options.string("project").pipe(Options.withAlias("p"), Options.withDescription("Jira project key (e.g. RPS)"));
45
+ const releasedOption = Options.boolean("released").pipe(Options.withDescription("Only list released versions"), Options.withDefault(false));
46
+ const unreleasedOption = Options.boolean("unreleased").pipe(Options.withDescription("Only list unreleased versions"), Options.withDefault(false));
47
+ const jsonOption = Options.boolean("json").pipe(Options.withDescription("Output as JSON"), Options.withDefault(false));
48
+ const emailsOption = Options.boolean("emails").pipe(Options.withDescription("Include resolved user email addresses in --json output"), Options.withDefault(false));
49
+ const customFieldOption = Options.string("custom-field").pipe(Options.withDescription("Custom field display name to include on each ticket (repeatable, e.g. " +
50
+ "--custom-field \"Security & Compliance Impact\"). Values are exposed in " +
51
+ "ticket.customFields[<name>]."), Options.atLeast(0));
52
+ const maxOption = Options.integer("max").pipe(Options.withAlias("m"), Options.withDescription("Maximum number of versions to fetch (default: all)"), Options.optional);
53
+ const idArg = Args.string("id").pipe(Args.withDescription("Version id (numeric)"));
54
+ const listCommand = Command.make("list", {
55
+ project: projectOption,
56
+ released: releasedOption,
57
+ unreleased: unreleasedOption,
58
+ customFields: customFieldOption,
59
+ max: maxOption,
60
+ json: jsonOption,
61
+ emails: emailsOption
62
+ }, ({ customFields, emails, json, max, project, released, unreleased }) => Effect.gen(function* () {
63
+ if (released && unreleased) {
64
+ return yield* Effect.fail(new JiraApiError({
65
+ message: "--released and --unreleased are mutually exclusive; pass at most one (omit both to list all)."
66
+ }));
67
+ }
68
+ const service = yield* VersionService;
69
+ const versions = yield* service.listProjectVersions(project, {
70
+ released,
71
+ unreleased,
72
+ ...(Option.isSome(max) ? { maxResults: max.value } : {}),
73
+ customFieldNames: customFields
74
+ });
75
+ if (json) {
76
+ const output = emails ? versions : versions.map(stripEmails);
77
+ yield* Console.log(JSON.stringify(output, null, 2));
78
+ return;
79
+ }
80
+ const sep = " ";
81
+ yield* Console.log(["id", "name", "released", "releaseDate", "driver", "contributors", "approvers"].join(sep));
82
+ for (const v of versions) {
83
+ yield* Console.log([
84
+ v.id,
85
+ v.name,
86
+ String(v.released),
87
+ v.releaseDate ?? "-",
88
+ v.driver?.displayName ?? "-",
89
+ v.contributors.map((c) => c.displayName).join("|") || "-",
90
+ v.approvers.map((a) => `${a.person.displayName}:${a.status}`).join("|") || "-"
91
+ ].join(sep));
92
+ }
93
+ })).pipe(Command.withDescription("List versions for a Jira project"));
94
+ /** Cap on the number of ticket keys listed in the human `view` output. */
95
+ const TICKET_KEYS_LIMIT = 20;
96
+ const viewCommand = Command.make("view", { id: idArg, json: jsonOption, emails: emailsOption }, ({ emails, id, json }) => Effect.gen(function* () {
97
+ yield* ensureNumericId(id);
98
+ const service = yield* VersionService;
99
+ const version = yield* service.getVersion(id);
100
+ if (json) {
101
+ const output = emails ? version : stripEmails(version);
102
+ yield* Console.log(JSON.stringify(output, null, 2));
103
+ return;
104
+ }
105
+ yield* Console.log(`# ${version.name} (${version.id})`);
106
+ yield* Console.log(`released: ${version.released}`);
107
+ yield* Console.log(`releaseDate: ${version.releaseDate ?? "-"}`);
108
+ yield* Console.log(`driver: ${version.driver?.displayName ?? "-"}`);
109
+ yield* Console.log(`contributors: ${version.contributors.map((c) => c.displayName).join(", ") || "-"}`);
110
+ yield* Console.log(`approvers: ${version.approvers.map((a) => `${a.person.displayName}:${a.status}`).join(", ") || "-"}`);
111
+ yield* Console.log(`tickets (${version.tickets.length}): ${formatTicketKeys(version.tickets)}`);
112
+ })).pipe(Command.withDescription("Show a single Jira version"));
113
+ /**
114
+ * Render a version's ticket keys for the human `view`: the first
115
+ * {@link TICKET_KEYS_LIMIT} keys, with a `(+M more)` suffix when truncated, or
116
+ * `-` when there are none.
117
+ */
118
+ const formatTicketKeys = (tickets) => {
119
+ if (tickets.length === 0)
120
+ return "-";
121
+ const keys = tickets.map((t) => t.key);
122
+ const shown = keys.slice(0, TICKET_KEYS_LIMIT).join(", ");
123
+ const remaining = keys.length - TICKET_KEYS_LIMIT;
124
+ return remaining > 0 ? `${shown} (+${remaining} more)` : shown;
125
+ };
126
+ const descriptionOption = Options.string("description").pipe(Options.withAlias("d"), Options.withDescription("New version description"));
127
+ const setCommand = Command.make("set", { id: idArg, description: descriptionOption, json: jsonOption }, ({ description, id, json }) => Effect.gen(function* () {
128
+ yield* ensureNumericId(id);
129
+ const service = yield* VersionService;
130
+ const version = yield* service.updateVersion(id, { description });
131
+ if (json) {
132
+ yield* Console.log(JSON.stringify(version, null, 2));
133
+ return;
134
+ }
135
+ yield* Console.log(`Updated version ${version.name} (${version.id})`);
136
+ yield* Console.log(`description: ${version.description ?? "-"}`);
137
+ })).pipe(Command.withDescription("Update a version's description (requires manage:jira-project scope)"));
138
+ // === relatedwork ===
139
+ const titleOption = Options.string("title").pipe(Options.withAlias("t"), Options.withDescription("Related-work link title (e.g. \"Release notes\")"));
140
+ const urlOption = Options.string("url").pipe(Options.withAlias("u"), Options.withDescription("Related-work link URL (e.g. a Confluence page)"));
141
+ const categoryOption = Options.string("category").pipe(Options.withAlias("c"), Options.withDescription("Related-work category (Jira groups by this; e.g. Communication, Testing, Design)"), Options.withDefault("Communication"));
142
+ const relatedWorkListCommand = Command.make("list", { id: idArg, json: jsonOption }, ({ id, json }) => Effect.gen(function* () {
143
+ yield* ensureNumericId(id);
144
+ const service = yield* VersionService;
145
+ const items = yield* service.listRelatedWork(id);
146
+ if (json) {
147
+ yield* Console.log(JSON.stringify(items, null, 2));
148
+ return;
149
+ }
150
+ if (items.length === 0) {
151
+ yield* Console.log("(no related work)");
152
+ return;
153
+ }
154
+ const sep = " ";
155
+ yield* Console.log(["category", "title", "url"].join(sep));
156
+ for (const w of items) {
157
+ yield* Console.log([w.category || "-", w.title ?? "-", w.url ?? "-"].join(sep));
158
+ }
159
+ })).pipe(Command.withDescription("List a version's related-work links"));
160
+ const relatedWorkAddCommand = Command.make("add", {
161
+ id: idArg,
162
+ title: titleOption,
163
+ url: urlOption,
164
+ category: categoryOption,
165
+ json: jsonOption
166
+ }, ({ category, id, json, title, url }) => Effect.gen(function* () {
167
+ yield* ensureNumericId(id);
168
+ const service = yield* VersionService;
169
+ const created = yield* service.addRelatedWork(id, { title, category, url });
170
+ if (json) {
171
+ yield* Console.log(JSON.stringify(created, null, 2));
172
+ return;
173
+ }
174
+ yield* Console.log(`Attached "${created.title ?? title}" (${created.category}) to version ${id}`);
175
+ yield* Console.log(`url: ${created.url ?? url}`);
176
+ })).pipe(Command.withDescription("Attach a related-work link (e.g. a Confluence page) to a version (requires manage:jira-project scope)"));
177
+ const relatedWorkCommand = Command.make("relatedwork").pipe(Command.withDescription("List or attach version related-work links (Confluence pages on the release report)"), Command.withSubcommands([relatedWorkListCommand, relatedWorkAddCommand]));
178
+ export const versionCommand = Command.make("version").pipe(Command.withDescription("List, view, or edit Jira project versions (releases)"), Command.withSubcommands([listCommand, viewCommand, setCommand, relatedWorkCommand]));
179
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/commands/version.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,21 @@
1
- import * as HttpServer from "@effect/platform/HttpServer";
2
- import type { ServeError } from "@effect/platform/HttpServerError";
1
+ /**
2
+ * Local HTTP callback server for OAuth2 authorization code capture.
3
+ *
4
+ * **Mental model**
5
+ *
6
+ * - **Deferred-coordinated lifecycle**: {@link startCallbackServer} returns a `codePromise`
7
+ * (Deferred) and a `shutdown` effect. The server validates the CSRF `state` parameter
8
+ * and resolves the Deferred with the authorization code.
9
+ * - **Port auto-discovery**: Tries default port 8585, increments on conflict.
10
+ *
11
+ * @internal
12
+ */
3
13
  import { OAuthError } from "@knpkv/atlassian-common/auth";
4
14
  import * as Context from "effect/Context";
5
15
  import * as Effect from "effect/Effect";
6
16
  import * as Layer from "effect/Layer";
17
+ import { HttpServer } from "effect/unstable/http";
18
+ import type * as HttpServerError from "effect/unstable/http/HttpServerError";
7
19
  /**
8
20
  * Factory service for creating HTTP servers.
9
21
  * This allows mocking the server creation in tests.
@@ -11,9 +23,9 @@ import * as Layer from "effect/Layer";
11
23
  * @category Services
12
24
  */
13
25
  export interface HttpServerFactory {
14
- readonly createServerLayer: (port: number) => Layer.Layer<HttpServer.HttpServer, ServeError, never>;
26
+ readonly createServerLayer: (port: number) => Layer.Layer<HttpServer.HttpServer, HttpServerError.ServeError, never>;
15
27
  }
16
- declare const HttpServerFactoryTag_base: Context.TagClass<HttpServerFactoryTag, "@knpkv/jira-cli/HttpServerFactory", HttpServerFactory>;
28
+ declare const HttpServerFactoryTag_base: Context.ServiceClass<HttpServerFactoryTag, "@knpkv/jira-cli/HttpServerFactory", HttpServerFactory>;
17
29
  /**
18
30
  * Tag for the HttpServerFactory service.
19
31
  *
@@ -30,7 +42,7 @@ export declare class HttpServerFactoryTag extends HttpServerFactoryTag_base {
30
42
  *
31
43
  * @category Layers
32
44
  */
33
- export declare const makeHttpServerFactory: (createLayerFn: (port: number) => Layer.Layer<HttpServer.HttpServer, ServeError, never>) => Layer.Layer<HttpServerFactoryTag>;
45
+ export declare const makeHttpServerFactory: (createLayerFn: (port: number) => Layer.Layer<HttpServer.HttpServer, HttpServerError.ServeError, never>) => Layer.Layer<HttpServerFactoryTag>;
34
46
  /**
35
47
  * Result from the OAuth callback server.
36
48
  */
@@ -1 +1 @@
1
- {"version":3,"file":"oauthServer.d.ts","sourceRoot":"","sources":["../../src/internal/oauthServer.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,UAAU,MAAM,6BAA6B,CAAA;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAA;AAGlE,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAA;AACzD,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAA;AAEzC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAKrC;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,iBAAiB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,KAAK,CAAC,KAAK,CACvD,UAAU,CAAC,UAAU,EACrB,UAAU,EACV,KAAK,CACN,CAAA;CACF;;AAED;;;;GAIG;AACH,qBAAa,oBAAqB,SAAQ,yBAGvC;CAAG;AAEN;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,GAChC,eAAe,CAAC,IAAI,EAAE,MAAM,KAAK,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU,EAAE,UAAU,EAAE,KAAK,CAAC,KACrF,KAAK,CAAC,KAAK,CAAC,oBAAoB,CAG/B,CAAA;AAwCJ;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,wDAAwD;IACxD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;IACvD,mCAAmC;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IAC7C,0CAA0C;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,GAC9B,eAAe,MAAM,KACpB,MAAM,CAAC,MAAM,CAAC,oBAAoB,EAAE,UAAU,EAAE,oBAAoB,CA2EnE,CAAA"}
1
+ {"version":3,"file":"oauthServer.d.ts","sourceRoot":"","sources":["../../src/internal/oauthServer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAA;AACzD,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAA;AAEzC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAGvC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAErC,OAAO,EAAc,UAAU,EAAsB,MAAM,sBAAsB,CAAA;AACjF,OAAO,KAAK,KAAK,eAAe,MAAM,sCAAsC,CAAA;AAK5E;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,iBAAiB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,KAAK,CAAC,KAAK,CACvD,UAAU,CAAC,UAAU,EACrB,eAAe,CAAC,UAAU,EAC1B,KAAK,CACN,CAAA;CACF;;AAED;;;;GAIG;AACH,qBAAa,oBAAqB,SAAQ,yBAGF;CAAG;AAE3C;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,GAChC,eAAe,CAAC,IAAI,EAAE,MAAM,KAAK,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU,EAAE,eAAe,CAAC,UAAU,EAAE,KAAK,CAAC,KACrG,KAAK,CAAC,KAAK,CAAC,oBAAoB,CAG/B,CAAA;AAEJ;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,wDAAwD;IACxD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;IACvD,mCAAmC;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IAC7C,0CAA0C;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,GAC9B,eAAe,MAAM,KACpB,MAAM,CAAC,MAAM,CAAC,oBAAoB,EAAE,UAAU,EAAE,oBAAoB,CAuFnE,CAAA"}
@@ -10,24 +10,23 @@
10
10
  *
11
11
  * @internal
12
12
  */
13
- import * as HttpRouter from "@effect/platform/HttpRouter";
14
- import * as HttpServer from "@effect/platform/HttpServer";
15
- import * as HttpServerRequest from "@effect/platform/HttpServerRequest";
16
- import * as HttpServerResponse from "@effect/platform/HttpServerResponse";
17
13
  import { OAuthError } from "@knpkv/atlassian-common/auth";
18
14
  import * as Context from "effect/Context";
19
15
  import * as Deferred from "effect/Deferred";
20
16
  import * as Effect from "effect/Effect";
17
+ import * as Exit from "effect/Exit";
21
18
  import * as Fiber from "effect/Fiber";
22
19
  import * as Layer from "effect/Layer";
20
+ import * as Scope from "effect/Scope";
21
+ import { HttpRouter, HttpServer, HttpServerResponse } from "effect/unstable/http";
23
22
  const DEFAULT_PORT = 8585;
24
- const MAX_PORT_ATTEMPTS = 10;
23
+ const MAX_PORT = 8594;
25
24
  /**
26
25
  * Tag for the HttpServerFactory service.
27
26
  *
28
27
  * @category Services
29
28
  */
30
- export class HttpServerFactoryTag extends Context.Tag("@knpkv/jira-cli/HttpServerFactory")() {
29
+ export class HttpServerFactoryTag extends Context.Service()("@knpkv/jira-cli/HttpServerFactory") {
31
30
  }
32
31
  /**
33
32
  * Create a HttpServerFactory layer from a layer factory function.
@@ -41,31 +40,6 @@ export class HttpServerFactoryTag extends Context.Tag("@knpkv/jira-cli/HttpServe
41
40
  export const makeHttpServerFactory = (createLayerFn) => Layer.succeed(HttpServerFactoryTag, {
42
41
  createServerLayer: createLayerFn
43
42
  });
44
- /**
45
- * Check if a port is available by attempting to start a server.
46
- */
47
- const isPortAvailable = (port) => Effect.gen(function* () {
48
- const factory = yield* HttpServerFactoryTag;
49
- const serverLayer = factory.createServerLayer(port);
50
- const result = yield* Layer.build(serverLayer).pipe(Effect.scoped, Effect.as(true), Effect.catchAll(() => Effect.succeed(false)));
51
- return result;
52
- });
53
- /**
54
- * Find an available port starting from the default.
55
- */
56
- const findAvailablePort = () => Effect.gen(function* () {
57
- for (let attempt = 0; attempt < MAX_PORT_ATTEMPTS; attempt++) {
58
- const port = DEFAULT_PORT + attempt;
59
- const available = yield* isPortAvailable(port);
60
- if (available) {
61
- return port;
62
- }
63
- }
64
- return yield* Effect.fail(new OAuthError({
65
- step: "authorize",
66
- cause: `Could not find available port (tried ${DEFAULT_PORT}-${DEFAULT_PORT + MAX_PORT_ATTEMPTS - 1}). Close other applications using these ports.`
67
- }));
68
- });
69
43
  /**
70
44
  * Start a local HTTP server to receive OAuth callback.
71
45
  *
@@ -76,11 +50,18 @@ const findAvailablePort = () => Effect.gen(function* () {
76
50
  */
77
51
  export const startCallbackServer = (expectedState) => Effect.gen(function* () {
78
52
  const factory = yield* HttpServerFactoryTag;
79
- const port = yield* findAvailablePort();
80
53
  const deferred = yield* Deferred.make();
81
- const readyDeferred = yield* Deferred.make();
82
- const app = HttpRouter.empty.pipe(HttpRouter.get("/callback", Effect.gen(function* () {
83
- const req = yield* HttpServerRequest.HttpServerRequest;
54
+ const serverScope = yield* Scope.make();
55
+ const buildServerContext = (port) => Layer.buildWithScope(factory.createServerLayer(port), serverScope).pipe(Effect.map((context) => ({ context, port })), Effect.catchCause((cause) => port < MAX_PORT
56
+ ? buildServerContext(port + 1)
57
+ : Effect.fail(new OAuthError({ step: "authorize", cause }))));
58
+ const { context: serverContext } = yield* buildServerContext(DEFAULT_PORT);
59
+ const server = Context.get(serverContext, HttpServer.HttpServer);
60
+ const port = yield* (server.address._tag === "TcpAddress"
61
+ ? Effect.succeed(server.address.port)
62
+ : Effect.fail(new OAuthError({ step: "authorize", cause: "OAuth callback server must listen on a TCP port" })));
63
+ const router = yield* HttpRouter.make;
64
+ yield* router.add("GET", "/callback", (req) => Effect.gen(function* () {
84
65
  const url = new URL(req.url, `http://localhost:${port}`);
85
66
  const code = url.searchParams.get("code");
86
67
  const state = url.searchParams.get("state");
@@ -100,13 +81,15 @@ export const startCallbackServer = (expectedState) => Effect.gen(function* () {
100
81
  }
101
82
  yield* Deferred.succeed(deferred, code);
102
83
  return HttpServerResponse.html("<html><body><h1>Success!</h1><p>You can close this window and return to the terminal.</p></body></html>");
103
- })));
104
- const serverLayer = factory.createServerLayer(port);
105
- const serverFiber = yield* HttpServer.serve(app).pipe(Layer.provide(serverLayer), Layer.build, Effect.tap(() => Deferred.succeed(readyDeferred, undefined)), Effect.tapError((err) => Deferred.fail(readyDeferred, new OAuthError({ step: "authorize", cause: err }))), Effect.flatMap(() => Effect.never), Effect.scoped, Effect.fork);
106
- yield* Deferred.await(readyDeferred);
84
+ }));
85
+ const app = router.asHttpEffect();
86
+ const serverFiber = yield* HttpServer.serveEffect(app).pipe(Effect.provide(serverContext), Effect.provideService(Scope.Scope, serverScope), Effect.forkIn(serverScope));
107
87
  return {
108
88
  codePromise: Deferred.await(deferred),
109
- shutdown: Fiber.interrupt(serverFiber).pipe(Effect.asVoid),
89
+ shutdown: Effect.gen(function* () {
90
+ yield* Fiber.interrupt(serverFiber);
91
+ yield* Scope.close(serverScope, Exit.void);
92
+ }),
110
93
  port
111
94
  };
112
95
  });
@@ -1 +1 @@
1
- {"version":3,"file":"oauthServer.js","sourceRoot":"","sources":["../../src/internal/oauthServer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"oauthServer.js","sourceRoot":"","sources":["../../src/internal/oauthServer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Cross-platform browser launcher backed by Effect v4 child process services.
3
+ *
4
+ * @internal
5
+ */
6
+ import * as Effect from "effect/Effect";
7
+ import type * as PlatformError from "effect/PlatformError";
8
+ import { ChildProcessSpawner } from "effect/unstable/process";
9
+ export declare const openBrowser: (url: string) => Effect.Effect<void, PlatformError.PlatformError, ChildProcessSpawner.ChildProcessSpawner>;
10
+ //# sourceMappingURL=openBrowser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openBrowser.d.ts","sourceRoot":"","sources":["../../src/internal/openBrowser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,KAAK,aAAa,MAAM,sBAAsB,CAAA;AAC1D,OAAO,EAAgB,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAiB3E,eAAO,MAAM,WAAW,GACtB,KAAK,MAAM,KACV,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC,aAAa,EAAE,mBAAmB,CAAC,mBAAmB,CAIxF,CAAA"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Cross-platform browser launcher backed by Effect v4 child process services.
3
+ *
4
+ * @internal
5
+ */
6
+ import * as Effect from "effect/Effect";
7
+ import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
8
+ const run = (command, args) => Effect.gen(function* () {
9
+ const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
10
+ yield* spawner.exitCode(ChildProcess.make(command, args, {
11
+ stdin: "ignore",
12
+ stdout: "ignore",
13
+ stderr: "ignore"
14
+ }));
15
+ });
16
+ export const openBrowser = (url) => run("open", [url]).pipe(Effect.catch(() => run("xdg-open", [url])), Effect.catch(() => run("rundll32.exe", ["url.dll,FileProtocolHandler", url])));
17
+ //# sourceMappingURL=openBrowser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openBrowser.js","sourceRoot":"","sources":["../../src/internal/openBrowser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAE3E,MAAM,GAAG,GAAG,CACV,OAAe,EACf,IAA2B,EACgE,EAAE,CAC7F,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,mBAAmB,CAAC,mBAAmB,CAAA;IAC9D,KAAK,CAAC,CAAC,OAAO,CAAC,QAAQ,CACrB,YAAY,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE;QAC/B,KAAK,EAAE,QAAQ;QACf,MAAM,EAAE,QAAQ;QAChB,MAAM,EAAE,QAAQ;KACjB,CAAC,CACH,CAAA;AACH,CAAC,CAAC,CAAA;AAEJ,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,GAAW,EACgF,EAAE,CAC7F,GAAG,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CACrB,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAC1C,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC,CAAC,CAC9E,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knpkv/jira-cli",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "description": "CLI tool to fetch Jira tickets and export to markdown",
5
5
  "license": "MIT",
6
6
  "author": "knpkv",
@@ -46,23 +46,21 @@
46
46
  "access": "public"
47
47
  },
48
48
  "peerDependencies": {
49
- "@effect/platform": ">=0.93.0 <0.96.0",
50
- "effect": ">=3.19.3"
49
+ "effect": "4.0.0-beta.87"
51
50
  },
52
51
  "dependencies": {
53
- "@effect/cli": "latest",
54
- "@effect/platform-node": "latest",
52
+ "@effect/platform-node": "4.0.0-beta.87",
55
53
  "gray-matter": "^4.0.3",
56
- "@knpkv/atlassian-common": "0.2.0",
57
- "@knpkv/jira-api-client": "0.2.0"
54
+ "@knpkv/agent-skills": "^0.2.0",
55
+ "@knpkv/atlassian-common": "0.3.0",
56
+ "@knpkv/jira-api-client": "0.3.0"
58
57
  },
59
58
  "devDependencies": {
60
- "@effect/platform": "latest",
61
- "@effect/vitest": "latest",
59
+ "@effect/vitest": "4.0.0-beta.87",
62
60
  "@types/node": "latest",
63
- "effect": "latest",
64
- "typescript": "~5.9.0",
65
- "vitest": "^4.0.13"
61
+ "effect": "4.0.0-beta.87",
62
+ "typescript": "~6.0.3",
63
+ "vitest": "^4.1.9"
66
64
  },
67
65
  "keywords": [
68
66
  "effect",
@@ -0,0 +1,90 @@
1
+ ---
2
+ name: jira
3
+ description: Use the @knpkv/jira-cli command line tool to authenticate with Jira Cloud, fetch Jira issues, export issues to markdown, search by JQL or fixVersion, and inspect or update Jira project versions and related work links. Trigger when the user asks an agent to query Jira, collect tickets for release notes, write ticket markdown, inspect release metadata, or attach Confluence release-report links to a Jira version.
4
+ ---
5
+
6
+ # Jira
7
+
8
+ Use the `jira` binary for Jira Cloud issue export and release-version workflows.
9
+
10
+ ## Preconditions
11
+
12
+ - Authenticate first with `jira auth status`, `jira auth create`, `jira auth configure`, and `jira auth login`.
13
+ - Use `--json` on version commands when the agent needs structured data.
14
+ - Use numeric version ids for `jira version view`, `jira version set`, and `jira version relatedwork`.
15
+ - Confirm before commands that mutate Jira: `jira version set` and `jira version relatedwork add`.
16
+
17
+ ## Authentication
18
+
19
+ ```bash
20
+ jira auth status
21
+ jira auth create
22
+ jira auth configure --client-id <id> --client-secret <secret>
23
+ jira auth login
24
+ jira auth login --site https://example.atlassian.net
25
+ ```
26
+
27
+ OAuth scopes used by release workflows include `read:jira-work`, `write:jira-work`, `manage:jira-project`, `read:jira-user`, `read:me`, and `offline_access`.
28
+
29
+ ## Issue Export
30
+
31
+ Fetch one issue as markdown:
32
+
33
+ ```bash
34
+ jira get PROJ-123 --output-dir ./jira-tickets
35
+ ```
36
+
37
+ Search with JQL:
38
+
39
+ ```bash
40
+ jira search 'project = PROJ AND status = Done' --output-dir ./jira-tickets
41
+ jira search 'fixVersion = "1.0.0"' --format single --max-results 200
42
+ ```
43
+
44
+ Search by fix version:
45
+
46
+ ```bash
47
+ jira search --by-version "1.0.0" --project PROJ
48
+ jira search --by-version "1.0.0" --project PROJ --format single
49
+ ```
50
+
51
+ Output formats:
52
+
53
+ - `--format multi` writes one markdown file per issue.
54
+ - `--format single` writes `jira-export.md`.
55
+
56
+ ## Version Workflows
57
+
58
+ List versions:
59
+
60
+ ```bash
61
+ jira version list --project PROJ --json
62
+ jira version list --project PROJ --unreleased --max 10 --json
63
+ jira version list --project PROJ --custom-field "Security & Compliance Impact" --json
64
+ ```
65
+
66
+ View a version:
67
+
68
+ ```bash
69
+ jira version view 10042 --json
70
+ ```
71
+
72
+ Update a version description:
73
+
74
+ ```bash
75
+ jira version set 10042 --description "Q3 release"
76
+ ```
77
+
78
+ Manage related work links:
79
+
80
+ ```bash
81
+ jira version relatedwork list 10042 --json
82
+ jira version relatedwork add 10042 --title "Release notes" --url "https://example.atlassian.net/wiki/spaces/PROJ/pages/123" --category Communication
83
+ ```
84
+
85
+ ## Agent Workflow
86
+
87
+ 1. Use read-only commands first to find issue keys, version ids, and current release metadata.
88
+ 2. Prefer `--json` for release metadata and parse the resulting JSON instead of scraping tables.
89
+ 3. Avoid printing tokens or OAuth secrets. Let interactive commands prompt for secrets when needed.
90
+ 4. Confirm exact version id, title, URL, category, or description before mutating Jira.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Jira CLI"
3
+ short_description: "Search Jira and manage releases"
4
+ default_prompt: "Use $jira to search Jira issues, export markdown, or update release metadata."