@jiraacp/cli 2026.405.4

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 (113) hide show
  1. package/README.md +283 -0
  2. package/dist/abort-GQE4OI5S.js +103 -0
  3. package/dist/abort-GQE4OI5S.js.map +1 -0
  4. package/dist/abort-VMRQOADY.js +96 -0
  5. package/dist/abort-VMRQOADY.js.map +1 -0
  6. package/dist/bot-WOTETAJY.js +13 -0
  7. package/dist/bot-WOTETAJY.js.map +1 -0
  8. package/dist/cancel-clarification-4G5S2HJZ.js +64 -0
  9. package/dist/cancel-clarification-4G5S2HJZ.js.map +1 -0
  10. package/dist/chunk-3U373M37.js +67 -0
  11. package/dist/chunk-3U373M37.js.map +1 -0
  12. package/dist/chunk-3YHD4SIN.js +97 -0
  13. package/dist/chunk-3YHD4SIN.js.map +1 -0
  14. package/dist/chunk-6IY6CRUJ.js +690 -0
  15. package/dist/chunk-6IY6CRUJ.js.map +1 -0
  16. package/dist/chunk-B6OA3XJK.js +1167 -0
  17. package/dist/chunk-B6OA3XJK.js.map +1 -0
  18. package/dist/chunk-BM4R6NST.js +191 -0
  19. package/dist/chunk-BM4R6NST.js.map +1 -0
  20. package/dist/chunk-FLPIU2QO.js +77 -0
  21. package/dist/chunk-FLPIU2QO.js.map +1 -0
  22. package/dist/chunk-H7YXX4UA.js +86 -0
  23. package/dist/chunk-H7YXX4UA.js.map +1 -0
  24. package/dist/chunk-IT74N3UH.js +19 -0
  25. package/dist/chunk-IT74N3UH.js.map +1 -0
  26. package/dist/chunk-JOT4UVSO.js +186 -0
  27. package/dist/chunk-JOT4UVSO.js.map +1 -0
  28. package/dist/chunk-KSJKCLEJ.js +222 -0
  29. package/dist/chunk-KSJKCLEJ.js.map +1 -0
  30. package/dist/chunk-LIEW4ULF.js +139 -0
  31. package/dist/chunk-LIEW4ULF.js.map +1 -0
  32. package/dist/chunk-M4V3YOCY.js +82 -0
  33. package/dist/chunk-M4V3YOCY.js.map +1 -0
  34. package/dist/chunk-MMWQHH25.js +207 -0
  35. package/dist/chunk-MMWQHH25.js.map +1 -0
  36. package/dist/chunk-OJ4CNF73.js +78 -0
  37. package/dist/chunk-OJ4CNF73.js.map +1 -0
  38. package/dist/chunk-PFJAC3RO.js +137 -0
  39. package/dist/chunk-PFJAC3RO.js.map +1 -0
  40. package/dist/chunk-PVKVCUNR.js +159 -0
  41. package/dist/chunk-PVKVCUNR.js.map +1 -0
  42. package/dist/chunk-RXT4WSIY.js +35 -0
  43. package/dist/chunk-RXT4WSIY.js.map +1 -0
  44. package/dist/chunk-RZK74PDF.js +34 -0
  45. package/dist/chunk-RZK74PDF.js.map +1 -0
  46. package/dist/chunk-UDTWVKRX.js +68 -0
  47. package/dist/chunk-UDTWVKRX.js.map +1 -0
  48. package/dist/chunk-VCEONSWJ.js +307 -0
  49. package/dist/chunk-VCEONSWJ.js.map +1 -0
  50. package/dist/chunk-VWBCDZWQ.js +119 -0
  51. package/dist/chunk-VWBCDZWQ.js.map +1 -0
  52. package/dist/chunk-WEJCTFQB.js +228 -0
  53. package/dist/chunk-WEJCTFQB.js.map +1 -0
  54. package/dist/chunk-YJK7IRPI.js +223 -0
  55. package/dist/chunk-YJK7IRPI.js.map +1 -0
  56. package/dist/claude-md-HQ6L4CRP.js +8 -0
  57. package/dist/claude-md-HQ6L4CRP.js.map +1 -0
  58. package/dist/cli.js +276 -0
  59. package/dist/cli.js.map +1 -0
  60. package/dist/commands-RG45VBTZ.js +407 -0
  61. package/dist/commands-RG45VBTZ.js.map +1 -0
  62. package/dist/commands-WYVRVE5Z.js +400 -0
  63. package/dist/commands-WYVRVE5Z.js.map +1 -0
  64. package/dist/config-edit-G7O56HXO.js +50 -0
  65. package/dist/config-edit-G7O56HXO.js.map +1 -0
  66. package/dist/config-set-QN3JRNZL.js +63 -0
  67. package/dist/config-set-QN3JRNZL.js.map +1 -0
  68. package/dist/daemon-CGBV55JK.js +104 -0
  69. package/dist/daemon-CGBV55JK.js.map +1 -0
  70. package/dist/dashboard-YVFJ5DXR.js +143 -0
  71. package/dist/dashboard-YVFJ5DXR.js.map +1 -0
  72. package/dist/doctor-BPTLVLTD.js +98 -0
  73. package/dist/doctor-BPTLVLTD.js.map +1 -0
  74. package/dist/human-loop-RBTA2TYK.js +16 -0
  75. package/dist/human-loop-RBTA2TYK.js.map +1 -0
  76. package/dist/human-loop-XGWXUNCS.js +18 -0
  77. package/dist/human-loop-XGWXUNCS.js.map +1 -0
  78. package/dist/index.d.ts +583 -0
  79. package/dist/index.js +28 -0
  80. package/dist/index.js.map +1 -0
  81. package/dist/loader-DGW7HCJ5.js +21 -0
  82. package/dist/loader-DGW7HCJ5.js.map +1 -0
  83. package/dist/logs-JUVQWN6C.js +93 -0
  84. package/dist/logs-JUVQWN6C.js.map +1 -0
  85. package/dist/mcp.js +132 -0
  86. package/dist/mcp.js.map +1 -0
  87. package/dist/orchestrator-3MGXX3QW.js +22 -0
  88. package/dist/orchestrator-3MGXX3QW.js.map +1 -0
  89. package/dist/orchestrator-BVUKN5N3.js +13 -0
  90. package/dist/orchestrator-BVUKN5N3.js.map +1 -0
  91. package/dist/pause-FLDZ3OD6.js +62 -0
  92. package/dist/pause-FLDZ3OD6.js.map +1 -0
  93. package/dist/projects-QMIGNW7U.js +129 -0
  94. package/dist/projects-QMIGNW7U.js.map +1 -0
  95. package/dist/replay-M4JEG4Z4.js +151 -0
  96. package/dist/replay-M4JEG4Z4.js.map +1 -0
  97. package/dist/schedule-CDHD77VZ.js +17 -0
  98. package/dist/schedule-CDHD77VZ.js.map +1 -0
  99. package/dist/serve-XI7JTIPZ.js +231 -0
  100. package/dist/serve-XI7JTIPZ.js.map +1 -0
  101. package/dist/sprint-KZZWVNK6.js +200 -0
  102. package/dist/sprint-KZZWVNK6.js.map +1 -0
  103. package/dist/status-I6GU2LWE.js +48 -0
  104. package/dist/status-I6GU2LWE.js.map +1 -0
  105. package/dist/topic-manager-4AMEPMFI.js +12 -0
  106. package/dist/topic-manager-4AMEPMFI.js.map +1 -0
  107. package/dist/triage-WNHGPVZQ.js +251 -0
  108. package/dist/triage-WNHGPVZQ.js.map +1 -0
  109. package/dist/usage-AWWBI37F.js +155 -0
  110. package/dist/usage-AWWBI37F.js.map +1 -0
  111. package/dist/wizard-CYEJJLNF.js +190 -0
  112. package/dist/wizard-CYEJJLNF.js.map +1 -0
  113. package/package.json +56 -0
