Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ jobs:
node-version: 22
cache: npm
- run: npm ci
- run: npx nx run-many -t smoke --projects=cockpit-ag-ui-interrupts-python,cockpit-ag-ui-streaming-python,cockpit-deep-agents-planning-python,cockpit-deep-agents-filesystem-python,cockpit-deep-agents-subagents-python,cockpit-deep-agents-memory-python,cockpit-deep-agents-skills-python,cockpit-deep-agents-sandboxes-python,cockpit-langgraph-persistence-python,cockpit-langgraph-durable-execution-python,cockpit-langgraph-streaming-python,cockpit-langgraph-interrupts-python,cockpit-langgraph-memory-python,cockpit-langgraph-subgraphs-python,cockpit-langgraph-time-travel-python,cockpit-langgraph-deployment-runtime-python --skip-nx-cache
- run: npx nx run-many -t smoke --projects=cockpit-ag-ui-interrupts-python,cockpit-ag-ui-streaming-python,cockpit-deep-agents-planning-python,cockpit-deep-agents-filesystem-python,cockpit-deep-agents-subagents-python,cockpit-deep-agents-memory-python,cockpit-deep-agents-skills-python,cockpit-deep-agents-sandboxes-python,cockpit-langgraph-persistence-python,cockpit-langgraph-durable-execution-python,cockpit-langgraph-streaming-python,cockpit-langgraph-interrupts-python,cockpit-langgraph-memory-python,cockpit-langgraph-subgraphs-python,cockpit-langgraph-time-travel-python,cockpit-langgraph-deployment-runtime-python,cockpit-chat-messages-python,cockpit-render-spec-rendering-python --skip-nx-cache

cockpit-secret-integration:
name: Cockpit — secret-gated integration
Expand Down
58 changes: 41 additions & 17 deletions apps/cockpit/cockpit-e2e-wiring.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,6 @@ function parseStringProperty(source: string, key: string): string | undefined {
return match?.[1];
}

function parseNumberProperty(source: string, key: string): number | undefined {
const match = source.match(new RegExp(`${key}:\\s*(\\d+)`));
return match ? Number(match[1]) : undefined;
}

