Skip to content

Commit c75cb7a

Browse files
committed
feat(dev): make the ai-gateway app startable from dev:start
pnpm dev:start ai-gateway starts apps/ai-gateway in its own opt-in group on port 3010 plus the port offset, clear of the ports the web dev script probes. Selecting it also syncs apps/web/.env.development.local, which the app reads.
1 parent 77263f8 commit c75cb7a

4 files changed

Lines changed: 54 additions & 1 deletion

File tree

‎DEVELOPMENT.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ should pass against the local PostgreSQL database.
240240
|---|---|
241241
| `KILO_PORT_OFFSET=auto pnpm dev:start` | Start all local services in a tmux dashboard with worktree-safe ports |
242242
| `pnpm dev:start agents cloud-agent-public-tunnels` | Same as `dev:start agents`, plus Cloudflare quick tunnels for sandbox-facing Worker/Next/session-ingest URLs |
243+
| `pnpm dev:start ai-gateway` | Also start the standalone AI gateway app (`apps/ai-gateway`) on port 3010 plus the port offset |
243244
| `pnpm dev:stop` | Stop the tmux session and all services |
244245
| `pnpm dev:env` | Sync `.dev.vars` files from `.env.local` (see [Worker `.dev.vars` setup](#worker-dev-vars-setup)) |
245246
| `pnpm dev:env --missing-secrets-only` | Sync env files and create missing local Secrets Store entries without refreshing existing secrets |

‎dev/local/env-sync/plan.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -749,7 +749,9 @@ function computePlan(
749749

750750
// --- .env.development.local changes ---
751751
const envDevLocalChanges: EnvDevLocalChange[] = [];
752-
const processEnvDevLocal = !serviceFilter || serviceFilter.has('nextjs');
752+
// apps/ai-gateway runs with the web app's env files (see its scripts/dev.sh).
753+
const processEnvDevLocal =
754+
!serviceFilter || serviceFilter.has('nextjs') || serviceFilter.has('ai-gateway');
753755

754756
const envDevLocalExamplePath = path.join(repoRoot, 'apps/web/.env.development.local.example');
755757
if (processEnvDevLocal && fs.existsSync(envDevLocalExamplePath)) {

‎dev/local/services.test.ts‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,29 @@ test('keeps auto routing workers in their own opt-in group', () => {
199199
assert.ok(!alwaysOn.includes('auto-routing-benchmark'));
200200
});
201201

202+
test('keeps the AI gateway app in its own opt-in group', () => {
203+
const service = getService('ai-gateway');
204+
205+
assert.equal(service.group, 'ai-gateway');
206+
assert.equal(service.type, 'nextjs');
207+
assert.equal(service.dir, 'apps/ai-gateway');
208+
assert.equal(service.port, 3010 + portOffset);
209+
assert.deepEqual(service.command, [
210+
'env',
211+
`AI_GATEWAY_PORT=${3010 + portOffset}`,
212+
'pnpm',
213+
'run',
214+
'dev',
215+
]);
216+
assert.deepEqual(resolveTargets(['ai-gateway']), [
217+
'redis',
218+
'postgres',
219+
'redis-http',
220+
'ai-gateway',
221+
]);
222+
assert.ok(!resolveGroups(getAlwaysOnGroupIds()).includes('ai-gateway'));
223+
});
224+
202225
test('registers user data export with worktree-aware ports and dependencies', () => {
203226
const service = getService('user-data-export');
204227

‎dev/local/services.ts‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ const groups: ServiceGroup[] = [
6363
{ id: 'deploy', label: 'Deploy', alwaysOn: false },
6464
{ id: 'observability', label: 'Observability', alwaysOn: false },
6565
{ id: 'auto-routing', label: 'Auto Routing', alwaysOn: false, sectionBreakBefore: true },
66+
{ id: 'ai-gateway', label: 'AI Gateway', alwaysOn: false },
6667
{ id: 'mobile', label: 'Mobile', alwaysOn: false, sectionBreakBefore: true },
6768
{ id: 'storybook', label: 'Storybook', alwaysOn: false, sectionBreakBefore: true },
6869
{ id: 'deletion-mock', label: 'Deletion Mock', alwaysOn: false, sectionBreakBefore: true },
@@ -113,6 +114,13 @@ const serviceMeta: Record<string, ServiceMeta> = {
113114
dependsOn: ['postgres', 'nextjs'],
114115
dir: 'services/user-data-export',
115116
},
117+
// The standalone AI gateway app (apps/ai-gateway). It serves the gateway
118+
// routes the web app also serves, from the same database and Redis.
119+
'ai-gateway': {
120+
group: 'ai-gateway',
121+
dependsOn: ['postgres', 'redis', 'redis-http'],
122+
dir: 'apps/ai-gateway',
123+
},
116124
// auto-routing (kilo-auto/efficient decision engine + benchmark runner)
117125
'auto-routing': {
118126
group: 'auto-routing',
@@ -675,6 +683,8 @@ function workerEnvPrefix(): string[] {
675683
return vars.length > 0 ? ['env', ...vars] : [];
676684
}
677685

686+
const AI_GATEWAY_BASE_PORT = 3010;
687+
678688
function buildServiceDefs(): ServiceDef[] {
679689
const repoRoot = REPO_ROOT;
680690
const defs: ServiceDef[] = [];
@@ -695,6 +705,23 @@ function buildServiceDefs(): ServiceDef[] {
695705
continue;
696706
}
697707

708+
if (name === 'ai-gateway') {
709+
// Clear of the 3000-3009 range the web app's dev script probes. The port
710+
// is passed as AI_GATEWAY_PORT because the session exports PORT for the
711+
// web app.
712+
const port = AI_GATEWAY_BASE_PORT + portOffset;
713+
defs.push({
714+
name,
715+
type: 'nextjs',
716+
dir: meta.dir ?? name,
717+
port,
718+
dependsOn: meta.dependsOn,
719+
command: ['env', `AI_GATEWAY_PORT=${port}`, 'pnpm', 'run', 'dev'],
720+
group: meta.group,
721+
});
722+
continue;
723+
}
724+
698725
if (name === 'storybook') {
699726
defs.push({
700727
name,

0 commit comments

Comments
 (0)