maxsimcli 4.7.0 → 4.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +0,0 @@
1
- {"version":3,"file":"server-BAHfh_vw.cjs","names":["execFile","planningPath","fs","path","fail","fail","path","fs","z","findPhaseInternal","phasesPath","fs","listSubDirs","getArchivedPhaseDirs","comparePhaseNum","phaseAddCore","phaseInsertCore","phaseCompleteCore","updateLocalMappingStatus","findIssueInMapping","z","planningPath","todayISO","generateSlugInternal","path","fs","parseTodoFrontmatter","z","statePath","fs","stateExtractField","escapeStringRegexp","stateReplaceField","appendToStateSection","cmdRoadmapAnalyze","safeReadFile","planningPath","stateExtractField","z","loadConfig","findPhaseInternal","path","cmdContextLoad","fs","cmdRoadmapAnalyze","z","cmdConfigGet","loadConfig","cmdConfigSet","path","z","findIssueInMapping","z","fs","path","path","fs","getPhasePattern","normalizePhaseName","stateExtractField","comparePhaseNum","extractFrontmatter","WebSocketServer","WebSocket","stateReplaceField","McpServer","StreamableHTTPServerTransport","ws","os"],"sources":["../src/github/gh.ts","../src/github/mapping.ts","../src/github/issues.ts","../src/github/projects.ts","../src/github/milestones.ts","../src/github/sync.ts","../src/mcp/utils.ts","../src/mcp/phase-tools.ts","../src/mcp/todo-tools.ts","../src/mcp/state-tools.ts","../src/mcp/context-tools.ts","../src/mcp/roadmap-tools.ts","../src/mcp/config-tools.ts","../src/github/types.ts","../src/github/labels.ts","../src/github/templates.ts","../src/mcp/github-tools.ts","../src/mcp/board-tools.ts","../src/mcp/index.ts","../../../node_modules/node-pty/lib/utils.js","../../../node_modules/node-pty/lib/eventEmitter2.js","../../../node_modules/node-pty/lib/terminal.js","../../../node_modules/node-pty/lib/shared/conout.js","../../../node_modules/node-pty/lib/windowsConoutConnection.js","../../../node_modules/node-pty/lib/windowsPtyAgent.js","../../../node_modules/node-pty/lib/windowsTerminal.js","../../../node_modules/node-pty/lib/unixTerminal.js","../../../node_modules/node-pty/lib/index.js","../src/backend/terminal.ts","../src/backend/server.ts"],"sourcesContent":["/**\n * GitHub CLI Wrapper — Core gh CLI interaction layer\n *\n * Wraps the `gh` CLI using `child_process.execFile` (never `exec`) for security.\n * Provides typed results via GhResult<T> discriminated union.\n * Supports graceful degradation: detectGitHubMode() returns 'local-only'\n * when gh is not installed or not authenticated with required scopes.\n *\n * CRITICAL: Never import octokit or any npm GitHub SDK.\n * CRITICAL: Never call process.exit() — return GhResult instead.\n */\n\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nimport type { AuthStatus, GhErrorCode, GhResult, GitHubMode } from './types.js';\n\nconst execFileAsync = promisify(execFile);\n\n// ---- Auth check ------------------------------------------------------------\n\n/**\n * Check if the `gh` CLI is installed and authenticated with required scopes.\n *\n * Parses the output of `gh auth status` (which writes to stderr, not stdout).\n * Returns structured AuthStatus with scope detection for 'project' scope.\n * Timeout: 10 seconds.\n */\nexport async function checkGhAuth(): Promise<AuthStatus> {\n try {\n const { stdout, stderr } = await execFileAsync('gh', ['auth', 'status'], {\n timeout: 10_000,\n });\n\n // gh auth status writes to stderr (not stdout)\n const output = stderr || stdout;\n\n const authenticated = !output.includes('not logged in');\n\n // Parse scopes from \"Token scopes: 'scope1', 'scope2', ...\"\n const scopeMatch = output.match(/Token scopes?:\\s*'([^']+(?:',\\s*'[^']+)*)'/);\n const scopes: string[] = [];\n if (scopeMatch) {\n // Extract all quoted scope values\n const allScopes = scopeMatch[0].matchAll(/'([^']+)'/g);\n for (const m of allScopes) {\n scopes.push(m[1]);\n }\n }\n\n // Parse username from \"Logged in to github.com as USERNAME\"\n const userMatch = output.match(/Logged in to [^\\s]+ as ([^\\s(]+)/);\n\n return {\n installed: true,\n authenticated,\n scopes,\n hasProjectScope: scopes.includes('project') || scopes.includes('read:project'),\n username: userMatch ? userMatch[1] : null,\n };\n } catch (e: unknown) {\n const error = e as { code?: string; stderr?: string; message?: string };\n\n // ENOENT = gh CLI not found on PATH\n if (error.code === 'ENOENT') {\n return {\n installed: false,\n authenticated: false,\n scopes: [],\n hasProjectScope: false,\n username: null,\n };\n }\n\n // gh auth status exits with code 1 when not authenticated.\n // It may still write useful stderr — try to parse it.\n const output = error.stderr || error.message || '';\n\n // If stderr mentions \"not logged in\" or exit code 1, treat as not authenticated\n return {\n installed: true,\n authenticated: false,\n scopes: [],\n hasProjectScope: false,\n username: null,\n };\n }\n}\n\n// ---- Mode detection --------------------------------------------------------\n\n/**\n * Detect the GitHub integration mode based on auth status.\n *\n * Returns 'full' only when gh is installed, authenticated, and has the\n * 'project' scope. Otherwise returns 'local-only' for graceful degradation.\n */\nexport async function detectGitHubMode(): Promise<GitHubMode> {\n const auth = await checkGhAuth();\n\n if (!auth.installed) {\n return 'local-only';\n }\n\n if (!auth.authenticated) {\n return 'local-only';\n }\n\n if (!auth.hasProjectScope) {\n // Warn to stderr (not stdout — stdout is reserved for MCP JSON-RPC)\n console.error(\n \"[maxsim] GitHub Projects requires 'project' scope. Run: gh auth refresh -s project\",\n );\n return 'local-only';\n }\n\n return 'full';\n}\n\n// ---- gh CLI exec -----------------------------------------------------------\n\n/**\n * Execute a `gh` CLI command and return a typed GhResult.\n *\n * - Uses `execFile` (not `exec`) for security\n * - Default timeout: 30 seconds\n * - Auto-detects JSON output when args contain `--json` or `--format`\n * - Maps exit codes and stderr patterns to GhErrorCode\n * - For `gh issue create`: does NOT try to parse JSON (it returns a URL string)\n * - Always includes raw stderr in error messages for AI consumption\n */\nexport async function ghExec<T = string>(\n args: string[],\n options?: {\n cwd?: string;\n parseJson?: boolean;\n timeout?: number;\n },\n): Promise<GhResult<T>> {\n const timeout = options?.timeout ?? 30_000;\n\n // Detect if output should be parsed as JSON\n const isIssueCreate = args[0] === 'issue' && args[1] === 'create';\n const hasJsonFlag = args.includes('--json') || args.some(a => a.startsWith('--format'));\n const shouldParseJson = options?.parseJson ?? (hasJsonFlag && !isIssueCreate);\n\n try {\n const { stdout, stderr } = await execFileAsync('gh', args, {\n cwd: options?.cwd,\n timeout,\n maxBuffer: 10 * 1024 * 1024, // 10 MB\n });\n\n if (shouldParseJson) {\n try {\n const parsed = JSON.parse(stdout) as T;\n return { ok: true, data: parsed };\n } catch {\n return {\n ok: false,\n error: `Failed to parse gh output as JSON: ${stdout.slice(0, 500)}`,\n code: 'UNKNOWN',\n };\n }\n }\n\n return { ok: true, data: stdout.trim() as unknown as T };\n } catch (e: unknown) {\n return mapExecError(e);\n }\n}\n\n// ---- GraphQL ---------------------------------------------------------------\n\n/**\n * Execute a GraphQL query via `gh api graphql`.\n *\n * - String variables use `-f key=value`\n * - Non-string variables (numbers, booleans) use `-F key=value`\n * - Parses JSON response and checks for GraphQL `errors` array\n */\nexport async function ghGraphQL<T = unknown>(\n query: string,\n variables?: Record<string, unknown>,\n): Promise<GhResult<T>> {\n const args: string[] = ['api', 'graphql', '-f', `query=${query}`];\n\n if (variables) {\n for (const [key, value] of Object.entries(variables)) {\n if (typeof value === 'string') {\n args.push('-f', `${key}=${value}`);\n } else {\n // -F for non-string types (numbers, booleans, etc.)\n args.push('-F', `${key}=${String(value)}`);\n }\n }\n }\n\n const result = await ghExec<{ data?: T; errors?: Array<{ message: string }> }>(args, {\n parseJson: true,\n });\n\n if (!result.ok) {\n return result;\n }\n\n // Check for GraphQL-level errors\n if (result.data.errors && result.data.errors.length > 0) {\n const messages = result.data.errors.map(e => e.message).join('; ');\n const code = mapGraphQLErrorCode(messages);\n return { ok: false, error: `GraphQL error: ${messages}`, code };\n }\n\n if (result.data.data === undefined) {\n return { ok: false, error: 'GraphQL response missing data field', code: 'UNKNOWN' };\n }\n\n return { ok: true, data: result.data.data };\n}\n\n// ---- Error mapping ---------------------------------------------------------\n\n/**\n * Map an execFile error to a GhResult with appropriate GhErrorCode.\n */\nfunction mapExecError<T>(e: unknown): GhResult<T> {\n const error = e as {\n code?: string;\n stderr?: string;\n stdout?: string;\n message?: string;\n status?: number;\n };\n\n // gh CLI not found\n if (error.code === 'ENOENT') {\n return {\n ok: false,\n error: 'gh CLI is not installed. Install from https://cli.github.com/',\n code: 'NOT_INSTALLED',\n };\n }\n\n const stderr = error.stderr || error.message || '';\n const exitCode = error.status;\n\n // Exit code 4 = not found (gh convention)\n if (exitCode === 4) {\n return { ok: false, error: `Not found: ${stderr}`, code: 'NOT_FOUND' };\n }\n\n // Pattern matching on stderr for specific error types\n if (\n stderr.includes('not logged in') ||\n stderr.includes('authentication') ||\n stderr.includes('auth login') ||\n stderr.includes('401')\n ) {\n return { ok: false, error: `Authentication required: ${stderr}`, code: 'NOT_AUTHENTICATED' };\n }\n\n if (stderr.includes('403') || stderr.includes('permission') || stderr.includes('denied')) {\n return { ok: false, error: `Permission denied: ${stderr}`, code: 'PERMISSION_DENIED' };\n }\n\n if (stderr.includes('rate limit') || stderr.includes('429') || stderr.includes('API rate')) {\n return { ok: false, error: `Rate limited: ${stderr}`, code: 'RATE_LIMITED' };\n }\n\n if (stderr.includes('scope') || stderr.includes('insufficient')) {\n return { ok: false, error: `Missing scope: ${stderr}`, code: 'SCOPE_MISSING' };\n }\n\n if (stderr.includes('not found') || stderr.includes('404') || stderr.includes('Could not resolve')) {\n return { ok: false, error: `Not found: ${stderr}`, code: 'NOT_FOUND' };\n }\n\n return { ok: false, error: `gh command failed: ${stderr}`, code: 'UNKNOWN' };\n}\n\n/**\n * Map GraphQL error messages to GhErrorCode.\n */\nfunction mapGraphQLErrorCode(message: string): GhErrorCode {\n const lower = message.toLowerCase();\n\n if (lower.includes('not found') || lower.includes('could not resolve')) {\n return 'NOT_FOUND';\n }\n if (lower.includes('insufficient') || lower.includes('scope')) {\n return 'SCOPE_MISSING';\n }\n if (lower.includes('forbidden') || lower.includes('permission')) {\n return 'PERMISSION_DENIED';\n }\n if (lower.includes('rate') || lower.includes('throttl')) {\n return 'RATE_LIMITED';\n }\n\n return 'UNKNOWN';\n}\n","/**\n * GitHub Issues Mapping — Persistence layer for github-issues.json\n *\n * Manages the `.planning/github-issues.json` file that maps MAXSIM tasks/todos\n * to their corresponding GitHub issue numbers, node IDs, and project item IDs.\n *\n * All file operations use synchronous fs (matching the pattern in existing core modules).\n * Uses planningPath() from core to construct file paths.\n *\n * CRITICAL: Never call process.exit() — throw or return null instead.\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport { planningPath } from '../core/core.js';\nimport type { IssueMappingFile, PhaseMapping, TaskIssueMapping } from './types.js';\n\n// ---- Constants -------------------------------------------------------------\n\nconst MAPPING_FILENAME = 'github-issues.json';\n\n// ---- Helpers ---------------------------------------------------------------\n\n/**\n * Get the absolute path to `.planning/github-issues.json` for a given cwd.\n */\nfunction mappingFilePath(cwd: string): string {\n return planningPath(cwd, MAPPING_FILENAME);\n}\n\n// ---- Public API ------------------------------------------------------------\n\n/**\n * Load and parse the mapping file.\n *\n * Returns null if the file does not exist.\n * Throws on malformed JSON or invalid structure (missing required fields).\n */\nexport function loadMapping(cwd: string): IssueMappingFile | null {\n const filePath = mappingFilePath(cwd);\n\n try {\n fs.statSync(filePath);\n } catch {\n return null;\n }\n\n const raw = fs.readFileSync(filePath, 'utf-8');\n const parsed = JSON.parse(raw) as Record<string, unknown>;\n\n // Validate basic structure — must have project_number and repo\n if (typeof parsed.project_number !== 'number' || typeof parsed.repo !== 'string') {\n throw new Error(\n `Invalid github-issues.json: missing required fields 'project_number' (number) and 'repo' (string)`,\n );\n }\n\n return parsed as unknown as IssueMappingFile;\n}\n\n/**\n * Write the mapping file to `.planning/github-issues.json`.\n *\n * Creates the `.planning/` directory if it does not exist.\n * Writes with 2-space indent for readability and diff-friendliness.\n */\nexport function saveMapping(cwd: string, mapping: IssueMappingFile): void {\n const filePath = mappingFilePath(cwd);\n const dir = path.dirname(filePath);\n\n fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(filePath, JSON.stringify(mapping, null, 2) + '\\n', 'utf-8');\n}\n\n/**\n * Update a specific task's issue mapping within a phase.\n *\n * Load-modify-save pattern. Creates phase entry if it does not exist.\n * Merges partial data with existing entry (if any).\n *\n * @throws If mapping file does not exist (must be initialized first via saveMapping)\n */\nexport function updateTaskMapping(\n cwd: string,\n phaseNum: string,\n taskId: string,\n data: Partial<TaskIssueMapping>,\n): void {\n const mapping = loadMapping(cwd);\n if (!mapping) {\n throw new Error('github-issues.json does not exist. Run project setup first.');\n }\n\n // Create phase entry if missing\n if (!mapping.phases[phaseNum]) {\n mapping.phases[phaseNum] = {\n tracking_issue: { number: 0, node_id: '', item_id: '', status: 'To Do' },\n plan: '',\n tasks: {},\n } satisfies PhaseMapping;\n }\n\n // Merge with existing task data (if any)\n const existing = mapping.phases[phaseNum].tasks[taskId];\n const defaults: TaskIssueMapping = { number: 0, node_id: '', item_id: '', status: 'To Do' };\n mapping.phases[phaseNum].tasks[taskId] = Object.assign(defaults, existing, data);\n\n saveMapping(cwd, mapping);\n}\n\n/**\n * Update a specific todo's issue mapping.\n *\n * Load-modify-save pattern. Creates `todos` section if missing.\n * Merges partial data with existing entry (if any).\n *\n * @throws If mapping file does not exist (must be initialized first via saveMapping)\n */\nexport function updateTodoMapping(\n cwd: string,\n todoId: string,\n data: Partial<TaskIssueMapping>,\n): void {\n const mapping = loadMapping(cwd);\n if (!mapping) {\n throw new Error('github-issues.json does not exist. Run project setup first.');\n }\n\n // Create todos section if missing\n if (!mapping.todos) {\n mapping.todos = {};\n }\n\n // Merge with existing todo data (if any)\n const existing = mapping.todos[todoId];\n const defaults: TaskIssueMapping = { number: 0, node_id: '', item_id: '', status: 'To Do' };\n mapping.todos[todoId] = Object.assign(defaults, existing, data);\n\n saveMapping(cwd, mapping);\n}\n\n/**\n * Create a properly typed empty mapping object with sensible defaults.\n *\n * Used during initial project setup to create the mapping file.\n */\nexport function createEmptyMapping(repo: string): IssueMappingFile {\n return {\n project_number: 0,\n project_id: '',\n repo,\n status_field_id: '',\n status_options: {},\n estimate_field_id: '',\n milestone_id: 0,\n milestone_title: '',\n labels: {},\n phases: {},\n todos: {},\n };\n}\n\n/**\n * Quick lookup: get the issue mapping for a specific task in a phase.\n *\n * Returns null if the mapping file, phase, or task does not exist.\n */\nexport function getIssueForTask(\n cwd: string,\n phaseNum: string,\n taskId: string,\n): TaskIssueMapping | null {\n const mapping = loadMapping(cwd);\n if (!mapping) return null;\n\n const phase = mapping.phases[phaseNum];\n if (!phase) return null;\n\n return phase.tasks[taskId] ?? null;\n}\n\n/**\n * Quick lookup: get the issue mapping for a specific todo.\n *\n * Returns null if the mapping file or todo does not exist.\n */\nexport function getIssueForTodo(cwd: string, todoId: string): TaskIssueMapping | null {\n const mapping = loadMapping(cwd);\n if (!mapping) return null;\n\n return mapping.todos?.[todoId] ?? null;\n}\n","/**\n * GitHub Issues — Issue CRUD, lifecycle, batch operations, and branch naming\n *\n * Provides all issue-related operations: creating task issues with full spec bodies,\n * parent tracking issues with live task lists, todo issues, comments, close/reopen,\n * import external issues, supersession handling, and branch naming.\n *\n * Uses `ghExec` from gh.ts for all GitHub CLI operations.\n * Uses mapping.ts for persisting issue-to-task associations.\n *\n * CRITICAL: `gh issue create` does NOT support --format json.\n * Parse the URL from stdout to extract issue number.\n * CRITICAL: Never call process.exit() — return GhResult instead.\n * CRITICAL: Never import octokit or any npm GitHub SDK.\n */\n\nimport type { GhResult } from './types.js';\nimport { ghExec } from './gh.js';\nimport { loadMapping, saveMapping } from './mapping.js';\n\n// ---- Helpers ---------------------------------------------------------------\n\n/**\n * Parse an issue number from a `gh issue create` stdout URL.\n *\n * `gh issue create` outputs a URL like:\n * https://github.com/owner/repo/issues/42\\n\n *\n * We trim whitespace and extract the last path segment as the issue number.\n */\nfunction parseIssueNumberFromUrl(stdout: string): number | null {\n const trimmed = stdout.trim();\n const lastSegment = trimmed.split('/').pop();\n if (!lastSegment) return null;\n const num = parseInt(lastSegment, 10);\n return Number.isNaN(num) ? null : num;\n}\n\n/**\n * After creating an issue (parsed number from URL), fetch its node_id\n * via `gh issue view {number} --json nodeId,number,url`.\n */\nasync function fetchIssueDetails(\n issueNumber: number,\n): Promise<GhResult<{ number: number; url: string; node_id: string }>> {\n const result = await ghExec<{ nodeId: string; number: number; url: string }>(\n ['issue', 'view', String(issueNumber), '--json', 'nodeId,number,url'],\n { parseJson: true },\n );\n\n if (!result.ok) return { ok: false, error: result.error, code: result.code };\n\n return {\n ok: true,\n data: {\n number: result.data.number,\n url: result.data.url,\n node_id: result.data.nodeId,\n },\n };\n}\n\n// ---- Issue Creation Functions -----------------------------------------------\n\n/**\n * Create a task issue with full specification body in collapsible details section.\n *\n * Title format: `[P{phaseNum}] {title}`\n * Body includes summary, actions, acceptance criteria, dependencies in `<details>`.\n * Labels: maxsim, phase-task.\n *\n * Returns the issue number, URL, and node_id.\n */\nexport async function createTaskIssue(opts: {\n title: string;\n phaseNum: string;\n planNum: string;\n taskId: string;\n summary: string;\n actions: string[];\n acceptanceCriteria: string[];\n dependencies?: number[];\n milestone?: string;\n projectTitle?: string;\n labels?: string[];\n estimate?: number;\n}): Promise<GhResult<{ number: number; url: string; node_id: string }>> {\n const issueTitle = `[P${opts.phaseNum}] ${opts.title}`;\n\n // Build the issue body with collapsible details section\n const depsSection =\n opts.dependencies && opts.dependencies.length > 0\n ? `\\n### Dependencies\\nDepends on: ${opts.dependencies.map(d => `#${d}`).join(', ')}\\n`\n : '';\n\n const estimateSection =\n opts.estimate !== undefined ? `\\n### Estimate\\n${opts.estimate} points\\n` : '';\n\n const body = `## Summary\n${opts.summary}\n\n<details>\n<summary>Full Specification</summary>\n\n### Actions\n${opts.actions.map(a => `- ${a}`).join('\\n')}\n\n### Acceptance Criteria\n${opts.acceptanceCriteria.map(c => `- [ ] ${c}`).join('\\n')}\n${depsSection}${estimateSection}\n</details>\n\n---\n*Phase: ${opts.phaseNum} | Plan: ${opts.planNum} | Task: ${opts.taskId}*\n*Generated by MAXSIM*`;\n\n // Build gh issue create args\n const args: string[] = ['issue', 'create', '--title', issueTitle, '--body', body];\n\n // Always add maxsim and phase-task labels\n args.push('--label', 'maxsim');\n args.push('--label', 'phase-task');\n\n // Add any additional labels\n if (opts.labels) {\n for (const label of opts.labels) {\n args.push('--label', label);\n }\n }\n\n // Optional milestone\n if (opts.milestone) {\n args.push('--milestone', opts.milestone);\n }\n\n // Optional project\n if (opts.projectTitle) {\n args.push('--project', opts.projectTitle);\n }\n\n // Create the issue — stdout is a URL, NOT JSON\n const createResult = await ghExec<string>(args);\n if (!createResult.ok) return { ok: false, error: createResult.error, code: createResult.code };\n\n // Parse issue number from URL\n const issueNumber = parseIssueNumberFromUrl(createResult.data);\n if (issueNumber === null) {\n return {\n ok: false,\n error: `Failed to parse issue number from gh output: ${createResult.data}`,\n code: 'UNKNOWN',\n };\n }\n\n // Fetch node_id via separate gh issue view call\n return fetchIssueDetails(issueNumber);\n}\n\n/**\n * Create a parent tracking issue for a phase with a live checkbox task list.\n *\n * Title format: `[Phase {phaseNum}] {phaseName}`\n * Body includes task list with checkbox links: `- [ ] #{childNumber}`\n * Labels: maxsim, phase-task.\n */\nexport async function createParentTrackingIssue(opts: {\n phaseNum: string;\n phaseName: string;\n childIssueNumbers: number[];\n milestone?: string;\n projectTitle?: string;\n}): Promise<GhResult<{ number: number; url: string; node_id: string }>> {\n const issueTitle = `[Phase ${opts.phaseNum}] ${opts.phaseName}`;\n\n const taskList = opts.childIssueNumbers.map(n => `- [ ] #${n}`).join('\\n');\n\n const body = `## Phase ${opts.phaseNum}: ${opts.phaseName}\n\n### Tasks\n${taskList}\n\n---\n*Phase tracking issue -- Generated by MAXSIM*`;\n\n const args: string[] = ['issue', 'create', '--title', issueTitle, '--body', body];\n args.push('--label', 'maxsim');\n args.push('--label', 'phase-task');\n\n if (opts.milestone) {\n args.push('--milestone', opts.milestone);\n }\n\n if (opts.projectTitle) {\n args.push('--project', opts.projectTitle);\n }\n\n const createResult = await ghExec<string>(args);\n if (!createResult.ok) return { ok: false, error: createResult.error, code: createResult.code };\n\n const issueNumber = parseIssueNumberFromUrl(createResult.data);\n if (issueNumber === null) {\n return {\n ok: false,\n error: `Failed to parse issue number from gh output: ${createResult.data}`,\n code: 'UNKNOWN',\n };\n }\n\n return fetchIssueDetails(issueNumber);\n}\n\n/**\n * Create a todo issue with a lighter body (no collapsible details section).\n *\n * Labels: maxsim, todo.\n */\nexport async function createTodoIssue(opts: {\n title: string;\n description?: string;\n acceptanceCriteria?: string[];\n milestone?: string;\n projectTitle?: string;\n}): Promise<GhResult<{ number: number; url: string; node_id: string }>> {\n let body = '';\n\n if (opts.description) {\n body += `${opts.description}\\n`;\n }\n\n if (opts.acceptanceCriteria && opts.acceptanceCriteria.length > 0) {\n body += `\\n### Acceptance Criteria\\n`;\n body += opts.acceptanceCriteria.map(c => `- [ ] ${c}`).join('\\n');\n body += '\\n';\n }\n\n body += `\\n---\\n*Generated by MAXSIM*`;\n\n const args: string[] = ['issue', 'create', '--title', opts.title, '--body', body];\n args.push('--label', 'maxsim');\n args.push('--label', 'todo');\n\n if (opts.milestone) {\n args.push('--milestone', opts.milestone);\n }\n\n if (opts.projectTitle) {\n args.push('--project', opts.projectTitle);\n }\n\n const createResult = await ghExec<string>(args);\n if (!createResult.ok) return { ok: false, error: createResult.error, code: createResult.code };\n\n const issueNumber = parseIssueNumberFromUrl(createResult.data);\n if (issueNumber === null) {\n return {\n ok: false,\n error: `Failed to parse issue number from gh output: ${createResult.data}`,\n code: 'UNKNOWN',\n };\n }\n\n return fetchIssueDetails(issueNumber);\n}\n\n// ---- Utility Functions (pure/simple) ----------------------------------------\n\n/**\n * Get the branch name for an issue.\n *\n * Format: `maxsim/issue-{issueNumber}-{slug}`\n * Pure function, no async needed.\n */\nexport function getIssueBranchName(issueNumber: number, slug: string): string {\n return `maxsim/issue-${issueNumber}-${slug}`;\n}\n\n/**\n * Build a PR description body with `Closes #{N}` lines for auto-close on merge (AC-08).\n *\n * This function is called by `mcp_create_pr` in Plan 04's github-tools.ts.\n */\nexport function buildPrBody(closesIssues: number[], additionalContent?: string): string {\n const closesLines = closesIssues.map(n => `Closes #${n}`).join('\\n');\n const content = additionalContent ? `\\n\\n${additionalContent}` : '';\n return `${closesLines}${content}`;\n}\n\n// ---- Lifecycle Functions ----------------------------------------------------\n\n/**\n * Close an issue with an optional reason.\n *\n * Reason defaults to 'completed' if not specified.\n */\nexport async function closeIssue(\n issueNumber: number,\n reason?: 'completed' | 'not_planned',\n): Promise<GhResult<void>> {\n const args: string[] = ['issue', 'close', String(issueNumber)];\n if (reason) {\n args.push('--reason', reason);\n }\n\n const result = await ghExec<string>(args);\n if (!result.ok) return { ok: false, error: result.error, code: result.code };\n return { ok: true, data: undefined };\n}\n\n/**\n * Reopen a closed issue.\n */\nexport async function reopenIssue(issueNumber: number): Promise<GhResult<void>> {\n const result = await ghExec<string>(['issue', 'reopen', String(issueNumber)]);\n if (!result.ok) return { ok: false, error: result.error, code: result.code };\n return { ok: true, data: undefined };\n}\n\n/**\n * Close an issue as superseded by a newer issue.\n *\n * 1. Posts \"Superseded by #{newIssueNumber}\" comment on old issue\n * 2. Adds 'superseded' label to old issue\n * 3. Closes old issue as completed\n * 4. Posts \"Replaces #{oldIssueNumber}\" comment on new issue\n *\n * Creates bidirectional cross-references.\n */\nexport async function closeIssueAsSuperseded(\n oldIssueNumber: number,\n newIssueNumber: number,\n): Promise<GhResult<void>> {\n // 1. Post cross-reference comment on old issue\n const commentResult = await postComment(\n oldIssueNumber,\n `Superseded by #${newIssueNumber}`,\n );\n if (!commentResult.ok) return { ok: false, error: commentResult.error, code: commentResult.code };\n\n // 2. Add superseded label\n const labelResult = await ghExec<string>([\n 'issue',\n 'edit',\n String(oldIssueNumber),\n '--add-label',\n 'superseded',\n ]);\n if (!labelResult.ok) return { ok: false, error: labelResult.error, code: labelResult.code };\n\n // 3. Close old issue\n const closeResult = await closeIssue(oldIssueNumber, 'completed');\n if (!closeResult.ok) return closeResult;\n\n // 4. Post cross-reference comment on new issue\n const replaceCommentResult = await postComment(\n newIssueNumber,\n `Replaces #${oldIssueNumber}`,\n );\n if (!replaceCommentResult.ok) return { ok: false, error: replaceCommentResult.error, code: replaceCommentResult.code };\n\n return { ok: true, data: undefined };\n}\n\n/**\n * Post a comment on an issue.\n */\nexport async function postComment(\n issueNumber: number,\n body: string,\n): Promise<GhResult<void>> {\n const result = await ghExec<string>([\n 'issue',\n 'comment',\n String(issueNumber),\n '--body',\n body,\n ]);\n if (!result.ok) return { ok: false, error: result.error, code: result.code };\n return { ok: true, data: undefined };\n}\n\n// ---- Import Function --------------------------------------------------------\n\n/**\n * Import an existing external GitHub issue into MAXSIM tracking.\n *\n * Reads the issue details and adds 'maxsim' and 'imported' labels.\n * Returns the issue details for the AI to decide placement.\n */\nexport async function importExternalIssue(\n issueNumber: number,\n): Promise<GhResult<{ number: number; title: string; labels: string[] }>> {\n // Fetch issue details\n const viewResult = await ghExec<{\n title: string;\n labels: Array<{ name: string }>;\n body: string;\n state: string;\n }>(['issue', 'view', String(issueNumber), '--json', 'title,labels,body,state'], {\n parseJson: true,\n });\n\n if (!viewResult.ok) return { ok: false, error: viewResult.error, code: viewResult.code };\n\n // Add maxsim and imported labels\n const labelResult = await ghExec<string>([\n 'issue',\n 'edit',\n String(issueNumber),\n '--add-label',\n 'maxsim,imported',\n ]);\n if (!labelResult.ok) return { ok: false, error: labelResult.error, code: labelResult.code };\n\n const existingLabels = viewResult.data.labels.map(l => l.name);\n const allLabels = Array.from(new Set([...existingLabels, 'maxsim', 'imported']));\n\n return {\n ok: true,\n data: {\n number: issueNumber,\n title: viewResult.data.title,\n labels: allLabels,\n },\n };\n}\n\n// ---- Parent Tracking Update -------------------------------------------------\n\n/**\n * Update the parent tracking issue's task list checkbox.\n *\n * Reads the parent issue body, finds `- [ ] #{childNumber}` or `- [x] #{childNumber}`,\n * toggles the checkbox, and updates the issue body via `gh issue edit`.\n */\nexport async function updateParentTaskList(\n parentIssueNumber: number,\n childIssueNumber: number,\n checked: boolean,\n): Promise<GhResult<void>> {\n // Read current body\n const viewResult = await ghExec<{ body: string }>(\n ['issue', 'view', String(parentIssueNumber), '--json', 'body'],\n { parseJson: true },\n );\n\n if (!viewResult.ok) return { ok: false, error: viewResult.error, code: viewResult.code };\n\n const currentBody = viewResult.data.body;\n\n // Build regex to match either checked or unchecked state for this child issue\n const checkboxPattern = new RegExp(\n `- \\\\[([ x])\\\\] #${childIssueNumber}\\\\b`,\n 'g',\n );\n\n const newCheckState = checked ? 'x' : ' ';\n const updatedBody = currentBody.replace(checkboxPattern, `- [${newCheckState}] #${childIssueNumber}`);\n\n if (updatedBody === currentBody) {\n // No matching task list entry found -- not necessarily an error\n return { ok: true, data: undefined };\n }\n\n // Update the issue body\n const editResult = await ghExec<string>([\n 'issue',\n 'edit',\n String(parentIssueNumber),\n '--body',\n updatedBody,\n ]);\n\n if (!editResult.ok) return { ok: false, error: editResult.error, code: editResult.code };\n return { ok: true, data: undefined };\n}\n\n// ---- Batch Operations -------------------------------------------------------\n\n/**\n * Create all issues for a plan at once (eager creation on plan finalization).\n *\n * 1. Creates all task issues with concurrency limit of 5 (rate limit safety).\n * 2. After all task issues created, creates parent tracking issue.\n * 3. Updates mapping file for all created issues.\n * 4. Returns parent issue number and all task issue numbers.\n *\n * Handles partial failures: continues batch, reports which failed.\n */\nexport async function createAllPlanIssues(opts: {\n phaseNum: string;\n planNum: string;\n phaseName: string;\n tasks: Array<{\n taskId: string;\n title: string;\n summary: string;\n actions: string[];\n acceptanceCriteria: string[];\n dependencies?: string[];\n estimate?: number;\n }>;\n milestone?: string;\n projectTitle?: string;\n cwd: string;\n}): Promise<\n GhResult<{\n parentIssue: number;\n taskIssues: Array<{ taskId: string; issueNumber: number }>;\n }>\n> {\n const BATCH_SIZE = 5;\n const results: Array<{ taskId: string; issueNumber: number; nodeId: string }> = [];\n const failures: Array<{ taskId: string; error: string }> = [];\n\n // Process tasks in batches of 5 for rate limit safety\n for (let i = 0; i < opts.tasks.length; i += BATCH_SIZE) {\n const batch = opts.tasks.slice(i, i + BATCH_SIZE);\n\n const batchPromises = batch.map(async task => {\n // Resolve task dependencies to issue numbers from already-created issues\n let depIssueNumbers: number[] | undefined;\n if (task.dependencies && task.dependencies.length > 0) {\n depIssueNumbers = task.dependencies\n .map(depId => {\n const found = results.find(r => r.taskId === depId);\n return found ? found.issueNumber : 0;\n })\n .filter(n => n > 0);\n }\n\n const result = await createTaskIssue({\n title: task.title,\n phaseNum: opts.phaseNum,\n planNum: opts.planNum,\n taskId: task.taskId,\n summary: task.summary,\n actions: task.actions,\n acceptanceCriteria: task.acceptanceCriteria,\n dependencies: depIssueNumbers,\n milestone: opts.milestone,\n projectTitle: opts.projectTitle,\n estimate: task.estimate,\n });\n\n return { taskId: task.taskId, result };\n });\n\n const batchResults = await Promise.all(batchPromises);\n\n for (const { taskId, result } of batchResults) {\n if (result.ok) {\n results.push({\n taskId,\n issueNumber: result.data.number,\n nodeId: result.data.node_id,\n });\n } else {\n failures.push({ taskId, error: result.error });\n }\n }\n }\n\n // If ALL tasks failed, return error\n if (results.length === 0) {\n return {\n ok: false,\n error: `All task issue creations failed: ${failures.map(f => `${f.taskId}: ${f.error}`).join('; ')}`,\n code: 'UNKNOWN',\n };\n }\n\n // Create parent tracking issue with all child issue numbers\n const childNumbers = results.map(r => r.issueNumber);\n const parentResult = await createParentTrackingIssue({\n phaseNum: opts.phaseNum,\n phaseName: opts.phaseName,\n childIssueNumbers: childNumbers,\n milestone: opts.milestone,\n projectTitle: opts.projectTitle,\n });\n\n if (!parentResult.ok) {\n return {\n ok: false,\n error: `Task issues created but parent tracking issue failed: ${parentResult.error}`,\n code: parentResult.code,\n };\n }\n\n // Update mapping file for all created issues\n const mapping = loadMapping(opts.cwd);\n if (mapping) {\n // Ensure phase entry exists\n if (!mapping.phases[opts.phaseNum]) {\n mapping.phases[opts.phaseNum] = {\n tracking_issue: { number: 0, node_id: '', item_id: '', status: 'To Do' },\n plan: '',\n tasks: {},\n };\n }\n\n // Update parent tracking issue\n mapping.phases[opts.phaseNum].tracking_issue = {\n number: parentResult.data.number,\n node_id: parentResult.data.node_id,\n item_id: '',\n status: 'To Do',\n };\n mapping.phases[opts.phaseNum].plan = `${opts.phaseNum}-${opts.planNum}`;\n\n // Update each task issue\n for (const r of results) {\n mapping.phases[opts.phaseNum].tasks[r.taskId] = {\n number: r.issueNumber,\n node_id: r.nodeId,\n item_id: '',\n status: 'To Do',\n };\n }\n\n saveMapping(opts.cwd, mapping);\n }\n\n // Build result with failure info if partial\n const taskIssues = results.map(r => ({ taskId: r.taskId, issueNumber: r.issueNumber }));\n\n return {\n ok: true,\n data: {\n parentIssue: parentResult.data.number,\n taskIssues,\n },\n };\n}\n\n/**\n * Supersede old plan's issues when a plan is re-planned (fresh issues per plan).\n *\n * 1. Load mapping to find old plan's issue numbers.\n * 2. For each old issue, close as superseded with cross-reference to new issue.\n * 3. Close old parent tracking issue as superseded.\n * 4. Update mapping: mark old entries, add new entries.\n */\nexport async function supersedePlanIssues(opts: {\n phaseNum: string;\n oldPlanNum: string;\n newPlanNum: string;\n newIssueNumbers: Array<{ taskId: string; issueNumber: number }>;\n cwd: string;\n}): Promise<GhResult<void>> {\n const mapping = loadMapping(opts.cwd);\n if (!mapping) {\n return {\n ok: false,\n error: 'github-issues.json does not exist. Run project setup first.',\n code: 'NOT_FOUND',\n };\n }\n\n const phase = mapping.phases[opts.phaseNum];\n if (!phase) {\n return {\n ok: false,\n error: `No phase ${opts.phaseNum} found in mapping file`,\n code: 'NOT_FOUND',\n };\n }\n\n // Check that this is the old plan\n const currentPlan = phase.plan;\n const expectedOldPlan = `${opts.phaseNum}-${opts.oldPlanNum}`;\n if (currentPlan !== expectedOldPlan) {\n return {\n ok: false,\n error: `Phase ${opts.phaseNum} is on plan '${currentPlan}', expected '${expectedOldPlan}'`,\n code: 'UNKNOWN',\n };\n }\n\n const failures: string[] = [];\n\n // Supersede each old task issue with corresponding new issue\n const oldTasks = Object.entries(phase.tasks);\n for (const [taskId, oldTask] of oldTasks) {\n // Find the corresponding new issue for this task\n const newIssue = opts.newIssueNumbers.find(n => n.taskId === taskId);\n if (!newIssue) {\n // No corresponding new issue — just close the old one\n const closeResult = await closeIssue(oldTask.number, 'completed');\n if (!closeResult.ok) {\n failures.push(`close task ${taskId} (#${oldTask.number}): ${closeResult.error}`);\n }\n continue;\n }\n\n const supersedeResult = await closeIssueAsSuperseded(\n oldTask.number,\n newIssue.issueNumber,\n );\n if (!supersedeResult.ok) {\n failures.push(\n `supersede task ${taskId} (#${oldTask.number} -> #${newIssue.issueNumber}): ${supersedeResult.error}`,\n );\n }\n }\n\n // Close old parent tracking issue\n if (phase.tracking_issue.number > 0) {\n // Find any new parent issue number (if available) for cross-reference\n // The new parent will be created separately, so we just close the old one\n const closeResult = await closeIssue(phase.tracking_issue.number, 'completed');\n if (!closeResult.ok) {\n failures.push(\n `close parent tracking issue #${phase.tracking_issue.number}: ${closeResult.error}`,\n );\n }\n }\n\n // Update mapping: update the plan reference\n phase.plan = `${opts.phaseNum}-${opts.newPlanNum}`;\n\n // Clear old task entries and add new ones\n phase.tasks = {};\n for (const newIssue of opts.newIssueNumbers) {\n phase.tasks[newIssue.taskId] = {\n number: newIssue.issueNumber,\n node_id: '',\n item_id: '',\n status: 'To Do',\n };\n }\n\n saveMapping(opts.cwd, mapping);\n\n if (failures.length > 0) {\n // Partial failure: mapping updated but some GitHub operations failed\n return {\n ok: false,\n error: `Partial failure during supersession: ${failures.join('; ')}`,\n code: 'UNKNOWN',\n };\n }\n\n return { ok: true, data: undefined };\n}\n","/**\n * GitHub Projects v2 — Board creation, field setup, and item management\n *\n * Manages GitHub Projects v2 boards for MAXSIM task tracking.\n * Uses `gh project` CLI commands for most operations, falling back to\n * `gh api graphql` for operations with no CLI equivalent (adding\n * single-select status options).\n *\n * One project board per repo (not per milestone). 4 columns:\n * To Do, In Progress, In Review, Done.\n *\n * CRITICAL: Never import octokit or any npm GitHub SDK.\n * CRITICAL: Never call process.exit() — return GhResult instead.\n */\n\nimport type { GhErrorCode, GhResult } from './types.js';\nimport { ghExec, ghGraphQL } from './gh.js';\nimport { loadMapping, saveMapping, createEmptyMapping } from './mapping.js';\n\n// ---- Helpers ---------------------------------------------------------------\n\n/**\n * Extract error info from a failed GhResult and re-wrap it for a different\n * generic type. This avoids TypeScript narrowing issues with discriminated\n * union property access.\n */\nfunction fail<T>(result: { ok: false; error: string; code: GhErrorCode }): GhResult<T> {\n return { ok: false, error: result.error, code: result.code };\n}\n\n// ---- Project Board Creation ------------------------------------------------\n\n/**\n * Create a new GitHub Projects v2 board.\n *\n * Runs `gh project create --owner @me --title \"{title}\" --format json`.\n * Returns the project number and node ID.\n */\nexport async function createProjectBoard(\n title: string,\n): Promise<GhResult<{ number: number; id: string }>> {\n const result = await ghExec<{ number: number; id: string }>(\n ['project', 'create', '--owner', '@me', '--title', title, '--format', 'json'],\n { parseJson: true },\n );\n\n if (!result.ok) {\n return result;\n }\n\n return { ok: true, data: { number: result.data.number, id: result.data.id } };\n}\n\n// ---- Ensure Project Board --------------------------------------------------\n\n/**\n * Ensure a project board exists, creating it if needed.\n *\n * Checks the mapping file for an existing project. If found, verifies it\n * still exists via `gh project view`. If not found, creates a new board\n * and sets up fields and status options.\n *\n * Returns the project number, ID, and whether it was newly created.\n */\nexport async function ensureProjectBoard(\n title: string,\n cwd: string,\n): Promise<GhResult<{ number: number; id: string; created: boolean }>> {\n // Check mapping file for existing project\n const mapping = loadMapping(cwd);\n\n if (mapping && mapping.project_number > 0 && mapping.project_id) {\n // Verify the project still exists\n const viewResult = await ghExec(\n ['project', 'view', String(mapping.project_number), '--owner', '@me', '--format', 'json'],\n { parseJson: true },\n );\n\n if (viewResult.ok) {\n return {\n ok: true,\n data: {\n number: mapping.project_number,\n id: mapping.project_id,\n created: false,\n },\n };\n }\n\n // Project was deleted — fall through to create a new one\n }\n\n // Create the project board\n const createResult = await createProjectBoard(title);\n if (!createResult.ok) {\n return fail(createResult);\n }\n\n const { number, id } = createResult.data;\n\n // Set up fields and status options\n const setupResult = await setupProjectFields(number, id, cwd);\n if (!setupResult.ok) {\n return fail(setupResult);\n }\n\n return { ok: true, data: { number, id, created: true } };\n}\n\n// ---- Field Queries ---------------------------------------------------------\n\ntype FieldInfo = {\n id: string;\n name: string;\n type: string;\n options?: Array<{ id: string; name: string }>;\n};\n\n/**\n * Get all fields for a project board.\n *\n * Runs `gh project field-list {num} --owner @me --format json`.\n * Returns field list with IDs, names, types, and options (for single-select).\n */\nexport async function getProjectFields(\n projectNum: number,\n): Promise<GhResult<FieldInfo[]>> {\n const result = await ghExec<{ fields: FieldInfo[] }>(\n ['project', 'field-list', String(projectNum), '--owner', '@me', '--format', 'json'],\n { parseJson: true },\n );\n\n if (!result.ok) {\n return fail(result);\n }\n\n // gh project field-list returns { fields: [...] } or a flat array in JSON format\n const fields = result.data.fields ?? (result.data as unknown as FieldInfo[]);\n\n return { ok: true, data: fields };\n}\n\n// ---- Status Option Management ----------------------------------------------\n\n/**\n * Add a new single-select option to a project field via GraphQL.\n *\n * The `updateProjectV2Field` mutation REPLACES all options, so all existing\n * options must be included alongside the new one.\n *\n * Returns the new option's ID.\n */\nexport async function addStatusOption(\n projectId: string,\n statusFieldId: string,\n optionName: string,\n existingOptions: Array<{ id: string; name: string }>,\n): Promise<GhResult<string>> {\n // Build the options array: existing + new\n // The mutation replaces all options, so we must include every existing one\n const allOptions = [\n ...existingOptions.map(o => `{name: \"${o.name}\", description: \"\", color: GRAY}`),\n `{name: \"${optionName}\", description: \"\", color: BLUE}`,\n ];\n\n const query = `\n mutation {\n updateProjectV2Field(input: {\n projectId: \"${projectId}\"\n fieldId: \"${statusFieldId}\"\n singleSelectOptions: [${allOptions.join(', ')}]\n }) {\n projectV2Field {\n ... on ProjectV2SingleSelectField {\n options { id name }\n }\n }\n }\n }\n `;\n\n const result = await ghGraphQL<{\n updateProjectV2Field: {\n projectV2Field: {\n options: Array<{ id: string; name: string }>;\n };\n };\n }>(query);\n\n if (!result.ok) {\n return fail(result);\n }\n\n const options = result.data.updateProjectV2Field.projectV2Field.options;\n const newOption = options.find(o => o.name === optionName);\n\n if (!newOption) {\n return {\n ok: false,\n error: `Option \"${optionName}\" was not found after mutation — it may have been renamed or rejected`,\n code: 'UNKNOWN',\n };\n }\n\n return { ok: true, data: newOption.id };\n}\n\n// ---- Field Setup Orchestration ---------------------------------------------\n\n/**\n * Set up project fields: Status options and Estimate number field.\n *\n * Orchestrates the full field setup:\n * (a) Get existing fields\n * (b) Find Status field, verify \"In Review\" option exists or add it\n * (c) Create Estimate NUMBER field via `gh project field-create`\n * (d) Store all field/option IDs in the mapping file\n */\nexport async function setupProjectFields(\n projectNum: number,\n projectId: string,\n cwd: string,\n): Promise<GhResult<void>> {\n // (a) Get existing fields\n const fieldsResult = await getProjectFields(projectNum);\n if (!fieldsResult.ok) {\n return fail(fieldsResult);\n }\n\n const fields = fieldsResult.data;\n\n // (b) Find Status field\n const statusField = fields.find(\n f => f.name === 'Status' && (f.type === 'SINGLE_SELECT' || f.type === 'ProjectV2SingleSelectField'),\n );\n\n if (!statusField) {\n return {\n ok: false,\n error: 'Status field not found on project board. This is unexpected for a Projects v2 board.',\n code: 'NOT_FOUND',\n };\n }\n\n const statusOptions = statusField.options ?? [];\n\n // Build status options map (existing)\n const statusOptionsMap: Record<string, string> = {};\n for (const opt of statusOptions) {\n statusOptionsMap[opt.name] = opt.id;\n }\n\n // Check if \"In Review\" exists\n if (!statusOptionsMap['In Review']) {\n const addResult = await addStatusOption(\n projectId,\n statusField.id,\n 'In Review',\n statusOptions,\n );\n\n if (!addResult.ok) {\n return fail(addResult);\n }\n\n statusOptionsMap['In Review'] = addResult.data;\n }\n\n // Also ensure the default options are tracked\n // GitHub defaults may be \"Todo\" not \"To Do\" — normalize\n if (statusOptionsMap['Todo'] && !statusOptionsMap['To Do']) {\n statusOptionsMap['To Do'] = statusOptionsMap['Todo'];\n }\n\n // (c) Create Estimate NUMBER field (if it does not exist)\n const estimateField = fields.find(f => f.name === 'Estimate');\n let estimateFieldId = estimateField?.id ?? '';\n\n if (!estimateField) {\n const createFieldResult = await ghExec<string>(\n [\n 'project', 'field-create', String(projectNum),\n '--owner', '@me',\n '--name', 'Estimate',\n '--data-type', 'NUMBER',\n ],\n );\n\n if (!createFieldResult.ok) {\n return fail(createFieldResult);\n }\n\n // Re-fetch fields to get the Estimate field ID\n const refetch = await getProjectFields(projectNum);\n if (refetch.ok) {\n const est = refetch.data.find(f => f.name === 'Estimate');\n if (est) {\n estimateFieldId = est.id;\n }\n }\n }\n\n // (d) Store field/option IDs in mapping file\n // Detect repo from git remote\n const repoResult = await ghExec<string>(['repo', 'view', '--json', 'nameWithOwner', '--jq', '.nameWithOwner']);\n const repo = repoResult.ok ? repoResult.data.trim() : '';\n\n const mapping = loadMapping(cwd) ?? createEmptyMapping(repo);\n mapping.project_number = projectNum;\n mapping.project_id = projectId;\n mapping.status_field_id = statusField.id;\n mapping.status_options = statusOptionsMap;\n mapping.estimate_field_id = estimateFieldId;\n\n if (repo && !mapping.repo) {\n mapping.repo = repo;\n }\n\n saveMapping(cwd, mapping);\n\n return { ok: true, data: undefined };\n}\n\n// ---- Item Management -------------------------------------------------------\n\n/**\n * Add an issue to a project board.\n *\n * Runs `gh project item-add {num} --owner @me --url {issueUrl} --format json`.\n * Returns the project item ID (different from the issue ID).\n */\nexport async function addItemToProject(\n projectNum: number,\n issueUrl: string,\n): Promise<GhResult<{ item_id: string }>> {\n const result = await ghExec<{ id: string }>(\n [\n 'project', 'item-add', String(projectNum),\n '--owner', '@me',\n '--url', issueUrl,\n '--format', 'json',\n ],\n { parseJson: true },\n );\n\n if (!result.ok) {\n return fail(result);\n }\n\n return { ok: true, data: { item_id: result.data.id } };\n}\n\n/**\n * Move a project item to a specific status column.\n *\n * Runs `gh project item-edit` with single-select-option-id for the\n * Status field.\n */\nexport async function moveItemToStatus(\n projectId: string,\n itemId: string,\n statusFieldId: string,\n statusOptionId: string,\n): Promise<GhResult<void>> {\n const result = await ghExec<string>([\n 'project', 'item-edit',\n '--project-id', projectId,\n '--id', itemId,\n '--field-id', statusFieldId,\n '--single-select-option-id', statusOptionId,\n ]);\n\n if (!result.ok) {\n return fail(result);\n }\n\n return { ok: true, data: undefined };\n}\n\n/**\n * Set the Estimate (story points) field on a project item.\n *\n * Runs `gh project item-edit` with --number flag for the Estimate field.\n */\nexport async function setEstimate(\n projectId: string,\n itemId: string,\n estimateFieldId: string,\n points: number,\n): Promise<GhResult<void>> {\n const result = await ghExec<string>([\n 'project', 'item-edit',\n '--project-id', projectId,\n '--id', itemId,\n '--field-id', estimateFieldId,\n '--number', String(points),\n ]);\n\n if (!result.ok) {\n return fail(result);\n }\n\n return { ok: true, data: undefined };\n}\n","/**\n * GitHub Milestones — CRUD operations for milestone management\n *\n * Manages GitHub milestones for MAXSIM milestone grouping.\n * One milestone per MAXSIM milestone. Uses the REST API via `gh api`\n * (simpler than GraphQL for milestone operations).\n *\n * Auto-closes milestones when all issues are closed (AC-12).\n *\n * CRITICAL: Never import octokit or any npm GitHub SDK.\n * CRITICAL: Never call process.exit() — return GhResult instead.\n */\n\nimport type { GhErrorCode, GhResult } from './types.js';\nimport { ghExec } from './gh.js';\n\n// ---- Helpers ---------------------------------------------------------------\n\n/**\n * Re-wrap a failed GhResult for a different generic type.\n */\nfunction fail<T>(result: { ok: false; error: string; code: GhErrorCode }): GhResult<T> {\n return { ok: false, error: result.error, code: result.code };\n}\n\n// ---- Milestone CRUD --------------------------------------------------------\n\n/**\n * Create a new GitHub milestone.\n *\n * Uses the REST API: `POST /repos/{owner}/{repo}/milestones`.\n * The `{owner}` and `{repo}` placeholders are auto-resolved by `gh api`.\n *\n * Returns the milestone number and internal ID.\n */\nexport async function createMilestone(\n title: string,\n description?: string,\n): Promise<GhResult<{ number: number; id: number }>> {\n const args: string[] = [\n 'api', 'repos/{owner}/{repo}/milestones',\n '-X', 'POST',\n '-f', `title=${title}`,\n '-f', 'state=open',\n ];\n\n // Only include description if provided (gh api -f sends empty string otherwise)\n if (description) {\n args.push('-f', `description=${description}`);\n }\n\n const result = await ghExec<{ number: number; id: number }>(args, { parseJson: true });\n\n if (!result.ok) {\n return result;\n }\n\n return {\n ok: true,\n data: { number: result.data.number, id: result.data.id },\n };\n}\n\n/**\n * Find an existing milestone by title.\n *\n * Uses the REST API: `GET /repos/{owner}/{repo}/milestones`.\n * Fetches all open milestones and filters by exact title match.\n *\n * Returns null if no milestone with the given title exists.\n */\nexport async function findMilestone(\n title: string,\n): Promise<GhResult<{ number: number; id: number } | null>> {\n // Fetch all open milestones (default state=open)\n const result = await ghExec<Array<{ number: number; id: number; title: string }>>(\n ['api', 'repos/{owner}/{repo}/milestones', '--paginate'],\n { parseJson: true },\n );\n\n if (!result.ok) {\n return fail(result);\n }\n\n const milestones = result.data;\n const match = milestones.find(m => m.title === title);\n\n if (!match) {\n return { ok: true, data: null };\n }\n\n return { ok: true, data: { number: match.number, id: match.id } };\n}\n\n/**\n * Ensure a milestone exists, creating it if needed. Idempotent.\n *\n * First attempts to find an existing milestone with the given title.\n * If not found, creates a new one. Returns whether it was newly created.\n */\nexport async function ensureMilestone(\n title: string,\n description?: string,\n): Promise<GhResult<{ number: number; id: number; created: boolean }>> {\n // Try to find existing\n const findResult = await findMilestone(title);\n if (!findResult.ok) {\n return fail(findResult);\n }\n\n if (findResult.data) {\n return {\n ok: true,\n data: { ...findResult.data, created: false },\n };\n }\n\n // Create new milestone\n const createResult = await createMilestone(title, description);\n if (!createResult.ok) {\n return fail(createResult);\n }\n\n return {\n ok: true,\n data: { ...createResult.data, created: true },\n };\n}\n\n/**\n * Close a milestone if all its issues are closed.\n *\n * Fetches milestone details via REST API to check `open_issues` count.\n * If open_issues === 0, patches the milestone state to \"closed\".\n *\n * This implements AC-12: milestones auto-close when all issues are closed.\n */\nexport async function closeMilestoneIfComplete(\n milestoneNumber: number,\n): Promise<GhResult<{ closed: boolean }>> {\n // Get milestone details to check open_issues count\n const detailResult = await ghExec<{\n number: number;\n open_issues: number;\n closed_issues: number;\n state: string;\n }>(\n ['api', `repos/{owner}/{repo}/milestones/${milestoneNumber}`],\n { parseJson: true },\n );\n\n if (!detailResult.ok) {\n return fail(detailResult);\n }\n\n const milestone = detailResult.data;\n\n // Already closed\n if (milestone.state === 'closed') {\n return { ok: true, data: { closed: true } };\n }\n\n // Still has open issues — don't close\n if (milestone.open_issues > 0) {\n return { ok: true, data: { closed: false } };\n }\n\n // All issues closed — close the milestone\n const closeResult = await ghExec<string>([\n 'api', `repos/{owner}/{repo}/milestones/${milestoneNumber}`,\n '-X', 'PATCH',\n '-f', 'state=closed',\n ]);\n\n if (!closeResult.ok) {\n return fail(closeResult);\n }\n\n return { ok: true, data: { closed: true } };\n}\n","/**\n * GitHub Sync — Detect external changes to tracked issues\n *\n * Compares local mapping file (github-issues.json) against actual GitHub state.\n * Uses batched GraphQL queries for efficiency (avoids N+1 sequential calls).\n *\n * CRITICAL: Never import octokit or any npm GitHub SDK.\n * CRITICAL: Never call process.exit() — return GhResult instead.\n */\n\nimport type { GhErrorCode, GhResult, IssueStatus } from './types.js';\nimport { ghGraphQL, ghExec } from './gh.js';\nimport { loadMapping } from './mapping.js';\n\n// ---- Helpers ---------------------------------------------------------------\n\n/**\n * Re-wrap a failed GhResult for a different generic type.\n */\nfunction fail<T>(result: { ok: false; error: string; code: GhErrorCode }): GhResult<T> {\n return { ok: false, error: result.error, code: result.code };\n}\n\n// ---- Types -----------------------------------------------------------------\n\nexport interface SyncChange {\n issueNumber: number;\n field: string;\n localValue: string;\n remoteValue: string;\n}\n\nexport interface SyncCheckResult {\n inSync: boolean;\n changes: SyncChange[];\n}\n\nexport interface VerifyIssueStateResult {\n verified: boolean;\n actualState: string;\n}\n\nexport interface HandleExternalCloseResult {\n action: 'accepted' | 'reopened';\n reason: string;\n}\n\n// ---- Batch GraphQL Issue Fetch ---------------------------------------------\n\ninterface GraphQLIssueNode {\n number: number;\n state: string;\n title: string;\n labels: { nodes: Array<{ name: string }> };\n}\n\n/**\n * Batch-fetch issue details via a single GraphQL query.\n *\n * Fetches up to 100 issues per query using node ID lookups.\n * Falls back to sequential `gh issue view` if GraphQL fails.\n */\nasync function batchFetchIssues(\n repo: string,\n issueNumbers: number[],\n): Promise<GhResult<Map<number, { state: string; title: string; labels: string[] }>>> {\n if (issueNumbers.length === 0) {\n return { ok: true, data: new Map() };\n }\n\n // Split owner/repo\n const [owner, name] = repo.split('/');\n if (!owner || !name) {\n return {\n ok: false,\n error: `Invalid repo format: ${repo}. Expected \"owner/repo\".`,\n code: 'UNKNOWN',\n };\n }\n\n // Build GraphQL query with aliases for each issue\n // GitHub GraphQL limits: we query up to 100 issues at a time\n const BATCH_SIZE = 100;\n const resultMap = new Map<number, { state: string; title: string; labels: string[] }>();\n\n for (let i = 0; i < issueNumbers.length; i += BATCH_SIZE) {\n const batch = issueNumbers.slice(i, i + BATCH_SIZE);\n\n const issueFragments = batch\n .map(\n (num, idx) =>\n `issue_${idx}: issue(number: ${num}) { number state title labels(first: 20) { nodes { name } } }`,\n )\n .join('\\n ');\n\n const query = `\n query {\n repository(owner: \"${owner}\", name: \"${name}\") {\n ${issueFragments}\n }\n }\n `;\n\n const result = await ghGraphQL<{\n repository: Record<string, GraphQLIssueNode | null>;\n }>(query);\n\n if (!result.ok) {\n // Fall back to sequential fetching on GraphQL failure\n return batchFetchIssuesSequential(issueNumbers);\n }\n\n const repoData = result.data.repository;\n for (let idx = 0; idx < batch.length; idx++) {\n const issueData = repoData[`issue_${idx}`];\n if (issueData) {\n resultMap.set(issueData.number, {\n state: issueData.state.toLowerCase(),\n title: issueData.title,\n labels: issueData.labels.nodes.map(l => l.name),\n });\n }\n }\n }\n\n return { ok: true, data: resultMap };\n}\n\n/**\n * Sequential fallback: fetch issues one at a time via `gh issue view`.\n */\nasync function batchFetchIssuesSequential(\n issueNumbers: number[],\n): Promise<GhResult<Map<number, { state: string; title: string; labels: string[] }>>> {\n const resultMap = new Map<number, { state: string; title: string; labels: string[] }>();\n\n for (const num of issueNumbers) {\n const result = await ghExec<{\n state: string;\n title: string;\n labels: Array<{ name: string }>;\n }>(['issue', 'view', String(num), '--json', 'state,title,labels'], {\n parseJson: true,\n });\n\n if (result.ok) {\n resultMap.set(num, {\n state: result.data.state.toLowerCase(),\n title: result.data.title,\n labels: result.data.labels.map(l => l.name),\n });\n }\n // Skip issues that fail to fetch (may have been deleted)\n }\n\n return { ok: true, data: resultMap };\n}\n\n// ---- Public API ------------------------------------------------------------\n\n/**\n * Compare local mapping file against GitHub reality.\n *\n * For each tracked issue (phases + todos), fetches current GitHub state\n * and compares against the local mapping. Reports discrepancies in\n * state, title, and labels.\n *\n * Uses batched GraphQL for efficiency (single query for up to 100 issues).\n */\nexport async function syncCheck(\n cwd: string,\n): Promise<GhResult<SyncCheckResult>> {\n const mapping = loadMapping(cwd);\n if (!mapping) {\n return {\n ok: false,\n error: 'github-issues.json does not exist. Run project setup first.',\n code: 'NOT_FOUND',\n };\n }\n\n if (!mapping.repo) {\n return {\n ok: false,\n error: 'No repo configured in github-issues.json.',\n code: 'NOT_FOUND',\n };\n }\n\n // Collect all tracked issue numbers with their local status\n const trackedIssues: Array<{\n issueNumber: number;\n localStatus: IssueStatus;\n source: string; // e.g., \"phase 01, task 1.1\" or \"todo xyz\"\n }> = [];\n\n // Phases\n for (const [phaseNum, phase] of Object.entries(mapping.phases)) {\n if (phase.tracking_issue.number > 0) {\n trackedIssues.push({\n issueNumber: phase.tracking_issue.number,\n localStatus: phase.tracking_issue.status,\n source: `phase ${phaseNum} tracking`,\n });\n }\n for (const [taskId, task] of Object.entries(phase.tasks)) {\n if (task.number > 0) {\n trackedIssues.push({\n issueNumber: task.number,\n localStatus: task.status,\n source: `phase ${phaseNum}, task ${taskId}`,\n });\n }\n }\n }\n\n // Todos\n if (mapping.todos) {\n for (const [todoId, todo] of Object.entries(mapping.todos)) {\n if (todo.number > 0) {\n trackedIssues.push({\n issueNumber: todo.number,\n localStatus: todo.status,\n source: `todo ${todoId}`,\n });\n }\n }\n }\n\n if (trackedIssues.length === 0) {\n return {\n ok: true,\n data: { inSync: true, changes: [] },\n };\n }\n\n // Batch-fetch all issue states from GitHub\n const issueNumbers = trackedIssues.map(t => t.issueNumber);\n const fetchResult = await batchFetchIssues(mapping.repo, issueNumbers);\n if (!fetchResult.ok) {\n return fail(fetchResult);\n }\n\n const remoteStates = fetchResult.data;\n const changes: SyncChange[] = [];\n\n for (const tracked of trackedIssues) {\n const remote = remoteStates.get(tracked.issueNumber);\n if (!remote) {\n // Issue not found on GitHub (may have been deleted)\n changes.push({\n issueNumber: tracked.issueNumber,\n field: 'existence',\n localValue: 'exists',\n remoteValue: 'not found',\n });\n continue;\n }\n\n // Compare state: map GitHub state to expected local status\n // GitHub states: \"open\" or \"closed\"\n // Local statuses: \"To Do\", \"In Progress\", \"In Review\", \"Done\"\n const isRemoteClosed = remote.state === 'closed';\n const isLocalDone = tracked.localStatus === 'Done';\n\n if (isRemoteClosed && !isLocalDone) {\n changes.push({\n issueNumber: tracked.issueNumber,\n field: 'state',\n localValue: tracked.localStatus,\n remoteValue: 'closed (Done)',\n });\n } else if (!isRemoteClosed && isLocalDone) {\n changes.push({\n issueNumber: tracked.issueNumber,\n field: 'state',\n localValue: 'Done',\n remoteValue: `open (${remote.state})`,\n });\n }\n }\n\n return {\n ok: true,\n data: {\n inSync: changes.length === 0,\n changes,\n },\n };\n}\n\n/**\n * Quick single-issue state check.\n *\n * Verifies whether an issue is in the expected state (open or closed).\n */\nexport async function verifyIssueState(\n issueNumber: number,\n expectedState: 'open' | 'closed',\n): Promise<GhResult<VerifyIssueStateResult>> {\n const result = await ghExec<{ state: string }>(\n ['issue', 'view', String(issueNumber), '--json', 'state'],\n { parseJson: true },\n );\n\n if (!result.ok) {\n return fail(result);\n }\n\n const actualState = result.data.state.toLowerCase();\n\n return {\n ok: true,\n data: {\n verified: actualState === expectedState,\n actualState,\n },\n };\n}\n\n/**\n * Handle an externally closed issue: provide data for the AI to decide.\n *\n * When sync detects an externally closed issue, this function gathers\n * the context needed for the AI to decide whether to accept the close\n * (if the code actually implements the task) or reopen it.\n *\n * Does NOT auto-decide — returns data for AI decision-making.\n */\nexport async function handleExternalClose(\n cwd: string,\n issueNumber: number,\n): Promise<GhResult<{ action: 'accepted' | 'reopened'; reason: string }>> {\n // Fetch the issue details and closing context\n const issueResult = await ghExec<{\n state: string;\n stateReason: string;\n title: string;\n body: string;\n closedBy: { login: string } | null;\n }>(\n [\n 'issue',\n 'view',\n String(issueNumber),\n '--json',\n 'state,stateReason,title,body,closedBy',\n ],\n { parseJson: true },\n );\n\n if (!issueResult.ok) {\n return fail(issueResult);\n }\n\n const issue = issueResult.data;\n\n if (issue.state.toLowerCase() !== 'closed') {\n return {\n ok: true,\n data: {\n action: 'reopened',\n reason: `Issue #${issueNumber} is not closed (state: ${issue.state}). No action needed.`,\n },\n };\n }\n\n // Gather context about who closed it and why\n const closedBy = issue.closedBy?.login ?? 'unknown';\n const stateReason = issue.stateReason || 'completed';\n\n // Return data for AI to decide\n // The AI will check the codebase to determine if the task is truly complete\n return {\n ok: true,\n data: {\n action: 'accepted',\n reason: `Issue #${issueNumber} \"${issue.title}\" was closed externally by ${closedBy} (reason: ${stateReason}). AI should verify code implements the task before accepting.`,\n },\n };\n}\n","/**\n * MCP Utilities — Shared helpers for MCP tools\n *\n * CRITICAL: Never import output() or error() from core — they call process.exit().\n * CRITICAL: Never write to stdout — it is reserved for MCP JSON-RPC protocol.\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\n\n/**\n * Walk up from startDir to find a directory containing `.planning/`.\n * Returns the directory containing `.planning/` or null if not found.\n */\nlet _cachedRoot: string | null | undefined;\n\nexport function detectProjectRoot(startDir?: string): string | null {\n // Only cache when using default startDir (cwd)\n if (startDir === undefined && _cachedRoot !== undefined) {\n return _cachedRoot;\n }\n\n let dir = startDir || process.cwd();\n\n // Safety limit to prevent infinite loops\n for (let i = 0; i < 100; i++) {\n const planningDir = path.join(dir, '.planning');\n try {\n const stat = fs.statSync(planningDir);\n if (stat.isDirectory()) {\n if (startDir === undefined) _cachedRoot = dir;\n return dir;\n }\n } catch {\n // Not found here, walk up\n }\n\n const parent = path.dirname(dir);\n if (parent === dir) {\n // Reached filesystem root\n if (startDir === undefined) _cachedRoot = null;\n return null;\n }\n dir = parent;\n }\n\n if (startDir === undefined) _cachedRoot = null;\n return null;\n}\n\n/**\n * Return a structured MCP success response.\n */\nexport function mcpSuccess(data: Record<string, unknown>, summary: string) {\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ success: true, data, summary }, null, 2),\n },\n ],\n };\n}\n\n/**\n * Return a structured MCP error response.\n */\nexport function mcpError(error: string, summary: string) {\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ success: false, error, summary }, null, 2),\n },\n ],\n isError: true as const,\n };\n}\n","/**\n * Phase CRUD MCP Tools — Phase operations exposed as MCP tools\n *\n * Integrates with GitHub: phase completion triggers sync check, issue close,\n * board move to Done, and milestone completion check. Find/list enrich\n * responses with GitHub issue data when available.\n *\n * CRITICAL: Never import output() or error() from core — they call process.exit().\n * CRITICAL: Never write to stdout — it is reserved for MCP JSON-RPC protocol.\n * CRITICAL: Never call process.exit() — the server must stay alive after every tool call.\n */\n\nimport fs from 'node:fs';\nimport { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\n\nimport {\n findPhaseInternal,\n comparePhaseNum,\n getArchivedPhaseDirs,\n phasesPath,\n listSubDirs,\n} from '../core/core.js';\n\nimport {\n phaseAddCore,\n phaseInsertCore,\n phaseCompleteCore,\n} from '../core/phase.js';\n\nimport { detectGitHubMode } from '../github/gh.js';\nimport { closeIssue, postComment, updateParentTaskList } from '../github/issues.js';\nimport { moveItemToStatus } from '../github/projects.js';\nimport { closeMilestoneIfComplete } from '../github/milestones.js';\nimport { loadMapping, saveMapping } from '../github/mapping.js';\nimport { syncCheck } from '../github/sync.js';\nimport type { IssueMappingFile, IssueStatus } from '../github/types.js';\n\nimport { detectProjectRoot, mcpSuccess, mcpError } from './utils.js';\n\n/**\n * Register all phase CRUD tools on the MCP server.\n */\nexport function registerPhaseTools(server: McpServer): void {\n // ── mcp_find_phase ──────────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_find_phase',\n 'Find a phase directory by number or name. Returns phase details including plans, summaries, and status.',\n {\n phase: z.string().describe('Phase number or name (e.g. \"01\", \"1\", \"01A\", \"1.1\")'),\n },\n async ({ phase }) => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n const result = findPhaseInternal(cwd, phase);\n if (!result) {\n return mcpError(`Phase ${phase} not found`, 'Phase not found');\n }\n\n // Enrich with GitHub issue data if mapping exists\n let githubTracking: { number: number; status: string } | null = null;\n let githubTaskIssues: Record<string, { number: number; status: string }> | null = null;\n let githubWarning: string | undefined;\n\n try {\n const mapping = loadMapping(cwd);\n if (mapping && result.phase_number) {\n const phaseMapping = mapping.phases[result.phase_number];\n if (phaseMapping) {\n if (phaseMapping.tracking_issue.number > 0) {\n githubTracking = {\n number: phaseMapping.tracking_issue.number,\n status: phaseMapping.tracking_issue.status,\n };\n }\n const taskEntries = Object.entries(phaseMapping.tasks);\n if (taskEntries.length > 0) {\n githubTaskIssues = {};\n for (const [taskId, task] of taskEntries) {\n if (task.number > 0) {\n githubTaskIssues[taskId] = {\n number: task.number,\n status: task.status,\n };\n }\n }\n }\n }\n }\n } catch (e) {\n githubWarning = `GitHub data enrichment failed: ${(e as Error).message}`;\n }\n\n return mcpSuccess(\n {\n found: result.found,\n directory: result.directory,\n phase_number: result.phase_number,\n phase_name: result.phase_name,\n phase_slug: result.phase_slug,\n plans: result.plans,\n summaries: result.summaries,\n incomplete_plans: result.incomplete_plans,\n has_research: result.has_research,\n has_context: result.has_context,\n has_verification: result.has_verification,\n archived: result.archived ?? null,\n github_tracking_issue: githubTracking,\n github_task_issues: githubTaskIssues,\n ...(githubWarning ? { github_warning: githubWarning } : {}),\n },\n `Found phase ${result.phase_number}: ${result.phase_name ?? 'unnamed'}`,\n );\n } catch (e) {\n return mcpError((e as Error).message, 'Operation failed');\n }\n },\n );\n\n // ── mcp_list_phases ─────────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_list_phases',\n 'List phase directories with pagination. Returns sorted phases with offset/limit support.',\n {\n include_archived: z\n .boolean()\n .optional()\n .default(false)\n .describe('Include archived phases from completed milestones'),\n offset: z\n .number()\n .optional()\n .default(0)\n .describe('Number of phases to skip (for pagination)'),\n limit: z\n .number()\n .optional()\n .default(20)\n .describe('Maximum number of phases to return'),\n },\n async ({ include_archived, offset, limit }) => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n const phasesDir = phasesPath(cwd);\n if (!fs.existsSync(phasesDir)) {\n return mcpSuccess(\n { directories: [], count: 0, total_count: 0, offset, limit, has_more: false },\n 'No phases directory found',\n );\n }\n\n let dirs = listSubDirs(phasesDir);\n\n if (include_archived) {\n const archived = getArchivedPhaseDirs(cwd);\n for (const a of archived) {\n dirs.push(`${a.name} [${a.milestone}]`);\n }\n }\n\n dirs.sort((a, b) => comparePhaseNum(a, b));\n\n const total_count = dirs.length;\n const paginated = dirs.slice(offset, offset + limit);\n const has_more = offset + limit < total_count;\n\n // Enrich with GitHub issue counts if in 'full' mode\n let githubIssueCounts: Record<string, { open: number; closed: number }> | null = null;\n let githubWarning: string | undefined;\n\n try {\n const mode = await detectGitHubMode();\n if (mode === 'full') {\n const mapping = loadMapping(cwd);\n if (mapping && Object.keys(mapping.phases).length > 0) {\n githubIssueCounts = {};\n for (const [phaseNum, phaseData] of Object.entries(mapping.phases)) {\n let open = 0;\n let closed = 0;\n for (const task of Object.values(phaseData.tasks)) {\n if (task.number > 0) {\n if (task.status === 'Done') {\n closed++;\n } else {\n open++;\n }\n }\n }\n githubIssueCounts[phaseNum] = { open, closed };\n }\n }\n }\n } catch (e) {\n githubWarning = `GitHub enrichment failed: ${(e as Error).message}`;\n }\n\n return mcpSuccess(\n {\n directories: paginated,\n count: paginated.length,\n total_count,\n offset,\n limit,\n has_more,\n github_issue_counts: githubIssueCounts,\n ...(githubWarning ? { github_warning: githubWarning } : {}),\n },\n `Showing ${paginated.length} of ${total_count} phase(s)`,\n );\n } catch (e) {\n return mcpError((e as Error).message, 'Operation failed');\n }\n },\n );\n\n // ── mcp_create_phase ────────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_create_phase',\n 'Create a new phase. Adds the next sequential phase directory and appends to ROADMAP.md.',\n {\n name: z.string().describe('Phase description/name (e.g. \"Authentication System\")'),\n },\n async ({ name }) => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n if (!name || !name.trim()) {\n return mcpError('Phase name must not be empty', 'Validation failed');\n }\n\n const result = await phaseAddCore(cwd, name, { includeStubs: true });\n\n // No GitHub action needed on phase creation — issues are created\n // on plan finalization (eager creation), not phase creation.\n\n return mcpSuccess(\n {\n phase_number: result.phase_number,\n padded: result.padded,\n name: result.description,\n slug: result.slug,\n directory: result.directory,\n },\n `Created Phase ${result.phase_number}: ${result.description}`,\n );\n } catch (e) {\n return mcpError((e as Error).message, 'Operation failed');\n }\n },\n );\n\n // ── mcp_insert_phase ────────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_insert_phase',\n 'Insert a decimal phase after a specified phase (e.g. 01.1 after 01). Creates directory and updates ROADMAP.md.',\n {\n name: z.string().describe('Phase description/name'),\n after: z.string().describe('Phase number to insert after (e.g. \"01\", \"1\")'),\n },\n async ({ name, after }) => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n if (!name || !name.trim()) {\n return mcpError('Phase name must not be empty', 'Validation failed');\n }\n\n const result = await phaseInsertCore(cwd, after, name, { includeStubs: true });\n\n return mcpSuccess(\n {\n phase_number: result.phase_number,\n after_phase: result.after_phase,\n name: result.description,\n slug: result.slug,\n directory: result.directory,\n },\n `Inserted Phase ${result.phase_number}: ${result.description} after Phase ${result.after_phase}`,\n );\n } catch (e) {\n return mcpError((e as Error).message, 'Operation failed');\n }\n },\n );\n\n // ── mcp_complete_phase ──────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_complete_phase',\n 'Mark a phase as complete. Updates ROADMAP.md checkbox, progress table, plan count, STATE.md, and REQUIREMENTS.md.',\n {\n phase: z.string().describe('Phase number to complete (e.g. \"01\", \"1\", \"1.1\")'),\n },\n async ({ phase }) => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n // BEFORE completing locally: run sync check (AC-09)\n let syncDiscrepancies: Array<{ issueNumber: number; field: string; localValue: string; remoteValue: string }> = [];\n let githubWarning: string | undefined;\n\n try {\n const mode = await detectGitHubMode();\n if (mode === 'full') {\n const syncResult = await syncCheck(cwd);\n if (syncResult.ok && !syncResult.data.inSync) {\n syncDiscrepancies = syncResult.data.changes;\n }\n }\n } catch (e) {\n githubWarning = `Sync check failed: ${(e as Error).message}`;\n }\n\n // Complete locally\n const result = await phaseCompleteCore(cwd, phase);\n\n // AFTER completing locally: GitHub operations\n let githubClosed = false;\n let milestoneClosed = false;\n\n try {\n const mode = await detectGitHubMode();\n if (mode === 'full') {\n const mapping = loadMapping(cwd);\n if (mapping) {\n const phaseMapping = mapping.phases[phase];\n if (phaseMapping) {\n // Close the parent tracking issue\n if (phaseMapping.tracking_issue.number > 0) {\n const closeResult = await closeIssue(phaseMapping.tracking_issue.number, 'completed');\n if (closeResult.ok) {\n githubClosed = true;\n phaseMapping.tracking_issue.status = 'Done';\n\n // Move to \"Done\" on the board\n if (\n phaseMapping.tracking_issue.item_id &&\n mapping.status_field_id &&\n mapping.status_options['Done']\n ) {\n await moveItemToStatus(\n mapping.project_id,\n phaseMapping.tracking_issue.item_id,\n mapping.status_field_id,\n mapping.status_options['Done'],\n );\n }\n }\n }\n\n // Close any remaining open task issues for this phase\n for (const [_taskId, task] of Object.entries(phaseMapping.tasks)) {\n if (task.number > 0 && task.status !== 'Done') {\n const taskCloseResult = await closeIssue(task.number, 'completed');\n if (taskCloseResult.ok) {\n task.status = 'Done';\n\n // Move task to \"Done\" on board\n if (task.item_id && mapping.status_field_id && mapping.status_options['Done']) {\n await moveItemToStatus(\n mapping.project_id,\n task.item_id,\n mapping.status_field_id,\n mapping.status_options['Done'],\n );\n }\n\n // Update parent tracking issue checkbox\n if (phaseMapping.tracking_issue.number > 0) {\n await updateParentTaskList(\n phaseMapping.tracking_issue.number,\n task.number,\n true,\n );\n }\n }\n }\n }\n\n saveMapping(cwd, mapping);\n\n // Check if milestone should be closed (all issues done)\n if (mapping.milestone_id > 0) {\n const msResult = await closeMilestoneIfComplete(mapping.milestone_id);\n if (msResult.ok) {\n milestoneClosed = msResult.data.closed;\n }\n }\n }\n }\n }\n } catch (e) {\n githubWarning = (githubWarning ? githubWarning + '; ' : '') +\n `GitHub completion operations failed: ${(e as Error).message}`;\n }\n\n return mcpSuccess(\n {\n completed_phase: result.completed_phase,\n phase_name: result.phase_name,\n plans_executed: result.plans_executed,\n next_phase: result.next_phase,\n next_phase_name: result.next_phase_name,\n is_last_phase: result.is_last_phase,\n date: result.date,\n roadmap_updated: result.roadmap_updated,\n state_updated: result.state_updated,\n sync_discrepancies: syncDiscrepancies.length > 0 ? syncDiscrepancies : null,\n github_closed: githubClosed,\n milestone_closed: milestoneClosed,\n ...(githubWarning ? { github_warning: githubWarning } : {}),\n },\n `Phase ${phase} marked as complete${result.next_phase ? `, next: Phase ${result.next_phase}` : ''}`,\n );\n } catch (e) {\n return mcpError((e as Error).message, 'Operation failed');\n }\n },\n );\n\n // ── mcp_bounce_issue ────────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_bounce_issue',\n 'Bounce a task back from In Review to In Progress with a detailed comment explaining what failed. Implements reviewer feedback loop (AC-05).',\n {\n issue_number: z.number().describe('GitHub issue number to bounce back'),\n reason: z.string().describe('Detailed reason why the task is being bounced back (reviewer feedback)'),\n },\n async ({ issue_number, reason }) => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n const mode = await detectGitHubMode();\n\n if (mode === 'local-only') {\n // In local-only mode, update local mapping only\n const mapping = loadMapping(cwd);\n if (mapping) {\n const updated = updateLocalMappingStatus(mapping, issue_number, 'In Progress');\n if (updated) {\n saveMapping(cwd, mapping);\n return mcpSuccess(\n {\n mode: 'local-only',\n issue_number,\n status: 'In Progress',\n local_updated: true,\n reason,\n },\n `Local-only: issue #${issue_number} bounced to In Progress (reason recorded locally)`,\n );\n }\n }\n return mcpSuccess(\n {\n mode: 'local-only',\n issue_number,\n reason,\n note: 'Bounce recorded locally. GitHub operations skipped.',\n },\n `Local-only: bounce for issue #${issue_number} recorded`,\n );\n }\n\n // Full mode: move on board + post comment\n const mapping = loadMapping(cwd);\n let githubWarning: string | undefined;\n let moved = false;\n let commented = false;\n\n // Post reviewer feedback comment\n try {\n const commentBody = `## Bounced Back to In Progress\\n\\n**Reason:** ${reason}\\n\\n---\\n*Review feedback posted by MAXSIM*`;\n const commentResult = await postComment(issue_number, commentBody);\n commented = commentResult.ok;\n if (!commentResult.ok) {\n githubWarning = `Comment failed: ${commentResult.error}`;\n }\n } catch (e) {\n githubWarning = `Comment failed: ${(e as Error).message}`;\n }\n\n // Move to \"In Progress\" on the board\n try {\n if (mapping) {\n const issueEntry = findIssueInMapping(mapping, issue_number);\n if (\n issueEntry?.item_id &&\n mapping.status_field_id &&\n mapping.status_options['In Progress']\n ) {\n const moveResult = await moveItemToStatus(\n mapping.project_id,\n issueEntry.item_id,\n mapping.status_field_id,\n mapping.status_options['In Progress'],\n );\n moved = moveResult.ok;\n if (!moveResult.ok) {\n githubWarning = (githubWarning ? githubWarning + '; ' : '') +\n `Board move failed: ${moveResult.error}`;\n }\n }\n\n // Update local mapping status\n updateLocalMappingStatus(mapping, issue_number, 'In Progress');\n saveMapping(cwd, mapping);\n }\n } catch (e) {\n githubWarning = (githubWarning ? githubWarning + '; ' : '') +\n `Board move failed: ${(e as Error).message}`;\n }\n\n return mcpSuccess(\n {\n mode: 'full',\n issue_number,\n status: 'In Progress',\n commented,\n moved,\n reason,\n ...(githubWarning ? { github_warning: githubWarning } : {}),\n },\n `Issue #${issue_number} bounced to In Progress${commented ? ' with feedback comment' : ''}`,\n );\n } catch (e) {\n return mcpError((e as Error).message, 'Operation failed');\n }\n },\n );\n}\n\n// ---- Internal Helpers ──────────────────────────────────────────────────────\n\nimport type { TaskIssueMapping } from '../github/types.js';\n\n/**\n * Find an issue entry in the mapping file (searches phases and todos).\n */\nfunction findIssueInMapping(\n mapping: IssueMappingFile,\n issueNumber: number,\n): TaskIssueMapping | null {\n // Search phases\n for (const phase of Object.values(mapping.phases)) {\n if (phase.tracking_issue.number === issueNumber) {\n return phase.tracking_issue;\n }\n for (const task of Object.values(phase.tasks)) {\n if (task.number === issueNumber) {\n return task;\n }\n }\n }\n\n // Search todos\n if (mapping.todos) {\n for (const todo of Object.values(mapping.todos)) {\n if (todo.number === issueNumber) {\n return todo;\n }\n }\n }\n\n return null;\n}\n\n/**\n * Update local mapping status for an issue (mutates mapping in-place).\n * Returns true if the issue was found and updated.\n */\nfunction updateLocalMappingStatus(\n mapping: IssueMappingFile,\n issueNumber: number,\n status: IssueStatus,\n): boolean {\n // Search phases\n for (const phase of Object.values(mapping.phases)) {\n if (phase.tracking_issue.number === issueNumber) {\n phase.tracking_issue.status = status;\n return true;\n }\n for (const task of Object.values(phase.tasks)) {\n if (task.number === issueNumber) {\n task.status = status;\n return true;\n }\n }\n }\n\n // Search todos\n if (mapping.todos) {\n for (const todo of Object.values(mapping.todos)) {\n if (todo.number === issueNumber) {\n todo.status = status;\n return true;\n }\n }\n }\n\n return false;\n}\n","/**\n * Todo CRUD MCP Tools — Todo operations exposed as MCP tools\n *\n * Integrates with GitHub: todo add creates GitHub issue in 'full' mode,\n * todo complete closes GitHub issue and moves to Done on board,\n * todo list enriches with GitHub issue data when available.\n *\n * CRITICAL: Never import output() or error() from core — they call process.exit().\n * CRITICAL: Never write to stdout — it is reserved for MCP JSON-RPC protocol.\n * CRITICAL: Never call process.exit() — the server must stay alive after every tool call.\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\n\nimport { generateSlugInternal, todayISO, planningPath } from '../core/core.js';\nimport { parseTodoFrontmatter } from '../core/commands.js';\n\nimport { detectGitHubMode } from '../github/gh.js';\nimport { createTodoIssue, closeIssue } from '../github/issues.js';\nimport { addItemToProject, moveItemToStatus } from '../github/projects.js';\nimport { loadMapping, saveMapping, updateTodoMapping } from '../github/mapping.js';\n\nimport { detectProjectRoot, mcpSuccess, mcpError } from './utils.js';\n\n/**\n * Register all todo CRUD tools on the MCP server.\n */\nexport function registerTodoTools(server: McpServer): void {\n // ── mcp_add_todo ────────────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_add_todo',\n 'Create a new todo item in .planning/todos/pending/ with frontmatter metadata.',\n {\n title: z.string().describe('Title of the todo item'),\n description: z.string().optional().describe('Optional description body'),\n area: z.string().optional().default('general').describe('Area/category (default: general)'),\n phase: z.string().optional().describe('Associated phase number'),\n },\n async ({ title, description, area, phase }) => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n const pendingDir = planningPath(cwd, 'todos', 'pending');\n fs.mkdirSync(pendingDir, { recursive: true });\n\n const today = todayISO();\n const slug = generateSlugInternal(title) || 'untitled';\n const timestamp = Date.now();\n const filename = `${timestamp}-${slug}.md`;\n const filePath = path.join(pendingDir, filename);\n\n const content = `---\\ncreated: ${today}\\ntitle: ${title}\\narea: ${area || 'general'}\\nphase: ${phase || 'unassigned'}\\n---\\n${description || ''}\\n`;\n\n fs.writeFileSync(filePath, content, 'utf-8');\n\n // GitHub integration: create issue in 'full' mode\n let githubIssueNumber: number | null = null;\n let githubIssueUrl: string | null = null;\n let githubWarning: string | undefined;\n\n try {\n const mode = await detectGitHubMode();\n if (mode === 'full') {\n const mapping = loadMapping(cwd);\n\n const issueResult = await createTodoIssue({\n title,\n description: description || undefined,\n milestone: mapping?.milestone_title || undefined,\n });\n\n if (issueResult.ok) {\n githubIssueNumber = issueResult.data.number;\n githubIssueUrl = issueResult.data.url;\n\n // Add to project board\n if (mapping && mapping.project_number > 0) {\n const issueUrl = `https://github.com/${mapping.repo}/issues/${issueResult.data.number}`;\n const addResult = await addItemToProject(mapping.project_number, issueUrl);\n\n if (addResult.ok) {\n // Store mapping\n updateTodoMapping(cwd, filename, {\n number: issueResult.data.number,\n node_id: issueResult.data.node_id,\n item_id: addResult.data.item_id,\n status: 'To Do',\n });\n\n // Set status to \"To Do\" on board\n if (mapping.status_field_id && mapping.status_options['To Do']) {\n await moveItemToStatus(\n mapping.project_id,\n addResult.data.item_id,\n mapping.status_field_id,\n mapping.status_options['To Do'],\n );\n }\n } else {\n // Store mapping without item_id (not on board)\n updateTodoMapping(cwd, filename, {\n number: issueResult.data.number,\n node_id: issueResult.data.node_id,\n item_id: '',\n status: 'To Do',\n });\n githubWarning = `Issue created but board add failed: ${addResult.error}`;\n }\n } else {\n // No mapping or project — just record the issue number\n githubWarning = 'Issue created but no project board configured for board tracking.';\n }\n } else {\n githubWarning = `GitHub issue creation failed: ${issueResult.error}`;\n }\n }\n } catch (e) {\n githubWarning = `GitHub operation failed: ${(e as Error).message}`;\n }\n\n return mcpSuccess(\n {\n file: filename,\n path: `.planning/todos/pending/${filename}`,\n title,\n area: area || 'general',\n github_issue_number: githubIssueNumber,\n github_issue_url: githubIssueUrl,\n ...(githubWarning ? { github_warning: githubWarning } : {}),\n },\n `Todo created: ${title}${githubIssueNumber ? ` (GitHub #${githubIssueNumber})` : ''}`,\n );\n } catch (e) {\n return mcpError((e as Error).message, 'Operation failed');\n }\n },\n );\n\n // ── mcp_complete_todo ───────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_complete_todo',\n 'Mark a pending todo as completed by moving it from pending/ to completed/ with a completion timestamp.',\n {\n todo_id: z.string().describe('Filename of the todo (e.g., 1234567890-my-task.md)'),\n },\n async ({ todo_id }) => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n const pendingDir = planningPath(cwd, 'todos', 'pending');\n const completedDir = planningPath(cwd, 'todos', 'completed');\n const sourcePath = path.join(pendingDir, todo_id);\n\n if (!fs.existsSync(sourcePath)) {\n return mcpError(`Todo not found in pending: ${todo_id}`, 'Todo not found');\n }\n\n fs.mkdirSync(completedDir, { recursive: true });\n\n let content = fs.readFileSync(sourcePath, 'utf-8');\n const today = todayISO();\n content = `completed: ${today}\\n` + content;\n\n fs.writeFileSync(path.join(completedDir, todo_id), content, 'utf-8');\n fs.unlinkSync(sourcePath);\n\n // GitHub integration: close issue in 'full' mode\n let githubClosed = false;\n let githubWarning: string | undefined;\n\n try {\n const mode = await detectGitHubMode();\n if (mode === 'full') {\n const mapping = loadMapping(cwd);\n if (mapping?.todos?.[todo_id]) {\n const todoMapping = mapping.todos[todo_id];\n if (todoMapping.number > 0) {\n // Close the issue\n const closeResult = await closeIssue(todoMapping.number, 'completed');\n githubClosed = closeResult.ok;\n\n if (!closeResult.ok) {\n githubWarning = `GitHub issue close failed: ${closeResult.error}`;\n }\n\n // Move to Done on board\n if (\n todoMapping.item_id &&\n mapping.status_field_id &&\n mapping.status_options['Done']\n ) {\n await moveItemToStatus(\n mapping.project_id,\n todoMapping.item_id,\n mapping.status_field_id,\n mapping.status_options['Done'],\n );\n }\n\n // Update local mapping status\n todoMapping.status = 'Done';\n saveMapping(cwd, mapping);\n }\n }\n }\n } catch (e) {\n githubWarning = `GitHub operation failed: ${(e as Error).message}`;\n }\n\n return mcpSuccess(\n {\n completed: true,\n file: todo_id,\n date: today,\n github_closed: githubClosed,\n ...(githubWarning ? { github_warning: githubWarning } : {}),\n },\n `Todo completed: ${todo_id}${githubClosed ? ' (GitHub issue closed)' : ''}`,\n );\n } catch (e) {\n return mcpError((e as Error).message, 'Operation failed');\n }\n },\n );\n\n // ── mcp_list_todos ──────────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_list_todos',\n 'List todo items, optionally filtered by area and status (pending, completed, or all).',\n {\n area: z.string().optional().describe('Filter by area/category'),\n status: z\n .enum(['pending', 'completed', 'all'])\n .optional()\n .default('pending')\n .describe('Which todos to list (default: pending)'),\n },\n async ({ area, status }) => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n const todosBase = planningPath(cwd, 'todos');\n const dirs: string[] = [];\n\n if (status === 'pending' || status === 'all') {\n dirs.push(path.join(todosBase, 'pending'));\n }\n if (status === 'completed' || status === 'all') {\n dirs.push(path.join(todosBase, 'completed'));\n }\n\n const todos: Array<{\n file: string;\n created: string;\n title: string;\n area: string;\n status: string;\n path: string;\n github_issue_number?: number;\n github_status?: string;\n }> = [];\n\n // Load GitHub mapping for enrichment (best effort)\n let todoMappings: Record<string, { number: number; status: string }> | null = null;\n let githubWarning: string | undefined;\n\n try {\n const mode = await detectGitHubMode();\n if (mode === 'full') {\n const mapping = loadMapping(cwd);\n if (mapping?.todos) {\n todoMappings = {};\n for (const [todoId, data] of Object.entries(mapping.todos)) {\n if (data.number > 0) {\n todoMappings[todoId] = {\n number: data.number,\n status: data.status,\n };\n }\n }\n }\n }\n } catch (e) {\n githubWarning = `GitHub enrichment failed: ${(e as Error).message}`;\n }\n\n for (const dir of dirs) {\n const dirStatus = dir.endsWith('pending') ? 'pending' : 'completed';\n\n let files: string[] = [];\n try {\n files = fs.readdirSync(dir).filter((f) => f.endsWith('.md'));\n } catch {\n // Directory may not exist\n continue;\n }\n\n for (const file of files) {\n try {\n const content = fs.readFileSync(path.join(dir, file), 'utf-8');\n const fm = parseTodoFrontmatter(content);\n\n if (area && fm.area !== area) continue;\n\n const todoEntry: (typeof todos)[number] = {\n file,\n created: fm.created,\n title: fm.title,\n area: fm.area,\n status: dirStatus,\n path: `.planning/todos/${dirStatus}/${file}`,\n };\n\n // Enrich with GitHub data if available\n if (todoMappings?.[file]) {\n todoEntry.github_issue_number = todoMappings[file].number;\n todoEntry.github_status = todoMappings[file].status;\n }\n\n todos.push(todoEntry);\n } catch {\n // Skip unreadable files\n }\n }\n }\n\n return mcpSuccess(\n {\n count: todos.length,\n todos,\n ...(githubWarning ? { github_warning: githubWarning } : {}),\n },\n `${todos.length} todos found`,\n );\n } catch (e) {\n return mcpError((e as Error).message, 'Operation failed');\n }\n },\n );\n}\n","/**\n * State Management MCP Tools — STATE.md operations exposed as MCP tools\n *\n * Integrates with GitHub: blocker add/resolve uses best-effort GitHub\n * issue linking when blocker text references issue numbers.\n *\n * CRITICAL: Never import output() or error() from core — they call process.exit().\n * CRITICAL: Never write to stdout — it is reserved for MCP JSON-RPC protocol.\n * CRITICAL: Never call process.exit() — the server must stay alive after every tool call.\n */\n\nimport fs from 'node:fs';\nimport { z } from 'zod';\nimport escapeStringRegexp from 'escape-string-regexp';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\n\nimport { statePath } from '../core/core.js';\nimport { stateExtractField, stateReplaceField, appendToStateSection } from '../core/state.js';\n\nimport { detectGitHubMode } from '../github/gh.js';\nimport { postComment } from '../github/issues.js';\n\nimport { detectProjectRoot, mcpSuccess, mcpError } from './utils.js';\n\n// ---- Helpers ---------------------------------------------------------------\n\n/**\n * Extract GitHub issue numbers from text.\n *\n * Matches patterns like \"#42\", \"issue 42\", \"issue #42\", \"blocked by #42\".\n * Returns unique issue numbers found.\n */\nfunction extractIssueNumbers(text: string): number[] {\n const matches = text.matchAll(/#(\\d+)|issue\\s+#?(\\d+)/gi);\n const numbers = new Set<number>();\n for (const match of matches) {\n const num = parseInt(match[1] || match[2], 10);\n if (!Number.isNaN(num) && num > 0) {\n numbers.add(num);\n }\n }\n return Array.from(numbers);\n}\n\n/**\n * Register all state management tools on the MCP server.\n */\nexport function registerStateTools(server: McpServer): void {\n // ── mcp_get_state ───────────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_get_state',\n 'Read STATE.md content — full file, a specific **field:** value, or a ## section.',\n {\n field: z\n .string()\n .optional()\n .describe('Specific field or section name, or omit for full STATE.md'),\n },\n async ({ field }) => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n const stPath = statePath(cwd);\n if (!fs.existsSync(stPath)) {\n return mcpError('STATE.md not found', 'STATE.md missing');\n }\n\n const content = fs.readFileSync(stPath, 'utf-8');\n\n if (!field) {\n return mcpSuccess({ content }, 'Full STATE.md retrieved');\n }\n\n // Try **field:** value pattern first\n const fieldValue = stateExtractField(content, field);\n if (fieldValue) {\n return mcpSuccess(\n { content: fieldValue, field },\n `State field retrieved: ${field}`,\n );\n }\n\n // Try ## Section pattern\n const fieldEscaped = escapeStringRegexp(field);\n const sectionPattern = new RegExp(\n `##\\\\s*${fieldEscaped}\\\\s*\\n([\\\\s\\\\S]*?)(?=\\\\n##|$)`,\n 'i',\n );\n const sectionMatch = content.match(sectionPattern);\n if (sectionMatch) {\n return mcpSuccess(\n { content: sectionMatch[1].trim(), field },\n `State section retrieved: ${field}`,\n );\n }\n\n return mcpError(\n `Section or field \"${field}\" not found in STATE.md`,\n 'Field not found',\n );\n } catch (e) {\n return mcpError((e as Error).message, 'Operation failed');\n }\n },\n );\n\n // ── mcp_update_state ────────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_update_state',\n 'Update a **field:** value in STATE.md (e.g., \"Status\", \"Current focus\").',\n {\n field: z.string().describe('Field name (e.g., \"Status\", \"Current focus\")'),\n value: z.string().describe('New value for the field'),\n },\n async ({ field, value }) => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n const stPath = statePath(cwd);\n if (!fs.existsSync(stPath)) {\n return mcpError('STATE.md not found', 'STATE.md missing');\n }\n\n const content = fs.readFileSync(stPath, 'utf-8');\n const updated = stateReplaceField(content, field, value);\n\n if (!updated) {\n return mcpError(\n `Field \"${field}\" not found in STATE.md`,\n 'Field not found',\n );\n }\n\n fs.writeFileSync(stPath, updated, 'utf-8');\n\n return mcpSuccess(\n { updated: true, field, value },\n `State updated: ${field}`,\n );\n } catch (e) {\n return mcpError((e as Error).message, 'Operation failed');\n }\n },\n );\n\n // ── mcp_add_decision ────────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_add_decision',\n 'Record a decision in the Decisions section of STATE.md.',\n {\n summary: z.string().describe('Decision summary'),\n rationale: z.string().optional().describe('Optional rationale'),\n phase: z.string().optional().describe('Associated phase number'),\n },\n async ({ summary, rationale, phase }) => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n const stPath = statePath(cwd);\n if (!fs.existsSync(stPath)) {\n return mcpError('STATE.md not found', 'STATE.md missing');\n }\n\n const content = fs.readFileSync(stPath, 'utf-8');\n const entry = `- [Phase ${phase || '?'}]: ${summary}${rationale ? ` -- ${rationale}` : ''}`;\n\n const sectionPattern =\n /(###?\\s*(?:Decisions|Decisions Made|Accumulated.*Decisions)\\s*\\n)([\\s\\S]*?)(?=\\n###?|\\n##[^#]|$)/i;\n const updated = appendToStateSection(content, sectionPattern, entry, [/None yet\\.?\\s*\\n?/gi, /No decisions yet\\.?\\s*\\n?/gi]);\n\n if (!updated) {\n return mcpError(\n 'Decisions section not found in STATE.md',\n 'Section not found',\n );\n }\n\n fs.writeFileSync(stPath, updated, 'utf-8');\n\n return mcpSuccess(\n { added: true, decision: entry },\n 'Decision recorded',\n );\n } catch (e) {\n return mcpError((e as Error).message, 'Operation failed');\n }\n },\n );\n\n // ── mcp_add_blocker ─────────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_add_blocker',\n 'Add a blocker entry to the Blockers section of STATE.md.',\n {\n text: z.string().describe('Blocker description'),\n },\n async ({ text }) => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n const stPath = statePath(cwd);\n if (!fs.existsSync(stPath)) {\n return mcpError('STATE.md not found', 'STATE.md missing');\n }\n\n const content = fs.readFileSync(stPath, 'utf-8');\n const entry = `- ${text}`;\n\n const sectionPattern =\n /(###?\\s*(?:Blockers|Blockers\\/Concerns|Concerns)\\s*\\n)([\\s\\S]*?)(?=\\n###?|\\n##[^#]|$)/i;\n const updated = appendToStateSection(content, sectionPattern, entry, [/None\\.?\\s*\\n?/gi, /None yet\\.?\\s*\\n?/gi]);\n\n if (!updated) {\n return mcpError(\n 'Blockers section not found in STATE.md',\n 'Section not found',\n );\n }\n\n fs.writeFileSync(stPath, updated, 'utf-8');\n\n // GitHub integration: best-effort dependency linking\n let githubLinked: number[] = [];\n let githubWarning: string | undefined;\n\n try {\n const mode = await detectGitHubMode();\n if (mode === 'full') {\n const issueNumbers = extractIssueNumbers(text);\n if (issueNumbers.length > 0) {\n for (const issueNum of issueNumbers) {\n const commentResult = await postComment(\n issueNum,\n `**Blocker added in MAXSIM:**\\n\\n${text}\\n\\n---\\n*Posted by MAXSIM blocker tracking*`,\n );\n if (commentResult.ok) {\n githubLinked.push(issueNum);\n }\n }\n }\n }\n } catch (e) {\n githubWarning = `GitHub linking failed: ${(e as Error).message}`;\n }\n\n return mcpSuccess(\n {\n added: true,\n blocker: text,\n github_linked_issues: githubLinked.length > 0 ? githubLinked : null,\n ...(githubWarning ? { github_warning: githubWarning } : {}),\n },\n `Blocker added${githubLinked.length > 0 ? ` (linked to ${githubLinked.map(n => `#${n}`).join(', ')})` : ''}`,\n );\n } catch (e) {\n return mcpError((e as Error).message, 'Operation failed');\n }\n },\n );\n\n // ── mcp_resolve_blocker ─────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_resolve_blocker',\n 'Remove a blocker from STATE.md by matching text (case-insensitive partial match).',\n {\n text: z\n .string()\n .describe('Text to match against blocker entries (case-insensitive partial match)'),\n },\n async ({ text }) => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n const stPath = statePath(cwd);\n if (!fs.existsSync(stPath)) {\n return mcpError('STATE.md not found', 'STATE.md missing');\n }\n\n let content = fs.readFileSync(stPath, 'utf-8');\n\n const sectionPattern =\n /(###?\\s*(?:Blockers|Blockers\\/Concerns|Concerns)\\s*\\n)([\\s\\S]*?)(?=\\n###?|\\n##[^#]|$)/i;\n const match = content.match(sectionPattern);\n\n if (!match) {\n return mcpError(\n 'Blockers section not found in STATE.md',\n 'Section not found',\n );\n }\n\n const sectionBody = match[2];\n const lines = sectionBody.split('\\n');\n\n // Collect matching blocker lines for GitHub comment\n const matchingLines: string[] = [];\n const filtered = lines.filter((line) => {\n if (!line.startsWith('- ')) return true;\n if (line.toLowerCase().includes(text.toLowerCase())) {\n matchingLines.push(line);\n return false;\n }\n return true;\n });\n\n let newBody = filtered.join('\\n');\n if (!newBody.trim() || !newBody.includes('- ')) {\n newBody = 'None\\n';\n }\n\n content = content.replace(\n sectionPattern,\n (_match, header: string) => `${header}${newBody}`,\n );\n\n fs.writeFileSync(stPath, content, 'utf-8');\n\n // GitHub integration: post resolution comment on referenced issues\n let githubCommented: number[] = [];\n let githubWarning: string | undefined;\n\n try {\n const mode = await detectGitHubMode();\n if (mode === 'full') {\n // Extract issue numbers from the matched blocker text\n const allText = matchingLines.join(' ') + ' ' + text;\n const issueNumbers = extractIssueNumbers(allText);\n if (issueNumbers.length > 0) {\n for (const issueNum of issueNumbers) {\n const commentResult = await postComment(\n issueNum,\n `**Blocker resolved in MAXSIM:**\\n\\nResolved blocker matching: \"${text}\"\\n\\n---\\n*Posted by MAXSIM blocker tracking*`,\n );\n if (commentResult.ok) {\n githubCommented.push(issueNum);\n }\n }\n }\n }\n } catch (e) {\n githubWarning = `GitHub comment failed: ${(e as Error).message}`;\n }\n\n return mcpSuccess(\n {\n resolved: true,\n blocker: text,\n github_commented_issues: githubCommented.length > 0 ? githubCommented : null,\n ...(githubWarning ? { github_warning: githubWarning } : {}),\n },\n `Blocker resolved${githubCommented.length > 0 ? ` (commented on ${githubCommented.map(n => `#${n}`).join(', ')})` : ''}`,\n );\n } catch (e) {\n return mcpError((e as Error).message, 'Operation failed');\n }\n },\n );\n}\n","/**\n * Context Query MCP Tools — Project context exposed as MCP tools\n *\n * CRITICAL: Never import output() or error() from core — they call process.exit().\n * CRITICAL: Never write to stdout — it is reserved for MCP JSON-RPC protocol.\n * CRITICAL: Never call process.exit() — the server must stay alive after every tool call.\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\n\nimport {\n findPhaseInternal,\n planningPath,\n safeReadFile,\n loadConfig,\n} from '../core/core.js';\n\nimport { cmdRoadmapAnalyze } from '../core/roadmap.js';\nimport { stateExtractField } from '../core/state.js';\nimport { cmdContextLoad } from '../core/context-loader.js';\nimport { detectProjectRoot, mcpSuccess, mcpError } from './utils.js';\n\n/**\n * Register all context query tools on the MCP server.\n */\nexport function registerContextTools(server: McpServer): void {\n // ── mcp_get_active_phase ────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_get_active_phase',\n 'Get the currently active phase and next phase from roadmap analysis and STATE.md.',\n {},\n async () => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n const roadmapResult = await cmdRoadmapAnalyze(cwd);\n let current_phase: unknown = null;\n let next_phase: unknown = null;\n let phase_name: string | null = null;\n let status: string | null = null;\n\n if (roadmapResult.ok) {\n const data = roadmapResult.result as Record<string, unknown>;\n current_phase = data.current_phase ?? null;\n next_phase = data.next_phase ?? null;\n }\n\n // Also read STATE.md for current phase field\n const stateContent = safeReadFile(planningPath(cwd, 'STATE.md'));\n if (stateContent) {\n const statePhase = stateExtractField(stateContent, 'Current Phase');\n if (statePhase) phase_name = statePhase;\n const stateStatus = stateExtractField(stateContent, 'Status');\n if (stateStatus) status = stateStatus;\n }\n\n return mcpSuccess(\n { current_phase, next_phase, phase_name, status },\n `Active phase: ${phase_name ?? current_phase ?? 'unknown'}`,\n );\n } catch (e: unknown) {\n return mcpError('Failed: ' + (e as Error).message, 'Error occurred');\n }\n },\n );\n\n // ── mcp_get_guidelines ──────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_get_guidelines',\n 'Get project guidelines: PROJECT.md vision, config, and optionally phase-specific context.',\n {\n phase: z\n .string()\n .optional()\n .describe('Optional phase number to include phase-specific context'),\n },\n async ({ phase }) => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n const project_vision = safeReadFile(planningPath(cwd, 'PROJECT.md'));\n const config = loadConfig(cwd);\n\n let phase_context: string | null = null;\n if (phase) {\n const phaseInfo = findPhaseInternal(cwd, phase);\n if (phaseInfo) {\n const contextPath = path.join(\n phaseInfo.directory,\n `${phaseInfo.phase_number}-CONTEXT.md`,\n );\n phase_context = safeReadFile(contextPath);\n }\n }\n\n return mcpSuccess(\n { project_vision, config, phase_context },\n `Guidelines loaded${phase ? ` with phase ${phase} context` : ''}`,\n );\n } catch (e: unknown) {\n return mcpError('Failed: ' + (e as Error).message, 'Error occurred');\n }\n },\n );\n\n // ── mcp_get_context_for_task ────────────────────────────────────────────────\n\n server.tool(\n 'mcp_get_context_for_task',\n 'Load context files for a task. Includes project context, roadmap, artefakte, and codebase docs filtered by topic. ' +\n 'Topic keywords select relevant codebase docs: \"ui/frontend\" loads CONVENTIONS+STRUCTURE, ' +\n '\"api/backend\" loads ARCHITECTURE+CONVENTIONS, \"testing\" loads TESTING+CONVENTIONS, ' +\n '\"database\" loads ARCHITECTURE+STACK, \"refactor\" loads CONCERNS+ARCHITECTURE. ' +\n 'Without topic, defaults to STACK+ARCHITECTURE.',\n {\n phase: z\n .string()\n .optional()\n .describe('Phase number to scope context to'),\n topic: z\n .string()\n .optional()\n .describe('Topic keywords to filter codebase docs (e.g. \"frontend\", \"api\", \"testing\", \"database\", \"refactor\")'),\n },\n async ({ phase, topic }) => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n const result = cmdContextLoad(cwd, phase, topic, true);\n if (!result.ok) {\n return mcpError(result.error, 'Context load failed');\n }\n\n return mcpSuccess(\n { context: result.result },\n `Context loaded${phase ? ` for phase ${phase}` : ''}${topic ? ` topic \"${topic}\"` : ''}`,\n );\n } catch (e: unknown) {\n return mcpError('Failed: ' + (e as Error).message, 'Error occurred');\n }\n },\n );\n\n // ── mcp_get_project_overview ────────────────────────────────────────────────\n\n server.tool(\n 'mcp_get_project_overview',\n 'Get a high-level project overview: PROJECT.md, REQUIREMENTS.md, and STATE.md contents.',\n {},\n async () => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n const project = safeReadFile(planningPath(cwd, 'PROJECT.md'));\n const requirements = safeReadFile(planningPath(cwd, 'REQUIREMENTS.md'));\n const state = safeReadFile(planningPath(cwd, 'STATE.md'));\n\n return mcpSuccess(\n { project, requirements, state },\n 'Project overview loaded',\n );\n } catch (e: unknown) {\n return mcpError('Failed: ' + (e as Error).message, 'Error occurred');\n }\n },\n );\n\n // ── mcp_get_phase_detail ────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_get_phase_detail',\n 'Get detailed information about a specific phase including all its files (plans, summaries, context, research, verification).',\n {\n phase: z.string().describe('Phase number or name (e.g. \"01\", \"1\", \"01A\")'),\n },\n async ({ phase }) => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n const phaseInfo = findPhaseInternal(cwd, phase);\n if (!phaseInfo) {\n return mcpError(`Phase ${phase} not found`, 'Phase not found');\n }\n\n // Read all files in the phase directory\n const files: Array<{ name: string; content: string | null }> = [];\n try {\n const entries = fs.readdirSync(phaseInfo.directory);\n for (const entry of entries) {\n const fullPath = path.join(phaseInfo.directory, entry);\n const stat = fs.statSync(fullPath);\n if (stat.isFile()) {\n files.push({\n name: entry,\n content: safeReadFile(fullPath),\n });\n }\n }\n } catch {\n // Directory may not exist or be empty\n }\n\n return mcpSuccess(\n {\n phase_number: phaseInfo.phase_number,\n phase_name: phaseInfo.phase_name,\n directory: phaseInfo.directory,\n files,\n },\n `Phase ${phaseInfo.phase_number} detail: ${files.length} file(s)`,\n );\n } catch (e: unknown) {\n return mcpError('Failed: ' + (e as Error).message, 'Error occurred');\n }\n },\n );\n}\n","/**\n * Roadmap Query MCP Tools — Roadmap analysis exposed as MCP tools\n *\n * CRITICAL: Never import output() or error() from core — they call process.exit().\n * CRITICAL: Never write to stdout — it is reserved for MCP JSON-RPC protocol.\n * CRITICAL: Never call process.exit() — the server must stay alive after every tool call.\n */\n\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\n\nimport { cmdRoadmapAnalyze } from '../core/roadmap.js';\nimport { detectProjectRoot, mcpSuccess, mcpError } from './utils.js';\n\n/**\n * Register all roadmap query tools on the MCP server.\n */\nexport function registerRoadmapTools(server: McpServer): void {\n // ── mcp_get_roadmap ─────────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_get_roadmap',\n 'Get the full roadmap analysis including all phases, their status, and progress.',\n {},\n async () => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n const result = await cmdRoadmapAnalyze(cwd);\n if (!result.ok) {\n return mcpError(result.error, 'Roadmap analysis failed');\n }\n\n return mcpSuccess(\n { roadmap: result.result },\n 'Roadmap analysis complete',\n );\n } catch (e: unknown) {\n return mcpError('Failed: ' + (e as Error).message, 'Error occurred');\n }\n },\n );\n\n // ── mcp_get_roadmap_progress ────────────────────────────────────────────────\n\n server.tool(\n 'mcp_get_roadmap_progress',\n 'Get a focused progress summary: total phases, completed, in-progress, not started, and progress percentage.',\n {},\n async () => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n const result = await cmdRoadmapAnalyze(cwd);\n if (!result.ok) {\n return mcpError(result.error, 'Roadmap analysis failed');\n }\n\n const data = result.result as Record<string, unknown>;\n const phases = (data.phases ?? []) as Array<Record<string, unknown>>;\n\n const total_phases = phases.length;\n let completed = 0;\n let in_progress = 0;\n let not_started = 0;\n\n for (const p of phases) {\n const status = String(p.status ?? '').toLowerCase();\n if (status === 'completed' || status === 'done') {\n completed++;\n } else if (status === 'in-progress' || status === 'in_progress' || status === 'active') {\n in_progress++;\n } else {\n not_started++;\n }\n }\n\n const progress_percent =\n total_phases > 0 ? Math.round((completed / total_phases) * 100) : 0;\n\n return mcpSuccess(\n {\n total_phases,\n completed,\n in_progress,\n not_started,\n progress_percent,\n current_phase: data.current_phase ?? null,\n next_phase: data.next_phase ?? null,\n },\n `Progress: ${completed}/${total_phases} phases complete (${progress_percent}%)`,\n );\n } catch (e: unknown) {\n return mcpError('Failed: ' + (e as Error).message, 'Error occurred');\n }\n },\n );\n}\n","/**\n * Config Query MCP Tools — Project configuration exposed as MCP tools\n *\n * CRITICAL: Never import output() or error() from core — they call process.exit().\n * CRITICAL: Never write to stdout — it is reserved for MCP JSON-RPC protocol.\n * CRITICAL: Never call process.exit() — the server must stay alive after every tool call.\n */\n\nimport { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\n\nimport { loadConfig } from '../core/core.js';\nimport { cmdConfigGet, cmdConfigSet } from '../core/config.js';\nimport { detectProjectRoot, mcpSuccess, mcpError } from './utils.js';\n\n/**\n * Register all config query tools on the MCP server.\n */\nexport function registerConfigTools(server: McpServer): void {\n // ── mcp_get_config ──────────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_get_config',\n 'Get project configuration. Optionally provide a key path to get a specific value.',\n {\n key: z\n .string()\n .optional()\n .describe('Optional dot-separated key path (e.g. \"model_profile\", \"branching.strategy\")'),\n },\n async ({ key }) => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n if (key) {\n const result = cmdConfigGet(cwd, key, true);\n if (!result.ok) {\n return mcpError(result.error, 'Config get failed');\n }\n return mcpSuccess(\n { key, value: result.rawValue ?? result.result },\n `Config value for \"${key}\"`,\n );\n }\n\n const config = loadConfig(cwd);\n return mcpSuccess(\n { config },\n 'Full configuration loaded',\n );\n } catch (e: unknown) {\n return mcpError('Failed: ' + (e as Error).message, 'Error occurred');\n }\n },\n );\n\n // ── mcp_update_config ───────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_update_config',\n 'Update a project configuration value by key path.',\n {\n key: z.string().describe('Dot-separated key path (e.g. \"model_profile\", \"branching.strategy\")'),\n value: z.string().describe('New value to set'),\n },\n async ({ key, value }) => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n const result = cmdConfigSet(cwd, key, value, true);\n if (!result.ok) {\n return mcpError(result.error, 'Config update failed');\n }\n\n return mcpSuccess(\n { updated: true, key, value },\n `Config \"${key}\" updated to \"${value}\"`,\n );\n } catch (e: unknown) {\n return mcpError('Failed: ' + (e as Error).message, 'Error occurred');\n }\n },\n );\n}\n","/**\n * GitHub Integration — Type definitions\n *\n * All types for the GitHub Issues/Projects v2 integration layer.\n * Used by gh.ts, mapping.ts, and downstream modules (issues, projects, etc.).\n */\n\n// ---- Error codes for gh CLI wrapper ----------------------------------------\n\nexport type GhErrorCode =\n | 'NOT_AUTHENTICATED'\n | 'NOT_INSTALLED'\n | 'RATE_LIMITED'\n | 'NOT_FOUND'\n | 'PERMISSION_DENIED'\n | 'SCOPE_MISSING'\n | 'UNKNOWN';\n\n// ---- GhResult discriminated union ------------------------------------------\n\nexport type GhResult<T> =\n | { ok: true; data: T }\n | { ok: false; error: string; code: GhErrorCode };\n\n// ---- Auth status -----------------------------------------------------------\n\nexport interface AuthStatus {\n installed: boolean;\n authenticated: boolean;\n scopes: string[];\n hasProjectScope: boolean;\n username: string | null;\n}\n\n// ---- GitHub operation mode -------------------------------------------------\n\nexport type GitHubMode = 'full' | 'local-only';\n\n// ---- Issue status ----------------------------------------------------------\n\nexport type IssueStatus = 'To Do' | 'In Progress' | 'In Review' | 'Done';\n\n// ---- Task-to-issue mapping -------------------------------------------------\n\nexport interface TaskIssueMapping {\n number: number;\n node_id: string;\n item_id: string;\n status: IssueStatus;\n}\n\n// ---- Phase mapping ---------------------------------------------------------\n\nexport interface PhaseMapping {\n tracking_issue: TaskIssueMapping;\n plan: string;\n tasks: Record<string, TaskIssueMapping>;\n}\n\n// ---- Root mapping file (.planning/github-issues.json) ----------------------\n\nexport interface IssueMappingFile {\n project_number: number;\n project_id: string;\n repo: string;\n status_field_id: string;\n status_options: Record<string, string>;\n estimate_field_id: string;\n milestone_id: number;\n milestone_title: string;\n labels: Record<string, string>;\n phases: Record<string, PhaseMapping>;\n todos: Record<string, TaskIssueMapping>;\n}\n\n// ---- Label definitions -----------------------------------------------------\n\nexport const MAXSIM_LABELS = [\n { name: 'maxsim', color: '6f42c1', description: 'MAXSIM managed issue' },\n { name: 'phase-task', color: '0075ca', description: 'MAXSIM phase task' },\n { name: 'todo', color: 'fbca04', description: 'MAXSIM todo item' },\n { name: 'imported', color: 'e4e669', description: 'Imported into MAXSIM tracking' },\n { name: 'superseded', color: 'd73a4a', description: 'Superseded by newer plan' },\n] as const;\n\n// ---- Fibonacci story points ------------------------------------------------\n\nexport const FIBONACCI_POINTS = [1, 2, 3, 5, 8, 13, 21, 34] as const;\n\n// ---- Default project board status columns ----------------------------------\n\nexport const DEFAULT_STATUS_OPTIONS = ['To Do', 'In Progress', 'In Review', 'Done'] as const;\n","/**\n * GitHub Labels — Label creation and verification\n *\n * Manages MAXSIM-specific labels on the GitHub repository.\n * Labels are created idempotently using `--force` flag (updates existing).\n * Uses `gh label create` for each label.\n *\n * CRITICAL: Never import octokit or any npm GitHub SDK.\n * CRITICAL: Never call process.exit() — return GhResult instead.\n */\n\nimport type { GhResult } from './types.js';\nimport { MAXSIM_LABELS } from './types.js';\nimport { ghExec } from './gh.js';\n\n// ---- Label Management ------------------------------------------------------\n\n/**\n * Ensure all MAXSIM labels exist on the repository.\n *\n * Iterates over MAXSIM_LABELS and runs `gh label create` with `--force`\n * for each label. The `--force` flag updates existing labels with the\n * specified color and description.\n *\n * Continues on individual label failures (logs to stderr).\n * Only fails if ALL labels fail to create.\n */\nexport async function ensureLabels(): Promise<GhResult<void>> {\n let successCount = 0;\n const errors: string[] = [];\n\n for (const label of MAXSIM_LABELS) {\n const result = await ghExec<string>([\n 'label', 'create', label.name,\n '--color', label.color,\n '--description', label.description,\n '--force',\n ]);\n\n if (result.ok) {\n successCount++;\n } else {\n // Log individual failure but continue\n const errMsg = result.error;\n console.error(`[maxsim] Failed to create label \"${label.name}\": ${errMsg}`);\n errors.push(`${label.name}: ${errMsg}`);\n }\n }\n\n // Only fail if ALL labels failed\n if (successCount === 0 && errors.length > 0) {\n return {\n ok: false,\n error: `All labels failed to create: ${errors.join('; ')}`,\n code: 'UNKNOWN',\n };\n }\n\n return { ok: true, data: undefined };\n}\n\n// Re-export MAXSIM_LABELS for convenience\nexport { MAXSIM_LABELS };\n","/**\n * GitHub Issue Templates — Template file generation\n *\n * Installs GitHub Issue Form YAML templates into `.github/ISSUE_TEMPLATE/`\n * for the MAXSIM-managed issue types: phase tasks and todos.\n *\n * These are file-system operations only (no gh CLI needed).\n * Uses synchronous fs to match existing core module patterns.\n *\n * CRITICAL: Never call process.exit().\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\n\n// ---- Template Content ------------------------------------------------------\n\n/**\n * Phase task issue template (GitHub Issue Forms YAML format).\n *\n * Used for issues created from MAXSIM phase plans.\n * Labels: maxsim, phase-task\n */\nconst PHASE_TASK_TEMPLATE = `name: \"MAXSIM Phase Task\"\ndescription: \"Task generated by MAXSIM phase planning\"\nlabels: [\"maxsim\", \"phase-task\"]\nbody:\n - type: markdown\n attributes:\n value: |\n This issue was auto-generated by MAXSIM.\n\n - type: textarea\n id: summary\n attributes:\n label: Summary\n description: Task summary\n validations:\n required: true\n\n - type: textarea\n id: spec\n attributes:\n label: Full Specification\n description: Detailed task specification including actions, criteria, and dependencies\n`;\n\n/**\n * Todo issue template (GitHub Issue Forms YAML format).\n *\n * Used for issues created from MAXSIM todo items.\n * Labels: maxsim, todo\n */\nconst TODO_TEMPLATE = `name: \"MAXSIM Todo\"\ndescription: \"Todo item tracked by MAXSIM\"\nlabels: [\"maxsim\", \"todo\"]\nbody:\n - type: textarea\n id: description\n attributes:\n label: Description\n description: Brief description of the todo item\n validations:\n required: true\n\n - type: textarea\n id: acceptance\n attributes:\n label: Acceptance Criteria\n description: What defines \"done\" for this todo?\n`;\n\n// ---- Installation ----------------------------------------------------------\n\n/**\n * Install MAXSIM issue templates into the project's `.github/ISSUE_TEMPLATE/` directory.\n *\n * Creates the directory recursively if it does not exist.\n * Writes two YAML files:\n * - phase-task.yml (for phase plan tasks)\n * - todo.yml (for todo items)\n *\n * Overwrites existing templates if present (to ensure latest version).\n * This is a synchronous file write operation (no gh CLI needed).\n */\nexport function installIssueTemplates(cwd: string): void {\n const templateDir = path.join(cwd, '.github', 'ISSUE_TEMPLATE');\n\n // Create directory recursively if it doesn't exist\n fs.mkdirSync(templateDir, { recursive: true });\n\n // Write phase task template\n fs.writeFileSync(\n path.join(templateDir, 'phase-task.yml'),\n PHASE_TASK_TEMPLATE,\n 'utf-8',\n );\n\n // Write todo template\n fs.writeFileSync(\n path.join(templateDir, 'todo.yml'),\n TODO_TEMPLATE,\n 'utf-8',\n );\n}\n","/**\n * GitHub Issue Lifecycle MCP Tools — GitHub operations exposed as MCP tools\n *\n * Provides MCP tools for issue CRUD, PR creation with auto-close linking (AC-08),\n * sync checking (AC-09), and issue import. Every tool checks detectGitHubMode()\n * and degrades gracefully to local-only behavior when GitHub is not configured.\n *\n * CRITICAL: Never import output() or error() from core — they call process.exit().\n * CRITICAL: Never write to stdout — it is reserved for MCP JSON-RPC protocol.\n * CRITICAL: Never call process.exit() — the server must stay alive after every tool call.\n */\n\nimport { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\n\nimport { detectGitHubMode, ghExec } from '../github/gh.js';\nimport {\n createAllPlanIssues,\n createTodoIssue,\n closeIssue,\n postComment,\n importExternalIssue,\n supersedePlanIssues,\n buildPrBody,\n} from '../github/issues.js';\nimport {\n ensureProjectBoard,\n addItemToProject,\n moveItemToStatus,\n setEstimate,\n} from '../github/projects.js';\nimport { ensureLabels } from '../github/labels.js';\nimport { ensureMilestone } from '../github/milestones.js';\nimport { installIssueTemplates } from '../github/templates.js';\nimport { loadMapping, saveMapping, updateTaskMapping } from '../github/mapping.js';\nimport { syncCheck } from '../github/sync.js';\n\nimport { detectProjectRoot, mcpSuccess, mcpError } from './utils.js';\n\n/**\n * Register all GitHub issue lifecycle tools on the MCP server.\n */\nexport function registerGitHubTools(server: McpServer): void {\n // ── mcp_github_setup ─────────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_github_setup',\n 'Set up GitHub integration: create project board, labels, milestone, and issue templates.',\n {\n milestone_title: z\n .string()\n .optional()\n .describe('Milestone title (defaults to current milestone from STATE.md)'),\n },\n async ({ milestone_title }) => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n const mode = await detectGitHubMode();\n\n // In local-only mode, only install issue templates (local files)\n if (mode === 'local-only') {\n installIssueTemplates(cwd);\n return mcpSuccess(\n {\n mode: 'local-only',\n templates_installed: true,\n board_created: false,\n labels_created: false,\n milestone_created: false,\n },\n 'Local-only mode: installed issue templates only. Run `gh auth login` with project scope for full GitHub integration.',\n );\n }\n\n // Full mode: create board, labels, milestone, templates\n const boardTitle = 'MAXSIM Task Board';\n const boardResult = await ensureProjectBoard(boardTitle, cwd);\n if (!boardResult.ok) {\n return mcpError(`Board setup failed: ${boardResult.error}`, 'Setup failed');\n }\n\n const labelsResult = await ensureLabels();\n if (!labelsResult.ok) {\n return mcpError(`Label setup failed: ${labelsResult.error}`, 'Setup failed');\n }\n\n let milestoneData: { number: number; id: number; created: boolean } | null = null;\n if (milestone_title) {\n const msResult = await ensureMilestone(milestone_title);\n if (msResult.ok) {\n milestoneData = msResult.data;\n\n // Update mapping with milestone info\n const mapping = loadMapping(cwd);\n if (mapping) {\n mapping.milestone_id = msResult.data.number;\n mapping.milestone_title = milestone_title;\n saveMapping(cwd, mapping);\n }\n }\n }\n\n installIssueTemplates(cwd);\n\n return mcpSuccess(\n {\n mode: 'full',\n board: {\n number: boardResult.data.number,\n created: boardResult.data.created,\n },\n labels_created: true,\n milestone: milestoneData\n ? {\n number: milestoneData.number,\n title: milestone_title,\n created: milestoneData.created,\n }\n : null,\n templates_installed: true,\n },\n `GitHub integration set up: board #${boardResult.data.number}, labels, ${milestoneData ? `milestone \"${milestone_title}\"` : 'no milestone'}, templates`,\n );\n } catch (e) {\n return mcpError((e as Error).message, 'Operation failed');\n }\n },\n );\n\n // ── mcp_create_plan_issues ───────────────────────────────────────────────────\n\n server.tool(\n 'mcp_create_plan_issues',\n 'Create GitHub issues for all tasks in a finalized plan. Creates task issues and parent tracking issue.',\n {\n phase: z.string().describe('Phase number (e.g. \"01\")'),\n plan: z.string().describe('Plan number (e.g. \"01\")'),\n phase_name: z.string().describe('Phase description for the tracking issue title'),\n tasks: z\n .array(\n z.object({\n taskId: z.string(),\n title: z.string(),\n summary: z.string(),\n actions: z.array(z.string()),\n acceptanceCriteria: z.array(z.string()),\n dependencies: z.array(z.string()).optional(),\n estimate: z.number().optional(),\n }),\n )\n .describe('Array of task objects to create issues for'),\n milestone: z.string().optional().describe('Milestone title to assign'),\n },\n async ({ phase, plan, phase_name, tasks, milestone }) => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n const mode = await detectGitHubMode();\n\n if (mode === 'local-only') {\n return mcpSuccess(\n {\n mode: 'local-only',\n warning: 'GitHub not configured, issues not created',\n tasks_count: tasks.length,\n },\n 'Local-only mode: GitHub issues not created. Run `gh auth login` for full integration.',\n );\n }\n\n // Get project title for auto-adding to board\n const mapping = loadMapping(cwd);\n const projectTitle = mapping?.project_number\n ? undefined // Will be added separately via addItemToProject\n : undefined;\n\n const result = await createAllPlanIssues({\n phaseNum: phase,\n planNum: plan,\n phaseName: phase_name,\n tasks,\n milestone,\n projectTitle,\n cwd,\n });\n\n if (!result.ok) {\n return mcpError(`Issue creation failed: ${result.error}`, 'Creation failed');\n }\n\n // Add all issues to project board and set estimates\n if (mapping && mapping.project_number > 0) {\n const repo = mapping.repo;\n const allIssueNumbers = [\n result.data.parentIssue,\n ...result.data.taskIssues.map(t => t.issueNumber),\n ];\n\n for (const issueNum of allIssueNumbers) {\n const issueUrl = `https://github.com/${repo}/issues/${issueNum}`;\n const addResult = await addItemToProject(mapping.project_number, issueUrl);\n if (addResult.ok) {\n // Store item_id in mapping for board operations\n const taskEntry = result.data.taskIssues.find(t => t.issueNumber === issueNum);\n if (taskEntry) {\n updateTaskMapping(cwd, phase, taskEntry.taskId, {\n item_id: addResult.data.item_id,\n });\n }\n\n // Move to \"To Do\" status\n if (mapping.status_options['To Do'] && mapping.status_field_id) {\n await moveItemToStatus(\n mapping.project_id,\n addResult.data.item_id,\n mapping.status_field_id,\n mapping.status_options['To Do'],\n );\n }\n\n // Set estimate if task has one\n if (taskEntry && mapping.estimate_field_id) {\n const taskDef = tasks.find(t => t.taskId === taskEntry.taskId);\n if (taskDef?.estimate) {\n await setEstimate(\n mapping.project_id,\n addResult.data.item_id,\n mapping.estimate_field_id,\n taskDef.estimate,\n );\n }\n }\n }\n }\n }\n\n return mcpSuccess(\n {\n mode: 'full',\n parent_issue: result.data.parentIssue,\n task_issues: result.data.taskIssues,\n total_created: result.data.taskIssues.length + 1,\n },\n `Created ${result.data.taskIssues.length} task issues + parent tracking issue #${result.data.parentIssue}`,\n );\n } catch (e) {\n return mcpError((e as Error).message, 'Operation failed');\n }\n },\n );\n\n // ── mcp_create_todo_issue ────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_create_todo_issue',\n 'Create a GitHub issue for a todo item.',\n {\n title: z.string().describe('Todo title'),\n description: z.string().optional().describe('Todo description'),\n acceptance_criteria: z\n .array(z.string())\n .optional()\n .describe('Acceptance criteria list'),\n },\n async ({ title, description, acceptance_criteria }) => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n const mode = await detectGitHubMode();\n\n if (mode === 'local-only') {\n return mcpSuccess(\n {\n mode: 'local-only',\n warning: 'GitHub not configured. Use mcp_add_todo for local todo tracking.',\n title,\n },\n 'Local-only mode: GitHub todo issue not created.',\n );\n }\n\n const mapping = loadMapping(cwd);\n const result = await createTodoIssue({\n title,\n description,\n acceptanceCriteria: acceptance_criteria,\n milestone: mapping?.milestone_title || undefined,\n });\n\n if (!result.ok) {\n return mcpError(`Todo issue creation failed: ${result.error}`, 'Creation failed');\n }\n\n // Add to project board\n if (mapping && mapping.project_number > 0) {\n const issueUrl = `https://github.com/${mapping.repo}/issues/${result.data.number}`;\n const addResult = await addItemToProject(mapping.project_number, issueUrl);\n if (addResult.ok && mapping) {\n // Update mapping\n if (!mapping.todos) {\n mapping.todos = {};\n }\n mapping.todos[`todo-${result.data.number}`] = {\n number: result.data.number,\n node_id: result.data.node_id,\n item_id: addResult.data.item_id,\n status: 'To Do',\n };\n saveMapping(cwd, mapping);\n }\n }\n\n return mcpSuccess(\n {\n mode: 'full',\n issue_number: result.data.number,\n url: result.data.url,\n },\n `Created todo issue #${result.data.number}: ${title}`,\n );\n } catch (e) {\n return mcpError((e as Error).message, 'Operation failed');\n }\n },\n );\n\n // ── mcp_move_issue ───────────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_move_issue',\n 'Move a GitHub issue to a new status column (To Do, In Progress, In Review, Done).',\n {\n issue_number: z.number().describe('GitHub issue number'),\n status: z\n .enum(['To Do', 'In Progress', 'In Review', 'Done'])\n .describe('Target status column'),\n },\n async ({ issue_number, status }) => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n const mode = await detectGitHubMode();\n const mapping = loadMapping(cwd);\n\n if (mode === 'local-only') {\n // In local-only mode, just update local mapping status\n if (mapping) {\n const updated = updateLocalMappingStatus(mapping, issue_number, status);\n if (updated) {\n saveMapping(cwd, mapping);\n return mcpSuccess(\n { mode: 'local-only', issue_number, status, local_updated: true },\n `Local mapping updated: issue #${issue_number} -> ${status}`,\n );\n }\n }\n return mcpError(\n `Issue #${issue_number} not found in local mapping`,\n 'Issue not tracked',\n );\n }\n\n if (!mapping) {\n return mcpError(\n 'github-issues.json not found. Run mcp_github_setup first.',\n 'Setup required',\n );\n }\n\n // Find the item_id for this issue in the mapping\n const issueEntry = findIssueInMapping(mapping, issue_number);\n if (!issueEntry) {\n return mcpError(\n `Issue #${issue_number} not found in local mapping`,\n 'Issue not tracked',\n );\n }\n\n if (!issueEntry.item_id) {\n return mcpError(\n `Issue #${issue_number} has no project item_id. It may not have been added to the board.`,\n 'Not on board',\n );\n }\n\n const statusOptionId = mapping.status_options[status];\n if (!statusOptionId) {\n return mcpError(\n `Status \"${status}\" not found in project board options`,\n 'Invalid status',\n );\n }\n\n const moveResult = await moveItemToStatus(\n mapping.project_id,\n issueEntry.item_id,\n mapping.status_field_id,\n statusOptionId,\n );\n\n if (!moveResult.ok) {\n return mcpError(`Move failed: ${moveResult.error}`, 'Move failed');\n }\n\n // Update local mapping\n updateLocalMappingStatus(mapping, issue_number, status);\n saveMapping(cwd, mapping);\n\n return mcpSuccess(\n { mode: 'full', issue_number, status, moved: true },\n `Issue #${issue_number} moved to \"${status}\"`,\n );\n } catch (e) {\n return mcpError((e as Error).message, 'Operation failed');\n }\n },\n );\n\n // ── mcp_close_issue ──────────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_close_issue',\n 'Close a GitHub issue as completed or not planned.',\n {\n issue_number: z.number().describe('GitHub issue number'),\n reason: z\n .enum(['completed', 'not_planned'])\n .optional()\n .default('completed')\n .describe('Close reason'),\n },\n async ({ issue_number, reason }) => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n const mode = await detectGitHubMode();\n\n if (mode === 'local-only') {\n return mcpSuccess(\n {\n mode: 'local-only',\n warning: 'GitHub not configured. Cannot close remote issue.',\n issue_number,\n },\n 'Local-only mode: cannot close GitHub issue.',\n );\n }\n\n const result = await closeIssue(issue_number, reason);\n if (!result.ok) {\n return mcpError(`Close failed: ${result.error}`, 'Close failed');\n }\n\n // Move to Done on board and update local mapping\n const mapping = loadMapping(cwd);\n if (mapping) {\n const issueEntry = findIssueInMapping(mapping, issue_number);\n if (issueEntry?.item_id && mapping.status_options['Done'] && mapping.status_field_id) {\n await moveItemToStatus(\n mapping.project_id,\n issueEntry.item_id,\n mapping.status_field_id,\n mapping.status_options['Done'],\n );\n }\n updateLocalMappingStatus(mapping, issue_number, 'Done');\n saveMapping(cwd, mapping);\n }\n\n return mcpSuccess(\n { mode: 'full', issue_number, reason, closed: true },\n `Issue #${issue_number} closed (${reason})`,\n );\n } catch (e) {\n return mcpError((e as Error).message, 'Operation failed');\n }\n },\n );\n\n // ── mcp_post_comment ─────────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_post_comment',\n 'Post a progress comment on a GitHub issue.',\n {\n issue_number: z.number().describe('GitHub issue number'),\n body: z.string().describe('Comment body (markdown supported)'),\n },\n async ({ issue_number, body }) => {\n try {\n const mode = await detectGitHubMode();\n\n if (mode === 'local-only') {\n return mcpSuccess(\n {\n mode: 'local-only',\n warning: 'GitHub not configured. Cannot post comment.',\n issue_number,\n },\n 'Local-only mode: cannot post comment on GitHub issue.',\n );\n }\n\n const result = await postComment(issue_number, body);\n if (!result.ok) {\n return mcpError(`Comment failed: ${result.error}`, 'Comment failed');\n }\n\n return mcpSuccess(\n { mode: 'full', issue_number, commented: true },\n `Comment posted on issue #${issue_number}`,\n );\n } catch (e) {\n return mcpError((e as Error).message, 'Operation failed');\n }\n },\n );\n\n // ── mcp_import_issue ─────────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_import_issue',\n 'Import an external GitHub issue into MAXSIM tracking.',\n {\n issue_number: z.number().describe('GitHub issue number to import'),\n },\n async ({ issue_number }) => {\n try {\n const mode = await detectGitHubMode();\n\n if (mode === 'local-only') {\n return mcpSuccess(\n {\n mode: 'local-only',\n warning: 'GitHub not configured. Cannot import issue.',\n issue_number,\n },\n 'Local-only mode: cannot import GitHub issue.',\n );\n }\n\n const result = await importExternalIssue(issue_number);\n if (!result.ok) {\n return mcpError(`Import failed: ${result.error}`, 'Import failed');\n }\n\n return mcpSuccess(\n {\n mode: 'full',\n issue_number: result.data.number,\n title: result.data.title,\n labels: result.data.labels,\n imported: true,\n },\n `Imported issue #${result.data.number}: \"${result.data.title}\". Assign to a phase or todo for tracking.`,\n );\n } catch (e) {\n return mcpError((e as Error).message, 'Operation failed');\n }\n },\n );\n\n // ── mcp_sync_check ───────────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_sync_check',\n 'Check for external changes to tracked GitHub issues.',\n {},\n async () => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n const mode = await detectGitHubMode();\n\n if (mode === 'local-only') {\n return mcpSuccess(\n {\n mode: 'local-only',\n warning: 'GitHub not configured. Sync check not available.',\n in_sync: true,\n changes: [],\n },\n 'Local-only mode: sync check skipped.',\n );\n }\n\n const result = await syncCheck(cwd);\n if (!result.ok) {\n return mcpError(`Sync check failed: ${result.error}`, 'Sync failed');\n }\n\n return mcpSuccess(\n {\n mode: 'full',\n in_sync: result.data.inSync,\n changes: result.data.changes,\n change_count: result.data.changes.length,\n },\n result.data.inSync\n ? 'All tracked issues are in sync with GitHub.'\n : `${result.data.changes.length} discrepancies found between local mapping and GitHub.`,\n );\n } catch (e) {\n return mcpError((e as Error).message, 'Operation failed');\n }\n },\n );\n\n // ── mcp_supersede_plan ───────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_supersede_plan',\n 'Close old plan issues and link to new plan issues.',\n {\n phase: z.string().describe('Phase number'),\n old_plan: z.string().describe('Old plan number to supersede'),\n new_plan: z.string().describe('New plan number that replaces it'),\n },\n async ({ phase, old_plan, new_plan }) => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n const mode = await detectGitHubMode();\n\n if (mode === 'local-only') {\n return mcpSuccess(\n {\n mode: 'local-only',\n warning: 'GitHub not configured. Cannot supersede plan issues.',\n phase,\n old_plan,\n new_plan,\n },\n 'Local-only mode: plan supersession skipped.',\n );\n }\n\n const mapping = loadMapping(cwd);\n if (!mapping) {\n return mcpError(\n 'github-issues.json not found. Run mcp_github_setup first.',\n 'Setup required',\n );\n }\n\n // Get new plan's issue numbers from the mapping (they should exist from mcp_create_plan_issues)\n const newPhaseMapping = mapping.phases[phase];\n if (!newPhaseMapping) {\n return mcpError(\n `Phase ${phase} not found in mapping. Create new plan issues first.`,\n 'Phase not found',\n );\n }\n\n const newIssueNumbers = Object.entries(newPhaseMapping.tasks).map(\n ([taskId, task]) => ({ taskId, issueNumber: task.number }),\n );\n\n const result = await supersedePlanIssues({\n phaseNum: phase,\n oldPlanNum: old_plan,\n newPlanNum: new_plan,\n newIssueNumbers,\n cwd,\n });\n\n if (!result.ok) {\n return mcpError(`Supersession failed: ${result.error}`, 'Supersession failed');\n }\n\n return mcpSuccess(\n {\n mode: 'full',\n phase,\n old_plan,\n new_plan,\n superseded: true,\n },\n `Plan ${phase}-${old_plan} superseded by ${phase}-${new_plan}`,\n );\n } catch (e) {\n return mcpError((e as Error).message, 'Operation failed');\n }\n },\n );\n\n // ── mcp_create_pr ────────────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_create_pr',\n 'Create a pull request with auto-close linking for tracked GitHub issues. Generates PR description with Closes #N lines (AC-08).',\n {\n issue_numbers: z\n .array(z.number())\n .describe('Issue numbers to auto-close when PR merges'),\n branch: z.string().describe('Source branch name for the PR'),\n title: z.string().describe('PR title'),\n base: z.string().optional().default('main').describe('Base branch (default: main)'),\n additional_context: z\n .string()\n .optional()\n .describe('Additional context to include in PR body'),\n draft: z.boolean().optional().default(false).describe('Create as draft PR'),\n },\n async ({ issue_numbers, branch, title, base, additional_context, draft }) => {\n try {\n const mode = await detectGitHubMode();\n\n // Build PR body with Closes #N lines (AC-08)\n const prBody = buildPrBody(issue_numbers, additional_context);\n\n if (mode === 'local-only') {\n // Return the generated body so user can create PR manually\n return mcpSuccess(\n {\n mode: 'local-only',\n warning: 'GitHub not configured. PR not created. Use the body below to create manually.',\n pr_body: prBody,\n issues_linked: issue_numbers,\n },\n 'Local-only mode: PR body generated but PR not created.',\n );\n }\n\n // Create the PR via gh CLI\n const args: string[] = [\n 'pr',\n 'create',\n '--title',\n title,\n '--body',\n prBody,\n '--head',\n branch,\n ];\n\n if (base) {\n args.push('--base', base);\n }\n\n if (draft) {\n args.push('--draft');\n }\n\n const createResult = await ghExec<string>(args);\n if (!createResult.ok) {\n return mcpError(`PR creation failed: ${createResult.error}`, 'PR creation failed');\n }\n\n // Parse PR URL and number from stdout\n const prUrl = createResult.data.trim();\n const prNumberMatch = prUrl.match(/\\/pull\\/(\\d+)/);\n const prNumber = prNumberMatch ? parseInt(prNumberMatch[1], 10) : null;\n\n return mcpSuccess(\n {\n mode: 'full',\n pr_number: prNumber,\n pr_url: prUrl,\n issues_linked: issue_numbers,\n draft,\n },\n `PR${draft ? ' (draft)' : ''} created: ${prUrl} — auto-closes ${issue_numbers.map(n => `#${n}`).join(', ')}`,\n );\n } catch (e) {\n return mcpError((e as Error).message, 'Operation failed');\n }\n },\n );\n}\n\n// ---- Internal Helpers ──────────────────────────────────────────────────────\n\nimport type { IssueMappingFile, IssueStatus, TaskIssueMapping } from '../github/types.js';\n\n/**\n * Find an issue entry in the mapping file (searches phases and todos).\n */\nfunction findIssueInMapping(\n mapping: IssueMappingFile,\n issueNumber: number,\n): TaskIssueMapping | null {\n // Search phases\n for (const phase of Object.values(mapping.phases)) {\n if (phase.tracking_issue.number === issueNumber) {\n return phase.tracking_issue;\n }\n for (const task of Object.values(phase.tasks)) {\n if (task.number === issueNumber) {\n return task;\n }\n }\n }\n\n // Search todos\n if (mapping.todos) {\n for (const todo of Object.values(mapping.todos)) {\n if (todo.number === issueNumber) {\n return todo;\n }\n }\n }\n\n return null;\n}\n\n/**\n * Update local mapping status for an issue (mutates mapping in-place).\n * Returns true if the issue was found and updated.\n */\nfunction updateLocalMappingStatus(\n mapping: IssueMappingFile,\n issueNumber: number,\n status: IssueStatus,\n): boolean {\n // Search phases\n for (const phase of Object.values(mapping.phases)) {\n if (phase.tracking_issue.number === issueNumber) {\n phase.tracking_issue.status = status;\n return true;\n }\n for (const task of Object.values(phase.tasks)) {\n if (task.number === issueNumber) {\n task.status = status;\n return true;\n }\n }\n }\n\n // Search todos\n if (mapping.todos) {\n for (const todo of Object.values(mapping.todos)) {\n if (todo.number === issueNumber) {\n todo.status = status;\n return true;\n }\n }\n }\n\n return false;\n}\n","/**\n * Board Query MCP Tools — Project board operations exposed as MCP tools\n *\n * Provides MCP tools for querying the GitHub project board, searching issues,\n * getting issue details, and setting estimates. Every tool checks detectGitHubMode()\n * and degrades gracefully to local-only behavior when GitHub is not configured.\n *\n * CRITICAL: Never import output() or error() from core — they call process.exit().\n * CRITICAL: Never write to stdout — it is reserved for MCP JSON-RPC protocol.\n * CRITICAL: Never call process.exit() — the server must stay alive after every tool call.\n */\n\nimport { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\n\nimport { detectGitHubMode, ghExec } from '../github/gh.js';\nimport { setEstimate } from '../github/projects.js';\nimport { loadMapping } from '../github/mapping.js';\nimport { FIBONACCI_POINTS } from '../github/types.js';\nimport type { IssueMappingFile, TaskIssueMapping } from '../github/types.js';\n\nimport { detectProjectRoot, mcpSuccess, mcpError } from './utils.js';\n\n/**\n * Register all board query tools on the MCP server.\n */\nexport function registerBoardTools(server: McpServer): void {\n // ── mcp_query_board ──────────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_query_board',\n 'Query the GitHub project board. Returns all items with their status, estimates, and issue details.',\n {\n status: z\n .enum(['To Do', 'In Progress', 'In Review', 'Done'])\n .optional()\n .describe('Filter by status column'),\n phase: z\n .string()\n .optional()\n .describe('Filter by phase number (matches issue title prefix)'),\n },\n async ({ status, phase }) => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n const mode = await detectGitHubMode();\n const mapping = loadMapping(cwd);\n\n if (mode === 'local-only') {\n // Return local mapping data as fallback\n if (!mapping) {\n return mcpSuccess(\n { mode: 'local-only', items: [], count: 0 },\n 'Local-only mode: no mapping file found.',\n );\n }\n\n const items = buildLocalBoardItems(mapping, status, phase);\n return mcpSuccess(\n { mode: 'local-only', items, count: items.length },\n `Local-only mode: ${items.length} items from local mapping.`,\n );\n }\n\n if (!mapping || !mapping.project_number) {\n return mcpError(\n 'No project board configured. Run mcp_github_setup first.',\n 'Setup required',\n );\n }\n\n // Query the project board via gh CLI\n const result = await ghExec<{\n items: Array<{\n id: string;\n title: string;\n status: string | null;\n content: { number: number; type: string; title: string; url: string } | null;\n }>;\n }>(\n [\n 'project',\n 'item-list',\n String(mapping.project_number),\n '--owner',\n '@me',\n '--format',\n 'json',\n ],\n { parseJson: true },\n );\n\n if (!result.ok) {\n return mcpError(`Board query failed: ${result.error}`, 'Query failed');\n }\n\n let items = result.data.items || [];\n\n // Filter by status\n if (status) {\n items = items.filter(item => item.status === status);\n }\n\n // Filter by phase (match title prefix like \"[P01]\" or \"[Phase 01]\")\n if (phase) {\n const phasePrefix = `[P${phase}]`;\n const phasePrefixAlt = `[Phase ${phase}]`;\n items = items.filter(\n item =>\n item.title?.includes(phasePrefix) ||\n item.title?.includes(phasePrefixAlt) ||\n item.content?.title?.includes(phasePrefix) ||\n item.content?.title?.includes(phasePrefixAlt),\n );\n }\n\n const formatted = items.map(item => ({\n item_id: item.id,\n title: item.content?.title ?? item.title,\n issue_number: item.content?.number ?? null,\n status: item.status ?? 'No Status',\n url: item.content?.url ?? null,\n }));\n\n return mcpSuccess(\n { mode: 'full', items: formatted, count: formatted.length },\n `Board query: ${formatted.length} items${status ? ` in \"${status}\"` : ''}${phase ? ` for phase ${phase}` : ''}`,\n );\n } catch (e) {\n return mcpError((e as Error).message, 'Operation failed');\n }\n },\n );\n\n // ── mcp_search_issues ────────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_search_issues',\n 'Search GitHub issues by label, milestone, state, or text query.',\n {\n labels: z\n .array(z.string())\n .optional()\n .describe('Filter by label names'),\n milestone: z\n .string()\n .optional()\n .describe('Filter by milestone title'),\n state: z\n .enum(['open', 'closed', 'all'])\n .optional()\n .default('open')\n .describe('Filter by issue state'),\n query: z\n .string()\n .optional()\n .describe('Text search query'),\n },\n async ({ labels, milestone, state, query }) => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n const mode = await detectGitHubMode();\n\n if (mode === 'local-only') {\n // Return local mapping data as fallback\n const mapping = loadMapping(cwd);\n if (!mapping) {\n return mcpSuccess(\n { mode: 'local-only', issues: [], count: 0 },\n 'Local-only mode: no mapping file found.',\n );\n }\n\n const items = buildLocalSearchResults(mapping, state);\n return mcpSuccess(\n { mode: 'local-only', issues: items, count: items.length },\n `Local-only mode: ${items.length} items from local mapping.`,\n );\n }\n\n // Build gh issue list args\n const args: string[] = [\n 'issue',\n 'list',\n '--json',\n 'number,title,state,labels,milestone',\n '--limit',\n '100',\n ];\n\n if (state && state !== 'all') {\n args.push('--state', state);\n } else if (state === 'all') {\n args.push('--state', 'all');\n }\n\n if (labels && labels.length > 0) {\n for (const label of labels) {\n args.push('--label', label);\n }\n }\n\n if (milestone) {\n args.push('--milestone', milestone);\n }\n\n if (query) {\n args.push('--search', query);\n }\n\n const result = await ghExec<\n Array<{\n number: number;\n title: string;\n state: string;\n labels: Array<{ name: string }>;\n milestone: { title: string } | null;\n }>\n >(args, { parseJson: true });\n\n if (!result.ok) {\n return mcpError(`Search failed: ${result.error}`, 'Search failed');\n }\n\n const issues = result.data.map(issue => ({\n number: issue.number,\n title: issue.title,\n state: issue.state,\n labels: issue.labels.map(l => l.name),\n milestone: issue.milestone?.title ?? null,\n }));\n\n return mcpSuccess(\n { mode: 'full', issues, count: issues.length },\n `Found ${issues.length} issues`,\n );\n } catch (e) {\n return mcpError((e as Error).message, 'Operation failed');\n }\n },\n );\n\n // ── mcp_get_issue_detail ─────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_get_issue_detail',\n 'Get full details of a specific GitHub issue including comments.',\n {\n issue_number: z.number().describe('GitHub issue number'),\n },\n async ({ issue_number }) => {\n try {\n const mode = await detectGitHubMode();\n\n if (mode === 'local-only') {\n return mcpSuccess(\n {\n mode: 'local-only',\n warning: 'GitHub not configured. Cannot fetch issue details.',\n issue_number,\n },\n 'Local-only mode: cannot fetch issue details.',\n );\n }\n\n const result = await ghExec<{\n number: number;\n title: string;\n body: string;\n state: string;\n labels: Array<{ name: string }>;\n comments: Array<{ author: { login: string }; body: string; createdAt: string }>;\n assignees: Array<{ login: string }>;\n }>(\n [\n 'issue',\n 'view',\n String(issue_number),\n '--json',\n 'number,title,body,state,labels,comments,assignees',\n ],\n { parseJson: true },\n );\n\n if (!result.ok) {\n return mcpError(`Fetch failed: ${result.error}`, 'Fetch failed');\n }\n\n const issue = result.data;\n\n return mcpSuccess(\n {\n mode: 'full',\n number: issue.number,\n title: issue.title,\n body: issue.body,\n state: issue.state,\n labels: issue.labels.map(l => l.name),\n assignees: issue.assignees.map(a => a.login),\n comments: issue.comments.map(c => ({\n author: c.author.login,\n body: c.body,\n created_at: c.createdAt,\n })),\n comment_count: issue.comments.length,\n },\n `Issue #${issue.number}: ${issue.title} (${issue.state})`,\n );\n } catch (e) {\n return mcpError((e as Error).message, 'Operation failed');\n }\n },\n );\n\n // ── mcp_set_estimate ─────────────────────────────────────────────────────────\n\n server.tool(\n 'mcp_set_estimate',\n 'Set Fibonacci story points on a GitHub issue.',\n {\n issue_number: z.number().describe('GitHub issue number'),\n points: z.number().describe('Fibonacci story points (1, 2, 3, 5, 8, 13, 21, 34)'),\n },\n async ({ issue_number, points }) => {\n try {\n const cwd = detectProjectRoot();\n if (!cwd) {\n return mcpError('No .planning/ directory found', 'Project not detected');\n }\n\n // Validate Fibonacci points\n if (!(FIBONACCI_POINTS as readonly number[]).includes(points)) {\n return mcpError(\n `Invalid points: ${points}. Must be one of: ${FIBONACCI_POINTS.join(', ')}`,\n 'Validation failed',\n );\n }\n\n const mode = await detectGitHubMode();\n\n if (mode === 'local-only') {\n return mcpSuccess(\n {\n mode: 'local-only',\n warning: 'GitHub not configured. Cannot set estimate.',\n issue_number,\n points,\n },\n 'Local-only mode: cannot set estimate on GitHub project.',\n );\n }\n\n const mapping = loadMapping(cwd);\n if (!mapping) {\n return mcpError(\n 'github-issues.json not found. Run mcp_github_setup first.',\n 'Setup required',\n );\n }\n\n if (!mapping.estimate_field_id) {\n return mcpError(\n 'Estimate field not configured. Re-run mcp_github_setup.',\n 'Setup required',\n );\n }\n\n // Find item_id for this issue\n const issueEntry = findIssueInMapping(mapping, issue_number);\n if (!issueEntry) {\n return mcpError(\n `Issue #${issue_number} not found in local mapping`,\n 'Issue not tracked',\n );\n }\n\n if (!issueEntry.item_id) {\n return mcpError(\n `Issue #${issue_number} has no project item_id. It may not have been added to the board.`,\n 'Not on board',\n );\n }\n\n const result = await setEstimate(\n mapping.project_id,\n issueEntry.item_id,\n mapping.estimate_field_id,\n points,\n );\n\n if (!result.ok) {\n return mcpError(`Set estimate failed: ${result.error}`, 'Estimate failed');\n }\n\n return mcpSuccess(\n { mode: 'full', issue_number, points, set: true },\n `Estimate set: issue #${issue_number} = ${points} points`,\n );\n } catch (e) {\n return mcpError((e as Error).message, 'Operation failed');\n }\n },\n );\n}\n\n// ---- Internal Helpers ──────────────────────────────────────────────────────\n\n/**\n * Find an issue entry in the mapping file (searches phases and todos).\n */\nfunction findIssueInMapping(\n mapping: IssueMappingFile,\n issueNumber: number,\n): TaskIssueMapping | null {\n // Search phases\n for (const phase of Object.values(mapping.phases)) {\n if (phase.tracking_issue.number === issueNumber) {\n return phase.tracking_issue;\n }\n for (const task of Object.values(phase.tasks)) {\n if (task.number === issueNumber) {\n return task;\n }\n }\n }\n\n // Search todos\n if (mapping.todos) {\n for (const todo of Object.values(mapping.todos)) {\n if (todo.number === issueNumber) {\n return todo;\n }\n }\n }\n\n return null;\n}\n\n/**\n * Build local board items from the mapping file (for local-only mode).\n */\nfunction buildLocalBoardItems(\n mapping: IssueMappingFile,\n statusFilter?: string,\n phaseFilter?: string,\n): Array<{\n issue_number: number;\n title: string;\n status: string;\n source: string;\n}> {\n const items: Array<{\n issue_number: number;\n title: string;\n status: string;\n source: string;\n }> = [];\n\n for (const [phaseNum, phase] of Object.entries(mapping.phases)) {\n if (phaseFilter && phaseNum !== phaseFilter) continue;\n\n if (phase.tracking_issue.number > 0) {\n const entry = {\n issue_number: phase.tracking_issue.number,\n title: `[Phase ${phaseNum}] Tracking`,\n status: phase.tracking_issue.status,\n source: `phase ${phaseNum}`,\n };\n if (!statusFilter || entry.status === statusFilter) {\n items.push(entry);\n }\n }\n\n for (const [taskId, task] of Object.entries(phase.tasks)) {\n if (task.number > 0) {\n const entry = {\n issue_number: task.number,\n title: `[P${phaseNum}] Task ${taskId}`,\n status: task.status,\n source: `phase ${phaseNum}, task ${taskId}`,\n };\n if (!statusFilter || entry.status === statusFilter) {\n items.push(entry);\n }\n }\n }\n }\n\n // Todos (no phase filter for todos)\n if (!phaseFilter && mapping.todos) {\n for (const [todoId, todo] of Object.entries(mapping.todos)) {\n if (todo.number > 0) {\n const entry = {\n issue_number: todo.number,\n title: `Todo: ${todoId}`,\n status: todo.status,\n source: `todo ${todoId}`,\n };\n if (!statusFilter || entry.status === statusFilter) {\n items.push(entry);\n }\n }\n }\n }\n\n return items;\n}\n\n/**\n * Build local search results from the mapping file (for local-only mode).\n */\nfunction buildLocalSearchResults(\n mapping: IssueMappingFile,\n stateFilter?: string,\n): Array<{\n issue_number: number;\n title: string;\n state: string;\n source: string;\n}> {\n const items: Array<{\n issue_number: number;\n title: string;\n state: string;\n source: string;\n }> = [];\n\n for (const [phaseNum, phase] of Object.entries(mapping.phases)) {\n for (const [taskId, task] of Object.entries(phase.tasks)) {\n if (task.number > 0) {\n const state = task.status === 'Done' ? 'closed' : 'open';\n if (stateFilter && stateFilter !== 'all' && state !== stateFilter) continue;\n items.push({\n issue_number: task.number,\n title: `[P${phaseNum}] Task ${taskId}`,\n state,\n source: `phase ${phaseNum}`,\n });\n }\n }\n }\n\n if (mapping.todos) {\n for (const [todoId, todo] of Object.entries(mapping.todos)) {\n if (todo.number > 0) {\n const state = todo.status === 'Done' ? 'closed' : 'open';\n if (stateFilter && stateFilter !== 'all' && state !== stateFilter) continue;\n items.push({\n issue_number: todo.number,\n title: `Todo: ${todoId}`,\n state,\n source: 'todo',\n });\n }\n }\n }\n\n return items;\n}\n","/**\n * MCP Tool Registration — Orchestrates all tool registrations\n *\n * This is the single entry point for registering MCP tools on the server.\n */\n\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { registerPhaseTools } from './phase-tools.js';\nimport { registerTodoTools } from './todo-tools.js';\nimport { registerStateTools } from './state-tools.js';\nimport { registerContextTools } from './context-tools.js';\nimport { registerRoadmapTools } from './roadmap-tools.js';\nimport { registerConfigTools } from './config-tools.js';\nimport { registerGitHubTools } from './github-tools.js';\nimport { registerBoardTools } from './board-tools.js';\n\n/**\n * Register all MCP tools on the given server instance.\n */\nexport function registerAllTools(server: McpServer): void {\n registerPhaseTools(server);\n registerTodoTools(server);\n registerStateTools(server);\n registerContextTools(server);\n registerRoadmapTools(server);\n registerConfigTools(server);\n registerGitHubTools(server);\n registerBoardTools(server);\n}\n","\"use strict\";\n/**\n * Copyright (c) 2017, Daniel Imms (MIT License).\n * Copyright (c) 2018, Microsoft Corporation (MIT License).\n */\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.loadNativeModule = exports.assign = void 0;\nfunction assign(target) {\n var sources = [];\n for (var _i = 1; _i < arguments.length; _i++) {\n sources[_i - 1] = arguments[_i];\n }\n sources.forEach(function (source) { return Object.keys(source).forEach(function (key) { return target[key] = source[key]; }); });\n return target;\n}\nexports.assign = assign;\nfunction loadNativeModule(name) {\n // Check build, debug, and then prebuilds.\n var dirs = ['build/Release', 'build/Debug', \"prebuilds/\" + process.platform + \"-\" + process.arch];\n // Check relative to the parent dir for unbundled and then the current dir for bundled\n var relative = ['..', '.'];\n var lastError;\n for (var _i = 0, dirs_1 = dirs; _i < dirs_1.length; _i++) {\n var d = dirs_1[_i];\n for (var _a = 0, relative_1 = relative; _a < relative_1.length; _a++) {\n var r = relative_1[_a];\n var dir = r + \"/\" + d + \"/\";\n try {\n return { dir: dir, module: require(dir + \"/\" + name + \".node\") };\n }\n catch (e) {\n lastError = e;\n }\n }\n }\n throw new Error(\"Failed to load native module: \" + name + \".node, checked: \" + dirs.join(', ') + \": \" + lastError);\n}\nexports.loadNativeModule = loadNativeModule;\n//# sourceMappingURL=utils.js.map","\"use strict\";\n/**\n * Copyright (c) 2019, Microsoft Corporation (MIT License).\n */\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.EventEmitter2 = void 0;\nvar EventEmitter2 = /** @class */ (function () {\n function EventEmitter2() {\n this._listeners = [];\n }\n Object.defineProperty(EventEmitter2.prototype, \"event\", {\n get: function () {\n var _this = this;\n if (!this._event) {\n this._event = function (listener) {\n _this._listeners.push(listener);\n var disposable = {\n dispose: function () {\n for (var i = 0; i < _this._listeners.length; i++) {\n if (_this._listeners[i] === listener) {\n _this._listeners.splice(i, 1);\n return;\n }\n }\n }\n };\n return disposable;\n };\n }\n return this._event;\n },\n enumerable: false,\n configurable: true\n });\n EventEmitter2.prototype.fire = function (data) {\n var queue = [];\n for (var i = 0; i < this._listeners.length; i++) {\n queue.push(this._listeners[i]);\n }\n for (var i = 0; i < queue.length; i++) {\n queue[i].call(undefined, data);\n }\n };\n return EventEmitter2;\n}());\nexports.EventEmitter2 = EventEmitter2;\n//# sourceMappingURL=eventEmitter2.js.map","\"use strict\";\n/**\n * Copyright (c) 2012-2015, Christopher Jeffrey (MIT License)\n * Copyright (c) 2016, Daniel Imms (MIT License).\n * Copyright (c) 2018, Microsoft Corporation (MIT License).\n */\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.Terminal = exports.DEFAULT_ROWS = exports.DEFAULT_COLS = void 0;\nvar events_1 = require(\"events\");\nvar eventEmitter2_1 = require(\"./eventEmitter2\");\nexports.DEFAULT_COLS = 80;\nexports.DEFAULT_ROWS = 24;\n/**\n * Default messages to indicate PAUSE/RESUME for automatic flow control.\n * To avoid conflicts with rebound XON/XOFF control codes (such as on-my-zsh),\n * the sequences can be customized in `IPtyForkOptions`.\n */\nvar FLOW_CONTROL_PAUSE = '\\x13'; // defaults to XOFF\nvar FLOW_CONTROL_RESUME = '\\x11'; // defaults to XON\nvar Terminal = /** @class */ (function () {\n function Terminal(opt) {\n this._pid = 0;\n this._fd = 0;\n this._cols = 0;\n this._rows = 0;\n this._readable = false;\n this._writable = false;\n this._onData = new eventEmitter2_1.EventEmitter2();\n this._onExit = new eventEmitter2_1.EventEmitter2();\n // for 'close'\n this._internalee = new events_1.EventEmitter();\n // setup flow control handling\n this.handleFlowControl = !!(opt === null || opt === void 0 ? void 0 : opt.handleFlowControl);\n this._flowControlPause = (opt === null || opt === void 0 ? void 0 : opt.flowControlPause) || FLOW_CONTROL_PAUSE;\n this._flowControlResume = (opt === null || opt === void 0 ? void 0 : opt.flowControlResume) || FLOW_CONTROL_RESUME;\n if (!opt) {\n return;\n }\n // Do basic type checks here in case node-pty is being used within JavaScript. If the wrong\n // types go through to the C++ side it can lead to hard to diagnose exceptions.\n this._checkType('name', opt.name ? opt.name : undefined, 'string');\n this._checkType('cols', opt.cols ? opt.cols : undefined, 'number');\n this._checkType('rows', opt.rows ? opt.rows : undefined, 'number');\n this._checkType('cwd', opt.cwd ? opt.cwd : undefined, 'string');\n this._checkType('env', opt.env ? opt.env : undefined, 'object');\n this._checkType('uid', opt.uid ? opt.uid : undefined, 'number');\n this._checkType('gid', opt.gid ? opt.gid : undefined, 'number');\n this._checkType('encoding', opt.encoding ? opt.encoding : undefined, 'string');\n }\n Object.defineProperty(Terminal.prototype, \"onData\", {\n get: function () { return this._onData.event; },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Terminal.prototype, \"onExit\", {\n get: function () { return this._onExit.event; },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Terminal.prototype, \"pid\", {\n get: function () { return this._pid; },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Terminal.prototype, \"cols\", {\n get: function () { return this._cols; },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Terminal.prototype, \"rows\", {\n get: function () { return this._rows; },\n enumerable: false,\n configurable: true\n });\n Terminal.prototype.write = function (data) {\n if (this.handleFlowControl) {\n // PAUSE/RESUME messages are not forwarded to the pty\n if (data === this._flowControlPause) {\n this.pause();\n return;\n }\n if (data === this._flowControlResume) {\n this.resume();\n return;\n }\n }\n // everything else goes to the real pty\n this._write(data);\n };\n Terminal.prototype._forwardEvents = function () {\n var _this = this;\n this.on('data', function (e) { return _this._onData.fire(e); });\n this.on('exit', function (exitCode, signal) { return _this._onExit.fire({ exitCode: exitCode, signal: signal }); });\n };\n Terminal.prototype._checkType = function (name, value, type, allowArray) {\n if (allowArray === void 0) { allowArray = false; }\n if (value === undefined) {\n return;\n }\n if (allowArray) {\n if (Array.isArray(value)) {\n value.forEach(function (v, i) {\n if (typeof v !== type) {\n throw new Error(name + \"[\" + i + \"] must be a \" + type + \" (not a \" + typeof v[i] + \")\");\n }\n });\n return;\n }\n }\n if (typeof value !== type) {\n throw new Error(name + \" must be a \" + type + \" (not a \" + typeof value + \")\");\n }\n };\n /** See net.Socket.end */\n Terminal.prototype.end = function (data) {\n this._socket.end(data);\n };\n /** See stream.Readable.pipe */\n Terminal.prototype.pipe = function (dest, options) {\n return this._socket.pipe(dest, options);\n };\n /** See net.Socket.pause */\n Terminal.prototype.pause = function () {\n return this._socket.pause();\n };\n /** See net.Socket.resume */\n Terminal.prototype.resume = function () {\n return this._socket.resume();\n };\n /** See net.Socket.setEncoding */\n Terminal.prototype.setEncoding = function (encoding) {\n if (this._socket._decoder) {\n delete this._socket._decoder;\n }\n if (encoding) {\n this._socket.setEncoding(encoding);\n }\n };\n Terminal.prototype.addListener = function (eventName, listener) { this.on(eventName, listener); };\n Terminal.prototype.on = function (eventName, listener) {\n if (eventName === 'close') {\n this._internalee.on('close', listener);\n return;\n }\n this._socket.on(eventName, listener);\n };\n Terminal.prototype.emit = function (eventName) {\n var args = [];\n for (var _i = 1; _i < arguments.length; _i++) {\n args[_i - 1] = arguments[_i];\n }\n if (eventName === 'close') {\n return this._internalee.emit.apply(this._internalee, arguments);\n }\n return this._socket.emit.apply(this._socket, arguments);\n };\n Terminal.prototype.listeners = function (eventName) {\n return this._socket.listeners(eventName);\n };\n Terminal.prototype.removeListener = function (eventName, listener) {\n this._socket.removeListener(eventName, listener);\n };\n Terminal.prototype.removeAllListeners = function (eventName) {\n this._socket.removeAllListeners(eventName);\n };\n Terminal.prototype.once = function (eventName, listener) {\n this._socket.once(eventName, listener);\n };\n Terminal.prototype._close = function () {\n this._socket.readable = false;\n this.write = function () { };\n this.end = function () { };\n this._writable = false;\n this._readable = false;\n };\n Terminal.prototype._parseEnv = function (env) {\n var keys = Object.keys(env || {});\n var pairs = [];\n for (var i = 0; i < keys.length; i++) {\n if (keys[i] === undefined) {\n continue;\n }\n pairs.push(keys[i] + '=' + env[keys[i]]);\n }\n return pairs;\n };\n return Terminal;\n}());\nexports.Terminal = Terminal;\n//# sourceMappingURL=terminal.js.map","\"use strict\";\n/**\n * Copyright (c) 2020, Microsoft Corporation (MIT License).\n */\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.getWorkerPipeName = void 0;\nfunction getWorkerPipeName(conoutPipeName) {\n return conoutPipeName + \"-worker\";\n}\nexports.getWorkerPipeName = getWorkerPipeName;\n//# sourceMappingURL=conout.js.map","\"use strict\";\n/**\n * Copyright (c) 2020, Microsoft Corporation (MIT License).\n */\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nvar __generator = (this && this.__generator) || function (thisArg, body) {\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\n return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\n function verb(n) { return function (v) { return step([n, v]); }; }\n function step(op) {\n if (f) throw new TypeError(\"Generator is already executing.\");\n while (_) try {\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\n if (y = 0, t) op = [op[0] & 2, t.value];\n switch (op[0]) {\n case 0: case 1: t = op; break;\n case 4: _.label++; return { value: op[1], done: false };\n case 5: _.label++; y = op[1]; op = [0]; continue;\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\n default:\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\n if (t[2]) _.ops.pop();\n _.trys.pop(); continue;\n }\n op = body.call(thisArg, _);\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\n }\n};\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.ConoutConnection = void 0;\nvar worker_threads_1 = require(\"worker_threads\");\nvar conout_1 = require(\"./shared/conout\");\nvar path_1 = require(\"path\");\nvar eventEmitter2_1 = require(\"./eventEmitter2\");\n/**\n * The amount of time to wait for additional data after the conpty shell process has exited before\n * shutting down the worker and sockets. The timer will be reset if a new data event comes in after\n * the timer has started.\n */\nvar FLUSH_DATA_INTERVAL = 1000;\n/**\n * Connects to and manages the lifecycle of the conout socket. This socket must be drained on\n * another thread in order to avoid deadlocks where Conpty waits for the out socket to drain\n * when `ClosePseudoConsole` is called. This happens when data is being written to the terminal when\n * the pty is closed.\n *\n * See also:\n * - https://github.com/microsoft/node-pty/issues/375\n * - https://github.com/microsoft/vscode/issues/76548\n * - https://github.com/microsoft/terminal/issues/1810\n * - https://docs.microsoft.com/en-us/windows/console/closepseudoconsole\n */\nvar ConoutConnection = /** @class */ (function () {\n function ConoutConnection(_conoutPipeName, _useConptyDll) {\n var _this = this;\n this._conoutPipeName = _conoutPipeName;\n this._useConptyDll = _useConptyDll;\n this._isDisposed = false;\n this._onReady = new eventEmitter2_1.EventEmitter2();\n var workerData = {\n conoutPipeName: _conoutPipeName\n };\n var scriptPath = __dirname.replace('node_modules.asar', 'node_modules.asar.unpacked');\n this._worker = new worker_threads_1.Worker(path_1.join(scriptPath, 'worker/conoutSocketWorker.js'), { workerData: workerData });\n this._worker.on('message', function (message) {\n switch (message) {\n case 1 /* READY */:\n _this._onReady.fire();\n return;\n default:\n console.warn('Unexpected ConoutWorkerMessage', message);\n }\n });\n }\n Object.defineProperty(ConoutConnection.prototype, \"onReady\", {\n get: function () { return this._onReady.event; },\n enumerable: false,\n configurable: true\n });\n ConoutConnection.prototype.dispose = function () {\n if (!this._useConptyDll && this._isDisposed) {\n return;\n }\n this._isDisposed = true;\n // Drain all data from the socket before closing\n this._drainDataAndClose();\n };\n ConoutConnection.prototype.connectSocket = function (socket) {\n socket.connect(conout_1.getWorkerPipeName(this._conoutPipeName));\n };\n ConoutConnection.prototype._drainDataAndClose = function () {\n var _this = this;\n if (this._drainTimeout) {\n clearTimeout(this._drainTimeout);\n }\n this._drainTimeout = setTimeout(function () { return _this._destroySocket(); }, FLUSH_DATA_INTERVAL);\n };\n ConoutConnection.prototype._destroySocket = function () {\n return __awaiter(this, void 0, void 0, function () {\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0: return [4 /*yield*/, this._worker.terminate()];\n case 1:\n _a.sent();\n return [2 /*return*/];\n }\n });\n });\n };\n return ConoutConnection;\n}());\nexports.ConoutConnection = ConoutConnection;\n//# sourceMappingURL=windowsConoutConnection.js.map","\"use strict\";\n/**\n * Copyright (c) 2012-2015, Christopher Jeffrey, Peter Sunde (MIT License)\n * Copyright (c) 2016, Daniel Imms (MIT License).\n * Copyright (c) 2018, Microsoft Corporation (MIT License).\n */\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.argsToCommandLine = exports.WindowsPtyAgent = void 0;\nvar fs = require(\"fs\");\nvar os = require(\"os\");\nvar path = require(\"path\");\nvar child_process_1 = require(\"child_process\");\nvar net_1 = require(\"net\");\nvar windowsConoutConnection_1 = require(\"./windowsConoutConnection\");\nvar utils_1 = require(\"./utils\");\nvar conptyNative;\nvar winptyNative;\n/**\n * The amount of time to wait for additional data after the conpty shell process has exited before\n * shutting down the socket. The timer will be reset if a new data event comes in after the timer\n * has started.\n */\nvar FLUSH_DATA_INTERVAL = 1000;\n/**\n * This agent sits between the WindowsTerminal class and provides a common interface for both conpty\n * and winpty.\n */\nvar WindowsPtyAgent = /** @class */ (function () {\n function WindowsPtyAgent(file, args, env, cwd, cols, rows, debug, _useConpty, _useConptyDll, conptyInheritCursor) {\n var _this = this;\n if (_useConptyDll === void 0) { _useConptyDll = false; }\n if (conptyInheritCursor === void 0) { conptyInheritCursor = false; }\n this._useConpty = _useConpty;\n this._useConptyDll = _useConptyDll;\n this._pid = 0;\n this._innerPid = 0;\n if (this._useConpty === undefined || this._useConpty === true) {\n this._useConpty = this._getWindowsBuildNumber() >= 18309;\n }\n if (this._useConpty) {\n if (!conptyNative) {\n conptyNative = utils_1.loadNativeModule('conpty').module;\n }\n }\n else {\n if (!winptyNative) {\n winptyNative = utils_1.loadNativeModule('pty').module;\n }\n }\n this._ptyNative = this._useConpty ? conptyNative : winptyNative;\n // Sanitize input variable.\n cwd = path.resolve(cwd);\n // Compose command line\n var commandLine = argsToCommandLine(file, args);\n // Open pty session.\n var term;\n if (this._useConpty) {\n term = this._ptyNative.startProcess(file, cols, rows, debug, this._generatePipeName(), conptyInheritCursor, this._useConptyDll);\n }\n else {\n term = this._ptyNative.startProcess(file, commandLine, env, cwd, cols, rows, debug);\n this._pid = term.pid;\n this._innerPid = term.innerPid;\n }\n // Not available on windows.\n this._fd = term.fd;\n // Generated incremental number that has no real purpose besides using it\n // as a terminal id.\n this._pty = term.pty;\n // Create terminal pipe IPC channel and forward to a local unix socket.\n this._outSocket = new net_1.Socket();\n this._outSocket.setEncoding('utf8');\n // The conout socket must be ready out on another thread to avoid deadlocks\n this._conoutSocketWorker = new windowsConoutConnection_1.ConoutConnection(term.conout, this._useConptyDll);\n this._conoutSocketWorker.onReady(function () {\n _this._conoutSocketWorker.connectSocket(_this._outSocket);\n });\n this._outSocket.on('connect', function () {\n _this._outSocket.emit('ready_datapipe');\n });\n var inSocketFD = fs.openSync(term.conin, 'w');\n this._inSocket = new net_1.Socket({\n fd: inSocketFD,\n readable: false,\n writable: true\n });\n this._inSocket.setEncoding('utf8');\n if (this._useConpty) {\n var connect = this._ptyNative.connect(this._pty, commandLine, cwd, env, this._useConptyDll, function (c) { return _this._$onProcessExit(c); });\n this._innerPid = connect.pid;\n }\n }\n Object.defineProperty(WindowsPtyAgent.prototype, \"inSocket\", {\n get: function () { return this._inSocket; },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(WindowsPtyAgent.prototype, \"outSocket\", {\n get: function () { return this._outSocket; },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(WindowsPtyAgent.prototype, \"fd\", {\n get: function () { return this._fd; },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(WindowsPtyAgent.prototype, \"innerPid\", {\n get: function () { return this._innerPid; },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(WindowsPtyAgent.prototype, \"pty\", {\n get: function () { return this._pty; },\n enumerable: false,\n configurable: true\n });\n WindowsPtyAgent.prototype.resize = function (cols, rows) {\n if (this._useConpty) {\n if (this._exitCode !== undefined) {\n throw new Error('Cannot resize a pty that has already exited');\n }\n this._ptyNative.resize(this._pty, cols, rows, this._useConptyDll);\n return;\n }\n this._ptyNative.resize(this._pid, cols, rows);\n };\n WindowsPtyAgent.prototype.clear = function () {\n if (this._useConpty) {\n this._ptyNative.clear(this._pty, this._useConptyDll);\n }\n };\n WindowsPtyAgent.prototype.kill = function () {\n var _this = this;\n // Tell the agent to kill the pty, this releases handles to the process\n if (this._useConpty) {\n if (!this._useConptyDll) {\n this._inSocket.readable = false;\n this._outSocket.readable = false;\n this._getConsoleProcessList().then(function (consoleProcessList) {\n consoleProcessList.forEach(function (pid) {\n try {\n process.kill(pid);\n }\n catch (e) {\n // Ignore if process cannot be found (kill ESRCH error)\n }\n });\n });\n this._ptyNative.kill(this._pty, this._useConptyDll);\n this._conoutSocketWorker.dispose();\n }\n else {\n // Close the input write handle to signal the end of session.\n this._inSocket.destroy();\n this._ptyNative.kill(this._pty, this._useConptyDll);\n this._outSocket.on('data', function () {\n _this._conoutSocketWorker.dispose();\n });\n }\n }\n else {\n // Because pty.kill closes the handle, it will kill most processes by itself.\n // Process IDs can be reused as soon as all handles to them are\n // dropped, so we want to immediately kill the entire console process list.\n // If we do not force kill all processes here, node servers in particular\n // seem to become detached and remain running (see\n // Microsoft/vscode#26807).\n var processList = this._ptyNative.getProcessList(this._pid);\n this._ptyNative.kill(this._pid, this._innerPid);\n processList.forEach(function (pid) {\n try {\n process.kill(pid);\n }\n catch (e) {\n // Ignore if process cannot be found (kill ESRCH error)\n }\n });\n }\n };\n WindowsPtyAgent.prototype._getConsoleProcessList = function () {\n var _this = this;\n return new Promise(function (resolve) {\n var agent = child_process_1.fork(path.join(__dirname, 'conpty_console_list_agent'), [_this._innerPid.toString()]);\n agent.on('message', function (message) {\n clearTimeout(timeout);\n resolve(message.consoleProcessList);\n });\n var timeout = setTimeout(function () {\n // Something went wrong, just send back the shell PID\n agent.kill();\n resolve([_this._innerPid]);\n }, 5000);\n });\n };\n Object.defineProperty(WindowsPtyAgent.prototype, \"exitCode\", {\n get: function () {\n if (this._useConpty) {\n return this._exitCode;\n }\n var winptyExitCode = this._ptyNative.getExitCode(this._innerPid);\n return winptyExitCode === -1 ? undefined : winptyExitCode;\n },\n enumerable: false,\n configurable: true\n });\n WindowsPtyAgent.prototype._getWindowsBuildNumber = function () {\n var osVersion = (/(\\d+)\\.(\\d+)\\.(\\d+)/g).exec(os.release());\n var buildNumber = 0;\n if (osVersion && osVersion.length === 4) {\n buildNumber = parseInt(osVersion[3]);\n }\n return buildNumber;\n };\n WindowsPtyAgent.prototype._generatePipeName = function () {\n return \"conpty-\" + Math.random() * 10000000;\n };\n /**\n * Triggered from the native side when a contpy process exits.\n */\n WindowsPtyAgent.prototype._$onProcessExit = function (exitCode) {\n var _this = this;\n this._exitCode = exitCode;\n if (!this._useConptyDll) {\n this._flushDataAndCleanUp();\n this._outSocket.on('data', function () { return _this._flushDataAndCleanUp(); });\n }\n };\n WindowsPtyAgent.prototype._flushDataAndCleanUp = function () {\n var _this = this;\n if (this._useConptyDll) {\n return;\n }\n if (this._closeTimeout) {\n clearTimeout(this._closeTimeout);\n }\n this._closeTimeout = setTimeout(function () { return _this._cleanUpProcess(); }, FLUSH_DATA_INTERVAL);\n };\n WindowsPtyAgent.prototype._cleanUpProcess = function () {\n if (this._useConptyDll) {\n return;\n }\n this._inSocket.readable = false;\n this._outSocket.readable = false;\n this._outSocket.destroy();\n };\n return WindowsPtyAgent;\n}());\nexports.WindowsPtyAgent = WindowsPtyAgent;\n// Convert argc/argv into a Win32 command-line following the escaping convention\n// documented on MSDN (e.g. see CommandLineToArgvW documentation). Copied from\n// winpty project.\nfunction argsToCommandLine(file, args) {\n if (isCommandLine(args)) {\n if (args.length === 0) {\n return file;\n }\n return argsToCommandLine(file, []) + \" \" + args;\n }\n var argv = [file];\n Array.prototype.push.apply(argv, args);\n var result = '';\n for (var argIndex = 0; argIndex < argv.length; argIndex++) {\n if (argIndex > 0) {\n result += ' ';\n }\n var arg = argv[argIndex];\n // if it is empty or it contains whitespace and is not already quoted\n var hasLopsidedEnclosingQuote = xOr((arg[0] !== '\"'), (arg[arg.length - 1] !== '\"'));\n var hasNoEnclosingQuotes = ((arg[0] !== '\"') && (arg[arg.length - 1] !== '\"'));\n var quote = arg === '' ||\n (arg.indexOf(' ') !== -1 ||\n arg.indexOf('\\t') !== -1) &&\n ((arg.length > 1) &&\n (hasLopsidedEnclosingQuote || hasNoEnclosingQuotes));\n if (quote) {\n result += '\\\"';\n }\n var bsCount = 0;\n for (var i = 0; i < arg.length; i++) {\n var p = arg[i];\n if (p === '\\\\') {\n bsCount++;\n }\n else if (p === '\"') {\n result += repeatText('\\\\', bsCount * 2 + 1);\n result += '\"';\n bsCount = 0;\n }\n else {\n result += repeatText('\\\\', bsCount);\n bsCount = 0;\n result += p;\n }\n }\n if (quote) {\n result += repeatText('\\\\', bsCount * 2);\n result += '\\\"';\n }\n else {\n result += repeatText('\\\\', bsCount);\n }\n }\n return result;\n}\nexports.argsToCommandLine = argsToCommandLine;\nfunction isCommandLine(args) {\n return typeof args === 'string';\n}\nfunction repeatText(text, count) {\n var result = '';\n for (var i = 0; i < count; i++) {\n result += text;\n }\n return result;\n}\nfunction xOr(arg1, arg2) {\n return ((arg1 && !arg2) || (!arg1 && arg2));\n}\n//# sourceMappingURL=windowsPtyAgent.js.map","\"use strict\";\n/**\n * Copyright (c) 2012-2015, Christopher Jeffrey, Peter Sunde (MIT License)\n * Copyright (c) 2016, Daniel Imms (MIT License).\n * Copyright (c) 2018, Microsoft Corporation (MIT License).\n */\nvar __extends = (this && this.__extends) || (function () {\n var extendStatics = function (d, b) {\n extendStatics = Object.setPrototypeOf ||\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\n function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };\n return extendStatics(d, b);\n };\n return function (d, b) {\n extendStatics(d, b);\n function __() { this.constructor = d; }\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n };\n})();\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.WindowsTerminal = void 0;\nvar terminal_1 = require(\"./terminal\");\nvar windowsPtyAgent_1 = require(\"./windowsPtyAgent\");\nvar utils_1 = require(\"./utils\");\nvar DEFAULT_FILE = 'cmd.exe';\nvar DEFAULT_NAME = 'Windows Shell';\nvar WindowsTerminal = /** @class */ (function (_super) {\n __extends(WindowsTerminal, _super);\n function WindowsTerminal(file, args, opt) {\n var _this = _super.call(this, opt) || this;\n _this._checkType('args', args, 'string', true);\n // Initialize arguments\n args = args || [];\n file = file || DEFAULT_FILE;\n opt = opt || {};\n opt.env = opt.env || process.env;\n if (opt.encoding) {\n console.warn('Setting encoding on Windows is not supported');\n }\n var env = utils_1.assign({}, opt.env);\n _this._cols = opt.cols || terminal_1.DEFAULT_COLS;\n _this._rows = opt.rows || terminal_1.DEFAULT_ROWS;\n var cwd = opt.cwd || process.cwd();\n var name = opt.name || env.TERM || DEFAULT_NAME;\n var parsedEnv = _this._parseEnv(env);\n // If the terminal is ready\n _this._isReady = false;\n // Functions that need to run after `ready` event is emitted.\n _this._deferreds = [];\n // Create new termal.\n _this._agent = new windowsPtyAgent_1.WindowsPtyAgent(file, args, parsedEnv, cwd, _this._cols, _this._rows, false, opt.useConpty, opt.useConptyDll, opt.conptyInheritCursor);\n _this._socket = _this._agent.outSocket;\n // Not available until `ready` event emitted.\n _this._pid = _this._agent.innerPid;\n _this._fd = _this._agent.fd;\n _this._pty = _this._agent.pty;\n // The forked windows terminal is not available until `ready` event is\n // emitted.\n _this._socket.on('ready_datapipe', function () {\n // Run deferreds and set ready state once the first data event is received.\n _this._socket.once('data', function () {\n // Wait until the first data event is fired then we can run deferreds.\n if (!_this._isReady) {\n // Terminal is now ready and we can avoid having to defer method\n // calls.\n _this._isReady = true;\n // Execute all deferred methods\n _this._deferreds.forEach(function (fn) {\n // NB! In order to ensure that `this` has all its references\n // updated any variable that need to be available in `this` before\n // the deferred is run has to be declared above this forEach\n // statement.\n fn.run();\n });\n // Reset\n _this._deferreds = [];\n }\n });\n // Shutdown if `error` event is emitted.\n _this._socket.on('error', function (err) {\n // Close terminal session.\n _this._close();\n // EIO, happens when someone closes our child process: the only process\n // in the terminal.\n // node < 0.6.14: errno 5\n // node >= 0.6.14: read EIO\n if (err.code) {\n if (~err.code.indexOf('errno 5') || ~err.code.indexOf('EIO'))\n return;\n }\n // Throw anything else.\n if (_this.listeners('error').length < 2) {\n throw err;\n }\n });\n // Cleanup after the socket is closed.\n _this._socket.on('close', function () {\n _this.emit('exit', _this._agent.exitCode);\n _this._close();\n });\n });\n _this._file = file;\n _this._name = name;\n _this._readable = true;\n _this._writable = true;\n _this._forwardEvents();\n return _this;\n }\n WindowsTerminal.prototype._write = function (data) {\n this._defer(this._doWrite, data);\n };\n WindowsTerminal.prototype._doWrite = function (data) {\n this._agent.inSocket.write(data);\n };\n /**\n * openpty\n */\n WindowsTerminal.open = function (options) {\n throw new Error('open() not supported on windows, use Fork() instead.');\n };\n /**\n * TTY\n */\n WindowsTerminal.prototype.resize = function (cols, rows) {\n var _this = this;\n if (cols <= 0 || rows <= 0 || isNaN(cols) || isNaN(rows) || cols === Infinity || rows === Infinity) {\n throw new Error('resizing must be done using positive cols and rows');\n }\n this._deferNoArgs(function () {\n _this._agent.resize(cols, rows);\n _this._cols = cols;\n _this._rows = rows;\n });\n };\n WindowsTerminal.prototype.clear = function () {\n var _this = this;\n this._deferNoArgs(function () {\n _this._agent.clear();\n });\n };\n WindowsTerminal.prototype.destroy = function () {\n var _this = this;\n this._deferNoArgs(function () {\n _this.kill();\n });\n };\n WindowsTerminal.prototype.kill = function (signal) {\n var _this = this;\n this._deferNoArgs(function () {\n if (signal) {\n throw new Error('Signals not supported on windows.');\n }\n _this._close();\n _this._agent.kill();\n });\n };\n WindowsTerminal.prototype._deferNoArgs = function (deferredFn) {\n var _this = this;\n // If the terminal is ready, execute.\n if (this._isReady) {\n deferredFn.call(this);\n return;\n }\n // Queue until terminal is ready.\n this._deferreds.push({\n run: function () { return deferredFn.call(_this); }\n });\n };\n WindowsTerminal.prototype._defer = function (deferredFn, arg) {\n var _this = this;\n // If the terminal is ready, execute.\n if (this._isReady) {\n deferredFn.call(this, arg);\n return;\n }\n // Queue until terminal is ready.\n this._deferreds.push({\n run: function () { return deferredFn.call(_this, arg); }\n });\n };\n Object.defineProperty(WindowsTerminal.prototype, \"process\", {\n get: function () { return this._name; },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(WindowsTerminal.prototype, \"master\", {\n get: function () { throw new Error('master is not supported on Windows'); },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(WindowsTerminal.prototype, \"slave\", {\n get: function () { throw new Error('slave is not supported on Windows'); },\n enumerable: false,\n configurable: true\n });\n return WindowsTerminal;\n}(terminal_1.Terminal));\nexports.WindowsTerminal = WindowsTerminal;\n//# sourceMappingURL=windowsTerminal.js.map","\"use strict\";\nvar __extends = (this && this.__extends) || (function () {\n var extendStatics = function (d, b) {\n extendStatics = Object.setPrototypeOf ||\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\n function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };\n return extendStatics(d, b);\n };\n return function (d, b) {\n extendStatics(d, b);\n function __() { this.constructor = d; }\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n };\n})();\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.UnixTerminal = void 0;\n/**\n * Copyright (c) 2012-2015, Christopher Jeffrey (MIT License)\n * Copyright (c) 2016, Daniel Imms (MIT License).\n * Copyright (c) 2018, Microsoft Corporation (MIT License).\n */\nvar fs = require(\"fs\");\nvar path = require(\"path\");\nvar tty = require(\"tty\");\nvar terminal_1 = require(\"./terminal\");\nvar utils_1 = require(\"./utils\");\nvar native = utils_1.loadNativeModule('pty');\nvar pty = native.module;\nvar helperPath = native.dir + '/spawn-helper';\nhelperPath = path.resolve(__dirname, helperPath);\nhelperPath = helperPath.replace('app.asar', 'app.asar.unpacked');\nhelperPath = helperPath.replace('node_modules.asar', 'node_modules.asar.unpacked');\nvar DEFAULT_FILE = 'sh';\nvar DEFAULT_NAME = 'xterm';\nvar DESTROY_SOCKET_TIMEOUT_MS = 200;\nvar UnixTerminal = /** @class */ (function (_super) {\n __extends(UnixTerminal, _super);\n function UnixTerminal(file, args, opt) {\n var _a, _b;\n var _this = _super.call(this, opt) || this;\n _this._boundClose = false;\n _this._emittedClose = false;\n if (typeof args === 'string') {\n throw new Error('args as a string is not supported on unix.');\n }\n // Initialize arguments\n args = args || [];\n file = file || DEFAULT_FILE;\n opt = opt || {};\n opt.env = opt.env || process.env;\n _this._cols = opt.cols || terminal_1.DEFAULT_COLS;\n _this._rows = opt.rows || terminal_1.DEFAULT_ROWS;\n var uid = (_a = opt.uid) !== null && _a !== void 0 ? _a : -1;\n var gid = (_b = opt.gid) !== null && _b !== void 0 ? _b : -1;\n var env = utils_1.assign({}, opt.env);\n if (opt.env === process.env) {\n _this._sanitizeEnv(env);\n }\n var cwd = opt.cwd || process.cwd();\n env.PWD = cwd;\n var name = opt.name || env.TERM || DEFAULT_NAME;\n env.TERM = name;\n var parsedEnv = _this._parseEnv(env);\n var encoding = (opt.encoding === undefined ? 'utf8' : opt.encoding);\n var onexit = function (code, signal) {\n // XXX Sometimes a data event is emitted after exit. Wait til socket is\n // destroyed.\n if (!_this._emittedClose) {\n if (_this._boundClose) {\n return;\n }\n _this._boundClose = true;\n // From macOS High Sierra 10.13.2 sometimes the socket never gets\n // closed. A timeout is applied here to avoid the terminal never being\n // destroyed when this occurs.\n var timeout_1 = setTimeout(function () {\n timeout_1 = null;\n // Destroying the socket now will cause the close event to fire\n _this._socket.destroy();\n }, DESTROY_SOCKET_TIMEOUT_MS);\n _this.once('close', function () {\n if (timeout_1 !== null) {\n clearTimeout(timeout_1);\n }\n _this.emit('exit', code, signal);\n });\n return;\n }\n _this.emit('exit', code, signal);\n };\n // fork\n var term = pty.fork(file, args, parsedEnv, cwd, _this._cols, _this._rows, uid, gid, (encoding === 'utf8'), helperPath, onexit);\n _this._socket = new tty.ReadStream(term.fd);\n if (encoding !== null) {\n _this._socket.setEncoding(encoding);\n }\n _this._writeStream = new CustomWriteStream(term.fd, (encoding || undefined));\n // setup\n _this._socket.on('error', function (err) {\n // NOTE: fs.ReadStream gets EAGAIN twice at first:\n if (err.code) {\n if (~err.code.indexOf('EAGAIN')) {\n return;\n }\n }\n // close\n _this._close();\n // EIO on exit from fs.ReadStream:\n if (!_this._emittedClose) {\n _this._emittedClose = true;\n _this.emit('close');\n }\n // EIO, happens when someone closes our child process: the only process in\n // the terminal.\n // node < 0.6.14: errno 5\n // node >= 0.6.14: read EIO\n if (err.code) {\n if (~err.code.indexOf('errno 5') || ~err.code.indexOf('EIO')) {\n return;\n }\n }\n // throw anything else\n if (_this.listeners('error').length < 2) {\n throw err;\n }\n });\n _this._pid = term.pid;\n _this._fd = term.fd;\n _this._pty = term.pty;\n _this._file = file;\n _this._name = name;\n _this._readable = true;\n _this._writable = true;\n _this._socket.on('close', function () {\n if (_this._emittedClose) {\n return;\n }\n _this._emittedClose = true;\n _this._close();\n _this.emit('close');\n });\n _this._forwardEvents();\n return _this;\n }\n Object.defineProperty(UnixTerminal.prototype, \"master\", {\n get: function () { return this._master; },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(UnixTerminal.prototype, \"slave\", {\n get: function () { return this._slave; },\n enumerable: false,\n configurable: true\n });\n UnixTerminal.prototype._write = function (data) {\n this._writeStream.write(data);\n };\n Object.defineProperty(UnixTerminal.prototype, \"fd\", {\n /* Accessors */\n get: function () { return this._fd; },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(UnixTerminal.prototype, \"ptsName\", {\n get: function () { return this._pty; },\n enumerable: false,\n configurable: true\n });\n /**\n * openpty\n */\n UnixTerminal.open = function (opt) {\n var self = Object.create(UnixTerminal.prototype);\n opt = opt || {};\n if (arguments.length > 1) {\n opt = {\n cols: arguments[1],\n rows: arguments[2]\n };\n }\n var cols = opt.cols || terminal_1.DEFAULT_COLS;\n var rows = opt.rows || terminal_1.DEFAULT_ROWS;\n var encoding = (opt.encoding === undefined ? 'utf8' : opt.encoding);\n // open\n var term = pty.open(cols, rows);\n self._master = new tty.ReadStream(term.master);\n if (encoding !== null) {\n self._master.setEncoding(encoding);\n }\n self._master.resume();\n self._slave = new tty.ReadStream(term.slave);\n if (encoding !== null) {\n self._slave.setEncoding(encoding);\n }\n self._slave.resume();\n self._socket = self._master;\n self._pid = -1;\n self._fd = term.master;\n self._pty = term.pty;\n self._file = process.argv[0] || 'node';\n self._name = process.env.TERM || '';\n self._readable = true;\n self._writable = true;\n self._socket.on('error', function (err) {\n self._close();\n if (self.listeners('error').length < 2) {\n throw err;\n }\n });\n self._socket.on('close', function () {\n self._close();\n });\n return self;\n };\n UnixTerminal.prototype.destroy = function () {\n var _this = this;\n this._close();\n // Need to close the read stream so node stops reading a dead file\n // descriptor. Then we can safely SIGHUP the shell.\n this._socket.once('close', function () {\n _this.kill('SIGHUP');\n });\n this._socket.destroy();\n this._writeStream.dispose();\n };\n UnixTerminal.prototype.kill = function (signal) {\n try {\n process.kill(this.pid, signal || 'SIGHUP');\n }\n catch (e) { /* swallow */ }\n };\n Object.defineProperty(UnixTerminal.prototype, \"process\", {\n /**\n * Gets the name of the process.\n */\n get: function () {\n if (process.platform === 'darwin') {\n var title = pty.process(this._fd);\n return (title !== 'kernel_task') ? title : this._file;\n }\n return pty.process(this._fd, this._pty) || this._file;\n },\n enumerable: false,\n configurable: true\n });\n /**\n * TTY\n */\n UnixTerminal.prototype.resize = function (cols, rows) {\n if (cols <= 0 || rows <= 0 || isNaN(cols) || isNaN(rows) || cols === Infinity || rows === Infinity) {\n throw new Error('resizing must be done using positive cols and rows');\n }\n pty.resize(this._fd, cols, rows);\n this._cols = cols;\n this._rows = rows;\n };\n UnixTerminal.prototype.clear = function () {\n };\n UnixTerminal.prototype._sanitizeEnv = function (env) {\n // Make sure we didn't start our server from inside tmux.\n delete env['TMUX'];\n delete env['TMUX_PANE'];\n // Make sure we didn't start our server from inside screen.\n // http://web.mit.edu/gnu/doc/html/screen_20.html\n delete env['STY'];\n delete env['WINDOW'];\n // Delete some variables that might confuse our terminal.\n delete env['WINDOWID'];\n delete env['TERMCAP'];\n delete env['COLUMNS'];\n delete env['LINES'];\n };\n return UnixTerminal;\n}(terminal_1.Terminal));\nexports.UnixTerminal = UnixTerminal;\n/**\n * A custom write stream that writes directly to a file descriptor with proper\n * handling of backpressure and errors. This avoids some event loop exhaustion\n * issues that can occur when using the standard APIs in Node.\n */\nvar CustomWriteStream = /** @class */ (function () {\n function CustomWriteStream(_fd, _encoding) {\n this._fd = _fd;\n this._encoding = _encoding;\n this._writeQueue = [];\n }\n CustomWriteStream.prototype.dispose = function () {\n clearImmediate(this._writeImmediate);\n this._writeImmediate = undefined;\n };\n CustomWriteStream.prototype.write = function (data) {\n // Writes are put in a queue and processed asynchronously in order to handle\n // backpressure from the kernel buffer.\n var buffer = typeof data === 'string'\n ? Buffer.from(data, this._encoding)\n : Buffer.from(data);\n if (buffer.byteLength !== 0) {\n this._writeQueue.push({ buffer: buffer, offset: 0 });\n if (this._writeQueue.length === 1) {\n this._processWriteQueue();\n }\n }\n };\n CustomWriteStream.prototype._processWriteQueue = function () {\n var _this = this;\n this._writeImmediate = undefined;\n if (this._writeQueue.length === 0) {\n return;\n }\n var task = this._writeQueue[0];\n // Write to the underlying file descriptor and handle it directly, rather\n // than using the `net.Socket`/`tty.WriteStream` wrappers which swallow and\n // mask errors like EAGAIN and can cause the thread to block indefinitely.\n fs.write(this._fd, task.buffer, task.offset, function (err, written) {\n if (err) {\n if ('code' in err && err.code === 'EAGAIN') {\n // `setImmediate` is used to yield to the event loop and re-attempt\n // the write later.\n _this._writeImmediate = setImmediate(function () { return _this._processWriteQueue(); });\n }\n else {\n // Stop processing immediately on unexpected error and log\n _this._writeQueue.length = 0;\n console.error('Unhandled pty write error', err);\n }\n return;\n }\n task.offset += written;\n if (task.offset >= task.buffer.byteLength) {\n _this._writeQueue.shift();\n }\n // Since there is more room in the kernel buffer, we can continue to write\n // until we hit EAGAIN or exhaust the queue.\n //\n // Note that old versions of bash, like v3.2 which ships in macOS, appears\n // to have a bug in its readline implementation that causes data\n // corruption when writes to the pty happens too quickly. Instead of\n // trying to workaround that we just accept it so that large pastes are as\n // fast as possible.\n // Context: https://github.com/microsoft/node-pty/issues/833\n _this._processWriteQueue();\n });\n };\n return CustomWriteStream;\n}());\n//# sourceMappingURL=unixTerminal.js.map","\"use strict\";\n/**\n * Copyright (c) 2012-2015, Christopher Jeffrey, Peter Sunde (MIT License)\n * Copyright (c) 2016, Daniel Imms (MIT License).\n * Copyright (c) 2018, Microsoft Corporation (MIT License).\n */\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.native = exports.open = exports.createTerminal = exports.fork = exports.spawn = void 0;\nvar utils_1 = require(\"./utils\");\nvar terminalCtor;\nif (process.platform === 'win32') {\n terminalCtor = require('./windowsTerminal').WindowsTerminal;\n}\nelse {\n terminalCtor = require('./unixTerminal').UnixTerminal;\n}\n/**\n * Forks a process as a pseudoterminal.\n * @param file The file to launch.\n * @param args The file's arguments as argv (string[]) or in a pre-escaped\n * CommandLine format (string). Note that the CommandLine option is only\n * available on Windows and is expected to be escaped properly.\n * @param options The options of the terminal.\n * @throws When the file passed to spawn with does not exists.\n * @see CommandLineToArgvW https://msdn.microsoft.com/en-us/library/windows/desktop/bb776391(v=vs.85).aspx\n * @see Parsing C++ Comamnd-Line Arguments https://msdn.microsoft.com/en-us/library/17w5ykft.aspx\n * @see GetCommandLine https://msdn.microsoft.com/en-us/library/windows/desktop/ms683156.aspx\n */\nfunction spawn(file, args, opt) {\n return new terminalCtor(file, args, opt);\n}\nexports.spawn = spawn;\n/** @deprecated */\nfunction fork(file, args, opt) {\n return new terminalCtor(file, args, opt);\n}\nexports.fork = fork;\n/** @deprecated */\nfunction createTerminal(file, args, opt) {\n return new terminalCtor(file, args, opt);\n}\nexports.createTerminal = createTerminal;\nfunction open(options) {\n return terminalCtor.open(options);\n}\nexports.open = open;\n/**\n * Expose the native API when not Windows, note that this is not public API and\n * could be removed at any time.\n */\nexports.native = (process.platform !== 'win32' ? utils_1.loadNativeModule('pty').module : null);\n//# sourceMappingURL=index.js.map","/**\n * Backend Terminal — PTY management and scrollback session store\n *\n * Adapted from packages/dashboard/src/terminal/pty-manager.ts and session-store.ts.\n * Provides terminal support with graceful degradation when node-pty is unavailable.\n */\n\nimport type { WebSocket } from 'ws';\n\n// ─── Session Store ──────────────────────────────────────────────────────────\n\nconst MAX_SCROLLBACK = 50_000;\n\nexport class SessionStore {\n private scrollback: string[] = [];\n\n append(data: string): void {\n this.scrollback.push(data);\n if (this.scrollback.length > MAX_SCROLLBACK * 1.5) {\n this.scrollback = this.scrollback.slice(-MAX_SCROLLBACK);\n }\n }\n\n getAll(): string {\n return this.scrollback.join('');\n }\n\n clear(): void {\n this.scrollback = [];\n }\n}\n\n// ─── PTY Manager ────────────────────────────────────────────────────────────\n\ntype IPty = import('node-pty').IPty;\n\n// Lazy-load node-pty — it's a native C++ addon that may not be available\nlet pty: typeof import('node-pty') | null = null;\nlet ptyLoadError: string | null = null;\ntry {\n pty = require('node-pty');\n} catch (err) {\n ptyLoadError = err instanceof Error ? err.message : String(err);\n}\n\ninterface PtySession {\n process: IPty;\n pid: number;\n startTime: number;\n cwd: string;\n skipPermissions: boolean;\n disconnectTimer: ReturnType<typeof setTimeout> | null;\n store: SessionStore;\n}\n\ninterface PtyStatus {\n pid: number;\n uptime: number;\n cwd: string;\n memoryMB: number;\n isActive: boolean;\n skipPermissions: boolean;\n alive: boolean;\n}\n\nconst DISCONNECT_TIMEOUT_MS = 60_000;\nconst STATUS_INTERVAL_MS = 1_000;\nconst ACTIVE_THRESHOLD_MS = 2_000;\n\nfunction ptyLog(level: string, ...args: unknown[]): void {\n const ts = new Date().toISOString();\n const msg = args.map(a => typeof a === 'string' ? a : JSON.stringify(a)).join(' ');\n console.error(`[${ts}] [${level}] [pty-manager] ${msg}`);\n}\n\nexport class PtyManager {\n private static instance: PtyManager | null = null;\n private session: PtySession | null = null;\n private connectedClients = new Set<WebSocket>();\n private lastOutputTime = 0;\n private statusInterval: ReturnType<typeof setInterval> | null = null;\n\n static getInstance(): PtyManager {\n if (!PtyManager.instance) {\n PtyManager.instance = new PtyManager();\n }\n return PtyManager.instance;\n }\n\n spawn(opts: {\n skipPermissions: boolean;\n cwd: string;\n cols?: number;\n rows?: number;\n }): void {\n if (!pty) {\n ptyLog('ERROR', `node-pty not available: ${ptyLoadError}`);\n this.broadcastToClients({\n type: 'output',\n data: `\\r\\n\\x1b[31mTerminal unavailable: node-pty is not installed.\\r\\nError: ${ptyLoadError}\\r\\nRun: npm install node-pty\\x1b[0m\\r\\n`,\n });\n return;\n }\n\n if (this.session) {\n ptyLog('INFO', 'Killing existing session before spawn');\n this.kill();\n }\n\n const isWin = process.platform === 'win32';\n const shell = isWin ? 'cmd.exe' : '/bin/sh';\n const claudeCmd = `claude${opts.skipPermissions ? ' --dangerously-skip-permissions' : ''}`;\n const shellArgs = isWin ? ['/c', claudeCmd] : ['-c', claudeCmd];\n\n ptyLog('INFO', `Spawning: shell=${shell}, args=${JSON.stringify(shellArgs)}, cwd=${opts.cwd}`);\n\n const proc = pty.spawn(shell, shellArgs, {\n name: 'xterm-256color',\n cols: opts.cols ?? 120,\n rows: opts.rows ?? 30,\n cwd: opts.cwd,\n env: process.env as Record<string, string>,\n });\n\n ptyLog('INFO', `Process spawned with pid=${proc.pid}`);\n\n const store = new SessionStore();\n\n this.session = {\n process: proc,\n pid: proc.pid,\n startTime: Date.now(),\n cwd: opts.cwd,\n skipPermissions: opts.skipPermissions,\n disconnectTimer: null,\n store,\n };\n\n this.lastOutputTime = Date.now();\n\n proc.onData((data: string) => {\n this.lastOutputTime = Date.now();\n store.append(data);\n if (this.session?.pid === proc.pid) {\n this.broadcastToClients({ type: 'output', data });\n }\n });\n\n proc.onExit(({ exitCode }: { exitCode: number }) => {\n ptyLog('INFO', `Process exited with code=${exitCode}`);\n if (this.session?.pid !== proc.pid) {\n ptyLog('INFO', `Ignoring stale exit for old pid=${proc.pid}`);\n return;\n }\n this.broadcastToClients({ type: 'exit', code: exitCode });\n this.stopStatusBroadcast();\n this.session = null;\n });\n\n this.broadcastToClients({ type: 'started', pid: proc.pid });\n this.startStatusBroadcast();\n }\n\n write(data: string): void {\n if (this.session) {\n this.session.process.write(data);\n }\n }\n\n resize(cols: number, rows: number): void {\n if (this.session) {\n this.session.process.resize(cols, rows);\n }\n }\n\n kill(): void {\n if (this.session) {\n this.stopStatusBroadcast();\n try {\n this.session.process.kill();\n } catch {\n // process may already be dead\n }\n if (this.session.disconnectTimer) {\n clearTimeout(this.session.disconnectTimer);\n }\n this.session = null;\n }\n }\n\n getStatus(): PtyStatus | null {\n if (!this.session) return null;\n return {\n pid: this.session.pid,\n uptime: Math.floor((Date.now() - this.session.startTime) / 1000),\n cwd: this.session.cwd,\n memoryMB: Math.round((process.memoryUsage().rss / 1024 / 1024) * 10) / 10,\n isActive: Date.now() - this.lastOutputTime < ACTIVE_THRESHOLD_MS,\n skipPermissions: this.session.skipPermissions,\n alive: true,\n };\n }\n\n addClient(ws: WebSocket): void {\n this.connectedClients.add(ws);\n\n if (this.session?.disconnectTimer) {\n clearTimeout(this.session.disconnectTimer);\n this.session.disconnectTimer = null;\n }\n\n if (this.session) {\n const scrollback = this.session.store.getAll();\n if (scrollback) {\n ws.send(JSON.stringify({ type: 'scrollback', data: scrollback }));\n }\n const status = this.getStatus();\n if (status) {\n ws.send(JSON.stringify({ type: 'status', ...status }));\n }\n }\n }\n\n removeClient(ws: WebSocket): void {\n this.connectedClients.delete(ws);\n\n if (this.connectedClients.size === 0 && this.session) {\n this.session.disconnectTimer = setTimeout(() => {\n console.error('[pty] No clients connected for 60s, killing process');\n this.kill();\n }, DISCONNECT_TIMEOUT_MS);\n }\n }\n\n isAlive(): boolean {\n return this.session !== null;\n }\n\n isAvailable(): boolean {\n return pty !== null;\n }\n\n private broadcastToClients(message: Record<string, unknown>): void {\n const data = JSON.stringify(message);\n for (const client of this.connectedClients) {\n if ((client as { readyState: number }).readyState === 1 /* WebSocket.OPEN */) {\n client.send(data);\n }\n }\n }\n\n private startStatusBroadcast(): void {\n this.stopStatusBroadcast();\n this.statusInterval = setInterval(() => {\n const status = this.getStatus();\n if (status) {\n this.broadcastToClients({ type: 'status', ...status });\n }\n }, STATUS_INTERVAL_MS);\n }\n\n private stopStatusBroadcast(): void {\n if (this.statusInterval) {\n clearInterval(this.statusInterval);\n this.statusInterval = null;\n }\n }\n}\n","/**\n * MAXSIM Backend Server — Unified persistent backend service\n *\n * Consolidates HTTP API, WebSocket, MCP endpoint, terminal management,\n * and file watching into a single per-project process.\n *\n * CRITICAL: Never import output() or error() from core — they call process.exit().\n * CRITICAL: Never write to stdout directly — stdout may be reserved for protocol use.\n * All logging must go to stderr via console.error().\n */\n\nimport * as path from 'node:path';\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport { createServer } from 'node:http';\nimport type { IncomingMessage } from 'node:http';\nimport type { Duplex } from 'node:stream';\n\nimport express, { type Request, type Response } from 'express';\nimport { WebSocketServer, WebSocket } from 'ws';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';\nimport detectPort from 'detect-port';\n\nimport {\n normalizePhaseName,\n comparePhaseNum,\n getPhasePattern,\n extractFrontmatter,\n stateExtractField,\n stateReplaceField,\n} from '../core/index.js';\n\nimport type {\n RoadmapPhase,\n RoadmapMilestone,\n RoadmapAnalysis,\n PhaseStatus,\n} from '../core/index.js';\n\nimport { registerAllTools } from '../mcp/index.js';\nimport { PtyManager } from './terminal.js';\n\nimport type {\n BackendConfig,\n BackendStatus,\n BackendServer,\n PendingQuestion,\n} from './types.js';\n\n// ─── Logging ──────────────────────────────────────────────────────────────\n\nfunction log(level: 'INFO' | 'WARN' | 'ERROR', tag: string, ...args: unknown[]): void {\n const ts = new Date().toISOString();\n const msg = args.map(a => typeof a === 'string' ? a : JSON.stringify(a)).join(' ');\n console.error(`[${ts}] [${level}] [${tag}] ${msg}`);\n}\n\n// ─── Path security ─────────────────────────────────────────────────────────\n\nfunction isWithinPlanning(cwd: string, targetPath: string): boolean {\n const planningDir = path.resolve(cwd, '.planning');\n const resolved = path.resolve(cwd, targetPath);\n return resolved.startsWith(planningDir);\n}\n\n// ─── Write-suppression for watcher loop prevention ─────────────────────────\n\nfunction normalizeFsPath(p: string): string {\n return p.replace(/\\\\/g, '/');\n}\n\n// ─── Types ─────────────────────────────────────────────────────────────────\n\ninterface DashboardPhase {\n number: string;\n name: string;\n goal: string;\n dependsOn: string[];\n planCount: number;\n summaryCount: number;\n diskStatus: 'complete' | 'partial' | 'planned' | 'discussed' | 'researched' | 'empty' | 'no_directory';\n roadmapComplete: boolean;\n hasContext: boolean;\n hasResearch: boolean;\n}\n\ninterface PlanTask {\n name: string;\n type: string;\n files: string[];\n action: string;\n verify: string;\n done: string;\n completed: boolean;\n}\n\ninterface PlanFile {\n path: string;\n content: string;\n frontmatter: Record<string, unknown>;\n tasks: PlanTask[];\n}\n\ninterface TodoItem {\n text: string;\n completed: boolean;\n file: string;\n}\n\ninterface ParsedState {\n position: string | null;\n lastActivity: string | null;\n currentPhase: string | null;\n currentPlan: string | null;\n status: string | null;\n progress: string | null;\n decisions: string[];\n blockers: string[];\n content: string;\n}\n\n// ─── Parsers ───────────────────────────────────────────────────────────────\n\nfunction parseRoadmap(cwd: string): RoadmapAnalysis | null {\n const roadmapPath = path.join(cwd, '.planning', 'ROADMAP.md');\n if (!fs.existsSync(roadmapPath)) return null;\n\n const content = fs.readFileSync(roadmapPath, 'utf-8').replace(/\\r\\n/g, '\\n');\n const phasesDir = path.join(cwd, '.planning', 'phases');\n const phasePattern = getPhasePattern();\n const phases: RoadmapPhase[] = [];\n let match: RegExpExecArray | null;\n\n while ((match = phasePattern.exec(content)) !== null) {\n const phaseNum = match[1];\n const phaseName = match[2].replace(/\\(INSERTED\\)/i, '').trim();\n\n const sectionStart = match.index;\n const restOfContent = content.slice(sectionStart);\n const nextHeader = restOfContent.match(/\\n#{2,4}\\s+Phase\\s+\\d/i);\n const sectionEnd = nextHeader ? sectionStart + nextHeader.index! : content.length;\n const section = content.slice(sectionStart, sectionEnd);\n\n const goalMatch = section.match(/\\*\\*Goal(?::\\*\\*|\\*\\*:)\\s*([^\\n]+)/i);\n const goal = goalMatch ? goalMatch[1].trim() : null;\n\n const dependsMatch = section.match(/\\*\\*Depends on:\\*\\*\\s*([^\\n]+)/i);\n const depends_on = dependsMatch ? dependsMatch[1].trim() : null;\n\n const normalized = normalizePhaseName(phaseNum);\n let diskStatus: PhaseStatus = 'no_directory';\n let planCount = 0;\n let summaryCount = 0;\n let hasContext = false;\n let hasResearch = false;\n\n try {\n const entries = fs.readdirSync(phasesDir, { withFileTypes: true });\n const dirs = entries.filter(e => e.isDirectory()).map(e => e.name);\n const dirMatch = dirs.find(d => d.startsWith(normalized + '-') || d === normalized);\n\n if (dirMatch) {\n const phaseFiles = fs.readdirSync(path.join(phasesDir, dirMatch));\n planCount = phaseFiles.filter(f => f.endsWith('-PLAN.md') || f === 'PLAN.md').length;\n summaryCount = phaseFiles.filter(f => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md').length;\n hasContext = phaseFiles.some(f => f.endsWith('-CONTEXT.md') || f === 'CONTEXT.md');\n hasResearch = phaseFiles.some(f => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md');\n\n if (summaryCount >= planCount && planCount > 0) diskStatus = 'complete';\n else if (summaryCount > 0) diskStatus = 'partial';\n else if (planCount > 0) diskStatus = 'planned';\n else if (hasResearch) diskStatus = 'researched';\n else if (hasContext) diskStatus = 'discussed';\n else diskStatus = 'empty';\n }\n } catch {\n // phases dir may not exist\n }\n\n const checkboxPattern = new RegExp(`-\\\\s*\\\\[(x| )\\\\]\\\\s*.*Phase\\\\s+${phaseNum.replace('.', '\\\\.')}`, 'i');\n const checkboxMatch = content.match(checkboxPattern);\n const roadmapComplete = checkboxMatch ? checkboxMatch[1] === 'x' : false;\n\n phases.push({\n number: phaseNum,\n name: phaseName,\n goal,\n depends_on,\n plan_count: planCount,\n summary_count: summaryCount,\n has_context: hasContext,\n has_research: hasResearch,\n disk_status: diskStatus,\n roadmap_complete: roadmapComplete,\n });\n }\n\n const milestones: RoadmapMilestone[] = [];\n const milestonePattern = /##\\s*(.*v(\\d+\\.\\d+)[^(\\n]*)/gi;\n let mMatch: RegExpExecArray | null;\n while ((mMatch = milestonePattern.exec(content)) !== null) {\n milestones.push({ heading: mMatch[1].trim(), version: 'v' + mMatch[2] });\n }\n\n const currentPhase = phases.find(p => p.disk_status === 'planned' || p.disk_status === 'partial') || null;\n const nextPhase = phases.find(p =>\n p.disk_status === 'empty' || p.disk_status === 'no_directory' ||\n p.disk_status === 'discussed' || p.disk_status === 'researched'\n ) || null;\n\n const totalPlans = phases.reduce((sum, p) => sum + p.plan_count, 0);\n const totalSummaries = phases.reduce((sum, p) => sum + p.summary_count, 0);\n const completedPhases = phases.filter(p => p.disk_status === 'complete').length;\n\n return {\n milestones,\n phases,\n phase_count: phases.length,\n completed_phases: completedPhases,\n total_plans: totalPlans,\n total_summaries: totalSummaries,\n progress_percent: totalPlans > 0 ? Math.min(100, Math.round((totalSummaries / totalPlans) * 100)) : 0,\n current_phase: currentPhase ? currentPhase.number : null,\n next_phase: nextPhase ? nextPhase.number : null,\n missing_phase_details: null,\n };\n}\n\nfunction parseState(cwd: string): ParsedState | null {\n const statePath = path.join(cwd, '.planning', 'STATE.md');\n if (!fs.existsSync(statePath)) return null;\n\n const content = fs.readFileSync(statePath, 'utf-8').replace(/\\r\\n/g, '\\n');\n\n const position = stateExtractField(content, 'Current Position') || stateExtractField(content, 'Phase');\n const lastActivity = stateExtractField(content, 'Last activity') || stateExtractField(content, 'Last Activity');\n const currentPhase = stateExtractField(content, 'Current Phase') || stateExtractField(content, 'Phase');\n const currentPlan = stateExtractField(content, 'Current Plan') || stateExtractField(content, 'Plan');\n const status = stateExtractField(content, 'Status');\n const progress = stateExtractField(content, 'Progress');\n\n const decisions: string[] = [];\n const decisionsMatch = content.match(/###?\\s*Decisions\\s*\\n([\\s\\S]*?)(?=\\n###?|\\n##[^#]|$)/i);\n if (decisionsMatch) {\n const items = decisionsMatch[1].match(/^-\\s+(.+)$/gm) || [];\n for (const item of items) decisions.push(item.replace(/^-\\s+/, '').trim());\n }\n\n const blockers: string[] = [];\n const blockersMatch = content.match(/###?\\s*(?:Blockers|Blockers\\/Concerns)\\s*\\n([\\s\\S]*?)(?=\\n###?|\\n##[^#]|$)/i);\n if (blockersMatch) {\n const items = blockersMatch[1].match(/^-\\s+(.+)$/gm) || [];\n for (const item of items) blockers.push(item.replace(/^-\\s+/, '').trim());\n }\n\n return { position, lastActivity, currentPhase, currentPlan, status, progress, decisions, blockers, content };\n}\n\nfunction parsePhases(cwd: string): DashboardPhase[] {\n const phasesDir = path.join(cwd, '.planning', 'phases');\n if (!fs.existsSync(phasesDir)) return [];\n\n const phases: DashboardPhase[] = [];\n try {\n const entries = fs.readdirSync(phasesDir, { withFileTypes: true });\n const dirs = entries\n .filter(e => e.isDirectory())\n .map(e => e.name)\n .sort((a, b) => comparePhaseNum(a, b));\n\n for (const dir of dirs) {\n const dm = dir.match(/^(\\d+[A-Z]?(?:\\.\\d+)?)-?(.*)/i);\n const phaseNum = dm ? dm[1] : dir;\n const phaseName = dm && dm[2] ? dm[2].replace(/-/g, ' ') : '';\n\n const phaseFiles = fs.readdirSync(path.join(phasesDir, dir));\n const planCount = phaseFiles.filter(f => f.endsWith('-PLAN.md') || f === 'PLAN.md').length;\n const summaryCount = phaseFiles.filter(f => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md').length;\n const hasContext = phaseFiles.some(f => f.endsWith('-CONTEXT.md') || f === 'CONTEXT.md');\n const hasResearch = phaseFiles.some(f => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md');\n\n let diskStatus: DashboardPhase['diskStatus'] = 'no_directory';\n if (summaryCount >= planCount && planCount > 0) diskStatus = 'complete';\n else if (summaryCount > 0) diskStatus = 'partial';\n else if (planCount > 0) diskStatus = 'planned';\n else if (hasResearch) diskStatus = 'researched';\n else if (hasContext) diskStatus = 'discussed';\n else diskStatus = 'empty';\n\n phases.push({\n number: phaseNum,\n name: phaseName,\n goal: '',\n dependsOn: [],\n planCount,\n summaryCount,\n diskStatus,\n roadmapComplete: diskStatus === 'complete',\n hasContext,\n hasResearch,\n });\n }\n } catch {\n // phases dir may not exist or be empty\n }\n\n return phases;\n}\n\nfunction parsePhaseDetail(\n cwd: string,\n phaseId: string\n): { plans: PlanFile[]; context: string | null; research: string | null } | null {\n const phasesDir = path.join(cwd, '.planning', 'phases');\n if (!fs.existsSync(phasesDir)) return null;\n\n const normalized = normalizePhaseName(phaseId);\n try {\n const entries = fs.readdirSync(phasesDir, { withFileTypes: true });\n const dirs = entries.filter(e => e.isDirectory()).map(e => e.name);\n const dirMatch = dirs.find(d => d.startsWith(normalized + '-') || d === normalized);\n if (!dirMatch) return null;\n\n const phaseDir = path.join(phasesDir, dirMatch);\n const phaseFiles = fs.readdirSync(phaseDir);\n\n const planFileNames = phaseFiles\n .filter(f => f.endsWith('-PLAN.md') || f === 'PLAN.md')\n .sort();\n\n const plans: PlanFile[] = [];\n for (const planFileName of planFileNames) {\n const planPath = path.join(phaseDir, planFileName);\n const content = fs.readFileSync(planPath, 'utf-8').replace(/\\r\\n/g, '\\n');\n const frontmatter = extractFrontmatter(content) as Record<string, unknown>;\n\n const tasks: PlanTask[] = [];\n const taskRegex = /<task\\s+type=\"([^\"]*)\"[^>]*>\\s*<name>([^<]+)<\\/name>([\\s\\S]*?)<\\/task>/g;\n let taskMatch: RegExpExecArray | null;\n\n while ((taskMatch = taskRegex.exec(content)) !== null) {\n const taskType = taskMatch[1];\n const taskName = taskMatch[2].trim();\n const taskBody = taskMatch[3];\n\n const filesMatch = taskBody.match(/<files>([\\s\\S]*?)<\\/files>/);\n const actionMatch = taskBody.match(/<action>([\\s\\S]*?)<\\/action>/);\n const verifyMatch = taskBody.match(/<verify>([\\s\\S]*?)<\\/verify>/);\n const doneMatch = taskBody.match(/<done>([\\s\\S]*?)<\\/done>/);\n\n const files = filesMatch\n ? filesMatch[1].trim().split('\\n').map(f => f.trim()).filter(Boolean)\n : [];\n\n const doneText = doneMatch ? doneMatch[1].trim() : '';\n tasks.push({\n name: taskName,\n type: taskType,\n files,\n action: actionMatch ? actionMatch[1].trim() : '',\n verify: verifyMatch ? verifyMatch[1].trim() : '',\n done: doneText,\n completed: /^\\[x\\]/i.test(doneText),\n });\n }\n\n plans.push({\n path: path.join('.planning', 'phases', dirMatch, planFileName),\n content,\n frontmatter,\n tasks,\n });\n }\n\n let context: string | null = null;\n const contextFile = phaseFiles.find(f => f.endsWith('-CONTEXT.md') || f === 'CONTEXT.md');\n if (contextFile) context = fs.readFileSync(path.join(phaseDir, contextFile), 'utf-8');\n\n let research: string | null = null;\n const researchFile = phaseFiles.find(f => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md');\n if (researchFile) research = fs.readFileSync(path.join(phaseDir, researchFile), 'utf-8');\n\n return { plans, context, research };\n } catch {\n return null;\n }\n}\n\nfunction parseTodos(cwd: string): { pending: TodoItem[]; completed: TodoItem[] } {\n const pendingDir = path.join(cwd, '.planning', 'todos', 'pending');\n const completedDir = path.join(cwd, '.planning', 'todos', 'completed');\n\n const pending: TodoItem[] = [];\n const completed: TodoItem[] = [];\n\n if (fs.existsSync(pendingDir)) {\n try {\n const files = fs.readdirSync(pendingDir).filter(f => f.endsWith('.md'));\n for (const file of files) {\n try {\n const content = fs.readFileSync(path.join(pendingDir, file), 'utf-8');\n const titleMatch = content.match(/^title:\\s*(.+)$/m);\n pending.push({ text: titleMatch ? titleMatch[1].trim() : file.replace('.md', ''), completed: false, file });\n } catch { /* skip unreadable */ }\n }\n } catch { /* pending dir may not exist */ }\n }\n\n if (fs.existsSync(completedDir)) {\n try {\n const files = fs.readdirSync(completedDir).filter(f => f.endsWith('.md'));\n for (const file of files) {\n try {\n const content = fs.readFileSync(path.join(completedDir, file), 'utf-8');\n const titleMatch = content.match(/^title:\\s*(.+)$/m);\n completed.push({ text: titleMatch ? titleMatch[1].trim() : file.replace('.md', ''), completed: true, file });\n } catch { /* skip unreadable */ }\n }\n } catch { /* completed dir may not exist */ }\n }\n\n return { pending, completed };\n}\n\nfunction parseProject(cwd: string): { project: string | null; requirements: string | null } {\n const projectPath = path.join(cwd, '.planning', 'PROJECT.md');\n const requirementsPath = path.join(cwd, '.planning', 'REQUIREMENTS.md');\n const project = fs.existsSync(projectPath) ? fs.readFileSync(projectPath, 'utf-8') : null;\n const requirements = fs.existsSync(requirementsPath) ? fs.readFileSync(requirementsPath, 'utf-8') : null;\n return { project, requirements };\n}\n\n// ─── Server Factory ────────────────────────────────────────────────────────\n\nexport function createBackendServer(config: BackendConfig): BackendServer {\n const {\n projectCwd,\n host,\n enableTerminal,\n enableFileWatcher,\n enableMcp,\n logDir,\n } = config;\n\n let resolvedPort = config.port;\n const startTime = Date.now();\n let serverReady = false;\n\n // Logging\n fs.mkdirSync(logDir, { recursive: true });\n\n // ─── Write suppression ─────────────────────────────────────────────────\n const suppressedPaths = new Map<string, number>();\n const SUPPRESS_TTL_MS = 500;\n\n function suppressPath(filePath: string): void {\n suppressedPaths.set(normalizeFsPath(filePath), Date.now());\n }\n\n function isSuppressed(filePath: string): boolean {\n const normalized = normalizeFsPath(filePath);\n const timestamp = suppressedPaths.get(normalized);\n if (timestamp === undefined) return false;\n if (Date.now() - timestamp > SUPPRESS_TTL_MS) {\n suppressedPaths.delete(normalized);\n return false;\n }\n return true;\n }\n\n // Periodic cleanup of stale suppressed paths\n const cleanupInterval = setInterval(() => {\n const now = Date.now();\n for (const [p, ts] of suppressedPaths.entries()) {\n if (now - ts > SUPPRESS_TTL_MS) suppressedPaths.delete(p);\n }\n }, 60_000);\n cleanupInterval.unref();\n\n // ─── MCP shared state ──────────────────────────────────────────────────\n const questionQueue: PendingQuestion[] = [];\n const pendingAnswers = new Map<string, (answer: string) => void>();\n\n // ─── WebSocket ─────────────────────────────────────────────────────────\n let clientCount = 0;\n\n const wss = new WebSocketServer({ noServer: true });\n\n wss.on('connection', (ws) => {\n clientCount++;\n log('INFO', 'ws', `Client connected (${clientCount} total)`);\n\n ws.on('close', () => {\n clientCount--;\n log('INFO', 'ws', `Client disconnected (${clientCount} total)`);\n });\n\n ws.on('error', (err) => {\n log('ERROR', 'ws', `Client error: ${err.message}`);\n });\n\n ws.send(JSON.stringify({ type: 'connected', timestamp: Date.now() }));\n\n // Send queued questions on reconnect\n if (questionQueue.length > 0) {\n ws.send(JSON.stringify({\n type: 'questions-queued',\n questions: questionQueue,\n count: questionQueue.length,\n }));\n }\n });\n\n function broadcast(message: Record<string, unknown>): void {\n const data = JSON.stringify(message);\n for (const client of wss.clients) {\n if (client.readyState === WebSocket.OPEN) {\n client.send(data);\n }\n }\n }\n\n // ─── File watcher ──────────────────────────────────────────────────────\n let watcher: { close(): Promise<void> } | null = null;\n\n async function setupWatcher(): Promise<void> {\n if (!enableFileWatcher) return;\n\n const planningDir = path.join(projectCwd, '.planning');\n if (!fs.existsSync(planningDir)) {\n log('WARN', 'watcher', `.planning/ directory not found at ${planningDir}`);\n return;\n }\n\n try {\n const chokidar = await import('chokidar');\n const changedPaths = new Set<string>();\n let flushTimer: ReturnType<typeof setTimeout> | null = null;\n\n function flushChanges(): void {\n if (changedPaths.size > 0) {\n const changes = Array.from(changedPaths);\n changedPaths.clear();\n log('INFO', 'watcher', `Broadcasting ${changes.length} change(s)`);\n broadcast({ type: 'file-changes', changes, timestamp: Date.now() });\n }\n }\n\n function onFileChange(filePath: string): void {\n const normalized = normalizeFsPath(filePath);\n if (isSuppressed(normalized)) return;\n changedPaths.add(normalized);\n if (flushTimer) clearTimeout(flushTimer);\n flushTimer = setTimeout(flushChanges, 500);\n }\n\n const w = chokidar.watch(planningDir, {\n persistent: true,\n ignoreInitial: true,\n depth: 5,\n });\n\n w.on('add', onFileChange);\n w.on('change', onFileChange);\n w.on('unlink', onFileChange);\n w.on('error', (err: unknown) => {\n log('ERROR', 'watcher', `Error: ${(err as Error).message}`);\n });\n\n watcher = w;\n log('INFO', 'watcher', `Watching ${planningDir}`);\n } catch (err) {\n log('ERROR', 'watcher', `Failed to start file watcher: ${(err as Error).message}`);\n }\n }\n\n // ─── Express app ───────────────────────────────────────────────────────\n const app = express();\n app.use(express.json());\n\n // ── Health ──\n app.get('/api/health', (_req: Request, res: Response) => {\n res.json({\n status: 'ok' as const,\n ready: serverReady,\n port: resolvedPort,\n cwd: projectCwd,\n uptime: (Date.now() - startTime) / 1000,\n pid: process.pid,\n mcpEndpoint: enableMcp ? `http://127.0.0.1:${resolvedPort}/mcp` : null,\n terminalAvailable: enableTerminal && PtyManager.getInstance().isAvailable(),\n connectedClients: clientCount,\n });\n });\n\n app.get('/api/ready', (_req: Request, res: Response) => {\n if (serverReady) {\n return res.json({ ready: true, port: resolvedPort, cwd: projectCwd });\n }\n return res.status(503).json({ ready: false, message: 'Server is starting up' });\n });\n\n // ── Roadmap ──\n app.get('/api/roadmap', (_req: Request, res: Response) => {\n try {\n const data = parseRoadmap(projectCwd);\n if (!data) return res.status(404).json({ error: 'ROADMAP.md not found' });\n return res.json(data);\n } catch (err) {\n log('ERROR', 'api', `GET /api/roadmap failed: ${(err as Error).message}`);\n return res.status(500).json({ error: 'Internal server error' });\n }\n });\n\n app.patch('/api/roadmap', (req: Request, res: Response) => {\n try {\n const roadmapPath = path.join(projectCwd, '.planning', 'ROADMAP.md');\n if (!fs.existsSync(roadmapPath)) return res.status(404).json({ error: 'ROADMAP.md not found' });\n\n const { phaseNumber, checked } = req.body as { phaseNumber?: string; checked?: boolean };\n if (!phaseNumber || checked === undefined) {\n return res.status(400).json({ error: 'phaseNumber and checked are required' });\n }\n\n let content = fs.readFileSync(roadmapPath, 'utf-8').replace(/\\r\\n/g, '\\n');\n const escapedNum = phaseNumber.replace('.', '\\\\.');\n const pattern = new RegExp(`(-\\\\s*\\\\[)(x| )(\\\\]\\\\s*.*Phase\\\\s+${escapedNum})`, 'i');\n const match = content.match(pattern);\n\n if (!match) return res.status(404).json({ error: `Phase ${phaseNumber} checkbox not found` });\n\n content = content.replace(pattern, `$1${checked ? 'x' : ' '}$3`);\n suppressPath(roadmapPath);\n fs.writeFileSync(roadmapPath, content, 'utf-8');\n return res.json({ updated: true, phaseNumber, checked });\n } catch (err) {\n log('ERROR', 'api', `PATCH /api/roadmap failed: ${(err as Error).message}`);\n return res.status(500).json({ error: 'Internal server error' });\n }\n });\n\n // ── State ──\n app.get('/api/state', (_req: Request, res: Response) => {\n try {\n const data = parseState(projectCwd);\n if (!data) return res.status(404).json({ error: 'STATE.md not found' });\n return res.json(data);\n } catch (err) {\n log('ERROR', 'api', `GET /api/state failed: ${(err as Error).message}`);\n return res.status(500).json({ error: 'Internal server error' });\n }\n });\n\n app.patch('/api/state', (req: Request, res: Response) => {\n try {\n const statePath = path.join(projectCwd, '.planning', 'STATE.md');\n if (!fs.existsSync(statePath)) return res.status(404).json({ error: 'STATE.md not found' });\n\n const { field, value } = req.body as { field?: string; value?: string };\n if (!field || value === undefined) {\n return res.status(400).json({ error: 'field and value are required' });\n }\n\n const content = fs.readFileSync(statePath, 'utf-8').replace(/\\r\\n/g, '\\n');\n const updated = stateReplaceField(content, field, value);\n if (!updated) return res.status(404).json({ error: `Field \"${field}\" not found in STATE.md` });\n\n suppressPath(statePath);\n fs.writeFileSync(statePath, updated, 'utf-8');\n return res.json({ updated: true, field });\n } catch (err) {\n log('ERROR', 'api', `PATCH /api/state failed: ${(err as Error).message}`);\n return res.status(500).json({ error: 'Internal server error' });\n }\n });\n\n // Helper: ensure STATE.md exists\n function ensureStateMd(statePath: string): void {\n if (fs.existsSync(statePath)) return;\n const planningDir = path.dirname(statePath);\n fs.mkdirSync(planningDir, { recursive: true });\n const template = `# Project State\n\n## Current Position\n\nPhase: 1\nStatus: In progress\nLast activity: ${new Date().toISOString().split('T')[0]} — State file created\n\n## Accumulated Context\n\n### Decisions\n\nNone yet.\n\n### Blockers/Concerns\n\nNone yet.\n`;\n fs.writeFileSync(statePath, template, 'utf-8');\n }\n\n // Helper: append to a STATE.md section\n function appendToStateSection(\n statePath: string,\n sectionPattern: RegExp,\n entry: string,\n fallbackSection: string,\n ): void {\n let content = fs.readFileSync(statePath, 'utf-8').replace(/\\r\\n/g, '\\n');\n const match = content.match(sectionPattern);\n\n if (match) {\n let sectionBody = match[2];\n sectionBody = sectionBody\n .replace(/None yet\\.?\\s*\\n?/gi, '')\n .replace(/No decisions yet\\.?\\s*\\n?/gi, '')\n .replace(/None\\.?\\s*\\n?/gi, '');\n sectionBody = sectionBody.trimEnd() + '\\n' + entry + '\\n';\n content = content.replace(sectionPattern, (_m, header: string) => `${header}${sectionBody}`);\n } else {\n content = content.trimEnd() + '\\n\\n' + fallbackSection + '\\n' + entry + '\\n';\n }\n\n suppressPath(statePath);\n fs.writeFileSync(statePath, content, 'utf-8');\n }\n\n // ── Add Decision ──\n app.post('/api/state/decision', (req: Request, res: Response) => {\n try {\n const statePath = path.join(projectCwd, '.planning', 'STATE.md');\n ensureStateMd(statePath);\n\n const { phase, text } = req.body as { phase?: string; text?: string };\n if (!text?.trim()) return res.status(400).json({ error: 'text is required' });\n\n const phaseLabel = phase?.trim() || '?';\n const entry = `- [Phase ${phaseLabel}]: ${text.trim()}`;\n const sectionPattern = /(###?\\s*(?:Decisions|Decisions Made|Accumulated.*Decisions)\\s*\\n)([\\s\\S]*?)(?=\\n###?|\\n##[^#]|$)/i;\n\n appendToStateSection(statePath, sectionPattern, entry, '### Decisions');\n return res.json({ added: true, decision: entry });\n } catch (err) {\n log('ERROR', 'api', `POST /api/state/decision failed: ${(err as Error).message}`);\n return res.status(500).json({ error: 'Internal server error' });\n }\n });\n\n // ── Add Blocker ──\n app.post('/api/state/blocker', (req: Request, res: Response) => {\n try {\n const statePath = path.join(projectCwd, '.planning', 'STATE.md');\n ensureStateMd(statePath);\n\n const { text } = req.body as { text?: string };\n if (!text?.trim()) return res.status(400).json({ error: 'text is required' });\n\n const entry = `- ${text.trim()}`;\n const sectionPattern = /(###?\\s*(?:Blockers|Blockers\\/Concerns|Concerns)\\s*\\n)([\\s\\S]*?)(?=\\n###?|\\n##[^#]|$)/i;\n\n appendToStateSection(statePath, sectionPattern, entry, '### Blockers/Concerns');\n return res.json({ added: true, blocker: text.trim() });\n } catch (err) {\n log('ERROR', 'api', `POST /api/state/blocker failed: ${(err as Error).message}`);\n return res.status(500).json({ error: 'Internal server error' });\n }\n });\n\n // ── Phases ──\n app.get('/api/phases', (_req: Request, res: Response) => {\n try {\n return res.json(parsePhases(projectCwd));\n } catch (err) {\n log('ERROR', 'api', `GET /api/phases failed: ${(err as Error).message}`);\n return res.status(500).json({ error: 'Internal server error' });\n }\n });\n\n app.get('/api/phase/:id', (req: Request, res: Response) => {\n try {\n const data = parsePhaseDetail(projectCwd, req.params.id);\n if (!data) return res.status(404).json({ error: `Phase ${req.params.id} not found` });\n return res.json(data);\n } catch (err) {\n log('ERROR', 'api', `GET /api/phase/:id failed: ${(err as Error).message}`);\n return res.status(500).json({ error: 'Internal server error' });\n }\n });\n\n // ── Todos ──\n app.get('/api/todos', (_req: Request, res: Response) => {\n try {\n return res.json(parseTodos(projectCwd));\n } catch (err) {\n log('ERROR', 'api', `GET /api/todos failed: ${(err as Error).message}`);\n return res.status(500).json({ error: 'Internal server error' });\n }\n });\n\n app.post('/api/todos', (req: Request, res: Response) => {\n try {\n const pendingDir = path.join(projectCwd, '.planning', 'todos', 'pending');\n const { text } = req.body as { text?: string };\n if (!text) return res.status(400).json({ error: 'text is required' });\n\n fs.mkdirSync(pendingDir, { recursive: true });\n\n const timestamp = new Date().toISOString().split('T')[0];\n const slug = text.toLowerCase().replace(/[^a-z0-9]+/g, '-').slice(0, 40);\n const filename = `${timestamp}-${slug}.md`;\n const filePath = path.join(pendingDir, filename);\n const content = `title: ${text}\\ncreated: ${timestamp}\\narea: general\\n\\n${text}\\n`;\n\n suppressPath(filePath);\n fs.writeFileSync(filePath, content, 'utf-8');\n\n return res.json({ created: true, file: filename, text });\n } catch (err) {\n log('ERROR', 'api', `POST /api/todos failed: ${(err as Error).message}`);\n return res.status(500).json({ error: 'Internal server error' });\n }\n });\n\n app.patch('/api/todos', (req: Request, res: Response) => {\n try {\n const pendingDir = path.join(projectCwd, '.planning', 'todos', 'pending');\n const completedDir = path.join(projectCwd, '.planning', 'todos', 'completed');\n const { file, completed } = req.body as { file?: string; completed?: boolean };\n\n if (!file) return res.status(400).json({ error: 'file is required' });\n if (file.includes('/') || file.includes('\\\\') || file.includes('..')) {\n return res.status(400).json({ error: 'Invalid filename' });\n }\n\n if (completed) {\n const sourcePath = path.join(pendingDir, file);\n if (!fs.existsSync(sourcePath)) return res.status(404).json({ error: 'Todo not found in pending' });\n\n fs.mkdirSync(completedDir, { recursive: true });\n const today = new Date().toISOString().split('T')[0];\n let content = fs.readFileSync(sourcePath, 'utf-8');\n content = `completed: ${today}\\n` + content;\n const destPath = path.join(completedDir, file);\n\n suppressPath(sourcePath);\n suppressPath(destPath);\n fs.writeFileSync(destPath, content, 'utf-8');\n fs.unlinkSync(sourcePath);\n\n return res.json({ completed: true, file, date: today });\n } else {\n const sourcePath = path.join(completedDir, file);\n if (!fs.existsSync(sourcePath)) return res.status(404).json({ error: 'Todo not found in completed' });\n\n fs.mkdirSync(pendingDir, { recursive: true });\n let content = fs.readFileSync(sourcePath, 'utf-8');\n content = content.replace(/^completed:\\s*.+\\n/m, '');\n const destPath = path.join(pendingDir, file);\n\n suppressPath(sourcePath);\n suppressPath(destPath);\n fs.writeFileSync(destPath, content, 'utf-8');\n fs.unlinkSync(sourcePath);\n\n return res.json({ completed: false, file });\n }\n } catch (err) {\n log('ERROR', 'api', `PATCH /api/todos failed: ${(err as Error).message}`);\n return res.status(500).json({ error: 'Internal server error' });\n }\n });\n\n // ── Project ──\n app.get('/api/project', (_req: Request, res: Response) => {\n try {\n return res.json(parseProject(projectCwd));\n } catch (err) {\n log('ERROR', 'api', `GET /api/project failed: ${(err as Error).message}`);\n return res.status(500).json({ error: 'Internal server error' });\n }\n });\n\n // ── Plan file (read) ──\n app.get('/api/plan/*', (req: Request, res: Response) => {\n try {\n const pathSegments = (req.params as Record<string, string>)['0'].split('/');\n const relativePath = path.join('.planning', ...pathSegments);\n\n if (!isWithinPlanning(projectCwd, relativePath)) {\n return res.status(403).json({ error: 'Path traversal not allowed' });\n }\n\n const fullPath = path.join(projectCwd, relativePath);\n if (!fs.existsSync(fullPath)) return res.status(404).json({ error: 'File not found' });\n\n const content = fs.readFileSync(fullPath, 'utf-8');\n return res.json({ path: relativePath, content });\n } catch (err) {\n log('ERROR', 'api', `GET /api/plan/* failed: ${(err as Error).message}`);\n return res.status(500).json({ error: 'Internal server error' });\n }\n });\n\n // ── Plan file (write) ──\n app.put('/api/plan/*', (req: Request, res: Response) => {\n try {\n const pathSegments = (req.params as Record<string, string>)['0'].split('/');\n const relativePath = path.join('.planning', ...pathSegments);\n\n if (!isWithinPlanning(projectCwd, relativePath)) {\n return res.status(403).json({ error: 'Path traversal not allowed' });\n }\n\n const { content } = req.body as { content?: string };\n if (content === undefined) return res.status(400).json({ error: 'content is required' });\n\n const fullPath = path.join(projectCwd, relativePath);\n const dir = path.dirname(fullPath);\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });\n\n suppressPath(fullPath);\n fs.writeFileSync(fullPath, content, 'utf-8');\n\n return res.json({ written: true, path: relativePath });\n } catch (err) {\n log('ERROR', 'api', `PUT /api/plan/* failed: ${(err as Error).message}`);\n return res.status(500).json({ error: 'Internal server error' });\n }\n });\n\n // ── Server info ──\n app.get('/api/server-info', (_req: Request, res: Response) => {\n const localNetworkIp = getLocalNetworkIp();\n return res.json({\n localUrl: `http://127.0.0.1:${resolvedPort}`,\n networkUrl: localNetworkIp ? `http://${localNetworkIp}:${resolvedPort}` : null,\n projectName: path.basename(projectCwd),\n projectCwd,\n });\n });\n\n // ── Shutdown ──\n let shutdownFn: (() => void) | null = null;\n\n app.post('/api/shutdown', (_req: Request, res: Response) => {\n res.json({ shutdown: true });\n setTimeout(() => shutdownFn?.(), 100);\n });\n\n // ── MCP answer ──\n app.post('/api/mcp-answer', (req: Request, res: Response) => {\n const { questionId, answer } = req.body as { questionId: string; answer: string };\n if (!questionId || !answer) return res.status(400).json({ error: 'questionId and answer are required' });\n const resolve = pendingAnswers.get(questionId);\n if (!resolve) return res.status(404).json({ error: 'No pending question with that ID' });\n pendingAnswers.delete(questionId);\n resolve(answer);\n return res.json({ answered: true });\n });\n\n // ── MCP endpoint ──\n if (enableMcp) {\n app.post('/mcp', async (req: Request, res: Response) => {\n const mcpServer = new McpServer({ name: 'maxsim-backend', version: '1.0.0' });\n registerAllTools(mcpServer);\n try {\n const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });\n await mcpServer.connect(transport);\n await transport.handleRequest(req, res, req.body);\n res.on('close', () => {\n transport.close();\n mcpServer.close();\n });\n } catch (error) {\n log('ERROR', 'mcp', `Error handling MCP POST request: ${error}`);\n if (!res.headersSent) {\n res.status(500).json({\n jsonrpc: '2.0',\n error: { code: -32603, message: 'Internal server error' },\n id: null,\n });\n }\n }\n });\n\n app.get('/mcp', (_req: Request, res: Response) => {\n res.writeHead(405).end(JSON.stringify({\n jsonrpc: '2.0',\n error: { code: -32000, message: 'Method not allowed.' },\n id: null,\n }));\n });\n\n app.delete('/mcp', (_req: Request, res: Response) => {\n res.status(200).end();\n });\n }\n\n // ─── Terminal WebSocket ────────────────────────────────────────────────\n const terminalWss = new WebSocketServer({ noServer: true });\n const ptyManager = enableTerminal ? PtyManager.getInstance() : null;\n\n if (ptyManager && !ptyManager.isAvailable()) {\n log('WARN', 'server', 'node-pty not available — terminal features disabled');\n }\n\n terminalWss.on('connection', (ws: WebSocket) => {\n if (!ptyManager) return;\n log('INFO', 'terminal-ws', 'Client connected');\n ptyManager.addClient(ws);\n\n if (!ptyManager.isAvailable()) {\n ws.send(JSON.stringify({ type: 'unavailable', reason: 'node-pty is not installed' }));\n }\n\n ws.on('message', (raw: Buffer | string) => {\n try {\n const msg = JSON.parse(typeof raw === 'string' ? raw : raw.toString());\n switch (msg.type) {\n case 'input':\n ptyManager.write(msg.data);\n break;\n case 'resize':\n ptyManager.resize(msg.cols, msg.rows);\n break;\n case 'spawn':\n try {\n ptyManager.spawn({\n skipPermissions: !!msg.skipPermissions,\n cwd: projectCwd,\n cols: msg.cols,\n rows: msg.rows,\n });\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n ws.send(JSON.stringify({ type: 'output', data: `\\r\\n\\x1b[31mFailed to start terminal: ${errMsg}\\x1b[0m\\r\\n` }));\n }\n break;\n case 'kill':\n ptyManager.kill();\n break;\n }\n } catch (err) {\n log('ERROR', 'terminal-ws', `Message handling error: ${(err as Error).message}`);\n }\n });\n\n ws.on('close', () => {\n log('INFO', 'terminal-ws', 'Client disconnected');\n ptyManager.removeClient(ws);\n });\n\n ws.on('error', (err) => {\n log('ERROR', 'terminal-ws', `Client error: ${err.message}`);\n });\n });\n\n // ─── HTTP Server ───────────────────────────────────────────────────────\n const server = createServer(app);\n\n // WebSocket upgrade routing\n server.on('upgrade', (req: IncomingMessage, socket: Duplex, head: Buffer) => {\n const url = req.url || '/';\n if (url === '/ws/terminal' || url.startsWith('/ws/terminal?')) {\n terminalWss.handleUpgrade(req, socket, head, (ws) => {\n terminalWss.emit('connection', ws, req);\n });\n } else if (url === '/api/ws' || url.startsWith('/api/ws?')) {\n wss.handleUpgrade(req, socket, head, (ws) => {\n wss.emit('connection', ws, req);\n });\n } else {\n socket.destroy();\n }\n });\n\n // ─── Lifecycle methods ─────────────────────────────────────────────────\n\n async function start(): Promise<void> {\n const port = await detectPort(config.port);\n resolvedPort = port;\n\n await setupWatcher();\n\n return new Promise<void>((resolve) => {\n server.listen(port, host, () => {\n serverReady = true;\n log('INFO', 'server', `Backend ready on ${host}:${port} for ${projectCwd}`);\n if (enableMcp) {\n log('INFO', 'mcp', `MCP endpoint available at http://127.0.0.1:${port}/mcp`);\n }\n resolve();\n });\n });\n }\n\n async function stop(): Promise<void> {\n log('INFO', 'server', 'Shutting down...');\n clearInterval(cleanupInterval);\n\n if (ptyManager) {\n ptyManager.kill();\n }\n\n if (watcher) {\n await watcher.close().catch(() => {});\n }\n\n terminalWss.close(() => {});\n wss.close(() => {});\n\n return new Promise<void>((resolve) => {\n server.close(() => {\n log('INFO', 'server', 'Server closed');\n resolve();\n });\n });\n }\n\n shutdownFn = () => {\n stop().then(() => process.exit(0)).catch(() => process.exit(1));\n };\n\n function getStatus(): BackendStatus {\n return {\n status: serverReady ? 'ok' : 'starting',\n ready: serverReady,\n port: resolvedPort,\n cwd: projectCwd,\n uptime: (Date.now() - startTime) / 1000,\n pid: process.pid,\n mcpEndpoint: enableMcp ? `http://127.0.0.1:${resolvedPort}/mcp` : null,\n terminalAvailable: ptyManager?.isAvailable() ?? false,\n connectedClients: clientCount,\n };\n }\n\n function getPort(): number {\n return resolvedPort;\n }\n\n return { start, stop, getStatus, getPort };\n}\n\n// ─── Utility ────────────────────────────────────────────────────────────────\n\nfunction getLocalNetworkIp(): string | null {\n const ifaces = os.networkInterfaces();\n for (const iface of Object.values(ifaces)) {\n for (const info of iface ?? []) {\n if (info.family === 'IPv4' && !info.internal) {\n return info.address;\n }\n }\n }\n return null;\n}\n"],"x_google_ignoreList":[19,20,21,22,23,24,25,26,27],"mappings":"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"}