@knpkv/jira-cli 1.1.2 → 1.2.1

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 (99) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +23 -7
  3. package/dist/AttachmentService.d.ts +22 -0
  4. package/dist/AttachmentService.d.ts.map +1 -0
  5. package/dist/AttachmentService.js +67 -0
  6. package/dist/AttachmentService.js.map +1 -0
  7. package/dist/IssueService.d.ts +2 -20
  8. package/dist/IssueService.d.ts.map +1 -1
  9. package/dist/IssueService.js +47 -36
  10. package/dist/IssueService.js.map +1 -1
  11. package/dist/JiraAuth.d.ts +1 -1
  12. package/dist/JiraAuth.d.ts.map +1 -1
  13. package/dist/JiraAuth.js.map +1 -1
  14. package/dist/VersionService.d.ts.map +1 -1
  15. package/dist/VersionService.js +39 -45
  16. package/dist/VersionService.js.map +1 -1
  17. package/dist/bin.js +2 -2
  18. package/dist/bin.js.map +1 -1
  19. package/dist/commands/auth.d.ts +1 -1
  20. package/dist/commands/index.d.ts +1 -0
  21. package/dist/commands/index.d.ts.map +1 -1
  22. package/dist/commands/index.js +1 -0
  23. package/dist/commands/index.js.map +1 -1
  24. package/dist/commands/issue.d.ts.map +1 -1
  25. package/dist/commands/issue.js +2 -1
  26. package/dist/commands/issue.js.map +1 -1
  27. package/dist/commands/issueAttachment.d.ts +6 -0
  28. package/dist/commands/issueAttachment.d.ts.map +1 -0
  29. package/dist/commands/issueAttachment.js +88 -0
  30. package/dist/commands/issueAttachment.js.map +1 -0
  31. package/dist/commands/layers.d.ts +4 -3
  32. package/dist/commands/layers.d.ts.map +1 -1
  33. package/dist/commands/layers.js +12 -4
  34. package/dist/commands/layers.js.map +1 -1
  35. package/dist/commands/search.js.map +1 -1
  36. package/dist/index.d.ts +1 -0
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +1 -0
  39. package/dist/index.js.map +1 -1
  40. package/dist/internal/attachmentInsertion.d.ts +10 -0
  41. package/dist/internal/attachmentInsertion.d.ts.map +1 -0
  42. package/dist/internal/attachmentInsertion.js +22 -0
  43. package/dist/internal/attachmentInsertion.js.map +1 -0
  44. package/dist/internal/frontmatter.d.ts.map +1 -1
  45. package/dist/internal/frontmatter.js +15 -3
  46. package/dist/internal/frontmatter.js.map +1 -1
  47. package/dist/internal/sync/baseline.js +2 -1
  48. package/dist/internal/sync/baseline.js.map +1 -1
  49. package/dist/internal/sync/changes.js.map +1 -1
  50. package/dist/internal/sync/config.d.ts.map +1 -1
  51. package/dist/internal/sync/config.js +1 -1
  52. package/dist/internal/sync/config.js.map +1 -1
  53. package/dist/internal/sync/document.d.ts.map +1 -1
  54. package/dist/internal/sync/document.js +88 -29
  55. package/dist/internal/sync/document.js.map +1 -1
  56. package/dist/internal/sync/fieldValues.d.ts +0 -5
  57. package/dist/internal/sync/fieldValues.d.ts.map +1 -1
  58. package/dist/internal/sync/fieldValues.js +9 -4
  59. package/dist/internal/sync/fieldValues.js.map +1 -1
  60. package/dist/internal/sync/manifest.js.map +1 -1
  61. package/dist/internal/sync/schemas.d.ts +5 -5
  62. package/dist/internal/sync/schemas.d.ts.map +1 -1
  63. package/dist/internal/sync/schemas.js +2 -1
  64. package/dist/internal/sync/schemas.js.map +1 -1
  65. package/dist/internal/sync/types.d.ts +5 -2
  66. package/dist/internal/sync/types.d.ts.map +1 -1
  67. package/dist/internal/sync/types.js.map +1 -1
  68. package/package.json +13 -9
  69. package/src/AttachmentService.ts +106 -0
  70. package/src/IssueService.ts +81 -61
  71. package/src/JiraAuth.ts +7 -11
  72. package/src/VersionService.ts +142 -159
  73. package/src/bin.ts +2 -2
  74. package/src/commands/index.ts +1 -0
  75. package/src/commands/issue.ts +3 -2
  76. package/src/commands/issueAttachment.ts +146 -0
  77. package/src/commands/layers.ts +20 -3
  78. package/src/commands/search.ts +1 -1
  79. package/src/index.ts +6 -0
  80. package/src/internal/attachmentInsertion.ts +44 -0
  81. package/src/internal/frontmatter.ts +17 -3
  82. package/src/internal/sync/baseline.ts +3 -3
  83. package/src/internal/sync/changes.ts +1 -1
  84. package/src/internal/sync/config.ts +1 -2
  85. package/src/internal/sync/document.ts +98 -29
  86. package/src/internal/sync/fieldValues.ts +4 -6
  87. package/src/internal/sync/manifest.ts +1 -1
  88. package/src/internal/sync/schemas.ts +3 -2
  89. package/src/internal/sync/types.ts +16 -4
  90. package/test/IssueService.test.ts +94 -0
  91. package/test/VersionService.test.ts +41 -20
  92. package/test/attachmentInsertion.test.ts +25 -0
  93. package/test/commandTree.test.ts +38 -0
  94. package/test/frontmatter.test.ts +20 -1
  95. package/test/integration.test.ts +94 -3
  96. package/test/layers.test.ts +12 -0
  97. package/test/syncDocument.test.ts +30 -1
  98. package/vitest.config.integration.ts +4 -0
  99. package/vitest.config.ts +4 -0
