Skip to content

Commit 616cc07

Browse files
committed
ci: add comprehensive quality gate
1 parent da5a62e commit 616cc07

5 files changed

Lines changed: 132 additions & 21 deletions

File tree

.github/workflows/ci.yml

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,18 @@ on:
66
push:
77
branches: [main]
88

9+
permissions:
10+
contents: read
11+
12+
concurrency:
13+
group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
14+
cancel-in-progress: true
15+
916
jobs:
1017
typecheck:
1118
runs-on: ubuntu-latest
1219
name: Typecheck
20+
timeout-minutes: 10
1321

1422
steps:
1523
- name: Checkout
@@ -18,30 +26,28 @@ jobs:
1826
- name: Setup Bun
1927
uses: oven-sh/setup-bun@v2
2028
with:
21-
bun-version: latest
29+
bun-version: 1.3.14
2230

23-
- name: Install dependencies
31+
- name: Install workspace dependencies
2432
run: |
25-
cd opencode && bun install --frozen-lockfile || bun install
26-
cd ../packages/nine1bot && bun install --frozen-lockfile || bun install
27-
cd ../../web && bun install --frozen-lockfile || bun install
28-
cd ../packages/browser-extension && bun install --frozen-lockfile || bun install
33+
bun install --frozen-lockfile
34+
bun install --cwd opencode --frozen-lockfile
35+
bun install --cwd packages/nine1bot --frozen-lockfile
36+
bun install --cwd web --frozen-lockfile
37+
bun install --cwd packages/browser-extension --frozen-lockfile
2938
30-
- name: Typecheck opencode
39+
- name: Typecheck upstream opencode (advisory)
3140
# TODO: Fix TypeScript errors inherited from upstream opencode
3241
# Many type errors exist in acp/, agent/, cli/cmd/ directories
3342
# Temporarily allowing failure until these are resolved
34-
run: cd opencode && bun run typecheck || echo "Typecheck failed but continuing..."
43+
run: bun run --cwd opencode typecheck
3544
continue-on-error: true
3645

37-
- name: Typecheck nine1bot
38-
# Note: May show errors from opencode dependencies due to path alias resolution
39-
# The actual nine1bot code errors are what matter
40-
run: cd packages/nine1bot && bun run typecheck || echo "Typecheck completed with warnings"
41-
continue-on-error: true
46+
- name: Typecheck maintained workspace
47+
run: bun run ci:typecheck
4248

43-
- name: Test nine1bot
44-
run: cd packages/nine1bot && bun test
49+
- name: Test maintained workspace
50+
run: bun run ci:test
4551

4652
build:
4753
strategy:

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
"web": "bun run --cwd web dev",
2626
"nine1bot": "bun run packages/nine1bot/src/index.ts",
2727
"rebuild": "web/node_modules/.bin/vue-tsc -b web/tsconfig.json && web/node_modules/.bin/vite build web --config web/vite.config.ts",
28-
"dev:test": "node scripts/dev-test.mjs"
28+
"dev:test": "node scripts/dev-test.mjs",
29+
"ci:typecheck": "bun run --cwd packages/platform-protocol typecheck && bun run --cwd packages/platform-feishu typecheck && bun run --cwd packages/platform-gitlab typecheck && bun run --cwd packages/nine1bot typecheck && bun run --cwd packages/browser-extension typecheck && bun run --cwd packages/browser-mcp-server typecheck && bun run --cwd web typecheck",
30+
"ci:test": "bun test packages/nine1bot/src packages/platform-feishu/test packages/platform-gitlab/test packages/browser-extension/test packages/browser-mcp-server/test web/test scripts"
2931
}
3032
}

packages/nine1bot/src/platform/manager.test.ts

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -397,16 +397,16 @@ describe('PlatformAdapterManager', () => {
397397
})
398398
})
399399

