feat(aircoding): AirCoding V2 baseline — deterministic multi-agent architecture

Forked from OpenCode v1.17.4 with multi-agent system:
- 5 agents: aircoding, scheduler, worker, architect, reviewer
- Deterministic DAG scheduling engine (coordinator_tick)
- Tool whitelists as hard enforcement
- AirCoding validation plugin
- V1 requirements: C4 docs, ADR, AGENTS.md, debug-log.md
- Design documents in docs/
This commit is contained in:
airlongdian
2026-06-13 21:53:43 +08:00
commit deaf7eb806
5757 changed files with 1169969 additions and 0 deletions

26
packages/ui/.gitignore vendored Normal file
View File

@@ -0,0 +1,26 @@
dist
.wrangler
.output
.vercel
.netlify
# Environment
.env
.env*.local
# dependencies
/node_modules
# IDEs and editors
/.idea
.project
.classpath
*.launch
.settings/
# Temp
gitignore
# System Files
.DS_Store
Thumbs.db

82
packages/ui/package.json Normal file
View File

@@ -0,0 +1,82 @@
{
"name": "@opencode-ai/ui",
"version": "1.17.4",
"type": "module",
"license": "MIT",
"exports": {
"./package.json": "./package.json",
"./*": "./src/components/*.tsx",
"./session-diff": "./src/components/session-diff.ts",
"./i18n/*": "./src/i18n/*.ts",
"./pierre": "./src/pierre/index.ts",
"./pierre/*": "./src/pierre/*.ts",
"./hooks": "./src/hooks/index.ts",
"./context": "./src/context/index.ts",
"./context/*": "./src/context/*.tsx",
"./styles": "./src/styles/index.css",
"./styles/tailwind": "./src/styles/tailwind/index.css",
"./theme": "./src/theme/index.ts",
"./theme/*": "./src/theme/*.ts",
"./theme/context": "./src/theme/context.tsx",
"./icons/provider": "./src/components/provider-icons/types.ts",
"./icons/file-type": "./src/components/file-icons/types.ts",
"./icons/app": "./src/components/app-icons/types.ts",
"./fonts/*": "./src/assets/fonts/*",
"./audio/*": "./src/assets/audio/*",
"./v2/*.css": "./src/v2/components/*.css",
"./v2/*": "./src/v2/components/*.tsx",
"./v2/styles/*": "./src/v2/styles/*"
},
"scripts": {
"typecheck": "tsgo --noEmit",
"test": "bun test src --only-failures",
"dev": "vite",
"generate:tailwind": "bun run script/tailwind.ts",
"generate:v2-oc2": "bun run script/build-oc2-v2-overrides.ts"
},
"devDependencies": {
"@tailwindcss/vite": "catalog:",
"@tsconfig/node22": "catalog:",
"@types/bun": "catalog:",
"@types/katex": "0.16.7",
"@types/luxon": "catalog:",
"@typescript/native-preview": "catalog:",
"tailwindcss": "catalog:",
"typescript": "catalog:",
"vite": "catalog:",
"vite-plugin-icons-spritesheet": "3.0.1",
"vite-plugin-solid": "catalog:"
},
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode-ai/core": "workspace:*",
"@opencode-ai/sdk": "workspace:*",
"@pierre/diffs": "catalog:",
"@shikijs/transformers": "3.9.2",
"@solid-primitives/bounds": "0.1.3",
"@solid-primitives/event-listener": "2.4.5",
"@solid-primitives/media": "2.3.3",
"@solid-primitives/resize-observer": "2.1.3",
"@solidjs/meta": "catalog:",
"@solidjs/router": "catalog:",
"diff": "catalog:",
"dompurify": "3.3.1",
"fuzzysort": "catalog:",
"katex": "0.16.27",
"luxon": "catalog:",
"marked": "catalog:",
"marked-katex-extension": "5.1.6",
"marked-shiki": "catalog:",
"morphdom": "2.7.8",
"motion": "12.34.5",
"motion-dom": "12.34.3",
"motion-utils": "12.29.2",
"remeda": "catalog:",
"remend": "catalog:",
"shiki": "catalog:",
"solid-js": "catalog:",
"solid-list": "catalog:",
"strip-ansi": "7.1.2",
"virtua": "catalog:"
}
}

View File

