@knpkv/jira-cli 0.1.1 → 1.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 (143) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/README.md +66 -4
  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/JiraCliError.d.ts +30 -0
  12. package/dist/JiraCliError.d.ts.map +1 -1
  13. package/dist/JiraCliError.js +14 -0
  14. package/dist/JiraCliError.js.map +1 -1
  15. package/dist/MarkdownWriter.d.ts +4 -4
  16. package/dist/MarkdownWriter.d.ts.map +1 -1
  17. package/dist/MarkdownWriter.js +6 -6
  18. package/dist/MarkdownWriter.js.map +1 -1
  19. package/dist/SyncWorkspace.d.ts +34 -0
  20. package/dist/SyncWorkspace.d.ts.map +1 -0
  21. package/dist/SyncWorkspace.js +105 -0
  22. package/dist/SyncWorkspace.js.map +1 -0
  23. package/dist/VersionService.d.ts +206 -0
  24. package/dist/VersionService.d.ts.map +1 -0
  25. package/dist/VersionService.js +426 -0
  26. package/dist/VersionService.js.map +1 -0
  27. package/dist/bin.js +29 -22
  28. package/dist/bin.js.map +1 -1
  29. package/dist/commands/auth.d.ts +2 -21
  30. package/dist/commands/auth.d.ts.map +1 -1
  31. package/dist/commands/auth.js +6 -6
  32. package/dist/commands/auth.js.map +1 -1
  33. package/dist/commands/get.d.ts +3 -8
  34. package/dist/commands/get.d.ts.map +1 -1
  35. package/dist/commands/get.js +4 -4
  36. package/dist/commands/get.js.map +1 -1
  37. package/dist/commands/index.d.ts +2 -2
  38. package/dist/commands/index.d.ts.map +1 -1
  39. package/dist/commands/index.js +2 -2
  40. package/dist/commands/index.js.map +1 -1
  41. package/dist/commands/issue.d.ts +8 -0
  42. package/dist/commands/issue.d.ts.map +1 -0
  43. package/dist/commands/issue.js +10 -0
  44. package/dist/commands/issue.js.map +1 -0
  45. package/dist/commands/layers.d.ts +6 -18
  46. package/dist/commands/layers.d.ts.map +1 -1
  47. package/dist/commands/layers.js +35 -24
  48. package/dist/commands/layers.js.map +1 -1
  49. package/dist/commands/search.d.ts +3 -8
  50. package/dist/commands/search.d.ts.map +1 -1
  51. package/dist/commands/search.js +8 -8
  52. package/dist/commands/search.js.map +1 -1
  53. package/dist/commands/version.d.ts +12 -0
  54. package/dist/commands/version.d.ts.map +1 -0
  55. package/dist/commands/version.js +179 -0
  56. package/dist/commands/version.js.map +1 -0
  57. package/dist/internal/frontmatter.d.ts.map +1 -1
  58. package/dist/internal/frontmatter.js +14 -1
  59. package/dist/internal/frontmatter.js.map +1 -1
  60. package/dist/internal/oauthServer.d.ts +17 -5
  61. package/dist/internal/oauthServer.d.ts.map +1 -1
  62. package/dist/internal/oauthServer.js +23 -40
  63. package/dist/internal/oauthServer.js.map +1 -1
  64. package/dist/internal/openBrowser.d.ts +10 -0
  65. package/dist/internal/openBrowser.d.ts.map +1 -0
  66. package/dist/internal/openBrowser.js +17 -0
  67. package/dist/internal/openBrowser.js.map +1 -0
  68. package/dist/internal/sync/baseline.d.ts +11 -0
  69. package/dist/internal/sync/baseline.d.ts.map +1 -0
  70. package/dist/internal/sync/baseline.js +18 -0
  71. package/dist/internal/sync/baseline.js.map +1 -0
  72. package/dist/internal/sync/changes.d.ts +15 -0
  73. package/dist/internal/sync/changes.d.ts.map +1 -0
  74. package/dist/internal/sync/changes.js +72 -0
  75. package/dist/internal/sync/changes.js.map +1 -0
  76. package/dist/internal/sync/config.d.ts +12 -0
  77. package/dist/internal/sync/config.d.ts.map +1 -0
  78. package/dist/internal/sync/config.js +53 -0
  79. package/dist/internal/sync/config.js.map +1 -0
  80. package/dist/internal/sync/document.d.ts +9 -0
  81. package/dist/internal/sync/document.d.ts.map +1 -0
  82. package/dist/internal/sync/document.js +173 -0
  83. package/dist/internal/sync/document.js.map +1 -0
  84. package/dist/internal/sync/fieldValues.d.ts +30 -0
  85. package/dist/internal/sync/fieldValues.d.ts.map +1 -0
  86. package/dist/internal/sync/fieldValues.js +91 -0
  87. package/dist/internal/sync/fieldValues.js.map +1 -0
  88. package/dist/internal/sync/manifest.d.ts +12 -0
  89. package/dist/internal/sync/manifest.d.ts.map +1 -0
  90. package/dist/internal/sync/manifest.js +23 -0
  91. package/dist/internal/sync/manifest.js.map +1 -0
  92. package/dist/internal/sync/paths.d.ts +26 -0
  93. package/dist/internal/sync/paths.d.ts.map +1 -0
  94. package/dist/internal/sync/paths.js +22 -0
  95. package/dist/internal/sync/paths.js.map +1 -0
  96. package/dist/internal/sync/schemas.d.ts +128 -0
  97. package/dist/internal/sync/schemas.d.ts.map +1 -0
  98. package/dist/internal/sync/schemas.js +82 -0
  99. package/dist/internal/sync/schemas.js.map +1 -0
  100. package/dist/internal/sync/types.d.ts +144 -0
  101. package/dist/internal/sync/types.d.ts.map +1 -0
  102. package/dist/internal/sync/types.js +17 -0
  103. package/dist/internal/sync/types.js.map +1 -0
  104. package/package.json +13 -12
  105. package/skills/jira/SKILL.md +90 -0
  106. package/skills/jira/agents/openai.yaml +4 -0
  107. package/src/IssueService.ts +34 -28
  108. package/src/JiraAuth.ts +53 -39
  109. package/src/JiraCliError.ts +24 -0
  110. package/src/MarkdownWriter.ts +7 -11
  111. package/src/SyncWorkspace.ts +185 -0
  112. package/src/VersionService.ts +647 -0
  113. package/src/bin.ts +39 -29
  114. package/src/commands/auth.ts +6 -12
  115. package/src/commands/get.ts +4 -4
  116. package/src/commands/index.ts +2 -2
  117. package/src/commands/issue.ts +13 -0
  118. package/src/commands/layers.ts +44 -26
  119. package/src/commands/search.ts +8 -8
  120. package/src/commands/version.ts +267 -0
  121. package/src/internal/frontmatter.ts +15 -1
  122. package/src/internal/oauthServer.ts +43 -70
  123. package/src/internal/openBrowser.ts +31 -0
  124. package/src/internal/sync/baseline.ts +27 -0
  125. package/src/internal/sync/changes.ts +118 -0
  126. package/src/internal/sync/config.ts +76 -0
  127. package/src/internal/sync/document.ts +201 -0
  128. package/src/internal/sync/fieldValues.ts +145 -0
  129. package/src/internal/sync/manifest.ts +32 -0
  130. package/src/internal/sync/paths.ts +48 -0
  131. package/src/internal/sync/schemas.ts +103 -0
  132. package/src/internal/sync/types.ts +192 -0
  133. package/test/SyncWorkspace.test.ts +76 -0
  134. package/test/VersionService.test.ts +266 -0
  135. package/test/commandTree.test.ts +266 -0
  136. package/test/frontmatter.test.ts +69 -0
  137. package/test/integration.test.ts +187 -0
  138. package/test/syncChanges.test.ts +106 -0
  139. package/test/syncConfig.test.ts +138 -0
  140. package/test/syncDocument.test.ts +69 -0
  141. package/test/syncFieldValues.test.ts +101 -0
  142. package/vitest.config.integration.ts +17 -0
  143. package/vitest.config.ts +6 -0
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Runtime schemas for Jira Markdown Sync local workspace files.
3
+ *
4
+ * @internal
5
+ */
6
+ import * as Effect from "effect/Effect";
7
+ import * as Schema from "effect/Schema";
8
+ import { FIELD_SHAPES } from "./types.js";
9
+ const SiteUrl = Schema.String.pipe(Schema.check(Schema.isPattern(/^https:\/\/[a-z0-9][a-z0-9-]*\.atlassian\.net$/)));
10
+ const NonEmptyString = Schema.String.pipe(Schema.check(Schema.isMinLength(1)));
11
+ export const FieldShapeSchema = Schema.Literals(FIELD_SHAPES);
12
+ export const RequestedCustomFieldSchema = Schema.Struct({
13
+ displayName: NonEmptyString,
14
+ fieldId: Schema.optional(NonEmptyString),
15
+ shape: FieldShapeSchema,
16
+ ordered: Schema.optional(Schema.Boolean)
17
+ });
18
+ export const WorkspaceConfigSchema = Schema.Struct({
19
+ version: Schema.Literal(1).pipe(Schema.withDecodingDefaultTypeKey(Effect.succeed(1))),
20
+ siteUrl: SiteUrl,
21
+ documentsDir: NonEmptyString.pipe(Schema.withDecodingDefaultTypeKey(Effect.succeed("issues"))),
22
+ customFields: Schema.Array(RequestedCustomFieldSchema).pipe(Schema.withDecodingDefaultTypeKey(Effect.succeed([])))
23
+ });
24
+ export const ManifestIssueSchema = Schema.Struct({
25
+ issueId: NonEmptyString,
26
+ issueKey: NonEmptyString,
27
+ documentPath: NonEmptyString,
28
+ filenameMode: Schema.Literals(["convention", "custom"])
29
+ });
30
+ export const SyncManifestSchema = Schema.Struct({
31
+ version: Schema.Literal(1),
32
+ siteUrl: SiteUrl,
33
+ issues: Schema.Array(ManifestIssueSchema)
34
+ });
35
+ const UserFieldValueSchema = Schema.Struct({
36
+ accountId: NonEmptyString,
37
+ displayName: NonEmptyString
38
+ });
39
+ const OptionFieldValueSchema = Schema.Struct({
40
+ id: Schema.optional(NonEmptyString),
41
+ value: NonEmptyString
42
+ });
43
+ const CascadingFieldValueSchema = Schema.Struct({
44
+ parent: OptionFieldValueSchema,
45
+ child: Schema.optional(OptionFieldValueSchema)
46
+ });
47
+ const SyncFieldValueItemSchema = Schema.Union([
48
+ Schema.String,
49
+ Schema.Number,
50
+ Schema.Boolean,
51
+ UserFieldValueSchema,
52
+ OptionFieldValueSchema
53
+ ]);
54
+ export const SyncFieldValueSchema = Schema.Union([
55
+ Schema.String,
56
+ Schema.Number,
57
+ Schema.Boolean,
58
+ Schema.Null,
59
+ UserFieldValueSchema,
60
+ OptionFieldValueSchema,
61
+ CascadingFieldValueSchema,
62
+ Schema.Array(SyncFieldValueItemSchema)
63
+ ]);
64
+ export const BaselineCustomFieldSchema = Schema.Struct({
65
+ fieldId: NonEmptyString,
66
+ displayName: NonEmptyString,
67
+ shape: FieldShapeSchema,
68
+ value: SyncFieldValueSchema
69
+ });
70
+ export const SyncBaselineSchema = Schema.Struct({
71
+ version: Schema.Literal(1),
72
+ issueId: NonEmptyString,
73
+ issueKey: NonEmptyString,
74
+ fields: Schema.Struct({
75
+ summary: Schema.String,
76
+ description: Schema.String,
77
+ labels: Schema.Array(Schema.String),
78
+ customFields: Schema.Record(Schema.String, BaselineCustomFieldSchema)
79
+ }),
80
+ comments: Schema.Array(Schema.Struct({ id: NonEmptyString }))
81
+ });
82
+ //# sourceMappingURL=schemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../../src/internal/sync/schemas.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Core domain types for Jira Markdown Sync local workspace state.
3
+ *
4
+ * @internal
5
+ */
6
+ export declare const FIELD_SHAPES: readonly ["text", "multilineText", "number", "boolean", "date", "singleSelect", "multiSelect", "user", "cascadingSelect"];
7
+ export type FieldShape = typeof FIELD_SHAPES[number];
8
+ export interface RequestedCustomField {
9
+ readonly displayName: string;
10
+ readonly fieldId?: string | undefined;
11
+ readonly shape: FieldShape;
12
+ readonly ordered?: boolean | undefined;
13
+ }
14
+ export interface WorkspaceConfig {
15
+ readonly version: 1;
16
+ readonly siteUrl: string;
17
+ readonly documentsDir: string;
18
+ readonly customFields: ReadonlyArray<RequestedCustomField>;
19
+ }
20
+ export type FilenameMode = "convention" | "custom";
21
+ export interface ManifestIssue {
22
+ readonly issueId: string;
23
+ readonly issueKey: string;
24
+ readonly documentPath: string;
25
+ readonly filenameMode: FilenameMode;
26
+ }
27
+ export interface SyncManifest {
28
+ readonly version: 1;
29
+ readonly siteUrl: string;
30
+ readonly issues: ReadonlyArray<ManifestIssue>;
31
+ }
32
+ export interface UserFieldValue {
33
+ readonly accountId: string;
34
+ readonly displayName: string;
35
+ }
36
+ export interface OptionFieldValue {
37
+ readonly id?: string | undefined;
38
+ readonly value: string;
39
+ }
40
+ export interface CascadingFieldValue {
41
+ readonly parent: OptionFieldValue;
42
+ readonly child?: OptionFieldValue | undefined;
43
+ }
44
+ export type SyncFieldScalar = string | number | boolean | null;
45
+ export type SyncFieldValue = SyncFieldScalar | UserFieldValue | OptionFieldValue | CascadingFieldValue | ReadonlyArray<string | number | boolean | UserFieldValue | OptionFieldValue>;
46
+ export interface BaselineCustomField {
47
+ readonly fieldId: string;
48
+ readonly displayName: string;
49
+ readonly shape: FieldShape;
50
+ readonly value: SyncFieldValue;
51
+ }
52
+ export interface SyncBaselineFields {
53
+ readonly summary: string;
54
+ readonly description: string;
55
+ readonly labels: ReadonlyArray<string>;
56
+ readonly customFields: Readonly<Record<string, BaselineCustomField>>;
57
+ }
58
+ export interface SyncBaselineComment {
59
+ readonly id: string;
60
+ }
61
+ export interface SyncBaseline {
62
+ readonly version: 1;
63
+ readonly issueId: string;
64
+ readonly issueKey: string;
65
+ readonly fields: SyncBaselineFields;
66
+ readonly comments: ReadonlyArray<SyncBaselineComment>;
67
+ }
68
+ export interface IssueDocumentFrontMatter {
69
+ readonly issueId: string;
70
+ readonly issueKey: string;
71
+ readonly summary: string;
72
+ readonly status: string;
73
+ readonly issueType: string;
74
+ readonly priority: string | null;
75
+ readonly assignee: UserFieldValue | null;
76
+ readonly reporter: UserFieldValue | null;
77
+ readonly labels: ReadonlyArray<string>;
78
+ readonly customFields: Readonly<Record<string, SyncFieldValue>>;
79
+ }
80
+ export interface CommentDraft {
81
+ readonly draftId: string;
82
+ readonly body: string;
83
+ }
84
+ export interface AcceptedComment {
85
+ readonly id: string;
86
+ readonly author: string;
87
+ readonly created: string;
88
+ readonly body: string;
89
+ }
90
+ export interface AttachmentReference {
91
+ readonly filename: string;
92
+ readonly url: string;
93
+ }
94
+ export interface IssueDocument {
95
+ readonly frontMatter: IssueDocumentFrontMatter;
96
+ readonly description: string;
97
+ readonly multilineCustomFields: Readonly<Record<string, string>>;
98
+ readonly commentDrafts: ReadonlyArray<CommentDraft>;
99
+ readonly acceptedComments: ReadonlyArray<AcceptedComment>;
100
+ readonly attachments: ReadonlyArray<AttachmentReference>;
101
+ readonly localNotes: string;
102
+ }
103
+ export type SyncFieldPath = "summary" | "description" | "labels" | `customFields.${string}` | `readOnly.${string}`;
104
+ export interface SyncValidationFailure {
105
+ readonly _tag: "ValidationFailure";
106
+ readonly message: string;
107
+ readonly issueKey?: string;
108
+ readonly field?: SyncFieldPath;
109
+ readonly path?: string;
110
+ }
111
+ export interface SyncConflict {
112
+ readonly issueId: string;
113
+ readonly issueKey: string;
114
+ readonly field: SyncFieldPath;
115
+ readonly baselineValue: SyncFieldValue;
116
+ readonly jiraValue: SyncFieldValue;
117
+ readonly documentValue: SyncFieldValue;
118
+ }
119
+ export type PlannedFieldChange = {
120
+ readonly _tag: "RemoteOnly";
121
+ readonly issueId: string;
122
+ readonly issueKey: string;
123
+ readonly field: SyncFieldPath;
124
+ readonly jiraValue: SyncFieldValue;
125
+ } | {
126
+ readonly _tag: "LocalOnly";
127
+ readonly issueId: string;
128
+ readonly issueKey: string;
129
+ readonly field: SyncFieldPath;
130
+ readonly documentValue: SyncFieldValue;
131
+ } | {
132
+ readonly _tag: "Conflict";
133
+ readonly issueId: string;
134
+ readonly issueKey: string;
135
+ readonly field: SyncFieldPath;
136
+ readonly baselineValue: SyncFieldValue;
137
+ readonly jiraValue: SyncFieldValue;
138
+ readonly documentValue: SyncFieldValue;
139
+ };
140
+ export interface SyncPlan {
141
+ readonly changes: ReadonlyArray<PlannedFieldChange>;
142
+ readonly validationFailures: ReadonlyArray<SyncValidationFailure>;
143
+ }
144
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/internal/sync/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Core domain types for Jira Markdown Sync local workspace state.
3
+ *
4
+ * @internal
5
+ */
6
+ export const FIELD_SHAPES = [
7
+ "text",
8
+ "multilineText",
9
+ "number",
10
+ "boolean",
11
+ "date",
12
+ "singleSelect",
13
+ "multiSelect",
14
+ "user",
15
+ "cascadingSelect"
16
+ ];
17
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/internal/sync/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,MAAM;IACN,eAAe;IACf,QAAQ;IACR,SAAS;IACT,MAAM;IACN,cAAc;IACd,aAAa;IACb,MAAM;IACN,iBAAiB;CACT,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knpkv/jira-cli",
3
- "version": "0.1.1",
3
+ "version": "1.0.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,23 @@
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
+ "js-yaml": "^4.1.0",
55
+ "@knpkv/agent-skills": "^0.2.1",
56
+ "@knpkv/atlassian-common": "0.3.0",
57
+ "@knpkv/jira-api-client": "0.3.0"
58
58
  },