@@ -4,6 +4,7 @@ import * as Layer from "effect/Layer"
4
4
  import * as Ref from "effect/Ref"
5
5
  import * as Terminal from "effect/Terminal"
6
6
  import { Command } from "effect/unstable/cli"
7
+ import { AttachmentService } from "../src/AttachmentService.js"
7
8
  import { issueCommand } from "../src/commands/issue.js"
8
9
  import { versionCommand } from "../src/commands/version.js"
9
10
  import { type Issue, IssueService } from "../src/IssueService.js"
@@ -13,6 +14,7 @@ import { type RelatedWork, type Version, VersionService } from "../src/VersionSe
13
14
  interface CommandCalls {
14
15
  readonly issueGet: number
15
16
  readonly issueSearch: number
17
+ readonly issueAttachmentUpload: number
16
18
  readonly versionList: number
17
19
  readonly versionGet: number
18
20
  readonly versionUpdate: number
@@ -23,6 +25,7 @@ interface CommandCalls {
23
25
 
24
26
  const emptyCalls: CommandCalls = {
25
27
  issueGet: 0,
28
+ issueAttachmentUpload: 0,
26
29
  issueSearch: 0,
27
30
  relatedWorkAdd: 0,
28
31
  relatedWorkList: 0,
@@ -52,6 +55,15 @@ const sampleIssue: Issue = {
52
55
  url: "https://example.atlassian.net/browse/PROJ-123"
53
56
  }
54
57
 
58
+ const sampleAttachment = {
59
+ id: "30001",
60
+ filename: "evidence.png",
61
+ url: "https://example.atlassian.net/rest/api/3/attachment/content/30001",
62
+ mediaType: "image/png",
63
+ mimeType: "image/png",
64
+ size: 123
65
+ }
66
+
55
67
  const sampleVersion: Version = {
56
68
  approvers: [],
57
69
  archived: false,
@@ -88,6 +100,16 @@ const CaptureTerminalLayer = (stdout: Ref.Ref<string>) =>
88
100
 
89
101
  const CommandServicesLayer = (calls: Ref.Ref<CommandCalls>) =>
90
102
  Layer.mergeAll(
103
+ Layer.succeed(
104
+ AttachmentService,
105
+ AttachmentService.of({
106
+ uploadToIssue: () =>
107
+ Ref.update(calls, (state) => ({
108
+ ...state,
109
+ issueAttachmentUpload: state.issueAttachmentUpload + 1
110
+ })).pipe(Effect.as(sampleAttachment))
111
+ })
112
+ ),
91
113
  Layer.succeed(
92
114
  IssueService,
93
115
  IssueService.of({
@@ -158,24 +180,40 @@ describe("Jira command tree", () => {
158
180
  const calls = yield* Ref.make(emptyCalls)
159
181
  const getOutput = yield* Ref.make("")
160
182
  const searchOutput = yield* Ref.make("")
183
+ const uploadOutput = yield* Ref.make("")
161
184
  const legacyGetOutput = yield* Ref.make("")
162
185
  const legacySearchOutput = yield* Ref.make("")
163
186
 
164
187
  const getExit = yield* runJiraCommand(["issue", "get", "PROJ-123"], calls, getOutput)
165
188
  const searchExit = yield* runJiraCommand(["issue", "search", "project = PROJ"], calls, searchOutput)
189
+ const uploadExit = yield* runJiraCommand(
190
+ [
191
+ "issue",
192
+ "attachment",
193
+ "upload",
194
+ "PROJ-123",
195
+ "./evidence.png",
196
+ "--no-insert"
197
+ ],
198
+ calls,
199
+ uploadOutput
200
+ )
166
201
  const legacyGetExit = yield* runJiraCommand(["get", "PROJ-123"], calls, legacyGetOutput)
167
202
  const legacySearchExit = yield* runJiraCommand(["search", "project = PROJ"], calls, legacySearchOutput)
168
203
 
169
204
  expect(getExit._tag).toBe("Success")
170
205
  expect(searchExit._tag).toBe("Success")
206
+ expect(uploadExit._tag).toBe("Success")
171
207
  expect(legacyGetExit._tag).toBe("Failure")
172
208
  expect(legacySearchExit._tag).toBe("Failure")
173
209
 
174
210
  expect(yield* Ref.get(calls)).toMatchObject({
175
211
  issueGet: 1,
212
+ issueAttachmentUpload: 1,
176
213
  issueSearch: 1,
177
214
  writeMulti: 2
178
215
  })
216
+ expect(sampleAttachment.mimeType).toBe(sampleAttachment.mediaType)
179
217
  }))
180
218
 
181
219
  it.effect("exposes canonical version commands and rejects legacy names", () =>
@@ -10,7 +10,10 @@ import type { Issue } from "../src/IssueService.js"
10
10
  */
11
11
  const parseFrontMatter = (output: string): Record<string, unknown> => {
12
12
  const match = output.match(/^---\n([\s\S]*?)\n---/)
13
- return match ? (yaml.load(match[1]) as Record<string, unknown>) : {}
13
+ const parsed = match ? yaml.load(match[1]) : {}
14
+ return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)
15
+ ? Object.fromEntries(Object.entries(parsed))
16
+ : {}
14
17
  }
15
18
 
16
19
  const makeIssue = (overrides: Partial<Issue> = {}): Issue => ({
@@ -57,6 +60,22 @@ describe("frontmatter", () => {
57
60
  expect(data.priority).toBeNull()
58
61
  expect(data.assignee).toBeNull()
59
62
  })
63
+
64
+ it("renders image and SVG attachments as inline previews with identity metadata", () => {
65
+ const output = serializeIssue(makeIssue({
66
+ attachments: [{
67
+ id: "10001",
68
+ filename: "diagram.svg",
69
+ url: "https://example.atlassian.net/rest/api/3/attachment/content/10001",
70
+ mediaType: "application/octet-stream",
71
+ size: 42
72
+ }]
73
+ }))
74
+ expect(output).toContain(
75
+ "<!-- jiraAttachment: {\"jiraAttachmentId\":\"10001\",\"mediaType\":\"application/octet-stream\",\"size\":42} -->"
76
+ )
77
+ expect(output).toContain("![diagram.svg](https://example.atlassian.net/rest/api/3/attachment/content/10001)")
78
+ })
60
79
  })
61
80
 
62
81
  describe("extractFrontMatter", () => {
@@ -10,6 +10,7 @@
10
10
  * - JIRA_BASE_URL defaults to https://knpkv.atlassian.net
11
11
  * - JIRA_ISSUE_KEY defaults to KAN-1
12
12
  */
13
+ import * as NodeHttpClient from "@effect/platform-node/NodeHttpClient"
13
14
  import * as NodeServices from "@effect/platform-node/NodeServices"
14
15
  import { describe, expect, it } from "@effect/vitest"
15
16
  import { JiraApiClient, JiraApiConfig } from "@knpkv/jira-api-client"
@@ -18,11 +19,14 @@ import * as FileSystem from "effect/FileSystem"
18
19
  import * as Path from "effect/Path"
19
20
  import * as Redacted from "effect/Redacted"
20
21
  import * as yaml from "js-yaml"
22
+ import { AttachmentService, layer as AttachmentServiceLayer } from "../src/AttachmentService.js"
23
+ import { insertJiraAttachmentReference } from "../src/internal/attachmentInsertion.js"
21
24
  import { IssueService, layer as IssueServiceLayer, SiteUrl } from "../src/IssueService.js"
22
25
  import { layer as MarkdownWriterLayer, MarkdownWriter } from "../src/MarkdownWriter.js"
23
26
 
24
27
  const DEFAULT_BASE_URL = "https://knpkv.atlassian.net"
25
28
  const DEFAULT_ISSUE_KEY = "KAN-1"
29
+ const INTEGRATION_ATTACHMENT_FILENAME = "inline-attachment.svg"
26
30
 
27
31
  interface IntegrationConfig {
28
32
  readonly baseUrl: string
@@ -54,6 +58,20 @@ const SHOULD_RUN_INTEGRATION = Effect.runSync(
54
58
  )
55
59
  )
56
60
 
61
+ const SHOULD_RUN_ATTACHMENT_INTEGRATION = Effect.runSync(
62
+ Effect.all([
63
+ Config.option(Config.string("JIRA_INTEGRATION")),
64
+ Config.option(Config.string("JIRA_ATTACHMENT_INTEGRATION"))
65
+ ]).pipe(
66
+ Effect.map(([integration, attachment]) =>
67
+ Option.isSome(integration) &&
68
+ envFlagEnabled(integration.value) &&
69
+ Option.isSome(attachment) &&
70
+ envFlagEnabled(attachment.value)
71
+ )
72
+ )
73
+ )
74
+
57
75
  const readIntegrationConfig = Effect.gen(function*() {
58
76
  const baseUrl = yield* Config.option(Config.string("JIRA_BASE_URL"))
59
77
  const issueKey = yield* Config.option(Config.string("JIRA_ISSUE_KEY"))
@@ -72,17 +90,19 @@ const makeIntegrationLayer = (config: IntegrationConfig) => {
72
90
  const configLayer = Layer.succeed(JiraApiConfig, {
73
91
  baseUrl: config.baseUrl,
74
92
  auth: {
75
- type: "basic" as const,
93
+ type: "basic",
76
94
  email: config.email,
77
95
  apiToken: config.apiKey
78
- }
96
+ } satisfies { readonly type: "basic"; readonly email: string; readonly apiToken: typeof config.apiKey }
79
97
  })
80
98
 
81
99
  return MarkdownWriterLayer.pipe(
100
+ Layer.provideMerge(AttachmentServiceLayer),
82
101
  Layer.provideMerge(IssueServiceLayer),
83
102
  Layer.provideMerge(Layer.succeed(SiteUrl, config.baseUrl)),
84
103
  Layer.provideMerge(JiraApiClient.layer),
85
104
  Layer.provideMerge(configLayer),
105
+ Layer.provideMerge(NodeHttpClient.layerUndici),
86
106
  Layer.provideMerge(NodeServices.layer)
87
107
  )
88
108
  }
@@ -102,16 +122,49 @@ const readText = (filePath: string) =>
102
122
  Effect.flatMap((fs) => fs.readFileString(filePath))
103
123
  )
104
124
 
125
+ const writeText = (filePath: string, content: string) =>
126
+ FileSystem.FileSystem.pipe(
127
+ Effect.flatMap((fs) => fs.writeFileString(filePath, content))
128
+ )
129
+
105
130
  const pathExists = (filePath: string) =>
106
131
  FileSystem.FileSystem.pipe(
107
132
  Effect.flatMap((fs) => fs.exists(filePath))
108
133
  )
109
134
 
135
+ const integrationAttachmentFixturePath = Path.Path.pipe(
136
+ Effect.flatMap((path) =>
137
+ path.fromFileUrl(new URL("../../atlassian-common/test/fixtures/attachments/inline-attachment.svg", import.meta.url))
138
+ )
139
+ )
140
+
141
+ const copyIntegrationAttachmentAsset = (testDir: string) =>
142
+ Effect.gen(function*() {
143
+ const source = yield* integrationAttachmentFixturePath
144
+ const target = yield* joinPath(testDir, INTEGRATION_ATTACHMENT_FILENAME)
145
+ yield* writeText(target, yield* readText(source))
146
+ return target
147
+ })
148
+
149
+ const expectCanonicalIssueIncludesAttachmentMedia = (
150
+ config: IntegrationConfig,
151
+ issue: { readonly attachments: ReadonlyArray<{ readonly filename: string }> },
152
+ markdown: string
153
+ ) => {
154
+ if (config.issueKey !== DEFAULT_ISSUE_KEY) return
155
+
156
+ expect(issue.attachments.some((attachment) => attachment.filename === INTEGRATION_ATTACHMENT_FILENAME)).toBe(true)
157
+ expect(markdown).toContain("## Attachments")
158
+ expect(markdown).toContain(`![${INTEGRATION_ATTACHMENT_FILENAME}](`)
159
+ expect(markdown).toContain("jiraAttachmentId")
160
+ expect(markdown).toContain("image/svg+xml")
161
+ }
162
+
110
163
  const parseFrontMatter = (markdown: string): Record<string, unknown> => {
111
164
  const match = /^---\n([\s\S]*?)\n---/.exec(markdown)
112
165
  const parsed = match?.[1] ? yaml.load(match[1]) : {}
113
166
  return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)
114
- ? parsed as Record<string, unknown>
167
+ ? Object.fromEntries(Object.entries(parsed))
115
168
  : {}
116
169
  }
117
170
 
@@ -140,6 +193,7 @@ const getIssueAsMarkdown = (config: IntegrationConfig, testDir: string) =>
140
193
  expect(frontMatter.summary).toBe(issue.summary)
141
194
  expect(typeof frontMatter.status).toBe("string")
142
195
  expect(markdown).toContain(`# ${config.issueKey}:`)
196
+ expectCanonicalIssueIncludesAttachmentMedia(config, issue, markdown)
143
197
 
144
198
  return { frontMatter, issue }
145
199
  })
@@ -184,4 +238,41 @@ describe("Jira integration", () => {
184
238
  }),
185
239
  120000
186
240
  )
241
+
242
+ it.effect.skipIf(!SHOULD_RUN_ATTACHMENT_INTEGRATION)(
243
+ "uploads an SVG attachment and inserts a Markdown attachment reference",
244
+ () =>
245
+ Effect.gen(function*() {
246
+ const config = yield* readIntegrationConfig
247
+ return yield* Effect.gen(function*() {
248
+ const testDir = yield* makeTempRoot
249
+ const assetPath = yield* copyIntegrationAttachmentAsset(testDir)
250
+ const documentPath = yield* joinPath(testDir, `${config.issueKey}.md`)
251
+ yield* writeText(documentPath, `# ${config.issueKey}\n\n![Attachment proof](${assetPath})\n`)
252
+
253
+ const attachmentService = yield* AttachmentService
254
+ const issueService = yield* IssueService
255
+ const attachment = yield* attachmentService.uploadToIssue(config.issueKey, { filePath: assetPath })
256
+ expect(attachment.id).toBeTruthy()
257
+ expect(attachment.filename).toBe(INTEGRATION_ATTACHMENT_FILENAME)
258
+ expect(attachment.mediaType === null || attachment.mediaType.includes("svg")).toBe(true)
259
+
260
+ const issue = yield* issueService.getByKey(config.issueKey)
261
+ expect(issue.attachments.some((candidate) => candidate.id === attachment.id)).toBe(true)
262
+
263
+ const insertion = insertJiraAttachmentReference(yield* readText(documentPath), assetPath, attachment)
264
+ expect(insertion.replacements).toBe(1)
265
+ yield* writeText(documentPath, insertion.content)
266
+
267
+ const updated = yield* readText(documentPath)
268
+ expect(updated).toContain(`"jiraAttachmentId":"${attachment.id}"`)
269
+ expect(updated).toContain(`![${INTEGRATION_ATTACHMENT_FILENAME}](`)
270
+ expect(updated).not.toContain(`![Attachment proof](${assetPath})`)
271
+ }).pipe(
272
+ Effect.provide(makeIntegrationLayer(config)),
273
+ Effect.scoped
274
+ )
275
+ }),
276
+ 120000
277
+ )
187
278
  })
@@ -0,0 +1,12 @@
1
+ import { describe, expect, it } from "@effect/vitest"
2
+ import { getLayerType } from "../src/commands/layers.js"
3
+
4
+ describe("getLayerType", () => {
5
+ it("routes attachment upload dry-runs to the config-free minimal layer", () => {
6
+ expect(getLayerType(["issue", "attachment", "upload", "PROJ-1", "./evidence.png", "--dry-run"])).toBe(
7
+ "minimal"
8
+ )
9
+ expect(getLayerType(["issue", "attachment", "upload", "PROJ-1", "./evidence.png", "-n"])).toBe("minimal")
10
+ expect(getLayerType(["issue", "attachment", "upload", "PROJ-1", "./evidence.png"])).toBe("full")
11
+ })
12
+ })
@@ -29,7 +29,13 @@ const document: IssueDocument = {
29
29
  created: "2026-06-27",
30
30
  body: "Existing Jira comment."
31
31
  }],
32
- attachments: [{ filename: "evidence.png", url: "https://example.atlassian.net/evidence.png" }],
32
+ attachments: [{
33
+ id: "30001",
34
+ filename: "evidence.png",
35
+ url: "https://example.atlassian.net/evidence.png",
36
+ mediaType: "image/png",
37
+ size: 1234
38
+ }],
33
39
  localNotes: "Private local note."
34
40
  }
35
41
 
@@ -66,4 +72,27 @@ describe("Issue Document parsing", () => {
66
72
  const serialized = serializeIssueDocument(document).replace("<!-- draftId: draft-1 -->", "<!-- draft: draft-1 -->")
67
73
  expect(() => parseIssueDocument("PROJ-123.md", serialized)).toThrow(SyncValidationError)
68
74
  })
75
+
76
+ it("renders image attachments inline with hidden identity metadata", () => {
77
+ const serialized = serializeIssueDocument(document)
78
+ expect(serialized).toContain(
79
+ "<!-- jiraAttachment: {\"jiraAttachmentId\":\"30001\",\"mediaType\":\"image/png\",\"size\":1234} -->"
80
+ )
81
+ expect(serialized).toContain("![evidence.png](https://example.atlassian.net/evidence.png)")
82
+ })
83
+
84
+ it("keeps parsing legacy attachment link lines", () => {
85
+ const serialized = serializeIssueDocument(document).replace(
86
+ /<!-- jiraAttachment:[\s\S]*?\n!\[evidence\.png]\(https:\/\/example\.atlassian\.net\/evidence\.png\)/,
87
+ "- [evidence.png](https://example.atlassian.net/evidence.png)"
88
+ )
89
+ const parsed = parseIssueDocument("PROJ-123.md", serialized)
90
+ expect(parsed.attachments).toEqual([{
91
+ id: "",
92
+ filename: "evidence.png",
93
+ url: "https://example.atlassian.net/evidence.png",
94
+ mediaType: null,
95
+ size: null
96
+ }])
97
+ })
69
98
  })