@@ -0,0 +1,32 @@
#!/usr/bin/env bun
import { V2_PRIMITIVES_DEFAULT } from "../src/theme/v2/default-primitives"
import type { DesktopTheme } from "../src/theme/types"
const themePath = import.meta.dir + "/../src/theme/themes/oc-2.json"
const theme = (await Bun.file(themePath).json()) as DesktopTheme
const css = await Bun.file(import.meta.dir + "/../src/v2/styles/theme.css").text()
const light = { ...V2_PRIMITIVES_DEFAULT, ...readTokens("light") }
const dark = { ...V2_PRIMITIVES_DEFAULT, ...readTokens("dark") }
const next: DesktopTheme = {
...theme,
light: { ...theme.light, v2Overrides: light },
dark: { ...theme.dark, v2Overrides: dark },
}
await Bun.write(themePath, JSON.stringify(next, null, 2) + "\n")
console.log("Updated oc-2.json v2Overrides", Object.keys(light).length, "tokens per mode")
function readTokens(mode: "light" | "dark") {
const selector = mode === "light" ? ":root" : `\\[data-color-scheme="${mode}"\\]`
const block = css.match(new RegExp(`${selector} \\{([\\s\\S]*?)\\n \\}`))?.[1]
if (!block) throw new Error(`Missing ${mode} OC-2 tokens`)
return Object.fromEntries(
[...block.matchAll(/--(v2-[\w-]+):\s*([^;]+);/g)]
// Fonts and the fixed avatar foreground remain global CSS rather than theme overrides.
.filter(([, key]) => key !== "v2-avatar-fg" && key !== "v2-font-family-sans")
.map(([, key, value]) => [key, value!.replace(/\s+/g, " ").trim()]),
)
}

View File