59
59
  "devDependencies": {
60
- "@effect/platform": "latest",
61
- "@effect/vitest": "latest",
60
+ "@effect/vitest": "4.0.0-beta.87",
61
+ "@types/js-yaml": "^4.0.9",
62
62
  "@types/node": "latest",
63
- "effect": "latest",
64
- "typescript": "~5.9.0",
65
- "vitest": "^4.0.13"
63
+ "effect": "4.0.0-beta.87",
64
+ "typescript": "~6.0.3",
65
+ "vitest": "^4.1.9"
66
66
  },
67
67
  "keywords": [
68
68
  "effect",
@@ -78,6 +78,7 @@
78
78
  "build": "tsc",
79
79
  "clean": "rimraf dist dist-test .tsbuildinfo",
80
80
  "test": "vitest run",
81
+ "test:integration": "vitest run --config vitest.config.integration.ts",
81
82
  "test:watch": "vitest",
82
83
  "lint": "eslint src",
83
84
  "lint:fix": "eslint src --fix",
@@ -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 get`, `jira version update`, and `jira version related-work`.
15
+ - Confirm before remote write commands: `jira version update` and `jira version related-work 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 issue get PROJ-123 --output-dir ./jira-tickets
35
+ ```
36
+
37
+ Search with JQL:
38
+
39
+ ```bash
40
+ jira issue search 'project = PROJ AND status = Done' --output-dir ./jira-tickets
41
+ jira issue search 'fixVersion = "1.0.0"' --format single --max-results 200
42
+ ```
43
+
44
+ Search by fix version:
45
+
46
+ ```bash
47
+ jira issue search --by-version "1.0.0" --project PROJ
48
+ jira issue 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 get 10042 --json
70
+ ```
71
+
72
+ Update a version description:
73
+
74
+ ```bash
75
+ jira version update 10042 --description "Q3 release"
76
+ ```
77
+
78
+ Manage related work links:
79
+
80
+ ```bash
81
+ jira version related-work list 10042 --json
82
+ jira version related-work 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."
@@ -29,7 +29,7 @@ import { JiraApiError } from "./JiraCliError.js"
29
29
  *
30
30
  * @category Config
31
31
  */
32
- export class SiteUrl extends Context.Tag("@knpkv/jira-cli/SiteUrl")<SiteUrl, string>() {}
32
+ export class SiteUrl extends Context.Service<SiteUrl, string>()("@knpkv/jira-cli/SiteUrl") {}
33
33
 
34
34
  /**
35
35
  * Attachment metadata.
@@ -104,6 +104,12 @@ export interface SearchResult {
104
104
  readonly maxResults: number
105
105
  }
106
106
 
107
+ interface SearchJqlResponse {
108
+ readonly issues?: ReadonlyArray<unknown>
109
+ readonly isLast?: boolean
110
+ readonly nextPageToken?: string
111
+ }
112
+
107
113
  /**
108
114
  * IssueService interface.
109
115
  *
@@ -138,10 +144,10 @@ export interface IssueServiceShape {
138
144
  *
139
145
  * @category Services
140
146
  */
141
- export class IssueService extends Context.Tag("@knpkv/jira-cli/IssueService")<
147
+ export class IssueService extends Context.Service<
142
148
  IssueService,
143
149
  IssueServiceShape
144
- >() {}
150
+ >()("@knpkv/jira-cli/IssueService") {}
145
151
 
146
152
  const FIELDS = [
147
153
  "summary",
@@ -299,7 +305,7 @@ const make = Effect.gen(function*() {
299
305
  jql: string,
300
306
  maxResults: number,
301
307
  nextPageToken?: string
302
- ) =>
308
+ ): Effect.Effect<SearchJqlResponse, JiraApiError> =>
303
309
  toEffect(client.v3.client.GET("/rest/api/3/search/jql", {
304
310
  params: {
305
311
  query: {
@@ -311,6 +317,7 @@ const make = Effect.gen(function*() {
311
317
  }
312
318
  }
313
319
  })).pipe(
320
+ Effect.map((result) => result as SearchJqlResponse),
314
321
  Effect.mapError((cause) => new JiraApiError({ message: "Failed to search issues", cause }))
315
322
  )
316
323
 
@@ -336,36 +343,35 @@ const make = Effect.gen(function*() {
336
343
  const searchAll = (
337
344
  jql: string,
338
345
  options?: { readonly maxResults?: number }
339
- ): Effect.Effect<ReadonlyArray<Issue>, JiraApiError> =>
340
- Effect.gen(function*() {
341
- const allIssues: Array<Issue> = []
342
- const maxResults = options?.maxResults ?? 100
343
- let nextPageToken: string | undefined = undefined
344
- let pageCount = 0
345
-
346
- // Fetch first page
347
- let result = yield* searchJql(jql, maxResults, nextPageToken)
348
- let issues = result.issues ?? []
346
+ ): Effect.Effect<ReadonlyArray<Issue>, JiraApiError> => (Effect.gen(function*() {
347
+ const allIssues: Array<Issue> = []
348
+ const maxResults = options?.maxResults ?? 100
349
+ let nextPageToken: string | undefined = undefined
350
+ let pageCount = 0
351
+
352
+ // Fetch first page
353
+ let result = yield* searchJql(jql, maxResults, nextPageToken)
354
+ let issues = result.issues ?? []
355
+ pageCount++
356
+
357
+ for (const bean of issues) {
358
+ allIssues.push(mapIssue(bean as unknown as Record<string, unknown>, siteUrl))
359
+ }
360
+
361
+ // Fetch remaining pages with iteration guard
362
+ while (!result.isLast && result.nextPageToken && pageCount < MAX_PAGES) {
363
+ nextPageToken = result.nextPageToken
364
+ result = yield* searchJql(jql, maxResults, nextPageToken)
365
+ issues = result.issues ?? []
349
366
  pageCount++
350
367
 
351
368
  for (const bean of issues) {
352
369
  allIssues.push(mapIssue(bean as unknown as Record<string, unknown>, siteUrl))
353
370
  }
371
+ }
354
372
 
355
- // Fetch remaining pages with iteration guard
356
- while (!result.isLast && result.nextPageToken && pageCount < MAX_PAGES) {
357
- nextPageToken = result.nextPageToken
358
- result = yield* searchJql(jql, maxResults, nextPageToken)
359
- issues = result.issues ?? []
360
- pageCount++
361
-
362
- for (const bean of issues) {
363
- allIssues.push(mapIssue(bean as unknown as Record<string, unknown>, siteUrl))
364
- }
365
- }
366
-
367
- return allIssues
368
- })
373
+ return allIssues
374
+ }) as Effect.Effect<ReadonlyArray<Issue>, JiraApiError>)
369
375
 
370
376
  return IssueService.of({ getByKey, search, searchAll })
371
377
  })