Files
wehub-resource-sync 2c632336aa
CI / Viewer CI (push) Successful in 13m37s
CI / Core CI (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:32:38 +08:00

101 lines
3.6 KiB
Python

from __future__ import annotations
import argparse
from pathlib import Path
from agent.record_persistence import create_draft_record
from cli.common import add_data_root_argument, storage_repo_from_args
from storage.identifiers import validate_category_slug, validate_record_id
from storage.library_manifest import upsert_record
def _build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(prog="articraft external")
add_data_root_argument(parser)
subparsers = parser.add_subparsers(dest="command", required=True)
init = subparsers.add_parser("init", help="Create an external-agent draft record.")
init.add_argument("prompt")
init.add_argument("--agent", choices=("codex", "claude-code", "cursor"), default="codex")
init.add_argument("--record-id", default=None)
init.add_argument("--label", default=None)
init.add_argument("--tag", dest="tags", action="append", default=None)
finalize = subparsers.add_parser("finalize", help="Finalize a local external-agent record.")
finalize.add_argument("record")
finalize.add_argument("--category-slug", default=None)
subparsers.add_parser("categories", help="List local categories.")
return parser
def _resolve_record_id(repo, record_ref: str) -> str:
candidate = Path(record_ref).expanduser()
if candidate.exists():
resolved = candidate.resolve()
records_root = repo.layout.records_root.resolve()
try:
relative = resolved.relative_to(records_root)
except ValueError as exc:
raise ValueError(f"Record path must be inside {records_root}") from exc
if len(relative.parts) != 1 or not resolved.is_dir():
raise ValueError(f"Record path must point to a direct child of {records_root}")
return validate_record_id(relative.parts[0])
return validate_record_id(record_ref)
def main(argv: list[str] | None = None) -> int:
parser = _build_parser()
args = parser.parse_args(argv)
repo = storage_repo_from_args(args)
repo.ensure_layout()
if args.command == "init":
try:
record_dir = create_draft_record(
repo_root=args.repo_root,
data_root=repo.layout.data_root,
prompt_text=args.prompt,
record_id=args.record_id,
label=args.label,
tags=list(args.tags or []),
external_agent=args.agent,
)
except Exception as exc:
print(str(exc))
return 1
print(f"record_id={record_dir.name}")
print(f"record_dir={record_dir}")
return 0
if args.command == "finalize":
try:
record_id = _resolve_record_id(repo, args.record)
record_path = repo.layout.record_metadata_path(record_id)
record = repo.read_json(record_path)
if not isinstance(record, dict):
raise ValueError(f"Record not found: {record_id}")
if args.category_slug:
record["category_slug"] = validate_category_slug(args.category_slug)
repo.write_json(record_path, record)
upsert_record(repo, record_id)
except Exception as exc:
print(str(exc))
return 1
print(f"finalized record_id={record_id}")
return 0
if args.command == "categories":
root = repo.layout.categories_root
if root.exists():
for path in sorted(item for item in root.iterdir() if item.is_dir()):
print(path.name)
return 0
parser.error(f"Unsupported command: {args.command}")
return 2
if __name__ == "__main__":
raise SystemExit(main())