@@ -0,0 +1,285 @@
--background-base: #F8F7F7;
--background-weak: var(--smoke-light-3);
--background-strong: var(--smoke-light-1);
--background-stronger: #FCFCFC;
--surface-base: var(--smoke-light-alpha-2);
--base: var(--smoke-light-alpha-2);
--surface-base-hover: #0500000F;
--surface-base-active: var(--smoke-light-alpha-3);
--surface-base-interactive-active: var(--cobalt-light-alpha-3);
--base2: var(--smoke-light-alpha-2);
--base3: var(--smoke-light-alpha-2);
--surface-inset-base: var(--smoke-light-alpha-2);
--surface-inset-base-hover: var(--smoke-light-alpha-3);
--surface-inset-strong: #1F000017;
--surface-inset-strong-hover: #1F000017;
--surface-raised-base: var(--smoke-light-alpha-1);
--surface-float-base: var(--smoke-dark-1);
--surface-float-base-hover: var(--smoke-dark-2);
--surface-raised-base-hover: var(--smoke-light-alpha-2);
--surface-raised-base-active: var(--smoke-light-alpha-3);
--surface-raised-strong: var(--smoke-light-1);
--surface-raised-strong-hover: var(--white);
--surface-raised-stronger: var(--white);
--surface-raised-stronger-hover: var(--white);
--surface-weak: var(--smoke-light-alpha-3);
--surface-weaker: var(--smoke-light-alpha-4);
--surface-strong: #FFFFFF;
--surface-raised-stronger-non-alpha: var(--white);
--surface-brand-base: var(--yuzu-light-9);
--surface-brand-hover: var(--yuzu-light-10);
--surface-interactive-base: var(--cobalt-light-3);
--surface-interactive-hover: var(--cobalt-light-4);
--surface-interactive-weak: var(--cobalt-light-2);
--surface-interactive-weak-hover: var(--cobalt-light-3);
--surface-success-base: var(--apple-light-3);
--surface-success-weak: var(--apple-light-2);
--surface-success-strong: var(--apple-light-9);
--surface-warning-base: var(--solaris-light-3);
--surface-warning-weak: var(--solaris-light-2);
--surface-warning-strong: var(--solaris-light-9);
--surface-critical-base: var(--ember-light-3);
--surface-critical-weak: var(--ember-light-2);
--surface-critical-strong: var(--ember-light-9);
--surface-info-base: var(--lilac-light-3);
--surface-info-weak: var(--lilac-light-2);
--surface-info-strong: var(--lilac-light-9);
--surface-diff-unchanged-base: #FFFFFF00;
--surface-diff-skip-base: var(--smoke-light-2);
--surface-diff-hidden-base: var(--blue-light-3);
--surface-diff-hidden-weak: var(--blue-light-2);
--surface-diff-hidden-weaker: var(--blue-light-1);
--surface-diff-hidden-strong: var(--blue-light-5);
--surface-diff-hidden-stronger: var(--blue-light-9);
--surface-diff-add-base: var(--mint-light-3);
--surface-diff-add-weak: var(--mint-light-2);
--surface-diff-add-weaker: var(--mint-light-1);
--surface-diff-add-strong: var(--mint-light-5);
--surface-diff-add-stronger: var(--mint-light-9);
--surface-diff-delete-base: var(--ember-light-3);
--surface-diff-delete-weak: var(--ember-light-2);
--surface-diff-delete-weaker: var(--ember-light-1);
--surface-diff-delete-strong: var(--ember-light-6);
--surface-diff-delete-stronger: var(--ember-light-9);
--text-base: var(--smoke-light-11);
--input-base: var(--smoke-light-1);
--input-hover: var(--smoke-light-2);
--input-active: var(--cobalt-light-1);
--input-selected: var(--cobalt-light-4);
--input-focus: var(--cobalt-light-1);
--input-disabled: var(--smoke-light-4);
--text-weak: var(--smoke-light-9);
--text-weaker: var(--smoke-light-8);
--text-strong: var(--smoke-light-12);
--text-interactive-base: var(--cobalt-light-9);
--text-on-brand-base: var(--smoke-light-alpha-11);
--text-on-interactive-base: var(--smoke-light-1);
--text-on-interactive-weak: var(--smoke-dark-alpha-11);
--text-on-success-base: var(--apple-light-10);
--text-on-critical-base: var(--ember-light-10);
--text-on-critical-weak: var(--ember-light-8);
--text-on-critical-strong: var(--ember-light-12);
--text-on-warning-base: var(--smoke-dark-alpha-11);
--text-on-info-base: var(--smoke-dark-alpha-11);
--text-diff-add-base: var(--mint-light-11);
--text-diff-delete-base: var(--ember-light-10);
--text-diff-delete-strong: var(--ember-light-12);
--text-diff-add-strong: var(--mint-light-12);
--text-on-info-weak: var(--smoke-dark-alpha-9);
--text-on-info-strong: var(--smoke-dark-alpha-12);
--text-on-warning-weak: var(--smoke-dark-alpha-9);
--text-on-warning-strong: var(--smoke-dark-alpha-12);
--text-on-success-weak: var(--apple-light-6);
--text-on-success-strong: var(--apple-light-12);
--text-on-brand-weak: var(--smoke-light-alpha-9);
--text-on-brand-weaker: var(--smoke-light-alpha-8);
--text-on-brand-strong: var(--smoke-light-alpha-12);
--button-secondary-base: #FDFCFC;
--button-secondary-hover: #FAF9F9;
--border-base: var(--smoke-light-alpha-7);
--border-hover: var(--smoke-light-alpha-8);
--border-active: var(--smoke-light-alpha-9);
--border-selected: var(--cobalt-light-alpha-9);
--border-disabled: var(--smoke-light-alpha-8);
--border-focus: var(--smoke-light-alpha-9);
--border-weak-base: var(--smoke-light-alpha-5);
--border-strong-base: var(--smoke-light-alpha-7);
--border-strong-hover: var(--smoke-light-alpha-8);
--border-strong-active: var(--smoke-light-alpha-7);
--border-strong-selected: var(--cobalt-light-alpha-6);
--border-strong-disabled: var(--smoke-light-alpha-6);
--border-strong-focus: var(--smoke-light-alpha-7);
--border-weak-hover: var(--smoke-light-alpha-6);
--border-weak-active: var(--smoke-light-alpha-7);
--border-weak-selected: var(--cobalt-light-alpha-5);
--border-weak-disabled: var(--smoke-light-alpha-6);
--border-weak-focus: var(--smoke-light-alpha-7);
--border-weaker-base: var(--smoke-light-alpha-3);
--border-interactive-base: var(--cobalt-light-7);
--border-interactive-hover: var(--cobalt-light-8);
--border-interactive-active: var(--cobalt-light-9);
--border-interactive-selected: var(--cobalt-light-9);
--border-interactive-disabled: var(--smoke-light-8);
--border-interactive-focus: var(--cobalt-light-9);
--border-success-base: var(--apple-light-6);
--border-success-hover: var(--apple-light-7);
--border-success-selected: var(--apple-light-9);
--border-warning-base: var(--solaris-light-6);
--border-warning-hover: var(--solaris-light-7);
--border-warning-selected: var(--solaris-light-9);
--border-critical-base: var(--ember-light-6);
--border-critical-hover: var(--ember-light-7);
--border-critical-selected: var(--ember-light-9);
--border-info-base: var(--lilac-light-6);
--border-info-hover: var(--lilac-light-7);
--border-info-selected: var(--lilac-light-9);
--icon-base: var(--smoke-light-9);
--icon-hover: var(--smoke-light-11);
--icon-active: var(--smoke-light-12);
--icon-selected: var(--smoke-light-12);
--icon-disabled: var(--smoke-light-8);
--icon-focus: var(--smoke-light-12);
--icon-invert-base: #FFFFFF;
--icon-weak-base: var(--smoke-light-7);
--icon-weak-hover: var(--smoke-light-8);
--icon-weak-active: var(--smoke-light-9);
--icon-weak-selected: var(--smoke-light-10);
--icon-weak-disabled: var(--smoke-light-6);
--icon-weak-focus: var(--smoke-light-9);
--icon-strong-base: var(--smoke-light-12);
--icon-strong-hover: #151313;
--icon-strong-active: #020202;
--icon-strong-selected: #020202;
--icon-strong-disabled: var(--smoke-light-8);
--icon-strong-focus: #020202;
--icon-brand-base: var(--smoke-light-12);
--icon-interactive-base: var(--cobalt-light-9);
--icon-success-base: var(--apple-light-7);
--icon-success-hover: var(--apple-light-8);
--icon-success-active: var(--apple-light-11);
--icon-warning-base: var(--amber-light-7);
--icon-warning-hover: var(--amber-light-8);
--icon-warning-active: var(--amber-light-11);
--icon-critical-base: var(--ember-light-10);
--icon-critical-hover: var(--ember-light-11);
--icon-critical-active: var(--ember-light-12);
--icon-info-base: var(--lilac-light-7);
--icon-info-hover: var(--lilac-light-8);
--icon-info-active: var(--lilac-light-11);
--icon-on-brand-base: var(--smoke-light-alpha-11);
--icon-on-brand-hover: var(--smoke-light-alpha-12);
--icon-on-brand-selected: var(--smoke-light-alpha-12);
--icon-on-interactive-base: var(--smoke-light-1);
--icon-agent-plan-base: var(--purple-light-9);
--icon-agent-docs-base: var(--amber-light-9);
--icon-agent-ask-base: var(--cyan-light-9);
--icon-agent-build-base: var(--cobalt-light-9);
--icon-on-success-base: var(--apple-light-alpha-9);
--icon-on-success-hover: var(--apple-light-alpha-10);
--icon-on-success-selected: var(--apple-light-alpha-11);
--icon-on-warning-base: var(--amber-lightalpha-9);
--icon-on-warning-hover: var(--amber-lightalpha-10);
--icon-on-warning-selected: var(--amber-lightalpha-11);
--icon-on-critical-base: var(--ember-light-alpha-9);
--icon-on-critical-hover: var(--ember-light-alpha-10);
--icon-on-critical-selected: var(--ember-light-alpha-11);
--icon-on-info-base: var(--lilac-light-9);
--icon-on-info-hover: var(--lilac-light-alpha-10);
--icon-on-info-selected: var(--lilac-light-alpha-11);
--icon-diff-add-base: var(--mint-light-11);
--icon-diff-add-hover: var(--mint-light-12);
--icon-diff-add-active: var(--mint-light-12);
--icon-diff-delete-base: var(--ember-light-10);
--icon-diff-delete-hover: var(--ember-light-11);
--syntax-comment: var(--text-weaker);
--syntax-regexp: var(--text-base);
--syntax-string: #007663;
--syntax-keyword: var(--text-weak);
--syntax-primitive: #FB7F51;
--syntax-operator: var(--text-weak);
--syntax-variable: var(--text-strong);
--syntax-property: #EC6CC8;
--syntax-type: #738400;
--syntax-constant: #00B2B9;
--syntax-punctuation: var(--text-weaker);
--syntax-object: var(--text-strong);
--syntax-success: var(--apple-light-10);
--syntax-warning: var(--amber-light-10);
--syntax-critical: var(--ember-light-9);
--syntax-info: #0091A7;
--syntax-diff-add: var(--mint-light-11);
--syntax-diff-delete: var(--ember-light-11);
--syntax-diff-unknown: #FF0000;
--markdown-heading: #D68C27;
--markdown-text: #1A1A1A;
--markdown-link: #3B7DD8;
--markdown-link-text: #318795;
--markdown-code: #3D9A57;
--markdown-block-quote: #B0851F;
--markdown-emph: #B0851F;
--markdown-strong: #D68C27;
--markdown-horizontal-rule: #8A8A8A;
--markdown-list-item: #3B7DD8;
--markdown-list-enumeration: #318795;
--markdown-image: #3B7DD8;
--markdown-image-text: #318795;
--markdown-code-block: #1A1A1A;
--border-color: #FFFFFF;
--button-ghost-hover: var(--smoke-light-alpha-2);
--button-ghost-hover2: var(--smoke-light-alpha-3);
--v2-background-bg-base: var(--v2-grey-100);
--v2-background-bg-deep: var(--v2-grey-200);
--v2-background-bg-layer-01: var(--v2-grey-200);
--v2-background-bg-layer-02: var(--v2-grey-300);
--v2-background-bg-layer-03: var(--v2-grey-400);
--v2-background-bg-layer-04: var(--v2-grey-600);
--v2-background-bg-inverse: var(--v2-grey-1000);
--v2-background-bg-contrast: var(--v2-grey-900);
--v2-background-bg-button-neutral: var(--v2-grey-100);
--v2-background-bg-accent: var(--v2-blue-600);
--v2-text-text-base: var(--v2-grey-1000);
--v2-text-text-muted: var(--v2-grey-700);
--v2-text-text-faint: var(--v2-grey-600);
--v2-text-text-inverse: var(--v2-grey-100);
--v2-text-text-contrast: var(--v2-grey-100);
--v2-text-text-accent: var(--v2-blue-600);
--v2-text-text-accent-hover: var(--v2-blue-700);
--v2-icon-icon-base: var(--v2-grey-800);
--v2-icon-icon-muted: var(--v2-grey-600);
--v2-icon-icon-inverse: var(--v2-grey-100);
--v2-icon-icon-contrast: var(--v2-grey-200);
--v2-icon-icon-accent: var(--v2-blue-600);
--v2-icon-icon-accent-hover: var(--v2-blue-700);
--v2-border-border-muted: var(--v2-alpha-dark-8);
--v2-border-border-base: var(--v2-alpha-dark-10);
--v2-border-border-strong: var(--v2-alpha-dark-20);
--v2-border-border-inverse: var(--v2-grey-1000);
--v2-border-border-focus: var(--v2-blue-500);
--v2-overlay-simple-overlay-hover: var(--v2-alpha-dark-4);
--v2-overlay-simple-overlay-pressed: var(--v2-alpha-dark-8);
--v2-overlay-simple-overlay-contrast-hover: var(--v2-alpha-light-12);
--v2-overlay-simple-overlay-contrast-pressed: var(--v2-alpha-light-24);
--v2-overlay-simple-overlay-scrim: var(--v2-alpha-dark-40);
--v2-overlay-gradient-depth-overlay-depth-top: var(--v2-alpha-light-100);
--v2-overlay-gradient-depth-overlay-depth-bot: var(--v2-alpha-light-0);
--v2-overlay-simple-tab-active-scrim: #fafafa00;
--v2-overlay-simple-tab-hover-scrim: #eeeeee00;
--v2-overlay-simple-tab-scrim: #fafafa00;
--v2-state-bg-success: var(--v2-green-100);
--v2-state-fg-success: var(--v2-green-800);
--v2-state-border-success: var(--v2-green-300);
--v2-state-bg-warning: var(--v2-yellow-100);
--v2-state-fg-warning: var(--v2-yellow-800);
--v2-state-border-warning: var(--v2-yellow-300);
--v2-state-bg-danger: var(--v2-red-100);
--v2-state-fg-danger: var(--v2-red-800);
--v2-state-border-danger: var(--v2-red-300);
--v2-state-bg-info: var(--v2-blue-100);
--v2-state-fg-info: var(--v2-blue-800);
--v2-state-border-info: var(--v2-blue-300);

View File

@@ -0,0 +1,23 @@
#!/usr/bin/env bun
const colors = await Bun.file(import.meta.dir + "/colors.txt").text()
const variables = []
for (const line of colors.split("\n")) {
if (!line.trim()) continue
const [variable] = line.trim().split(":")
const name = variable!.trim().substring(2)
variables.push(`--color-${name}: var(--${name});`)
}
const output = `
/* Generated by script/tailwind.ts */
/* Do not edit this file manually */
@theme {
--color-*: initial;
${variables.join("\n ")}
}
`
await Bun.file(import.meta.dir + "/../src/styles/tailwind/colors.css").write(output.trim())

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Some files were not shown because too many files have changed in this diff Show More