( options: GoalSetupServerOptions )
| 76 | } |
| 77 | |
| 78 | export async function startGoalSetupServer( |
| 79 | options: GoalSetupServerOptions |
| 80 | ): Promise<GoalSetupServerResult> { |
| 81 | const { bundle, htmlContent, origin = "claude-code", onReady } = options; |
| 82 | const isRemote = isRemoteSession(); |
| 83 | const configuredPort = getServerPort(); |
| 84 | const wslFlag = await isWSL(); |
| 85 | const repoInfo = await getRepoInfo(); |
| 86 | const gitUser = detectGitUser(); |
| 87 | |
| 88 | let settled = false; |
| 89 | let resolveDecision: (result: { |
| 90 | result?: GoalSetupResult; |
| 91 | exit?: boolean; |
| 92 | }) => void; |
| 93 | const decisionPromise = new Promise<{ |
| 94 | result?: GoalSetupResult; |
| 95 | exit?: boolean; |
| 96 | }>((resolve) => { |
| 97 | resolveDecision = resolve; |
| 98 | }); |
| 99 | |
| 100 | const resolveOnce = (result: { result?: GoalSetupResult; exit?: boolean }) => { |
| 101 | if (settled) return; |
| 102 | settled = true; |
| 103 | resolveDecision(result); |
| 104 | }; |
| 105 | |
| 106 | let server: ReturnType<typeof Bun.serve> | null = null; |
| 107 | |
| 108 | for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) { |
| 109 | try { |
| 110 | server = Bun.serve({ |
| 111 | hostname: getServerHostname(), |
| 112 | port: configuredPort, |
| 113 | // Bun's default 10s idleTimeout kills long-running requests. |
| 114 | idleTimeout: 0, |
| 115 | |
| 116 | async fetch(req) { |
| 117 | const url = new URL(req.url); |
| 118 | |
| 119 | if ( |
| 120 | (url.pathname === "/api/plan" || |
| 121 | url.pathname === "/api/goal-setup") && |
| 122 | req.method === "GET" |
| 123 | ) { |
| 124 | return Response.json({ |
| 125 | plan: "", |
| 126 | origin, |
| 127 | mode: "goal-setup", |
| 128 | goalSetup: bundle, |
| 129 | repoInfo, |
| 130 | projectRoot: process.cwd(), |
| 131 | isWSL: wslFlag, |
| 132 | serverConfig: getServerConfig(gitUser), |
| 133 | sharingEnabled: false, |
| 134 | }); |
| 135 | } |
no test coverage detected