fifony 0.1.23 → 0.1.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +1 -2
  2. package/app/dist/assets/{KeyboardShortcutsHelp-BB5jLK_E.js → KeyboardShortcutsHelp-DghUbt7X.js} +1 -1
  3. package/app/dist/assets/{OnboardingWizard-xyM3Okjv.js → OnboardingWizard-DmR2BUmf.js} +1 -1
  4. package/app/dist/assets/{analytics.lazy-CfJXsh6r.js → analytics.lazy-dj9i_px8.js} +1 -1
  5. package/app/dist/assets/index-Dau_ep-t.js +43 -0
  6. package/app/dist/assets/index-Qr2OPvRO.css +1 -0
  7. package/app/dist/index.html +2 -2
  8. package/app/dist/service-worker.js +1 -1
  9. package/dist/agent/run-local.js +7 -7
  10. package/dist/agent/run-local.js.map +1 -1
  11. package/dist/{chunk-NLIVWBNV.js → chunk-D6WNSDQ5.js} +4 -4
  12. package/dist/{chunk-KT5V7N5H.js → chunk-HJFRXKDS.js} +27 -48
  13. package/dist/chunk-HJFRXKDS.js.map +1 -0
  14. package/dist/{chunk-DD5BE2W6.js → chunk-RINIJIFO.js} +5 -2
  15. package/dist/chunk-RINIJIFO.js.map +1 -0
  16. package/dist/{chunk-G6CQK2WH.js → chunk-V6IHUFZB.js} +45 -10
  17. package/dist/{chunk-G6CQK2WH.js.map → chunk-V6IHUFZB.js.map} +1 -1
  18. package/dist/cli.js +4 -4
  19. package/dist/issue-runner-QSUROSNX.js +13 -0
  20. package/dist/{issue-state-machine-NSDN4MV4.js → issue-state-machine-H4BWOONX.js} +3 -3
  21. package/dist/mcp/server.js +1 -1
  22. package/dist/{queue-workers-VHYQYYLG.js → queue-workers-BW4XANJJ.js} +2 -2
  23. package/dist/{store-FH7L6KR2.js → store-JFDHTPVH.js} +5 -5
  24. package/package.json +1 -1
  25. package/app/dist/assets/index-C1QEwHZG.js +0 -43
  26. package/app/dist/assets/index-DjmUHXd1.css +0 -1
  27. package/dist/chunk-DD5BE2W6.js.map +0 -1
  28. package/dist/chunk-KT5V7N5H.js.map +0 -1
  29. package/dist/issue-runner-6VFNHYJL.js +0 -13
  30. /package/dist/{chunk-NLIVWBNV.js.map → chunk-D6WNSDQ5.js.map} +0 -0
  31. /package/dist/{issue-runner-6VFNHYJL.js.map → issue-runner-QSUROSNX.js.map} +0 -0
  32. /package/dist/{issue-state-machine-NSDN4MV4.js.map → issue-state-machine-H4BWOONX.js.map} +0 -0
  33. /package/dist/{queue-workers-VHYQYYLG.js.map → queue-workers-BW4XANJJ.js.map} +0 -0
  34. /package/dist/{store-FH7L6KR2.js.map → store-JFDHTPVH.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/boot.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { mkdirSync } from \"node:fs\";\nimport { env, exit, argv } from \"node:process\";\nimport { CLI_ARGS, PACKAGE_ROOT, STATE_ROOT, TARGET_ROOT } from \"./concerns/constants.ts\";\nimport { debugBoot, fail, now, sleep, parseIntArg } from \"./concerns/helpers.ts\";\nimport { initLogger, logger } from \"./concerns/logger.ts\";\nimport { initStateStore, loadPersistedState, persistState, persistStateFull, closeStateStore } from \"./persistence/store.ts\";\nimport { initQueueWorkers, stopQueueWorkers, enqueueForPlanning, enqueueForExecution, enqueueForReview } from \"./persistence/plugins/queue-workers.ts\";\nimport { createContainer } from \"./persistence/container.ts\";\nimport {\n applyPersistedSettings,\n loadRuntimeSettings,\n persistDetectedProvidersSetting,\n syncRuntimeConfigSettings,\n} from \"./persistence/settings.ts\";\nimport { buildQueueTitle, detectProjectName, resolveProjectMetadata } from \"./domains/project.ts\";\nimport {\n detectAvailableProviders,\n resolveDefaultProvider,\n getProviderDefaultCommand,\n} from \"./agents/providers.ts\";\nimport { setSkipSource, detectDefaultBranch } from \"./domains/workspace.ts\";\nimport { deriveConfig, applyWorkflowConfig, buildRuntimeState, computeMetrics, addEvent, validateConfig } from \"./domains/issues.ts\";\nimport { hasDirtyState } from \"./persistence/dirty-tracker.ts\";\nimport { executeTransition } from \"./persistence/plugins/issue-state-machine.ts\";\nimport { startApiServer } from \"./persistence/plugins/api-server.ts\";\nimport { installGracefulShutdown, isShuttingDown, ensureNotStale, hasTerminalQueue } from \"./persistence/plugins/scheduler.ts\";\nimport { cleanWorkspace, isAgentStillRunning, cleanStalePidFile } from \"./agents/agent.ts\";\nimport { recoverPlanningSession } from \"./agents/planning/issue-planner.ts\";\nimport { hydrate as hydrateTokenLedger } from \"./domains/tokens.ts\";\nimport { resolve } from \"node:path\";\nimport type { RuntimeState } from \"./types.ts\";\n\nfunction parsePort(args: string[]): number | undefined {\n for (let i = 0; i < args.length; i += 1) {\n const arg = args[i];\n if (arg === \"--port\") {\n const value = args[i + 1];\n if (!value || !/^\\d+$/.test(value)) {\n fail(`Invalid value for --port: ${value ?? \"<empty>\"}`);\n }\n return parseIntArg(value, 4040);\n }\n }\n return undefined;\n}\n\nasync function startDevFrontend(apiPort: number, devPort: number): Promise<void> {\n const VITE_CONFIG_PATH = resolve(PACKAGE_ROOT, \"app/vite.config.js\");\n let createViteServer: typeof import(\"vite\").createServer;\n try {\n const vite = await import(\"vite\");\n createViteServer = vite.createServer;\n } catch {\n logger.warn(\"Vite not installed (devDependency). Run 'pnpm install' in the project to enable --dev mode.\");\n return;\n }\n // Wait for the API server to be ready before starting the proxy\n for (let attempt = 0; attempt < 20; attempt++) {\n try {\n const res = await fetch(`http://localhost:${apiPort}/api/health`);\n if (res.ok) break;\n } catch {\n await new Promise((r) => setTimeout(r, 250));\n }\n }\n\n try {\n const server = await createViteServer({\n configFile: VITE_CONFIG_PATH,\n customLogger: {\n info: (msg: string) => logger.info(`[Vite] ${msg}`),\n warn: (msg: string) => logger.warn(`[Vite] ${msg}`),\n warnOnce: (msg: string) => logger.warn(`[Vite] ${msg}`),\n error: (msg: string) => {\n if (msg.includes(\"ws proxy error\") || msg.includes(\"ws proxy socket error\")) {\n logger.debug(`[Vite] ${msg.split(\"\\n\")[0]} (transient, suppressed)`);\n return;\n }\n logger.error(`[Vite] ${msg}`);\n },\n hasErrorLogged: () => false,\n clearScreen: () => {},\n hasWarned: false,\n },\n server: {\n port: devPort,\n host: true,\n proxy: {\n \"/api\": `http://localhost:${apiPort}`,\n \"/ws\": {\n target: `ws://localhost:${apiPort}`,\n ws: true,\n configure: (proxy) => {\n const silence = (err: any) => {\n logger.debug(`[Vite] WS proxy transient: ${err.code || err.message}`);\n };\n proxy.on(\"error\", silence);\n proxy.on(\"proxyReqWs\", (_proxyReq: any, _req: any, socket: any) => {\n socket.on(\"error\", silence);\n });\n },\n },\n \"/docs\": `http://localhost:${apiPort}`,\n \"/health\": `http://localhost:${apiPort}`,\n \"/manifest.webmanifest\": `http://localhost:${apiPort}`,\n \"/service-worker.js\": `http://localhost:${apiPort}`,\n \"/icon.svg\": `http://localhost:${apiPort}`,\n \"/icon-maskable.svg\": `http://localhost:${apiPort}`,\n \"/offline.html\": `http://localhost:${apiPort}`,\n },\n },\n });\n await server.listen();\n logger.info(`Dev frontend available at http://localhost:${devPort}`);\n } catch (error) {\n logger.warn(`Failed to start Vite dev server: ${String(error)}`);\n }\n}\n\nfunction usage() {\n console.log(\n `Usage: ${argv[1]} [options]\\n` +\n \"Options:\\n\" +\n \" --workspace <path> Target workspace root (default: current directory)\\n\" +\n \" --persistence <path> Persistence root (default: current directory)\\n\" +\n \" --port <n> Start local dashboard\\n\" +\n \" --concurrency <n> Maximum number of local workers\\n\" +\n \" --attempts <n> Maximum attempts per issue\\n\" +\n \" --poll <ms> Scheduler interval in ms\\n\" +\n \" --timeout <ms> Agent command timeout in ms (default: 1800000)\\n\" +\n \" --dev Start Vite dev server alongside API (HMR on port+1)\\n\" +\n \" --once Process once and exit\\n\" +\n \" --skip-source Skip source snapshot copy\\n\" +\n \" --skip-scan Skip project analysis\\n\" +\n \" --skip-recovery Skip orphaned agent recovery\\n\" +\n \" --fast-boot Equivalent to --skip-source --skip-scan --skip-recovery\\n\",\n );\n}\n\nasync function main() {\n debugBoot(\"main:start\");\n\n const args = CLI_ARGS;\n if (args.includes(\"--help\") || args.includes(\"-h\")) {\n usage();\n return;\n }\n\n mkdirSync(STATE_ROOT, { recursive: true });\n initLogger(STATE_ROOT);\n logger.info(\"[Boot] Fifony runtime starting\");\n logger.info({ stateRoot: STATE_ROOT, cwd: process.cwd() }, \"[Boot] State root initialized\");\n\n // Detect available providers\n const detectedProviders = detectAvailableProviders();\n for (const p of detectedProviders) {\n logger.info(`Provider ${p.name}: ${p.available ? `available at ${p.path}` : \"not found\"}`);\n }\n\n const interfaceMode = (env.FIFONY_INTERFACE ?? \"cli\").trim().toLowerCase();\n const runOnce = args.includes(\"--once\");\n const devMode = args.includes(\"--dev\") || env.NODE_ENV === \"development\";\n const fastBoot = args.includes(\"--fast-boot\");\n const skipSource = fastBoot || args.includes(\"--skip-source\");\n if (skipSource) setSkipSource(true);\n\n debugBoot(\"main:state-root-ready\");\n\n const port = parsePort(args);\n let config = applyWorkflowConfig(deriveConfig(args), port);\n\n // Auto-resolve provider command if not configured\n if (!config.agentCommand.trim()) {\n const defaultProvider = resolveDefaultProvider(detectedProviders);\n if (defaultProvider) {\n const defaultCommand = getProviderDefaultCommand(defaultProvider);\n if (defaultCommand) {\n config = { ...config, agentProvider: defaultProvider, agentCommand: defaultCommand };\n logger.info(`Auto-detected provider: ${defaultProvider} → ${defaultCommand}`);\n }\n }\n }\n\n const dashboardPort = port ?? (config.dashboardPort ? Number.parseInt(config.dashboardPort, 10) : undefined);\n const skipRecovery = args.includes(\"--skip-recovery\") || args.includes(\"--fast-boot\");\n const detectedProjectName = detectProjectName(TARGET_ROOT);\n\n // ── Phase B: Parallel initialization ────────────────────────────────────────\n debugBoot(\"main:phase-b-start\");\n logger.debug(\"[Boot] Initializing state store (s3db)\");\n await initStateStore();\n logger.info(\"[Boot] State store initialized\");\n debugBoot(\"main:store-initialized\");\n\n // ── Early API start: dashboard available while boot continues ─────────────\n // Build a minimal placeholder state for the early API server\n const earlyState: RuntimeState = {\n projectName: detectedProjectName,\n detectedProjectName,\n projectNameSource: detectedProjectName ? \"detected\" : \"missing\",\n queueTitle: buildQueueTitle(detectedProjectName),\n startedAt: now(),\n updatedAt: now(),\n trackerKind: \"filesystem\",\n sourceRepoUrl: TARGET_ROOT,\n sourceRef: \"workspace\",\n config,\n issues: [],\n events: [],\n metrics: { total: 0, planning: 0, queued: 0, inProgress: 0, blocked: 0, done: 0, cancelled: 0, activeWorkers: 0 },\n notes: [],\n booting: true,\n };\n\n let apiState = earlyState;\n // Initialize container early so API routes can use commands immediately\n createContainer(apiState);\n debugBoot(\"main:container-early-init\");\n\n if (dashboardPort) {\n await startApiServer(apiState, dashboardPort);\n debugBoot(\"main:api-server-early-start\");\n\n if (devMode) {\n const devPort = dashboardPort + 1;\n await startDevFrontend(dashboardPort, devPort);\n }\n }\n\n // ── Phase C: Parallel state loading ─────────────────────────────────────────\n debugBoot(\"main:phase-c-start\");\n logger.debug(\"[Boot] Loading persisted state, settings, and recovering sessions\");\n const [previous, persistedSettings] = await Promise.all([\n loadPersistedState(),\n loadRuntimeSettings(),\n persistDetectedProvidersSetting(detectedProviders),\n recoverPlanningSession(),\n ]);\n logger.info({ hadPreviousState: previous !== null, issueCount: previous?.issues?.length ?? 0, settingsCount: persistedSettings.length }, \"[Boot] State loaded from persistence\");\n debugBoot(\"main:state-loaded\");\n\n config = applyPersistedSettings(config, persistedSettings);\n await syncRuntimeConfigSettings(config, persistedSettings);\n const projectMetadata = resolveProjectMetadata(persistedSettings, TARGET_ROOT);\n const state = buildRuntimeState(previous, config, projectMetadata);\n debugBoot(\"main:state-merged\");\n\n state.config.dashboardPort = dashboardPort ? String(dashboardPort) : undefined;\n state.updatedAt = now();\n state.booting = false;\n\n // Reconcile in-memory state with FSM persisted state (source of truth)\n try {\n const { getIssueStateMachinePlugin, ISSUE_STATE_MACHINE_ID } = await import(\"./persistence/plugins/issue-state-machine.ts\");\n const fsmPlugin = getIssueStateMachinePlugin();\n if (fsmPlugin?.getState) {\n for (const issue of state.issues) {\n try {\n const fsmState = await fsmPlugin.getState(ISSUE_STATE_MACHINE_ID, issue.id);\n if (fsmState && fsmState !== issue.state) {\n logger.warn({ issueId: issue.id, memoryState: issue.state, fsmState }, \"[Boot] Reconciling desync — FSM is source of truth\");\n issue.state = fsmState as typeof issue.state;\n }\n } catch { /* FSM entity may not exist yet */ }\n }\n }\n } catch { /* FSM plugin may not be ready */ }\n\n // Detect and lock the default branch once at startup\n if (!state.config.defaultBranch) {\n try {\n const detectedBranch = detectDefaultBranch(TARGET_ROOT);\n state.config.defaultBranch = detectedBranch;\n logger.info({ defaultBranch: detectedBranch }, \"[Agent] Default branch detected\");\n } catch {\n // Not a git repo or detection failed — leave undefined\n }\n }\n\n if (state.config.agentCommand) {\n state.notes.push(`Using agent command: ${state.config.agentCommand}`);\n }\n state.notes.push(`Agent session max turns: ${state.config.maxTurns}`);\n state.notes.push(`Agent provider: ${state.config.agentProvider}`);\n state.notes.push(`Interface mode: ${interfaceMode}`);\n\n if (!state.config.agentCommand.trim()) {\n const available = detectedProviders.filter((p) => p.available).map((p) => p.name);\n fail(\n available.length === 0\n ? \"No agent command configured and no providers (claude, codex) found in PATH.\\nInstall claude or codex, or set FIFONY_AGENT_COMMAND.\"\n : \"No agent command configured. Set FIFONY_AGENT_COMMAND.\",\n );\n }\n\n // Validate config at startup (spec §6.3)\n const configErrors = validateConfig(config);\n if (configErrors.length > 0) {\n for (const err of configErrors) logger.warn(`Config validation: ${err}`);\n }\n\n // Clean terminal workspaces in background (non-blocking boot)\n const terminalIssues = state.issues.filter((i) => i.state === \"Done\" || i.state === \"Cancelled\");\n if (terminalIssues.length > 0) {\n logger.info(`Scheduling cleanup of ${terminalIssues.length} terminal workspace(s) in background...`);\n setImmediate(async () => {\n for (const issue of terminalIssues) {\n try { await cleanWorkspace(issue.id, issue, state); } catch {}\n }\n logger.info(\"Background workspace cleanup complete.\");\n });\n }\n\n // Recover orphaned agent processes from previous session\n if (!skipRecovery) {\n logger.debug({ issueCount: state.issues.filter((i) => i.state === \"Running\" || i.state === \"Queued\").length }, \"[Boot] Checking for orphaned agent processes\");\n for (const issue of state.issues) {\n if (issue.state === \"Running\" || issue.state === \"Queued\") {\n const { alive, pid } = isAgentStillRunning(issue);\n if (alive && pid) {\n logger.info(`Agent for ${issue.identifier} still alive (PID ${pid.pid}), keeping state as Running.`);\n if (issue.state !== \"Running\") {\n try { await executeTransition(issue, \"RUN\", { issue, note: `Orphaned agent detected (PID ${pid.pid}), still alive — tracking resumed.` }); }\n catch { issue.state = \"Running\"; }\n }\n addEvent(state, issue.id, \"info\", `Orphaned agent detected (PID ${pid.pid}), still alive — tracking resumed.`);\n } else {\n // Agent died — clean PID file, mark as Queued for resumption\n if (issue.workspacePath) cleanStalePidFile(issue.workspacePath);\n if (issue.state === \"Running\") {\n try { await executeTransition(issue, \"REQUEUE\", { issue, note: `Agent process not found on boot — marked Queued.` }); }\n catch { issue.state = \"Queued\"; }\n addEvent(state, issue.id, \"info\", `Agent for ${issue.identifier} not found, marked Queued.`);\n }\n }\n }\n }\n }\n\n state.metrics = computeMetrics(state.issues);\n\n // Swap state into API server IMMEDIATELY so the dashboard shows real data\n if (dashboardPort) {\n Object.assign(apiState, state);\n debugBoot(\"main:api-state-swapped\");\n }\n createContainer(apiState);\n logger.info(\"[Boot] DI container initialized with full state\");\n\n await persistStateFull(state);\n\n // Initialize queue workers (can be slow — dashboard already has real data)\n try {\n await initQueueWorkers(state);\n } catch (error) {\n logger.warn({ err: error }, \"[Boot] Queue workers failed to initialize — continuing without queue-based dispatch\");\n }\n\n const running = new Set<string>();\n installGracefulShutdown(state, running);\n\n logger.info(\"[Boot] Runtime ready\");\n hydrateTokenLedger(state.issues);\n logger.info(`Loaded issues: ${state.issues.length}`);\n logger.info(`Worker concurrency: ${state.config.workerConcurrency}`);\n logger.info(`Max attempts: ${state.config.maxAttemptsDefault}`);\n logger.info(`Max turns: ${state.config.maxTurns}`);\n logger.info(`Agent provider: ${state.config.agentProvider}`);\n logger.info(`Interface mode: ${interfaceMode}`);\n\n try {\n addEvent(state, undefined, \"info\", `Runtime started in local-only mode (filesystem tracker).`);\n const runForever = !runOnce && (Boolean(dashboardPort) || interfaceMode === \"mcp\");\n logger.info({ runForever, runOnce, dashboardPort, interfaceMode }, \"[Boot] Entering queue supervisor loop\");\n\n // Boot recovery: enqueue all in-progress issues so queue workers pick them up\n for (const issue of state.issues) {\n try {\n if (issue.state === \"Planning\" && issue.planningStatus !== \"planning\") {\n await enqueueForPlanning(issue);\n } else if (issue.state === \"Queued\" || issue.state === \"Running\") {\n await enqueueForExecution(issue);\n } else if (issue.state === \"Reviewing\") {\n await enqueueForReview(issue);\n }\n } catch (err) {\n logger.error({ err, issueId: issue.id, state: issue.state }, \"[Boot] Failed to enqueue issue for recovery\");\n }\n }\n\n const PERSIST_DEBOUNCE_MS = 5_000;\n let lastPersistAt = 0;\n\n if (runForever) {\n while (!isShuttingDown()) {\n // Take a snapshot of states before stale recovery so we can detect transitions\n const statesBefore = new Map(state.issues.map((i) => [i.id, i.state]));\n await ensureNotStale(state, state.config.staleInProgressTimeoutMs);\n\n // Re-enqueue any issues that just changed state due to stale recovery or retry eligibility\n for (const issue of state.issues) {\n const prev = statesBefore.get(issue.id);\n if (prev !== issue.state) {\n if (issue.state === \"Queued\") enqueueForExecution(issue).catch(() => {});\n else if (issue.state === \"Reviewing\") enqueueForReview(issue).catch(() => {});\n else if (issue.state === \"Planning\") enqueueForPlanning(issue).catch(() => {});\n }\n }\n\n state.updatedAt = now();\n if (hasDirtyState() || Date.now() - lastPersistAt > PERSIST_DEBOUNCE_MS) {\n await persistState(state);\n lastPersistAt = Date.now();\n }\n await sleep(1_000);\n }\n } else {\n // Batch mode: wait until all issues reach terminal states\n while (!hasTerminalQueue(state)) {\n await sleep(state.config.pollIntervalMs);\n }\n }\n } catch (error) {\n console.error(\"FATAL STACK TRACE:\", error);\n addEvent(state, undefined, \"error\", `Fatal runtime error: ${String(error)}`);\n await persistState(state);\n throw error;\n } finally {\n state.updatedAt = now();\n state.metrics = computeMetrics(state.issues);\n await persistStateFull(state);\n try { await stopQueueWorkers(); } catch {}\n await closeStateStore();\n }\n}\n\nmain().catch((error) => {\n logger.error({ err: error }, `Fatal runtime error: ${String(error)}`);\n exit(1);\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/boot.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { mkdirSync } from \"node:fs\";\nimport { env, exit, argv } from \"node:process\";\nimport { CLI_ARGS, PACKAGE_ROOT, STATE_ROOT, TARGET_ROOT } from \"./concerns/constants.ts\";\nimport { debugBoot, fail, now, sleep, parseIntArg } from \"./concerns/helpers.ts\";\nimport { initLogger, logger } from \"./concerns/logger.ts\";\nimport { initStateStore, loadPersistedState, persistState, persistStateFull, closeStateStore } from \"./persistence/store.ts\";\nimport { initQueueWorkers, stopQueueWorkers, enqueueForPlanning, enqueueForExecution, enqueueForReview } from \"./persistence/plugins/queue-workers.ts\";\nimport { createContainer } from \"./persistence/container.ts\";\nimport {\n applyPersistedSettings,\n loadRuntimeSettings,\n persistDetectedProvidersSetting,\n syncRuntimeConfigSettings,\n} from \"./persistence/settings.ts\";\nimport { buildQueueTitle, detectProjectName, resolveProjectMetadata } from \"./domains/project.ts\";\nimport {\n detectAvailableProviders,\n resolveDefaultProvider,\n getProviderDefaultCommand,\n} from \"./agents/providers.ts\";\nimport { setSkipSource, detectDefaultBranch } from \"./domains/workspace.ts\";\nimport { deriveConfig, applyWorkflowConfig, buildRuntimeState, computeMetrics, addEvent, validateConfig } from \"./domains/issues.ts\";\nimport { hasDirtyState } from \"./persistence/dirty-tracker.ts\";\nimport { executeTransition } from \"./persistence/plugins/issue-state-machine.ts\";\nimport { startApiServer } from \"./persistence/plugins/api-server.ts\";\nimport { installGracefulShutdown, isShuttingDown, ensureNotStale, hasTerminalQueue } from \"./persistence/plugins/scheduler.ts\";\nimport { cleanWorkspace, isAgentStillRunning, cleanStalePidFile } from \"./agents/agent.ts\";\nimport { recoverPlanningSession } from \"./agents/planning/issue-planner.ts\";\nimport { hydrate as hydrateTokenLedger } from \"./domains/tokens.ts\";\nimport { resolve } from \"node:path\";\nimport type { RuntimeState } from \"./types.ts\";\n\nfunction parsePort(args: string[]): number | undefined {\n for (let i = 0; i < args.length; i += 1) {\n const arg = args[i];\n if (arg === \"--port\") {\n const value = args[i + 1];\n if (!value || !/^\\d+$/.test(value)) {\n fail(`Invalid value for --port: ${value ?? \"<empty>\"}`);\n }\n return parseIntArg(value, 4040);\n }\n }\n return undefined;\n}\n\nasync function startDevFrontend(apiPort: number, devPort: number): Promise<void> {\n const VITE_CONFIG_PATH = resolve(PACKAGE_ROOT, \"app/vite.config.js\");\n let createViteServer: typeof import(\"vite\").createServer;\n try {\n const vite = await import(\"vite\");\n createViteServer = vite.createServer;\n } catch {\n logger.warn(\"Vite not installed (devDependency). Run 'pnpm install' in the project to enable --dev mode.\");\n return;\n }\n // Wait for the API server to be ready before starting the proxy\n for (let attempt = 0; attempt < 20; attempt++) {\n try {\n const res = await fetch(`http://localhost:${apiPort}/api/health`);\n if (res.ok) break;\n } catch {\n await new Promise((r) => setTimeout(r, 250));\n }\n }\n\n try {\n const server = await createViteServer({\n configFile: VITE_CONFIG_PATH,\n customLogger: {\n info: (msg: string) => logger.info(`[Vite] ${msg}`),\n warn: (msg: string) => logger.warn(`[Vite] ${msg}`),\n warnOnce: (msg: string) => logger.warn(`[Vite] ${msg}`),\n error: (msg: string) => {\n if (msg.includes(\"ws proxy error\") || msg.includes(\"ws proxy socket error\")) {\n logger.debug(`[Vite] ${msg.split(\"\\n\")[0]} (transient, suppressed)`);\n return;\n }\n logger.error(`[Vite] ${msg}`);\n },\n hasErrorLogged: () => false,\n clearScreen: () => {},\n hasWarned: false,\n },\n server: {\n port: devPort,\n host: true,\n proxy: {\n \"/api\": `http://localhost:${apiPort}`,\n \"/ws\": {\n target: `ws://localhost:${apiPort}`,\n ws: true,\n configure: (proxy) => {\n const silence = (err: any) => {\n logger.debug(`[Vite] WS proxy transient: ${err.code || err.message}`);\n };\n proxy.on(\"error\", silence);\n proxy.on(\"proxyReqWs\", (_proxyReq: any, _req: any, socket: any) => {\n socket.on(\"error\", silence);\n });\n },\n },\n \"/docs\": `http://localhost:${apiPort}`,\n \"/health\": `http://localhost:${apiPort}`,\n \"/manifest.webmanifest\": `http://localhost:${apiPort}`,\n \"/service-worker.js\": `http://localhost:${apiPort}`,\n \"/icon.svg\": `http://localhost:${apiPort}`,\n \"/icon-maskable.svg\": `http://localhost:${apiPort}`,\n \"/offline.html\": `http://localhost:${apiPort}`,\n },\n },\n });\n await server.listen();\n logger.info(`Dev frontend available at http://localhost:${devPort}`);\n } catch (error) {\n logger.warn(`Failed to start Vite dev server: ${String(error)}`);\n }\n}\n\nfunction usage() {\n console.log(\n `Usage: ${argv[1]} [options]\\n` +\n \"Options:\\n\" +\n \" --workspace <path> Target workspace root (default: current directory)\\n\" +\n \" --persistence <path> Persistence root (default: current directory)\\n\" +\n \" --port <n> Start local dashboard\\n\" +\n \" --concurrency <n> Maximum number of local workers\\n\" +\n \" --attempts <n> Maximum attempts per issue\\n\" +\n \" --poll <ms> Scheduler interval in ms\\n\" +\n \" --timeout <ms> Agent command timeout in ms (default: 1800000)\\n\" +\n \" --dev Start Vite dev server alongside API (HMR on port+1)\\n\" +\n \" --once Process once and exit\\n\" +\n \" --skip-source Skip source snapshot copy\\n\" +\n \" --skip-scan Skip project analysis\\n\" +\n \" --skip-recovery Skip orphaned agent recovery\\n\" +\n \" --fast-boot Equivalent to --skip-source --skip-scan --skip-recovery\\n\",\n );\n}\n\nasync function main() {\n debugBoot(\"main:start\");\n\n const args = CLI_ARGS;\n if (args.includes(\"--help\") || args.includes(\"-h\")) {\n usage();\n return;\n }\n\n mkdirSync(STATE_ROOT, { recursive: true });\n initLogger(STATE_ROOT);\n logger.info(\"[Boot] Fifony runtime starting\");\n logger.info({ stateRoot: STATE_ROOT, cwd: process.cwd() }, \"[Boot] State root initialized\");\n\n // Detect available providers\n const detectedProviders = detectAvailableProviders();\n for (const p of detectedProviders) {\n logger.info(`Provider ${p.name}: ${p.available ? `available at ${p.path}` : \"not found\"}`);\n }\n\n const interfaceMode = (env.FIFONY_INTERFACE ?? \"cli\").trim().toLowerCase();\n const runOnce = args.includes(\"--once\");\n const devMode = args.includes(\"--dev\") || env.NODE_ENV === \"development\";\n const fastBoot = args.includes(\"--fast-boot\");\n const skipSource = fastBoot || args.includes(\"--skip-source\");\n if (skipSource) setSkipSource(true);\n\n debugBoot(\"main:state-root-ready\");\n\n const port = parsePort(args);\n let config = applyWorkflowConfig(deriveConfig(args), port);\n\n // Auto-resolve provider command if not configured\n if (!config.agentCommand.trim()) {\n const defaultProvider = resolveDefaultProvider(detectedProviders);\n if (defaultProvider) {\n const defaultCommand = getProviderDefaultCommand(defaultProvider);\n if (defaultCommand) {\n config = { ...config, agentProvider: defaultProvider, agentCommand: defaultCommand };\n logger.info(`Auto-detected provider: ${defaultProvider} → ${defaultCommand}`);\n }\n }\n }\n\n const dashboardPort = port ?? (config.dashboardPort ? Number.parseInt(config.dashboardPort, 10) : undefined);\n const skipRecovery = args.includes(\"--skip-recovery\") || args.includes(\"--fast-boot\");\n const detectedProjectName = detectProjectName(TARGET_ROOT);\n\n // ── Phase B: Parallel initialization ────────────────────────────────────────\n debugBoot(\"main:phase-b-start\");\n logger.debug(\"[Boot] Initializing state store (s3db)\");\n await initStateStore();\n logger.info(\"[Boot] State store initialized\");\n debugBoot(\"main:store-initialized\");\n\n // ── Early API start: dashboard available while boot continues ─────────────\n // Build a minimal placeholder state for the early API server\n const earlyState: RuntimeState = {\n projectName: detectedProjectName,\n detectedProjectName,\n projectNameSource: detectedProjectName ? \"detected\" : \"missing\",\n queueTitle: buildQueueTitle(detectedProjectName),\n startedAt: now(),\n updatedAt: now(),\n trackerKind: \"filesystem\",\n sourceRepoUrl: TARGET_ROOT,\n sourceRef: \"workspace\",\n config,\n issues: [],\n events: [],\n metrics: { total: 0, planning: 0, queued: 0, inProgress: 0, blocked: 0, done: 0, merged: 0, cancelled: 0, activeWorkers: 0 },\n notes: [],\n booting: true,\n };\n\n let apiState = earlyState;\n // Initialize container early so API routes can use commands immediately\n createContainer(apiState);\n debugBoot(\"main:container-early-init\");\n\n if (dashboardPort) {\n await startApiServer(apiState, dashboardPort);\n debugBoot(\"main:api-server-early-start\");\n\n if (devMode) {\n const devPort = dashboardPort + 1;\n await startDevFrontend(dashboardPort, devPort);\n }\n }\n\n // ── Phase C: Parallel state loading ─────────────────────────────────────────\n debugBoot(\"main:phase-c-start\");\n logger.debug(\"[Boot] Loading persisted state, settings, and recovering sessions\");\n const [previous, persistedSettings] = await Promise.all([\n loadPersistedState(),\n loadRuntimeSettings(),\n persistDetectedProvidersSetting(detectedProviders),\n recoverPlanningSession(),\n ]);\n logger.info({ hadPreviousState: previous !== null, issueCount: previous?.issues?.length ?? 0, settingsCount: persistedSettings.length }, \"[Boot] State loaded from persistence\");\n debugBoot(\"main:state-loaded\");\n\n config = applyPersistedSettings(config, persistedSettings);\n await syncRuntimeConfigSettings(config, persistedSettings);\n const projectMetadata = resolveProjectMetadata(persistedSettings, TARGET_ROOT);\n const state = buildRuntimeState(previous, config, projectMetadata);\n debugBoot(\"main:state-merged\");\n\n state.config.dashboardPort = dashboardPort ? String(dashboardPort) : undefined;\n state.updatedAt = now();\n state.booting = false;\n\n // Reconcile in-memory state with FSM persisted state (source of truth)\n try {\n const { getIssueStateMachinePlugin, ISSUE_STATE_MACHINE_ID } = await import(\"./persistence/plugins/issue-state-machine.ts\");\n const fsmPlugin = getIssueStateMachinePlugin();\n if (fsmPlugin?.getState) {\n for (const issue of state.issues) {\n try {\n const fsmState = await fsmPlugin.getState(ISSUE_STATE_MACHINE_ID, issue.id);\n if (fsmState && fsmState !== issue.state) {\n logger.warn({ issueId: issue.id, memoryState: issue.state, fsmState }, \"[Boot] Reconciling desync — FSM is source of truth\");\n issue.state = fsmState as typeof issue.state;\n }\n } catch { /* FSM entity may not exist yet */ }\n }\n }\n } catch { /* FSM plugin may not be ready */ }\n\n // Detect and lock the default branch once at startup\n if (!state.config.defaultBranch) {\n try {\n const detectedBranch = detectDefaultBranch(TARGET_ROOT);\n state.config.defaultBranch = detectedBranch;\n logger.info({ defaultBranch: detectedBranch }, \"[Agent] Default branch detected\");\n } catch {\n // Not a git repo or detection failed — leave undefined\n }\n }\n\n if (state.config.agentCommand) {\n state.notes.push(`Using agent command: ${state.config.agentCommand}`);\n }\n state.notes.push(`Agent session max turns: ${state.config.maxTurns}`);\n state.notes.push(`Agent provider: ${state.config.agentProvider}`);\n state.notes.push(`Interface mode: ${interfaceMode}`);\n\n if (!state.config.agentCommand.trim()) {\n const available = detectedProviders.filter((p) => p.available).map((p) => p.name);\n fail(\n available.length === 0\n ? \"No agent command configured and no providers (claude, codex) found in PATH.\\nInstall claude or codex, or set FIFONY_AGENT_COMMAND.\"\n : \"No agent command configured. Set FIFONY_AGENT_COMMAND.\",\n );\n }\n\n // Validate config at startup (spec §6.3)\n const configErrors = validateConfig(config);\n if (configErrors.length > 0) {\n for (const err of configErrors) logger.warn(`Config validation: ${err}`);\n }\n\n // Clean terminal workspaces in background (non-blocking boot)\n const terminalIssues = state.issues.filter((i) => i.state === \"Merged\" || i.state === \"Cancelled\");\n if (terminalIssues.length > 0) {\n logger.info(`Scheduling cleanup of ${terminalIssues.length} terminal workspace(s) in background...`);\n setImmediate(async () => {\n for (const issue of terminalIssues) {\n try { await cleanWorkspace(issue.id, issue, state); } catch {}\n }\n logger.info(\"Background workspace cleanup complete.\");\n });\n }\n\n // Recover orphaned agent processes from previous session\n if (!skipRecovery) {\n logger.debug({ issueCount: state.issues.filter((i) => i.state === \"Running\" || i.state === \"Queued\").length }, \"[Boot] Checking for orphaned agent processes\");\n for (const issue of state.issues) {\n if (issue.state === \"Running\" || issue.state === \"Queued\") {\n const { alive, pid } = isAgentStillRunning(issue);\n if (alive && pid) {\n logger.info(`Agent for ${issue.identifier} still alive (PID ${pid.pid}), keeping state as Running.`);\n if (issue.state !== \"Running\") {\n try { await executeTransition(issue, \"RUN\", { issue, note: `Orphaned agent detected (PID ${pid.pid}), still alive — tracking resumed.` }); }\n catch { issue.state = \"Running\"; }\n }\n addEvent(state, issue.id, \"info\", `Orphaned agent detected (PID ${pid.pid}), still alive — tracking resumed.`);\n } else {\n // Agent died — clean PID file, mark as Queued for resumption\n if (issue.workspacePath) cleanStalePidFile(issue.workspacePath);\n if (issue.state === \"Running\") {\n try { await executeTransition(issue, \"REQUEUE\", { issue, note: `Agent process not found on boot — marked Queued.` }); }\n catch { issue.state = \"Queued\"; }\n addEvent(state, issue.id, \"info\", `Agent for ${issue.identifier} not found, marked Queued.`);\n }\n }\n }\n }\n }\n\n state.metrics = computeMetrics(state.issues);\n\n // Swap state into API server IMMEDIATELY so the dashboard shows real data\n if (dashboardPort) {\n Object.assign(apiState, state);\n debugBoot(\"main:api-state-swapped\");\n }\n createContainer(apiState);\n logger.info(\"[Boot] DI container initialized with full state\");\n\n await persistStateFull(state);\n\n // Initialize queue workers (can be slow — dashboard already has real data)\n try {\n await initQueueWorkers(state);\n } catch (error) {\n logger.warn({ err: error }, \"[Boot] Queue workers failed to initialize — continuing without queue-based dispatch\");\n }\n\n const running = new Set<string>();\n installGracefulShutdown(state, running);\n\n logger.info(\"[Boot] Runtime ready\");\n hydrateTokenLedger(state.issues);\n logger.info(`Loaded issues: ${state.issues.length}`);\n logger.info(`Worker concurrency: ${state.config.workerConcurrency}`);\n logger.info(`Max attempts: ${state.config.maxAttemptsDefault}`);\n logger.info(`Max turns: ${state.config.maxTurns}`);\n logger.info(`Agent provider: ${state.config.agentProvider}`);\n logger.info(`Interface mode: ${interfaceMode}`);\n\n try {\n addEvent(state, undefined, \"info\", `Runtime started in local-only mode (filesystem tracker).`);\n const runForever = !runOnce && (Boolean(dashboardPort) || interfaceMode === \"mcp\");\n logger.info({ runForever, runOnce, dashboardPort, interfaceMode }, \"[Boot] Entering queue supervisor loop\");\n\n // Boot recovery: enqueue all in-progress issues so queue workers pick them up\n for (const issue of state.issues) {\n try {\n if (issue.state === \"Planning\" && issue.planningStatus !== \"planning\") {\n await enqueueForPlanning(issue);\n } else if (issue.state === \"Queued\" || issue.state === \"Running\") {\n await enqueueForExecution(issue);\n } else if (issue.state === \"Reviewing\") {\n await enqueueForReview(issue);\n }\n } catch (err) {\n logger.error({ err, issueId: issue.id, state: issue.state }, \"[Boot] Failed to enqueue issue for recovery\");\n }\n }\n\n const PERSIST_DEBOUNCE_MS = 5_000;\n let lastPersistAt = 0;\n\n if (runForever) {\n while (!isShuttingDown()) {\n // Take a snapshot of states before stale recovery so we can detect transitions\n const statesBefore = new Map(state.issues.map((i) => [i.id, i.state]));\n await ensureNotStale(state, state.config.staleInProgressTimeoutMs);\n\n // Re-enqueue any issues that just changed state due to stale recovery or retry eligibility\n for (const issue of state.issues) {\n const prev = statesBefore.get(issue.id);\n if (prev !== issue.state) {\n if (issue.state === \"Queued\") enqueueForExecution(issue).catch(() => {});\n else if (issue.state === \"Reviewing\") enqueueForReview(issue).catch(() => {});\n else if (issue.state === \"Planning\") enqueueForPlanning(issue).catch(() => {});\n }\n }\n\n state.updatedAt = now();\n if (hasDirtyState() || Date.now() - lastPersistAt > PERSIST_DEBOUNCE_MS) {\n await persistState(state);\n lastPersistAt = Date.now();\n }\n await sleep(1_000);\n }\n } else {\n // Batch mode: wait until all issues reach terminal states\n while (!hasTerminalQueue(state)) {\n await sleep(state.config.pollIntervalMs);\n }\n }\n } catch (error) {\n console.error(\"FATAL STACK TRACE:\", error);\n addEvent(state, undefined, \"error\", `Fatal runtime error: ${String(error)}`);\n await persistState(state);\n throw error;\n } finally {\n state.updatedAt = now();\n state.metrics = computeMetrics(state.issues);\n await persistStateFull(state);\n try { await stopQueueWorkers(); } catch {}\n await closeStateStore();\n }\n}\n\nmain().catch((error) => {\n logger.error({ err: error }, `Fatal runtime error: ${String(error)}`);\n exit(1);\n});\n"],"mappings":"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","names":[]}