@@ -3,6 +3,10 @@ import { defineConfig } from "vitest/config"
3
3
  export default defineConfig({
4
4
  resolve: {
5
5
  alias: {
6
+ "@knpkv/atlassian-common/attachments": new URL("../atlassian-common/src/attachments.ts", import.meta.url).pathname,
7
+ "@knpkv/atlassian-common/auth": new URL("../atlassian-common/src/auth/index.ts", import.meta.url).pathname,
8
+ "@knpkv/atlassian-common/config": new URL("../atlassian-common/src/config/index.ts", import.meta.url).pathname,
9
+ "@knpkv/agent-skills": new URL("../agent-skills/src/index.ts", import.meta.url).pathname,
6
10
  "@knpkv/jira-api-client": new URL("../jira-api-client/src/index.ts", import.meta.url).pathname
7
11
  }
8
12
  },
package/vitest.config.ts CHANGED
@@ -3,6 +3,10 @@ import { defineConfig } from "vitest/config"
3
3
  export default defineConfig({
4
4
  resolve: {
5
5
  alias: {
6
+ "@knpkv/atlassian-common/attachments": new URL("../atlassian-common/src/attachments.ts", import.meta.url).pathname,
7
+ "@knpkv/atlassian-common/auth": new URL("../atlassian-common/src/auth/index.ts", import.meta.url).pathname,
8
+ "@knpkv/atlassian-common/config": new URL("../atlassian-common/src/config/index.ts", import.meta.url).pathname,
9
+ "@knpkv/agent-skills": new URL("../agent-skills/src/index.ts", import.meta.url).pathname,
6
10
  "@knpkv/jira-api-client": new URL("../jira-api-client/src/index.ts", import.meta.url).pathname
7
11
  }
8
12
  },