panopticon-cli 0.4.28 → 0.4.31

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 (51) hide show
  1. package/dist/{agents-ND4NKCK2.js → agents-GQDAKTEQ.js} +5 -4
  2. package/dist/{chunk-SIAUVHVO.js → chunk-3XAB4IXF.js} +4 -2
  3. package/dist/{chunk-SIAUVHVO.js.map → chunk-3XAB4IXF.js.map} +1 -1
  4. package/dist/chunk-ELK6Q7QI.js +545 -0
  5. package/dist/chunk-ELK6Q7QI.js.map +1 -0
  6. package/dist/{chunk-ZLB6G4NW.js → chunk-HNEWTIR3.js} +41 -9
  7. package/dist/chunk-HNEWTIR3.js.map +1 -0
  8. package/dist/chunk-LYSBSZYV.js +1523 -0
  9. package/dist/chunk-LYSBSZYV.js.map +1 -0
  10. package/dist/{chunk-4KNEZGKZ.js → chunk-TMXN7THF.js} +45 -24
  11. package/dist/chunk-TMXN7THF.js.map +1 -0
  12. package/dist/{chunk-ON5NIBGW.js → chunk-VIWUCJ4V.js} +37 -8
  13. package/dist/chunk-VIWUCJ4V.js.map +1 -0
  14. package/dist/{chunk-VTMXR7JF.js → chunk-VU4FLXV5.js} +47 -40
  15. package/dist/{chunk-VTMXR7JF.js.map → chunk-VU4FLXV5.js.map} +1 -1
  16. package/dist/cli/index.js +153 -86
  17. package/dist/cli/index.js.map +1 -1
  18. package/dist/{config-QWTS63TU.js → config-BOAMSKTF.js} +4 -2
  19. package/dist/dashboard/public/assets/{index--VPaQ2VU.css → index-C7X6LP5Z.css} +1 -1
  20. package/dist/dashboard/public/assets/{index-GYQaqwVS.js → index-izWbAt7V.js} +152 -152
  21. package/dist/dashboard/public/index.html +2 -2
  22. package/dist/dashboard/server.js +94706 -24017
  23. package/dist/feedback-writer-AAKF5BTK.js +111 -0
  24. package/dist/feedback-writer-AAKF5BTK.js.map +1 -0
  25. package/dist/index.d.ts +1 -0
  26. package/dist/index.js +16 -14
  27. package/dist/index.js.map +1 -1
  28. package/dist/{remote-workspace-FNXLMNBG.js → remote-workspace-2G6V2KNP.js} +7 -5
  29. package/dist/{remote-workspace-FNXLMNBG.js.map → remote-workspace-2G6V2KNP.js.map} +1 -1
  30. package/dist/{specialist-context-WXO3FKIB.js → specialist-context-6SE5VRRC.js} +3 -3
  31. package/dist/{specialist-logs-SJWLETJT.js → specialist-logs-EXLOQHQ2.js} +3 -3
  32. package/dist/{specialists-5YJIDRW6.js → specialists-BRUHPAXE.js} +3 -3
  33. package/dist/{traefik-7OLLXUD7.js → traefik-CUJM6K5Z.js} +3 -3
  34. package/package.json +3 -2
  35. package/scripts/record-cost-event.js +243 -79
  36. package/scripts/record-cost-event.ts +128 -68
  37. package/templates/traefik/docker-compose.yml +7 -4
  38. package/templates/traefik/dynamic/panopticon.yml.template +3 -1
  39. package/dist/chunk-46DPNFMW.js +0 -278
  40. package/dist/chunk-46DPNFMW.js.map +0 -1
  41. package/dist/chunk-4KNEZGKZ.js.map +0 -1
  42. package/dist/chunk-ON5NIBGW.js.map +0 -1
  43. package/dist/chunk-SUMIHS2B.js +0 -1714
  44. package/dist/chunk-SUMIHS2B.js.map +0 -1
  45. package/dist/chunk-ZLB6G4NW.js.map +0 -1
  46. /package/dist/{agents-ND4NKCK2.js.map → agents-GQDAKTEQ.js.map} +0 -0
  47. /package/dist/{config-QWTS63TU.js.map → config-BOAMSKTF.js.map} +0 -0
  48. /package/dist/{specialist-context-WXO3FKIB.js.map → specialist-context-6SE5VRRC.js.map} +0 -0
  49. /package/dist/{specialist-logs-SJWLETJT.js.map → specialist-logs-EXLOQHQ2.js.map} +0 -0
  50. /package/dist/{specialists-5YJIDRW6.js.map → specialists-BRUHPAXE.js.map} +0 -0
  51. /package/dist/{traefik-7OLLXUD7.js.map → traefik-CUJM6K5Z.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/settings.ts","../src/lib/providers.ts","../src/lib/tracker/interface.ts","../src/lib/tracker/linear.ts","../src/lib/tracker/github.ts","../src/lib/tracker/gitlab.ts","../src/lib/tracker/rally-api.ts","../src/lib/tracker/rally.ts","../src/lib/tracker/factory.ts"],"sourcesContent":["import { readFileSync, writeFileSync, existsSync } from 'fs';\nimport { SETTINGS_FILE } from './paths.js';\n\n// Model identifiers\nexport type AnthropicModel = 'claude-opus-4-6' | 'claude-sonnet-4-5' | 'claude-haiku-4-5';\nexport type OpenAIModel = 'gpt-5.2-codex' | 'o3-deep-research' | 'gpt-4o' | 'gpt-4o-mini';\nexport type GoogleModel = 'gemini-3-pro-preview' | 'gemini-3-flash-preview' | 'gemini-2.5-pro' | 'gemini-2.5-flash';\nexport type ZAIModel = 'glm-4.7' | 'glm-4.7-flash';\nexport type KimiModel = 'kimi-k2' | 'kimi-k2.5';\nexport type ModelId = AnthropicModel | OpenAIModel | GoogleModel | ZAIModel | KimiModel;\n\n// Task complexity levels\nexport type ComplexityLevel = 'trivial' | 'simple' | 'medium' | 'complex' | 'expert';\n\n// Specialist agent types\nexport interface SpecialistModels {\n review_agent: ModelId;\n test_agent: ModelId;\n merge_agent: ModelId;\n}\n\n// Complexity-based model mapping\nexport type ComplexityModels = {\n [K in ComplexityLevel]: ModelId;\n};\n\n// All model configuration\nexport interface ModelsConfig {\n specialists: SpecialistModels;\n planning_agent: ModelId;\n status_review: ModelId;\n complexity: ComplexityModels;\n}\n\n// API keys for external providers\nexport interface ApiKeysConfig {\n openai?: string;\n google?: string;\n zai?: string;\n kimi?: string;\n}\n\n// Complete settings structure\nexport interface SettingsConfig {\n models: ModelsConfig;\n api_keys: ApiKeysConfig;\n}\n\n// Default settings - match optimal defaults from settings-api.ts\nconst DEFAULT_SETTINGS: SettingsConfig = {\n models: {\n specialists: {\n review_agent: 'claude-opus-4-6',\n test_agent: 'claude-sonnet-4-5',\n merge_agent: 'claude-sonnet-4-5',\n },\n planning_agent: 'claude-opus-4-6',\n status_review: 'claude-opus-4-6',\n complexity: {\n trivial: 'claude-haiku-4-5',\n simple: 'claude-haiku-4-5',\n medium: 'kimi-k2.5',\n complex: 'kimi-k2.5',\n expert: 'claude-opus-4-6',\n },\n },\n api_keys: {},\n};\n\n/**\n * Deep merge utility that recursively merges objects.\n * - Recursively merges nested objects\n * - User values take precedence over defaults\n */\nfunction deepMerge<T extends object>(defaults: T, overrides: Partial<T>): T {\n const result = { ...defaults };\n\n for (const key of Object.keys(overrides) as (keyof T)[]) {\n const defaultVal = defaults[key];\n const overrideVal = overrides[key];\n\n // Skip undefined values in overrides\n if (overrideVal === undefined) continue;\n\n // Deep merge if both values are non-array objects\n if (\n typeof defaultVal === 'object' &&\n defaultVal !== null &&\n !Array.isArray(defaultVal) &&\n typeof overrideVal === 'object' &&\n overrideVal !== null &&\n !Array.isArray(overrideVal)\n ) {\n result[key] = deepMerge(defaultVal, overrideVal as any);\n } else {\n // For primitives or null - override wins\n result[key] = overrideVal as T[keyof T];\n }\n }\n\n return result;\n}\n\n/**\n * Load settings from ~/.panopticon/settings.json\n * Returns default settings if file doesn't exist or is invalid\n * Also loads API keys from environment variables as fallback\n */\nexport function loadSettings(): SettingsConfig {\n let settings: SettingsConfig;\n\n if (!existsSync(SETTINGS_FILE)) {\n settings = getDefaultSettings();\n } else {\n try {\n const content = readFileSync(SETTINGS_FILE, 'utf8');\n const parsed = JSON.parse(content) as Partial<SettingsConfig>;\n settings = deepMerge(DEFAULT_SETTINGS, parsed);\n } catch (error) {\n console.error('Warning: Failed to parse settings.json, using defaults');\n settings = getDefaultSettings();\n }\n }\n\n // Load API keys from environment variables as fallback\n // This allows using ~/.panopticon.env for API keys\n const envApiKeys: ApiKeysConfig = {};\n if (process.env.OPENAI_API_KEY) envApiKeys.openai = process.env.OPENAI_API_KEY;\n if (process.env.GOOGLE_API_KEY) envApiKeys.google = process.env.GOOGLE_API_KEY;\n if (process.env.ZAI_API_KEY) envApiKeys.zai = process.env.ZAI_API_KEY;\n if (process.env.KIMI_API_KEY) envApiKeys.kimi = process.env.KIMI_API_KEY;\n\n // Merge env vars as fallback (settings.json takes precedence)\n settings.api_keys = {\n ...envApiKeys,\n ...settings.api_keys,\n };\n\n return settings;\n}\n\n/**\n * Save settings to ~/.panopticon/settings.json\n * Writes with pretty formatting (2-space indent)\n */\nexport function saveSettings(settings: SettingsConfig): void {\n const content = JSON.stringify(settings, null, 2);\n writeFileSync(SETTINGS_FILE, content, 'utf8');\n}\n\n/**\n * Validate settings structure and model IDs\n * Returns error message if invalid, null if valid\n */\nexport function validateSettings(settings: SettingsConfig): string | null {\n // Validate models structure\n if (!settings.models) {\n return 'Missing models configuration';\n }\n\n // Validate specialists\n if (!settings.models.specialists) {\n return 'Missing specialists configuration';\n }\n const specialists = settings.models.specialists;\n if (!specialists.review_agent || !specialists.test_agent || !specialists.merge_agent) {\n return 'Missing specialist agent model configuration';\n }\n\n // Validate planning agent\n if (!settings.models.planning_agent) {\n return 'Missing planning_agent configuration';\n }\n\n // Validate complexity levels\n if (!settings.models.complexity) {\n return 'Missing complexity configuration';\n }\n const complexity = settings.models.complexity;\n const requiredLevels: ComplexityLevel[] = ['trivial', 'simple', 'medium', 'complex', 'expert'];\n for (const level of requiredLevels) {\n if (!complexity[level]) {\n return `Missing complexity level: ${level}`;\n }\n }\n\n // Validate api_keys structure (optional keys)\n if (!settings.api_keys) {\n return 'Missing api_keys configuration';\n }\n\n return null;\n}\n\n/**\n * Get a deep copy of the default settings\n */\nexport function getDefaultSettings(): SettingsConfig {\n return JSON.parse(JSON.stringify(DEFAULT_SETTINGS));\n}\n\n/**\n * Get available models for a provider based on configured API keys\n * Returns empty array if provider API key is not configured\n */\nexport function getAvailableModels(settings: SettingsConfig): {\n anthropic: AnthropicModel[];\n openai: OpenAIModel[];\n google: GoogleModel[];\n zai: ZAIModel[];\n kimi: KimiModel[];\n} {\n const anthropicModels: AnthropicModel[] = [\n 'claude-opus-4-6',\n 'claude-sonnet-4-5',\n 'claude-haiku-4-5',\n ];\n\n const openaiModels: OpenAIModel[] = settings.api_keys.openai\n ? ['gpt-5.2-codex', 'o3-deep-research', 'gpt-4o', 'gpt-4o-mini']\n : [];\n\n const googleModels: GoogleModel[] = settings.api_keys.google\n ? ['gemini-3-pro-preview', 'gemini-3-flash-preview']\n : [];\n\n const zaiModels: ZAIModel[] = settings.api_keys.zai\n ? ['glm-4.7', 'glm-4.7-flash']\n : [];\n\n const kimiModels: KimiModel[] = settings.api_keys.kimi\n ? ['kimi-k2', 'kimi-k2.5']\n : [];\n\n return {\n anthropic: anthropicModels,\n openai: openaiModels,\n google: googleModels,\n zai: zaiModels,\n kimi: kimiModels,\n };\n}\n\n/**\n * Check if a model ID is an Anthropic model\n * Anthropic models can be run directly with `claude` CLI\n */\nexport function isAnthropicModel(modelId: ModelId | string): boolean {\n return modelId.startsWith('claude-');\n}\n\n/**\n * Get the Claude CLI model flag for an Anthropic model\n * Maps our model IDs to Claude's expected format\n */\nexport function getClaudeModelFlag(modelId: ModelId | string): string {\n const modelMap: Record<string, string> = {\n 'claude-opus-4-6': 'opus',\n 'claude-sonnet-4-5': 'sonnet',\n 'claude-haiku-4-5': 'haiku',\n };\n return modelMap[modelId] || 'sonnet';\n}\n\n/**\n * Get the command to run an agent with a specific model\n * Returns 'claude' for Anthropic models, 'claude-code-router' for others\n */\nexport function getAgentCommand(modelId: ModelId | string): { command: string; args: string[] } {\n if (isAnthropicModel(modelId)) {\n return {\n command: 'claude',\n args: ['--model', getClaudeModelFlag(modelId)],\n };\n }\n // Non-Anthropic models require the router\n return {\n command: 'claude-code-router',\n args: [],\n };\n}\n","/**\r\n * Provider Configuration and Compatibility\r\n *\r\n * Defines which LLM providers are compatible with Claude Code's API format.\r\n * - Direct providers: Implement Anthropic-compatible API (no router needed)\r\n * - Router providers: Require claude-code-router for API translation\r\n */\r\n\r\nimport type { ModelId, AnthropicModel, OpenAIModel, GoogleModel, ZAIModel } from './settings.js';\r\n\r\nexport type ProviderName = 'anthropic' | 'kimi' | 'openai' | 'google' | 'zai';\r\n\r\n/**\r\n * Provider compatibility types\r\n * - direct: Anthropic-compatible API, use ANTHROPIC_BASE_URL directly\r\n * - router: Incompatible API, requires claude-code-router for translation\r\n */\r\nexport type ProviderCompatibility = 'direct' | 'router';\r\n\r\n/**\r\n * Provider configuration\r\n */\r\nexport interface ProviderConfig {\r\n name: ProviderName;\r\n displayName: string;\r\n compatibility: ProviderCompatibility;\r\n baseUrl?: string; // For direct providers\r\n models: ModelId[];\r\n tested: boolean; // Whether compatibility has been verified\r\n description: string;\r\n}\r\n\r\n/**\r\n * All provider configurations\r\n */\r\nexport const PROVIDERS: Record<ProviderName, ProviderConfig> = {\r\n anthropic: {\r\n name: 'anthropic',\r\n displayName: 'Anthropic',\r\n compatibility: 'direct',\r\n models: ['claude-opus-4-6', 'claude-sonnet-4-5', 'claude-haiku-4-5'],\r\n tested: true,\r\n description: 'Native Claude API',\r\n },\r\n\r\n kimi: {\r\n name: 'kimi',\r\n displayName: 'Kimi (Moonshot AI)',\r\n compatibility: 'direct',\r\n baseUrl: 'https://api.kimi.com/coding/',\r\n models: [], // Kimi uses same model names as Anthropic\r\n tested: true,\r\n description: 'Anthropic-compatible API, tested 2026-01-28',\r\n },\r\n\r\n zai: {\r\n name: 'zai',\r\n displayName: 'Z.AI (GLM)',\r\n compatibility: 'direct',\r\n baseUrl: 'https://api.z.ai/api/anthropic',\r\n models: ['glm-4.7', 'glm-4.7-flash'],\r\n tested: true,\r\n description: 'Anthropic-compatible API, tested 2026-01-28',\r\n },\r\n\r\n openai: {\r\n name: 'openai',\r\n displayName: 'OpenAI',\r\n compatibility: 'router',\r\n models: ['gpt-5.2-codex', 'o3-deep-research', 'gpt-4o', 'gpt-4o-mini'],\r\n tested: false,\r\n description: 'Requires claude-code-router for API translation',\r\n },\r\n\r\n google: {\r\n name: 'google',\r\n displayName: 'Google (Gemini)',\r\n compatibility: 'router',\r\n models: ['gemini-3-pro-preview', 'gemini-3-flash-preview'],\r\n tested: false,\r\n description: 'Requires claude-code-router for API translation',\r\n },\r\n};\r\n\r\n/**\r\n * Get provider for a given model ID\r\n */\r\nexport function getProviderForModel(modelId: ModelId): ProviderConfig {\r\n // Check Anthropic models\r\n if (['claude-opus-4-6', 'claude-sonnet-4-5', 'claude-haiku-4-5'].includes(modelId)) {\r\n return PROVIDERS.anthropic;\r\n }\r\n\r\n // Check OpenAI models\r\n if (['gpt-5.2-codex', 'o3-deep-research', 'gpt-4o', 'gpt-4o-mini'].includes(modelId)) {\r\n return PROVIDERS.openai;\r\n }\r\n\r\n // Check Google models\r\n if (['gemini-3-pro-preview', 'gemini-3-flash-preview'].includes(modelId)) {\r\n return PROVIDERS.google;\r\n }\r\n\r\n // Check Z.AI models\r\n if (['glm-4.7', 'glm-4.7-flash'].includes(modelId)) {\r\n return PROVIDERS.zai;\r\n }\r\n\r\n // Check Kimi models\r\n if (['kimi-k2', 'kimi-k2.5'].includes(modelId)) {\r\n return PROVIDERS.kimi;\r\n }\r\n\r\n // Default to Anthropic if unknown\r\n return PROVIDERS.anthropic;\r\n}\r\n\r\n/**\r\n * Check if a provider requires claude-code-router\r\n */\r\nexport function requiresRouter(provider: ProviderName): boolean {\r\n return PROVIDERS[provider].compatibility === 'router';\r\n}\r\n\r\n/**\r\n * Get all providers that require router (have router compatibility)\r\n */\r\nexport function getRouterProviders(): ProviderConfig[] {\r\n return Object.values(PROVIDERS).filter(p => p.compatibility === 'router');\r\n}\r\n\r\n/**\r\n * Get all direct-compatible providers\r\n */\r\nexport function getDirectProviders(): ProviderConfig[] {\r\n return Object.values(PROVIDERS).filter(p => p.compatibility === 'direct');\r\n}\r\n\r\n/**\r\n * Check if any configured providers require router\r\n * Used to determine if router installation is needed\r\n */\r\nexport function needsRouter(apiKeys: { openai?: string; google?: string; zai?: string }): boolean {\r\n return !!(apiKeys.openai || apiKeys.google);\r\n}\r\n\r\n/**\r\n * Get environment variables for spawning agent with specific provider\r\n */\r\nexport function getProviderEnv(\r\n provider: ProviderConfig,\r\n apiKey: string\r\n): Record<string, string> {\r\n if (provider.compatibility === 'direct') {\r\n // Direct providers use ANTHROPIC_BASE_URL\r\n const env: Record<string, string> = {};\r\n\r\n if (provider.baseUrl) {\r\n env.ANTHROPIC_BASE_URL = provider.baseUrl;\r\n }\r\n\r\n if (provider.name !== 'anthropic') {\r\n // Non-Anthropic providers need auth token\r\n env.ANTHROPIC_AUTH_TOKEN = apiKey;\r\n }\r\n\r\n // Z.AI recommends longer timeout\r\n if (provider.name === 'zai') {\r\n env.API_TIMEOUT_MS = '300000';\r\n }\r\n\r\n return env;\r\n } else {\r\n // Router providers use local router proxy\r\n return {\r\n ANTHROPIC_BASE_URL: 'http://localhost:3456',\r\n ANTHROPIC_AUTH_TOKEN: 'router-managed',\r\n };\r\n }\r\n}\r\n","/**\n * Issue Tracker Abstraction Layer\n *\n * Provides a unified interface for different issue tracking systems\n * (Linear, GitHub Issues, GitLab Issues, etc.)\n */\n\n// Supported tracker types\nexport type TrackerType = 'linear' | 'github' | 'gitlab' | 'rally';\n\n// Normalized issue state (lowest common denominator)\nexport type IssueState = 'open' | 'in_progress' | 'closed';\n\n// Normalized issue format\nexport interface Issue {\n /** Tracker-specific unique ID */\n id: string;\n\n /** Human-readable reference (e.g., MIN-630, #42) */\n ref: string;\n\n /** Issue title */\n title: string;\n\n /** Issue description/body (markdown) */\n description: string;\n\n /** Normalized state */\n state: IssueState;\n\n /** Labels/tags */\n labels: string[];\n\n /** Assignee username/name */\n assignee?: string;\n\n /** Web URL to the issue */\n url: string;\n\n /** Which tracker this issue came from */\n tracker: TrackerType;\n\n /** Cross-tracker linked issue references */\n linkedIssues?: string[];\n\n /** Priority (1=urgent, 2=high, 3=normal, 4=low) */\n priority?: number;\n\n /** Due date (ISO string) */\n dueDate?: string;\n\n /** Creation timestamp (ISO string) */\n createdAt: string;\n\n /** Last update timestamp (ISO string) */\n updatedAt: string;\n\n /** Parent issue FormattedID (e.g., \"F1234\") for Rally hierarchy */\n parentRef?: string;\n\n /** Rally artifact type (e.g., \"HierarchicalRequirement\", \"PortfolioItem/Feature\") */\n artifactType?: string;\n\n /** Raw tracker state name before normalization (e.g., \"Discovering\", \"In-Progress\") */\n rawState?: string;\n}\n\n// Comment on an issue\nexport interface Comment {\n id: string;\n issueId: string;\n body: string;\n author: string;\n createdAt: string;\n updatedAt: string;\n}\n\n// Filters for listing issues\nexport interface IssueFilters {\n /** Filter by state */\n state?: IssueState;\n\n /** Filter by labels (AND logic) */\n labels?: string[];\n\n /** Filter by assignee */\n assignee?: string;\n\n /** Filter by team/project (tracker-specific) */\n team?: string;\n\n /** Search query for title/description */\n query?: string;\n\n /** Maximum number of results */\n limit?: number;\n\n /** Include closed issues (default: false) */\n includeClosed?: boolean;\n}\n\n// Data for creating a new issue\nexport interface NewIssue {\n title: string;\n description?: string;\n labels?: string[];\n assignee?: string;\n team?: string;\n priority?: number;\n dueDate?: string;\n}\n\n// Data for updating an issue\nexport interface IssueUpdate {\n title?: string;\n description?: string;\n state?: IssueState;\n labels?: string[];\n assignee?: string;\n priority?: number;\n dueDate?: string;\n}\n\n/**\n * Abstract interface for issue trackers.\n * Implementations must handle normalization to/from tracker-specific formats.\n */\nexport interface IssueTracker {\n /** Tracker type identifier */\n readonly name: TrackerType;\n\n /**\n * List issues matching filters\n */\n listIssues(filters?: IssueFilters): Promise<Issue[]>;\n\n /**\n * Get a single issue by ID or ref\n * @param id - Issue ID or human-readable ref (e.g., \"MIN-630\", \"#42\")\n */\n getIssue(id: string): Promise<Issue>;\n\n /**\n * Update an existing issue\n */\n updateIssue(id: string, update: IssueUpdate): Promise<Issue>;\n\n /**\n * Create a new issue\n */\n createIssue(issue: NewIssue): Promise<Issue>;\n\n /**\n * Get comments on an issue\n */\n getComments(issueId: string): Promise<Comment[]>;\n\n /**\n * Add a comment to an issue\n */\n addComment(issueId: string, body: string): Promise<Comment>;\n\n /**\n * Transition issue to a new state\n */\n transitionIssue(id: string, state: IssueState): Promise<void>;\n\n /**\n * Link a PR/MR to an issue\n */\n linkPR(issueId: string, prUrl: string): Promise<void>;\n}\n\n/**\n * Error thrown when a tracker feature is not implemented\n */\nexport class NotImplementedError extends Error {\n constructor(feature: string) {\n super(`Not implemented: ${feature}`);\n this.name = 'NotImplementedError';\n }\n}\n\n/**\n * Error thrown when an issue is not found\n */\nexport class IssueNotFoundError extends Error {\n constructor(id: string, tracker: TrackerType) {\n super(`Issue not found: ${id} (tracker: ${tracker})`);\n this.name = 'IssueNotFoundError';\n }\n}\n\n/**\n * Error thrown when tracker authentication fails\n */\nexport class TrackerAuthError extends Error {\n constructor(tracker: TrackerType, message: string) {\n super(`Authentication failed for ${tracker}: ${message}`);\n this.name = 'TrackerAuthError';\n }\n}\n","/**\n * Linear Issue Tracker Adapter\n *\n * Implements IssueTracker interface for Linear.\n */\n\nimport { LinearClient } from '@linear/sdk';\nimport type {\n Issue,\n IssueFilters,\n IssueState,\n IssueTracker,\n IssueUpdate,\n NewIssue,\n Comment,\n TrackerType,\n} from './interface.js';\nimport { IssueNotFoundError, TrackerAuthError } from './interface.js';\n\n// Map Linear state types to our normalized states\nconst STATE_MAP: Record<string, IssueState> = {\n backlog: 'open',\n unstarted: 'open',\n started: 'in_progress',\n completed: 'closed',\n canceled: 'closed',\n};\n\nexport class LinearTracker implements IssueTracker {\n readonly name: TrackerType = 'linear';\n private client: LinearClient;\n private defaultTeam?: string;\n\n constructor(apiKey: string, options?: { team?: string }) {\n if (!apiKey) {\n throw new TrackerAuthError('linear', 'API key is required');\n }\n this.client = new LinearClient({ apiKey });\n this.defaultTeam = options?.team;\n }\n\n async listIssues(filters?: IssueFilters): Promise<Issue[]> {\n const team = filters?.team ?? this.defaultTeam;\n\n const result = await this.client.issues({\n first: filters?.limit ?? 50,\n filter: {\n team: team ? { key: { eq: team } } : undefined,\n state: filters?.state\n ? { type: { eq: this.reverseMapState(filters.state) } }\n : filters?.includeClosed\n ? undefined\n : { type: { neq: 'completed' } },\n labels: filters?.labels?.length\n ? { name: { in: filters.labels } }\n : undefined,\n assignee: filters?.assignee\n ? { name: { containsIgnoreCase: filters.assignee } }\n : undefined,\n },\n });\n\n const issues: Issue[] = [];\n for (const node of result.nodes) {\n issues.push(await this.normalizeIssue(node));\n }\n return issues;\n }\n\n async getIssue(id: string): Promise<Issue> {\n try {\n // Check if it's a UUID (36 chars with hyphens)\n const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id);\n\n if (isUuid) {\n // Fetch directly by UUID\n const issue = await this.client.issue(id);\n if (issue) {\n return this.normalizeIssue(issue);\n }\n } else {\n // Parse identifier (e.g., MIN-630) and search\n const match = id.match(/^([A-Z]+)-(\\d+)$/i);\n if (match) {\n const [, teamKey, number] = match;\n // Use searchIssues which supports identifier matching\n const results = await this.client.searchIssues(id, { first: 1 });\n if (results.nodes.length > 0) {\n return this.normalizeIssue(results.nodes[0]);\n }\n }\n }\n\n throw new IssueNotFoundError(id, 'linear');\n } catch (error) {\n if (error instanceof IssueNotFoundError) throw error;\n throw new IssueNotFoundError(id, 'linear');\n }\n }\n\n async updateIssue(id: string, update: IssueUpdate): Promise<Issue> {\n const issue = await this.getIssue(id);\n\n const updatePayload: Record<string, unknown> = {};\n\n if (update.title !== undefined) {\n updatePayload.title = update.title;\n }\n if (update.description !== undefined) {\n updatePayload.description = update.description;\n }\n if (update.priority !== undefined) {\n updatePayload.priority = update.priority;\n }\n if (update.dueDate !== undefined) {\n updatePayload.dueDate = update.dueDate;\n }\n if (update.state !== undefined) {\n // Need to find the state ID - this is complex in Linear\n // For now, we'll use the transition method\n await this.transitionIssue(id, update.state);\n }\n if (update.labels !== undefined) {\n // Need to look up label IDs - complex operation\n // TODO: Implement label updates\n }\n\n if (Object.keys(updatePayload).length > 0) {\n await this.client.updateIssue(issue.id, updatePayload);\n }\n\n return this.getIssue(id);\n }\n\n async createIssue(newIssue: NewIssue): Promise<Issue> {\n const team = newIssue.team ?? this.defaultTeam;\n\n if (!team) {\n throw new Error('Team is required to create an issue');\n }\n\n // Get team ID from key\n const teams = await this.client.teams({\n filter: { key: { eq: team } },\n });\n\n if (teams.nodes.length === 0) {\n throw new Error(`Team not found: ${team}`);\n }\n\n const teamId = teams.nodes[0].id;\n\n const result = await this.client.createIssue({\n teamId,\n title: newIssue.title,\n description: newIssue.description,\n priority: newIssue.priority,\n dueDate: newIssue.dueDate,\n });\n\n const created = await result.issue;\n if (!created) {\n throw new Error('Failed to create issue');\n }\n\n return this.normalizeIssue(created);\n }\n\n async getComments(issueId: string): Promise<Comment[]> {\n const issue = await this.client.issue(issueId);\n const comments = await issue.comments();\n\n return comments.nodes.map((c) => ({\n id: c.id,\n issueId,\n body: c.body,\n author: c.user?.then((u) => u?.name ?? 'Unknown') as unknown as string, // Simplified\n createdAt: c.createdAt.toISOString(),\n updatedAt: c.updatedAt.toISOString(),\n }));\n }\n\n async addComment(issueId: string, body: string): Promise<Comment> {\n const result = await this.client.createComment({\n issueId,\n body,\n });\n\n const comment = await result.comment;\n if (!comment) {\n throw new Error('Failed to create comment');\n }\n\n return {\n id: comment.id,\n issueId,\n body: comment.body,\n author: 'Panopticon', // Simplified\n createdAt: comment.createdAt.toISOString(),\n updatedAt: comment.updatedAt.toISOString(),\n };\n }\n\n async transitionIssue(id: string, state: IssueState): Promise<void> {\n // Resolve the Linear issue directly (avoid normalizeIssue which may fail on SDK edge cases)\n let linearIssue: any;\n const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id);\n if (isUuid) {\n linearIssue = await this.client.issue(id);\n } else {\n const results = await this.client.searchIssues(id, { first: 1 });\n if (results.nodes.length > 0) {\n linearIssue = results.nodes[0];\n } else {\n throw new IssueNotFoundError(id, 'linear');\n }\n }\n\n // Get workflow states for the issue's team\n const team = await linearIssue.team;\n if (!team) {\n throw new Error('Could not determine issue team');\n }\n\n const states = await team.states();\n const targetStateType = this.reverseMapState(state);\n\n // Find a state matching the target type.\n // Multiple states can share the same type (e.g., \"In Planning\", \"In Progress\", \"In Review\"\n // are all type \"started\"). Prefer the one with the lowest position (most basic/default state\n // for that type), which matches Linear's convention.\n const matchingStates = states.nodes\n .filter((s: any) => s.type === targetStateType)\n .sort((a: any, b: any) => (a.position ?? 0) - (b.position ?? 0));\n const targetState = matchingStates[0];\n if (!targetState) {\n throw new Error(`No state found matching type: ${targetStateType}`);\n }\n\n await this.client.updateIssue(linearIssue.id, {\n stateId: targetState.id,\n });\n }\n\n async linkPR(issueId: string, prUrl: string): Promise<void> {\n const issue = await this.getIssue(issueId);\n\n await this.client.createAttachment({\n issueId: issue.id,\n title: 'Pull Request',\n url: prUrl,\n });\n }\n\n private async normalizeIssue(linearIssue: any): Promise<Issue> {\n const state = await linearIssue.state;\n const assignee = await linearIssue.assignee;\n const labels = await linearIssue.labels();\n\n // Handle dueDate - can be Date, string, or undefined\n let dueDate: string | undefined;\n if (linearIssue.dueDate) {\n dueDate = linearIssue.dueDate instanceof Date\n ? linearIssue.dueDate.toISOString()\n : String(linearIssue.dueDate);\n }\n\n return {\n id: linearIssue.id,\n ref: linearIssue.identifier,\n title: linearIssue.title,\n description: linearIssue.description ?? '',\n state: this.mapState(state?.type ?? 'backlog'),\n labels: labels?.nodes?.map((l: any) => l.name) ?? [],\n assignee: assignee?.name,\n url: linearIssue.url,\n tracker: 'linear',\n priority: linearIssue.priority,\n dueDate,\n createdAt: linearIssue.createdAt instanceof Date\n ? linearIssue.createdAt.toISOString()\n : String(linearIssue.createdAt),\n updatedAt: linearIssue.updatedAt instanceof Date\n ? linearIssue.updatedAt.toISOString()\n : String(linearIssue.updatedAt),\n };\n }\n\n private mapState(linearState: string): IssueState {\n return STATE_MAP[linearState] ?? 'open';\n }\n\n private reverseMapState(state: IssueState): string {\n switch (state) {\n case 'open':\n return 'unstarted';\n case 'in_progress':\n return 'started';\n case 'closed':\n return 'completed';\n default:\n return 'unstarted';\n }\n }\n}\n","/**\n * GitHub Issues Tracker Adapter\n *\n * Implements IssueTracker interface for GitHub Issues.\n */\n\nimport { Octokit } from '@octokit/rest';\nimport type {\n Issue,\n IssueFilters,\n IssueState,\n IssueTracker,\n IssueUpdate,\n NewIssue,\n Comment,\n TrackerType,\n} from './interface.js';\nimport { IssueNotFoundError, TrackerAuthError } from './interface.js';\n\nexport class GitHubTracker implements IssueTracker {\n readonly name: TrackerType = 'github';\n private octokit: Octokit;\n private owner: string;\n private repo: string;\n\n constructor(token: string, owner: string, repo: string) {\n if (!token) {\n throw new TrackerAuthError('github', 'Token is required');\n }\n if (!owner || !repo) {\n throw new Error('GitHub owner and repo are required');\n }\n\n this.octokit = new Octokit({ auth: token });\n this.owner = owner;\n this.repo = repo;\n }\n\n async listIssues(filters?: IssueFilters): Promise<Issue[]> {\n const state = this.mapStateToGitHub(filters?.state);\n\n const response = await this.octokit.issues.listForRepo({\n owner: this.owner,\n repo: this.repo,\n state: filters?.includeClosed ? 'all' : state,\n labels: filters?.labels?.join(',') || undefined,\n assignee: filters?.assignee || undefined,\n per_page: filters?.limit ?? 50,\n });\n\n // Filter out pull requests (GitHub API returns both)\n const issues = response.data.filter((item) => !item.pull_request);\n\n return issues.map((issue) => this.normalizeIssue(issue));\n }\n\n async getIssue(id: string): Promise<Issue> {\n try {\n // Parse the issue number from refs like \"#42\" or just \"42\"\n const issueNumber = parseInt(id.replace(/^#/, ''), 10);\n\n if (isNaN(issueNumber)) {\n throw new IssueNotFoundError(id, 'github');\n }\n\n const { data: issue } = await this.octokit.issues.get({\n owner: this.owner,\n repo: this.repo,\n issue_number: issueNumber,\n });\n\n return this.normalizeIssue(issue);\n } catch (error: any) {\n if (error?.status === 404) {\n throw new IssueNotFoundError(id, 'github');\n }\n throw error;\n }\n }\n\n async updateIssue(id: string, update: IssueUpdate): Promise<Issue> {\n const issueNumber = parseInt(id.replace(/^#/, ''), 10);\n\n const updatePayload: Record<string, unknown> = {};\n\n if (update.title !== undefined) {\n updatePayload.title = update.title;\n }\n if (update.description !== undefined) {\n updatePayload.body = update.description;\n }\n if (update.state !== undefined) {\n updatePayload.state = update.state === 'closed' ? 'closed' : 'open';\n }\n if (update.labels !== undefined) {\n updatePayload.labels = update.labels;\n }\n if (update.assignee !== undefined) {\n updatePayload.assignees = update.assignee ? [update.assignee] : [];\n }\n\n await this.octokit.issues.update({\n owner: this.owner,\n repo: this.repo,\n issue_number: issueNumber,\n ...updatePayload,\n });\n\n return this.getIssue(id);\n }\n\n async createIssue(newIssue: NewIssue): Promise<Issue> {\n const { data: issue } = await this.octokit.issues.create({\n owner: this.owner,\n repo: this.repo,\n title: newIssue.title,\n body: newIssue.description,\n labels: newIssue.labels,\n assignees: newIssue.assignee ? [newIssue.assignee] : undefined,\n });\n\n return this.normalizeIssue(issue);\n }\n\n async getComments(issueId: string): Promise<Comment[]> {\n const issueNumber = parseInt(issueId.replace(/^#/, ''), 10);\n\n const { data: comments } = await this.octokit.issues.listComments({\n owner: this.owner,\n repo: this.repo,\n issue_number: issueNumber,\n });\n\n return comments.map((c) => ({\n id: String(c.id),\n issueId,\n body: c.body ?? '',\n author: c.user?.login ?? 'Unknown',\n createdAt: c.created_at,\n updatedAt: c.updated_at,\n }));\n }\n\n async addComment(issueId: string, body: string): Promise<Comment> {\n const issueNumber = parseInt(issueId.replace(/^#/, ''), 10);\n\n const { data: comment } = await this.octokit.issues.createComment({\n owner: this.owner,\n repo: this.repo,\n issue_number: issueNumber,\n body,\n });\n\n return {\n id: String(comment.id),\n issueId,\n body: comment.body ?? '',\n author: comment.user?.login ?? 'Unknown',\n createdAt: comment.created_at,\n updatedAt: comment.updated_at,\n };\n }\n\n async transitionIssue(id: string, state: IssueState): Promise<void> {\n await this.updateIssue(id, { state });\n }\n\n async linkPR(issueId: string, prUrl: string): Promise<void> {\n // GitHub auto-links PRs that mention issues\n // Add a comment with the PR link\n await this.addComment(\n issueId,\n `Linked Pull Request: ${prUrl}`\n );\n }\n\n private normalizeIssue(ghIssue: any): Issue {\n return {\n id: String(ghIssue.id),\n ref: `#${ghIssue.number}`,\n title: ghIssue.title,\n description: ghIssue.body ?? '',\n state: this.mapStateFromGitHub(ghIssue.state),\n labels: ghIssue.labels.map((l: any) =>\n typeof l === 'string' ? l : l.name\n ),\n assignee: ghIssue.assignee?.login,\n url: ghIssue.html_url,\n tracker: 'github',\n priority: undefined, // GitHub doesn't have priority\n dueDate: undefined, // GitHub doesn't have due dates on issues\n createdAt: ghIssue.created_at,\n updatedAt: ghIssue.updated_at,\n };\n }\n\n private mapStateFromGitHub(ghState: string): IssueState {\n // GitHub only has open and closed states\n // No way to distinguish \"in_progress\" without custom labels\n return ghState === 'closed' ? 'closed' : 'open';\n }\n\n private mapStateToGitHub(\n state?: IssueState\n ): 'open' | 'closed' | 'all' {\n if (!state) return 'open';\n if (state === 'closed') return 'closed';\n return 'open'; // Both 'open' and 'in_progress' map to 'open'\n }\n}\n","/**\n * GitLab Issues Tracker Adapter (Stub)\n *\n * Placeholder implementation for GitLab Issues support.\n * Full implementation will use @gitbeaker/rest.\n */\n\nimport type {\n Issue,\n IssueFilters,\n IssueState,\n IssueTracker,\n IssueUpdate,\n NewIssue,\n Comment,\n TrackerType,\n} from './interface.js';\nimport { NotImplementedError } from './interface.js';\n\nexport class GitLabTracker implements IssueTracker {\n readonly name: TrackerType = 'gitlab';\n\n constructor(\n private token: string,\n private projectId: string\n ) {\n // Stub - will initialize @gitbeaker client when implemented\n }\n\n async listIssues(_filters?: IssueFilters): Promise<Issue[]> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n\n async getIssue(_id: string): Promise<Issue> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n\n async updateIssue(_id: string, _update: IssueUpdate): Promise<Issue> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n\n async createIssue(_issue: NewIssue): Promise<Issue> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n\n async getComments(_issueId: string): Promise<Comment[]> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n\n async addComment(_issueId: string, _body: string): Promise<Comment> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n\n async transitionIssue(_id: string, _state: IssueState): Promise<void> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n\n async linkPR(_issueId: string, _prUrl: string): Promise<void> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n}\n","/**\n * Rally WSAPI REST Client\n *\n * Thin wrapper around native fetch for Rally Web Services API v2.0.\n * Provides typed methods for query, create, and update operations.\n */\n\nexport interface RallyQueryConfig {\n type: string;\n fetch?: string[];\n query?: string;\n limit?: number;\n workspace?: string;\n project?: string;\n projectScopeDown?: boolean;\n order?: string;\n}\n\nexport interface RallyQueryResult {\n QueryResult: {\n Results: any[];\n TotalResultCount: number;\n Errors: string[];\n Warnings: string[];\n };\n}\n\nexport interface RallyCreateConfig {\n type: string;\n data: any;\n fetch?: string[];\n}\n\nexport interface RallyCreateResult {\n CreateResult: {\n Object: any;\n Errors: string[];\n Warnings: string[];\n };\n}\n\nexport interface RallyUpdateConfig {\n type: string;\n ref: string;\n data: any;\n fetch?: string[];\n}\n\nexport interface RallyUpdateResult {\n OperationResult: {\n Object: any;\n Errors: string[];\n Warnings: string[];\n };\n}\n\nexport interface RallyApiConfig {\n apiKey: string;\n server?: string;\n requestOptions?: {\n headers?: Record<string, string>;\n };\n}\n\nexport class RallyRestApi {\n private apiKey: string;\n public server: string;\n private customHeaders: Record<string, string>;\n\n constructor(config: RallyApiConfig) {\n this.apiKey = config.apiKey;\n this.server = config.server || 'https://rally1.rallydev.com';\n this.customHeaders = config.requestOptions?.headers || {};\n }\n\n /**\n * Query Rally artifacts\n */\n async query(config: RallyQueryConfig): Promise<RallyQueryResult> {\n const params = new URLSearchParams();\n\n if (config.query) {\n params.set('query', config.query);\n }\n\n if (config.fetch && config.fetch.length > 0) {\n params.set('fetch', config.fetch.join(','));\n }\n\n if (config.limit !== undefined) {\n params.set('pagesize', String(config.limit));\n }\n\n if (config.workspace) {\n params.set('workspace', config.workspace);\n }\n\n if (config.project) {\n params.set('project', config.project);\n if (config.projectScopeDown) {\n params.set('projectScopeDown', 'true');\n }\n }\n\n if (config.order) {\n params.set('order', config.order);\n }\n\n const url = `${this.server}/slm/webservice/v2.0/${config.type}?${params.toString()}`;\n\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'ZSESSIONID': this.apiKey,\n 'Content-Type': 'application/json',\n ...this.customHeaders,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error('Unauthorized: Invalid API key or insufficient permissions');\n }\n throw new Error(`Rally API query failed: ${response.status} ${response.statusText}`);\n }\n\n const result = await response.json() as RallyQueryResult;\n\n if (result.QueryResult.Errors && result.QueryResult.Errors.length > 0) {\n const errorDetail = result.QueryResult.Errors.join(', ');\n const queryDetail = config.query ? ` (Query: ${config.query})` : '';\n if (process.env.DEBUG?.includes('rally')) {\n console.error('[Rally WSAPI] Query failed:', { query: config.query, errors: result.QueryResult.Errors });\n }\n throw new Error(`Rally API query failed: ${errorDetail}${queryDetail}`);\n }\n\n return result;\n }\n\n /**\n * Create a Rally object\n */\n async create(config: RallyCreateConfig): Promise<RallyCreateResult> {\n const url = `${this.server}/slm/webservice/v2.0/${config.type}/create`;\n\n const body: any = {\n [config.type]: config.data,\n };\n\n const params = new URLSearchParams();\n if (config.fetch && config.fetch.length > 0) {\n params.set('fetch', config.fetch.join(','));\n }\n\n const finalUrl = params.toString() ? `${url}?${params.toString()}` : url;\n\n const response = await fetch(finalUrl, {\n method: 'POST',\n headers: {\n 'ZSESSIONID': this.apiKey,\n 'Content-Type': 'application/json',\n ...this.customHeaders,\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n throw new Error(`Rally API create failed: ${response.status} ${response.statusText}`);\n }\n\n const result = await response.json() as RallyCreateResult;\n\n if (result.CreateResult.Errors && result.CreateResult.Errors.length > 0) {\n throw new Error(`Rally API create failed: ${result.CreateResult.Errors.join(', ')}`);\n }\n\n return result;\n }\n\n /**\n * Update a Rally object\n */\n async update(config: RallyUpdateConfig): Promise<RallyUpdateResult> {\n // Extract ObjectID from ref (e.g., \"/hierarchicalrequirement/12345\" -> \"12345\")\n const objectId = config.ref.split('/').pop();\n const url = `${this.server}/slm/webservice/v2.0/${config.type}/${objectId}`;\n\n const body: any = {\n [config.type]: config.data,\n };\n\n const params = new URLSearchParams();\n if (config.fetch && config.fetch.length > 0) {\n params.set('fetch', config.fetch.join(','));\n }\n\n const finalUrl = params.toString() ? `${url}?${params.toString()}` : url;\n\n const response = await fetch(finalUrl, {\n method: 'POST',\n headers: {\n 'ZSESSIONID': this.apiKey,\n 'Content-Type': 'application/json',\n ...this.customHeaders,\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n throw new Error(`Rally API update failed: ${response.status} ${response.statusText}`);\n }\n\n const result = await response.json() as RallyUpdateResult;\n\n if (result.OperationResult.Errors && result.OperationResult.Errors.length > 0) {\n throw new Error(`Rally API update failed: ${result.OperationResult.Errors.join(', ')}`);\n }\n\n return result;\n }\n}\n","/**\n * Rally Tracker Adapter\n *\n * Implements IssueTracker interface for Broadcom Rally (formerly CA Agile Central).\n * Supports all Rally work item types: User Stories, Defects, Tasks, and Features.\n */\n\nimport { RallyRestApi } from './rally-api.js';\nimport type {\n Issue,\n IssueFilters,\n IssueState,\n IssueTracker,\n IssueUpdate,\n NewIssue,\n Comment,\n TrackerType,\n} from './interface.js';\nimport { IssueNotFoundError, TrackerAuthError, NotImplementedError } from './interface.js';\n\n// Map Rally ScheduleState/State to normalized IssueState.\n// Covers all standard states for User Stories, Defects, Tasks, and Features.\nconst STATE_MAP: Record<string, IssueState> = {\n // User Stories (ScheduleState)\n 'New': 'open',\n 'Idea': 'open',\n 'Defined': 'open',\n 'In-Progress': 'in_progress',\n 'Completed': 'closed',\n 'Accepted': 'closed',\n\n // Defects (State)\n 'Submitted': 'open',\n 'Open': 'in_progress', // \"Open\" defects are actively being worked\n 'Fixed': 'closed',\n 'Closed': 'closed',\n\n // Features / PortfolioItems (State)\n 'Discovering': 'open',\n 'Developing': 'in_progress',\n 'Done': 'closed',\n};\n\n// Rally artifact types we support\ntype RallyArtifactType = 'HierarchicalRequirement' | 'Defect' | 'Task' | 'PortfolioItem/Feature';\n\n/**\n * Type-specific query configuration.\n *\n * Rally WSAPI cannot filter generic Artifact by ScheduleState because not all\n * subtypes have that field. Instead, we query each type separately with its\n * own state field and merge the results. (PAN-168)\n */\ninterface ArtifactTypeQuery {\n /** WSAPI endpoint type (lowercase) */\n type: string;\n /** The state field used for filtering on this artifact type */\n stateField: 'ScheduleState' | 'State';\n /** State values that represent \"closed\" for this type */\n closedStates: string[];\n}\n\nconst QUERYABLE_TYPES: ArtifactTypeQuery[] = [\n { type: 'hierarchicalrequirement', stateField: 'ScheduleState', closedStates: ['Completed', 'Accepted'] },\n { type: 'defect', stateField: 'State', closedStates: ['Closed'] },\n { type: 'task', stateField: 'State', closedStates: ['Completed'] },\n { type: 'portfolioitem/feature', stateField: 'State', closedStates: ['Done'] },\n];\n\nconst FETCH_FIELDS = [\n 'ObjectID',\n 'FormattedID',\n 'Name',\n 'Description',\n 'ScheduleState',\n 'State',\n 'Tags',\n 'Owner',\n 'Priority',\n 'DueDate',\n 'CreationDate',\n 'LastUpdateDate',\n 'Parent',\n 'PortfolioItem',\n '_type',\n];\n\n// Rally priority strings to numbers\nconst PRIORITY_MAP: Record<string, number> = {\n 'Resolve Immediately': 0,\n High: 1,\n Normal: 2,\n Low: 3,\n};\n\n// Reverse priority mapping\nconst REVERSE_PRIORITY_MAP: Record<number, string> = {\n 0: 'Resolve Immediately',\n 1: 'High',\n 2: 'Normal',\n 3: 'Low',\n 4: 'Low',\n};\n\nexport interface RallyConfig {\n apiKey: string;\n server?: string; // Default: rally1.rallydev.com\n workspace?: string; // Rally workspace OID (e.g., \"/workspace/12345\")\n project?: string; // Rally project OID (e.g., \"/project/67890\")\n}\n\nexport class RallyTracker implements IssueTracker {\n readonly name: TrackerType = 'rally' as TrackerType;\n private restApi: RallyRestApi;\n private workspace?: string;\n private project?: string;\n\n constructor(config: RallyConfig) {\n if (!config.apiKey) {\n throw new TrackerAuthError('rally' as TrackerType, 'API key is required');\n }\n\n this.restApi = new RallyRestApi({\n apiKey: config.apiKey,\n server: config.server || 'https://rally1.rallydev.com',\n requestOptions: {\n headers: {\n 'X-RallyIntegrationType': 'Panopticon',\n 'X-RallyIntegrationName': 'Panopticon CLI',\n 'X-RallyIntegrationVendor': 'Mind Your Now',\n 'X-RallyIntegrationVersion': '0.2.0',\n },\n },\n });\n\n this.workspace = config.workspace;\n this.project = config.project;\n }\n\n /**\n * List issues by querying each artifact type separately and merging results.\n *\n * Rally WSAPI cannot apply ScheduleState filters across the generic Artifact\n * endpoint because not all subtypes have that field. We query each type with\n * its own state field, then merge and sort. (PAN-168)\n */\n async listIssues(filters?: IssueFilters): Promise<Issue[]> {\n if (process.env.DEBUG?.includes('rally')) {\n console.debug('[Rally] Query filters:', JSON.stringify(filters));\n }\n\n const limit = filters?.limit ?? 50;\n\n // Extract ObjectID from project ref for explicit query scoping\n // e.g., \"/project/822404704163\" → \"822404704163\"\n let projectObjectId: string | undefined;\n if (this.project) {\n const match = this.project.match(/\\/project\\/(\\d+)/);\n if (match) projectObjectId = match[1];\n }\n\n const queries = QUERYABLE_TYPES.map(async (artifactType) => {\n const queryString = this.buildQueryStringForType(filters, artifactType, projectObjectId);\n\n if (process.env.DEBUG?.includes('rally')) {\n console.debug(`[Rally] ${artifactType.type} query:`, queryString);\n }\n\n const query: any = {\n type: artifactType.type,\n fetch: FETCH_FIELDS,\n limit,\n query: queryString,\n };\n\n if (this.workspace) {\n query.workspace = this.workspace;\n }\n if (this.project) {\n query.project = this.project;\n query.projectScopeDown = true;\n }\n\n try {\n const result = await this.queryRally(query);\n return result.Results.map((artifact: any) => this.normalizeIssue(artifact));\n } catch (error: any) {\n if (error.message?.includes('Unauthorized') || error.message?.includes('401')) {\n throw new TrackerAuthError('rally' as TrackerType, 'Invalid API key or insufficient permissions');\n }\n // Log and skip individual type failures so other types still return\n if (process.env.DEBUG?.includes('rally')) {\n console.debug(`[Rally] Failed to query ${artifactType.type}:`, error.message);\n }\n return [];\n }\n });\n\n const results = await Promise.all(queries);\n const allIssues = results.flat();\n\n // Sort by most recently updated first, then apply overall limit\n allIssues.sort(\n (a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()\n );\n\n return allIssues.slice(0, limit);\n }\n\n async getIssue(id: string): Promise<Issue> {\n try {\n // Rally FormattedIDs look like: US123, DE456, TA789, F012\n const query: any = {\n type: 'artifact',\n fetch: [\n 'FormattedID',\n 'Name',\n 'Description',\n 'ScheduleState',\n 'State',\n 'Tags',\n 'Owner',\n 'Priority',\n 'DueDate',\n 'CreationDate',\n 'LastUpdateDate',\n 'Parent',\n '_type',\n ],\n query: `(FormattedID = \"${id}\")`,\n };\n\n if (this.workspace) {\n query.workspace = this.workspace;\n }\n\n const result = await this.queryRally(query);\n\n if (!result.Results || result.Results.length === 0) {\n throw new IssueNotFoundError(id, 'rally' as TrackerType);\n }\n\n return this.normalizeIssue(result.Results[0]);\n } catch (error: any) {\n if (error instanceof IssueNotFoundError) throw error;\n throw new IssueNotFoundError(id, 'rally' as TrackerType);\n }\n }\n\n async updateIssue(id: string, update: IssueUpdate): Promise<Issue> {\n const issue = await this.getIssue(id);\n\n // Get the Rally object reference\n const query: any = {\n type: 'artifact',\n fetch: ['ObjectID', '_ref', '_type'],\n query: `(FormattedID = \"${id}\")`,\n };\n\n if (this.workspace) {\n query.workspace = this.workspace;\n }\n\n const result = await this.queryRally(query);\n if (!result.Results || result.Results.length === 0) {\n throw new IssueNotFoundError(id, 'rally' as TrackerType);\n }\n\n const artifact = result.Results[0];\n const updatePayload: Record<string, unknown> = {};\n\n if (update.title !== undefined) {\n updatePayload.Name = update.title;\n }\n if (update.description !== undefined) {\n updatePayload.Description = update.description;\n }\n if (update.state !== undefined) {\n const artifactType = (artifact._type || '').toLowerCase();\n const kind = artifactType.startsWith('portfolioitem') ? 'feature'\n : artifactType === 'defect' ? 'defect' : 'story';\n const rallyState = this.reverseMapState(update.state, kind);\n if (kind === 'story') {\n updatePayload.ScheduleState = rallyState;\n } else {\n updatePayload.State = rallyState;\n }\n }\n if (update.priority !== undefined) {\n updatePayload.Priority = REVERSE_PRIORITY_MAP[update.priority] || 'Normal';\n }\n if (update.dueDate !== undefined) {\n updatePayload.DueDate = update.dueDate;\n }\n\n if (Object.keys(updatePayload).length > 0) {\n await this.updateRally(artifact._type.toLowerCase(), artifact._ref, updatePayload);\n }\n\n return this.getIssue(id);\n }\n\n async createIssue(newIssue: NewIssue): Promise<Issue> {\n if (!this.project && !newIssue.team) {\n throw new Error('Project is required to create an issue. Set it in config or provide team field.');\n }\n\n const project = newIssue.team || this.project;\n\n // Default to HierarchicalRequirement (User Story) for new issues\n const createPayload: Record<string, unknown> = {\n Name: newIssue.title,\n Description: newIssue.description || '',\n Project: project,\n };\n\n if (newIssue.priority !== undefined) {\n createPayload.Priority = REVERSE_PRIORITY_MAP[newIssue.priority] || 'Normal';\n }\n if (newIssue.dueDate) {\n createPayload.DueDate = newIssue.dueDate;\n }\n if (this.workspace) {\n createPayload.Workspace = this.workspace;\n }\n\n const result = await this.createRally('hierarchicalrequirement', createPayload);\n\n // Fetch the created issue to return normalized format\n return this.getIssue(result.Object.FormattedID);\n }\n\n async getComments(issueId: string): Promise<Comment[]> {\n const issue = await this.getIssue(issueId);\n\n // Get the Rally object to find its Discussion\n const query: any = {\n type: 'artifact',\n fetch: ['ObjectID', '_ref', 'Discussion'],\n query: `(FormattedID = \"${issueId}\")`,\n };\n\n if (this.workspace) {\n query.workspace = this.workspace;\n }\n\n const result = await this.queryRally(query);\n if (!result.Results || result.Results.length === 0) {\n return [];\n }\n\n const artifact = result.Results[0];\n if (!artifact.Discussion) {\n return [];\n }\n\n // Query ConversationPosts for this Discussion\n const postsQuery: any = {\n type: 'conversationpost',\n fetch: ['ObjectID', 'Text', 'User', 'CreationDate', 'PostNumber'],\n query: `(Discussion = \"${artifact.Discussion._ref}\")`,\n order: 'PostNumber',\n };\n\n const postsResult = await this.queryRally(postsQuery);\n\n return (postsResult.Results || []).map((post: any) => ({\n id: post.ObjectID,\n issueId,\n body: post.Text || '',\n author: post.User?._refObjectName || 'Unknown',\n createdAt: post.CreationDate,\n updatedAt: post.CreationDate, // Rally doesn't track comment updates separately\n }));\n }\n\n async addComment(issueId: string, body: string): Promise<Comment> {\n // Get the Rally object to find its Discussion\n const query: any = {\n type: 'artifact',\n fetch: ['ObjectID', '_ref', 'Discussion'],\n query: `(FormattedID = \"${issueId}\")`,\n };\n\n if (this.workspace) {\n query.workspace = this.workspace;\n }\n\n const result = await this.queryRally(query);\n if (!result.Results || result.Results.length === 0) {\n throw new IssueNotFoundError(issueId, 'rally' as TrackerType);\n }\n\n const artifact = result.Results[0];\n\n // If no Discussion exists, create one\n let discussionRef = artifact.Discussion?._ref;\n if (!discussionRef) {\n const discussionResult = await this.createRally('conversationpost', {\n Artifact: artifact._ref,\n Text: body,\n });\n\n return {\n id: discussionResult.Object.ObjectID,\n issueId,\n body,\n author: 'Panopticon',\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n };\n }\n\n // Add a post to existing Discussion\n const postResult = await this.createRally('conversationpost', {\n Artifact: artifact._ref,\n Text: body,\n });\n\n return {\n id: postResult.Object.ObjectID,\n issueId,\n body,\n author: 'Panopticon',\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n };\n }\n\n async transitionIssue(id: string, state: IssueState): Promise<void> {\n await this.updateIssue(id, { state });\n }\n\n async linkPR(issueId: string, prUrl: string): Promise<void> {\n // Add a comment with the PR link\n await this.addComment(issueId, `Linked Pull Request: ${prUrl}`);\n }\n\n // Private helper methods\n\n /**\n * Build a Rally WSAPI query string for a specific artifact type.\n *\n * Each artifact type has its own state field:\n * - HierarchicalRequirement: ScheduleState (Defined, In-Progress, Completed, Accepted)\n * - Defect: State (Submitted, Open, Fixed, Closed)\n * - Task: State (Defined, In-Progress, Completed)\n *\n * Rally WSAPI v2.0 requires binary-nested AND/OR with outer parentheses.\n * (PAN-166, PAN-168)\n */\n private buildQueryStringForType(\n filters: IssueFilters | undefined,\n artifactType: ArtifactTypeQuery,\n projectObjectId?: string,\n ): string {\n const conditions: string[] = [];\n\n // Explicit project scoping — more reliable than WSAPI project param alone\n if (projectObjectId) {\n conditions.push(`(Project.ObjectID = \"${projectObjectId}\")`);\n }\n\n if (filters?.state && !filters.includeClosed) {\n const kind = artifactType.type.startsWith('portfolioitem') ? 'feature'\n : artifactType.type === 'defect' ? 'defect' : 'story';\n const rallyState = this.reverseMapState(filters.state, kind);\n conditions.push(`(${artifactType.stateField} = \"${rallyState}\")`);\n }\n\n if (!filters?.includeClosed) {\n // Exclude closed states for this specific artifact type\n const closedConditions = artifactType.closedStates.map(\n (state) => `(${artifactType.stateField} != \"${state}\")`\n );\n // Rally WSAPI only supports binary AND — nest into pairs\n const closedExpr = closedConditions.reduce(\n (acc, cond) => (acc ? `(${acc} AND ${cond})` : cond),\n '',\n );\n conditions.push(closedExpr);\n }\n\n if (filters?.assignee) {\n conditions.push(`(Owner.Name contains \"${filters.assignee}\")`);\n }\n\n if (filters?.labels && filters.labels.length > 0) {\n const labelConditions = filters.labels.map(\n (label) => `(Tags.Name contains \"${label}\")`\n );\n // Rally WSAPI only supports binary AND — nest into pairs\n const labelExpr = labelConditions.reduce((acc, cond) => acc ? `(${acc} AND ${cond})` : cond, '');\n conditions.push(labelExpr);\n }\n\n if (filters?.query) {\n conditions.push(`((Name contains \"${filters.query}\") OR (Description contains \"${filters.query}\"))`);\n }\n\n // Rally WSAPI only supports binary (expr AND expr) — reduce into nested pairs\n return conditions.reduce((acc, cond) => acc ? `(${acc} AND ${cond})` : cond, '');\n }\n\n private normalizeIssue(rallyArtifact: any): Issue {\n // Determine state from ScheduleState (User Stories, Tasks) or State (Defects, Features)\n // For PortfolioItem/Feature, State is a Rally ref object with Name/_refObjectName, not a string\n const rawStateValue = rallyArtifact.ScheduleState || rallyArtifact.State || 'Defined';\n const stateValue = typeof rawStateValue === 'object' && rawStateValue !== null\n ? (rawStateValue.Name || rawStateValue._refObjectName || 'Defined')\n : rawStateValue;\n const state = this.mapState(stateValue);\n\n // Extract tags — ensure all entries are strings\n const labels: string[] = [];\n if (rallyArtifact.Tags && rallyArtifact.Tags._tagsNameArray) {\n for (const tag of rallyArtifact.Tags._tagsNameArray) {\n if (typeof tag === 'string') {\n labels.push(tag);\n } else if (tag?.Name) {\n labels.push(tag.Name);\n }\n }\n }\n\n // Map priority\n const priority = rallyArtifact.Priority\n ? PRIORITY_MAP[rallyArtifact.Priority] ?? 2\n : undefined;\n\n // Use ObjectID if available, fall back to FormattedID\n const objectId = rallyArtifact.ObjectID || rallyArtifact.FormattedID;\n const artifactType = rallyArtifact._type || 'artifact';\n\n // Build URL - Rally's web UI detail path\n const baseUrl = this.restApi.server.replace('/slm/webservice/', '');\n const url = `${baseUrl}/#/detail/${artifactType.toLowerCase()}/${objectId}`;\n\n // Resolve parent reference.\n // For User Stories, PortfolioItem links to the parent Feature (F-prefixed),\n // while Parent links to a parent Story in the hierarchy. Prefer PortfolioItem\n // so that stories are correctly grouped under their Feature. (PAN-202)\n let parentRef: string | undefined;\n if (rallyArtifact.PortfolioItem) {\n if (rallyArtifact.PortfolioItem.FormattedID) {\n parentRef = rallyArtifact.PortfolioItem.FormattedID;\n } else if (rallyArtifact.PortfolioItem._refObjectName) {\n parentRef = rallyArtifact.PortfolioItem._refObjectName;\n }\n } else if (rallyArtifact.Parent) {\n if (rallyArtifact.Parent.FormattedID) {\n parentRef = rallyArtifact.Parent.FormattedID;\n } else if (rallyArtifact.Parent._refObjectName) {\n parentRef = rallyArtifact.Parent._refObjectName;\n }\n }\n\n return {\n id: String(objectId),\n ref: rallyArtifact.FormattedID,\n title: rallyArtifact.Name || '',\n description: rallyArtifact.Description || '',\n state,\n labels,\n assignee: rallyArtifact.Owner?._refObjectName,\n url,\n tracker: 'rally' as TrackerType,\n priority,\n dueDate: rallyArtifact.DueDate,\n createdAt: rallyArtifact.CreationDate,\n updatedAt: rallyArtifact.LastUpdateDate,\n parentRef,\n artifactType,\n rawState: stateValue,\n };\n }\n\n private mapState(rallyState: string): IssueState {\n return STATE_MAP[rallyState] ?? 'open';\n }\n\n private reverseMapState(state: IssueState, kind: 'story' | 'defect' | 'feature' = 'story'): string {\n if (kind === 'feature') {\n // Features / PortfolioItems use State: Discovering, Developing, Done\n switch (state) {\n case 'open': return 'Discovering';\n case 'in_progress': return 'Developing';\n case 'closed': return 'Done';\n default: return 'Discovering';\n }\n }\n if (kind === 'defect') {\n // Defects use State: Submitted, Open, Fixed, Closed\n switch (state) {\n case 'open': return 'Submitted';\n case 'in_progress': return 'Open';\n case 'closed': return 'Closed';\n default: return 'Submitted';\n }\n }\n // User Stories / Tasks use ScheduleState: Defined, In-Progress, Completed\n switch (state) {\n case 'open': return 'Defined';\n case 'in_progress': return 'In-Progress';\n case 'closed': return 'Completed';\n default: return 'Defined';\n }\n }\n\n // Rally API wrapper methods\n private async queryRally(queryConfig: any): Promise<any> {\n const result = await this.restApi.query(queryConfig);\n // Extract Results from WSAPI response format\n return {\n Results: result.QueryResult.Results,\n TotalResultCount: result.QueryResult.TotalResultCount,\n };\n }\n\n private async createRally(type: string, data: any): Promise<any> {\n const result = await this.restApi.create({\n type,\n data,\n fetch: ['FormattedID', 'ObjectID', '_ref'],\n });\n // Extract Object from WSAPI response format\n return {\n Object: result.CreateResult.Object,\n };\n }\n\n private async updateRally(type: string, ref: string, data: any): Promise<any> {\n const result = await this.restApi.update({\n type,\n ref,\n data,\n fetch: ['FormattedID', 'ObjectID'],\n });\n // Extract Object from WSAPI response format\n return {\n Object: result.OperationResult.Object,\n };\n }\n}\n","/**\n * Tracker Factory\n *\n * Creates appropriate tracker instances based on configuration.\n */\n\nimport type { IssueTracker, TrackerType } from './interface.js';\nimport { TrackerAuthError } from './interface.js';\nimport { LinearTracker } from './linear.js';\nimport { GitHubTracker } from './github.js';\nimport { GitLabTracker } from './gitlab.js';\nimport { RallyTracker } from './rally.js';\nimport type { TrackersConfig } from '../config.js';\nimport { loadConfig as loadYamlConfig } from '../config-yaml.js';\n\n// Configuration for a single tracker\nexport interface TrackerConfig {\n type: TrackerType;\n\n // Linear-specific\n apiKeyEnv?: string;\n team?: string;\n\n // GitHub-specific\n tokenEnv?: string;\n owner?: string;\n repo?: string;\n\n // GitLab-specific\n projectId?: string;\n\n // Rally-specific\n server?: string;\n workspace?: string;\n project?: string;\n}\n\n// Multi-tracker configuration (re-exported from config.ts)\n// Note: Use TrackersConfig from config.ts for full type with nested configs\n\n/**\n * Get tracker API key from config.yaml (Settings page).\n * This is checked FIRST — env vars are the fallback, not the other way around.\n */\nfunction getTrackerKeyFromConfig(trackerType: TrackerType): string | undefined {\n try {\n const yamlConfig = loadYamlConfig();\n return yamlConfig.trackerKeys[trackerType];\n } catch {\n return undefined;\n }\n}\n\n/**\n * Create a tracker instance from configuration.\n * Priority: config.yaml (Settings) > environment variable > custom env var name\n */\nexport function createTracker(config: TrackerConfig): IssueTracker {\n switch (config.type) {\n case 'linear': {\n const configKey = getTrackerKeyFromConfig('linear');\n const envKey = config.apiKeyEnv\n ? process.env[config.apiKeyEnv]\n : process.env.LINEAR_API_KEY;\n const apiKey = configKey || envKey;\n\n if (!apiKey) {\n throw new TrackerAuthError(\n 'linear',\n `API key not found. Configure in Settings or set ${config.apiKeyEnv ?? 'LINEAR_API_KEY'} environment variable.`\n );\n }\n\n return new LinearTracker(apiKey, { team: config.team });\n }\n\n case 'github': {\n const configKey = getTrackerKeyFromConfig('github');\n const envToken = config.tokenEnv\n ? process.env[config.tokenEnv]\n : process.env.GITHUB_TOKEN;\n const token = configKey || envToken;\n\n if (!token) {\n throw new TrackerAuthError(\n 'github',\n `Token not found. Configure in Settings or set ${config.tokenEnv ?? 'GITHUB_TOKEN'} environment variable.`\n );\n }\n\n if (!config.owner || !config.repo) {\n throw new Error(\n 'GitHub tracker requires owner and repo configuration'\n );\n }\n\n return new GitHubTracker(token, config.owner, config.repo);\n }\n\n case 'gitlab': {\n const configKey = getTrackerKeyFromConfig('gitlab');\n const envToken = config.tokenEnv\n ? process.env[config.tokenEnv]\n : process.env.GITLAB_TOKEN;\n const token = configKey || envToken;\n\n if (!token) {\n throw new TrackerAuthError(\n 'gitlab',\n `Token not found. Configure in Settings or set ${config.tokenEnv ?? 'GITLAB_TOKEN'} environment variable.`\n );\n }\n\n if (!config.projectId) {\n throw new Error('GitLab tracker requires projectId configuration');\n }\n\n return new GitLabTracker(token, config.projectId);\n }\n\n case 'rally': {\n const configKey = getTrackerKeyFromConfig('rally');\n const envKey = config.apiKeyEnv\n ? process.env[config.apiKeyEnv]\n : process.env.RALLY_API_KEY;\n const apiKey = configKey || envKey;\n\n if (!apiKey) {\n throw new TrackerAuthError(\n 'rally',\n `API key not found. Configure in Settings or set ${config.apiKeyEnv ?? 'RALLY_API_KEY'} environment variable.`\n );\n }\n\n return new RallyTracker({\n apiKey,\n server: config.server,\n workspace: config.workspace,\n project: config.project,\n });\n }\n\n default:\n throw new Error(`Unknown tracker type: ${config.type}`);\n }\n}\n\n/**\n * Create tracker from trackers configuration section\n */\nexport function createTrackerFromConfig(\n trackersConfig: TrackersConfig,\n trackerType: TrackerType\n): IssueTracker {\n const config = trackersConfig[trackerType];\n\n if (!config) {\n throw new Error(\n `No configuration found for tracker: ${trackerType}. Add [trackers.${trackerType}] to config.`\n );\n }\n\n return createTracker({ ...config, type: trackerType });\n}\n\n/**\n * Get the primary tracker from configuration\n */\nexport function getPrimaryTracker(trackersConfig: TrackersConfig): IssueTracker {\n return createTrackerFromConfig(trackersConfig, trackersConfig.primary);\n}\n\n/**\n * Get the secondary tracker from configuration (if configured)\n */\nexport function getSecondaryTracker(\n trackersConfig: TrackersConfig\n): IssueTracker | null {\n if (!trackersConfig.secondary) {\n return null;\n }\n return createTrackerFromConfig(trackersConfig, trackersConfig.secondary);\n}\n\n/**\n * Get all configured trackers\n */\nexport function getAllTrackers(trackersConfig: TrackersConfig): IssueTracker[] {\n const trackers: IssueTracker[] = [getPrimaryTracker(trackersConfig)];\n\n const secondary = getSecondaryTracker(trackersConfig);\n if (secondary) {\n trackers.push(secondary);\n }\n\n return trackers;\n}\n"],"mappings":"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","names":["STATE_MAP"]}
@@ -6,8 +6,8 @@ import {
6
6
  init_work_type_router,
7
7
  popFromHook,
8
8
  pushToHook,
9
- sendKeys
10
- } from "./chunk-ON5NIBGW.js";
9
+ sendKeysAsync
10
+ } from "./chunk-VIWUCJ4V.js";
11
11
  import {
12
12
  init_projects,
13
13
  projects_exports
@@ -553,9 +553,9 @@ function recordWake(name, sessionId) {
553
553
  }
554
554
  async function spawnEphemeralSpecialist(projectKey, specialistType, task) {
555
555
  ensureProjectSpecialistDir(projectKey, specialistType);
556
- const { loadContextDigest } = await import("./specialist-context-WXO3FKIB.js");
556
+ const { loadContextDigest } = await import("./specialist-context-6SE5VRRC.js");
557
557
  const contextDigest = loadContextDigest(projectKey, specialistType);
558
- const { createRunLog: createRunLog2 } = await import("./specialist-logs-SJWLETJT.js");
558
+ const { createRunLog: createRunLog2 } = await import("./specialist-logs-EXLOQHQ2.js");
559
559
  const { runId, filePath: logFilePath } = createRunLog2(
560
560
  projectKey,
561
561
  specialistType,
@@ -596,7 +596,7 @@ echo "## Specialist completed task"
596
596
  `tmux new-session -d -s "${tmuxSession}" "bash '${launcherScript}'"`,
597
597
  { encoding: "utf-8" }
598
598
  );
599
- const { saveAgentRuntimeState } = await import("./agents-ND4NKCK2.js");
599
+ const { saveAgentRuntimeState } = await import("./agents-GQDAKTEQ.js");
600
600
  saveAgentRuntimeState(tmuxSession, {
601
601
  state: "active",
602
602
  lastActivity: (/* @__PURE__ */ new Date()).toISOString(),
@@ -781,7 +781,7 @@ async function terminateSpecialist(projectKey, specialistType) {
781
781
  console.error(`[specialist] Failed to kill tmux session ${tmuxSession}:`, error);
782
782
  }
783
783
  if (metadata.currentRun) {
784
- const { finalizeRunLog: finalizeRunLog2 } = await import("./specialist-logs-SJWLETJT.js");
784
+ const { finalizeRunLog: finalizeRunLog2 } = await import("./specialist-logs-EXLOQHQ2.js");
785
785
  try {
786
786
  finalizeRunLog2(projectKey, specialistType, metadata.currentRun, {
787
787
  status: metadata.lastRunStatus || "incomplete",
@@ -794,19 +794,19 @@ async function terminateSpecialist(projectKey, specialistType) {
794
794
  }
795
795
  const key = `${projectKey}-${specialistType}`;
796
796
  gracePeriodStates.delete(key);
797
- const { saveAgentRuntimeState } = await import("./agents-ND4NKCK2.js");
797
+ const { saveAgentRuntimeState } = await import("./agents-GQDAKTEQ.js");
798
798
  saveAgentRuntimeState(tmuxSession, {
799
799
  state: "suspended",
800
800
  lastActivity: (/* @__PURE__ */ new Date()).toISOString()
801
801
  });
802
- const { scheduleDigestGeneration } = await import("./specialist-context-WXO3FKIB.js");
802
+ const { scheduleDigestGeneration } = await import("./specialist-context-6SE5VRRC.js");
803
803
  scheduleDigestGeneration(projectKey, specialistType);
804
804
  scheduleLogCleanup(projectKey, specialistType);
805
805
  }
806
806
  function scheduleLogCleanup(projectKey, specialistType) {
807
807
  Promise.resolve().then(async () => {
808
808
  try {
809
- const { cleanupOldLogs: cleanupOldLogs2 } = await import("./specialist-logs-SJWLETJT.js");
809
+ const { cleanupOldLogs: cleanupOldLogs2 } = await import("./specialist-logs-EXLOQHQ2.js");
810
810
  const { getSpecialistRetention } = await import("./projects-VXRUCMLM.js");
811
811
  const retention = getSpecialistRetention(projectKey);
812
812
  const deleted = cleanupOldLogs2(projectKey, specialistType, { maxDays: retention.max_days, maxRuns: retention.max_runs });
@@ -985,7 +985,7 @@ async function getSpecialistStatus(name, projectKey) {
985
985
  const sessionId = getSessionId(name);
986
986
  const running = await isRunning(name, projectKey);
987
987
  const contextTokens = countContextTokens(name);
988
- const { getAgentRuntimeState } = await import("./agents-ND4NKCK2.js");
988
+ const { getAgentRuntimeState } = await import("./agents-GQDAKTEQ.js");
989
989
  const tmuxSession = getTmuxSessionName(name, projectKey);
990
990
  const runtimeState = getAgentRuntimeState(tmuxSession);
991
991
  let state;
@@ -1118,7 +1118,7 @@ async function resetSpecialist(name) {
1118
1118
  try {
1119
1119
  await execAsync(`tmux send-keys -t "${tmuxSession}" C-c`, { encoding: "utf-8" });
1120
1120
  await new Promise((resolve) => setTimeout(resolve, 200));
1121
- sendKeys(tmuxSession, "cd ~");
1121
+ await sendKeysAsync(tmuxSession, "cd ~");
1122
1122
  await new Promise((resolve) => setTimeout(resolve, 200));
1123
1123
  await execAsync(`tmux send-keys -t "${tmuxSession}" C-u`, { encoding: "utf-8" });
1124
1124
  await new Promise((resolve) => setTimeout(resolve, 100));
@@ -1172,12 +1172,12 @@ async function wakeSpecialist(name, taskPrompt, options = {}) {
1172
1172
  const taskFile = join4(TASKS_DIR, `${name}-${Date.now()}.md`);
1173
1173
  writeFileSync(taskFile, taskPrompt, "utf-8");
1174
1174
  const shortMessage = `Read and execute the task in: ${taskFile}`;
1175
- sendKeys(tmuxSession, shortMessage);
1175
+ await sendKeysAsync(tmuxSession, shortMessage);
1176
1176
  } else {
1177
- sendKeys(tmuxSession, taskPrompt);
1177
+ await sendKeysAsync(tmuxSession, taskPrompt);
1178
1178
  }
1179
1179
  recordWake(name, sessionId || void 0);
1180
- const { saveAgentRuntimeState } = await import("./agents-ND4NKCK2.js");
1180
+ const { saveAgentRuntimeState } = await import("./agents-GQDAKTEQ.js");
1181
1181
  saveAgentRuntimeState(tmuxSession, {
1182
1182
  state: "active",
1183
1183
  lastActivity: (/* @__PURE__ */ new Date()).toISOString(),
@@ -1247,7 +1247,7 @@ Use the send-feedback-to-agent skill to report findings back to the issue agent.
1247
1247
  });
1248
1248
  console.log(`[specialist] review-agent: auto-passed ${task.issueId} (stale branch)`);
1249
1249
  const tmuxSession = getTmuxSessionName("review-agent");
1250
- const { saveAgentRuntimeState } = await import("./agents-ND4NKCK2.js");
1250
+ const { saveAgentRuntimeState } = await import("./agents-GQDAKTEQ.js");
1251
1251
  saveAgentRuntimeState(tmuxSession, {
1252
1252
  state: "idle",
1253
1253
  lastActivity: (/* @__PURE__ */ new Date()).toISOString()
@@ -1414,7 +1414,7 @@ IMPORTANT: Do NOT hand off to merge-agent. Human clicks Merge button when ready.
1414
1414
  async function wakeSpecialistOrQueue(name, task, options = {}) {
1415
1415
  const { priority = "normal", source = "handoff" } = options;
1416
1416
  const running = await isRunning(name);
1417
- const { getAgentRuntimeState } = await import("./agents-ND4NKCK2.js");
1417
+ const { getAgentRuntimeState } = await import("./agents-GQDAKTEQ.js");
1418
1418
  const tmuxSession = getTmuxSessionName(name);
1419
1419
  const runtimeState = getAgentRuntimeState(tmuxSession);
1420
1420
  const idle = runtimeState?.state === "idle" || runtimeState?.state === "suspended";
@@ -1445,7 +1445,7 @@ async function wakeSpecialistOrQueue(name, task, options = {}) {
1445
1445
  };
1446
1446
  }
1447
1447
  }
1448
- const { saveAgentRuntimeState } = await import("./agents-ND4NKCK2.js");
1448
+ const { saveAgentRuntimeState } = await import("./agents-GQDAKTEQ.js");
1449
1449
  saveAgentRuntimeState(tmuxSession, {
1450
1450
  state: "active",
1451
1451
  lastActivity: (/* @__PURE__ */ new Date()).toISOString(),
@@ -1543,15 +1543,36 @@ async function sendFeedbackToAgent(feedback) {
1543
1543
  console.error(`[specialist] Failed to log feedback:`, error);
1544
1544
  }
1545
1545
  const agentSession = `agent-${toIssueId.toLowerCase()}`;
1546
+ const feedbackMessage = formatFeedbackForAgent(fullFeedback);
1547
+ const { writeFeedbackFile } = await import("./feedback-writer-AAKF5BTK.js");
1548
+ const specialistMap = {
1549
+ "review-agent": "review-agent",
1550
+ "test-agent": "test-agent",
1551
+ "merge-agent": "merge-agent"
1552
+ };
1553
+ const specialist = specialistMap[fromSpecialist] || "review-agent";
1554
+ const outcome = feedback.feedbackType === "success" ? "approved" : feedback.feedbackType === "failure" ? "failed" : feedback.feedbackType;
1555
+ const fileResult = await writeFeedbackFile({
1556
+ issueId: toIssueId,
1557
+ specialist,
1558
+ outcome,
1559
+ summary: summary.slice(0, 100),
1560
+ markdownBody: feedbackMessage
1561
+ });
1562
+ if (!fileResult.success) {
1563
+ console.error(`[specialist] Failed to write feedback file for ${toIssueId}: ${fileResult.error}`);
1564
+ return false;
1565
+ }
1546
1566
  try {
1547
- const { messageAgent } = await import("./agents-ND4NKCK2.js");
1548
- const feedbackMessage = formatFeedbackForAgent(fullFeedback);
1549
- await messageAgent(agentSession, feedbackMessage);
1550
- console.log(`[specialist] Sent feedback from ${fromSpecialist} to ${agentSession}`);
1567
+ const { messageAgent } = await import("./agents-GQDAKTEQ.js");
1568
+ const msg = `SPECIALIST FEEDBACK: ${fromSpecialist} reported ${feedback.feedbackType.toUpperCase()} for ${toIssueId}.
1569
+ Read and address: ${fileResult.relativePath}`;
1570
+ await messageAgent(agentSession, msg);
1571
+ console.log(`[specialist] Sent feedback from ${fromSpecialist} to ${agentSession} (file: ${fileResult.relativePath})`);
1551
1572
  return true;
1552
1573
  } catch (err) {
1553
- console.log(`[specialist] Could not send feedback to ${agentSession}:`, err);
1554
- return false;
1574
+ console.log(`[specialist] Could not send reference to ${agentSession} (file written): ${err}`);
1575
+ return true;
1555
1576
  }
1556
1577
  }
1557
1578
  function formatFeedbackForAgent(feedback) {
@@ -2034,4 +2055,4 @@ export {
2034
2055
  getFeedbackStats,
2035
2056
  init_specialists
2036
2057
  };
2037
- //# sourceMappingURL=chunk-4KNEZGKZ.js.map
2058
+ //# sourceMappingURL=chunk-TMXN7THF.js.map