chore: push all design docs, V2 plan specs, and current working state

Includes AirPlan design documents, AircOding-alpha1-plan, AirPlanV2,
AirPlan-ParaV2, AirPlan-Para V1 reference docs, and all working code
changes across packages.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
AirCoding
2026-06-12 17:12:29 +08:00
parent 8f55c962bb
commit ae44be31d5
364 changed files with 46779 additions and 2812 deletions

View File

@@ -14,7 +14,8 @@
"clean": "rm -rf dist tsconfig.tsbuildinfo"
},
"dependencies": {
"@aircoding/contracts": "workspace:*"
"@aircoding/contracts": "workspace:*",
"@aircoding/runtime": "workspace:*"
},
"devDependencies": {
"@types/node": "^25.9.1",

View File

@@ -64,12 +64,12 @@ async function main(): Promise<void> {
// Handle exit
process.on('SIGTERM', () => {
clearInterval(heartbeat_interval)
process.exit(0)
process.exit(4) // Parent cancelled
})
process.on('SIGINT', () => {
clearInterval(heartbeat_interval)
process.exit(0)
process.exit(4) // Parent cancelled
})
}

View File

@@ -7,6 +7,8 @@
*/
import { WorkerRuntime } from '../WorkerRuntime.js'
import { CompressionValidator } from '@aircoding/runtime'
import type { ValidationResult } from '@aircoding/runtime'
const SUMMARY_PREFIX = `This is a compacted summary of earlier context. Treat it as reference only.
The latest user message and any newer runtime events after this summary are the source of truth.
@@ -67,7 +69,41 @@ export class CompactorRole {
const target_after = Math.max(1, Math.floor(threshold * 0.6))
const source_content = compact_spec.source_content || `Current token estimate: ${token_estimate_before}; target budget: ${threshold}.`
const summary = await this.build_summary(source_content, token_estimate_before, threshold)
const first_summary = await this.build_summary(source_content, token_estimate_before, threshold)
// FR-014 / V2 §3.3.1: Validate compaction quality
const validator = new CompressionValidator()
const validation = validator.validate(source_content, first_summary)
let summary = first_summary
if (!validation.ok) {
this.runtime.checkpoint('compaction_validation_failed', {
task_id,
missing_patterns: validation.missing.map((m: ValidationResult['missing'][number]) => `${m.pattern}: lost ${m.lost_count}/${m.original_count}`),
})
// Retry once with explicit preservation instruction
const retry_content = `CRITICAL: The previous summary lost critical references. You MUST preserve:\n${validation.missing.map((m: ValidationResult['missing'][number]) => `- ${m.pattern}: ${m.lost.join(', ')}`).join('\n')}\n\nOriginal context:\n${source_content}`
const retry_summary = await this.build_summary(retry_content, token_estimate_before, threshold)
const retry_validation = validator.validate(source_content, retry_summary)
if (!retry_validation.ok) {
// Both attempts failed — preserve original context, mark as skipped
result.summary_content = source_content.slice(0, threshold * 4) // raw text, char estimate
result.status = 'skipped'
this.runtime.emit('context.compaction.validation_failed', {
event_id: `evt_compaction_fail_${crypto.randomUUID()}`,
task_id,
agent_id: process.env.AIRCODING_AGENT_ID || 'compactor',
range_start_message_id,
range_end_message_id,
error: { message: `Compaction validation failed after retry: ${retry_validation.missing.map((m: ValidationResult['missing'][number]) => m.pattern).join(', ')}` },
evidence_refs: [],
metadata: {},
})
return result
}
// Retry succeeded — use retry summary
summary = retry_summary
}
const summary_id = `summary_${crypto.randomUUID()}`
const token_estimate_after = Math.min(target_after, Math.max(1, Math.floor(summary.length / 4)))

View File

@@ -1,70 +0,0 @@
import { describe, expect, test } from 'bun:test'
import { ExecutorRole } from '../src/roles/ExecutorRole.js'
class NativeToolRuntime {
turns = 0
calls: Array<{ name: string; args: Record<string, unknown> }> = []
emit() {}
heartbeat() {}
checkpoint() {}
async call_llm() {
this.turns++
if (this.turns === 1) {
return { content: '', tool_calls: [{ id: 'tu_1', name: 'fs.write', arguments: { path: 'a.txt', content: 'X' } }] }
}
return { content: 'DONE' }
}
async call_tool(name: string, args: Record<string, unknown>) {
this.calls.push({ name, args })
return { call_id: 'c', type: 'text' as const, content: { ok: true } }
}
}
class VerificationFailRuntime {
turns = 0
checkpointed = false
emit() {}
heartbeat() {}
checkpoint() { this.checkpointed = true }
async call_llm() {
this.turns++
if (this.turns === 1) {
return { content: '', tool_calls: [{ id: 'tu_main', name: 'fs.write', arguments: { path: 'main.cpp', content: 'int main(){return 0;}' } }] }
}
return { content: 'DONE' }
}
async call_tool(name: string, _args: Record<string, unknown>) {
if (name === 'fs.write') return { call_id: 'w', type: 'text' as const, content: { ok: true } }
if (name === 'shell.run') return { call_id: 's', type: 'error' as const, content: { exit_code: 1, stderr: 'compile failed' } }
return { call_id: 'x', type: 'error' as const, content: { message: 'unexpected tool' } }
}
}
describe('ExecutorRole structured tool execution', () => {
test('executes native tool_calls instead of regex text parsing', async () => {
const runtime = new NativeToolRuntime()
const result = await new ExecutorRole(runtime as any).run({
id: 't1',
title: 'create file',
description: 'create a file',
acceptance_criteria: ['file exists'],
})
expect(result.status).toBe('completed')
expect(runtime.calls).toEqual([{ name: 'fs.write', args: { path: 'a.txt', content: 'X' } }])
})
test('does not complete executable tasks when verification fails', async () => {
const runtime = new VerificationFailRuntime()
const result = await new ExecutorRole(runtime as any).run({
id: 't2',
title: 'compile cpp',
description: 'write and compile C++',
acceptance_criteria: ['must compile'],
})
expect(result.status).not.toBe('completed')
expect(runtime.checkpointed).toBe(false)
expect(result.changes).toEqual([{ file: 'main.cpp', type: 'create' }])
})
})

View File

@@ -1,11 +1,8 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src"
"skipLibCheck": true,
"outDir": "./dist"
},
"include": ["src"],
"references": [
{ "path": "../contracts" }
]
"include": ["src/**/*"]
}