@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.
- package/README.md +283 -0
- package/dist/abort-GQE4OI5S.js +103 -0
- package/dist/abort-GQE4OI5S.js.map +1 -0
- package/dist/abort-VMRQOADY.js +96 -0
- package/dist/abort-VMRQOADY.js.map +1 -0
- package/dist/bot-WOTETAJY.js +13 -0
- package/dist/bot-WOTETAJY.js.map +1 -0
- package/dist/cancel-clarification-4G5S2HJZ.js +64 -0
- package/dist/cancel-clarification-4G5S2HJZ.js.map +1 -0
- package/dist/chunk-3U373M37.js +67 -0
- package/dist/chunk-3U373M37.js.map +1 -0
- package/dist/chunk-3YHD4SIN.js +97 -0
- package/dist/chunk-3YHD4SIN.js.map +1 -0
- package/dist/chunk-6IY6CRUJ.js +690 -0
- package/dist/chunk-6IY6CRUJ.js.map +1 -0
- package/dist/chunk-B6OA3XJK.js +1167 -0
- package/dist/chunk-B6OA3XJK.js.map +1 -0
- package/dist/chunk-BM4R6NST.js +191 -0
- package/dist/chunk-BM4R6NST.js.map +1 -0
- package/dist/chunk-FLPIU2QO.js +77 -0
- package/dist/chunk-FLPIU2QO.js.map +1 -0
- package/dist/chunk-H7YXX4UA.js +86 -0
- package/dist/chunk-H7YXX4UA.js.map +1 -0
- package/dist/chunk-IT74N3UH.js +19 -0
- package/dist/chunk-IT74N3UH.js.map +1 -0
- package/dist/chunk-JOT4UVSO.js +186 -0
- package/dist/chunk-JOT4UVSO.js.map +1 -0
- package/dist/chunk-KSJKCLEJ.js +222 -0
- package/dist/chunk-KSJKCLEJ.js.map +1 -0
- package/dist/chunk-LIEW4ULF.js +139 -0
- package/dist/chunk-LIEW4ULF.js.map +1 -0
- package/dist/chunk-M4V3YOCY.js +82 -0
- package/dist/chunk-M4V3YOCY.js.map +1 -0
- package/dist/chunk-MMWQHH25.js +207 -0
- package/dist/chunk-MMWQHH25.js.map +1 -0
- package/dist/chunk-OJ4CNF73.js +78 -0
- package/dist/chunk-OJ4CNF73.js.map +1 -0
- package/dist/chunk-PFJAC3RO.js +137 -0
- package/dist/chunk-PFJAC3RO.js.map +1 -0
- package/dist/chunk-PVKVCUNR.js +159 -0
- package/dist/chunk-PVKVCUNR.js.map +1 -0
- package/dist/chunk-RXT4WSIY.js +35 -0
- package/dist/chunk-RXT4WSIY.js.map +1 -0
- package/dist/chunk-RZK74PDF.js +34 -0
- package/dist/chunk-RZK74PDF.js.map +1 -0
- package/dist/chunk-UDTWVKRX.js +68 -0
- package/dist/chunk-UDTWVKRX.js.map +1 -0
- package/dist/chunk-VCEONSWJ.js +307 -0
- package/dist/chunk-VCEONSWJ.js.map +1 -0
- package/dist/chunk-VWBCDZWQ.js +119 -0
- package/dist/chunk-VWBCDZWQ.js.map +1 -0
- package/dist/chunk-WEJCTFQB.js +228 -0
- package/dist/chunk-WEJCTFQB.js.map +1 -0
- package/dist/chunk-YJK7IRPI.js +223 -0
- package/dist/chunk-YJK7IRPI.js.map +1 -0
- package/dist/claude-md-HQ6L4CRP.js +8 -0
- package/dist/claude-md-HQ6L4CRP.js.map +1 -0
- package/dist/cli.js +276 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands-RG45VBTZ.js +407 -0
- package/dist/commands-RG45VBTZ.js.map +1 -0
- package/dist/commands-WYVRVE5Z.js +400 -0
- package/dist/commands-WYVRVE5Z.js.map +1 -0
- package/dist/config-edit-G7O56HXO.js +50 -0
- package/dist/config-edit-G7O56HXO.js.map +1 -0
- package/dist/config-set-QN3JRNZL.js +63 -0
- package/dist/config-set-QN3JRNZL.js.map +1 -0
- package/dist/daemon-CGBV55JK.js +104 -0
- package/dist/daemon-CGBV55JK.js.map +1 -0
- package/dist/dashboard-YVFJ5DXR.js +143 -0
- package/dist/dashboard-YVFJ5DXR.js.map +1 -0
- package/dist/doctor-BPTLVLTD.js +98 -0
- package/dist/doctor-BPTLVLTD.js.map +1 -0
- package/dist/human-loop-RBTA2TYK.js +16 -0
- package/dist/human-loop-RBTA2TYK.js.map +1 -0
- package/dist/human-loop-XGWXUNCS.js +18 -0
- package/dist/human-loop-XGWXUNCS.js.map +1 -0
- package/dist/index.d.ts +583 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/loader-DGW7HCJ5.js +21 -0
- package/dist/loader-DGW7HCJ5.js.map +1 -0
- package/dist/logs-JUVQWN6C.js +93 -0
- package/dist/logs-JUVQWN6C.js.map +1 -0
- package/dist/mcp.js +132 -0
- package/dist/mcp.js.map +1 -0
- package/dist/orchestrator-3MGXX3QW.js +22 -0
- package/dist/orchestrator-3MGXX3QW.js.map +1 -0
- package/dist/orchestrator-BVUKN5N3.js +13 -0
- package/dist/orchestrator-BVUKN5N3.js.map +1 -0
- package/dist/pause-FLDZ3OD6.js +62 -0
- package/dist/pause-FLDZ3OD6.js.map +1 -0
- package/dist/projects-QMIGNW7U.js +129 -0
- package/dist/projects-QMIGNW7U.js.map +1 -0
- package/dist/replay-M4JEG4Z4.js +151 -0
- package/dist/replay-M4JEG4Z4.js.map +1 -0
- package/dist/schedule-CDHD77VZ.js +17 -0
- package/dist/schedule-CDHD77VZ.js.map +1 -0
- package/dist/serve-XI7JTIPZ.js +231 -0
- package/dist/serve-XI7JTIPZ.js.map +1 -0
- package/dist/sprint-KZZWVNK6.js +200 -0
- package/dist/sprint-KZZWVNK6.js.map +1 -0
- package/dist/status-I6GU2LWE.js +48 -0
- package/dist/status-I6GU2LWE.js.map +1 -0
- package/dist/topic-manager-4AMEPMFI.js +12 -0
- package/dist/topic-manager-4AMEPMFI.js.map +1 -0
- package/dist/triage-WNHGPVZQ.js +251 -0
- package/dist/triage-WNHGPVZQ.js.map +1 -0
- package/dist/usage-AWWBI37F.js +155 -0
- package/dist/usage-AWWBI37F.js.map +1 -0
- package/dist/wizard-CYEJJLNF.js +190 -0
- package/dist/wizard-CYEJJLNF.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/integrations/jira/client.ts","../src/integrations/github/client.ts","../src/utils/pricing.ts","../src/pipeline/cost-guard.ts","../src/integrations/jira/tools.ts","../src/memory/context-builder.ts","../src/pipeline/stages/1-fetch.ts","../src/utils/process.ts","../src/pipeline/runner.ts","../src/pipeline/stages/2-analyze.ts","../src/pipeline/stages/3-clarify.ts","../src/pipeline/stages/4-code.ts","../src/pipeline/stages/5-git.ts","../src/pipeline/stages/6-review.ts","../src/pipeline/stages/7-deploy.ts","../src/pipeline/stages/8-test.ts","../src/pipeline/stages/9-notify.ts","../src/pipeline/hooks.ts","../src/pipeline/orchestrator.ts"],"sourcesContent":["import axios, { type AxiosInstance } from \"axios\";\n\nexport interface JiraConfig {\n url: string;\n token: string;\n email: string;\n}\n\n// Auto-discover instances from env vars: JIRA_{NAME}_URL, JIRA_{NAME}_TOKEN, JIRA_{NAME}_EMAIL\nfunction loadInstances(): Record<string, JiraConfig> {\n const instances: Record<string, JiraConfig> = {};\n\n for (const key of Object.keys(process.env)) {\n const match = key.match(/^JIRA_([A-Z0-9]+)_URL$/);\n if (!match) continue;\n\n const name = match[1].toLowerCase();\n const upper = match[1];\n const url = process.env[`JIRA_${upper}_URL`];\n const token = process.env[`JIRA_${upper}_TOKEN`];\n const email = process.env[`JIRA_${upper}_EMAIL`];\n\n if (url && token && email) {\n instances[name] = { url, token, email };\n }\n }\n\n return instances;\n}\n\nexport const INSTANCES = loadInstances();\n\nexport type JiraClient = AxiosInstance;\n\nexport function getClient(instance: string): JiraClient {\n const config = INSTANCES[instance];\n if (!config) {\n const available = Object.keys(INSTANCES).join(\", \") || \"none\";\n throw new Error(\n `Unknown Jira instance: \"${instance}\". Available: ${available}`,\n );\n }\n\n return axios.create({\n baseURL: `${config.url}/rest/api/3`,\n headers: {\n Authorization: `Basic ${Buffer.from(`${config.email}:${config.token}`).toString(\"base64\")}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n });\n}\n","import { Octokit } from \"@octokit/rest\";\n\nexport interface GitHubClient {\n createBranch(base: string, branch: string): Promise<void>;\n createPR(opts: {\n title: string;\n body: string;\n head: string;\n base: string;\n draft?: boolean;\n }): Promise<number>;\n mergePR(\n prNumber: number,\n strategy: \"squash\" | \"merge\" | \"rebase\",\n ): Promise<void>;\n addReviewers(prNumber: number, reviewers: string[]): Promise<void>;\n getPR(prNumber: number): Promise<{ state: string; merged: boolean }>;\n getRunStatus(\n branch: string,\n ): Promise<\"pending\" | \"success\" | \"failure\" | \"unknown\">;\n}\n\nexport function createGitHubClient(\n token: string,\n owner: string,\n repo: string,\n): GitHubClient {\n const octokit = new Octokit({ auth: token });\n\n return {\n async createBranch(base, branch) {\n const { data: ref } = await octokit.git.getRef({\n owner,\n repo,\n ref: `heads/${base}`,\n });\n await octokit.git.createRef({\n owner,\n repo,\n ref: `refs/heads/${branch}`,\n sha: ref.object.sha,\n });\n },\n\n async createPR({ title, body, head, base, draft = false }) {\n const { data } = await octokit.pulls.create({\n owner,\n repo,\n title,\n body,\n head,\n base,\n draft,\n });\n return data.number;\n },\n\n async mergePR(prNumber, strategy) {\n const mergeMethod =\n strategy === \"squash\"\n ? \"squash\"\n : strategy === \"rebase\"\n ? \"rebase\"\n : \"merge\";\n await octokit.pulls.merge({\n owner,\n repo,\n pull_number: prNumber,\n merge_method: mergeMethod,\n });\n },\n\n async addReviewers(prNumber, reviewers) {\n if (reviewers.length === 0) return;\n await octokit.pulls.requestReviewers({\n owner,\n repo,\n pull_number: prNumber,\n reviewers,\n });\n },\n\n async getPR(prNumber) {\n const { data } = await octokit.pulls.get({\n owner,\n repo,\n pull_number: prNumber,\n });\n return { state: data.state, merged: data.merged };\n },\n\n async getRunStatus(branch) {\n try {\n const { data } = await octokit.repos.getCombinedStatusForRef({\n owner,\n repo,\n ref: branch,\n });\n if (data.state === \"success\") return \"success\";\n if (data.state === \"failure\") return \"failure\";\n return \"pending\";\n } catch {\n return \"unknown\";\n }\n },\n };\n}\n","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","import type { TelegramNotifier } from \"../integrations/telegram/notifier.js\";\nimport { getEvents } from \"./state.js\";\nimport { estimateCostUsd, extractTokenUsage } from \"../utils/pricing.js\";\n\nexport async function checkCostLimit(opts: {\n runDir: string;\n maxCostUsd: number;\n telegram: TelegramNotifier;\n ticketKey: string;\n}): Promise<\"continue\" | \"abort\"> {\n const events = getEvents(opts.runDir);\n\n let totalCost = 0;\n\n for (const event of events) {\n if (event.type !== \"STAGE_COMPLETED\") continue;\n const tu = extractTokenUsage(event.output);\n if (!tu) continue;\n totalCost += estimateCostUsd(tu.inputTokens, tu.outputTokens, tu.model);\n }\n\n if (totalCost >= opts.maxCostUsd) {\n await opts.telegram.send(\n `⛔ <b>${opts.ticketKey}</b> — Cost limit reached ($${totalCost.toFixed(4)} / $${opts.maxCostUsd}). Aborting pipeline.`,\n );\n return \"abort\";\n }\n\n if (totalCost >= 0.8 * opts.maxCostUsd) {\n await opts.telegram.send(\n `⚠️ <b>${opts.ticketKey}</b> — Cost at 80% of limit ($${totalCost.toFixed(4)} / $${opts.maxCostUsd}).`,\n );\n }\n\n return \"continue\";\n}\n","import { z } from \"zod\";\nimport { getClient } from \"./client.js\";\n\n// ─── Schemas ────────────────────────────────────────────────────────────────\n\nconst instanceSchema = z.string().describe('Instance name (e.g. \"hi\", \"geo\")');\n\nexport const GetTasksSchema = z.object({\n instance: instanceSchema,\n assignees: z\n .array(z.string())\n .describe(\"List of Jira usernames or accountIds\"),\n project_key: z\n .string()\n .optional()\n .describe('Filter by project key (e.g. \"HI\")'),\n status: z\n .string()\n .optional()\n .describe('Filter by status (e.g. \"In Progress\")'),\n max_results: z.number().default(20),\n});\n\nexport const GetTicketSchema = z.object({\n instance: instanceSchema,\n ticket_key: z.string().describe('Jira ticket key (e.g. \"HI-123\")'),\n});\n\nexport const GetTransitionsSchema = z.object({\n instance: instanceSchema,\n ticket_key: z.string(),\n});\n\nexport const TransitionTicketSchema = z.object({\n instance: instanceSchema,\n ticket_key: z.string(),\n transition_name: z\n .string()\n .describe('Transition name (e.g. \"In Review\", \"Done\")'),\n});\n\nexport const AddCommentSchema = z.object({\n instance: instanceSchema,\n ticket_key: z.string(),\n comment: z.string().describe(\"Comment text (plain text or Jira markdown)\"),\n});\n\nexport const ReassignSchema = z.object({\n instance: instanceSchema,\n ticket_key: z.string(),\n account_id: z.string().describe(\"Jira accountId of the new assignee\"),\n});\n\n// ─── Tool implementations ────────────────────────────────────────────────────\n\nexport async function getTasks(\n args: z.infer<typeof GetTasksSchema>,\n): Promise<string> {\n const client = getClient(args.instance);\n\n const conditions = [\n args.assignees.map((a) => `assignee = \"${a}\"`).join(\" OR \"),\n args.project_key ? `project = ${args.project_key}` : null,\n args.status ? `status = \"${args.status}\"` : null,\n ].filter(Boolean);\n\n const jql = conditions.join(\" AND \") + \" ORDER BY updated DESC\";\n\n const { data } = await client.get(\"/search\", {\n params: {\n jql,\n maxResults: args.max_results,\n fields: \"summary,status,assignee,priority,description,created,updated\",\n },\n });\n\n const issues = data.issues.map((issue: JiraIssue) => ({\n key: issue.key,\n summary: issue.fields.summary,\n status: issue.fields.status.name,\n assignee: issue.fields.assignee?.displayName ?? \"Unassigned\",\n priority: issue.fields.priority?.name ?? \"None\",\n }));\n\n return JSON.stringify({ total: data.total, issues }, null, 2);\n}\n\nexport async function getTicket(\n args: z.infer<typeof GetTicketSchema>,\n): Promise<string> {\n const client = getClient(args.instance);\n const { data } = await client.get(`/issue/${args.ticket_key}`);\n\n return JSON.stringify(\n {\n key: data.key,\n summary: data.fields.summary,\n status: data.fields.status.name,\n assignee: data.fields.assignee?.displayName ?? \"Unassigned\",\n priority: data.fields.priority?.name,\n description: extractText(data.fields.description),\n acceptance_criteria: extractText(data.fields.customfield_10016),\n created: data.fields.created,\n updated: data.fields.updated,\n },\n null,\n 2,\n );\n}\n\nexport async function getTransitions(\n args: z.infer<typeof GetTransitionsSchema>,\n): Promise<string> {\n const client = getClient(args.instance);\n const { data } = await client.get(`/issue/${args.ticket_key}/transitions`);\n const transitions = data.transitions.map((t: JiraTransition) => ({\n id: t.id,\n name: t.name,\n }));\n return JSON.stringify(transitions, null, 2);\n}\n\nexport async function transitionTicket(\n args: z.infer<typeof TransitionTicketSchema>,\n): Promise<string> {\n const client = getClient(args.instance);\n\n const { data } = await client.get(`/issue/${args.ticket_key}/transitions`);\n const transition = data.transitions.find(\n (t: JiraTransition) =>\n t.name.toLowerCase() === args.transition_name.toLowerCase(),\n );\n\n if (!transition) {\n const available = data.transitions\n .map((t: JiraTransition) => t.name)\n .join(\", \");\n throw new Error(\n `Transition \"${args.transition_name}\" not found. Available: ${available}`,\n );\n }\n\n await client.post(`/issue/${args.ticket_key}/transitions`, {\n transition: { id: transition.id },\n });\n return `Transitioned ${args.ticket_key} to \"${transition.name}\"`;\n}\n\nexport async function addComment(\n args: z.infer<typeof AddCommentSchema>,\n): Promise<string> {\n const client = getClient(args.instance);\n\n await client.post(`/issue/${args.ticket_key}/comment`, {\n body: {\n type: \"doc\",\n version: 1,\n content: [\n { type: \"paragraph\", content: [{ type: \"text\", text: args.comment }] },\n ],\n },\n });\n\n return `Comment added to ${args.ticket_key}`;\n}\n\nexport async function reassign(\n args: z.infer<typeof ReassignSchema>,\n): Promise<string> {\n const client = getClient(args.instance);\n await client.put(`/issue/${args.ticket_key}/assignee`, {\n accountId: args.account_id,\n });\n return `${args.ticket_key} reassigned to accountId: ${args.account_id}`;\n}\n\n// ─── Helpers ────────────────────────────────────────────────────────────────\n\nfunction extractText(adfNode: AdfNode | null | undefined): string {\n if (!adfNode) return \"\";\n if (typeof adfNode === \"string\") return adfNode;\n if (adfNode.type === \"text\") return adfNode.text ?? \"\";\n if (adfNode.content) return adfNode.content.map(extractText).join(\" \");\n return \"\";\n}\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\ninterface JiraIssue {\n key: string;\n fields: {\n summary: string;\n status: { name: string };\n assignee: { displayName: string } | null;\n priority: { name: string } | null;\n description: AdfNode | null;\n customfield_10016: AdfNode | null;\n created: string;\n updated: string;\n };\n}\n\ninterface JiraTransition {\n id: string;\n name: string;\n}\n\ninterface AdfNode {\n type: string;\n text?: string;\n content?: AdfNode[];\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { StageId } from \"../config/schema.js\";\n\nexport function writeTicketContext(\n memoryDir: string,\n ticket: {\n key: string;\n summary: string;\n description: string;\n acceptanceCriteria: string;\n priority: string;\n clarifications?: string;\n },\n): void {\n fs.mkdirSync(memoryDir, { recursive: true });\n const content = `# Ticket: ${ticket.key}\n\n## Summary\n${ticket.summary}\n\n## Description\n${ticket.description || \"(none)\"}\n\n## Acceptance Criteria\n${ticket.acceptanceCriteria || \"(none)\"}\n\n## Priority\n${ticket.priority}\n${ticket.clarifications ? `\\n## Clarifications from Team\\n${ticket.clarifications}` : \"\"}\n`;\n fs.writeFileSync(path.join(memoryDir, \"ticket-context.md\"), content);\n}\n\nexport function readTicketContext(memoryDir: string): string {\n const p = path.join(memoryDir, \"ticket-context.md\");\n return fs.existsSync(p) ? fs.readFileSync(p, \"utf8\") : \"\";\n}\n\nexport function appendClarifications(memoryDir: string, answers: string): void {\n const p = path.join(memoryDir, \"ticket-context.md\");\n if (fs.existsSync(p)) {\n fs.appendFileSync(p, `\\n## Clarifications from Team\\n${answers}\\n`);\n }\n}\n\nexport function writeReviewFeedback(\n memoryDir: string,\n feedback: {\n prNumber: number;\n issues: { severity: \"minor\" | \"major\"; message: string }[];\n autoResolved: boolean;\n },\n): void {\n const lines = [\n `# Review Results`,\n `PR: #${feedback.prNumber}`,\n `Major issues: ${feedback.issues.filter((i) => i.severity === \"major\").length}`,\n `Minor issues: ${feedback.issues.filter((i) => i.severity === \"minor\").length}`,\n `Auto-resolved: ${feedback.autoResolved}`,\n \"\",\n \"## Issues\",\n ...feedback.issues.map(\n (i) => `- [${i.severity.toUpperCase()}] ${i.message}`,\n ),\n ];\n fs.writeFileSync(\n path.join(memoryDir, \"review-feedback.md\"),\n lines.join(\"\\n\"),\n );\n}\n\nexport function getContextFilesForStage(\n projectDir: string,\n memoryDir: string,\n stage: StageId,\n): string[] {\n const claudeMd = path.join(projectDir, \".claude\", \"CLAUDE.md\");\n const ticketCtx = path.join(memoryDir, \"ticket-context.md\");\n const reviewFeedback = path.join(memoryDir, \"review-feedback.md\");\n\n const files: string[] = [];\n if (fs.existsSync(claudeMd)) files.push(claudeMd);\n\n if ([\"code\", \"git\", \"review\", \"deploy\", \"test\", \"notify\"].includes(stage)) {\n if (fs.existsSync(ticketCtx)) files.push(ticketCtx);\n }\n if (stage === \"test\" && fs.existsSync(reviewFeedback)) {\n files.push(reviewFeedback);\n }\n return files;\n}\n","import type { Stage, PipelineContext, StageOutput } from \"./types.js\";\nimport { getTasks, getTicket } from \"../../integrations/jira/tools.js\";\nimport { writeTicketContext } from \"../../memory/context-builder.js\";\n\nexport const fetchStage: Stage = {\n id: \"fetch\",\n name: \"Fetch Ticket\",\n model: \"haiku\",\n\n async run(ctx: PipelineContext): Promise<StageOutput> {\n const { config, ticketKey, memoryDir } = ctx;\n\n ctx.logger.info({ ticketKey }, \"Fetching ticket from Jira\");\n\n const raw = await getTicket({\n instance: config.jira.instance,\n ticket_key: ticketKey,\n });\n const ticket = JSON.parse(raw) as {\n key: string;\n summary: string;\n status: string;\n assignee: string;\n priority: string;\n description: string;\n acceptance_criteria: string;\n };\n\n writeTicketContext(memoryDir, {\n key: ticket.key,\n summary: ticket.summary,\n description: ticket.description ?? \"\",\n acceptanceCriteria: ticket.acceptance_criteria ?? \"\",\n priority: ticket.priority ?? \"Medium\",\n });\n\n ctx.logger.info({ ticketKey, summary: ticket.summary }, \"Ticket fetched\");\n\n return {\n summary: ticket.summary,\n description: ticket.description,\n acceptanceCriteria: ticket.acceptance_criteria,\n status: ticket.status,\n };\n },\n};\n","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","import { spawnSafe, buildMinimalEnv } from \"../utils/process.js\";\n\nexport type AgentModel = \"haiku\" | \"sonnet\" | \"opus\";\n\nconst MODEL_IDS: Record<AgentModel, string> = {\n haiku: \"claude-haiku-4-5-20251001\",\n sonnet: \"claude-sonnet-4-6\",\n opus: \"claude-opus-4-6\",\n};\n\nexport interface RunAgentOptions {\n prompt: string;\n workdir: string;\n model: AgentModel;\n contextFiles?: string[];\n timeoutMs?: number;\n stallTimeoutMs?: number;\n extraEnv?: Record<string, string>;\n}\n\nexport async function runAgent(opts: RunAgentOptions): Promise<string> {\n const args = [\n \"--model\",\n MODEL_IDS[opts.model],\n \"--print\",\n \"--output-format\",\n \"text\",\n ];\n\n for (const f of opts.contextFiles ?? []) {\n args.push(\"--context\", f);\n }\n\n args.push(opts.prompt);\n\n const result = await spawnSafe(\"claude\", args, {\n cwd: opts.workdir,\n env: buildMinimalEnv(opts.extraEnv),\n timeoutMs: opts.timeoutMs ?? 1_800_000,\n stallTimeoutMs: opts.stallTimeoutMs ?? 300_000,\n });\n\n if (result.exitCode !== 0) {\n throw new Error(\n `Agent exited with code ${result.exitCode}:\\n${result.stderr}`,\n );\n }\n\n return result.stdout.trim();\n}\n\n/** Run two agents in parallel and return both outputs */\nexport async function runAgentsParallel(\n a: RunAgentOptions,\n b: RunAgentOptions,\n): Promise<[string, string]> {\n return Promise.all([runAgent(a), runAgent(b)]);\n}\n\n/** Detect if a task is complex enough to warrant Opus */\nexport function detectComplexity(description: string): AgentModel {\n const complexKeywords = [\n \"auth\",\n \"payment\",\n \"stripe\",\n \"oauth\",\n \"jwt\",\n \"migration\",\n \"schema\",\n \"database\",\n \"refactor\",\n \"cross-module\",\n \"multi-service\",\n \"security\",\n \"encryption\",\n \"permission\",\n ];\n const lower = description.toLowerCase();\n const matches = complexKeywords.filter((k) => lower.includes(k));\n return matches.length >= 2 ? \"opus\" : \"sonnet\";\n}\n","import type { Stage, PipelineContext, StageOutput } from \"./types.js\";\nimport { runAgent } from \"../runner.js\";\nimport { readTicketContext } from \"../../memory/context-builder.js\";\n\nconst CLARITY_PROMPT = (ticketCtx: string, requiredFields: string[]) =>\n `\nAnalyze this Jira ticket for clarity. Score from 0.0 to 1.0.\n\nRequired fields: ${requiredFields.join(\", \")}\n\nTicket:\n${ticketCtx}\n\nReply with JSON only:\n{\n \"score\": 0.0-1.0,\n \"missing\": [\"list of missing or ambiguous items\"],\n \"questions\": [\"specific questions to ask the team\"]\n}\n`.trim();\n\nexport const analyzeStage: Stage = {\n id: \"analyze\",\n name: \"Analyze Clarity\",\n model: \"sonnet\",\n\n async run(ctx: PipelineContext): Promise<StageOutput> {\n const { config, memoryDir, ticketKey } = ctx;\n\n const ticketCtx = readTicketContext(memoryDir);\n if (!ticketCtx)\n throw new Error(\"ticket-context.md not found — run fetch stage first\");\n\n ctx.logger.info({ ticketKey }, \"Analyzing ticket clarity\");\n\n const raw = await runAgent({\n prompt: CLARITY_PROMPT(\n ticketCtx,\n config.jira.requiredFields ?? [\"description\", \"acceptanceCriteria\"],\n ),\n workdir: config.workspace.rootDir,\n model: \"haiku\",\n timeoutMs: 60_000,\n stallTimeoutMs: 30_000,\n });\n\n // Extract JSON from agent output\n const jsonMatch = raw.match(/\\{[\\s\\S]*\\}/);\n if (!jsonMatch) {\n ctx.logger.warn(\n { ticketKey },\n \"Could not parse clarity JSON — defaulting to low score\",\n );\n return { score: 0, missing: [], questions: [], needsClarification: true };\n }\n\n const result = JSON.parse(jsonMatch[0]) as {\n score: number;\n missing: string[];\n questions: string[];\n };\n\n const threshold = config.jira.clarityScoreThreshold ?? 0.7;\n const needsClarification = result.score < threshold;\n\n ctx.logger.info(\n { ticketKey, score: result.score, threshold, needsClarification },\n \"Clarity analysis done\",\n );\n\n return { ...result, needsClarification };\n },\n};\n","import type { Stage, PipelineContext, StageOutput } from \"./types.js\";\nimport { requestClarification } from \"../../integrations/telegram/human-loop.js\";\nimport { appendClarifications } from \"../../memory/context-builder.js\";\nimport path from \"node:path\";\n\nexport const clarifyStage: Stage = {\n id: \"clarify\",\n name: \"Clarify\",\n model: \"haiku\",\n\n async shouldSkip(ctx: PipelineContext): Promise<boolean> {\n const lastAnalyze = ctx.state.current.completedStages.includes(\"analyze\");\n if (!lastAnalyze) return true;\n // Read analysis output from event log\n const events = (\n ctx.state as unknown as {\n events: Array<{ type: string; stage?: string; output?: unknown }>;\n }\n ).events;\n const analyzeEvent = events.findLast(\n (e) => e.type === \"STAGE_COMPLETED\" && e.stage === \"analyze\",\n );\n const output = analyzeEvent?.output as\n | { needsClarification?: boolean }\n | undefined;\n return !output?.needsClarification;\n },\n\n async run(ctx: PipelineContext): Promise<StageOutput> {\n const { config, ticketKey, memoryDir } = ctx;\n const storeDir = path.join(config.workspace.rootDir, \".jira-acp\");\n\n // Get questions from analyze stage output\n const events = (\n ctx.state as unknown as {\n events: Array<{ type: string; stage?: string; output?: unknown }>;\n }\n ).events;\n const analyzeEvent = events.findLast(\n (e) => e.type === \"STAGE_COMPLETED\" && e.stage === \"analyze\",\n );\n const questions = (analyzeEvent?.output as { questions?: string[] })\n ?.questions ?? [\"Please clarify the ticket requirements.\"];\n\n ctx.logger.info(\n { ticketKey, questions },\n \"Requesting clarification via Telegram\",\n );\n\n const hil = config.telegram.humanInTheLoop;\n const answers = await requestClarification(\n config.telegram.botToken,\n config.telegram.chatId,\n ticketKey,\n questions,\n storeDir,\n {\n timeoutMs: hil?.clarificationTimeoutMs ?? 3_600_000,\n onTimeout: hil?.clarificationTimeoutAction ?? \"skip\",\n },\n );\n\n appendClarifications(memoryDir, answers);\n ctx.logger.info({ ticketKey }, \"Clarifications received and saved\");\n\n return { clarified: true, answers };\n },\n};\n","import type { Stage, PipelineContext, StageOutput } from \"./types.js\";\nimport { runAgent, detectComplexity } from \"../runner.js\";\nimport {\n getContextFilesForStage,\n readTicketContext,\n} from \"../../memory/context-builder.js\";\n\nexport const codeStage: Stage = {\n id: \"code\",\n name: \"Code\",\n model: \"sonnet\",\n\n async run(ctx: PipelineContext): Promise<StageOutput> {\n const { config, ticketKey, memoryDir, projectDir } = ctx;\n\n const ticketCtx = readTicketContext(memoryDir);\n const contextFiles = getContextFilesForStage(projectDir, memoryDir, \"code\");\n\n const model = detectComplexity(ticketCtx);\n ctx.logger.info({ ticketKey, model }, \"Starting code agent\");\n\n const branchName = buildBranchName(\n config.github.branchPattern ?? \"feature/{ticketKey}-{slug}\",\n ticketKey,\n ticketCtx,\n );\n\n const prompt = `\nImplement the following Jira ticket: ${ticketKey}\n\nRead the ticket context from the provided context files.\n\nRequirements:\n1. Create branch: ${branchName}\n2. Implement all acceptance criteria\n3. Write tests for new functionality\n4. Commit with message: \"${ticketKey}: <short description>\"\n5. Do NOT push — pipeline will handle git operations\n\nBranch naming: ${branchName}\nWorkspace: ${config.workspace.rootDir}\n${config.workspace.buildCommand ? `Build command: ${config.workspace.buildCommand}` : \"\"}\n`.trim();\n\n if (!ctx.dryRun) {\n await runAgent({\n prompt,\n workdir: config.workspace.rootDir,\n model,\n contextFiles,\n timeoutMs: config.pipeline?.stageTimeouts?.code ?? 1_800_000,\n stallTimeoutMs: config.pipeline?.agentStallTimeoutMs ?? 300_000,\n });\n }\n\n ctx.logger.info({ ticketKey, branchName }, \"Code agent completed\");\n return { branchName };\n },\n};\n\nfunction buildBranchName(\n pattern: string,\n ticketKey: string,\n ticketCtx: string,\n): string {\n const summaryLine = ticketCtx\n .split(\"\\n\")\n .find((l) => l.startsWith(\"## Summary\"));\n const nextLine = summaryLine\n ? (ticketCtx.split(\"\\n\")[ticketCtx.split(\"\\n\").indexOf(summaryLine) + 1] ??\n \"\")\n : \"\";\n const slug = nextLine\n .toLowerCase()\n .replace(/[^a-z0-9\\s-]/g, \"\")\n .trim()\n .replace(/\\s+/g, \"-\")\n .slice(0, 40);\n\n return pattern\n .replace(\"{ticketKey}\", ticketKey)\n .replace(\"{prefix}\", \"feature\")\n .replace(\"{slug}\", slug || \"implementation\");\n}\n","import type { Stage, PipelineContext, StageOutput } from \"./types.js\";\nimport { spawnSafe } from \"../../utils/process.js\";\nimport { readTicketContext } from \"../../memory/context-builder.js\";\n\nexport const gitStage: Stage = {\n id: \"git\",\n name: \"Git & PR\",\n model: \"haiku\",\n\n async run(ctx: PipelineContext): Promise<StageOutput> {\n const { config, ticketKey, state } = ctx;\n const branchName = state.current.branchName;\n if (!branchName)\n throw new Error(\"No branch name in state — code stage must run first\");\n\n const workdir = config.workspace.rootDir;\n const ticketCtx = readTicketContext(ctx.memoryDir);\n const summaryLine = ticketCtx\n .split(\"\\n\")\n .find((l) => l.startsWith(\"## Summary\"));\n const summary =\n ticketCtx.split(\"\\n\")[\n ticketCtx.split(\"\\n\").indexOf(summaryLine ?? \"\") + 1\n ] ?? ticketKey;\n\n ctx.logger.info(\n { ticketKey, branchName },\n \"Pushing branch and creating PR\",\n );\n\n if (!ctx.dryRun) {\n // Push branch\n await spawnSafe(\"git\", [\"push\", \"origin\", branchName], { cwd: workdir });\n\n // Create PR via GitHub client\n const prNumber = await ctx.github.createPR({\n title: `[${ticketKey}] ${summary.trim()}`,\n body: buildPrBody(ticketKey, ticketCtx),\n head: branchName,\n base: config.github.defaultBranch ?? \"main\",\n draft: config.github.prDraftByDefault ?? false,\n });\n\n if (config.github.reviewers?.length) {\n await ctx.github.addReviewers(prNumber, config.github.reviewers);\n }\n\n ctx.logger.info({ ticketKey, prNumber }, \"PR created\");\n return { branchName, prNumber };\n }\n\n return { branchName, prNumber: null };\n },\n};\n\nfunction buildPrBody(ticketKey: string, ticketCtx: string): string {\n return `## ${ticketKey}\n\n${ticketCtx}\n\n---\n*Generated by jiraACP automated pipeline*`;\n}\n","import type { Stage, PipelineContext, StageOutput } from \"./types.js\";\nimport { runAgentsParallel } from \"../runner.js\";\nimport {\n getContextFilesForStage,\n writeReviewFeedback,\n} from \"../../memory/context-builder.js\";\nimport { requestApproval } from \"../../integrations/telegram/human-loop.js\";\n\nexport const reviewStage: Stage = {\n id: \"review\",\n name: \"Review\",\n model: \"sonnet\",\n\n async run(ctx: PipelineContext): Promise<StageOutput> {\n const { config, ticketKey, state, memoryDir, projectDir } = ctx;\n const prNumber = state.current.prNumber;\n if (!prNumber)\n throw new Error(\"No PR number in state — git stage must run first\");\n\n const contextFiles = getContextFilesForStage(\n projectDir,\n memoryDir,\n \"review\",\n );\n ctx.logger.info({ ticketKey, prNumber }, \"Running parallel review agents\");\n\n const logicPrompt = `Review PR #${prNumber} for ticket ${ticketKey}.\nFocus on: Does the implementation correctly satisfy the acceptance criteria?\nList issues as JSON: { \"issues\": [{ \"severity\": \"minor\"|\"major\", \"message\": \"...\" }] }`;\n\n const qualityPrompt = `Review PR #${prNumber} for ticket ${ticketKey}.\nFocus on: Missing tests, security issues, type safety, performance red flags.\nList issues as JSON: { \"issues\": [{ \"severity\": \"minor\"|\"major\", \"message\": \"...\" }] }`;\n\n const agentOpts = {\n workdir: config.workspace.rootDir,\n model: \"sonnet\" as const,\n contextFiles,\n timeoutMs: (config.pipeline?.stageTimeouts?.review ?? 600_000) / 2,\n stallTimeoutMs: 120_000,\n };\n\n const [logicRaw, qualityRaw] = ctx.dryRun\n ? ['{\"issues\":[]}', '{\"issues\":[]}']\n : await runAgentsParallel(\n { ...agentOpts, prompt: logicPrompt },\n { ...agentOpts, prompt: qualityPrompt },\n );\n\n const issues = [...parseIssues(logicRaw), ...parseIssues(qualityRaw)];\n\n const majorCount = issues.filter((i) => i.severity === \"major\").length;\n const threshold = config.github.majorIssueThreshold ?? 1;\n const needsHumanApproval = majorCount >= threshold;\n\n writeReviewFeedback(memoryDir, {\n prNumber,\n issues,\n autoResolved: !needsHumanApproval,\n });\n\n if (needsHumanApproval) {\n ctx.logger.warn(\n { ticketKey, majorCount },\n \"Major issues found — requesting human approval via Telegram\",\n );\n\n ctx.state.emit({\n type: \"HUMAN_APPROVAL_REQUESTED\",\n context: { prNumber, majorCount },\n });\n\n const hil = config.telegram.humanInTheLoop;\n const approved = ctx.dryRun\n ? true\n : await requestApproval(\n config.telegram.botToken,\n config.telegram.chatId,\n ticketKey,\n issues,\n {\n timeoutMs: hil?.reviewApprovalTimeoutMs ?? 86_400_000,\n onTimeout: hil?.reviewApprovalTimeoutAction ?? \"abort\",\n topicId: config.telegram.topicId,\n },\n );\n\n if (approved) {\n ctx.state.emit({ type: \"HUMAN_APPROVED\" });\n ctx.logger.info(\n { ticketKey, prNumber },\n \"Human approved — proceeding to merge\",\n );\n } else {\n ctx.state.emit({\n type: \"HUMAN_REJECTED\",\n reason: \"Reviewer rejected PR\",\n });\n throw new Error(`REVIEW_REJECTED:PR #${prNumber} rejected by reviewer`);\n }\n }\n\n // Auto-merge (or post-approval merge)\n if (!ctx.dryRun) {\n await ctx.github.mergePR(\n prNumber,\n config.github.autoMergeStrategy ?? \"squash\",\n );\n ctx.logger.info({ ticketKey, prNumber }, \"PR merged\");\n }\n\n return { prNumber, issues, merged: true };\n },\n};\n\nfunction parseIssues(\n raw: string,\n): Array<{ severity: \"minor\" | \"major\"; message: string }> {\n try {\n const match = raw.match(/\\{[\\s\\S]*\\}/);\n if (!match) return [];\n const parsed = JSON.parse(match[0]) as {\n issues?: Array<{ severity: string; message: string }>;\n };\n return (parsed.issues ?? []).map((i) => ({\n severity: i.severity === \"major\" ? \"major\" : \"minor\",\n message: i.message,\n }));\n } catch {\n return [];\n }\n}\n","import type { Stage, PipelineContext, StageOutput } from \"./types.js\";\nimport { spawnSafe, buildMinimalEnv } from \"../../utils/process.js\";\n\nexport const deployStage: Stage = {\n id: \"deploy\",\n name: \"Deploy\",\n model: \"haiku\",\n\n async shouldSkip(ctx: PipelineContext): Promise<boolean> {\n return !ctx.config.deploy?.enabled;\n },\n\n async run(ctx: PipelineContext): Promise<StageOutput> {\n const { config, ticketKey } = ctx;\n const deploy = config.deploy;\n\n if (!deploy?.command) throw new Error(\"deploy.command not configured\");\n\n ctx.logger.info({ ticketKey }, \"Deploying to dev server\");\n\n if (ctx.dryRun) return { deployed: false, dryRun: true };\n\n const result = await spawnSafe(deploy.command, [], {\n cwd: config.workspace.rootDir,\n env: buildMinimalEnv(deploy.env ?? {}),\n timeoutMs: deploy.timeoutMs ?? 1_200_000,\n });\n\n if (result.exitCode !== 0) {\n throw new Error(\n `Deploy failed (exit ${result.exitCode}):\\n${result.stderr}`,\n );\n }\n\n // Health check\n if (deploy.healthCheckUrl) {\n await healthCheck(\n deploy.healthCheckUrl,\n deploy.healthCheckTimeoutMs ?? 30_000,\n );\n }\n\n ctx.logger.info({ ticketKey }, \"Deploy successful\");\n return { deployed: true, deployUrl: deploy.healthCheckUrl };\n },\n};\n\nasync function healthCheck(url: string, timeoutMs: number): Promise<void> {\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n try {\n const res = await fetch(url, { signal: AbortSignal.timeout(5_000) });\n if (res.ok) return;\n } catch {\n /* keep retrying */\n }\n await sleep(2_000);\n }\n throw new Error(`Health check timed out after ${timeoutMs}ms: ${url}`);\n}\n\nconst sleep = (ms: number): Promise<void> =>\n new Promise((r) => setTimeout(r, ms));\n","import type { Stage, PipelineContext, StageOutput } from \"./types.js\";\nimport { runAgent } from \"../runner.js\";\nimport { getContextFilesForStage } from \"../../memory/context-builder.js\";\n\nconst sleep = (ms: number): Promise<void> =>\n new Promise((r) => setTimeout(r, ms));\n\nexport const testStage: Stage = {\n id: \"test\",\n name: \"UI Test\",\n model: \"sonnet\",\n\n async shouldSkip(ctx: PipelineContext): Promise<boolean> {\n return !ctx.config.test?.enabled;\n },\n\n async run(ctx: PipelineContext): Promise<StageOutput> {\n const { config, ticketKey, memoryDir, projectDir } = ctx;\n const testConfig = config.test;\n\n if (!testConfig?.baseUrl) throw new Error(\"test.baseUrl not configured\");\n\n // Wait before testing (let deploy settle)\n const waitMs = testConfig.waitBeforeTestMs ?? 5_000;\n ctx.logger.info({ ticketKey, waitMs }, \"Waiting before UI tests\");\n await sleep(waitMs);\n\n const contextFiles = getContextFilesForStage(projectDir, memoryDir, \"test\");\n const retries = testConfig.retries ?? 2;\n\n const prompt = `\nRun Playwright UI tests for ticket ${ticketKey} on ${testConfig.baseUrl}.\n\nTest the acceptance criteria from the ticket context.\nSpec pattern: ${testConfig.specPattern ?? \"e2e/**/*.spec.ts\"}\n\nReport results as JSON: { \"passed\": boolean, \"summary\": \"...\", \"failures\": [\"...\"] }\n`.trim();\n\n let lastError: Error | undefined;\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n ctx.logger.info(\n { ticketKey, attempt: attempt + 1 },\n \"Running UI tests\",\n );\n\n const raw = ctx.dryRun\n ? '{\"passed\":true,\"summary\":\"dry-run\",\"failures\":[]}'\n : await runAgent({\n prompt,\n workdir: config.workspace.rootDir,\n model: \"sonnet\",\n contextFiles,\n timeoutMs: testConfig.timeoutMs ?? 300_000,\n stallTimeoutMs: 60_000,\n });\n\n const match = raw.match(/\\{[\\s\\S]*\\}/);\n if (!match) throw new Error(\"Could not parse test results JSON\");\n\n const result = JSON.parse(match[0]) as {\n passed: boolean;\n summary: string;\n failures: string[];\n };\n\n if (result.passed) {\n ctx.logger.info({ ticketKey }, \"UI tests passed\");\n return { passed: true, summary: result.summary };\n }\n\n lastError = new Error(`Tests failed: ${result.failures.join(\", \")}`);\n ctx.logger.warn(\n { ticketKey, attempt: attempt + 1, failures: result.failures },\n \"Tests failed, retrying\",\n );\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n }\n }\n\n const failOnTest = config.pipeline?.failOnTestFailure ?? false;\n if (failOnTest)\n throw lastError ?? new Error(\"Tests failed after all retries\");\n\n await ctx.telegram.send(\n `⚠️ <b>${ticketKey}</b> UI tests failed after ${retries + 1} attempts. Continuing pipeline.\\n${lastError?.message}`,\n );\n return { passed: false, summary: lastError?.message ?? \"Tests failed\" };\n },\n};\n","import type { Stage, PipelineContext, StageOutput } from \"./types.js\";\nimport {\n transitionTicket,\n addComment,\n reassign,\n} from \"../../integrations/jira/tools.js\";\n\nexport const notifyStage: Stage = {\n id: \"notify\",\n name: \"Notify\",\n model: \"haiku\",\n\n async run(ctx: PipelineContext): Promise<StageOutput> {\n const { config, ticketKey, state } = ctx;\n const current = state.current;\n\n ctx.logger.info({ ticketKey }, \"Notifying: Jira + Telegram\");\n\n if (!ctx.dryRun) {\n // Transition to Done\n await transitionTicket({\n instance: config.jira.instance,\n ticket_key: ticketKey,\n transition_name: config.jira.doneTransition ?? \"Done\",\n });\n\n // Add completion comment\n const prInfo = current.prNumber ? `\\nPR: #${current.prNumber}` : \"\";\n const branchInfo = current.branchName\n ? `\\nBranch: ${current.branchName}`\n : \"\";\n await addComment({\n instance: config.jira.instance,\n ticket_key: ticketKey,\n comment: `✅ Implemented via jiraACP automated pipeline.${prInfo}${branchInfo}\\n\\nAll stages completed: fetch → analyze → code → review → deploy → test`,\n });\n\n // Reassign if configured\n if (config.jira.reassignTo) {\n await reassign({\n instance: config.jira.instance,\n ticket_key: ticketKey,\n account_id: config.jira.reassignTo,\n });\n }\n\n // Telegram notification\n await ctx.telegram.sendDone(ticketKey, {\n summary: \"Pipeline completed successfully\",\n prNumber: current.prNumber ?? undefined,\n });\n }\n\n ctx.logger.info({ ticketKey }, \"Notifications sent\");\n return { notified: true };\n },\n};\n","import type { Logger } from \"pino\";\nimport { spawnSafe, buildMinimalEnv } from \"../utils/process.js\";\n\nexport type HookName =\n | \"beforePipeline\"\n | \"beforeCode\"\n | \"afterCode\"\n | \"afterDeploy\"\n | \"afterPipeline\";\n\nexport class HookError extends Error {\n constructor(\n public readonly hookName: HookName,\n public readonly exitCode: number,\n ) {\n super(`Hook '${hookName}' failed with exit code ${exitCode}`);\n this.name = \"HookError\";\n }\n}\n\nexport async function runHook(\n name: HookName,\n command: string | undefined,\n ctx: { ticketKey: string; logger: Logger },\n): Promise<void> {\n if (!command?.trim()) return;\n\n // Simple whitespace split — quoted args (e.g. \"my script.sh\") are not supported.\n // Hook commands should avoid spaces in path; use a wrapper script if needed.\n const [bin, ...args] = command.trim().split(/\\s+/);\n const { logger } = ctx;\n\n logger.info({ hookName: name, command }, \"Running hook\");\n\n const result = await spawnSafe(bin, args, {\n env: buildMinimalEnv({ JIRA_ACP_TICKET: ctx.ticketKey }),\n });\n\n if (result.exitCode !== 0) {\n logger.error(\n { hookName: name, exitCode: result.exitCode, stderr: result.stderr },\n \"Hook failed\",\n );\n throw new HookError(name, result.exitCode);\n }\n\n logger.info({ hookName: name }, \"Hook completed\");\n}\n","import type { ProjectConfig, StageId } from \"../config/schema.js\";\nimport type { PipelineContext } from \"./stages/types.js\";\nimport type { JiraClient } from \"../integrations/jira/client.js\";\nimport { StateManager, getRunDir, getLockPath, getMemoryDir } from \"./state.js\";\nimport { acquireLock } from \"../utils/lock.js\";\nimport { createLogger } from \"../utils/logger.js\";\nimport { getClient as getJiraClient } from \"../integrations/jira/client.js\";\nimport { createGitHubClient } from \"../integrations/github/client.js\";\nimport { createTelegramNotifier } from \"../integrations/telegram/notifier.js\";\nimport { checkCostLimit } from \"./cost-guard.js\";\nimport { fetchStage } from \"./stages/1-fetch.js\";\nimport { analyzeStage } from \"./stages/2-analyze.js\";\nimport { clarifyStage } from \"./stages/3-clarify.js\";\nimport { codeStage } from \"./stages/4-code.js\";\nimport { gitStage } from \"./stages/5-git.js\";\nimport { reviewStage } from \"./stages/6-review.js\";\nimport { deployStage } from \"./stages/7-deploy.js\";\nimport { testStage } from \"./stages/8-test.js\";\nimport { notifyStage } from \"./stages/9-notify.js\";\nimport type { Stage } from \"./stages/types.js\";\nimport { runHook, HookError } from \"./hooks.js\";\nimport { initBot } from \"../integrations/telegram/bot.js\";\n\nconst ALL_STAGES: Stage[] = [\n fetchStage,\n analyzeStage,\n clarifyStage,\n codeStage,\n gitStage,\n reviewStage,\n deployStage,\n testStage,\n notifyStage,\n];\n\nexport interface RunOptions {\n fromStage?: StageId;\n toStage?: StageId;\n dryRun?: boolean;\n}\n\nexport async function runPipeline(\n ticketKey: string,\n config: ProjectConfig,\n opts: RunOptions = {},\n): Promise<void> {\n const projectDir = config.workspace.rootDir;\n const runDir = getRunDir(config.name, ticketKey);\n const lockPath = getLockPath(config.name, ticketKey);\n const memoryDir = getMemoryDir(config.name, ticketKey);\n const logger = createLogger(`pipeline:${ticketKey}`);\n const state = new StateManager(runDir);\n\n // Ensure bot is polling so human-in-the-loop handlers work\n if (config.telegram?.botToken) {\n await initBot(config.telegram.botToken);\n }\n\n const lock = await acquireLock(lockPath);\n\n const ctx: PipelineContext = {\n config,\n ticketKey,\n projectDir,\n state,\n memoryDir,\n dryRun: opts.dryRun ?? false,\n logger,\n jira: getJiraClient(config.jira.instance) as JiraClient,\n github: createGitHubClient(\n config.github.token,\n config.github.owner,\n config.github.repo,\n ),\n telegram: createTelegramNotifier(\n config.telegram.botToken,\n config.telegram.chatId,\n ticketKey,\n config.name,\n config.telegram.topicId,\n ),\n };\n\n state.emit({ type: \"STARTED\", ticketKey });\n\n const stages = filterStages(ALL_STAGES, opts.fromStage, opts.toStage);\n const hooksConfig = config.pipeline?.hooks;\n\n try {\n await runHook(\"beforePipeline\", hooksConfig?.beforePipeline, {\n ticketKey,\n logger,\n });\n\n for (const stage of stages) {\n if (await stage.shouldSkip?.(ctx)) {\n state.emit({\n type: \"STAGE_SKIPPED\",\n stage: stage.id,\n reason: \"shouldSkip returned true\",\n });\n logger.info({ stage: stage.id }, \"Stage skipped\");\n await ctx.telegram.notifyStageSkipped(stage.id).catch(() => undefined);\n continue;\n }\n\n if (stage.id === \"code\") {\n await runHook(\"beforeCode\", hooksConfig?.beforeCode, {\n ticketKey,\n logger,\n });\n }\n\n state.emit({ type: \"STAGE_STARTED\", stage: stage.id });\n logger.info({ stage: stage.id }, `▶ ${stage.name}`);\n await ctx.telegram.notifyStageStarted(stage.id).catch(() => undefined);\n\n try {\n const timeout = config.pipeline?.stageTimeouts?.[stage.id];\n const output = timeout\n ? await withTimeout(stage.run(ctx), timeout)\n : await stage.run(ctx);\n\n state.emit({ type: \"STAGE_COMPLETED\", stage: stage.id, output });\n logger.info({ stage: stage.id }, `✓ ${stage.name}`);\n await ctx.telegram\n .notifyStageCompleted(stage.id)\n .catch(() => undefined);\n\n if (config.pipeline?.maxCostUsdPerRun) {\n const decision = await checkCostLimit({\n runDir,\n maxCostUsd: config.pipeline.maxCostUsdPerRun,\n telegram: ctx.telegram,\n ticketKey,\n });\n if (decision === \"abort\") {\n state.emit({\n type: \"PIPELINE_ABORTED\",\n reason: \"Cost limit exceeded\",\n });\n throw new Error(\"Cost limit exceeded\");\n }\n }\n\n if (stage.id === \"code\") {\n await runHook(\"afterCode\", hooksConfig?.afterCode, {\n ticketKey,\n logger,\n });\n }\n\n if (stage.id === \"deploy\") {\n await runHook(\"afterDeploy\", hooksConfig?.afterDeploy, {\n ticketKey,\n logger,\n });\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n\n // SKIP signal from clarify stage\n if (message.startsWith(\"SKIP:\")) {\n state.emit({\n type: \"STAGE_SKIPPED\",\n stage: stage.id,\n reason: message,\n });\n logger.warn({ stage: stage.id }, `Skipped: ${message}`);\n return;\n }\n\n if (err instanceof HookError) {\n state.emit({ type: \"PIPELINE_ABORTED\", reason: message });\n throw err;\n }\n\n state.emit({ type: \"STAGE_FAILED\", stage: stage.id, error: message });\n await ctx.telegram\n .notifyStageFailed(stage.id, message)\n .catch(() => undefined);\n throw err;\n }\n }\n\n state.emit({ type: \"PIPELINE_COMPLETED\" });\n logger.info({ ticketKey }, \"Pipeline completed\");\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n if (!(err instanceof HookError)) {\n state.emit({ type: \"PIPELINE_ABORTED\", reason });\n }\n await ctx.telegram.sendError(ticketKey, err);\n logger.error({ ticketKey, reason }, \"Pipeline aborted\");\n process.exitCode = 1;\n } finally {\n await runHook(\"afterPipeline\", hooksConfig?.afterPipeline, {\n ticketKey,\n logger,\n });\n lock.release();\n }\n}\n\nexport async function resumePipeline(\n ticketKey: string,\n config: ProjectConfig,\n): Promise<void> {\n const logger = createLogger(`pipeline:${ticketKey}`);\n const state = new StateManager(getRunDir(config.name, ticketKey));\n const current = state.current;\n\n if (current.isCompleted) {\n logger.info({ ticketKey }, \"Pipeline already completed\");\n process.stdout.write(`Pipeline for ${ticketKey} already completed.\\n`);\n return;\n }\n\n const fromStage = current.currentStage ?? current.failedStage ?? \"fetch\";\n logger.info({ ticketKey, fromStage }, \"Resuming pipeline\");\n\n await runPipeline(ticketKey, config, { fromStage: fromStage as StageId });\n}\n\nfunction filterStages(stages: Stage[], from?: StageId, to?: StageId): Stage[] {\n const fromIdx = from ? stages.findIndex((s) => s.id === from) : 0;\n const toIdx = to ? stages.findIndex((s) => s.id === to) : stages.length - 1;\n return stages.slice(\n fromIdx < 0 ? 0 : fromIdx,\n toIdx < 0 ? stages.length : toIdx + 1,\n );\n}\n\nasync function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {\n const signal = AbortSignal.timeout(ms);\n const aborted = new Promise<never>((_, reject) => {\n signal.addEventListener(\"abort\", () => {\n reject(new Error(`Stage timed out after ${ms}ms`));\n });\n });\n return Promise.race([promise, aborted]);\n}\n"],"mappings":"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","names":["path","sleep"]}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
// src/pipeline/state.ts
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import os from "os";
|
|
4
|
+
import path from "path";
|
|
5
|
+
var RUNS_DIR = path.join(os.homedir(), ".jira-acp", "runs");
|
|
6
|
+
var INITIAL_STATE = {
|
|
7
|
+
ticketKey: "",
|
|
8
|
+
currentStage: null,
|
|
9
|
+
completedStages: [],
|
|
10
|
+
failedStage: null,
|
|
11
|
+
pendingClarification: false,
|
|
12
|
+
pendingHumanApproval: false,
|
|
13
|
+
branchName: null,
|
|
14
|
+
prNumber: null,
|
|
15
|
+
isCompleted: false,
|
|
16
|
+
isAborted: false,
|
|
17
|
+
abortReason: null,
|
|
18
|
+
startedAt: null
|
|
19
|
+
};
|
|
20
|
+
function applyEvent(state, event) {
|
|
21
|
+
switch (event.type) {
|
|
22
|
+
case "STARTED":
|
|
23
|
+
return {
|
|
24
|
+
...state,
|
|
25
|
+
ticketKey: event.ticketKey,
|
|
26
|
+
startedAt: event.timestamp
|
|
27
|
+
};
|
|
28
|
+
case "STAGE_STARTED":
|
|
29
|
+
return { ...state, currentStage: event.stage };
|
|
30
|
+
case "STAGE_COMPLETED": {
|
|
31
|
+
const output = event.output;
|
|
32
|
+
return {
|
|
33
|
+
...state,
|
|
34
|
+
currentStage: null,
|
|
35
|
+
completedStages: [...state.completedStages, event.stage],
|
|
36
|
+
branchName: output?.branchName ?? state.branchName,
|
|
37
|
+
prNumber: output?.prNumber ?? state.prNumber
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
case "STAGE_FAILED":
|
|
41
|
+
return { ...state, currentStage: null, failedStage: event.stage };
|
|
42
|
+
case "STAGE_SKIPPED":
|
|
43
|
+
return {
|
|
44
|
+
...state,
|
|
45
|
+
completedStages: [...state.completedStages, event.stage]
|
|
46
|
+
};
|
|
47
|
+
case "CLARIFICATION_REQUESTED":
|
|
48
|
+
return { ...state, pendingClarification: true };
|
|
49
|
+
case "CLARIFICATION_RECEIVED":
|
|
50
|
+
return { ...state, pendingClarification: false };
|
|
51
|
+
case "HUMAN_APPROVAL_REQUESTED":
|
|
52
|
+
return { ...state, pendingHumanApproval: true };
|
|
53
|
+
case "HUMAN_APPROVED":
|
|
54
|
+
case "HUMAN_REJECTED":
|
|
55
|
+
return { ...state, pendingHumanApproval: false };
|
|
56
|
+
case "PIPELINE_COMPLETED":
|
|
57
|
+
return { ...state, isCompleted: true, currentStage: null };
|
|
58
|
+
case "PIPELINE_ABORTED":
|
|
59
|
+
return {
|
|
60
|
+
...state,
|
|
61
|
+
isAborted: true,
|
|
62
|
+
abortReason: event.reason,
|
|
63
|
+
currentStage: null
|
|
64
|
+
};
|
|
65
|
+
default:
|
|
66
|
+
return state;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
var StateManager = class {
|
|
70
|
+
constructor(runDir) {
|
|
71
|
+
this.runDir = runDir;
|
|
72
|
+
fs.mkdirSync(runDir, { recursive: true });
|
|
73
|
+
this.statePath = path.join(runDir, "state.json");
|
|
74
|
+
this.events = this.load();
|
|
75
|
+
}
|
|
76
|
+
runDir;
|
|
77
|
+
statePath;
|
|
78
|
+
events = [];
|
|
79
|
+
emit(event) {
|
|
80
|
+
const full = {
|
|
81
|
+
...event,
|
|
82
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
83
|
+
};
|
|
84
|
+
fs.appendFileSync(this.statePath, JSON.stringify(full) + "\n");
|
|
85
|
+
this.events.push(full);
|
|
86
|
+
}
|
|
87
|
+
get current() {
|
|
88
|
+
return this.events.reduce(applyEvent, { ...INITIAL_STATE });
|
|
89
|
+
}
|
|
90
|
+
load() {
|
|
91
|
+
if (!fs.existsSync(this.statePath)) return [];
|
|
92
|
+
return fs.readFileSync(this.statePath, "utf8").split("\n").filter(Boolean).map((line) => JSON.parse(line));
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
function getRunDir(projectName, ticketKey) {
|
|
96
|
+
return path.join(RUNS_DIR, projectName, ticketKey);
|
|
97
|
+
}
|
|
98
|
+
function getLockPath(projectName, ticketKey) {
|
|
99
|
+
return path.join(getRunDir(projectName, ticketKey), `${ticketKey}.lock`);
|
|
100
|
+
}
|
|
101
|
+
function getMemoryDir(projectName, ticketKey) {
|
|
102
|
+
return path.join(getRunDir(projectName, ticketKey), "memory");
|
|
103
|
+
}
|
|
104
|
+
function getEvents(runDir) {
|
|
105
|
+
const storePath = path.join(runDir, "state.json");
|
|
106
|
+
if (!fs.existsSync(storePath)) return [];
|
|
107
|
+
return fs.readFileSync(storePath, "utf8").split("\n").filter(Boolean).map((line) => JSON.parse(line));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// src/integrations/telegram/topic-manager.ts
|
|
111
|
+
import fs2 from "fs";
|
|
112
|
+
import path2 from "path";
|
|
113
|
+
import os2 from "os";
|
|
114
|
+
var STORE_PATH = path2.join(os2.homedir(), ".jira-acp", "telegram-topics.json");
|
|
115
|
+
function loadStore() {
|
|
116
|
+
if (!fs2.existsSync(STORE_PATH)) return {};
|
|
117
|
+
try {
|
|
118
|
+
return JSON.parse(fs2.readFileSync(STORE_PATH, "utf8"));
|
|
119
|
+
} catch {
|
|
120
|
+
return {};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function saveStore(store) {
|
|
124
|
+
fs2.mkdirSync(path2.dirname(STORE_PATH), { recursive: true });
|
|
125
|
+
fs2.writeFileSync(STORE_PATH, JSON.stringify(store, null, 2));
|
|
126
|
+
}
|
|
127
|
+
async function getOrCreateTopic(bot, chatId, ticketKey, projectName) {
|
|
128
|
+
const store = loadStore();
|
|
129
|
+
const key = `${projectName}:${ticketKey}`;
|
|
130
|
+
if (store[key] !== void 0) return store[key];
|
|
131
|
+
try {
|
|
132
|
+
const topic = await bot.api.createForumTopic(chatId, ticketKey);
|
|
133
|
+
store[key] = topic.message_thread_id;
|
|
134
|
+
saveStore(store);
|
|
135
|
+
return topic.message_thread_id;
|
|
136
|
+
} catch {
|
|
137
|
+
return void 0;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
async function archiveTopic(bot, chatId, ticketKey, projectName) {
|
|
141
|
+
const store = loadStore();
|
|
142
|
+
const key = `${projectName}:${ticketKey}`;
|
|
143
|
+
const threadId = store[key];
|
|
144
|
+
if (threadId === void 0) return;
|
|
145
|
+
try {
|
|
146
|
+
await bot.api.closeForumTopic(chatId, threadId);
|
|
147
|
+
} catch {
|
|
148
|
+
}
|
|
149
|
+
delete store[key];
|
|
150
|
+
saveStore(store);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// src/integrations/telegram/prefs.ts
|
|
154
|
+
import fs3 from "fs";
|
|
155
|
+
import path3 from "path";
|
|
156
|
+
import os3 from "os";
|
|
157
|
+
var PREFS_PATH = path3.join(os3.homedir(), ".jira-acp", "telegram-prefs.json");
|
|
158
|
+
function load() {
|
|
159
|
+
if (!fs3.existsSync(PREFS_PATH)) return { verbosity: {} };
|
|
160
|
+
try {
|
|
161
|
+
return JSON.parse(fs3.readFileSync(PREFS_PATH, "utf8"));
|
|
162
|
+
} catch {
|
|
163
|
+
return { verbosity: {} };
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function save(prefs) {
|
|
167
|
+
fs3.mkdirSync(path3.dirname(PREFS_PATH), { recursive: true });
|
|
168
|
+
fs3.writeFileSync(PREFS_PATH, JSON.stringify(prefs, null, 2));
|
|
169
|
+
}
|
|
170
|
+
function getVerbosity(chatId) {
|
|
171
|
+
const prefs = load();
|
|
172
|
+
return prefs.verbosity[String(chatId)] ?? "medium";
|
|
173
|
+
}
|
|
174
|
+
function setVerbosity(chatId, level) {
|
|
175
|
+
const prefs = load();
|
|
176
|
+
prefs.verbosity[String(chatId)] = level;
|
|
177
|
+
save(prefs);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export {
|
|
181
|
+
StateManager,
|
|
182
|
+
getRunDir,
|
|
183
|
+
getLockPath,
|
|
184
|
+
getMemoryDir,
|
|
185
|
+
getEvents,
|
|
186
|
+
getOrCreateTopic,
|
|
187
|
+
archiveTopic,
|
|
188
|
+
getVerbosity,
|
|
189
|
+
setVerbosity
|
|
190
|
+
};
|
|
191
|
+
//# sourceMappingURL=chunk-BM4R6NST.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/pipeline/state.ts","../src/integrations/telegram/topic-manager.ts","../src/integrations/telegram/prefs.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport type { StageId } from \"../config/schema.js\";\n\nconst RUNS_DIR = path.join(os.homedir(), \".jira-acp\", \"runs\");\n\n// ── Event types ───────────────────────────────────────────────────────────\n\nexport type PipelineEvent =\n | { type: \"STARTED\"; ticketKey: string; timestamp: string }\n | { type: \"STAGE_STARTED\"; stage: StageId; timestamp: string }\n | {\n type: \"STAGE_COMPLETED\";\n stage: StageId;\n output: unknown;\n timestamp: string;\n }\n | { type: \"STAGE_FAILED\"; stage: StageId; error: string; timestamp: string }\n | { type: \"STAGE_SKIPPED\"; stage: StageId; reason: string; timestamp: string }\n | { type: \"CLARIFICATION_REQUESTED\"; questions: string[]; timestamp: string }\n | { type: \"CLARIFICATION_RECEIVED\"; answers: string; timestamp: string }\n | { type: \"HUMAN_APPROVAL_REQUESTED\"; context: unknown; timestamp: string }\n | { type: \"HUMAN_APPROVED\"; timestamp: string }\n | { type: \"HUMAN_REJECTED\"; reason: string; timestamp: string }\n | { type: \"PIPELINE_COMPLETED\"; timestamp: string }\n | { type: \"PIPELINE_ABORTED\"; reason: string; timestamp: string };\n\n// ── Derived state ─────────────────────────────────────────────────────────\n\nexport interface PipelineState {\n ticketKey: string;\n currentStage: StageId | null;\n completedStages: StageId[];\n failedStage: StageId | null;\n pendingClarification: boolean;\n pendingHumanApproval: boolean;\n branchName: string | null;\n prNumber: number | null;\n isCompleted: boolean;\n isAborted: boolean;\n abortReason: string | null;\n startedAt: string | null;\n}\n\nconst INITIAL_STATE: PipelineState = {\n ticketKey: \"\",\n currentStage: null,\n completedStages: [],\n failedStage: null,\n pendingClarification: false,\n pendingHumanApproval: false,\n branchName: null,\n prNumber: null,\n isCompleted: false,\n isAborted: false,\n abortReason: null,\n startedAt: null,\n};\n\nfunction applyEvent(state: PipelineState, event: PipelineEvent): PipelineState {\n switch (event.type) {\n case \"STARTED\":\n return {\n ...state,\n ticketKey: event.ticketKey,\n startedAt: event.timestamp,\n };\n case \"STAGE_STARTED\":\n return { ...state, currentStage: event.stage };\n case \"STAGE_COMPLETED\": {\n const output = event.output as Record<string, unknown>;\n return {\n ...state,\n currentStage: null,\n completedStages: [...state.completedStages, event.stage],\n branchName: (output?.branchName as string) ?? state.branchName,\n prNumber: (output?.prNumber as number) ?? state.prNumber,\n };\n }\n case \"STAGE_FAILED\":\n return { ...state, currentStage: null, failedStage: event.stage };\n case \"STAGE_SKIPPED\":\n return {\n ...state,\n completedStages: [...state.completedStages, event.stage],\n };\n case \"CLARIFICATION_REQUESTED\":\n return { ...state, pendingClarification: true };\n case \"CLARIFICATION_RECEIVED\":\n return { ...state, pendingClarification: false };\n case \"HUMAN_APPROVAL_REQUESTED\":\n return { ...state, pendingHumanApproval: true };\n case \"HUMAN_APPROVED\":\n case \"HUMAN_REJECTED\":\n return { ...state, pendingHumanApproval: false };\n case \"PIPELINE_COMPLETED\":\n return { ...state, isCompleted: true, currentStage: null };\n case \"PIPELINE_ABORTED\":\n return {\n ...state,\n isAborted: true,\n abortReason: event.reason,\n currentStage: null,\n };\n default:\n return state;\n }\n}\n\n// Distributes Omit over union members (standard Omit<Union, K> doesn't work on discriminated unions)\ntype DistributiveOmit<T, K extends PropertyKey> = T extends unknown\n ? Omit<T, K>\n : never;\n\n// ── State manager ─────────────────────────────────────────────────────────\n\nexport class StateManager {\n private readonly statePath: string;\n private events: PipelineEvent[] = [];\n\n constructor(private readonly runDir: string) {\n fs.mkdirSync(runDir, { recursive: true });\n this.statePath = path.join(runDir, \"state.json\");\n this.events = this.load();\n }\n\n emit(event: DistributiveOmit<PipelineEvent, \"timestamp\">): void {\n const full = {\n ...event,\n timestamp: new Date().toISOString(),\n } as PipelineEvent;\n fs.appendFileSync(this.statePath, JSON.stringify(full) + \"\\n\");\n this.events.push(full);\n }\n\n get current(): PipelineState {\n return this.events.reduce(applyEvent, { ...INITIAL_STATE });\n }\n\n private load(): PipelineEvent[] {\n if (!fs.existsSync(this.statePath)) return [];\n return fs\n .readFileSync(this.statePath, \"utf8\")\n .split(\"\\n\")\n .filter(Boolean)\n .map((line) => JSON.parse(line) as PipelineEvent);\n }\n}\n\n// ── Run directory helpers ─────────────────────────────────────────────────\n// Runs live in ~/.jira-acp/runs/<projectName>/<ticketKey>/\n\nexport function getRunDir(projectName: string, ticketKey: string): string {\n return path.join(RUNS_DIR, projectName, ticketKey);\n}\n\nexport function getLockPath(projectName: string, ticketKey: string): string {\n return path.join(getRunDir(projectName, ticketKey), `${ticketKey}.lock`);\n}\n\nexport function getMemoryDir(projectName: string, ticketKey: string): string {\n return path.join(getRunDir(projectName, ticketKey), \"memory\");\n}\n\nexport function getEvents(runDir: string): PipelineEvent[] {\n const storePath = path.join(runDir, \"state.json\");\n if (!fs.existsSync(storePath)) return [];\n return fs\n .readFileSync(storePath, \"utf8\")\n .split(\"\\n\")\n .filter(Boolean)\n .map((line) => JSON.parse(line) as PipelineEvent);\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport type { Bot } from \"grammy\";\n\nconst STORE_PATH = path.join(os.homedir(), \".jira-acp\", \"telegram-topics.json\");\n\ntype TopicStore = Record<string, number>; // \"projectName:ticketKey\" => message_thread_id\n\nfunction loadStore(): TopicStore {\n if (!fs.existsSync(STORE_PATH)) return {};\n try {\n return JSON.parse(fs.readFileSync(STORE_PATH, \"utf8\")) as TopicStore;\n } catch {\n return {};\n }\n}\n\nfunction saveStore(store: TopicStore): void {\n fs.mkdirSync(path.dirname(STORE_PATH), { recursive: true });\n fs.writeFileSync(STORE_PATH, JSON.stringify(store, null, 2));\n}\n\nexport async function getOrCreateTopic(\n bot: Bot,\n chatId: number | string,\n ticketKey: string,\n projectName: string,\n): Promise<number | undefined> {\n const store = loadStore();\n const key = `${projectName}:${ticketKey}`;\n\n if (store[key] !== undefined) return store[key];\n\n try {\n const topic = await bot.api.createForumTopic(chatId, ticketKey);\n store[key] = topic.message_thread_id;\n saveStore(store);\n return topic.message_thread_id;\n } catch {\n // Chat is not a forum supergroup — topic creation not supported\n return undefined;\n }\n}\n\n/** Get or create a persistent \"🔔 Notifications\" topic for system-level messages. */\nexport async function getOrCreateSystemTopic(\n bot: Bot,\n chatId: number | string,\n projectName: string,\n): Promise<number | undefined> {\n const store = loadStore();\n const key = `${projectName}:__notifications__`;\n\n if (store[key] !== undefined) return store[key];\n\n try {\n const topic = await bot.api.createForumTopic(chatId, \"🔔 Notifications\", {\n icon_color: 0x6fb9f0, // light blue\n });\n store[key] = topic.message_thread_id;\n saveStore(store);\n return topic.message_thread_id;\n } catch {\n return undefined;\n }\n}\n\nexport async function archiveTopic(\n bot: Bot,\n chatId: number | string,\n ticketKey: string,\n projectName: string,\n): Promise<void> {\n const store = loadStore();\n const key = `${projectName}:${ticketKey}`;\n const threadId = store[key];\n if (threadId === undefined) return;\n\n try {\n await bot.api.closeForumTopic(chatId, threadId);\n } catch {\n // Topic may already be closed or deleted\n }\n\n delete store[key];\n saveStore(store);\n}\n","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":"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","names":["fs","path","os","fs","path","os"]}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/utils/lock.ts
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
import path from "path";
|
|
6
|
+
async function acquireLock(lockPath, stage = "init") {
|
|
7
|
+
const dir = path.dirname(lockPath);
|
|
8
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
9
|
+
const data = {
|
|
10
|
+
pid: process.pid,
|
|
11
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12
|
+
stage
|
|
13
|
+
};
|
|
14
|
+
try {
|
|
15
|
+
fs.writeFileSync(lockPath, JSON.stringify(data), { flag: "wx" });
|
|
16
|
+
} catch (err) {
|
|
17
|
+
if (isNodeError(err) && err.code === "EEXIST") {
|
|
18
|
+
const existing = readLockData(lockPath);
|
|
19
|
+
if (existing && isProcessAlive(existing.pid)) {
|
|
20
|
+
throw new Error(
|
|
21
|
+
`Pipeline already running (PID ${existing.pid}, stage: ${existing.stage})`
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
fs.writeFileSync(lockPath, JSON.stringify(data));
|
|
25
|
+
} else {
|
|
26
|
+
throw err;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const cleanup = () => {
|
|
30
|
+
tryUnlink(lockPath);
|
|
31
|
+
};
|
|
32
|
+
process.once("exit", cleanup);
|
|
33
|
+
process.once("SIGINT", () => {
|
|
34
|
+
cleanup();
|
|
35
|
+
process.exit(130);
|
|
36
|
+
});
|
|
37
|
+
process.once("SIGTERM", () => {
|
|
38
|
+
cleanup();
|
|
39
|
+
process.exit(143);
|
|
40
|
+
});
|
|
41
|
+
return {
|
|
42
|
+
release() {
|
|
43
|
+
tryUnlink(lockPath);
|
|
44
|
+
process.removeListener("exit", cleanup);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function readLockData(lockPath) {
|
|
49
|
+
try {
|
|
50
|
+
return JSON.parse(fs.readFileSync(lockPath, "utf8"));
|
|
51
|
+
} catch {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function isProcessAlive(pid) {
|
|
56
|
+
try {
|
|
57
|
+
process.kill(pid, 0);
|
|
58
|
+
return true;
|
|
59
|
+
} catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function tryUnlink(p) {
|
|
64
|
+
try {
|
|
65
|
+
fs.unlinkSync(p);
|
|
66
|
+
} catch {
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function isNodeError(err) {
|
|
70
|
+
return err instanceof Error && "code" in err;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export {
|
|
74
|
+
acquireLock,
|
|
75
|
+
readLockData
|
|
76
|
+
};
|
|
77
|
+
//# sourceMappingURL=chunk-FLPIU2QO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/lock.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\n\nexport interface Lock {\n release(): void;\n}\n\ninterface LockData {\n pid: number;\n startedAt: string;\n stage: string;\n}\n\nexport async function acquireLock(\n lockPath: string,\n stage = \"init\",\n): Promise<Lock> {\n const dir = path.dirname(lockPath);\n fs.mkdirSync(dir, { recursive: true });\n\n const data: LockData = {\n pid: process.pid,\n startedAt: new Date().toISOString(),\n stage,\n };\n\n try {\n fs.writeFileSync(lockPath, JSON.stringify(data), { flag: \"wx\" }); // O_EXCL — fail if exists\n } catch (err: unknown) {\n if (isNodeError(err) && err.code === \"EEXIST\") {\n const existing = readLockData(lockPath);\n if (existing && isProcessAlive(existing.pid)) {\n throw new Error(\n `Pipeline already running (PID ${existing.pid}, stage: ${existing.stage})`,\n );\n }\n // Dead process — steal lock\n fs.writeFileSync(lockPath, JSON.stringify(data));\n } else {\n throw err;\n }\n }\n\n // Release on exit\n const cleanup = (): void => {\n tryUnlink(lockPath);\n };\n process.once(\"exit\", cleanup);\n process.once(\"SIGINT\", () => {\n cleanup();\n process.exit(130);\n });\n process.once(\"SIGTERM\", () => {\n cleanup();\n process.exit(143);\n });\n\n return {\n release() {\n tryUnlink(lockPath);\n process.removeListener(\"exit\", cleanup);\n },\n };\n}\n\nexport function readLockData(lockPath: string): LockData | null {\n try {\n return JSON.parse(fs.readFileSync(lockPath, \"utf8\")) as LockData;\n } catch {\n return null;\n }\n}\n\nfunction isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction tryUnlink(p: string): void {\n try {\n fs.unlinkSync(p);\n } catch {\n /* ignore */\n }\n}\n\nfunction isNodeError(err: unknown): err is NodeJS.ErrnoException {\n return err instanceof Error && \"code\" in err;\n}\n"],"mappings":";;;AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AAYjB,eAAsB,YACpB,UACA,QAAQ,QACO;AACf,QAAM,MAAM,KAAK,QAAQ,QAAQ;AACjC,KAAG,UAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAErC,QAAM,OAAiB;AAAA,IACrB,KAAK,QAAQ;AAAA,IACb,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC;AAAA,EACF;AAEA,MAAI;AACF,OAAG,cAAc,UAAU,KAAK,UAAU,IAAI,GAAG,EAAE,MAAM,KAAK,CAAC;AAAA,EACjE,SAAS,KAAc;AACrB,QAAI,YAAY,GAAG,KAAK,IAAI,SAAS,UAAU;AAC7C,YAAM,WAAW,aAAa,QAAQ;AACtC,UAAI,YAAY,eAAe,SAAS,GAAG,GAAG;AAC5C,cAAM,IAAI;AAAA,UACR,iCAAiC,SAAS,GAAG,YAAY,SAAS,KAAK;AAAA,QACzE;AAAA,MACF;AAEA,SAAG,cAAc,UAAU,KAAK,UAAU,IAAI,CAAC;AAAA,IACjD,OAAO;AACL,YAAM;AAAA,IACR;AAAA,EACF;AAGA,QAAM,UAAU,MAAY;AAC1B,cAAU,QAAQ;AAAA,EACpB;AACA,UAAQ,KAAK,QAAQ,OAAO;AAC5B,UAAQ,KAAK,UAAU,MAAM;AAC3B,YAAQ;AACR,YAAQ,KAAK,GAAG;AAAA,EAClB,CAAC;AACD,UAAQ,KAAK,WAAW,MAAM;AAC5B,YAAQ;AACR,YAAQ,KAAK,GAAG;AAAA,EAClB,CAAC;AAED,SAAO;AAAA,IACL,UAAU;AACR,gBAAU,QAAQ;AAClB,cAAQ,eAAe,QAAQ,OAAO;AAAA,IACxC;AAAA,EACF;AACF;AAEO,SAAS,aAAa,UAAmC;AAC9D,MAAI;AACF,WAAO,KAAK,MAAM,GAAG,aAAa,UAAU,MAAM,CAAC;AAAA,EACrD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,eAAe,KAAsB;AAC5C,MAAI;AACF,YAAQ,KAAK,KAAK,CAAC;AACnB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,UAAU,GAAiB;AAClC,MAAI;AACF,OAAG,WAAW,CAAC;AAAA,EACjB,QAAQ;AAAA,EAER;AACF;AAEA,SAAS,YAAY,KAA4C;AAC/D,SAAO,eAAe,SAAS,UAAU;AAC3C;","names":[]}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/memory/claude-md.ts
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
import path from "path";
|
|
6
|
+
async function generateClaudeMd(projectDir, config) {
|
|
7
|
+
const claudeDir = path.join(projectDir, ".claude");
|
|
8
|
+
fs.mkdirSync(claudeDir, { recursive: true });
|
|
9
|
+
const stack = detectStack(projectDir);
|
|
10
|
+
const upper = config.jira.instance.toUpperCase();
|
|
11
|
+
const content = `# Project: ${config.name}
|
|
12
|
+
|
|
13
|
+
## Architecture Overview
|
|
14
|
+
This project uses an AI-powered pipeline managed by jiraACP.
|
|
15
|
+
Workspace: ${projectDir}
|
|
16
|
+
|
|
17
|
+
## Tech Stack
|
|
18
|
+
${stack}
|
|
19
|
+
|
|
20
|
+
## Jira Integration
|
|
21
|
+
- Instance: ${config.jira.instance}
|
|
22
|
+
- Project key: ${config.jira.projectKey}
|
|
23
|
+
- Assignees: ${config.jira.assignees.join(", ")}
|
|
24
|
+
|
|
25
|
+
## Available MCP Tools
|
|
26
|
+
- jira_get_tasks \u2014 fetch assigned tickets
|
|
27
|
+
- jira_get_ticket \u2014 get full ticket details
|
|
28
|
+
- jira_transition_ticket \u2014 change ticket status
|
|
29
|
+
- jira_add_comment \u2014 add comment to ticket
|
|
30
|
+
- jira_reassign \u2014 reassign ticket to another user
|
|
31
|
+
|
|
32
|
+
## Workflow Rules
|
|
33
|
+
- Always create a feature branch before any commits
|
|
34
|
+
- Branch naming: feature/{TICKET-KEY}-{short-description}
|
|
35
|
+
- Commit message format: "{TICKET-KEY}: {description}"
|
|
36
|
+
- Never modify .env files or commit secrets
|
|
37
|
+
- Never force-push to ${config.github.defaultBranch ?? "main"}
|
|
38
|
+
- All changes through PR \u2014 never commit directly to main
|
|
39
|
+
|
|
40
|
+
## GitHub
|
|
41
|
+
- Owner: ${config.github.owner}
|
|
42
|
+
- Repo: ${config.github.repo}
|
|
43
|
+
- Base branch: ${config.github.defaultBranch ?? "main"}
|
|
44
|
+
|
|
45
|
+
## Required Env Vars
|
|
46
|
+
- JIRA_${upper}_URL, JIRA_${upper}_TOKEN, JIRA_${upper}_EMAIL
|
|
47
|
+
- GITHUB_TOKEN
|
|
48
|
+
- ANTHROPIC_API_KEY
|
|
49
|
+
`;
|
|
50
|
+
fs.writeFileSync(path.join(claudeDir, "CLAUDE.md"), content);
|
|
51
|
+
}
|
|
52
|
+
function detectStack(projectDir) {
|
|
53
|
+
const lines = [];
|
|
54
|
+
if (fs.existsSync(path.join(projectDir, "package.json"))) {
|
|
55
|
+
try {
|
|
56
|
+
const pkg = JSON.parse(
|
|
57
|
+
fs.readFileSync(path.join(projectDir, "package.json"), "utf8")
|
|
58
|
+
);
|
|
59
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
60
|
+
if (deps["next"]) lines.push("- Framework: Next.js");
|
|
61
|
+
else if (deps["@nestjs/core"]) lines.push("- Framework: NestJS");
|
|
62
|
+
else if (deps["express"]) lines.push("- Framework: Express");
|
|
63
|
+
if (deps["typescript"] || fs.existsSync(path.join(projectDir, "tsconfig.json"))) {
|
|
64
|
+
lines.push("- Language: TypeScript");
|
|
65
|
+
} else {
|
|
66
|
+
lines.push("- Language: JavaScript");
|
|
67
|
+
}
|
|
68
|
+
if (deps["prisma"] || deps["@prisma/client"]) lines.push("- ORM: Prisma");
|
|
69
|
+
if (deps["typeorm"]) lines.push("- ORM: TypeORM");
|
|
70
|
+
} catch {
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (fs.existsSync(path.join(projectDir, "pyproject.toml")) || fs.existsSync(path.join(projectDir, "requirements.txt"))) {
|
|
74
|
+
lines.push("- Language: Python");
|
|
75
|
+
}
|
|
76
|
+
if (fs.existsSync(path.join(projectDir, "go.mod")))
|
|
77
|
+
lines.push("- Language: Go");
|
|
78
|
+
if (fs.existsSync(path.join(projectDir, "Cargo.toml")))
|
|
79
|
+
lines.push("- Language: Rust");
|
|
80
|
+
return lines.length > 0 ? lines.join("\n") : "- (Auto-detection: update manually)";
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export {
|
|
84
|
+
generateClaudeMd
|
|
85
|
+
};
|
|
86
|
+
//# sourceMappingURL=chunk-H7YXX4UA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/memory/claude-md.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { ProjectConfig } from \"../config/schema.js\";\n\nexport async function generateClaudeMd(\n projectDir: string,\n config: ProjectConfig,\n): Promise<void> {\n const claudeDir = path.join(projectDir, \".claude\");\n fs.mkdirSync(claudeDir, { recursive: true });\n\n const stack = detectStack(projectDir);\n const upper = config.jira.instance.toUpperCase();\n\n const content = `# Project: ${config.name}\n\n## Architecture Overview\nThis project uses an AI-powered pipeline managed by jiraACP.\nWorkspace: ${projectDir}\n\n## Tech Stack\n${stack}\n\n## Jira Integration\n- Instance: ${config.jira.instance}\n- Project key: ${config.jira.projectKey}\n- Assignees: ${config.jira.assignees.join(\", \")}\n\n## Available MCP Tools\n- jira_get_tasks — fetch assigned tickets\n- jira_get_ticket — get full ticket details\n- jira_transition_ticket — change ticket status\n- jira_add_comment — add comment to ticket\n- jira_reassign — reassign ticket to another user\n\n## Workflow Rules\n- Always create a feature branch before any commits\n- Branch naming: feature/{TICKET-KEY}-{short-description}\n- Commit message format: \"{TICKET-KEY}: {description}\"\n- Never modify .env files or commit secrets\n- Never force-push to ${config.github.defaultBranch ?? \"main\"}\n- All changes through PR — never commit directly to main\n\n## GitHub\n- Owner: ${config.github.owner}\n- Repo: ${config.github.repo}\n- Base branch: ${config.github.defaultBranch ?? \"main\"}\n\n## Required Env Vars\n- JIRA_${upper}_URL, JIRA_${upper}_TOKEN, JIRA_${upper}_EMAIL\n- GITHUB_TOKEN\n- ANTHROPIC_API_KEY\n`;\n\n fs.writeFileSync(path.join(claudeDir, \"CLAUDE.md\"), content);\n}\n\nfunction detectStack(projectDir: string): string {\n const lines: string[] = [];\n\n if (fs.existsSync(path.join(projectDir, \"package.json\"))) {\n try {\n const pkg = JSON.parse(\n fs.readFileSync(path.join(projectDir, \"package.json\"), \"utf8\"),\n ) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n const deps = { ...pkg.dependencies, ...pkg.devDependencies };\n if (deps[\"next\"]) lines.push(\"- Framework: Next.js\");\n else if (deps[\"@nestjs/core\"]) lines.push(\"- Framework: NestJS\");\n else if (deps[\"express\"]) lines.push(\"- Framework: Express\");\n if (\n deps[\"typescript\"] ||\n fs.existsSync(path.join(projectDir, \"tsconfig.json\"))\n ) {\n lines.push(\"- Language: TypeScript\");\n } else {\n lines.push(\"- Language: JavaScript\");\n }\n if (deps[\"prisma\"] || deps[\"@prisma/client\"]) lines.push(\"- ORM: Prisma\");\n if (deps[\"typeorm\"]) lines.push(\"- ORM: TypeORM\");\n } catch {\n /* ignore */\n }\n }\n\n if (\n fs.existsSync(path.join(projectDir, \"pyproject.toml\")) ||\n fs.existsSync(path.join(projectDir, \"requirements.txt\"))\n ) {\n lines.push(\"- Language: Python\");\n }\n\n if (fs.existsSync(path.join(projectDir, \"go.mod\")))\n lines.push(\"- Language: Go\");\n if (fs.existsSync(path.join(projectDir, \"Cargo.toml\")))\n lines.push(\"- Language: Rust\");\n\n return lines.length > 0\n ? lines.join(\"\\n\")\n : \"- (Auto-detection: update manually)\";\n}\n"],"mappings":";;;AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AAGjB,eAAsB,iBACpB,YACA,QACe;AACf,QAAM,YAAY,KAAK,KAAK,YAAY,SAAS;AACjD,KAAG,UAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAE3C,QAAM,QAAQ,YAAY,UAAU;AACpC,QAAM,QAAQ,OAAO,KAAK,SAAS,YAAY;AAE/C,QAAM,UAAU,cAAc,OAAO,IAAI;AAAA;AAAA;AAAA;AAAA,aAI9B,UAAU;AAAA;AAAA;AAAA,EAGrB,KAAK;AAAA;AAAA;AAAA,cAGO,OAAO,KAAK,QAAQ;AAAA,iBACjB,OAAO,KAAK,UAAU;AAAA,eACxB,OAAO,KAAK,UAAU,KAAK,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAcvB,OAAO,OAAO,iBAAiB,MAAM;AAAA;AAAA;AAAA;AAAA,WAIlD,OAAO,OAAO,KAAK;AAAA,UACpB,OAAO,OAAO,IAAI;AAAA,iBACX,OAAO,OAAO,iBAAiB,MAAM;AAAA;AAAA;AAAA,SAG7C,KAAK,cAAc,KAAK,gBAAgB,KAAK;AAAA;AAAA;AAAA;AAKpD,KAAG,cAAc,KAAK,KAAK,WAAW,WAAW,GAAG,OAAO;AAC7D;AAEA,SAAS,YAAY,YAA4B;AAC/C,QAAM,QAAkB,CAAC;AAEzB,MAAI,GAAG,WAAW,KAAK,KAAK,YAAY,cAAc,CAAC,GAAG;AACxD,QAAI;AACF,YAAM,MAAM,KAAK;AAAA,QACf,GAAG,aAAa,KAAK,KAAK,YAAY,cAAc,GAAG,MAAM;AAAA,MAC/D;AAIA,YAAM,OAAO,EAAE,GAAG,IAAI,cAAc,GAAG,IAAI,gBAAgB;AAC3D,UAAI,KAAK,MAAM,EAAG,OAAM,KAAK,sBAAsB;AAAA,eAC1C,KAAK,cAAc,EAAG,OAAM,KAAK,qBAAqB;AAAA,eACtD,KAAK,SAAS,EAAG,OAAM,KAAK,sBAAsB;AAC3D,UACE,KAAK,YAAY,KACjB,GAAG,WAAW,KAAK,KAAK,YAAY,eAAe,CAAC,GACpD;AACA,cAAM,KAAK,wBAAwB;AAAA,MACrC,OAAO;AACL,cAAM,KAAK,wBAAwB;AAAA,MACrC;AACA,UAAI,KAAK,QAAQ,KAAK,KAAK,gBAAgB,EAAG,OAAM,KAAK,eAAe;AACxE,UAAI,KAAK,SAAS,EAAG,OAAM,KAAK,gBAAgB;AAAA,IAClD,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,MACE,GAAG,WAAW,KAAK,KAAK,YAAY,gBAAgB,CAAC,KACrD,GAAG,WAAW,KAAK,KAAK,YAAY,kBAAkB,CAAC,GACvD;AACA,UAAM,KAAK,oBAAoB;AAAA,EACjC;AAEA,MAAI,GAAG,WAAW,KAAK,KAAK,YAAY,QAAQ,CAAC;AAC/C,UAAM,KAAK,gBAAgB;AAC7B,MAAI,GAAG,WAAW,KAAK,KAAK,YAAY,YAAY,CAAC;AACnD,UAAM,KAAK,kBAAkB;AAE/B,SAAO,MAAM,SAAS,IAClB,MAAM,KAAK,IAAI,IACf;AACN;","names":[]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/utils/logger.ts
|
|
4
|
+
import pino from "pino";
|
|
5
|
+
var logger = pino({
|
|
6
|
+
transport: process.stdout.isTTY ? {
|
|
7
|
+
target: "pino-pretty",
|
|
8
|
+
options: { colorize: true, ignore: "pid,hostname" }
|
|
9
|
+
} : void 0,
|
|
10
|
+
level: process.env["LOG_LEVEL"] ?? "info"
|
|
11
|
+
});
|
|
12
|
+
function createLogger(name) {
|
|
13
|
+
return logger.child({ name });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
createLogger
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=chunk-IT74N3UH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/logger.ts"],"sourcesContent":["import pino from \"pino\";\n\nexport const logger = pino({\n transport: process.stdout.isTTY\n ? {\n target: \"pino-pretty\",\n options: { colorize: true, ignore: \"pid,hostname\" },\n }\n : undefined,\n level: process.env[\"LOG_LEVEL\"] ?? \"info\",\n});\n\nexport function createLogger(name: string): pino.Logger {\n return logger.child({ name });\n}\n"],"mappings":";;;AAAA,OAAO,UAAU;AAEV,IAAM,SAAS,KAAK;AAAA,EACzB,WAAW,QAAQ,OAAO,QACtB;AAAA,IACE,QAAQ;AAAA,IACR,SAAS,EAAE,UAAU,MAAM,QAAQ,eAAe;AAAA,EACpD,IACA;AAAA,EACJ,OAAO,QAAQ,IAAI,WAAW,KAAK;AACrC,CAAC;AAEM,SAAS,aAAa,MAA2B;AACtD,SAAO,OAAO,MAAM,EAAE,KAAK,CAAC;AAC9B;","names":[]}
|