@@ -0,0 +1,159 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ getVerbosity
4
+ } from "./chunk-RZK74PDF.js";
5
+ import {
6
+ getOrCreateTopic
7
+ } from "./chunk-3U373M37.js";
8
+ import {
9
+ getBot
10
+ } from "./chunk-OJ4CNF73.js";
11
+
12
+ // src/integrations/telegram/notifier.ts
13
+ var STAGE_IDS = [
14
+ "fetch",
15
+ "analyze",
16
+ "clarify",
17
+ "code",
18
+ "git",
19
+ "review",
20
+ "deploy",
21
+ "test",
22
+ "notify"
23
+ ];
24
+ var STAGE_EMOJI = {
25
+ fetch: "\u{1F4E5}",
26
+ analyze: "\u{1F50D}",
27
+ clarify: "\u{1F4AC}",
28
+ code: "\u{1F4BB}",
29
+ git: "\u{1F500}",
30
+ review: "\u{1F50E}",
31
+ deploy: "\u{1F680}",
32
+ test: "\u{1F9EA}",
33
+ notify: "\u{1F4E2}"
34
+ };
35
+ var STATUS_ICON = {
36
+ pending: "\u2B1C",
37
+ running: "\u25B6\uFE0F",
38
+ done: "\u2705",
39
+ skipped: "\u23ED",
40
+ failed: "\u274C"
41
+ };
42
+ function createTelegramNotifier(token, chatId, ticketKey, projectName, fallbackTopicId) {
43
+ const bot = getBot(token);
44
+ const stageStatus = Object.fromEntries(
45
+ STAGE_IDS.map((id) => [id, "pending"])
46
+ );
47
+ let progressMsgId;
48
+ let _topicResolved = false;
49
+ let _topicId = fallbackTopicId;
50
+ async function resolveTopicId() {
51
+ if (_topicResolved) return _topicId;
52
+ _topicResolved = true;
53
+ const created = await getOrCreateTopic(
54
+ bot,
55
+ chatId,
56
+ ticketKey,
57
+ projectName
58
+ ).catch(() => void 0);
59
+ if (created !== void 0) _topicId = created;
60
+ return _topicId;
61
+ }
62
+ async function makeThreadOpts() {
63
+ const topicId = await resolveTopicId();
64
+ return topicId ? { message_thread_id: topicId } : {};
65
+ }
66
+ function buildProgressText() {
67
+ const pills = STAGE_IDS.map((id) => {
68
+ const emoji = STAGE_EMOJI[id];
69
+ const icon = STATUS_ICON[stageStatus[id] ?? "pending"];
70
+ return `${emoji}${icon}`;
71
+ }).join(" ");
72
+ const current = STAGE_IDS.find((id) => stageStatus[id] === "running");
73
+ const statusLine = current ? `
74
+ Stage: <b>${current}</b> \u2014 in progress\u2026` : "";
75
+ return `\u{1F504} <b>${ticketKey}</b>
76
+ ${pills}${statusLine}`;
77
+ }
78
+ async function upsertProgress() {
79
+ const verbosity = getVerbosity(chatId);
80
+ if (verbosity === "low") return;
81
+ const text = buildProgressText();
82
+ const threadOpts = await makeThreadOpts();
83
+ if (progressMsgId !== void 0) {
84
+ try {
85
+ await bot.api.editMessageText(chatId, progressMsgId, text, {
86
+ parse_mode: "HTML"
87
+ });
88
+ return;
89
+ } catch {
90
+ }
91
+ }
92
+ const msg = await bot.api.sendMessage(chatId, text, {
93
+ parse_mode: "HTML",
94
+ ...threadOpts
95
+ });
96
+ progressMsgId = msg.message_id;
97
+ }
98
+ return {
99
+ async send(message) {
100
+ const threadOpts = await makeThreadOpts();
101
+ const msg = await bot.api.sendMessage(chatId, message, {
102
+ parse_mode: "HTML",
103
+ ...threadOpts
104
+ });
105
+ return msg.message_id;
106
+ },
107
+ async sendError(tk, err) {
108
+ const text = err instanceof Error ? err.message : String(err);
109
+ const threadOpts = await makeThreadOpts();
110
+ await bot.api.sendMessage(
111
+ chatId,
112
+ `\u274C <b>${tk}</b> pipeline failed
113
+ <code>${text}</code>`,
114
+ { parse_mode: "HTML", ...threadOpts }
115
+ );
116
+ },
117
+ async sendDone(tk, { summary, prNumber, deployUrl }) {
118
+ const lines = [`\u2705 <b>${tk}</b> completed`, summary];
119
+ if (prNumber) lines.push(`PR: #${prNumber}`);
120
+ if (deployUrl) lines.push(`Deploy: ${deployUrl}`);
121
+ const threadOpts = await makeThreadOpts();
122
+ await bot.api.sendMessage(chatId, lines.join("\n"), {
123
+ parse_mode: "HTML",
124
+ ...threadOpts
125
+ });
126
+ },
127
+ async notifyStageStarted(stage) {
128
+ stageStatus[stage] = "running";
129
+ await upsertProgress();
130
+ },
131
+ async notifyStageCompleted(stage) {
132
+ stageStatus[stage] = "done";
133
+ await upsertProgress();
134
+ },
135
+ async notifyStageFailed(stage, error) {
136
+ stageStatus[stage] = "failed";
137
+ await upsertProgress().catch(() => void 0);
138
+ const verbosity = getVerbosity(chatId);
139
+ if (verbosity !== "low") {
140
+ const threadOpts = await makeThreadOpts();
141
+ await bot.api.sendMessage(
142
+ chatId,
143
+ `\u274C Stage <b>${stage}</b> failed:
144
+ <code>${error.slice(0, 300)}</code>`,
145
+ { parse_mode: "HTML", ...threadOpts }
146
+ );
147
+ }
148
+ },
149
+ async notifyStageSkipped(stage) {
150
+ stageStatus[stage] = "skipped";
151
+ await upsertProgress();
152
+ }
153
+ };
154
+ }
155
+
156
+ export {
157
+ createTelegramNotifier
158
+ };
159
+ //# sourceMappingURL=chunk-PVKVCUNR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/integrations/telegram/notifier.ts"],"sourcesContent":["import type { StageId } from \"../../config/schema.js\";\nimport { getBot } from \"./bot.js\";\nimport { getOrCreateTopic } from \"./topic-manager.js\";\nimport { getVerbosity } from \"./prefs.js\";\n\nexport interface TelegramNotifier {\n send(message: string): Promise<number>;\n sendError(ticketKey: string, err: unknown): Promise<void>;\n sendDone(\n ticketKey: string,\n opts: { summary: string; prNumber?: number; deployUrl?: string },\n ): Promise<void>;\n notifyStageStarted(stage: StageId): Promise<void>;\n notifyStageCompleted(stage: StageId): Promise<void>;\n notifyStageFailed(stage: StageId, error: string): Promise<void>;\n notifyStageSkipped(stage: StageId): Promise<void>;\n}\n\ntype StageStatus = \"pending\" | \"running\" | \"done\" | \"skipped\" | \"failed\";\n\nconst STAGE_IDS: StageId[] = [\n \"fetch\",\n \"analyze\",\n \"clarify\",\n \"code\",\n \"git\",\n \"review\",\n \"deploy\",\n \"test\",\n \"notify\",\n];\n\nconst STAGE_EMOJI: Record<StageId, string> = {\n fetch: \"📥\",\n analyze: \"🔍\",\n clarify: \"💬\",\n code: \"💻\",\n git: \"🔀\",\n review: \"🔎\",\n deploy: \"🚀\",\n test: \"🧪\",\n notify: \"📢\",\n};\n\nconst STATUS_ICON: Record<StageStatus, string> = {\n pending: \"⬜\",\n running: \"▶️\",\n done: \"✅\",\n skipped: \"⏭\",\n failed: \"❌\",\n};\n\nexport function createTelegramNotifier(\n token: string,\n chatId: number | string,\n ticketKey: string,\n projectName: string,\n fallbackTopicId?: number,\n): TelegramNotifier {\n const bot = getBot(token);\n\n // Stage progress state\n const stageStatus: Record<string, StageStatus> = Object.fromEntries(\n STAGE_IDS.map((id) => [id, \"pending\" as StageStatus]),\n );\n let progressMsgId: number | undefined;\n\n // Lazy topic resolution — try forum topic, fall back to configured topicId\n let _topicResolved = false;\n let _topicId: number | undefined = fallbackTopicId;\n\n async function resolveTopicId(): Promise<number | undefined> {\n if (_topicResolved) return _topicId;\n _topicResolved = true;\n const created = await getOrCreateTopic(\n bot,\n chatId,\n ticketKey,\n projectName,\n ).catch(() => undefined);\n if (created !== undefined) _topicId = created;\n return _topicId;\n }\n\n async function makeThreadOpts(): Promise<\n Record<string, number> | Record<string, never>\n > {\n const topicId = await resolveTopicId();\n return topicId ? { message_thread_id: topicId } : {};\n }\n\n function buildProgressText(): string {\n const pills = STAGE_IDS.map((id) => {\n const emoji = STAGE_EMOJI[id];\n const icon = STATUS_ICON[stageStatus[id] ?? \"pending\"];\n return `${emoji}${icon}`;\n }).join(\" \");\n\n const current = STAGE_IDS.find((id) => stageStatus[id] === \"running\");\n const statusLine = current\n ? `\\nStage: <b>${current}</b> — in progress…`\n : \"\";\n\n return `🔄 <b>${ticketKey}</b>\\n${pills}${statusLine}`;\n }\n\n async function upsertProgress(): Promise<void> {\n const verbosity = getVerbosity(chatId);\n if (verbosity === \"low\") return;\n\n const text = buildProgressText();\n const threadOpts = await makeThreadOpts();\n\n if (progressMsgId !== undefined) {\n try {\n await bot.api.editMessageText(chatId, progressMsgId, text, {\n parse_mode: \"HTML\",\n });\n return;\n } catch {\n // Message deleted or too old — fall through to send new\n }\n }\n\n const msg = await bot.api.sendMessage(chatId, text, {\n parse_mode: \"HTML\",\n ...threadOpts,\n });\n progressMsgId = msg.message_id;\n }\n\n return {\n async send(message) {\n const threadOpts = await makeThreadOpts();\n const msg = await bot.api.sendMessage(chatId, message, {\n parse_mode: \"HTML\",\n ...threadOpts,\n });\n return msg.message_id;\n },\n\n async sendError(tk, err) {\n const text = err instanceof Error ? err.message : String(err);\n const threadOpts = await makeThreadOpts();\n await bot.api.sendMessage(\n chatId,\n `❌ <b>${tk}</b> pipeline failed\\n<code>${text}</code>`,\n { parse_mode: \"HTML\", ...threadOpts },\n );\n },\n\n async sendDone(tk, { summary, prNumber, deployUrl }) {\n const lines = [`✅ <b>${tk}</b> completed`, summary];\n if (prNumber) lines.push(`PR: #${prNumber}`);\n if (deployUrl) lines.push(`Deploy: ${deployUrl}`);\n const threadOpts = await makeThreadOpts();\n await bot.api.sendMessage(chatId, lines.join(\"\\n\"), {\n parse_mode: \"HTML\",\n ...threadOpts,\n });\n },\n\n async notifyStageStarted(stage) {\n stageStatus[stage] = \"running\";\n await upsertProgress();\n },\n\n async notifyStageCompleted(stage) {\n stageStatus[stage] = \"done\";\n await upsertProgress();\n },\n\n async notifyStageFailed(stage, error) {\n stageStatus[stage] = \"failed\";\n await upsertProgress().catch(() => undefined);\n\n const verbosity = getVerbosity(chatId);\n if (verbosity !== \"low\") {\n const threadOpts = await makeThreadOpts();\n await bot.api.sendMessage(\n chatId,\n `❌ Stage <b>${stage}</b> failed:\\n<code>${error.slice(0, 300)}</code>`,\n { parse_mode: \"HTML\", ...threadOpts },\n );\n }\n },\n\n async notifyStageSkipped(stage) {\n stageStatus[stage] = \"skipped\";\n await upsertProgress();\n },\n };\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/utils/pricing.ts
4
+ var MODEL_PRICING = {
5
+ "claude-haiku-4-5": { inputPer1M: 0.8, outputPer1M: 4 },
6
+ "claude-sonnet-4-5": { inputPer1M: 3, outputPer1M: 15 },
7
+ "claude-opus-4-5": { inputPer1M: 15, outputPer1M: 75 },
8
+ "claude-haiku-4": { inputPer1M: 0.8, outputPer1M: 4 },
9
+ "claude-sonnet-4": { inputPer1M: 3, outputPer1M: 15 },
10
+ "claude-opus-4": { inputPer1M: 15, outputPer1M: 75 }
11
+ };
12
+ var DEFAULT_PRICING = { inputPer1M: 3, outputPer1M: 15 };
13
+ function extractTokenUsage(output) {
14
+ if (typeof output !== "object" || output === null) return null;
15
+ const raw = output["tokenUsage"];
16
+ if (typeof raw !== "object" || raw === null) return null;
17
+ const tu = raw;
18
+ if (typeof tu["inputTokens"] !== "number" || typeof tu["outputTokens"] !== "number")
19
+ return null;
20
+ return {
21
+ inputTokens: tu["inputTokens"],
22
+ outputTokens: tu["outputTokens"],
23
+ model: typeof tu["model"] === "string" ? tu["model"] : "claude-sonnet-4"
24
+ };
25
+ }
26
+ function estimateCostUsd(inputTokens, outputTokens, model) {
27
+ const pricing = MODEL_PRICING[model] ?? DEFAULT_PRICING;
28
+ return inputTokens / 1e6 * pricing.inputPer1M + outputTokens / 1e6 * pricing.outputPer1M;
29
+ }
30
+
31
+ export {
32
+ extractTokenUsage,
33
+ estimateCostUsd
34
+ };
35
+ //# sourceMappingURL=chunk-RXT4WSIY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/pricing.ts"],"sourcesContent":["export interface ModelPricing {\n inputPer1M: number;\n outputPer1M: number;\n}\n\nexport interface TokenUsage {\n inputTokens: number;\n outputTokens: number;\n model: string;\n}\n\n// Prices in USD per 1M tokens — https://www.anthropic.com/pricing (updated 2026-01)\nexport const MODEL_PRICING: Record<string, ModelPricing> = {\n \"claude-haiku-4-5\": { inputPer1M: 0.8, outputPer1M: 4.0 },\n \"claude-sonnet-4-5\": { inputPer1M: 3.0, outputPer1M: 15.0 },\n \"claude-opus-4-5\": { inputPer1M: 15.0, outputPer1M: 75.0 },\n \"claude-haiku-4\": { inputPer1M: 0.8, outputPer1M: 4.0 },\n \"claude-sonnet-4\": { inputPer1M: 3.0, outputPer1M: 15.0 },\n \"claude-opus-4\": { inputPer1M: 15.0, outputPer1M: 75.0 },\n};\n\nconst DEFAULT_PRICING: ModelPricing = { inputPer1M: 3.0, outputPer1M: 15.0 };\n\n/** Type-safe extractor for tokenUsage from a stage output. Returns null if not present or malformed. */\nexport function extractTokenUsage(output: unknown): TokenUsage | null {\n if (typeof output !== \"object\" || output === null) return null;\n const raw = (output as Record<string, unknown>)[\"tokenUsage\"];\n if (typeof raw !== \"object\" || raw === null) return null;\n const tu = raw as Record<string, unknown>;\n if (\n typeof tu[\"inputTokens\"] !== \"number\" ||\n typeof tu[\"outputTokens\"] !== \"number\"\n )\n return null;\n return {\n inputTokens: tu[\"inputTokens\"] as number,\n outputTokens: tu[\"outputTokens\"] as number,\n model: typeof tu[\"model\"] === \"string\" ? tu[\"model\"] : \"claude-sonnet-4\",\n };\n}\n\nexport function estimateCostUsd(\n inputTokens: number,\n outputTokens: number,\n model: string,\n): number {\n const pricing = MODEL_PRICING[model] ?? DEFAULT_PRICING;\n return (\n (inputTokens / 1_000_000) * pricing.inputPer1M +\n (outputTokens / 1_000_000) * pricing.outputPer1M\n );\n}\n"],"mappings":";;;AAYO,IAAM,gBAA8C;AAAA,EACzD,oBAAoB,EAAE,YAAY,KAAK,aAAa,EAAI;AAAA,EACxD,qBAAqB,EAAE,YAAY,GAAK,aAAa,GAAK;AAAA,EAC1D,mBAAmB,EAAE,YAAY,IAAM,aAAa,GAAK;AAAA,EACzD,kBAAkB,EAAE,YAAY,KAAK,aAAa,EAAI;AAAA,EACtD,mBAAmB,EAAE,YAAY,GAAK,aAAa,GAAK;AAAA,EACxD,iBAAiB,EAAE,YAAY,IAAM,aAAa,GAAK;AACzD;AAEA,IAAM,kBAAgC,EAAE,YAAY,GAAK,aAAa,GAAK;AAGpE,SAAS,kBAAkB,QAAoC;AACpE,MAAI,OAAO,WAAW,YAAY,WAAW,KAAM,QAAO;AAC1D,QAAM,MAAO,OAAmC,YAAY;AAC5D,MAAI,OAAO,QAAQ,YAAY,QAAQ,KAAM,QAAO;AACpD,QAAM,KAAK;AACX,MACE,OAAO,GAAG,aAAa,MAAM,YAC7B,OAAO,GAAG,cAAc,MAAM;AAE9B,WAAO;AACT,SAAO;AAAA,IACL,aAAa,GAAG,aAAa;AAAA,IAC7B,cAAc,GAAG,cAAc;AAAA,IAC/B,OAAO,OAAO,GAAG,OAAO,MAAM,WAAW,GAAG,OAAO,IAAI;AAAA,EACzD;AACF;AAEO,SAAS,gBACd,aACA,cACA,OACQ;AACR,QAAM,UAAU,cAAc,KAAK,KAAK;AACxC,SACG,cAAc,MAAa,QAAQ,aACnC,eAAe,MAAa,QAAQ;AAEzC;","names":[]}
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/integrations/telegram/prefs.ts
4
+ import fs from "fs";
5
+ import path from "path";
6
+ import os from "os";
7
+ var PREFS_PATH = path.join(os.homedir(), ".jira-acp", "telegram-prefs.json");
8
+ function load() {
9
+ if (!fs.existsSync(PREFS_PATH)) return { verbosity: {} };
10
+ try {
11
+ return JSON.parse(fs.readFileSync(PREFS_PATH, "utf8"));
12
+ } catch {
13
+ return { verbosity: {} };
14
+ }
15
+ }
16
+ function save(prefs) {
17
+ fs.mkdirSync(path.dirname(PREFS_PATH), { recursive: true });
18
+ fs.writeFileSync(PREFS_PATH, JSON.stringify(prefs, null, 2));
19
+ }
20
+ function getVerbosity(chatId) {
21
+ const prefs = load();
22
+ return prefs.verbosity[String(chatId)] ?? "medium";
23
+ }
24
+ function setVerbosity(chatId, level) {
25
+ const prefs = load();
26
+ prefs.verbosity[String(chatId)] = level;
27
+ save(prefs);
28
+ }
29
+
30
+ export {
31
+ getVerbosity,
32
+ setVerbosity
33
+ };
34
+ //# sourceMappingURL=chunk-RZK74PDF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/integrations/telegram/prefs.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\n\nconst PREFS_PATH = path.join(os.homedir(), \".jira-acp\", \"telegram-prefs.json\");\n\nexport type Verbosity = \"low\" | \"medium\" | \"high\";\n\ninterface TelegramPrefs {\n verbosity: Record<string, Verbosity>;\n}\n\nfunction load(): TelegramPrefs {\n if (!fs.existsSync(PREFS_PATH)) return { verbosity: {} };\n try {\n return JSON.parse(fs.readFileSync(PREFS_PATH, \"utf8\")) as TelegramPrefs;\n } catch {\n return { verbosity: {} };\n }\n}\n\nfunction save(prefs: TelegramPrefs): void {\n fs.mkdirSync(path.dirname(PREFS_PATH), { recursive: true });\n fs.writeFileSync(PREFS_PATH, JSON.stringify(prefs, null, 2));\n}\n\nexport function getVerbosity(chatId: number | string): Verbosity {\n const prefs = load();\n return prefs.verbosity[String(chatId)] ?? \"medium\";\n}\n\nexport function setVerbosity(chatId: number | string, level: Verbosity): void {\n const prefs = load();\n prefs.verbosity[String(chatId)] = level;\n save(prefs);\n}\n"],"mappings":";;;AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,OAAO,QAAQ;AAEf,IAAM,aAAa,KAAK,KAAK,GAAG,QAAQ,GAAG,aAAa,qBAAqB;AAQ7E,SAAS,OAAsB;AAC7B,MAAI,CAAC,GAAG,WAAW,UAAU,EAAG,QAAO,EAAE,WAAW,CAAC,EAAE;AACvD,MAAI;AACF,WAAO,KAAK,MAAM,GAAG,aAAa,YAAY,MAAM,CAAC;AAAA,EACvD,QAAQ;AACN,WAAO,EAAE,WAAW,CAAC,EAAE;AAAA,EACzB;AACF;AAEA,SAAS,KAAK,OAA4B;AACxC,KAAG,UAAU,KAAK,QAAQ,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;AAC1D,KAAG,cAAc,YAAY,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AAC7D;AAEO,SAAS,aAAa,QAAoC;AAC/D,QAAM,QAAQ,KAAK;AACnB,SAAO,MAAM,UAAU,OAAO,MAAM,CAAC,KAAK;AAC5C;AAEO,SAAS,aAAa,QAAyB,OAAwB;AAC5E,QAAM,QAAQ,KAAK;AACnB,QAAM,UAAU,OAAO,MAAM,CAAC,IAAI;AAClC,OAAK,KAAK;AACZ;","names":[]}
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/utils/process.ts
4
+ import { spawn } from "child_process";
5
+ async function spawnSafe(bin, args, opts = {}) {
6
+ return new Promise((resolve, reject) => {
7
+ const proc = spawn(bin, args, {
8
+ cwd: opts.cwd,
9
+ env: opts.env ?? buildMinimalEnv(),
10
+ stdio: ["pipe", "pipe", "pipe"]
11
+ });
12
+ let stdout = "";
13
+ let stderr = "";
14
+ let stallTimer;
15
+ let globalTimer;
16
+ const resetStall = () => {
17
+ if (stallTimer) clearTimeout(stallTimer);
18
+ if (opts.stallTimeoutMs) {
19
+ stallTimer = setTimeout(() => {
20
+ proc.kill("SIGKILL");
21
+ reject(
22
+ new Error(
23
+ `Process stalled (no output for ${opts.stallTimeoutMs}ms)`
24
+ )
25
+ );
26
+ }, opts.stallTimeoutMs);
27
+ }
28
+ };
29
+ if (opts.timeoutMs) {
30
+ globalTimer = setTimeout(() => {
31
+ proc.kill("SIGKILL");
32
+ reject(new Error(`Process timed out after ${opts.timeoutMs}ms`));
33
+ }, opts.timeoutMs);
34
+ }
35
+ resetStall();
36
+ proc.stdout.on("data", (chunk) => {
37
+ stdout += chunk.toString();
38
+ resetStall();
39
+ });
40
+ proc.stderr.on("data", (chunk) => {
41
+ stderr += chunk.toString();
42
+ });
43
+ proc.on("close", (code) => {
44
+ if (stallTimer) clearTimeout(stallTimer);
45
+ if (globalTimer) clearTimeout(globalTimer);
46
+ resolve({ stdout, stderr, exitCode: code ?? 1 });
47
+ });
48
+ proc.on("error", (err) => {
49
+ if (stallTimer) clearTimeout(stallTimer);
50
+ if (globalTimer) clearTimeout(globalTimer);
51
+ reject(err);
52
+ });
53
+ });
54
+ }
55
+ function buildMinimalEnv(extra = {}) {
56
+ return {
57
+ PATH: process.env["PATH"] ?? "",
58
+ HOME: process.env["HOME"] ?? "",
59
+ ANTHROPIC_API_KEY: process.env["ANTHROPIC_API_KEY"] ?? "",
60
+ ...extra
61
+ };
62
+ }
63
+
64
+ export {
65
+ spawnSafe,
66
+ buildMinimalEnv
67
+ };
68
+ //# sourceMappingURL=chunk-UDTWVKRX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/process.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\n\nexport interface RunResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n}\n\nexport interface SpawnOptions {\n cwd?: string;\n env?: Record<string, string>;\n timeoutMs?: number;\n stallTimeoutMs?: number;\n}\n\n/** Spawn a process safely — args as array, never shell string (no injection risk) */\nexport async function spawnSafe(\n bin: string,\n args: string[],\n opts: SpawnOptions = {},\n): Promise<RunResult> {\n return new Promise((resolve, reject) => {\n const proc = spawn(bin, args, {\n cwd: opts.cwd,\n env: opts.env ?? buildMinimalEnv(),\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n\n let stdout = \"\";\n let stderr = \"\";\n let stallTimer: NodeJS.Timeout | undefined;\n let globalTimer: NodeJS.Timeout | undefined;\n\n const resetStall = (): void => {\n if (stallTimer) clearTimeout(stallTimer);\n if (opts.stallTimeoutMs) {\n stallTimer = setTimeout(() => {\n proc.kill(\"SIGKILL\");\n reject(\n new Error(\n `Process stalled (no output for ${opts.stallTimeoutMs}ms)`,\n ),\n );\n }, opts.stallTimeoutMs);\n }\n };\n\n if (opts.timeoutMs) {\n globalTimer = setTimeout(() => {\n proc.kill(\"SIGKILL\");\n reject(new Error(`Process timed out after ${opts.timeoutMs}ms`));\n }, opts.timeoutMs);\n }\n\n resetStall();\n\n proc.stdout.on(\"data\", (chunk: Buffer) => {\n stdout += chunk.toString();\n resetStall();\n });\n\n proc.stderr.on(\"data\", (chunk: Buffer) => {\n stderr += chunk.toString();\n });\n\n proc.on(\"close\", (code) => {\n if (stallTimer) clearTimeout(stallTimer);\n if (globalTimer) clearTimeout(globalTimer);\n resolve({ stdout, stderr, exitCode: code ?? 1 });\n });\n\n proc.on(\"error\", (err) => {\n if (stallTimer) clearTimeout(stallTimer);\n if (globalTimer) clearTimeout(globalTimer);\n reject(err);\n });\n });\n}\n\n/** Only forward what agents need — never spread full process.env */\nexport function buildMinimalEnv(\n extra: Record<string, string> = {},\n): Record<string, string> {\n return {\n PATH: process.env[\"PATH\"] ?? \"\",\n HOME: process.env[\"HOME\"] ?? \"\",\n ANTHROPIC_API_KEY: process.env[\"ANTHROPIC_API_KEY\"] ?? \"\",\n ...extra,\n };\n}\n"],"mappings":";;;AAAA,SAAS,aAAa;AAgBtB,eAAsB,UACpB,KACA,MACA,OAAqB,CAAC,GACF;AACpB,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,OAAO,MAAM,KAAK,MAAM;AAAA,MAC5B,KAAK,KAAK;AAAA,MACV,KAAK,KAAK,OAAO,gBAAgB;AAAA,MACjC,OAAO,CAAC,QAAQ,QAAQ,MAAM;AAAA,IAChC,CAAC;AAED,QAAI,SAAS;AACb,QAAI,SAAS;AACb,QAAI;AACJ,QAAI;AAEJ,UAAM,aAAa,MAAY;AAC7B,UAAI,WAAY,cAAa,UAAU;AACvC,UAAI,KAAK,gBAAgB;AACvB,qBAAa,WAAW,MAAM;AAC5B,eAAK,KAAK,SAAS;AACnB;AAAA,YACE,IAAI;AAAA,cACF,kCAAkC,KAAK,cAAc;AAAA,YACvD;AAAA,UACF;AAAA,QACF,GAAG,KAAK,cAAc;AAAA,MACxB;AAAA,IACF;AAEA,QAAI,KAAK,WAAW;AAClB,oBAAc,WAAW,MAAM;AAC7B,aAAK,KAAK,SAAS;AACnB,eAAO,IAAI,MAAM,2BAA2B,KAAK,SAAS,IAAI,CAAC;AAAA,MACjE,GAAG,KAAK,SAAS;AAAA,IACnB;AAEA,eAAW;AAEX,SAAK,OAAO,GAAG,QAAQ,CAAC,UAAkB;AACxC,gBAAU,MAAM,SAAS;AACzB,iBAAW;AAAA,IACb,CAAC;AAED,SAAK,OAAO,GAAG,QAAQ,CAAC,UAAkB;AACxC,gBAAU,MAAM,SAAS;AAAA,IAC3B,CAAC;AAED,SAAK,GAAG,SAAS,CAAC,SAAS;AACzB,UAAI,WAAY,cAAa,UAAU;AACvC,UAAI,YAAa,cAAa,WAAW;AACzC,cAAQ,EAAE,QAAQ,QAAQ,UAAU,QAAQ,EAAE,CAAC;AAAA,IACjD,CAAC;AAED,SAAK,GAAG,SAAS,CAAC,QAAQ;AACxB,UAAI,WAAY,cAAa,UAAU;AACvC,UAAI,YAAa,cAAa,WAAW;AACzC,aAAO,GAAG;AAAA,IACZ,CAAC;AAAA,EACH,CAAC;AACH;AAGO,SAAS,gBACd,QAAgC,CAAC,GACT;AACxB,SAAO;AAAA,IACL,MAAM,QAAQ,IAAI,MAAM,KAAK;AAAA,IAC7B,MAAM,QAAQ,IAAI,MAAM,KAAK;AAAA,IAC7B,mBAAmB,QAAQ,IAAI,mBAAmB,KAAK;AAAA,IACvD,GAAG;AAAA,EACL;AACF;","names":[]}
@@ -0,0 +1,307 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ buildMinimalEnv,
4
+ spawnSafe
5
+ } from "./chunk-UDTWVKRX.js";
6
+ import {
7
+ getTicket
8
+ } from "./chunk-JOT4UVSO.js";
9
+
10
+ // src/integrations/github/client.ts
11
+ import { Octokit } from "@octokit/rest";
12
+ function createGitHubClient(token, owner, repo) {
13
+ const octokit = new Octokit({ auth: token });
14
+ return {
15
+ async createBranch(base, branch) {
16
+ const { data: ref } = await octokit.git.getRef({
17
+ owner,
18
+ repo,
19
+ ref: `heads/${base}`
20
+ });
21
+ await octokit.git.createRef({
22
+ owner,
23
+ repo,
24
+ ref: `refs/heads/${branch}`,
25
+ sha: ref.object.sha
26
+ });
27
+ },
28
+ async createPR({ title, body, head, base, draft = false }) {
29
+ const { data } = await octokit.pulls.create({
30
+ owner,
31
+ repo,
32
+ title,
33
+ body,
34
+ head,
35
+ base,
36
+ draft
37
+ });
38
+ return data.number;
39
+ },
40
+ async mergePR(prNumber, strategy) {
41
+ const mergeMethod = strategy === "squash" ? "squash" : strategy === "rebase" ? "rebase" : "merge";
42
+ await octokit.pulls.merge({
43
+ owner,
44
+ repo,
45
+ pull_number: prNumber,
46
+ merge_method: mergeMethod
47
+ });
48
+ },
49
+ async addReviewers(prNumber, reviewers) {
50
+ if (reviewers.length === 0) return;
51
+ await octokit.pulls.requestReviewers({
52
+ owner,
53
+ repo,
54
+ pull_number: prNumber,
55
+ reviewers
56
+ });
57
+ },
58
+ async getPR(prNumber) {
59
+ const { data } = await octokit.pulls.get({
60
+ owner,
61
+ repo,
62
+ pull_number: prNumber
63
+ });
64
+ return { state: data.state, merged: data.merged };
65
+ },
66
+ async getRunStatus(branch) {
67
+ try {
68
+ const { data } = await octokit.repos.getCombinedStatusForRef({
69
+ owner,
70
+ repo,
71
+ ref: branch
72
+ });
73
+ if (data.state === "success") return "success";
74
+ if (data.state === "failure") return "failure";
75
+ return "pending";
76
+ } catch {
77
+ return "unknown";
78
+ }
79
+ }
80
+ };
81
+ }
82
+
83
+ // src/memory/context-builder.ts
84
+ import fs from "fs";
85
+ import path from "path";
86
+ function writeTicketContext(memoryDir, ticket) {
87
+ fs.mkdirSync(memoryDir, { recursive: true });
88
+ const content = `# Ticket: ${ticket.key}
89
+
90
+ ## Summary
91
+ ${ticket.summary}
92
+
93
+ ## Description
94
+ ${ticket.description || "(none)"}
95
+
96
+ ## Acceptance Criteria
97
+ ${ticket.acceptanceCriteria || "(none)"}
98
+
99
+ ## Priority
100
+ ${ticket.priority}
101
+ ${ticket.clarifications ? `
102
+ ## Clarifications from Team
103
+ ${ticket.clarifications}` : ""}
104
+ `;
105
+ fs.writeFileSync(path.join(memoryDir, "ticket-context.md"), content);
106
+ }
107
+ function readTicketContext(memoryDir) {
108
+ const p = path.join(memoryDir, "ticket-context.md");
109
+ return fs.existsSync(p) ? fs.readFileSync(p, "utf8") : "";
110
+ }
111
+ function appendClarifications(memoryDir, answers) {
112
+ const p = path.join(memoryDir, "ticket-context.md");
113
+ if (fs.existsSync(p)) {
114
+ fs.appendFileSync(p, `
115
+ ## Clarifications from Team
116
+ ${answers}
117
+ `);
118
+ }
119
+ }
120
+ function writeReviewFeedback(memoryDir, feedback) {
121
+ const lines = [
122
+ `# Review Results`,
123
+ `PR: #${feedback.prNumber}`,
124
+ `Major issues: ${feedback.issues.filter((i) => i.severity === "major").length}`,
125
+ `Minor issues: ${feedback.issues.filter((i) => i.severity === "minor").length}`,
126
+ `Auto-resolved: ${feedback.autoResolved}`,
127
+ "",
128
+ "## Issues",
129
+ ...feedback.issues.map(
130
+ (i) => `- [${i.severity.toUpperCase()}] ${i.message}`
131
+ )
132
+ ];
133
+ fs.writeFileSync(
134
+ path.join(memoryDir, "review-feedback.md"),
135
+ lines.join("\n")
136
+ );
137
+ }
138
+ function getContextFilesForStage(projectDir, memoryDir, stage) {
139
+ const claudeMd = path.join(projectDir, ".claude", "CLAUDE.md");
140
+ const ticketCtx = path.join(memoryDir, "ticket-context.md");
141
+ const reviewFeedback = path.join(memoryDir, "review-feedback.md");
142
+ const files = [];
143
+ if (fs.existsSync(claudeMd)) files.push(claudeMd);
144
+ if (["code", "git", "review", "deploy", "test", "notify"].includes(stage)) {
145
+ if (fs.existsSync(ticketCtx)) files.push(ticketCtx);
146
+ }
147
+ if (stage === "test" && fs.existsSync(reviewFeedback)) {
148
+ files.push(reviewFeedback);
149
+ }
150
+ return files;
151
+ }
152
+
153
+ // src/pipeline/stages/1-fetch.ts
154
+ var fetchStage = {
155
+ id: "fetch",
156
+ name: "Fetch Ticket",
157
+ model: "haiku",
158
+ async run(ctx) {
159
+ const { config, ticketKey, memoryDir } = ctx;
160
+ ctx.logger.info({ ticketKey }, "Fetching ticket from Jira");
161
+ const raw = await getTicket({
162
+ instance: config.jira.instance,
163
+ ticket_key: ticketKey
164
+ });
165
+ const ticket = JSON.parse(raw);
166
+ writeTicketContext(memoryDir, {
167
+ key: ticket.key,
168
+ summary: ticket.summary,
169
+ description: ticket.description ?? "",
170
+ acceptanceCriteria: ticket.acceptance_criteria ?? "",
171
+ priority: ticket.priority ?? "Medium"
172
+ });
173
+ ctx.logger.info({ ticketKey, summary: ticket.summary }, "Ticket fetched");
174
+ return {
175
+ summary: ticket.summary,
176
+ description: ticket.description,
177
+ acceptanceCriteria: ticket.acceptance_criteria,
178
+ status: ticket.status
179
+ };
180
+ }
181
+ };
182
+
183
+ // src/pipeline/runner.ts
184
+ var MODEL_IDS = {
185
+ haiku: "claude-haiku-4-5-20251001",
186
+ sonnet: "claude-sonnet-4-6",
187
+ opus: "claude-opus-4-6"
188
+ };
189
+ async function runAgent(opts) {
190
+ const args = [
191
+ "--model",
192
+ MODEL_IDS[opts.model],
193
+ "--print",
194
+ "--output-format",
195
+ "text"
196
+ ];
197
+ for (const f of opts.contextFiles ?? []) {
198
+ args.push("--context", f);
199
+ }
200
+ args.push(opts.prompt);
201
+ const result = await spawnSafe("claude", args, {
202
+ cwd: opts.workdir,
203
+ env: buildMinimalEnv(opts.extraEnv),
204
+ timeoutMs: opts.timeoutMs ?? 18e5,
205
+ stallTimeoutMs: opts.stallTimeoutMs ?? 3e5
206
+ });
207
+ if (result.exitCode !== 0) {
208
+ throw new Error(
209
+ `Agent exited with code ${result.exitCode}:
210
+ ${result.stderr}`
211
+ );
212
+ }
213
+ return result.stdout.trim();
214
+ }
215
+ async function runAgentsParallel(a, b) {
216
+ return Promise.all([runAgent(a), runAgent(b)]);
217
+ }
218
+ function detectComplexity(description) {
219
+ const complexKeywords = [
220
+ "auth",
221
+ "payment",
222
+ "stripe",
223
+ "oauth",
224
+ "jwt",
225
+ "migration",
226
+ "schema",
227
+ "database",
228
+ "refactor",
229
+ "cross-module",
230
+ "multi-service",
231
+ "security",
232
+ "encryption",
233
+ "permission"
234
+ ];
235
+ const lower = description.toLowerCase();
236
+ const matches = complexKeywords.filter((k) => lower.includes(k));
237
+ return matches.length >= 2 ? "opus" : "sonnet";
238
+ }
239
+
240
+ // src/pipeline/stages/2-analyze.ts
241
+ var CLARITY_PROMPT = (ticketCtx, requiredFields) => `
242
+ Analyze this Jira ticket for clarity. Score from 0.0 to 1.0.
243
+
244
+ Required fields: ${requiredFields.join(", ")}
245
+
246
+ Ticket:
247
+ ${ticketCtx}
248
+
249
+ Reply with JSON only:
250
+ {
251
+ "score": 0.0-1.0,
252
+ "missing": ["list of missing or ambiguous items"],
253
+ "questions": ["specific questions to ask the team"]
254
+ }
255
+ `.trim();
256
+ var analyzeStage = {
257
+ id: "analyze",
258
+ name: "Analyze Clarity",
259
+ model: "sonnet",
260
+ async run(ctx) {
261
+ const { config, memoryDir, ticketKey } = ctx;
262
+ const ticketCtx = readTicketContext(memoryDir);
263
+ if (!ticketCtx)
264
+ throw new Error("ticket-context.md not found \u2014 run fetch stage first");
265
+ ctx.logger.info({ ticketKey }, "Analyzing ticket clarity");
266
+ const raw = await runAgent({
267
+ prompt: CLARITY_PROMPT(
268
+ ticketCtx,
269
+ config.jira.requiredFields ?? ["description", "acceptanceCriteria"]
270
+ ),
271
+ workdir: config.workspace.rootDir,
272
+ model: "haiku",
273
+ timeoutMs: 6e4,
274
+ stallTimeoutMs: 3e4
275
+ });
276
+ const jsonMatch = raw.match(/\{[\s\S]*\}/);
277
+ if (!jsonMatch) {
278
+ ctx.logger.warn(
279
+ { ticketKey },
280
+ "Could not parse clarity JSON \u2014 defaulting to low score"
281
+ );
282
+ return { score: 0, missing: [], questions: [], needsClarification: true };
283
+ }
284
+ const result = JSON.parse(jsonMatch[0]);
285
+ const threshold = config.jira.clarityScoreThreshold ?? 0.7;
286
+ const needsClarification = result.score < threshold;
287
+ ctx.logger.info(
288
+ { ticketKey, score: result.score, threshold, needsClarification },
289
+ "Clarity analysis done"
290
+ );
291
+ return { ...result, needsClarification };
292
+ }
293
+ };
294
+
295
+ export {
296
+ createGitHubClient,
297
+ readTicketContext,
298
+ appendClarifications,
299
+ writeReviewFeedback,
300
+ getContextFilesForStage,
301
+ fetchStage,
302
+ runAgent,
303
+ runAgentsParallel,
304
+ detectComplexity,
305
+ analyzeStage
306
+ };
307
+ //# sourceMappingURL=chunk-VCEONSWJ.js.map