function activeCockpitE2eWiring(): E2eWiring[] {
return listProjectJsonFiles(join(repoRoot, 'cockpit'))
.map((projectJsonPath) => {
Expand Down Expand Up @@ -97,18 +92,9 @@ function activeCockpitE2eWiring(): E2eWiring[] {
// Post-port-registry migration: ports are imported from
// cockpit/ports.mjs rather than living as literals in
// global-setup-impl.ts. Look them up by project name.
let langgraphPort: number | undefined;
let angularPort: number | undefined;
try {
const ports = portsFor(project.name) as { angular: number; langgraph: number };
langgraphPort = ports.langgraph;
angularPort = ports.angular;
} catch {
// Cap not in registry (e.g. cockpit-ag-ui-streaming-angular).
// Fall back to parsing literals if global-setup still has them.
langgraphPort = parseNumberProperty(globalSetup, 'langgraphPort');
angularPort = parseNumberProperty(globalSetup, 'angularPort');
}
const ports = portsFor(project.name) as { angular: number; langgraph: number };
const langgraphPort = ports.langgraph;
const angularPort = ports.angular;

if (!project.name || !langgraphCwd || !langgraphPort || !angularPort) {
throw new Error(`Unable to parse e2e wiring for ${relative(repoRoot, projectJsonPath)}`);
Expand Down Expand Up @@ -242,6 +228,20 @@ describe('cockpit e2e wiring', () => {
expect(errors).toEqual([]);
});

it('keeps capability-registry ports aligned with cockpit/ports.mjs', async () => {
const mismatches: string[] = [];
for (const cap of capabilities) {
const ports = portsFor(cap.angularProject) as { angular: number; langgraph: number };
if (cap.port !== ports.angular) {
mismatches.push(`${cap.id}: registry.port ${cap.port} !== ports.angular ${ports.angular}`);
}
if (cap.pythonPort !== undefined && cap.pythonPort !== ports.langgraph) {
mismatches.push(`${cap.id}: registry.pythonPort ${cap.pythonPort} !== ports.langgraph ${ports.langgraph}`);
}
}
expect(mismatches).toEqual([]);
});

it('every cockpit cap project declares the expected scope:* tags', () => {
// Drift guard for the ci-scope thin-shim migration (PR #503/#507).
// The shim reads scope:* tags off projects nx considers affected to
Expand Down Expand Up @@ -284,4 +284,28 @@ describe('cockpit e2e wiring', () => {

expect(errors).toEqual([]);
});

it('smoke job represents every cockpit product with a real smoke target', () => {
const ci = readFileSync(join(repoRoot, '.github/workflows/ci.yml'), 'utf8');
const smokeLine = ci.split('\n').find((l) => l.includes('-t smoke --projects=')) ?? '';
const listed = (smokeLine.match(/--projects=(\S+)/)?.[1] ?? '').split(',').filter(Boolean);

// Every listed cockpit python project must actually declare a smoke target.
const missingTarget = listed.filter((name) => {
const cap = capabilities.find((c) => c.angularProject.replace('-angular', '-python') === name);
if (!cap?.pythonDir) return true; // listed a project not backed by a registry cap with python
const pj = JSON.parse(readFileSync(join(repoRoot, cap.pythonDir, 'project.json'), 'utf8'));
return !pj.targets?.smoke;
});
expect(missingTarget).toEqual([]);

// Every product must be represented by a listed project.
const products = [...new Set(capabilities.map((c) => c.product))];
const uncovered = products.filter(
(product) => !capabilities.some(
(c) => c.product === product && listed.includes(c.angularProject.replace('-angular', '-python')),
),
);
expect(uncovered).toEqual([]);
});
});
112 changes: 28 additions & 84 deletions apps/cockpit/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,155 +62,99 @@
"serve-streaming": {
"executor": "nx:run-commands",
"options": {
"commands": [
"npx nx serve cockpit --port 4201",
"npx nx run cockpit-langgraph-streaming-angular:serve:cockpit --port 4300",
"cd cockpit/langgraph/streaming/python && source $HOME/.local/bin/env 2>/dev/null; uv sync && uv run langgraph dev --port 8123"
],
"parallel": true
"command": "npx tsx apps/cockpit/scripts/serve-example.ts --capability=streaming",
"cwd": "."
}
},
"serve-persistence": {
"executor": "nx:run-commands",
"options": {
"commands": [
"npx nx serve cockpit --port 4201",
"npx nx run cockpit-langgraph-persistence-angular:serve:cockpit --port 4301",
"cd cockpit/langgraph/persistence/python && source $HOME/.local/bin/env 2>/dev/null; uv sync && uv run langgraph dev --port 8123"
],
"parallel": true
"command": "npx tsx apps/cockpit/scripts/serve-example.ts --capability=persistence",
"cwd": "."
}
},
"serve-interrupts": {
"executor": "nx:run-commands",
"options": {
"commands": [
"npx nx serve cockpit --port 4201",
"npx nx run cockpit-langgraph-interrupts-angular:serve:cockpit --port 4302",
"cd cockpit/langgraph/interrupts/python && source $HOME/.local/bin/env 2>/dev/null; uv sync && uv run langgraph dev --port 8123"
],
"parallel": true
"command": "npx tsx apps/cockpit/scripts/serve-example.ts --capability=interrupts",
"cwd": "."
}
},
"serve-memory": {
"executor": "nx:run-commands",
"options": {
"commands": [
"npx nx serve cockpit --port 4201",
"npx nx run cockpit-langgraph-memory-angular:serve:cockpit --port 4303",
"cd cockpit/langgraph/memory/python && source $HOME/.local/bin/env 2>/dev/null; uv sync && uv run langgraph dev --port 8123"
],
"parallel": true
"command": "npx tsx apps/cockpit/scripts/serve-example.ts --capability=memory",
"cwd": "."
}
},
"serve-durable-execution": {
"executor": "nx:run-commands",
"options": {
"commands": [
"npx nx serve cockpit --port 4201",
"npx nx run cockpit-langgraph-durable-execution-angular:serve:cockpit --port 4304",
"cd cockpit/langgraph/durable-execution/python && source $HOME/.local/bin/env 2>/dev/null; uv sync && uv run langgraph dev --port 8123"
],
"parallel": true
"command": "npx tsx apps/cockpit/scripts/serve-example.ts --capability=durable-execution",
"cwd": "."
}
},
"serve-subgraphs": {
"executor": "nx:run-commands",
"options": {
"commands": [
"npx nx serve cockpit --port 4201",
"npx nx run cockpit-langgraph-subgraphs-angular:serve:cockpit --port 4305",
"cd cockpit/langgraph/subgraphs/python && source $HOME/.local/bin/env 2>/dev/null; uv sync && uv run langgraph dev --port 8123"
],
"parallel": true
"command": "npx tsx apps/cockpit/scripts/serve-example.ts --capability=subgraphs",
"cwd": "."
}
},
"serve-time-travel": {
"executor": "nx:run-commands",
"options": {
"commands": [
"npx nx serve cockpit --port 4201",
"npx nx run cockpit-langgraph-time-travel-angular:serve:cockpit --port 4306",
"cd cockpit/langgraph/time-travel/python && source $HOME/.local/bin/env 2>/dev/null; uv sync && uv run langgraph dev --port 8123"
],
"parallel": true
"command": "npx tsx apps/cockpit/scripts/serve-example.ts --capability=time-travel",
"cwd": "."
}
},
"serve-deployment-runtime": {
"executor": "nx:run-commands",
"options": {
"commands": [
"npx nx serve cockpit --port 4201",
"npx nx run cockpit-langgraph-deployment-runtime-angular:serve:cockpit --port 4307",
"cd cockpit/langgraph/deployment-runtime/python && source $HOME/.local/bin/env 2>/dev/null; uv sync && uv run langgraph dev --port 8123"
],
"parallel": true
"command": "npx tsx apps/cockpit/scripts/serve-example.ts --capability=deployment-runtime",
"cwd": "."
}
},
"serve-planning": {
"executor": "nx:run-commands",
"options": {
"commands": [
"npx nx serve cockpit --port 4201",
"npx nx run cockpit-deep-agents-planning-angular:serve:cockpit --port 4310",
"cd cockpit/deep-agents/planning/python && source $HOME/.local/bin/env 2>/dev/null; uv sync && uv run langgraph dev --port 8123"
],
"parallel": true
"command": "npx tsx apps/cockpit/scripts/serve-example.ts --capability=da-planning",
"cwd": "."
}
},
"serve-filesystem": {
"executor": "nx:run-commands",
"options": {
"commands": [
"npx nx serve cockpit --port 4201",
"npx nx run cockpit-deep-agents-filesystem-angular:serve:cockpit --port 4311",
"cd cockpit/deep-agents/filesystem/python && source $HOME/.local/bin/env 2>/dev/null; uv sync && uv run langgraph dev --port 8123"
],
"parallel": true
"command": "npx tsx apps/cockpit/scripts/serve-example.ts --capability=da-filesystem",
"cwd": "."
}
},
"serve-da-subagents": {
"executor": "nx:run-commands",
"options": {
"commands": [
"npx nx serve cockpit --port 4201",
"npx nx run cockpit-deep-agents-subagents-angular:serve:cockpit --port 4312",
"cd cockpit/deep-agents/subagents/python && source $HOME/.local/bin/env 2>/dev/null; uv sync && uv run langgraph dev --port 8123"
],
"parallel": true
"command": "npx tsx apps/cockpit/scripts/serve-example.ts --capability=da-subagents",
"cwd": "."
}
},
"serve-da-memory": {
"executor": "nx:run-commands",
"options": {
"commands": [
"npx nx serve cockpit --port 4201",
"npx nx run cockpit-deep-agents-memory-angular:serve:cockpit --port 4313",
"cd cockpit/deep-agents/memory/python && source $HOME/.local/bin/env 2>/dev/null; uv sync && uv run langgraph dev --port 8123"
],
"parallel": true
"command": "npx tsx apps/cockpit/scripts/serve-example.ts --capability=da-memory",
"cwd": "."
}
},
"serve-skills": {
"executor": "nx:run-commands",
"options": {
"commands": [
"npx nx serve cockpit --port 4201",
"npx nx run cockpit-deep-agents-skills-angular:serve:cockpit --port 4314",
"cd cockpit/deep-agents/skills/python && source $HOME/.local/bin/env 2>/dev/null; uv sync && uv run langgraph dev --port 8123"
],
"parallel": true
"command": "npx tsx apps/cockpit/scripts/serve-example.ts --capability=da-skills",
"cwd": "."
}
},
"serve-sandboxes": {
"executor": "nx:run-commands",
"options": {
"commands": [
"npx nx serve cockpit --port 4201",
"npx nx run cockpit-deep-agents-sandboxes-angular:serve:cockpit --port 4315",
"cd cockpit/deep-agents/sandboxes/python && source $HOME/.local/bin/env 2>/dev/null; uv sync && uv run langgraph dev --port 8123"
],
"parallel": true
"command": "npx tsx apps/cockpit/scripts/serve-example.ts --capability=da-sandboxes",
"cwd": "."
}
},
"serve-all": {
Expand Down
39 changes: 39 additions & 0 deletions apps/cockpit/scripts/serve-example.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { describe, expect, it } from 'vitest';
import { backendCommand, COCKPIT_RUNTIME_ENV } from './serve-example';
import { findCapability, type Capability } from './capability-registry';

describe('backendCommand', () => {
it('uses uvicorn on the registry pythonPort for ag-ui caps', () => {
const cap = findCapability('ag-ui-streaming')!;
const cmd = backendCommand(cap)!;
expect(cmd).toContain('cd cockpit/ag-ui/streaming/python');
expect(cmd).toContain('uv run uvicorn src.server:app --port 5321');
expect(cmd).not.toContain('langgraph dev');
expect(cmd).not.toContain('8123');
});

it('uses langgraph dev on the registry pythonPort for langgraph caps', () => {
const cap = findCapability('streaming')!;
const cmd = backendCommand(cap)!;
expect(cmd).toContain('cd cockpit/langgraph/streaming/python');
expect(cmd).toContain('uv run langgraph dev --port 5300 --no-browser');
expect(cmd).not.toContain('uvicorn');
expect(cmd).not.toContain('8123');
});

it('uses langgraph dev for chat and render caps too', () => {
expect(backendCommand(findCapability('c-messages')!)).toContain('langgraph dev --port 5501');
expect(backendCommand(findCapability('r-spec-rendering')!)).toContain('langgraph dev --port 5401');
});

it('returns null when the capability has no pythonDir', () => {
const noPy: Capability = {
id: 'x', product: 'render', topic: 'x', angularProject: 'cockpit-render-x-angular', port: 4499,
};
expect(backendCommand(noPy)).toBeNull();
});

it('exposes an empty runtime base URL so the cockpit iframe targets localhost', () => {
expect(COCKPIT_RUNTIME_ENV).toEqual({ NEXT_PUBLIC_COCKPIT_RUNTIME_BASE_URL: '' });
});
});
Loading
Loading