Initial release: airdo
This commit is contained in:
42
.claude-plugin/plugin.json
Normal file
42
.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"name": "airdo",
|
||||||
|
"version": "0.5.0",
|
||||||
|
"description": "AirDo is the public execution plugin for one scoped task slice. It is designed to run standalone or as an isolated AirEng subagent and to finalize structured results into AirPlan.",
|
||||||
|
"author": {
|
||||||
|
"name": "14816",
|
||||||
|
"email": "noreply@example.com",
|
||||||
|
"url": "https://airlongdian.fun"
|
||||||
|
},
|
||||||
|
"homepage": "https://airlongdian.fun/plugins/airdo",
|
||||||
|
"repository": "http://git.airlongdian.fun/admin/airdo.git",
|
||||||
|
"license": "MIT",
|
||||||
|
"keywords": [
|
||||||
|
"airdo",
|
||||||
|
"executor",
|
||||||
|
"subagent",
|
||||||
|
"todo",
|
||||||
|
"validation"
|
||||||
|
],
|
||||||
|
"skills": "./skills/",
|
||||||
|
"interface": {
|
||||||
|
"displayName": "AirDo",
|
||||||
|
"shortDescription": "Execute one scoped task and finalize a structured result",
|
||||||
|
"longDescription": "AirDo is the public execution plugin for one narrow task slice. It can be run directly or launched by AirEng as a fully isolated subagent, auto-routes GUI work into AirXDB, auto-routes blockers into AirDbg, and finalizes one structured result in AirPlan for AirEng to merge.",
|
||||||
|
"developerName": "14816",
|
||||||
|
"category": "Productivity",
|
||||||
|
"capabilities": [
|
||||||
|
"Interactive",
|
||||||
|
"Write"
|
||||||
|
],
|
||||||
|
"websiteURL": "https://airlongdian.fun/plugins/airdo",
|
||||||
|
"privacyPolicyURL": "https://openai.com/policies/row-privacy-policy/",
|
||||||
|
"termsOfServiceURL": "https://openai.com/policies/row-terms-of-use/",
|
||||||
|
"defaultPrompt": [
|
||||||
|
"Use AirDo to start one scoped task from AirPlan/todo.md and create a structured result template.",
|
||||||
|
"Use AirDo to execute a handoff in an isolated subagent context and finalize the AirPlan result.",
|
||||||
|
"Use AirDo to continue from a repair brief until fixed or a real blocker remains."
|
||||||
|
],
|
||||||
|
"brandColor": "#2563EB",
|
||||||
|
"screenshots": []
|
||||||
|
}
|
||||||
|
}
|
||||||
38
commands/airdo.md
Normal file
38
commands/airdo.md
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
description: Start, inspect, hand off, or finish one scoped AirDo task slice with automatic AirXDB/AirDbg routing and AirPlan result finalization
|
||||||
|
argument-hint: [enter|status|handoff|finish]
|
||||||
|
allowed-tools: [Read, Glob, Grep, Bash, Write, Edit]
|
||||||
|
---
|
||||||
|
|
||||||
|
# /airdo
|
||||||
|
|
||||||
|
Use AirDo for one narrow execution slice. It can run directly in the parent thread, but it is primarily designed to be launched as an isolated AirEng subagent.
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
|
||||||
|
1. Parse `$ARGUMENTS`; default to `status` when empty.
|
||||||
|
2. Always operate from the current project root and store worker state under `AirPlan/state/airdo/`.
|
||||||
|
3. Run the matching mode:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python "$HOME/plugins/airdo/scripts/airdo_mode.py" --mode <enter|status|handoff|finish> --project . --task-id <task-id>
|
||||||
|
```
|
||||||
|
|
||||||
|
4. For `enter` or `handoff`, load:
|
||||||
|
- `AirPlan/AGENTS.md`
|
||||||
|
- `AirPlan/docs/architecture/adr/`
|
||||||
|
- `AirPlan/docs/architecture/c4/module.md`
|
||||||
|
- `AirPlan/plan.md`
|
||||||
|
- `AirPlan/todo.md`
|
||||||
|
- `AirPlan/state/airdo/tasks/<task-id>/brief.md`
|
||||||
|
|
||||||
|
5. When AirDo is invoked as an AirEng child:
|
||||||
|
- Treat the session as isolated and rebuild context only from the files above.
|
||||||
|
- Stay inside the task write scope from the brief/handoff.
|
||||||
|
- Finalize exactly one structured result under `AirPlan/state/airdo/results/<task-id>.json`.
|
||||||
|
- Treat `AirPlan/state/airdo/tasks/<task-id>/worker-state.json` `resultPath` as the canonical pointer to the latest result artifact. Do not assume the task-local template `result.json` is the finalized output.
|
||||||
|
- Do not stop at "准备实施", implementation-plan-only, or generic progress replies when the task is actionable. Continue editing, validating, and finalizing unless a real blocker or user decision is required.
|
||||||
|
- When the task changes planning or architecture reality, include concrete `documentUpdates` for `AirPlan/plan.md`, `AirPlan/docs/architecture/adr/`, and `AirPlan/docs/architecture/c4/module.md` instead of leaving those docs stale.
|
||||||
|
|
||||||
|
6. On GUI-like work, route acceptance through AirXDB before finishing.
|
||||||
|
7. On blockers or failed validation, route through AirDbg, continue through active repair briefs when present, and return one structured result for AirEng to merge.
|
||||||
80
scripts/airdo_mode.py
Normal file
80
scripts/airdo_mode.py
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def _add_lib_path() -> None:
|
||||||
|
root = Path(__file__).resolve().parents[3]
|
||||||
|
lib_path = root / "lib"
|
||||||
|
if str(lib_path) not in sys.path:
|
||||||
|
sys.path.insert(0, str(lib_path))
|
||||||
|
|
||||||
|
|
||||||
|
_add_lib_path()
|
||||||
|
|
||||||
|
from air_runtime.worker import enter_worker, finish_worker, handoff_worker, status_worker
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args() -> argparse.Namespace:
|
||||||
|
parser = argparse.ArgumentParser(description="AirDo public worker runtime")
|
||||||
|
parser.add_argument("--mode", choices=["enter", "status", "handoff", "finish"], default="status")
|
||||||
|
parser.add_argument("--project", default=".")
|
||||||
|
parser.add_argument("--task-id", default="")
|
||||||
|
parser.add_argument("--result", default="")
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
args = parse_args()
|
||||||
|
project_root = Path(args.project).expanduser().resolve()
|
||||||
|
|
||||||
|
if args.mode == "status":
|
||||||
|
status = status_worker(project_root)
|
||||||
|
print(f"airdo_mode={'enabled' if status['enabled'] else 'disabled'}")
|
||||||
|
print(f"project_root={project_root}")
|
||||||
|
print(f"active_task_id={status['activeTaskId']}")
|
||||||
|
print(f"known_tasks={','.join(status['taskIds'])}")
|
||||||
|
for key, value in status["artifactHealth"].items():
|
||||||
|
print(f"{key}={'ok' if value else 'missing'}")
|
||||||
|
return
|
||||||
|
|
||||||
|
if not args.task_id:
|
||||||
|
raise SystemExit("--task-id is required for enter, handoff, and finish modes")
|
||||||
|
|
||||||
|
if args.mode == "enter":
|
||||||
|
result = enter_worker(project_root, args.task_id)
|
||||||
|
print("airdo_mode=entered")
|
||||||
|
print(f"project_root={project_root}")
|
||||||
|
print(f"task_id={result['taskId']}")
|
||||||
|
print(f"brief_path={result['briefPath']}")
|
||||||
|
print(f"handoff_path={result['handoffPath']}")
|
||||||
|
print(f"result_path={result['resultPath']}")
|
||||||
|
print(f"worker_state_path={result['workerStatePath']}")
|
||||||
|
return
|
||||||
|
|
||||||
|
if args.mode == "handoff":
|
||||||
|
result = handoff_worker(project_root, args.task_id)
|
||||||
|
print("airdo_mode=handoff-ready")
|
||||||
|
print(f"project_root={project_root}")
|
||||||
|
print(f"task_id={result['taskId']}")
|
||||||
|
print(f"brief_path={result['briefPath']}")
|
||||||
|
print(f"handoff_path={result['handoffPath']}")
|
||||||
|
print(f"result_path={result['resultPath']}")
|
||||||
|
print(f"worker_state_path={result['workerStatePath']}")
|
||||||
|
return
|
||||||
|
|
||||||
|
result_path = Path(args.result).expanduser().resolve() if args.result else None
|
||||||
|
finalized = finish_worker(project_root, args.task_id, result_path)
|
||||||
|
print("airdo_mode=finished")
|
||||||
|
print(f"project_root={project_root}")
|
||||||
|
print(f"task_id={finalized['taskId']}")
|
||||||
|
print(f"task_status={finalized['status']}")
|
||||||
|
print(f"finalized_result_path={finalized['finalizedResultPath']}")
|
||||||
|
print(f"worker_state_path={finalized['workerStatePath']}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
47
skills/airdo/SKILL.md
Normal file
47
skills/airdo/SKILL.md
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
---
|
||||||
|
name: airdo
|
||||||
|
description: Public Air executor for one scoped todo slice. Use it standalone or as an isolated AirEng subagent and finalize the result into AirPlan.
|
||||||
|
---
|
||||||
|
|
||||||
|
# AirDo
|
||||||
|
|
||||||
|
## Role
|
||||||
|
|
||||||
|
- Execute one task or one very small implementation slice.
|
||||||
|
- Keep AirDo execution guarantees for context loading, evidence, and validation.
|
||||||
|
- Finalize one structured result package in `AirPlan/state/airdo/results/`.
|
||||||
|
- Act as the standard AirEng child executor when work is delegated into isolated subagents.
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
- `AirPlan/AGENTS.md`
|
||||||
|
- `AirPlan/docs/architecture/adr/`
|
||||||
|
- `AirPlan/docs/architecture/c4/module.md`
|
||||||
|
- `AirPlan/plan.md`
|
||||||
|
- `AirPlan/todo.md`
|
||||||
|
- `AirPlan/state/airdo/tasks/<task-id>/brief.md`
|
||||||
|
- `AirPlan/state/airdo/tasks/<task-id>/subagent-handoff.md` when launched by AirEng
|
||||||
|
|
||||||
|
## Result Rules
|
||||||
|
|
||||||
|
- Finalize one `result.json` per task.
|
||||||
|
- Treat `AirPlan/state/airdo/tasks/<task-id>/worker-state.json` `resultPath` as the canonical pointer to the latest result artifact. The task-local `result.json` is only the editable template before finalize.
|
||||||
|
- Include validations, evidence, risks, blockers, and document updates when needed.
|
||||||
|
- Do not edit global `AirPlan/todo.md`, `AirPlan/AGENTS.md`, ADR, or C4 files directly unless explicitly delegated through `documentUpdates`.
|
||||||
|
- If the task changes execution planning or architecture reality, include concrete `documentUpdates` so AirEng can keep `todo`, `plan`, ADR, and C4 synchronized during merge.
|
||||||
|
|
||||||
|
## Automatic Routing
|
||||||
|
|
||||||
|
- On `blocked` results, auto-request AirDbg before finalize.
|
||||||
|
- On GUI or visual work, auto-request AirXDB before finalize.
|
||||||
|
- If AirEng queued an active repair attempt, continue repairing automatically instead of stopping at the first blocker.
|
||||||
|
- Do not stop at implementation-prep or progress-only updates when the task is actionable. Continue until finalize unless a real blocker or explicit user decision is required.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python "$HOME/plugins/airdo/scripts/airdo_mode.py" --mode enter --project <project-root> --task-id T-001
|
||||||
|
python "$HOME/plugins/airdo/scripts/airdo_mode.py" --mode status --project <project-root>
|
||||||
|
python "$HOME/plugins/airdo/scripts/airdo_mode.py" --mode handoff --project <project-root> --task-id T-001
|
||||||
|
python "$HOME/plugins/airdo/scripts/airdo_mode.py" --mode finish --project <project-root> --task-id T-001
|
||||||
|
```
|
||||||
3
skills/airdo/agents/openai.yaml
Normal file
3
skills/airdo/agents/openai.yaml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
name: airdo
|
||||||
|
short_description: Public Air executor for one scoped task, validation evidence, and AirPlan result finalization
|
||||||
|
default_prompt: "Use AirDo to execute one task, gather validation evidence, auto-route GUI or debug work, and finalize a structured result in AirPlan for AirEng to merge. Do not stop at implementation-prep or progress-only updates when the task is actionable; continue until finalize unless a real blocker or explicit user decision is required."
|
||||||
Reference in New Issue
Block a user