400-
it('normalizes Windows runtime source paths before registering and reporting details', async () => {
400+
it('normalizes runtime source URLs into native paths before registering and reporting details', async () => {
401401
await withRuntimeSourceDirectories(async ({ agents, skills }) => {
402-
const windowsAgentUrlPath = `/${agents.replaceAll('\\', '/')}`
402+
const agentURLPath = `/${agents.replaceAll('\\', '/')}`
403403
const manager = new PlatformAdapterManager({
404404
contributions: [contribution('feishu', {
405405
defaultEnabled: true,
406406
sources: {
407407
agents: [{
408408
id: 'feishu-agents',
409-
directory: windowsAgentUrlPath,
409+
directory: agentURLPath,
410410
namespace: 'feishu.agent',
411411
visibility: 'recommendable',
412412
lifecycle: 'platform-enabled',
@@ -424,8 +424,8 @@ describe('PlatformAdapterManager', () => {
424424

425425
manager.registerRuntimeAdapters()
426426

427-
const expectedAgentDirectory = win32Path.normalize(agents)
428-
const expectedSkillDirectory = win32Path.normalize(skills)
427+
const expectedAgentDirectory = normalize(agents)
428+
const expectedSkillDirectory = normalize(skills)
429429

430430
expect(RuntimeSourceRegistry.listOwner('feishu')).toMatchObject({
431431
agents: [{
@@ -454,6 +454,43 @@ describe('PlatformAdapterManager', () => {
454454
})
455455
})
456456

457+
it('normalizes Windows drive URL paths independently of the host platform', () => {
458+
const manager = new PlatformAdapterManager({
459+
contributions: [contribution('feishu', {
460+
defaultEnabled: true,
461+
sources: {
462+
agents: [{
463+
id: 'feishu-agents',
464+
directory: '/C:/nine1bot/platform-resources/platform-feishu/agents',
465+
namespace: 'feishu.agent',
466+
visibility: 'recommendable',
467+
lifecycle: 'platform-enabled',
468+
}],
469+
skills: [{
470+
id: 'feishu-skills',
471+
directory: 'file:///C:/nine1bot/platform-resources/platform-feishu/skills',
472+
namespace: 'feishu.skill',
473+
visibility: 'declared-only',
474+
lifecycle: 'platform-enabled',
475+
}],
476+
},
477+
})],
478+
})
479+
480+
manager.registerRuntimeAdapters()
481+
482+
expect(RuntimeSourceRegistry.listOwner('feishu')).toMatchObject({
483+
agents: [{
484+
id: 'feishu-agents',
485+
directory: win32Path.normalize('C:\\nine1bot\\platform-resources\\platform-feishu\\agents'),
486+
}],
487+
skills: [{
488+
id: 'feishu-skills',
489+
directory: win32Path.normalize('C:\\nine1bot\\platform-resources\\platform-feishu\\skills'),
490+
}],
491+
})
492+
})
493+
457494
it('reports enabled registered source drift as error instead of disabled', async () => {
458495
const manager = new PlatformAdapterManager({
459496
contributions: [contribution('demo', {
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { describe, expect, test } from 'bun:test'
2+
import { readFile } from 'node:fs/promises'
3+
import { join } from 'node:path'
4+
5+
const root = join(import.meta.dir, '..')
6+
7+
async function readCIWorkflow() {
8+
return (await readFile(join(root, '.github', 'workflows', 'ci.yml'), 'utf8'))
9+
.replaceAll('\r\n', '\n')
10+
}
11+
12+
async function readRootPackageScripts(): Promise<Record<string, string>> {
13+
const packageJSON = JSON.parse(await readFile(join(root, 'package.json'), 'utf8')) as {
14+
scripts?: Record<string, string>
15+
}
16+
return packageJSON.scripts ?? {}
17+
}
18+
19+
describe('CI workflow contract', () => {
20+
test('keeps the existing four-platform build and startup smoke coverage', async () => {
21+
const workflow = await readCIWorkflow()
22+
23+
expect(workflow).toContain('platform: linux\n arch: x64')
24+
expect(workflow).toContain('platform: linux\n arch: arm64')
25+
expect(workflow).toContain('platform: darwin\n arch: arm64')
26+
expect(workflow).toContain('platform: windows\n arch: x64')
27+
expect(workflow).toContain('bun run scripts/build.ts --platform=${{ matrix.platform }} --arch=${{ matrix.arch }}')
28+
expect(workflow).toContain('./scripts/test-startup.sh ${{ matrix.platform }} ${{ matrix.arch }}')
29+
})
30+
31+
test('runs strict owned typechecks and every maintained test area', async () => {
32+
const workflow = await readCIWorkflow()
33+
const scripts = await readRootPackageScripts()
34+
const qualityJob = workflow.slice(
35+
workflow.indexOf(' typecheck:'),
36+
workflow.indexOf('\n build:'),
37+
)
38+
39+
expect(qualityJob).toContain('bun install --frozen-lockfile')
40+
expect(qualityJob).not.toContain('|| bun install')
41+
expect(qualityJob).toContain('bun install --cwd opencode --frozen-lockfile')
42+
expect(qualityJob).toContain('bun install --cwd packages/nine1bot --frozen-lockfile')
43+
expect(qualityJob).toContain('bun install --cwd web --frozen-lockfile')
44+
expect(qualityJob).toContain('bun install --cwd packages/browser-extension --frozen-lockfile')
45+
expect(qualityJob).toContain('bun run ci:typecheck')
46+
expect(qualityJob).toContain('bun run ci:test')
47+
expect(qualityJob).not.toContain('Typecheck completed with warnings')
48+
49+
expect(scripts['ci:typecheck']).toContain('packages/platform-protocol')
50+
expect(scripts['ci:typecheck']).toContain('packages/platform-feishu')
51+
expect(scripts['ci:typecheck']).toContain('packages/platform-gitlab')
52+
expect(scripts['ci:typecheck']).toContain('packages/nine1bot')
53+
expect(scripts['ci:typecheck']).toContain('packages/browser-extension')
54+
expect(scripts['ci:typecheck']).toContain('packages/browser-mcp-server')
55+
expect(scripts['ci:typecheck']).toContain('web')
56+
57+
expect(scripts['ci:test']).toContain('packages/nine1bot/src')
58+
expect(scripts['ci:test']).toContain('packages/platform-feishu/test')
59+
expect(scripts['ci:test']).toContain('packages/platform-gitlab/test')
60+
expect(scripts['ci:test']).toContain('packages/browser-extension/test')
61+
expect(scripts['ci:test']).toContain('packages/browser-mcp-server/test')
62+
expect(scripts['ci:test']).toContain('web/test')
63+
expect(scripts['ci:test']).toContain('scripts')
64+
})
65+
})

web/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"type": "module",
1313
"scripts": {
1414
"dev": "vite",
15+
"typecheck": "vue-tsc -b",
1516
"build": "vue-tsc -b && vite build",
1617
"preview": "vite preview"
1718
},

0 commit comments

Comments
 (0)