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:
275
AirPlan/docs/spec/AirPlan-ParaV2/plugins/airdbg/scripts/airdbg_mode.py
Executable file
275
AirPlan/docs/spec/AirPlan-ParaV2/plugins/airdbg/scripts/airdbg_mode.py
Executable file
@@ -0,0 +1,275 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Bootstrap AirDbg debugging context files."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from typing import Dict, Tuple
|
||||
|
||||
MARKER_BEGIN = "<!-- AIRDBG:BEGIN -->"
|
||||
MARKER_END = "<!-- AIRDBG:END -->"
|
||||
|
||||
|
||||
def now_iso() -> str:
|
||||
return datetime.now(timezone.utc).isoformat()
|
||||
|
||||
|
||||
def airdbg_agents_block() -> str:
|
||||
return f"""{MARKER_BEGIN}
|
||||
## AirDbg Debug Workflow
|
||||
|
||||
1. Use AirDbg for `/airdbg` debugging and repair sessions.
|
||||
2. Before fixing, load project context:
|
||||
- `AirPlan/AGENTS.md`
|
||||
- `AirPlan/docs/architecture/adr/`
|
||||
- `AirPlan/docs/architecture/c4/module.md`
|
||||
- `AirPlan/docs/debug/debug-log.md`
|
||||
3. Reproduce the issue before changing code whenever feasible.
|
||||
4. Identify root cause, then apply the smallest verifiable fix.
|
||||
5. Record reproduction, root cause, fix, validation, and residual risk in `AirPlan/docs/debug/debug-log.md`.
|
||||
6. When debugging needs graphical comparison, screenshots, GUI operation, browser/desktop UI, canvas, layout, focus, popup, or visual evidence, call AirXDB for screenshots, GUI exploration, or operation validation.
|
||||
7. For every local or remote GUI test or validation, do not treat process liveness, window launch, command success, or clean logs as a pass; require image/GUI evidence plus at least one GUI operation or state check. If screenshots are not diagnostically useful, such as many embedded-screen or display-pipeline scenarios, record equivalent screen evidence instead.
|
||||
8. If the GUI target is a remote device, test machine, VM, server, or SSH host, call the AirXDB remote device helper before local Computer MCP; it should probe SSH, auto-configure missing remote screenshot tools when possible, and save evidence under `AirPlan/docs/debug/airxdb-artifacts/`.
|
||||
9. When debugging needs packet capture, pcap reading, BPF filters, DNS/TCP/UDP/TLS/HTTP connectivity, ports, proxy, firewall, packet loss, retransmits, resets, or latency evidence, call AirNDB.
|
||||
10. If the network target is a remote device, test machine, VM, container host, server, or SSH host, call the AirNDB remote device helper before local capture; it should probe SSH, auto-configure missing remote tcpdump/dumpcap when possible, and save evidence under `AirPlan/docs/network/airndb-captures/`.
|
||||
11. When debugging needs C/C++ static analysis, cppcheck, code quality, security-relevant findings, CWE, null pointer, bounds, resource, conversion, uninitialized-variable evidence, or static-analysis capability to support validation, call AirSDB and read `AirPlan/docs/staticanalysis.md` plus XML/JSON artifacts when helpful.
|
||||
12. If the static-analysis target is a remote device, test machine, VM, container host, server, or SSH host, call the AirSDB remote device helper before local cppcheck; it should probe SSH, auto-configure missing remote cppcheck when possible, and maintain `staticanalysis.md`.
|
||||
13. Record AirXDB, AirNDB, and AirSDB commands, remote target when applicable, screenshot/pcap/staticanalysis/report paths, observations, and how they relate to root cause in `AirPlan/docs/debug/debug-log.md`.
|
||||
14. Update ADR records when a fix changes long-term behavior, contracts, dependencies, data ownership, error handling, GUI automation boundaries, remote-device boundaries, network boundaries, static-analysis boundaries, or architecture decisions.
|
||||
15. Update C4 module docs when module boundaries, dependencies, public interfaces, data ownership, GUI automation, local/remote screenshot evidence, local/remote packet capture, static-analysis evidence, network observability, or visual validation boundaries change.
|
||||
16. Keep ADRs concise because they are AI context records.
|
||||
{MARKER_END}
|
||||
"""
|
||||
|
||||
|
||||
def c4_module_template() -> str:
|
||||
return """# C4 Module
|
||||
|
||||
## System Context
|
||||
- TODO: Describe the system, users, and important external systems.
|
||||
|
||||
## Containers
|
||||
- TODO: Describe deployable/runtime units.
|
||||
|
||||
## Modules
|
||||
|
||||
| Module | Responsibility | Public Interfaces | Dependencies | Data Ownership | Debug-Relevant Notes |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| TODO | TODO | TODO | TODO | TODO | TODO |
|
||||
|
||||
## Error and Observability Flow
|
||||
- TODO: Describe where errors are raised, logged, retried, surfaced, or recovered.
|
||||
|
||||
## GUI / Visual Debug Boundaries
|
||||
- AirXDB screenshot evidence, GUI operation checks, graphical comparison, or visual validation used in debugging: TODO
|
||||
- AirXDB remote device evidence, SSH target, remote screenshot tool, or remote display constraints used in debugging: TODO
|
||||
- Browser bridge, desktop control, canvas, focus, popup, layout, or multi-display constraints relevant to defects: TODO
|
||||
|
||||
## Network / Packet Debug Boundaries
|
||||
- AirNDB pcap evidence, tcpdump/WinDump commands, BPF filters, packet summaries, or network validation used in debugging: TODO
|
||||
- AirNDB remote device evidence, SSH target, remote tcpdump/dumpcap tool, or remote capture permissions used in debugging: TODO
|
||||
- DNS, TCP, UDP, TLS, HTTP, proxy, firewall, port, NAT, WSL/container/VM/host network constraints relevant to defects: TODO
|
||||
|
||||
## Static Analysis Boundaries
|
||||
- AirSDB cppcheck evidence, staticanalysis.md entries, XML/JSON reports, suppressions, or quality gates used in debugging: TODO
|
||||
- AirSDB remote device evidence, SSH target, remote cppcheck tool, or remote static-analysis permissions used in debugging: TODO
|
||||
|
||||
## Change Log
|
||||
- TODO: Record module-boundary changes caused by fixes.
|
||||
"""
|
||||
|
||||
|
||||
def adr_template() -> str:
|
||||
return """# ADR-0001: AirDbg Debug Context Governance
|
||||
|
||||
- Status: Accepted
|
||||
- Date: TODO
|
||||
|
||||
## Context
|
||||
Debugging sessions need durable AI-readable context so future fixes can understand prior decisions.
|
||||
|
||||
## Decision
|
||||
Use AirDbg to maintain `AirPlan/AGENTS.md`, `AirPlan/docs/architecture/c4/module.md`, `AirPlan/docs/architecture/adr/`, and `AirPlan/docs/debug/debug-log.md` during repair work.
|
||||
When debugging requires graphical comparison, screenshots, GUI operations, or visual evidence, use AirXDB for evidence gathering and operation validation, then return to AirDbg for root-cause analysis and focused repair. If the GUI target is remote, use AirXDB's remote device helper before local Computer MCP so SSH and remote screenshot tooling are checked or auto-configured.
|
||||
Do not treat process liveness, window launch, command success, or clean logs as sufficient proof for a GUI pass. Require image/GUI evidence and a GUI operation or state check for every local or remote GUI validation. If screenshots are not diagnostically useful, such as many embedded-screen or display-pipeline scenarios, record equivalent screen evidence and why screenshots were skipped.
|
||||
When debugging requires packet capture, pcap analysis, DNS/TCP/UDP/TLS/HTTP connectivity evidence, ports, proxy, firewall, retransmits, resets, or latency analysis, use AirNDB for bounded network evidence, then return to AirDbg for root-cause analysis and focused repair. If the network target is remote, use AirNDB's remote device helper before local capture so SSH and remote tcpdump/dumpcap are checked or auto-configured.
|
||||
When debugging requires C/C++ static analysis, cppcheck, code quality, security-relevant findings, CWE evidence, or static-analysis capability to support validation, use AirSDB for local or remote static-analysis evidence and `staticanalysis.md` context, then return to AirDbg for root-cause analysis and focused repair.
|
||||
|
||||
## Consequences
|
||||
- Fixes carry reproducible context across sessions.
|
||||
- Architecture-impacting repairs must update ADR and C4 module docs.
|
||||
- ADRs stay concise and focused on decisions.
|
||||
- GUI evidence and graphical operation results are linked to root cause and validation records.
|
||||
- Embedded-screen or display-pipeline cases that skip screenshots still record equivalent screen evidence and the reason screenshots were not useful.
|
||||
- Network packet evidence and pcap summaries are linked to root cause and validation records.
|
||||
- Static-analysis evidence and staticanalysis.md summaries are linked to root cause and validation records.
|
||||
- Remote-device SSH targets, auto-configuration outcomes, and permission limits are recorded when they affect debugging.
|
||||
|
||||
## Alternatives
|
||||
- Chat-only debugging notes: rejected because context is easy to lose.
|
||||
"""
|
||||
|
||||
|
||||
def debug_log_template() -> str:
|
||||
return """# Debug Log
|
||||
|
||||
Append entries for AirDbg sessions.
|
||||
|
||||
## Entry Template
|
||||
|
||||
### YYYY-MM-DD: short problem title
|
||||
|
||||
- Symptom: TODO
|
||||
- Expected: TODO
|
||||
- Actual: TODO
|
||||
- Reproduction: TODO
|
||||
- Root cause: TODO
|
||||
- AirXDB local/remote evidence: TODO
|
||||
- AirNDB local/remote evidence: TODO
|
||||
- AirSDB local/remote static-analysis evidence: TODO
|
||||
- Fix: TODO
|
||||
- Validation: TODO
|
||||
- ADR/C4 updates: TODO
|
||||
- Residual risk: TODO
|
||||
"""
|
||||
|
||||
|
||||
def write_if_missing(path: Path, content: str) -> bool:
|
||||
if path.exists():
|
||||
return False
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(content, encoding="utf-8", newline="\n")
|
||||
return True
|
||||
|
||||
|
||||
def upsert_agents_md(path: Path) -> str:
|
||||
block = airdbg_agents_block().rstrip() + "\n"
|
||||
|
||||
if path.exists():
|
||||
original = path.read_text(encoding="utf-8")
|
||||
existed = True
|
||||
else:
|
||||
original = "# AGENTS.md\n\n"
|
||||
existed = False
|
||||
|
||||
begin = original.find(MARKER_BEGIN)
|
||||
end = original.find(MARKER_END)
|
||||
|
||||
if begin >= 0 and end > begin:
|
||||
end += len(MARKER_END)
|
||||
updated = original[:begin].rstrip() + "\n\n" + block + original[end:].lstrip()
|
||||
status = "updated"
|
||||
else:
|
||||
updated = original.rstrip() + "\n\n" + block
|
||||
status = "updated" if existed else "created"
|
||||
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(updated, encoding="utf-8", newline="\n")
|
||||
return status
|
||||
|
||||
|
||||
def artifact_map(project_root: Path) -> Dict[str, Path]:
|
||||
return {
|
||||
"AGENTS.md": project_root / "AirPlan" / "AGENTS.md",
|
||||
"c4_module": project_root / "AirPlan" / "docs" / "architecture" / "c4" / "module.md",
|
||||
"adr_dir": project_root / "AirPlan" / "docs" / "architecture" / "adr",
|
||||
"adr_0001": project_root / "AirPlan" / "docs" / "architecture" / "adr" / "ADR-0001-airdbg-debug-context-governance.md",
|
||||
"debug_log": project_root / "AirPlan" / "docs" / "debug" / "debug-log.md",
|
||||
"state": project_root / "AirPlan" / "state" / "airdbg" / "state.json",
|
||||
}
|
||||
|
||||
|
||||
def write_state(path: Path, enabled: bool, project_root: Path) -> None:
|
||||
artifacts = artifact_map(project_root)
|
||||
health = {
|
||||
name: artifacts[name].exists()
|
||||
for name in [
|
||||
"AGENTS.md",
|
||||
"c4_module",
|
||||
"adr_dir",
|
||||
"adr_0001",
|
||||
"debug_log",
|
||||
]
|
||||
}
|
||||
|
||||
payload = {
|
||||
"enabled": enabled,
|
||||
"updatedAt": now_iso(),
|
||||
"projectRoot": str(project_root),
|
||||
"artifactHealth": health,
|
||||
}
|
||||
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8")
|
||||
|
||||
|
||||
def enter_mode(project_root: Path) -> Tuple[str, Dict[str, str]]:
|
||||
artifacts = artifact_map(project_root)
|
||||
results: Dict[str, str] = {}
|
||||
|
||||
results["AGENTS.md"] = upsert_agents_md(artifacts["AGENTS.md"])
|
||||
results["c4_module"] = "created" if write_if_missing(artifacts["c4_module"], c4_module_template()) else "exists"
|
||||
artifacts["adr_dir"].mkdir(parents=True, exist_ok=True)
|
||||
results["adr_dir"] = "exists"
|
||||
results["adr_0001"] = "created" if write_if_missing(artifacts["adr_0001"], adr_template()) else "exists"
|
||||
results["debug_log"] = "created" if write_if_missing(artifacts["debug_log"], debug_log_template()) else "exists"
|
||||
|
||||
write_state(artifacts["state"], True, project_root)
|
||||
return "enabled", results
|
||||
|
||||
|
||||
def exit_mode(project_root: Path) -> Tuple[str, Dict[str, str]]:
|
||||
artifacts = artifact_map(project_root)
|
||||
write_state(artifacts["state"], False, project_root)
|
||||
return "disabled", {}
|
||||
|
||||
|
||||
def status_mode(project_root: Path) -> Tuple[str, Dict[str, str]]:
|
||||
artifacts = artifact_map(project_root)
|
||||
state_file = artifacts["state"]
|
||||
|
||||
enabled = False
|
||||
if state_file.exists():
|
||||
try:
|
||||
payload = json.loads(state_file.read_text(encoding="utf-8"))
|
||||
enabled = bool(payload.get("enabled"))
|
||||
except json.JSONDecodeError:
|
||||
enabled = False
|
||||
|
||||
results = {
|
||||
name: ("ok" if path.exists() else "missing")
|
||||
for name, path in artifacts.items()
|
||||
if name != "state"
|
||||
}
|
||||
return ("enabled" if enabled else "disabled"), results
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Manage AirDbg project artifacts.")
|
||||
parser.add_argument("--mode", choices=["enter", "exit", "status"], default="enter")
|
||||
parser.add_argument("--project", default=".")
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args = parse_args()
|
||||
project_root = Path(args.project).expanduser().resolve()
|
||||
|
||||
if args.mode == "enter":
|
||||
mode_state, result = enter_mode(project_root)
|
||||
elif args.mode == "exit":
|
||||
mode_state, result = exit_mode(project_root)
|
||||
else:
|
||||
mode_state, result = status_mode(project_root)
|
||||
|
||||
print(f"airdbg_mode={mode_state}")
|
||||
print(f"project_root={project_root}")
|
||||
for key, value in result.items():
|
||||
print(f"{key}={value}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Install the AirDbg plugin into the current user's home-local plugin directory."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict
|
||||
|
||||
PLUGIN_NAME = "airdbg"
|
||||
|
||||
|
||||
def copy_plugin(source: Path, target: Path) -> None:
|
||||
if source.resolve() == target.resolve():
|
||||
return
|
||||
if target.exists():
|
||||
shutil.rmtree(target)
|
||||
ignore = shutil.ignore_patterns("__pycache__", "*.pyc", ".DS_Store", ".git")
|
||||
shutil.copytree(source, target, ignore=ignore)
|
||||
|
||||
|
||||
def marketplace_payload() -> Dict[str, Any]:
|
||||
return {
|
||||
"name": "local-airdbg",
|
||||
"interface": {"displayName": "Local AirDbg Plugins"},
|
||||
"plugins": [],
|
||||
}
|
||||
|
||||
|
||||
def update_marketplace(path: Path) -> None:
|
||||
if path.exists():
|
||||
payload = json.loads(path.read_text(encoding="utf-8"))
|
||||
else:
|
||||
payload = marketplace_payload()
|
||||
|
||||
payload.setdefault("name", "local-airdbg")
|
||||
payload.setdefault("interface", {}).setdefault("displayName", "Local AirDbg Plugins")
|
||||
plugins = payload.setdefault("plugins", [])
|
||||
|
||||
entry = {
|
||||
"name": PLUGIN_NAME,
|
||||
"source": {
|
||||
"source": "local",
|
||||
"path": f"./plugins/{PLUGIN_NAME}",
|
||||
},
|
||||
"policy": {
|
||||
"installation": "INSTALLED_BY_DEFAULT",
|
||||
"authentication": "ON_INSTALL",
|
||||
},
|
||||
"category": "Productivity",
|
||||
}
|
||||
|
||||
for index, existing in enumerate(plugins):
|
||||
if existing.get("name") == PLUGIN_NAME:
|
||||
plugins[index] = entry
|
||||
break
|
||||
else:
|
||||
plugins.append(entry)
|
||||
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8")
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Install AirDbg as a home-local Codex plugin.")
|
||||
parser.add_argument("--source", default=str(Path(__file__).resolve().parents[1]))
|
||||
parser.add_argument("--home", default=str(Path.home()))
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args = parse_args()
|
||||
source = Path(args.source).expanduser().resolve()
|
||||
home = Path(args.home).expanduser().resolve()
|
||||
target = home / "plugins" / PLUGIN_NAME
|
||||
marketplace = home / ".agents" / "plugins" / "marketplace.json"
|
||||
|
||||
copy_plugin(source, target)
|
||||
update_marketplace(marketplace)
|
||||
|
||||
print(f"installed_plugin={target}")
|
||||
print(f"marketplace={marketplace}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user