@@ -34,7 +34,7 @@ async function enqueueForPlanning(issue) {
34
34
  }
35
35
  logger.info({ issueId: issue.id, identifier: current.identifier }, "[QueueWorkers:plan] Dispatching planning job");
36
36
  try {
37
- const { runPlanningJob } = await import("./issue-runner-6VFNHYJL.js");
37
+ const { runPlanningJob } = await import("./issue-runner-QSUROSNX.js");
38
38
  await runPlanningJob(runtimeState, current);
39
39
  } catch (error) {
40
40
  logger.error({ err: error, issueId: issue.id }, "[QueueWorkers:plan] Planning job failed");
@@ -43,7 +43,7 @@ async function enqueueForPlanning(issue) {
43
43
  async function enqueueForExecution(issue) {
44
44
  if (!active || !runtimeState) return;
45
45
  const running = /* @__PURE__ */ new Set();
46
- const { runIssueOnce } = await import("./issue-runner-6VFNHYJL.js");
46
+ const { runIssueOnce } = await import("./issue-runner-QSUROSNX.js");
47
47
  while (active && runtimeState) {
48
48
  const current = getCurrentIssue(issue.id);
49
49
  if (!current || current.state !== "Queued" && current.state !== "Running") {
@@ -69,7 +69,7 @@ async function enqueueForReview(issue) {
69
69
  logger.info({ issueId: issue.id, identifier: current.identifier }, "[QueueWorkers:review] Dispatching review job");
70
70
  const running = /* @__PURE__ */ new Set();
71
71
  try {
72
- const { runIssueOnce } = await import("./issue-runner-6VFNHYJL.js");
72
+ const { runIssueOnce } = await import("./issue-runner-QSUROSNX.js");
73
73
  await runIssueOnce(runtimeState, current, running);
74
74
  } catch (error) {
75
75
  logger.error({ err: error, issueId: issue.id }, "[QueueWorkers:review] Review job failed");
@@ -88,4 +88,4 @@ export {
88
88
  enqueueForReview,
89
89
  getQueueStats
90
90
  };
91
- //# sourceMappingURL=chunk-NLIVWBNV.js.map
91
+ //# sourceMappingURL=chunk-D6WNSDQ5.js.map
@@ -3,7 +3,7 @@ import {
3
3
  enqueueForExecution,
4
4
  enqueueForPlanning,
5
5
  enqueueForReview
6
- } from "./chunk-NLIVWBNV.js";
6
+ } from "./chunk-D6WNSDQ5.js";
7
7
  import {
8
8
  ADAPTERS,
9
9
  ISSUE_STATE_MACHINE_ID,
@@ -53,10 +53,11 @@ import {
53
53
  snapshotAndClearDirtyEventIds,
54
54
  snapshotAndClearDirtyIssueIds,
55
55
  snapshotAndClearDirtyIssuePlanIds
56
- } from "./chunk-G6CQK2WH.js";
56
+ } from "./chunk-V6IHUFZB.js";
57
57
  import {
58
58
  ALLOWED_STATES,
59
59
  ATTACHMENTS_ROOT,
60
+ COMPLETED_STATES,
60
61
  EXECUTING_STATES,
61
62
  FRONTEND_DIR,
62
63
  FRONTEND_ICON_SVG,
@@ -102,7 +103,7 @@ import {
102
103
  toStringArray,
103
104
  toStringValue,
104
105
  withRetryBackoff
105
- } from "./chunk-DD5BE2W6.js";
106
+ } from "./chunk-RINIJIFO.js";
106
107
  import {
107
108
  logger
108
109
  } from "./chunk-DVU3CXWA.js";
@@ -2004,7 +2005,7 @@ async function ensureNotStale(state, staleTimeoutMs) {
2004
2005
  }
2005
2006
  }
2006
2007
  function hasTerminalQueue(state) {
2007
- return state.issues.every((issue) => TERMINAL_STATES.has(issue.state) || issue.attempts >= issue.maxAttempts);
2008
+ return state.issues.every((issue) => COMPLETED_STATES.has(issue.state) || issue.attempts >= issue.maxAttempts);
2008
2009
  }
2009
2010
 
2010
2011
  // src/agents/providers-usage.ts
@@ -2471,7 +2472,6 @@ async function mergeWorkspaceCommand(input, deps) {
2471
2472
  { issue, target: "Done", note: "Approved and merged by user." },
2472
2473
  deps
2473
2474
  );
2474
- deps.eventStore.addEvent(issue.id, "state", `${issue.identifier} approved \u2014 moved to Done before merge.`);
2475
2475
  }
2476
2476
  const wp = issue.worktreePath ?? issue.workspacePath;
2477
2477
  if (!wp || !existsSync6(wp)) {
@@ -2485,30 +2485,9 @@ async function mergeWorkspaceCommand(input, deps) {
2485
2485
  );
2486
2486
  parseDiffStats(issue, stat);
2487
2487
  logger.info({ issueId: issue.id, linesAdded: issue.linesAdded, linesRemoved: issue.linesRemoved, filesChanged: issue.filesChanged }, "[Merge] Diff stats computed");
2488
- const { getIssueStateResource: getIssueStateResource2 } = await import("./store-FH7L6KR2.js");
2489
- const issueResource = getIssueStateResource2();
2490
- if (issueResource) {
2491
- await issueResource.patch(issue.id, {
2492
- linesAdded: issue.linesAdded || 0,
2493
- linesRemoved: issue.linesRemoved || 0,
2494
- filesChanged: issue.filesChanged || 0,
2495
- branchName: issue.branchName
2496
- });
2497
- const add = issueResource.add;
2498
- if (typeof add === "function") {
2499
- if (issue.linesAdded) await add.call(issueResource, issue.id, "linesAdded", issue.linesAdded);
2500
- if (issue.linesRemoved) await add.call(issueResource, issue.id, "linesRemoved", issue.linesRemoved);
2501
- if (issue.filesChanged) await add.call(issueResource, issue.id, "filesChanged", issue.filesChanged);
2502
- logger.info({ issueId: issue.id, linesAdded: issue.linesAdded, linesRemoved: issue.linesRemoved, filesChanged: issue.filesChanged }, "[Merge] EC add() sent for diff stats");
2503
- } else {
2504
- logger.debug({ issueId: issue.id }, "[Merge] resource.add not available \u2014 EC plugin may not be installed");
2505
- }
2506
- }
2507
2488
  } catch (err) {
2508
- logger.warn({ err: String(err), issueId: issue.id, branchName: issue.branchName, baseBranch: issue.baseBranch }, "[Merge] Failed to compute/sync diff stats");
2489
+ logger.warn({ err: String(err), issueId: issue.id }, "[Merge] Failed to compute diff stats");
2509
2490
  }
2510
- } else {
2511
- logger.warn({ issueId: issue.id, branchName: issue.branchName, baseBranch: issue.baseBranch }, "[Merge] Missing branchName or baseBranch \u2014 cannot compute diff stats");
2512
2491
  }
2513
2492
  try {
2514
2493
  const indexStatus = execSync("git diff --cached --name-only", { cwd: TARGET_ROOT, encoding: "utf8", stdio: "pipe" }).trim();
@@ -2526,22 +2505,23 @@ async function mergeWorkspaceCommand(input, deps) {
2526
2505
  skipped: result.skipped.length,
2527
2506
  conflicts: result.conflicts.length
2528
2507
  };
2529
- if (result.conflicts.length === 0) {
2530
- issue.mergedAt = now();
2531
- if (!issue.mergedReason) issue.mergedReason = "Merged by user via PreviewModal.";
2532
- if (issue.workspacePath) {
2533
- try {
2534
- await cleanWorkspace(issue.id, issue, state);
2535
- issue.workspacePath = void 0;
2536
- issue.worktreePath = void 0;
2537
- } catch {
2538
- }
2539
- }
2540
- }
2541
- const conflictMsg = result.conflicts.length > 0 ? ` ${result.conflicts.length} conflict(s): ${result.conflicts.join(", ")}.` : "";
2542
- deps.eventStore.addEvent(issue.id, "merge", `Workspace merged: ${result.copied.length} file(s) copied, ${result.deleted.length} deleted.${conflictMsg}`);
2543
2508
  if (result.conflicts.length > 0) {
2544
2509
  deps.eventStore.addEvent(issue.id, "error", `Merge conflicts: ${result.conflicts.join(", ")}`);
2510
+ await deps.persistencePort.persistState(state);
2511
+ return result;
2512
+ }
2513
+ if (!issue.mergedReason) issue.mergedReason = "Merged by user via PreviewModal.";
2514
+ await transitionIssueCommand(
2515
+ { issue, target: "Merged", note: `Workspace merged: ${result.copied.length} file(s) copied, ${result.deleted.length} deleted.` },
2516
+ deps
2517
+ );
2518
+ if (issue.workspacePath) {
2519
+ try {
2520
+ await cleanWorkspace(issue.id, issue, state);
2521
+ issue.workspacePath = void 0;
2522
+ issue.worktreePath = void 0;
2523
+ } catch {
2524
+ }
2545
2525
  }
2546
2526
  await deps.persistencePort.persistState(state);
2547
2527
  return result;
@@ -2839,7 +2819,7 @@ function registerStateRoutes(app, state) {
2839
2819
  const issue = findIssue(state, issueId);
2840
2820
  if (!issue) return c.json({ ok: false, error: "Issue not found." }, 404);
2841
2821
  try {
2842
- const { getIssueTransitionHistory } = await import("./issue-state-machine-NSDN4MV4.js");
2822
+ const { getIssueTransitionHistory } = await import("./issue-state-machine-H4BWOONX.js");
2843
2823
  const limit = parseInt(c.req.query("limit") ?? "50", 10);
2844
2824
  const offset = parseInt(c.req.query("offset") ?? "0", 10);
2845
2825
  const transitions = await getIssueTransitionHistory(issue.id, { limit, offset });
@@ -2850,7 +2830,7 @@ function registerStateRoutes(app, state) {
2850
2830
  });
2851
2831
  app.get("/api/state-machine/transitions", async (c) => {
2852
2832
  try {
2853
- const { getStateMachineTransitions } = await import("./issue-state-machine-NSDN4MV4.js");
2833
+ const { getStateMachineTransitions } = await import("./issue-state-machine-H4BWOONX.js");
2854
2834
  return c.json({ ok: true, transitions: getStateMachineTransitions() });
2855
2835
  } catch (error) {
2856
2836
  return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 500);
@@ -2858,7 +2838,7 @@ function registerStateRoutes(app, state) {
2858
2838
  });
2859
2839
  app.get("/api/state-machine/visualize", async (c) => {
2860
2840
  try {
2861
- const { visualizeStateMachine } = await import("./issue-state-machine-NSDN4MV4.js");
2841
+ const { visualizeStateMachine } = await import("./issue-state-machine-H4BWOONX.js");
2862
2842
  const dot = visualizeStateMachine();
2863
2843
  if (!dot) return c.json({ ok: false, error: "Visualization not available." }, 404);
2864
2844
  return c.json({ ok: true, dot });
@@ -4342,7 +4322,7 @@ function registerAnalyticsRoutes(app) {
4342
4322
  try {
4343
4323
  const context2 = getApiRuntimeContextOrThrow();
4344
4324
  const doneIssues = context2.state.issues.filter(
4345
- (i) => i.state === "Done" && i.completedAt
4325
+ (i) => (i.state === "Done" || i.state === "Merged") && i.completedAt
4346
4326
  );
4347
4327
  const msToDay = (ms) => ms / (1e3 * 60 * 60 * 24);
4348
4328
  const avg = (arr) => arr.length ? arr.reduce((a, b) => a + b, 0) / arr.length : null;
@@ -5144,7 +5124,6 @@ async function startApiServer(state, port) {
5144
5124
  "GET /onboarding": () => serveAppShell(),
5145
5125
  "GET /kanban": () => serveAppShell(),
5146
5126
  "GET /issues": () => serveAppShell(),
5147
- "GET /discover": () => serveAppShell(),
5148
5127
  "GET /agents": () => serveAppShell(),
5149
5128
  "GET /settings": () => serveAppShell(),
5150
5129
  "GET /settings/general": () => serveAppShell(),
@@ -7007,7 +6986,7 @@ async function runIssueOnce(state, issue, running) {
7007
6986
  const { workspacePath, promptText, promptFile } = await prepareWorkspace(issue, state, state.config.defaultBranch);
7008
6987
  container.issueRepository.markDirty(issue.id);
7009
6988
  try {
7010
- const { getIssueStateResource: getIssueStateResource2 } = await import("./store-FH7L6KR2.js");
6989
+ const { getIssueStateResource: getIssueStateResource2 } = await import("./store-JFDHTPVH.js");
7011
6990
  const res = getIssueStateResource2();
7012
6991
  if (res) {
7013
6992
  await res.patch(issue.id, {
@@ -7099,4 +7078,4 @@ export {
7099
7078
  syncReferenceRepositories,
7100
7079
  importReferenceArtifacts
7101
7080
  };
7102
- //# sourceMappingURL=chunk-KT5V7N5H.js.map
7081
+ //# sourceMappingURL=chunk-HJFRXKDS.js.map