agent-toolkit-cli 1.11.0__py3-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agent_toolkit/__init__.py +4 -0
- agent_toolkit/__main__.py +5 -0
- agent_toolkit/_paths.py +145 -0
- agent_toolkit/bin/.gitkeep +0 -0
- agent_toolkit/bin/agent-toolkit.exe +0 -0
- agent_toolkit/cli/__init__.py +0 -0
- agent_toolkit/cli/__main__.py +5 -0
- agent_toolkit/cli/build.py +278 -0
- agent_toolkit/cli/completion.py +297 -0
- agent_toolkit/cli/context_budget.py +455 -0
- agent_toolkit/cli/devcompanion.py +923 -0
- agent_toolkit/cli/devcompanion_queue.py +235 -0
- agent_toolkit/cli/diff.py +176 -0
- agent_toolkit/cli/doctor.py +1052 -0
- agent_toolkit/cli/insights.py +771 -0
- agent_toolkit/cli/install.py +706 -0
- agent_toolkit/cli/main.py +171 -0
- agent_toolkit/cli/mcp.py +537 -0
- agent_toolkit/cli/memory.py +739 -0
- agent_toolkit/cli/plugin.py +224 -0
- agent_toolkit/cli/project.py +459 -0
- agent_toolkit/cli/release.py +178 -0
- agent_toolkit/cli/skills.py +461 -0
- agent_toolkit/cli/uninstall.py +166 -0
- agent_toolkit/cli/update.py +298 -0
- agent_toolkit/cli/workspace.py +1713 -0
- agent_toolkit/compiler/hook_registry.py +110 -0
- agent_toolkit/compiler/loader.py +338 -0
- agent_toolkit/compiler/mcp_registry.py +87 -0
- agent_toolkit/compiler/model.py +182 -0
- agent_toolkit/compiler/provenance.py +140 -0
- agent_toolkit/compiler/registry_emit.py +263 -0
- agent_toolkit/compiler/target_registry.py +122 -0
- agent_toolkit/compiler/targets/__init__.py +1 -0
- agent_toolkit/compiler/targets/agent_plugins.py +160 -0
- agent_toolkit/compiler/targets/base.py +229 -0
- agent_toolkit/compiler/targets/claude_code.py +241 -0
- agent_toolkit/compiler/targets/codex.py +261 -0
- agent_toolkit/compiler/targets/copilot.py +275 -0
- agent_toolkit/compiler/targets/cursor.py +207 -0
- agent_toolkit/compiler/targets/gemini_cli.py +213 -0
- agent_toolkit/compiler/targets/muse_code.py +113 -0
- agent_toolkit/compiler/targets/opencode.py +204 -0
- agent_toolkit/compiler/targets/pi.py +263 -0
- agent_toolkit/compiler/targets/windsurf.py +267 -0
- agent_toolkit/compiler/tool_mapping.py +83 -0
- agent_toolkit/data/.gitignore +4 -0
- agent_toolkit/data/__init__.py +1 -0
- agent_toolkit/data/agents/agentic-security-reviewer/AGENT.md +60 -0
- agent_toolkit/data/agents/architect/AGENT.md +30 -0
- agent_toolkit/data/agents/assistant/AGENT.md +59 -0
- agent_toolkit/data/agents/build-error-resolver/AGENT.md +30 -0
- agent_toolkit/data/agents/client-workflow-bootstrap/AGENT.md +60 -0
- agent_toolkit/data/agents/code-reviewer/AGENT.md +49 -0
- agent_toolkit/data/agents/database-reviewer/AGENT.md +44 -0
- agent_toolkit/data/agents/docs-lookup/AGENT.md +28 -0
- agent_toolkit/data/agents/e2e-runner/AGENT.md +38 -0
- agent_toolkit/data/agents/performance-optimizer/AGENT.md +52 -0
- agent_toolkit/data/agents/planner/AGENT.md +41 -0
- agent_toolkit/data/agents/refactor-cleaner/AGENT.md +43 -0
- agent_toolkit/data/agents/reference-lookup/AGENT.md +33 -0
- agent_toolkit/data/agents/security-reviewer/AGENT.md +47 -0
- agent_toolkit/data/agents/tdd-guide/AGENT.md +58 -0
- agent_toolkit/data/agents/tech-assistant/AGENT.md +11 -0
- agent_toolkit/data/agents/typescript-reviewer/AGENT.md +61 -0
- agent_toolkit/data/capabilities/hooks/README.md +6 -0
- agent_toolkit/data/capabilities/hooks/pre-commit-validate.yaml +26 -0
- agent_toolkit/data/capabilities/hooks/scripts/pre-commit-validate.sh +41 -0
- agent_toolkit/data/capabilities/hooks/scripts/session-start-context.sh +11 -0
- agent_toolkit/data/capabilities/hooks/session-start-context.yaml +23 -0
- agent_toolkit/data/capabilities/targets/registry.yaml +90 -0
- agent_toolkit/data/capabilities/upstream.lock +118 -0
- agent_toolkit/data/catalogs/agent-catalog.yaml +81 -0
- agent_toolkit/data/catalogs/loop-catalog.yaml +55 -0
- agent_toolkit/data/catalogs/skill-catalog.yaml +520 -0
- agent_toolkit/data/catalogs/skills-layout.json +391 -0
- agent_toolkit/data/distributions/products.yaml +190 -0
- agent_toolkit/data/distributions/targets/claude-code.yaml +47 -0
- agent_toolkit/data/distributions/targets/cursor.yaml +42 -0
- agent_toolkit/data/distributions/targets/opencode.yaml +55 -0
- agent_toolkit/data/loops/changelog-drafter/loop.yaml +40 -0
- agent_toolkit/data/loops/ci-sweeper/loop.yaml +53 -0
- agent_toolkit/data/loops/daily-triage/loop.yaml +47 -0
- agent_toolkit/data/loops/dep-sweeper/loop.yaml +46 -0
- agent_toolkit/data/loops/issue-triage/loop.yaml +40 -0
- agent_toolkit/data/loops/oss-daily-briefing/loop.yaml +65 -0
- agent_toolkit/data/loops/oss-pr-monitor/loop.yaml +86 -0
- agent_toolkit/data/loops/oss-triage/loop.yaml +67 -0
- agent_toolkit/data/loops/post-merge-cleanup/loop.yaml +44 -0
- agent_toolkit/data/loops/pr-babysitter/loop.yaml +46 -0
- agent_toolkit/data/mcp/registry/chrome-devtools.yaml +61 -0
- agent_toolkit/data/mcp/registry/clickup.yaml +48 -0
- agent_toolkit/data/mcp/registry/figma.yaml +44 -0
- agent_toolkit/data/mcp/registry/github.yaml +52 -0
- agent_toolkit/data/mcp/registry/linear.yaml +47 -0
- agent_toolkit/data/mcp/registry/notion.yaml +48 -0
- agent_toolkit/data/mcp/registry/slack.yaml +46 -0
- agent_toolkit/data/mcp/templates/chrome-devtools/README.md +57 -0
- agent_toolkit/data/mcp/templates/chrome-devtools/config.template.json +6 -0
- agent_toolkit/data/mcp/templates/clickup/README.md +45 -0
- agent_toolkit/data/mcp/templates/clickup/config.template.json +8 -0
- agent_toolkit/data/mcp/templates/clickup/wrapper.sh +23 -0
- agent_toolkit/data/mcp/templates/figma/README.md +54 -0
- agent_toolkit/data/mcp/templates/figma/config.template.json +9 -0
- agent_toolkit/data/mcp/templates/github/README.md +16 -0
- agent_toolkit/data/mcp/templates/github/config.template.json +15 -0
- agent_toolkit/data/mcp/templates/github/wrapper.sh +6 -0
- agent_toolkit/data/mcp/templates/linear/README.md +49 -0
- agent_toolkit/data/mcp/templates/linear/config.template.json +10 -0
- agent_toolkit/data/mcp/templates/notion/README.md +7 -0
- agent_toolkit/data/mcp/templates/notion/config.template.json +8 -0
- agent_toolkit/data/mcp/templates/notion/wrapper.sh +23 -0
- agent_toolkit/data/mcp/templates/slack/README.md +8 -0
- agent_toolkit/data/mcp/templates/slack/config.template.json +9 -0
- agent_toolkit/data/mcp/templates/slack/wrapper.sh +23 -0
- agent_toolkit/data/packs/README.md +66 -0
- agent_toolkit/data/packs/agentic-security/README.md +19 -0
- agent_toolkit/data/packs/agentic-security/config.yaml +25 -0
- agent_toolkit/data/packs/architecture/README.md +22 -0
- agent_toolkit/data/packs/architecture/config.yaml +27 -0
- agent_toolkit/data/packs/code-quality/README.md +19 -0
- agent_toolkit/data/packs/code-quality/config.yaml +21 -0
- agent_toolkit/data/packs/delivery-discipline/README.md +19 -0
- agent_toolkit/data/packs/delivery-discipline/config.yaml +42 -0
- agent_toolkit/data/packs/design-engineering/README.md +19 -0
- agent_toolkit/data/packs/design-engineering/config.yaml +41 -0
- agent_toolkit/data/packs/engineering-workflow/README.md +21 -0
- agent_toolkit/data/packs/engineering-workflow/config.yaml +57 -0
- agent_toolkit/data/packs/oss-maintenance/README.md +245 -0
- agent_toolkit/data/packs/oss-maintenance/config.yaml +75 -0
- agent_toolkit/data/profiles/claude-code/CLAUDE.md +110 -0
- agent_toolkit/data/profiles/claude-code/agents/assistant.md +59 -0
- agent_toolkit/data/profiles/claude-code/agents/build-error-resolver.md +30 -0
- agent_toolkit/data/profiles/claude-code/agents/client-workflow-bootstrap.md +60 -0
- agent_toolkit/data/profiles/claude-code/agents/contribution-planner.md +39 -0
- agent_toolkit/data/profiles/claude-code/agents/database-reviewer.md +44 -0
- agent_toolkit/data/profiles/claude-code/agents/docs-lookup.md +28 -0
- agent_toolkit/data/profiles/claude-code/agents/e2e-runner.md +38 -0
- agent_toolkit/data/profiles/claude-code/agents/performance-optimizer.md +52 -0
- agent_toolkit/data/profiles/claude-code/agents/planner.md +41 -0
- agent_toolkit/data/profiles/claude-code/agents/refactor-cleaner.md +43 -0
- agent_toolkit/data/profiles/claude-code/agents/reference-lookup.md +33 -0
- agent_toolkit/data/profiles/claude-code/agents/security-reviewer.md +47 -0
- agent_toolkit/data/profiles/claude-code/agents/tdd-guide.md +58 -0
- agent_toolkit/data/profiles/claude-code/agents/typescript-reviewer.md +61 -0
- agent_toolkit/data/profiles/claude-code/settings.json +86 -0
- agent_toolkit/data/profiles/copilot/copilot-instructions.md +15 -0
- agent_toolkit/data/profiles/cursor/README.md +33 -0
- agent_toolkit/data/profiles/cursor/rules/architect.mdc +23 -0
- agent_toolkit/data/profiles/cursor/rules/assistant.mdc +61 -0
- agent_toolkit/data/profiles/cursor/rules/build-error-resolver.mdc +20 -0
- agent_toolkit/data/profiles/cursor/rules/code-reviewer.mdc +21 -0
- agent_toolkit/data/profiles/cursor/rules/database-reviewer.mdc +29 -0
- agent_toolkit/data/profiles/cursor/rules/docs-lookup.mdc +15 -0
- agent_toolkit/data/profiles/cursor/rules/e2e-runner.mdc +30 -0
- agent_toolkit/data/profiles/cursor/rules/performance-optimizer.mdc +27 -0
- agent_toolkit/data/profiles/cursor/rules/planner.mdc +28 -0
- agent_toolkit/data/profiles/cursor/rules/refactor-cleaner.mdc +26 -0
- agent_toolkit/data/profiles/cursor/rules/reference-lookup.mdc +20 -0
- agent_toolkit/data/profiles/cursor/rules/security-reviewer.mdc +20 -0
- agent_toolkit/data/profiles/cursor/rules/tdd-guide.mdc +26 -0
- agent_toolkit/data/profiles/cursor/rules/typescript-reviewer.mdc +28 -0
- agent_toolkit/data/profiles/muse-code/README.md +35 -0
- agent_toolkit/data/profiles/opencode/README.md +44 -0
- agent_toolkit/data/profiles/opencode/agents/architect.md +30 -0
- agent_toolkit/data/profiles/opencode/agents/assistant.md +96 -0
- agent_toolkit/data/profiles/opencode/agents/build-error-resolver.md +31 -0
- agent_toolkit/data/profiles/opencode/agents/client-workflow-bootstrap.md +66 -0
- agent_toolkit/data/profiles/opencode/agents/code-reviewer.md +47 -0
- agent_toolkit/data/profiles/opencode/agents/contribution-planner.md +44 -0
- agent_toolkit/data/profiles/opencode/agents/database-reviewer.md +43 -0
- agent_toolkit/data/profiles/opencode/agents/docs-lookup.md +28 -0
- agent_toolkit/data/profiles/opencode/agents/e2e-runner.md +33 -0
- agent_toolkit/data/profiles/opencode/agents/performance-optimizer.md +34 -0
- agent_toolkit/data/profiles/opencode/agents/planner.md +27 -0
- agent_toolkit/data/profiles/opencode/agents/refactor-cleaner.md +27 -0
- agent_toolkit/data/profiles/opencode/agents/reference-lookup.md +27 -0
- agent_toolkit/data/profiles/opencode/agents/security-reviewer.md +27 -0
- agent_toolkit/data/profiles/opencode/agents/tdd-guide.md +27 -0
- agent_toolkit/data/profiles/opencode/agents/typescript-reviewer.md +30 -0
- agent_toolkit/data/profiles/opencode/opencode.json +3 -0
- agent_toolkit/data/profiles/pi/skills/architect/skill.md +5 -0
- agent_toolkit/data/profiles/pi/skills/assistant/skill.md +3 -0
- agent_toolkit/data/profiles/pi/skills/code-reviewer/skill.md +5 -0
- agent_toolkit/data/profiles/pi/skills/planner/skill.md +3 -0
- agent_toolkit/data/profiles/pi/skills/security-reviewer/skill.md +3 -0
- agent_toolkit/data/profiles/windsurf/memories/global_rules.md +114 -0
- agent_toolkit/data/profiles/windsurf/rules/architect.mdc +23 -0
- agent_toolkit/data/profiles/windsurf/rules/assistant.mdc +61 -0
- agent_toolkit/data/profiles/windsurf/rules/build-error-resolver.mdc +20 -0
- agent_toolkit/data/profiles/windsurf/rules/code-reviewer.mdc +21 -0
- agent_toolkit/data/profiles/windsurf/rules/database-reviewer.mdc +29 -0
- agent_toolkit/data/profiles/windsurf/rules/docs-lookup.mdc +15 -0
- agent_toolkit/data/profiles/windsurf/rules/e2e-runner.mdc +30 -0
- agent_toolkit/data/profiles/windsurf/rules/performance-optimizer.mdc +27 -0
- agent_toolkit/data/profiles/windsurf/rules/planner.mdc +28 -0
- agent_toolkit/data/profiles/windsurf/rules/refactor-cleaner.mdc +26 -0
- agent_toolkit/data/profiles/windsurf/rules/reference-lookup.mdc +20 -0
- agent_toolkit/data/profiles/windsurf/rules/security-reviewer.mdc +20 -0
- agent_toolkit/data/profiles/windsurf/rules/tdd-guide.mdc +26 -0
- agent_toolkit/data/profiles/windsurf/rules/typescript-reviewer.mdc +28 -0
- agent_toolkit/data/skills/accessibility/review/SKILL.md +116 -0
- agent_toolkit/data/skills/accessibility/review/references/a11y-checklist.md +25 -0
- agent_toolkit/data/skills/accessibility/review/references/a11y-findings-template.md +56 -0
- agent_toolkit/data/skills/accessibility/review/references/research.md +47 -0
- agent_toolkit/data/skills/agentic-security/mcp-audit/SKILL.md +116 -0
- agent_toolkit/data/skills/agentic-security/mcp-audit/references/mcp-audit-template.md +51 -0
- agent_toolkit/data/skills/agentic-security/owasp-agentic-review/SKILL.md +73 -0
- agent_toolkit/data/skills/agentic-security/owasp-agentic-review/references/owasp-agentic-template.md +32 -0
- agent_toolkit/data/skills/agentic-security/supply-chain-audit/SKILL.md +142 -0
- agent_toolkit/data/skills/agentic-security/threat-modeling/SKILL.md +100 -0
- agent_toolkit/data/skills/agentic-security/threat-modeling/references/threat-model-template.md +55 -0
- agent_toolkit/data/skills/architecture/c4-model/SKILL.md +49 -0
- agent_toolkit/data/skills/cloud/aws-well-architected-review/SKILL.md +37 -0
- agent_toolkit/data/skills/cloud/cloud-design-patterns/SKILL.md +38 -0
- agent_toolkit/data/skills/core/assistant/SKILL.md +216 -0
- agent_toolkit/data/skills/core/assistant/references/AGENTS_TEMPLATE.md +0 -0
- agent_toolkit/data/skills/core/assistant/references/ORCHESTRATION.md +0 -0
- agent_toolkit/data/skills/core/assistant/references/REPO_INSPECTION.md +0 -0
- agent_toolkit/data/skills/core/dev-companion/SKILL.md +65 -0
- agent_toolkit/data/skills/core/dev-companion/references/LOOP_GUARDRAILS.md +0 -0
- agent_toolkit/data/skills/core/onboarding/SKILL.md +122 -0
- agent_toolkit/data/skills/core/output-handshake/SKILL.md +26 -0
- agent_toolkit/data/skills/core/pr-fallback/SKILL.md +35 -0
- agent_toolkit/data/skills/core/pr-fallback/references/pr-body-default.md +0 -0
- agent_toolkit/data/skills/core/project/SKILL.md +89 -0
- agent_toolkit/data/skills/core/workspace/SKILL.md +103 -0
- agent_toolkit/data/skills/core/workspace-knowledge-sync/SKILL.md +140 -0
- agent_toolkit/data/skills/data/dbt-validation/SKILL.md +41 -0
- agent_toolkit/data/skills/data/snowflake-validation/SKILL.md +38 -0
- agent_toolkit/data/skills/delivery/adr/SKILL.md +56 -0
- agent_toolkit/data/skills/delivery/adr/references/default-template.md +35 -0
- agent_toolkit/data/skills/delivery/adr/references/example-001-graphql-adoption.md +66 -0
- agent_toolkit/data/skills/delivery/agreement/SKILL.md +24 -0
- agent_toolkit/data/skills/delivery/agreement/references/default-template.md +17 -0
- agent_toolkit/data/skills/delivery/agreement/references/example-api-versioning.md +29 -0
- agent_toolkit/data/skills/delivery/bug/SKILL.md +26 -0
- agent_toolkit/data/skills/delivery/bug/references/default-template.md +26 -0
- agent_toolkit/data/skills/delivery/bug/references/example-search-filter-bug.md +58 -0
- agent_toolkit/data/skills/delivery/decision-log/SKILL.md +28 -0
- agent_toolkit/data/skills/delivery/decision-log/references/default-template.md +17 -0
- agent_toolkit/data/skills/delivery/decision-log/references/example-repository-pattern.md +27 -0
- agent_toolkit/data/skills/delivery/development-workflow/SKILL.md +34 -0
- agent_toolkit/data/skills/delivery/development-workflow/references/default-workflow-checklist.md +44 -0
- agent_toolkit/data/skills/delivery/epic/SKILL.md +22 -0
- agent_toolkit/data/skills/delivery/epic/references/default-template.md +26 -0
- agent_toolkit/data/skills/delivery/epic/references/example-unified-dashboard.md +40 -0
- agent_toolkit/data/skills/delivery/incident/SKILL.md +24 -0
- agent_toolkit/data/skills/delivery/incident/references/default-template.md +29 -0
- agent_toolkit/data/skills/delivery/incident/references/example-payment-outage.md +62 -0
- agent_toolkit/data/skills/delivery/management-unit-assessment/SKILL.md +104 -0
- agent_toolkit/data/skills/delivery/management-unit-assessment/references/default-template.md +24 -0
- agent_toolkit/data/skills/delivery/management-unit-assessment/references/example-team-assessment.md +126 -0
- agent_toolkit/data/skills/delivery/meeting-minutes/SKILL.md +25 -0
- agent_toolkit/data/skills/delivery/meeting-minutes/references/default-template.md +22 -0
- agent_toolkit/data/skills/delivery/meeting-minutes/references/example-weekly-sync.md +72 -0
- agent_toolkit/data/skills/delivery/planning/SKILL.md +31 -0
- agent_toolkit/data/skills/delivery/planning/references/default-template.md +25 -0
- agent_toolkit/data/skills/delivery/planning/references/example-sprint-planning.md +62 -0
- agent_toolkit/data/skills/delivery/prd/SKILL.md +46 -0
- agent_toolkit/data/skills/delivery/prd/references/default-template.md +31 -0
- agent_toolkit/data/skills/delivery/prd/references/example-unified-api.md +71 -0
- agent_toolkit/data/skills/delivery/project-assessment/SKILL.md +90 -0
- agent_toolkit/data/skills/delivery/project-assessment/references/default-template.md +26 -0
- agent_toolkit/data/skills/delivery/project-assessment/references/example-platform-assessment.md +122 -0
- agent_toolkit/data/skills/delivery/project-assessment-evidence/SKILL.md +88 -0
- agent_toolkit/data/skills/delivery/project-assessment-evidence/references/default-template.md +24 -0
- agent_toolkit/data/skills/delivery/project-assessment-evidence/references/example-evidence-map.md +46 -0
- agent_toolkit/data/skills/delivery/spike/SKILL.md +24 -0
- agent_toolkit/data/skills/delivery/spike/references/default-template.md +29 -0
- agent_toolkit/data/skills/delivery/spike/references/example-graphql-federation.md +79 -0
- agent_toolkit/data/skills/delivery/task/SKILL.md +21 -0
- agent_toolkit/data/skills/delivery/task/references/default-template.md +21 -0
- agent_toolkit/data/skills/delivery/task/references/example-nav-system.md +33 -0
- agent_toolkit/data/skills/delivery/technical-unit-assessment/SKILL.md +58 -0
- agent_toolkit/data/skills/delivery/technical-unit-assessment/references/default-template.md +26 -0
- agent_toolkit/data/skills/delivery/technical-unit-assessment/references/example-frontend-assessment.md +112 -0
- agent_toolkit/data/skills/delivery/technical-unit-assessment/references/indicator-groups.md +65 -0
- agent_toolkit/data/skills/delivery/trd/SKILL.md +49 -0
- agent_toolkit/data/skills/delivery/trd/references/default-template.md +31 -0
- agent_toolkit/data/skills/delivery/trd/references/example-api-migration.md +122 -0
- agent_toolkit/data/skills/delivery/user-story/SKILL.md +21 -0
- agent_toolkit/data/skills/delivery/user-story/references/default-template.md +21 -0
- agent_toolkit/data/skills/delivery/user-story/references/example-advanced-filtering.md +37 -0
- agent_toolkit/data/skills/delivery/work-item/SKILL.md +31 -0
- agent_toolkit/data/skills/delivery/work-item/references/default-template.md +21 -0
- agent_toolkit/data/skills/delivery/work-item/references/example-routing-dashboard.md +23 -0
- agent_toolkit/data/skills/delivery/workflow-client-bootstrap/SKILL.md +148 -0
- agent_toolkit/data/skills/delivery/workflow-client-bootstrap/questions.yaml +165 -0
- agent_toolkit/data/skills/delivery/workflow-generic-project/SKILL.md +79 -0
- agent_toolkit/data/skills/design/design-assessment/SKILL.md +150 -0
- agent_toolkit/data/skills/design/design-assessment/references/design-scorecard-template.md +78 -0
- agent_toolkit/data/skills/design/design-improvement/SKILL.md +167 -0
- agent_toolkit/data/skills/design/design-improvement/references/improvement-plan-template.md +113 -0
- agent_toolkit/data/skills/design/figma/LICENSE.txt +2 -0
- agent_toolkit/data/skills/design/figma/NOTICE.txt +25 -0
- agent_toolkit/data/skills/design/figma/SKILL.md +98 -0
- agent_toolkit/data/skills/design/figma/references/figma-mcp-config.md +82 -0
- agent_toolkit/data/skills/design/figma/references/figma-tools-and-prompts.md +34 -0
- agent_toolkit/data/skills/design/figma-code-connect-components/LICENSE.txt +2 -0
- agent_toolkit/data/skills/design/figma-code-connect-components/NOTICE.txt +18 -0
- agent_toolkit/data/skills/design/figma-code-connect-components/SKILL.md +354 -0
- agent_toolkit/data/skills/design/figma-code-connect-components/references/mapping-checklist.md +7 -0
- agent_toolkit/data/skills/design/figma-code-connect-components/scripts/normalize_node_id.py +25 -0
- agent_toolkit/data/skills/design/figma-create-design-system-rules/LICENSE.txt +2 -0
- agent_toolkit/data/skills/design/figma-create-design-system-rules/NOTICE.txt +19 -0
- agent_toolkit/data/skills/design/figma-create-design-system-rules/SKILL.md +554 -0
- agent_toolkit/data/skills/design/figma-create-design-system-rules/references/rule-template.md +15 -0
- agent_toolkit/data/skills/design/figma-create-design-system-rules/scripts/check_agents_md.sh +9 -0
- agent_toolkit/data/skills/design/figma-create-new-file/LICENSE.txt +2 -0
- agent_toolkit/data/skills/design/figma-create-new-file/NOTICE.txt +17 -0
- agent_toolkit/data/skills/design/figma-create-new-file/SKILL.md +72 -0
- agent_toolkit/data/skills/design/figma-implement-design/LICENSE.txt +2 -0
- agent_toolkit/data/skills/design/figma-implement-design/NOTICE.txt +19 -0
- agent_toolkit/data/skills/design/figma-implement-design/SKILL.md +268 -0
- agent_toolkit/data/skills/design/frontend-design/LICENSE.txt +177 -0
- agent_toolkit/data/skills/design/frontend-design/SKILL.md +82 -0
- agent_toolkit/data/skills/design/frontend-design/UPSTREAM.md +14 -0
- agent_toolkit/data/skills/design/frontend-design-review/LICENSE +21 -0
- agent_toolkit/data/skills/design/frontend-design-review/SKILL.md +194 -0
- agent_toolkit/data/skills/design/frontend-design-review/references/pattern-examples.md +21 -0
- agent_toolkit/data/skills/design/frontend-design-review/references/quick-checklist.md +38 -0
- agent_toolkit/data/skills/design/frontend-design-review/references/review-output-format.md +68 -0
- agent_toolkit/data/skills/design/frontend-design-review/references/review-type-modifiers.md +31 -0
- agent_toolkit/data/skills/design/web-design-guidelines/SKILL.md +78 -0
- agent_toolkit/data/skills/design/web-design-guidelines/references/LICENSE +21 -0
- agent_toolkit/data/skills/design/web-design-guidelines/references/web-interface-guidelines.md +180 -0
- agent_toolkit/data/skills/forge/gh-address-comments/LICENSE.txt +202 -0
- agent_toolkit/data/skills/forge/gh-address-comments/NOTICE.txt +20 -0
- agent_toolkit/data/skills/forge/gh-address-comments/SKILL.md +72 -0
- agent_toolkit/data/skills/forge/gh-address-comments/scripts/fetch_comments.py +239 -0
- agent_toolkit/data/skills/forge/gh-contribution-planner/SKILL.md +160 -0
- agent_toolkit/data/skills/forge/gh-contribution-planner/scripts/inspect_contributions.py +818 -0
- agent_toolkit/data/skills/forge/gh-fix-ci/LICENSE.txt +201 -0
- agent_toolkit/data/skills/forge/gh-fix-ci/NOTICE.txt +20 -0
- agent_toolkit/data/skills/forge/gh-fix-ci/SKILL.md +74 -0
- agent_toolkit/data/skills/forge/gh-fix-ci/scripts/inspect_pr_checks.py +509 -0
- agent_toolkit/data/skills/forge/github-cli-workflow/SKILL.md +49 -0
- agent_toolkit/data/skills/forge/gitlab-cli-workflow/SKILL.md +44 -0
- agent_toolkit/data/skills/forge/workflow-client-bootstrap/SKILL.md +14 -0
- agent_toolkit/data/skills/forge/workflow-generic-project/SKILL.md +14 -0
- agent_toolkit/data/skills/forge/worktree/SKILL.md +113 -0
- agent_toolkit/data/skills/integrations/clickup-cli/SKILL.md +78 -0
- agent_toolkit/data/skills/integrations/clickup-cli/references/docs-management.md +57 -0
- agent_toolkit/data/skills/integrations/clickup-cli/references/task-management.md +131 -0
- agent_toolkit/data/skills/integrations/clickup-cli/references/time-tracking.md +38 -0
- agent_toolkit/data/skills/integrations/linear/LICENSE.txt +202 -0
- agent_toolkit/data/skills/integrations/linear/NOTICE.txt +23 -0
- agent_toolkit/data/skills/integrations/linear/SKILL.md +134 -0
- agent_toolkit/data/skills/integrations/mcp/SKILL.md +88 -0
- agent_toolkit/data/skills/integrations/slack-assistant/SKILL.md +138 -0
- agent_toolkit/data/skills/integrations/slack-cli/SKILL.md +109 -0
- agent_toolkit/data/skills/integrations/slack-cli/references/INSTALLATION.md +42 -0
- agent_toolkit/data/skills/loops/loop-runner/SKILL.md +92 -0
- agent_toolkit/data/skills/ops/docs-generator/SKILL.md +120 -0
- agent_toolkit/data/skills/ops/llm-cost-advisor/SKILL.md +87 -0
- agent_toolkit/data/skills/ops/swarm/SKILL.md +108 -0
- agent_toolkit/data/skills/ops/swarm-handoff/SKILL.md +112 -0
- agent_toolkit/data/skills/ops/swarm-observer/SKILL.md +102 -0
- agent_toolkit/data/skills/ops/triage/SKILL.md +119 -0
- agent_toolkit/data/skills/quality/codeql/SKILL.md +106 -0
- agent_toolkit/data/skills/quality/codeql/references/codeql-queries.md +43 -0
- agent_toolkit/data/skills/quality/megalinter/SKILL.md +162 -0
- agent_toolkit/data/skills/quality/megalinter/references/megalinter-images.md +36 -0
- agent_toolkit/data/skills/quality/megalinter/references/megalinter-license.md +41 -0
- agent_toolkit/data/skills/quality/megalinter/references/megalinter-targets.md +66 -0
- agent_toolkit/data/skills/tooling/chrome-devtools/SKILL.md +146 -0
- agent_toolkit/data/skills/tooling/herdr/SKILL.md +109 -0
- agent_toolkit/data/skills/tooling/inventory/SKILL.md +81 -0
- agent_toolkit/data/skills/tooling/jupyter-notebook/LICENSE.txt +201 -0
- agent_toolkit/data/skills/tooling/jupyter-notebook/NOTICE.txt +27 -0
- agent_toolkit/data/skills/tooling/jupyter-notebook/SKILL.md +145 -0
- agent_toolkit/data/skills/tooling/jupyter-notebook/assets/experiment-template.ipynb +117 -0
- agent_toolkit/data/skills/tooling/jupyter-notebook/assets/tutorial-template.ipynb +115 -0
- agent_toolkit/data/skills/tooling/jupyter-notebook/references/experiment-patterns.md +10 -0
- agent_toolkit/data/skills/tooling/jupyter-notebook/references/notebook-structure.md +17 -0
- agent_toolkit/data/skills/tooling/jupyter-notebook/references/quality-checklist.md +11 -0
- agent_toolkit/data/skills/tooling/jupyter-notebook/references/tutorial-patterns.md +9 -0
- agent_toolkit/data/skills/tooling/jupyter-notebook/scripts/new_notebook.py +132 -0
- agent_toolkit/data/skills/tooling/mermaid/SKILL.md +36 -0
- agent_toolkit/data/skills/tooling/playwright-cli/LICENSE.txt +201 -0
- agent_toolkit/data/skills/tooling/playwright-cli/NOTICE.txt +29 -0
- agent_toolkit/data/skills/tooling/playwright-cli/SKILL.md +154 -0
- agent_toolkit/data/skills/tooling/playwright-cli/references/cli.md +116 -0
- agent_toolkit/data/skills/tooling/playwright-cli/references/workflows.md +98 -0
- agent_toolkit/data/skills/tooling/playwright-cli/scripts/executable_playwright_cli.sh +25 -0
- agent_toolkit/data_cache.py +79 -0
- agent_toolkit/data_sync.py +144 -0
- agent_toolkit/installer/__init__.py +0 -0
- agent_toolkit/installer/merge.py +59 -0
- agent_toolkit/installer/receipt.py +89 -0
- agent_toolkit/installer/sources.py +92 -0
- agent_toolkit/installer/tracking.py +63 -0
- agent_toolkit/launcher.py +69 -0
- agent_toolkit/loop/__init__.py +0 -0
- agent_toolkit/loop/budget.py +107 -0
- agent_toolkit/loop/gh_gate.py +923 -0
- agent_toolkit/loop/loop-gh-gate +923 -0
- agent_toolkit/loop/pack.py +65 -0
- agent_toolkit/loop/runner.py +2722 -0
- agent_toolkit/runner/__init__.py +0 -0
- agent_toolkit/runner/dispatcher.py +163 -0
- agent_toolkit/runner/policy.py +356 -0
- agent_toolkit/runner/providers/__init__.py +21 -0
- agent_toolkit/runner/providers/anthropic_provider.py +109 -0
- agent_toolkit/runner/providers/base.py +53 -0
- agent_toolkit/runner/providers/ollama_provider.py +108 -0
- agent_toolkit/runner/providers/openai_provider.py +103 -0
- agent_toolkit/runner/providers/opencode_provider.py +127 -0
- agent_toolkit/swarm/__init__.py +5 -0
- agent_toolkit/swarm/approvals.py +121 -0
- agent_toolkit/swarm/backends/__init__.py +596 -0
- agent_toolkit/swarm/budget.py +83 -0
- agent_toolkit/swarm/cli.py +2448 -0
- agent_toolkit/swarm/config.py +351 -0
- agent_toolkit/swarm/handoff.py +174 -0
- agent_toolkit/swarm/models.py +230 -0
- agent_toolkit/swarm/prompts.py +177 -0
- agent_toolkit/swarm/recipes.py +304 -0
- agent_toolkit/swarm/runner.py +267 -0
- agent_toolkit/swarm/state.py +93 -0
- agent_toolkit/swarm/store.py +148 -0
- agent_toolkit/swarm/worktree.py +105 -0
- agent_toolkit/templates/workspace/.gitignore +19 -0
- agent_toolkit/templates/workspace/AGENTS.md +82 -0
- agent_toolkit/templates/workspace/knowledge/README.md +22 -0
- agent_toolkit/templates/workspace/knowledge/learnings/general.md +3 -0
- agent_toolkit/templates/workspace/knowledge/todos/pending.md +7 -0
- agent_toolkit/templates/workspace/packs/README.md +24 -0
- agent_toolkit/templates/workspace/personas/architect.md +12 -0
- agent_toolkit/templates/workspace/personas/implementer.md +12 -0
- agent_toolkit/templates/workspace/personas/researcher.md +12 -0
- agent_toolkit/templates/workspace/personas/reviewer.md +12 -0
- agent_toolkit_cli-1.11.0.dist-info/METADATA +363 -0
- agent_toolkit_cli-1.11.0.dist-info/RECORD +438 -0
- agent_toolkit_cli-1.11.0.dist-info/WHEEL +4 -0
- agent_toolkit_cli-1.11.0.dist-info/entry_points.txt +4 -0
- agent_toolkit_cli-1.11.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,923 @@
|
|
|
1
|
+
"""
|
|
2
|
+
devcompanion — background job queue for agent-toolkit workspaces.
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
agent-toolkit devcompanion queue <project> [--template NAME] [--request "..."] [--id ID]
|
|
6
|
+
agent-toolkit devcompanion run-once [--no-llm]
|
|
7
|
+
agent-toolkit devcompanion status
|
|
8
|
+
agent-toolkit devcompanion done <job-id>
|
|
9
|
+
agent-toolkit devcompanion sync-todos
|
|
10
|
+
|
|
11
|
+
Aliases: dc
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
import re
|
|
18
|
+
import shutil
|
|
19
|
+
import subprocess
|
|
20
|
+
import sys
|
|
21
|
+
import sys as _sys
|
|
22
|
+
from datetime import datetime, timezone
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
|
|
25
|
+
if _sys.platform == "win32":
|
|
26
|
+
try:
|
|
27
|
+
_sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
|
28
|
+
_sys.stderr.reconfigure(encoding="utf-8", errors="replace")
|
|
29
|
+
except Exception:
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
from agent_toolkit.cli.devcompanion_queue import (
|
|
33
|
+
DCConfig,
|
|
34
|
+
find_job_path,
|
|
35
|
+
get_dc_config,
|
|
36
|
+
iter_jobs,
|
|
37
|
+
job_project_name,
|
|
38
|
+
job_project_path,
|
|
39
|
+
mark_job_done,
|
|
40
|
+
pending_jobs,
|
|
41
|
+
queue_job_path,
|
|
42
|
+
read_job,
|
|
43
|
+
write_job,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
# ── workspace detection ───────────────────────────────────────────────────────
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _find_workspace() -> Path:
|
|
50
|
+
"""Return workspace root: AGENT_TOOLKIT_WORKSPACE / HARNESS_DIR / walk-up / cwd."""
|
|
51
|
+
from agent_toolkit._paths import find_workspace_root
|
|
52
|
+
|
|
53
|
+
ws = find_workspace_root()
|
|
54
|
+
if ws is not None:
|
|
55
|
+
return ws
|
|
56
|
+
# Devcompanion also accepts .devcompanion as a marker
|
|
57
|
+
cwd = Path.cwd().resolve()
|
|
58
|
+
for parent in [cwd, *cwd.parents]:
|
|
59
|
+
if (parent / ".devcompanion").is_dir():
|
|
60
|
+
return parent
|
|
61
|
+
return cwd
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
WORKSPACE_ROOT: Path = _find_workspace()
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _workspace() -> Path:
|
|
68
|
+
"""Fresh workspace root (respects env changes in tests)."""
|
|
69
|
+
return _find_workspace()
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _projects_dir() -> Path:
|
|
73
|
+
return _workspace() / "projects"
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _templates_dir() -> Path:
|
|
77
|
+
return _workspace() / "templates" / "jobs"
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _knowledge_todos() -> Path:
|
|
81
|
+
return _workspace() / "knowledge" / "todos" / "pending.md"
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _cfg() -> DCConfig:
|
|
85
|
+
return get_dc_config(_workspace())
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
# ── colors ────────────────────────────────────────────────────────────────────
|
|
89
|
+
|
|
90
|
+
_USE_COLOR = sys.stdout.isatty() and not os.environ.get("NO_COLOR")
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _c(code: str, text: str) -> str:
|
|
94
|
+
return f"\033[{code}m{text}\033[0m" if _USE_COLOR else text
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _blue(t: str) -> str:
|
|
98
|
+
return _c("1;34", t)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _green(t: str) -> str:
|
|
102
|
+
return _c("1;32", t)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _yellow(t: str) -> str:
|
|
106
|
+
return _c("1;33", t)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _red(t: str) -> str:
|
|
110
|
+
return _c("1;31", t)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _cyan(t: str) -> str:
|
|
114
|
+
return _c("0;36", t)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _log(msg: str) -> None:
|
|
118
|
+
print(f"{_blue('[devcompanion]')} {msg}")
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _ok(msg: str) -> None:
|
|
122
|
+
print(f"{_green('[devcompanion]')} {msg}")
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _warn(msg: str) -> None:
|
|
126
|
+
print(f"{_yellow('[devcompanion]')} {msg}")
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _err(msg: str) -> None:
|
|
130
|
+
print(f"{_red('[devcompanion]')} {msg}", file=sys.stderr)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
# ── time helpers ──────────────────────────────────────────────────────────────
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _utc_now() -> str:
|
|
137
|
+
return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
# ── project resolution ────────────────────────────────────────────────────────
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _resolve_project(name: str) -> Path | None:
|
|
144
|
+
"""Resolve project name → real repo path via projects/ symlinks."""
|
|
145
|
+
projects_dir = _projects_dir()
|
|
146
|
+
if not projects_dir.is_dir():
|
|
147
|
+
return None
|
|
148
|
+
link = projects_dir / name
|
|
149
|
+
if link.is_symlink():
|
|
150
|
+
return link.resolve()
|
|
151
|
+
for entry in projects_dir.iterdir():
|
|
152
|
+
if entry.is_symlink() and name in entry.name:
|
|
153
|
+
return entry.resolve()
|
|
154
|
+
return None
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _list_projects() -> list[tuple[str, Path | None]]:
|
|
158
|
+
projects_dir = _projects_dir()
|
|
159
|
+
if not projects_dir.is_dir():
|
|
160
|
+
return []
|
|
161
|
+
result = []
|
|
162
|
+
for entry in sorted(projects_dir.iterdir()):
|
|
163
|
+
if entry.is_symlink():
|
|
164
|
+
target = entry.resolve() if entry.resolve().is_dir() else None
|
|
165
|
+
result.append((entry.name, target))
|
|
166
|
+
return result
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
# ── gh gate (reuse loop runner shim) ─────────────────────────────────────────
|
|
170
|
+
|
|
171
|
+
_MUTATING_DC_TEMPLATES = frozenset(
|
|
172
|
+
{
|
|
173
|
+
"create-pr",
|
|
174
|
+
"fix-ci",
|
|
175
|
+
"refactor",
|
|
176
|
+
"implement",
|
|
177
|
+
"investigate",
|
|
178
|
+
}
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def _gate_script_path() -> Path:
|
|
183
|
+
return Path(__file__).resolve().parent.parent / "loop" / "loop-gh-gate"
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def _job_is_mutating(job: dict) -> bool:
|
|
187
|
+
template = str(job.get("template") or "")
|
|
188
|
+
if template in _MUTATING_DC_TEMPLATES:
|
|
189
|
+
return True
|
|
190
|
+
actions = job.get("actions_allowed") or []
|
|
191
|
+
return bool(actions) and actions != ["plan_only"]
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def _install_dc_gate(job: dict, out_dir: Path) -> dict[str, str]:
|
|
195
|
+
"""Install loop-gh-gate PATH shim for devcompanion LLM runners."""
|
|
196
|
+
from agent_toolkit.loop.gh_gate import install_gh_shim
|
|
197
|
+
|
|
198
|
+
gate_script = _gate_script_path()
|
|
199
|
+
if not gate_script.is_file():
|
|
200
|
+
raise RuntimeError(f"loop-gh-gate missing at {gate_script} — refusing ungated run")
|
|
201
|
+
|
|
202
|
+
gate = job.get("loop_gate") or {}
|
|
203
|
+
tier = str(gate.get("tier", "L1"))
|
|
204
|
+
allow = list(gate.get("allowlist") or [])
|
|
205
|
+
deny = list(gate.get("deny") or [])
|
|
206
|
+
verifier = str(gate.get("verifier") or "")
|
|
207
|
+
run_dir = gate.get("run_dir")
|
|
208
|
+
gate_run_dir = Path(run_dir) if run_dir else out_dir
|
|
209
|
+
|
|
210
|
+
env = install_gh_shim(
|
|
211
|
+
gate_run_dir,
|
|
212
|
+
tier=tier,
|
|
213
|
+
allowlist=allow,
|
|
214
|
+
deny=deny,
|
|
215
|
+
verifier=verifier,
|
|
216
|
+
gate_script=gate_script,
|
|
217
|
+
)
|
|
218
|
+
_log(f"Hard gate active: gh shim → tier={tier} allow=[{', '.join(allow) or '∅'}]")
|
|
219
|
+
return env
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def _runner_env_for_job(job: dict, out_dir: Path) -> dict[str, str]:
|
|
223
|
+
"""Return subprocess env with gh gate installed; fail closed for mutating jobs."""
|
|
224
|
+
base = os.environ.copy()
|
|
225
|
+
try:
|
|
226
|
+
gate_env = _install_dc_gate(job, out_dir)
|
|
227
|
+
except RuntimeError as exc:
|
|
228
|
+
if _job_is_mutating(job):
|
|
229
|
+
raise RuntimeError(f"mutating devcompanion job requires gh gate: {exc}") from exc
|
|
230
|
+
_warn(f"gh gate not installed ({exc}); proceeding without gate")
|
|
231
|
+
return base
|
|
232
|
+
merged = base.copy()
|
|
233
|
+
for key, value in gate_env.items():
|
|
234
|
+
if key.startswith("LOOP_GATE_") or key == "PATH":
|
|
235
|
+
merged[key] = value
|
|
236
|
+
return merged
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
# ── template loading ──────────────────────────────────────────────────────────
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
class TemplateNotFoundError(FileNotFoundError):
|
|
243
|
+
"""Raised when a job template YAML is missing (#48 / CLI-011)."""
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def _load_template(name: str) -> dict:
|
|
247
|
+
templates_dir = _templates_dir()
|
|
248
|
+
tpl_file = templates_dir / f"{name}.yaml"
|
|
249
|
+
if not tpl_file.exists():
|
|
250
|
+
raise TemplateNotFoundError(f"Template not found: {name} (looked in {templates_dir}/)")
|
|
251
|
+
|
|
252
|
+
text = tpl_file.read_text(encoding="utf-8")
|
|
253
|
+
lines = text.splitlines()
|
|
254
|
+
|
|
255
|
+
def _extract(field: str) -> str:
|
|
256
|
+
for i, line in enumerate(lines):
|
|
257
|
+
if line.lstrip().startswith("#"):
|
|
258
|
+
continue
|
|
259
|
+
if re.match(rf"^{field}:\s*\|\s*$", line):
|
|
260
|
+
block_lines = []
|
|
261
|
+
for j in range(i + 1, len(lines)):
|
|
262
|
+
bl = lines[j]
|
|
263
|
+
if bl and not bl.startswith((" ", "\t", "#")):
|
|
264
|
+
break
|
|
265
|
+
if bl.lstrip().startswith("#"):
|
|
266
|
+
continue
|
|
267
|
+
block_lines.append(re.sub(r"^ ", "", bl))
|
|
268
|
+
return "\n".join(block_lines).rstrip()
|
|
269
|
+
m = re.match(rf"^{field}:\s+(.+)$", line)
|
|
270
|
+
if m:
|
|
271
|
+
return m.group(1).strip().strip('"').strip("'")
|
|
272
|
+
return ""
|
|
273
|
+
|
|
274
|
+
return {
|
|
275
|
+
"name": _extract("name") or name,
|
|
276
|
+
"description": _extract("description"),
|
|
277
|
+
"request": _extract("request"),
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
# ── todos sync ────────────────────────────────────────────────────────────────
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def _sync_todos() -> None:
|
|
285
|
+
"""Scan done job plans for checklist items and sync to knowledge/todos/pending.md."""
|
|
286
|
+
todos: list[str] = []
|
|
287
|
+
cfg = _cfg()
|
|
288
|
+
runs_dir = cfg.runs_dir
|
|
289
|
+
|
|
290
|
+
if runs_dir.is_dir():
|
|
291
|
+
for plan_md in sorted(runs_dir.rglob("plan.md")):
|
|
292
|
+
try:
|
|
293
|
+
for line in plan_md.read_text(encoding="utf-8").splitlines():
|
|
294
|
+
if line.strip().startswith("- [ ]"):
|
|
295
|
+
todos.append(line.strip())
|
|
296
|
+
except Exception:
|
|
297
|
+
pass
|
|
298
|
+
|
|
299
|
+
knowledge_todos = _knowledge_todos()
|
|
300
|
+
knowledge_todos.parent.mkdir(parents=True, exist_ok=True)
|
|
301
|
+
existing = ""
|
|
302
|
+
if knowledge_todos.exists():
|
|
303
|
+
existing = knowledge_todos.read_text(encoding="utf-8")
|
|
304
|
+
|
|
305
|
+
if todos:
|
|
306
|
+
block = "\n## Synced from devcompanion runs\n\n" + "\n".join(todos) + "\n"
|
|
307
|
+
marker = "\n## Synced from devcompanion runs\n"
|
|
308
|
+
if marker in existing:
|
|
309
|
+
pre = existing[: existing.index(marker)]
|
|
310
|
+
knowledge_todos.write_text(pre + block, encoding="utf-8")
|
|
311
|
+
else:
|
|
312
|
+
knowledge_todos.write_text(
|
|
313
|
+
(existing.rstrip() + "\n" + block) if existing else block, encoding="utf-8"
|
|
314
|
+
)
|
|
315
|
+
_ok(f"Synced {len(todos)} todo(s) → {knowledge_todos}")
|
|
316
|
+
else:
|
|
317
|
+
_ok("No '- [ ]' items found in run plans.")
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
# ── runners ───────────────────────────────────────────────────────────────────
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def _import_harness_runner():
|
|
324
|
+
"""Try to import the harness workstation runner."""
|
|
325
|
+
runner_root = os.environ.get("HARNESS_RUNNER_DIR", "").strip()
|
|
326
|
+
if not runner_root:
|
|
327
|
+
runner_root = str(Path.home() / ".local" / "share" / "agentic-harness" / "runner")
|
|
328
|
+
runner_dir = Path(runner_root) / "runner"
|
|
329
|
+
if not runner_dir.is_dir():
|
|
330
|
+
return None, f"runner dir not found: {runner_dir}"
|
|
331
|
+
if str(runner_dir) not in sys.path:
|
|
332
|
+
sys.path.insert(0, str(runner_dir))
|
|
333
|
+
try:
|
|
334
|
+
import dots_ai_devcompanion_runner as runner_mod
|
|
335
|
+
|
|
336
|
+
return runner_mod, None
|
|
337
|
+
except ImportError as exc:
|
|
338
|
+
return None, str(exc)
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def _has_loops(repo_path: str) -> bool:
|
|
342
|
+
if not repo_path:
|
|
343
|
+
return False
|
|
344
|
+
loops_dir = Path(repo_path) / "loops"
|
|
345
|
+
return loops_dir.is_dir() and any(loops_dir.iterdir())
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def _try_harness_runner(job_file: Path, out_dir: Path) -> bool:
|
|
349
|
+
runner, _reason = _import_harness_runner()
|
|
350
|
+
if runner is None:
|
|
351
|
+
return False
|
|
352
|
+
|
|
353
|
+
argv = ["--job", str(job_file), "--out", str(out_dir)]
|
|
354
|
+
try:
|
|
355
|
+
rc = runner.main(argv)
|
|
356
|
+
except Exception as exc:
|
|
357
|
+
_warn(f"Harness runner failed: {exc}")
|
|
358
|
+
return False
|
|
359
|
+
|
|
360
|
+
if rc is None:
|
|
361
|
+
rc = 0
|
|
362
|
+
if rc == 0:
|
|
363
|
+
_ok("Harness runner completed")
|
|
364
|
+
return True
|
|
365
|
+
|
|
366
|
+
_warn(f"Harness runner exited {rc}")
|
|
367
|
+
return False
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
def _try_loop_runner(job: dict, out_dir: Path) -> bool:
|
|
371
|
+
repo_path = job_project_path(job)
|
|
372
|
+
if not _has_loops(repo_path):
|
|
373
|
+
return False
|
|
374
|
+
|
|
375
|
+
toolkit_bin = shutil.which("agent-toolkit")
|
|
376
|
+
if not toolkit_bin:
|
|
377
|
+
return False
|
|
378
|
+
|
|
379
|
+
request = job.get("request", "")
|
|
380
|
+
try:
|
|
381
|
+
result = subprocess.run(
|
|
382
|
+
[toolkit_bin, "loop", "run", "--request", request],
|
|
383
|
+
capture_output=True,
|
|
384
|
+
text=True,
|
|
385
|
+
cwd=repo_path,
|
|
386
|
+
timeout=1800,
|
|
387
|
+
)
|
|
388
|
+
except subprocess.TimeoutExpired:
|
|
389
|
+
_warn("agent-toolkit loop run timed out (1800s)")
|
|
390
|
+
return False
|
|
391
|
+
|
|
392
|
+
out_dir.mkdir(parents=True, exist_ok=True)
|
|
393
|
+
if result.returncode == 0:
|
|
394
|
+
plan_md = out_dir / "plan.md"
|
|
395
|
+
if not plan_md.exists() and result.stdout.strip():
|
|
396
|
+
plan_md.write_text(result.stdout, encoding="utf-8")
|
|
397
|
+
_ok("agent-toolkit loop run completed")
|
|
398
|
+
return True
|
|
399
|
+
|
|
400
|
+
_warn(f"agent-toolkit loop run exited {result.returncode}: {result.stderr[:200]}")
|
|
401
|
+
return False
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
def _try_claude_runner(job: dict, out_dir: Path) -> bool:
|
|
405
|
+
claude_bin = shutil.which("claude")
|
|
406
|
+
if not claude_bin:
|
|
407
|
+
return False
|
|
408
|
+
|
|
409
|
+
repo_path = job_project_path(job)
|
|
410
|
+
request = job.get("request", "")
|
|
411
|
+
context = f"Repository: {repo_path}\n" if repo_path else ""
|
|
412
|
+
|
|
413
|
+
prompt = (
|
|
414
|
+
f"You are an AI assistant executing a background job.\n"
|
|
415
|
+
f"Workspace root: {_workspace()}\n"
|
|
416
|
+
f"{context}"
|
|
417
|
+
f"Output directory: {out_dir}\n\n"
|
|
418
|
+
f"{request}\n\n"
|
|
419
|
+
f"Write your plan to {out_dir}/plan.md. "
|
|
420
|
+
f"Work from the workspace root shown above."
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
try:
|
|
424
|
+
env = _runner_env_for_job(job, out_dir)
|
|
425
|
+
except RuntimeError as exc:
|
|
426
|
+
_err(str(exc))
|
|
427
|
+
return False
|
|
428
|
+
|
|
429
|
+
limits = job.get("limits") or {}
|
|
430
|
+
timeout = int(limits.get("timeout_sec", 1800))
|
|
431
|
+
|
|
432
|
+
try:
|
|
433
|
+
result = subprocess.run(
|
|
434
|
+
[claude_bin, "--print", "--allowedTools", "Bash,Read,Write,Edit,Glob,Grep"],
|
|
435
|
+
input=prompt,
|
|
436
|
+
capture_output=True,
|
|
437
|
+
text=True,
|
|
438
|
+
cwd=str(_workspace()),
|
|
439
|
+
timeout=timeout,
|
|
440
|
+
env=env,
|
|
441
|
+
)
|
|
442
|
+
except subprocess.TimeoutExpired:
|
|
443
|
+
_warn(f"claude runner timed out ({timeout}s)")
|
|
444
|
+
return False
|
|
445
|
+
|
|
446
|
+
out_dir.mkdir(parents=True, exist_ok=True)
|
|
447
|
+
if result.returncode == 0:
|
|
448
|
+
plan_md = out_dir / "plan.md"
|
|
449
|
+
if not plan_md.exists() and result.stdout.strip():
|
|
450
|
+
plan_md.write_text(result.stdout, encoding="utf-8")
|
|
451
|
+
_ok("claude runner completed")
|
|
452
|
+
return True
|
|
453
|
+
|
|
454
|
+
_warn(f"claude runner exited {result.returncode}: {result.stderr[:200]}")
|
|
455
|
+
return False
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
def _try_opencode_runner(job: dict, out_dir: Path) -> bool:
|
|
459
|
+
opencode_bin = shutil.which("opencode")
|
|
460
|
+
if not opencode_bin:
|
|
461
|
+
return False
|
|
462
|
+
|
|
463
|
+
request = job.get("request", "")
|
|
464
|
+
prompt = (
|
|
465
|
+
f"You are executing an autonomous loop run in an agentic-harness workspace.\n"
|
|
466
|
+
f"Workspace root: {_workspace()}\n"
|
|
467
|
+
f"Output directory: {out_dir}\n\n"
|
|
468
|
+
f"{request}\n\n"
|
|
469
|
+
f"Write your final report to {out_dir}/report.md and your plan to "
|
|
470
|
+
f"{out_dir}/plan.md. Work from the workspace root shown above."
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
try:
|
|
474
|
+
env = _runner_env_for_job(job, out_dir)
|
|
475
|
+
except RuntimeError as exc:
|
|
476
|
+
_err(str(exc))
|
|
477
|
+
return False
|
|
478
|
+
|
|
479
|
+
limits = job.get("limits") or {}
|
|
480
|
+
timeout = int(limits.get("timeout_sec", 900))
|
|
481
|
+
|
|
482
|
+
try:
|
|
483
|
+
result = subprocess.run(
|
|
484
|
+
[opencode_bin, "run", "--print-logs"],
|
|
485
|
+
input=prompt,
|
|
486
|
+
capture_output=True,
|
|
487
|
+
text=True,
|
|
488
|
+
cwd=str(_workspace()),
|
|
489
|
+
timeout=timeout,
|
|
490
|
+
env=env,
|
|
491
|
+
)
|
|
492
|
+
except subprocess.TimeoutExpired:
|
|
493
|
+
_warn(f"opencode runner timed out ({timeout}s)")
|
|
494
|
+
return False
|
|
495
|
+
|
|
496
|
+
if result.returncode == 0:
|
|
497
|
+
out_dir.mkdir(parents=True, exist_ok=True)
|
|
498
|
+
report_md = out_dir / "report.md"
|
|
499
|
+
if not report_md.exists() and result.stdout.strip():
|
|
500
|
+
report_md.write_text(result.stdout, encoding="utf-8")
|
|
501
|
+
_ok("opencode runner completed")
|
|
502
|
+
return True
|
|
503
|
+
|
|
504
|
+
_warn(f"opencode runner exited {result.returncode}: {result.stderr[:200]}")
|
|
505
|
+
return False
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
def _skeleton_run(job: dict, out_dir: Path) -> int:
|
|
509
|
+
out_dir.mkdir(parents=True, exist_ok=True)
|
|
510
|
+
try:
|
|
511
|
+
job_id = job.get("id", "unknown")
|
|
512
|
+
project = job_project_name(job)
|
|
513
|
+
request = job.get("request", "(no request)")
|
|
514
|
+
|
|
515
|
+
plan = f"""# Plan — {job_id}
|
|
516
|
+
|
|
517
|
+
**Generated**: {_utc_now()}
|
|
518
|
+
**Mode**: skeleton (no LLM)
|
|
519
|
+
**Project**: {project}
|
|
520
|
+
|
|
521
|
+
## Request
|
|
522
|
+
|
|
523
|
+
{request}
|
|
524
|
+
|
|
525
|
+
## Steps
|
|
526
|
+
|
|
527
|
+
> This is a skeleton plan. Run without --no-llm for AI-generated steps.
|
|
528
|
+
|
|
529
|
+
- [ ] Read project README and AGENTS.md
|
|
530
|
+
- [ ] Understand existing conventions and patterns
|
|
531
|
+
- [ ] Analyse the request in context
|
|
532
|
+
- [ ] Implement changes following project conventions
|
|
533
|
+
- [ ] Run tests and verify
|
|
534
|
+
- [ ] Create PR
|
|
535
|
+
|
|
536
|
+
## Notes
|
|
537
|
+
|
|
538
|
+
- Job ID: {job_id}
|
|
539
|
+
- Project path: {job_project_path(job) or "not set"}
|
|
540
|
+
"""
|
|
541
|
+
(out_dir / "plan.md").write_text(plan, encoding="utf-8")
|
|
542
|
+
_ok(f"Skeleton plan written → {out_dir / 'plan.md'}")
|
|
543
|
+
return 0
|
|
544
|
+
except Exception as exc:
|
|
545
|
+
_err(f"Skeleton runner failed: {exc}")
|
|
546
|
+
return 1
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
def _dispatch_run(cfg: DCConfig, job_file: Path, job: dict, out_dir: Path, no_llm: bool) -> int:
|
|
550
|
+
if no_llm:
|
|
551
|
+
_log("--no-llm flag set, using skeleton runner.")
|
|
552
|
+
return _skeleton_run(job, out_dir)
|
|
553
|
+
|
|
554
|
+
if _job_is_mutating(job) and not shutil.which("gh"):
|
|
555
|
+
_err(
|
|
556
|
+
"Mutating devcompanion job requires `gh` on PATH for loop-gh-gate "
|
|
557
|
+
f"(template={job.get('template') or 'custom'})"
|
|
558
|
+
)
|
|
559
|
+
return 2
|
|
560
|
+
|
|
561
|
+
if cfg.harness_mode:
|
|
562
|
+
runner, reason = _import_harness_runner()
|
|
563
|
+
if runner is not None:
|
|
564
|
+
if _try_harness_runner(job_file, out_dir):
|
|
565
|
+
return 0
|
|
566
|
+
elif reason:
|
|
567
|
+
_warn(f"Harness runner not available ({reason}). Trying fallbacks.")
|
|
568
|
+
|
|
569
|
+
if _try_claude_runner(job, out_dir):
|
|
570
|
+
return 0
|
|
571
|
+
if _try_opencode_runner(job, out_dir):
|
|
572
|
+
return 0
|
|
573
|
+
_warn("No LLM runner found, falling back to skeleton plan.")
|
|
574
|
+
return _skeleton_run(job, out_dir)
|
|
575
|
+
|
|
576
|
+
if _try_loop_runner(job, out_dir):
|
|
577
|
+
return 0
|
|
578
|
+
if _try_claude_runner(job, out_dir):
|
|
579
|
+
return 0
|
|
580
|
+
_warn("No LLM runner found, falling back to skeleton plan.")
|
|
581
|
+
return _skeleton_run(job, out_dir)
|
|
582
|
+
|
|
583
|
+
|
|
584
|
+
# ── subcommands ───────────────────────────────────────────────────────────────
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
def _safe_parse(parser, argv: list[str]) -> tuple[object | None, int | None]:
|
|
588
|
+
"""Parse argv without letting argparse SystemExit bypass cmd return codes (#48)."""
|
|
589
|
+
try:
|
|
590
|
+
return parser.parse_args(argv), None
|
|
591
|
+
except SystemExit as exc:
|
|
592
|
+
if exc.code in (0, None):
|
|
593
|
+
return None, 0
|
|
594
|
+
return None, int(exc.code) if isinstance(exc.code, int) else 2
|
|
595
|
+
|
|
596
|
+
|
|
597
|
+
def _cmd_queue(argv: list[str]) -> int:
|
|
598
|
+
import argparse
|
|
599
|
+
|
|
600
|
+
p = argparse.ArgumentParser(prog="agent-toolkit devcompanion queue", add_help=True)
|
|
601
|
+
p.add_argument("project", nargs="?", help="Project name (maps to projects/<project>)")
|
|
602
|
+
p.add_argument("--template", "-t", help="Job template name from templates/jobs/")
|
|
603
|
+
p.add_argument("--request", "-r", help="Custom request string")
|
|
604
|
+
p.add_argument("--id", help="Custom job ID (default: <project>-<timestamp>)")
|
|
605
|
+
args, parse_err = _safe_parse(p, argv)
|
|
606
|
+
if parse_err is not None:
|
|
607
|
+
return parse_err
|
|
608
|
+
|
|
609
|
+
if not args.project:
|
|
610
|
+
_err(
|
|
611
|
+
'Usage: agent-toolkit devcompanion queue <project> [--template NAME] [--request "..."]'
|
|
612
|
+
)
|
|
613
|
+
return 1
|
|
614
|
+
|
|
615
|
+
project_path = _resolve_project(args.project)
|
|
616
|
+
if project_path is None:
|
|
617
|
+
_err(f"Project not found: '{args.project}'")
|
|
618
|
+
projects = _list_projects()
|
|
619
|
+
if projects:
|
|
620
|
+
print("\nKnown projects:")
|
|
621
|
+
for name, target in projects:
|
|
622
|
+
s = str(target) if target else _red("(broken)")
|
|
623
|
+
print(f" {_cyan(f'{name:<30}')} → {s}")
|
|
624
|
+
else:
|
|
625
|
+
print(" (no projects indexed)")
|
|
626
|
+
return 1
|
|
627
|
+
|
|
628
|
+
request = ""
|
|
629
|
+
if args.template:
|
|
630
|
+
try:
|
|
631
|
+
tpl = _load_template(args.template)
|
|
632
|
+
except TemplateNotFoundError as exc:
|
|
633
|
+
_err(str(exc))
|
|
634
|
+
return 1
|
|
635
|
+
request = tpl["request"]
|
|
636
|
+
if args.request:
|
|
637
|
+
request = f"{request}\n\n---\n\n{args.request}"
|
|
638
|
+
elif args.request:
|
|
639
|
+
request = args.request
|
|
640
|
+
else:
|
|
641
|
+
_err("Provide --request or --template")
|
|
642
|
+
return 1
|
|
643
|
+
|
|
644
|
+
cfg = _cfg()
|
|
645
|
+
job_id = args.id or f"{args.project}-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
|
|
646
|
+
|
|
647
|
+
if cfg.harness_mode:
|
|
648
|
+
job: dict = {
|
|
649
|
+
"id": job_id,
|
|
650
|
+
"created_at": _utc_now(),
|
|
651
|
+
"request": request,
|
|
652
|
+
"repo_path": str(project_path),
|
|
653
|
+
"llm": True,
|
|
654
|
+
"limits": {"timeout_sec": 1800, "max_steps": 25},
|
|
655
|
+
"actions_allowed": ["plan_only"],
|
|
656
|
+
}
|
|
657
|
+
else:
|
|
658
|
+
job = {
|
|
659
|
+
"id": job_id,
|
|
660
|
+
"created_at": _utc_now(),
|
|
661
|
+
"project": args.project,
|
|
662
|
+
"project_path": str(project_path),
|
|
663
|
+
"request": request,
|
|
664
|
+
"template": args.template or "",
|
|
665
|
+
"status": "pending",
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
job_file = queue_job_path(cfg, job_id)
|
|
669
|
+
write_job(job_file, job)
|
|
670
|
+
|
|
671
|
+
_log(f"Project : {args.project}")
|
|
672
|
+
_log(f"Path : {project_path}")
|
|
673
|
+
_log(f"Job ID : {job_id}")
|
|
674
|
+
_ok(f"Job written → {job_file}")
|
|
675
|
+
print()
|
|
676
|
+
print(_cyan("Plan stub:"))
|
|
677
|
+
print(" Run 'agent-toolkit devcompanion run-once' to execute")
|
|
678
|
+
print(" Run 'agent-toolkit devcompanion status' to check progress")
|
|
679
|
+
return 0
|
|
680
|
+
|
|
681
|
+
|
|
682
|
+
def _cmd_run_once(argv: list[str]) -> int:
|
|
683
|
+
import argparse
|
|
684
|
+
|
|
685
|
+
p = argparse.ArgumentParser(prog="agent-toolkit devcompanion run-once", add_help=True)
|
|
686
|
+
p.add_argument("--no-llm", action="store_true", help="Always use skeleton plan, skip LLM")
|
|
687
|
+
args, parse_err = _safe_parse(p, argv)
|
|
688
|
+
if parse_err is not None:
|
|
689
|
+
return parse_err
|
|
690
|
+
|
|
691
|
+
cfg = _cfg()
|
|
692
|
+
pending = pending_jobs(cfg)
|
|
693
|
+
|
|
694
|
+
if not pending:
|
|
695
|
+
_ok("No pending jobs.")
|
|
696
|
+
return 0
|
|
697
|
+
|
|
698
|
+
job_file, job = pending[0]
|
|
699
|
+
job_id = job["id"]
|
|
700
|
+
out_dir = cfg.runs_dir / job_id
|
|
701
|
+
|
|
702
|
+
_log(f"Running job: {job_id}")
|
|
703
|
+
_log(f"Project : {job_project_name(job)}")
|
|
704
|
+
_log(f"Artifacts → {out_dir}")
|
|
705
|
+
|
|
706
|
+
if cfg.harness_mode:
|
|
707
|
+
cfg.queue_processing.mkdir(parents=True, exist_ok=True)
|
|
708
|
+
processing_file = cfg.queue_processing / job_file.name
|
|
709
|
+
job_file.rename(processing_file)
|
|
710
|
+
job_file = processing_file
|
|
711
|
+
else:
|
|
712
|
+
job["status"] = "running"
|
|
713
|
+
write_job(job_file, job)
|
|
714
|
+
|
|
715
|
+
rc = _dispatch_run(cfg, job_file, job, out_dir, args.no_llm)
|
|
716
|
+
|
|
717
|
+
if cfg.harness_mode:
|
|
718
|
+
dest_dir = cfg.queue_done if rc == 0 else cfg.queue_failed
|
|
719
|
+
dest_dir.mkdir(parents=True, exist_ok=True)
|
|
720
|
+
if job_file.exists():
|
|
721
|
+
job_file.rename(dest_dir / job_file.name)
|
|
722
|
+
else:
|
|
723
|
+
job["status"] = "done" if rc == 0 else "failed"
|
|
724
|
+
job["completed_at"] = _utc_now()
|
|
725
|
+
write_job(job_file, job)
|
|
726
|
+
|
|
727
|
+
if rc == 0:
|
|
728
|
+
_ok(f"Job done: {job_id}")
|
|
729
|
+
plan_path = out_dir / "plan.md"
|
|
730
|
+
if plan_path.exists():
|
|
731
|
+
print()
|
|
732
|
+
print(_cyan(f"── plan.md {'─' * 50}"))
|
|
733
|
+
print(plan_path.read_text(encoding="utf-8")[:2000])
|
|
734
|
+
else:
|
|
735
|
+
_err(f"Job failed: {job_id}")
|
|
736
|
+
|
|
737
|
+
return rc
|
|
738
|
+
|
|
739
|
+
|
|
740
|
+
def _cmd_status(_argv: list[str]) -> int:
|
|
741
|
+
cfg = _cfg()
|
|
742
|
+
print()
|
|
743
|
+
print(_blue("=== devcompanion queue status ==="))
|
|
744
|
+
print()
|
|
745
|
+
|
|
746
|
+
jobs = iter_jobs(cfg)
|
|
747
|
+
if not jobs:
|
|
748
|
+
print(" (queue is empty)")
|
|
749
|
+
print()
|
|
750
|
+
return 0
|
|
751
|
+
|
|
752
|
+
if cfg.harness_mode:
|
|
753
|
+
for state, directory, color in (
|
|
754
|
+
("pending", cfg.queue_pending, _yellow),
|
|
755
|
+
("processing", cfg.queue_processing, _cyan),
|
|
756
|
+
("done", cfg.queue_done, _green),
|
|
757
|
+
("failed", cfg.queue_failed, _red),
|
|
758
|
+
):
|
|
759
|
+
if not directory.is_dir():
|
|
760
|
+
continue
|
|
761
|
+
state_jobs = [item for item in jobs if item[0] == state]
|
|
762
|
+
print(f"{color(f'{state:<12}')} {len(state_jobs)} job(s)")
|
|
763
|
+
for _, jf, job in state_jobs[:5]:
|
|
764
|
+
jid = job.get("id", jf.stem)
|
|
765
|
+
project = job_project_name(job)
|
|
766
|
+
request = job.get("request", "").split("\n")[0][:60]
|
|
767
|
+
print(f" {_cyan(f'{jid:<45}')} [{project}] {request}")
|
|
768
|
+
if len(state_jobs) > 5:
|
|
769
|
+
print(f" … and {len(state_jobs) - 5} more")
|
|
770
|
+
print()
|
|
771
|
+
return 0
|
|
772
|
+
|
|
773
|
+
col_id = 42
|
|
774
|
+
col_project = 20
|
|
775
|
+
col_status = 12
|
|
776
|
+
col_created = 20
|
|
777
|
+
|
|
778
|
+
header = (
|
|
779
|
+
f"{'JOB ID':<{col_id}} "
|
|
780
|
+
f"{'PROJECT':<{col_project}} "
|
|
781
|
+
f"{'STATUS':<{col_status}} "
|
|
782
|
+
f"{'CREATED AT':<{col_created}}"
|
|
783
|
+
)
|
|
784
|
+
print(_cyan(header))
|
|
785
|
+
print("─" * (col_id + col_project + col_status + col_created + 6))
|
|
786
|
+
|
|
787
|
+
status_color = {
|
|
788
|
+
"pending": _yellow,
|
|
789
|
+
"running": _cyan,
|
|
790
|
+
"done": _green,
|
|
791
|
+
"failed": _red,
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
for status, jf, job in jobs:
|
|
795
|
+
try:
|
|
796
|
+
jid = job.get("id", jf.stem)[:col_id]
|
|
797
|
+
project = job_project_name(job)[:col_project]
|
|
798
|
+
created = job.get("created_at", "")[:19]
|
|
799
|
+
color = status_color.get(status, lambda x: x)
|
|
800
|
+
print(
|
|
801
|
+
f"{jid:<{col_id}} "
|
|
802
|
+
f"{project:<{col_project}} "
|
|
803
|
+
f"{color(f'{status:<{col_status}}')} "
|
|
804
|
+
f"{created:<{col_created}}"
|
|
805
|
+
)
|
|
806
|
+
except Exception:
|
|
807
|
+
print(f" {jf.name} (unreadable)")
|
|
808
|
+
|
|
809
|
+
print()
|
|
810
|
+
return 0
|
|
811
|
+
|
|
812
|
+
|
|
813
|
+
def _cmd_done(argv: list[str]) -> int:
|
|
814
|
+
import argparse
|
|
815
|
+
|
|
816
|
+
p = argparse.ArgumentParser(prog="agent-toolkit devcompanion done", add_help=True)
|
|
817
|
+
p.add_argument("job_id", nargs="?", help="Job ID to mark as done")
|
|
818
|
+
args, parse_err = _safe_parse(p, argv)
|
|
819
|
+
if parse_err is not None:
|
|
820
|
+
return parse_err
|
|
821
|
+
|
|
822
|
+
if not args.job_id:
|
|
823
|
+
_err("Usage: agent-toolkit devcompanion done <job-id>")
|
|
824
|
+
return 1
|
|
825
|
+
|
|
826
|
+
cfg = _cfg()
|
|
827
|
+
job_id = args.job_id
|
|
828
|
+
|
|
829
|
+
if cfg.harness_mode:
|
|
830
|
+
if mark_job_done(cfg, job_id, _utc_now()):
|
|
831
|
+
_ok(f"Marked as done: {job_id}")
|
|
832
|
+
return 0
|
|
833
|
+
_warn(f"Job file not found: {job_id}.job")
|
|
834
|
+
return 1
|
|
835
|
+
|
|
836
|
+
job_file = find_job_path(cfg, job_id)
|
|
837
|
+
if job_file is None:
|
|
838
|
+
_warn(f"Job file not found: {job_id}.json")
|
|
839
|
+
return 1
|
|
840
|
+
|
|
841
|
+
job = read_job(job_file)
|
|
842
|
+
job["status"] = "done"
|
|
843
|
+
job["completed_at"] = _utc_now()
|
|
844
|
+
write_job(job_file, job)
|
|
845
|
+
_ok(f"Marked as done: {job_id}")
|
|
846
|
+
return 0
|
|
847
|
+
|
|
848
|
+
|
|
849
|
+
def _cmd_sync_todos(_argv: list[str]) -> int:
|
|
850
|
+
_sync_todos()
|
|
851
|
+
return 0
|
|
852
|
+
|
|
853
|
+
|
|
854
|
+
def _cmd_help(_argv: list[str]) -> int:
|
|
855
|
+
cfg = _cfg()
|
|
856
|
+
queue_loc = str(cfg.dc_home / "queue") if cfg.harness_mode else str(cfg.queue_dir)
|
|
857
|
+
mode = "harness (.job files)" if cfg.harness_mode else "workspace (.json files)"
|
|
858
|
+
print(f"""
|
|
859
|
+
{_blue("agent-toolkit devcompanion")} — background job queue for AI Workspace
|
|
860
|
+
|
|
861
|
+
{_cyan("Usage:")}
|
|
862
|
+
agent-toolkit devcompanion queue <project> [options] Queue a job
|
|
863
|
+
agent-toolkit devcompanion run-once [--no-llm] Run oldest pending job
|
|
864
|
+
agent-toolkit devcompanion status Show all jobs
|
|
865
|
+
agent-toolkit devcompanion done <job-id> Mark a job as done
|
|
866
|
+
agent-toolkit devcompanion sync-todos Sync todos from plan.md files
|
|
867
|
+
|
|
868
|
+
{_cyan("Queue options:")}
|
|
869
|
+
--template NAME Job template from templates/jobs/ directory
|
|
870
|
+
--request "..." Custom request string (required if no --template)
|
|
871
|
+
--id ID Custom job ID (default: <project>-<timestamp>)
|
|
872
|
+
|
|
873
|
+
{_cyan("Workspace detection:")}
|
|
874
|
+
AGENT_TOOLKIT_WORKSPACE env var, or walk up from CWD looking for .devcompanion/
|
|
875
|
+
|
|
876
|
+
{_cyan("Queue mode:")}
|
|
877
|
+
{mode}
|
|
878
|
+
HARNESS_DC_HOME or HARNESS_DIR → harness queue under ~/.local/share/agentic-harness/dev-companion
|
|
879
|
+
|
|
880
|
+
{_cyan("Queue location:")}
|
|
881
|
+
{queue_loc}
|
|
882
|
+
|
|
883
|
+
{_cyan("Runs location:")}
|
|
884
|
+
{cfg.runs_dir}
|
|
885
|
+
|
|
886
|
+
{_cyan("Examples:")}
|
|
887
|
+
agent-toolkit devcompanion queue my-api --template code-review
|
|
888
|
+
agent-toolkit devcompanion queue my-api --request "add pagination to GET /users"
|
|
889
|
+
agent-toolkit devcompanion run-once
|
|
890
|
+
agent-toolkit devcompanion run-once --no-llm
|
|
891
|
+
agent-toolkit devcompanion status
|
|
892
|
+
agent-toolkit devcompanion done my-api-20260804-120000
|
|
893
|
+
agent-toolkit devcompanion sync-todos
|
|
894
|
+
|
|
895
|
+
{_cyan("Alias:")}
|
|
896
|
+
agent-toolkit dc <subcommand>
|
|
897
|
+
""")
|
|
898
|
+
return 0
|
|
899
|
+
|
|
900
|
+
|
|
901
|
+
def cmd_devcompanion(argv: list[str]) -> int:
|
|
902
|
+
if not argv or argv[0] in ("-h", "--help", "help"):
|
|
903
|
+
return _cmd_help([])
|
|
904
|
+
|
|
905
|
+
subcommand = argv[0]
|
|
906
|
+
rest = argv[1:]
|
|
907
|
+
|
|
908
|
+
dispatch = {
|
|
909
|
+
"queue": _cmd_queue,
|
|
910
|
+
"run-once": _cmd_run_once,
|
|
911
|
+
"status": _cmd_status,
|
|
912
|
+
"done": _cmd_done,
|
|
913
|
+
"sync-todos": _cmd_sync_todos,
|
|
914
|
+
"help": _cmd_help,
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
fn = dispatch.get(subcommand)
|
|
918
|
+
if fn is None:
|
|
919
|
+
_err(f"Unknown subcommand: {subcommand}")
|
|
920
|
+
print("Run 'agent-toolkit devcompanion help' for usage.", file=sys.stderr)
|
|
921
|
+
return 1
|
|
922
|
+
|
|
923
|
+
return fn(rest)
|