@fitlab-ai/agent-infra 0.9.2 → 0.9.3
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.
- package/README.md +10 -9
- package/README.zh-CN.md +10 -9
- package/dist/bin/internal-cli.js +15 -0
- package/dist/lib/agent-clients/adapter.js +45 -2
- package/dist/lib/agent-clients/adapters/antigravity-cli.js +64 -0
- package/dist/lib/agent-clients/adapters/claude-code.js +10 -1
- package/dist/lib/agent-clients/adapters/codex.js +9 -0
- package/dist/lib/agent-clients/adapters/index.js +2 -2
- package/dist/lib/agent-clients/adapters/opencode.js +9 -0
- package/dist/lib/agent-clients/config.js +42 -4
- package/dist/lib/agent-clients/next-steps.js +11 -2
- package/dist/lib/agent-clients/reconcile.js +2 -1
- package/dist/lib/agent-clients/registry.js +7 -1
- package/dist/lib/agent-clients/schema.js +18 -0
- package/dist/lib/agent-clients/tokens.js +49 -0
- package/dist/lib/agent-clients/types.js +1 -1
- package/dist/lib/defaults.json +1 -1
- package/dist/lib/git/workflow.js +54 -1
- package/dist/lib/internal/agent-client.js +61 -4
- package/dist/lib/internal/git-workflow.js +6 -1
- package/dist/lib/internal/platform-checks.js +3 -3
- package/dist/lib/internal/platform-comment.js +29 -2
- package/dist/lib/internal/platform-issue.js +7 -0
- package/dist/lib/internal/platform-pr-review.js +132 -0
- package/dist/lib/internal/platform-pr.js +20 -2
- package/dist/lib/internal/platform-release-notes.js +52 -16
- package/dist/lib/internal/pr-review-grade.js +140 -0
- package/dist/lib/internal/release-workflow.js +13 -6
- package/dist/lib/internal/task-activity.js +73 -0
- package/dist/lib/internal/task-event.js +17 -1
- package/dist/lib/internal/task-lifecycle.js +7 -0
- package/dist/lib/internal/task-orchestration.js +51 -6
- package/dist/lib/internal/task-review.js +8 -3
- package/dist/lib/platform/adapters.js +8 -1
- package/dist/lib/platform/completion-backfill.js +122 -0
- package/dist/lib/platform/issue-comments.js +3 -2
- package/dist/lib/platform/merged-pr-equivalence.js +115 -5
- package/dist/lib/platform/pr-checks.js +64 -41
- package/dist/lib/platform/pr-review.js +166 -0
- package/dist/lib/platform/pull-requests.js +324 -3
- package/dist/lib/platform/release-notes.js +85 -3
- package/dist/lib/pr-review/evidence-grading.js +229 -0
- package/dist/lib/run/tui.js +3 -5
- package/dist/lib/sandbox/commands/create.js +0 -20
- package/dist/lib/sandbox/commands/show.js +1 -1
- package/dist/lib/task/activity-intent.js +101 -0
- package/dist/lib/task/artifact-lifecycle.js +2 -1
- package/dist/lib/task/commands/log.js +15 -14
- package/dist/lib/task/delegation-receipts.js +23 -2
- package/dist/lib/task/events.js +67 -28
- package/dist/lib/task/finalization-artifacts.js +35 -0
- package/dist/lib/task/lifecycle-execution.js +46 -0
- package/dist/lib/task/orchestration.js +408 -44
- package/dist/lib/task/review-finalization.js +29 -9
- package/dist/lib/task/task-execution-lock.js +231 -0
- package/dist/lib/task/verification-checks.js +1 -1
- package/dist/lib/task/verification-engine.js +218 -2
- package/dist/lib/task/verification.js +4 -3
- package/dist/lib/task/workspace-snapshot.js +17 -5
- package/lib/agent-clients/adapter.ts +75 -2
- package/lib/agent-clients/adapters/antigravity-cli.ts +65 -0
- package/lib/agent-clients/adapters/claude-code.ts +10 -1
- package/lib/agent-clients/adapters/codex.ts +9 -0
- package/lib/agent-clients/adapters/index.ts +2 -2
- package/lib/agent-clients/adapters/opencode.ts +9 -0
- package/lib/agent-clients/config.ts +49 -4
- package/lib/agent-clients/next-steps.ts +15 -2
- package/lib/agent-clients/reconcile.ts +2 -1
- package/lib/agent-clients/registry.ts +10 -0
- package/lib/agent-clients/schema.ts +18 -0
- package/lib/agent-clients/tokens.ts +53 -0
- package/lib/agent-clients/types.ts +15 -1
- package/lib/defaults.json +1 -1
- package/lib/git/workflow.ts +66 -2
- package/lib/internal/agent-client.ts +59 -4
- package/lib/internal/git-workflow.ts +5 -1
- package/lib/internal/platform-checks.ts +4 -4
- package/lib/internal/platform-comment.ts +17 -2
- package/lib/internal/platform-issue.ts +4 -0
- package/lib/internal/platform-pr-review.ts +104 -0
- package/lib/internal/platform-pr.ts +14 -1
- package/lib/internal/platform-release-notes.ts +59 -16
- package/lib/internal/pr-review-grade.ts +130 -0
- package/lib/internal/release-workflow.ts +13 -6
- package/lib/internal/task-activity.ts +55 -0
- package/lib/internal/task-event.ts +9 -1
- package/lib/internal/task-lifecycle.ts +4 -0
- package/lib/internal/task-orchestration.ts +45 -6
- package/lib/internal/task-review.ts +8 -3
- package/lib/platform/adapters.ts +29 -2
- package/lib/platform/completion-backfill.ts +134 -0
- package/lib/platform/issue-comments.ts +3 -2
- package/lib/platform/merged-pr-equivalence.ts +127 -5
- package/lib/platform/pr-checks.ts +72 -45
- package/lib/platform/pr-review.ts +201 -0
- package/lib/platform/pull-requests.ts +395 -2
- package/lib/platform/release-notes.ts +100 -4
- package/lib/pr-review/evidence-grading.ts +318 -0
- package/lib/run/tui.ts +3 -4
- package/lib/sandbox/commands/create.ts +0 -20
- package/lib/sandbox/commands/show.ts +1 -1
- package/lib/server/server.schema.json +2 -2
- package/lib/task/activity-intent.ts +128 -0
- package/lib/task/artifact-lifecycle.ts +2 -1
- package/lib/task/commands/log.ts +15 -14
- package/lib/task/delegation-receipts.ts +32 -3
- package/lib/task/events.ts +75 -30
- package/lib/task/finalization-artifacts.ts +58 -0
- package/lib/task/lifecycle-execution.ts +106 -0
- package/lib/task/orchestration.ts +543 -64
- package/lib/task/review-finalization.ts +40 -9
- package/lib/task/task-execution-lock.ts +296 -0
- package/lib/task/verification-checks.ts +1 -1
- package/lib/task/verification-engine.ts +249 -2
- package/lib/task/verification.ts +5 -3
- package/lib/task/workspace-snapshot.ts +26 -5
- package/package.json +3 -3
- package/templates/.agents/QUICKSTART.en.md +25 -8
- package/templates/.agents/QUICKSTART.zh-CN.md +25 -8
- package/templates/.agents/README.en.md +10 -7
- package/templates/.agents/README.zh-CN.md +10 -7
- package/templates/.agents/hooks/lifecycle-delegation.js +15 -4
- package/templates/.agents/rules/create-issue.github.en.md +4 -2
- package/templates/.agents/rules/create-issue.github.zh-CN.md +4 -2
- package/templates/.agents/rules/issue-fields.github.en.md +3 -1
- package/templates/.agents/rules/issue-fields.github.zh-CN.md +3 -1
- package/templates/.agents/rules/issue-pr-commands.en.md +5 -3
- package/templates/.agents/rules/issue-pr-commands.github.en.md +5 -3
- package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +5 -3
- package/templates/.agents/rules/issue-pr-commands.zh-CN.md +5 -3
- package/templates/.agents/rules/issue-sync.github.en.md +7 -3
- package/templates/.agents/rules/issue-sync.github.zh-CN.md +8 -4
- package/templates/.agents/rules/lifecycle-orchestration.en.md +5 -2
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +5 -2
- package/templates/.agents/rules/milestone-inference.github.en.md +4 -2
- package/templates/.agents/rules/milestone-inference.github.zh-CN.md +4 -2
- package/templates/.agents/rules/next-step-output.en.md +3 -1
- package/templates/.agents/rules/next-step-output.zh-CN.md +3 -1
- package/templates/.agents/rules/no-mid-flow-questions.en.md +17 -0
- package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +17 -0
- package/templates/.agents/rules/pr-checks-commands.en.md +3 -3
- package/templates/.agents/rules/pr-checks-commands.github.en.md +2 -2
- package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +2 -2
- package/templates/.agents/rules/pr-checks-commands.zh-CN.md +3 -3
- package/templates/.agents/rules/pr-sync.en.md +3 -1
- package/templates/.agents/rules/pr-sync.github.en.md +11 -1
- package/templates/.agents/rules/pr-sync.github.zh-CN.md +11 -1
- package/templates/.agents/rules/pr-sync.zh-CN.md +3 -1
- package/templates/.agents/rules/release-commands.en.md +1 -1
- package/templates/.agents/rules/release-commands.github.en.md +12 -2
- package/templates/.agents/rules/release-commands.github.zh-CN.md +12 -2
- package/templates/.agents/rules/release-commands.zh-CN.md +1 -1
- package/templates/.agents/rules/task-management.en.md +11 -0
- package/templates/.agents/rules/task-management.zh-CN.md +11 -0
- package/templates/.agents/skills/analyze-task/SKILL.en.md +10 -7
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +10 -7
- package/templates/.agents/skills/block-task/SKILL.en.md +7 -5
- package/templates/.agents/skills/block-task/SKILL.zh-CN.md +7 -5
- package/templates/.agents/skills/cancel-task/SKILL.en.md +6 -4
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +6 -4
- package/templates/.agents/skills/close-codescan/SKILL.en.md +3 -1
- package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +3 -1
- package/templates/.agents/skills/close-dependabot/SKILL.en.md +3 -1
- package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +3 -1
- package/templates/.agents/skills/code-task/SKILL.en.md +9 -6
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +11 -8
- package/templates/.agents/skills/commit/SKILL.en.md +3 -1
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +3 -1
- package/templates/.agents/skills/commit/reference/commit-message.en.md +1 -1
- package/templates/.agents/skills/commit/reference/commit-message.zh-CN.md +1 -1
- package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +1 -1
- package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +1 -1
- package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +1 -1
- package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +1 -1
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +6 -4
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +6 -4
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +1 -1
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +1 -1
- package/templates/.agents/skills/complete-task/SKILL.en.md +21 -6
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +21 -6
- package/templates/.agents/skills/complete-task/config/verify.en.json +1 -0
- package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +1 -0
- package/templates/.agents/skills/complete-task/reference/external-delivery.en.md +17 -0
- package/templates/.agents/skills/complete-task/reference/external-delivery.zh-CN.md +17 -0
- package/templates/.agents/skills/create-pr/SKILL.en.md +3 -1
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +3 -1
- package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +1 -1
- package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +1 -1
- package/templates/.agents/skills/create-release-note/SKILL.en.md +17 -16
- package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +17 -16
- package/templates/.agents/skills/create-task/SKILL.en.md +5 -3
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +5 -3
- package/templates/.agents/skills/import-issue/SKILL.en.md +5 -3
- package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +5 -3
- package/templates/.agents/skills/plan-task/SKILL.en.md +8 -5
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +8 -5
- package/templates/.agents/skills/post-release/SKILL.en.md +2 -0
- package/templates/.agents/skills/post-release/SKILL.zh-CN.md +2 -0
- package/templates/.agents/skills/release/SKILL.en.md +16 -10
- package/templates/.agents/skills/release/SKILL.zh-CN.md +16 -10
- package/templates/.agents/skills/restore-task/SKILL.en.md +4 -1
- package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +4 -1
- package/templates/.agents/skills/review-analysis/SKILL.en.md +7 -4
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +7 -4
- package/templates/.agents/skills/review-code/SKILL.en.md +9 -6
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +9 -6
- package/templates/.agents/skills/review-plan/SKILL.en.md +7 -4
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +7 -4
- package/templates/.agents/skills/review-pr/SKILL.en.md +158 -0
- package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +158 -0
- package/templates/.agents/skills/review-pr/config/verify.en.json +37 -0
- package/templates/.agents/skills/review-pr/config/verify.zh-CN.json +37 -0
- package/templates/.agents/skills/review-pr/reference/evidence-grading.en.md +65 -0
- package/templates/.agents/skills/review-pr/reference/evidence-grading.zh-CN.md +65 -0
- package/templates/.agents/skills/review-pr/reference/output-guidance.en.md +18 -0
- package/templates/.agents/skills/review-pr/reference/output-guidance.zh-CN.md +18 -0
- package/templates/.agents/skills/review-pr/reference/report-template.en.md +85 -0
- package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +85 -0
- package/templates/.agents/skills/run-task/SKILL.en.md +8 -8
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +8 -8
- package/templates/.agents/skills/run-task/config/verify.en.json +2 -1
- package/templates/.agents/skills/run-task/config/verify.zh-CN.json +2 -1
- package/templates/.agents/skills/run-task/reference/host-validation.en.md +20 -0
- package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +20 -0
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +35 -61
- package/templates/.agents/skills/watch-pr/SKILL.en.md +13 -13
- package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +13 -13
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +27 -6
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +26 -5
- package/templates/.agents/templates/task.en.md +1 -1
- package/templates/.agents/templates/task.zh-CN.md +1 -1
- package/templates/.agents/workflows/bug-fix.en.yaml +3 -3
- package/templates/.agents/workflows/bug-fix.zh-CN.yaml +3 -3
- package/templates/.agents/workflows/code-review.en.yaml +1 -1
- package/templates/.agents/workflows/code-review.zh-CN.yaml +1 -1
- package/templates/.agents/workflows/feature-development.en.yaml +4 -4
- package/templates/.agents/workflows/feature-development.zh-CN.yaml +4 -4
- package/templates/.agents/workflows/refactoring.en.yaml +3 -3
- package/templates/.agents/workflows/refactoring.zh-CN.yaml +3 -3
- package/templates/.claude/commands/post-release.en.md +1 -0
- package/templates/.claude/commands/post-release.zh-CN.md +1 -0
- package/templates/.claude/commands/review-pr.en.md +8 -0
- package/templates/.claude/commands/review-pr.zh-CN.md +8 -0
- package/templates/.gemini/commands/_project_/review-pr.en.toml +10 -0
- package/templates/.gemini/commands/_project_/review-pr.zh-CN.toml +10 -0
- package/templates/.opencode/commands/post-release.en.md +2 -0
- package/templates/.opencode/commands/post-release.zh-CN.md +2 -0
- package/templates/.opencode/commands/review-pr.en.md +11 -0
- package/templates/.opencode/commands/review-pr.zh-CN.md +11 -0
- package/dist/lib/agent-clients/adapters/gemini-cli.js +0 -64
- package/lib/agent-clients/adapters/gemini-cli.ts +0 -65
- package/templates/.gemini/commands/_project_/analyze-task.en.toml +0 -10
- package/templates/.gemini/commands/_project_/analyze-task.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/archive-tasks.en.toml +0 -10
- package/templates/.gemini/commands/_project_/archive-tasks.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/block-task.en.toml +0 -10
- package/templates/.gemini/commands/_project_/block-task.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/cancel-task.en.toml +0 -10
- package/templates/.gemini/commands/_project_/cancel-task.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/check-task.en.toml +0 -10
- package/templates/.gemini/commands/_project_/check-task.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/close-codescan.en.toml +0 -8
- package/templates/.gemini/commands/_project_/close-codescan.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/close-dependabot.en.toml +0 -8
- package/templates/.gemini/commands/_project_/close-dependabot.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/code-task.en.toml +0 -10
- package/templates/.gemini/commands/_project_/code-task.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/commit.en.toml +0 -10
- package/templates/.gemini/commands/_project_/commit.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/complete-manual-validation.en.toml +0 -10
- package/templates/.gemini/commands/_project_/complete-manual-validation.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/complete-task.en.toml +0 -10
- package/templates/.gemini/commands/_project_/complete-task.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/create-pr.en.toml +0 -10
- package/templates/.gemini/commands/_project_/create-pr.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/create-release-note.en.toml +0 -8
- package/templates/.gemini/commands/_project_/create-release-note.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/create-task.en.toml +0 -8
- package/templates/.gemini/commands/_project_/create-task.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/import-codescan.en.toml +0 -8
- package/templates/.gemini/commands/_project_/import-codescan.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/import-dependabot.en.toml +0 -8
- package/templates/.gemini/commands/_project_/import-dependabot.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/import-issue.en.toml +0 -8
- package/templates/.gemini/commands/_project_/import-issue.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/init-labels.en.toml +0 -8
- package/templates/.gemini/commands/_project_/init-labels.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/init-milestones.en.toml +0 -10
- package/templates/.gemini/commands/_project_/init-milestones.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/plan-task.en.toml +0 -10
- package/templates/.gemini/commands/_project_/plan-task.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/post-release.en.toml +0 -6
- package/templates/.gemini/commands/_project_/post-release.zh-CN.toml +0 -6
- package/templates/.gemini/commands/_project_/refine-title.en.toml +0 -8
- package/templates/.gemini/commands/_project_/refine-title.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/release.en.toml +0 -8
- package/templates/.gemini/commands/_project_/release.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/restore-task.en.toml +0 -8
- package/templates/.gemini/commands/_project_/restore-task.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/review-analysis.en.toml +0 -10
- package/templates/.gemini/commands/_project_/review-analysis.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/review-code.en.toml +0 -10
- package/templates/.gemini/commands/_project_/review-code.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/review-plan.en.toml +0 -10
- package/templates/.gemini/commands/_project_/review-plan.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/run-task.en.toml +0 -8
- package/templates/.gemini/commands/_project_/run-task.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/test-integration.en.toml +0 -6
- package/templates/.gemini/commands/_project_/test-integration.zh-CN.toml +0 -6
- package/templates/.gemini/commands/_project_/test.en.toml +0 -6
- package/templates/.gemini/commands/_project_/test.zh-CN.toml +0 -6
- package/templates/.gemini/commands/_project_/update-agent-infra.en.toml +0 -6
- package/templates/.gemini/commands/_project_/update-agent-infra.zh-CN.toml +0 -6
- package/templates/.gemini/commands/_project_/upgrade-dependency.en.toml +0 -8
- package/templates/.gemini/commands/_project_/upgrade-dependency.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/watch-pr.en.toml +0 -10
- package/templates/.gemini/commands/_project_/watch-pr.zh-CN.toml +0 -10
- package/templates/.gemini/settings.json +0 -3
|
@@ -20,6 +20,28 @@ import type {
|
|
|
20
20
|
|
|
21
21
|
type AgentClientCapabilities = AgentClientCapabilityMap;
|
|
22
22
|
|
|
23
|
+
type AgentClientModelSelectionContext =
|
|
24
|
+
| Readonly<{
|
|
25
|
+
kind: 'catalog';
|
|
26
|
+
completeness: 'complete' | 'partial';
|
|
27
|
+
source: string;
|
|
28
|
+
models: readonly Readonly<{
|
|
29
|
+
id: string;
|
|
30
|
+
reasoningEfforts?: readonly string[];
|
|
31
|
+
}>[];
|
|
32
|
+
guidance?: string;
|
|
33
|
+
}>
|
|
34
|
+
| Readonly<{
|
|
35
|
+
kind: 'interactive-only';
|
|
36
|
+
command: string;
|
|
37
|
+
guidance: string;
|
|
38
|
+
}>;
|
|
39
|
+
|
|
40
|
+
type AgentClientDelegationEvidence = Readonly<{
|
|
41
|
+
actualModel: 'host-event' | 'unavailable';
|
|
42
|
+
actualReasoningEffort: 'host-event' | 'spawn-ack' | 'unavailable';
|
|
43
|
+
}>;
|
|
44
|
+
|
|
23
45
|
type AgentClientSeedCommand = Readonly<{
|
|
24
46
|
templates: Readonly<{
|
|
25
47
|
en: string;
|
|
@@ -41,6 +63,8 @@ type AgentClientAdapter = Readonly<{
|
|
|
41
63
|
displayName: string;
|
|
42
64
|
invocation: string;
|
|
43
65
|
capabilities: AgentClientCapabilities;
|
|
66
|
+
modelSelection: AgentClientModelSelectionContext;
|
|
67
|
+
delegationEvidence: AgentClientDelegationEvidence;
|
|
44
68
|
project: AgentClientProjectDescriptor;
|
|
45
69
|
sandbox: AgentClientSandboxDescriptor;
|
|
46
70
|
}>;
|
|
@@ -211,6 +235,51 @@ function defineAgentClientAdapter(
|
|
|
211
235
|
})
|
|
212
236
|
) as AgentClientCapabilities;
|
|
213
237
|
|
|
238
|
+
const modelSelection = candidate.modelSelection;
|
|
239
|
+
if (!modelSelection || typeof modelSelection !== 'object') {
|
|
240
|
+
throw new Error(`Agent Client '${candidate.id}' has an invalid model-selection context`);
|
|
241
|
+
}
|
|
242
|
+
let frozenModelSelection: AgentClientModelSelectionContext;
|
|
243
|
+
if (modelSelection.kind === 'interactive-only') {
|
|
244
|
+
if (!modelSelection.command?.trim() || !modelSelection.guidance?.trim()) {
|
|
245
|
+
throw new Error(`Agent Client '${candidate.id}' has an invalid model-selection context`);
|
|
246
|
+
}
|
|
247
|
+
frozenModelSelection = Object.freeze({ ...modelSelection });
|
|
248
|
+
} else if (
|
|
249
|
+
modelSelection.kind === 'catalog'
|
|
250
|
+
&& ['complete', 'partial'].includes(modelSelection.completeness)
|
|
251
|
+
&& typeof modelSelection.source === 'string'
|
|
252
|
+
&& modelSelection.source.trim() !== ''
|
|
253
|
+
&& Array.isArray(modelSelection.models)
|
|
254
|
+
) {
|
|
255
|
+
const models = modelSelection.models.map((model) => {
|
|
256
|
+
if (!model?.id?.trim() || (model.reasoningEfforts && !Array.isArray(model.reasoningEfforts))) {
|
|
257
|
+
throw new Error(`Agent Client '${candidate.id}' has an invalid model-selection context`);
|
|
258
|
+
}
|
|
259
|
+
return Object.freeze({
|
|
260
|
+
id: model.id,
|
|
261
|
+
...(model.reasoningEfforts
|
|
262
|
+
? { reasoningEfforts: Object.freeze([...model.reasoningEfforts]) }
|
|
263
|
+
: {})
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
frozenModelSelection = Object.freeze({
|
|
267
|
+
...modelSelection,
|
|
268
|
+
models: Object.freeze(models)
|
|
269
|
+
});
|
|
270
|
+
} else {
|
|
271
|
+
throw new Error(`Agent Client '${candidate.id}' has an invalid model-selection context`);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const evidence = candidate.delegationEvidence;
|
|
275
|
+
if (
|
|
276
|
+
!evidence
|
|
277
|
+
|| !['host-event', 'unavailable'].includes(evidence.actualModel)
|
|
278
|
+
|| !['host-event', 'spawn-ack', 'unavailable'].includes(evidence.actualReasoningEffort)
|
|
279
|
+
) {
|
|
280
|
+
throw new Error(`Agent Client '${candidate.id}' has invalid delegation evidence`);
|
|
281
|
+
}
|
|
282
|
+
|
|
214
283
|
if (
|
|
215
284
|
typeof candidate.project !== 'object'
|
|
216
285
|
|| candidate.project === null
|
|
@@ -219,8 +288,8 @@ function defineAgentClientAdapter(
|
|
|
219
288
|
throw new Error(`Agent Client '${candidate.id}' has an invalid project descriptor`);
|
|
220
289
|
}
|
|
221
290
|
const ownedPathPrefixes = candidate.project.ownedPathPrefixes;
|
|
222
|
-
if (!Array.isArray(ownedPathPrefixes)
|
|
223
|
-
throw new Error(`Agent Client '${candidate.id}'
|
|
291
|
+
if (!Array.isArray(ownedPathPrefixes)) {
|
|
292
|
+
throw new Error(`Agent Client '${candidate.id}' has invalid owned path prefixes`);
|
|
224
293
|
}
|
|
225
294
|
|
|
226
295
|
const paths = ownedPathPrefixes.map((prefix) => {
|
|
@@ -441,6 +510,8 @@ function defineAgentClientAdapter(
|
|
|
441
510
|
displayName: candidate.displayName,
|
|
442
511
|
invocation: candidate.invocation,
|
|
443
512
|
capabilities: Object.freeze(capabilities),
|
|
513
|
+
modelSelection: frozenModelSelection,
|
|
514
|
+
delegationEvidence: Object.freeze({ ...evidence }),
|
|
444
515
|
project: Object.freeze({
|
|
445
516
|
ownedPathPrefixes: Object.freeze(paths),
|
|
446
517
|
...projectAssets,
|
|
@@ -454,7 +525,9 @@ export { defineAgentClientAdapter };
|
|
|
454
525
|
export type {
|
|
455
526
|
AgentClientAdapter,
|
|
456
527
|
AgentClientCapabilities,
|
|
528
|
+
AgentClientDelegationEvidence,
|
|
457
529
|
AgentClientManifestEntry,
|
|
530
|
+
AgentClientModelSelectionContext,
|
|
458
531
|
AgentClientProjectDescriptor,
|
|
459
532
|
AgentClientSeedCommand,
|
|
460
533
|
AgentClientRegistry
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { defineAgentClientAdapter } from '../adapter.ts';
|
|
2
|
+
import { hostJoin } from '../../sandbox/engines/wsl2-paths.ts';
|
|
3
|
+
|
|
4
|
+
const antigravityCliAdapter = defineAgentClientAdapter({
|
|
5
|
+
id: 'antigravity-cli',
|
|
6
|
+
displayName: 'Antigravity CLI',
|
|
7
|
+
invocation: '/${skillName}',
|
|
8
|
+
capabilities: {
|
|
9
|
+
instructions: { level: 'compatible' },
|
|
10
|
+
skills: { level: 'integrated' },
|
|
11
|
+
commands: { level: 'integrated' },
|
|
12
|
+
hooks: { level: 'compatible' },
|
|
13
|
+
subagents: { level: 'unsupported' },
|
|
14
|
+
orchestration: { level: 'unsupported' },
|
|
15
|
+
sandbox: { level: 'integrated' },
|
|
16
|
+
verification: { level: 'compatible' }
|
|
17
|
+
},
|
|
18
|
+
modelSelection: {
|
|
19
|
+
kind: 'interactive-only',
|
|
20
|
+
command: '/model',
|
|
21
|
+
guidance: 'Use the host model picker for the complete model and reasoning-effort catalog.'
|
|
22
|
+
},
|
|
23
|
+
delegationEvidence: {
|
|
24
|
+
actualModel: 'unavailable',
|
|
25
|
+
actualReasoningEffort: 'unavailable'
|
|
26
|
+
},
|
|
27
|
+
project: {
|
|
28
|
+
ownedPathPrefixes: [],
|
|
29
|
+
managed: [],
|
|
30
|
+
merged: [],
|
|
31
|
+
ejected: [],
|
|
32
|
+
seedCommands: []
|
|
33
|
+
},
|
|
34
|
+
sandbox: {
|
|
35
|
+
createTool: ({ home }) => ({
|
|
36
|
+
id: 'antigravity-cli',
|
|
37
|
+
name: 'Antigravity CLI',
|
|
38
|
+
install: {
|
|
39
|
+
type: 'shell',
|
|
40
|
+
cmd: 'curl -fsSL https://antigravity.google/cli/install.sh | bash -s -- --dir /home/devuser/.npm-global/bin'
|
|
41
|
+
},
|
|
42
|
+
sandboxBase: hostJoin(home, '.agent-infra', 'sandboxes', 'antigravity-cli'),
|
|
43
|
+
containerMount: '/home/devuser/.gemini',
|
|
44
|
+
versionCmd: 'agy --version',
|
|
45
|
+
setupHint: 'Run agy inside the container to finish authentication.',
|
|
46
|
+
hostPreSeedFiles: [
|
|
47
|
+
{
|
|
48
|
+
hostPath: hostJoin(home, '.gemini', 'antigravity-cli', 'keybindings.json'),
|
|
49
|
+
sandboxName: 'antigravity-cli/keybindings.json'
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
hostPath: hostJoin(home, '.gemini', 'config', 'mcp_config.json'),
|
|
53
|
+
sandboxName: 'config/mcp_config.json'
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
}),
|
|
57
|
+
aliases: [
|
|
58
|
+
{ name: 'antigravity-yolo', command: 'agy --dangerously-skip-permissions; tput ed' },
|
|
59
|
+
{ name: 'agy-yolo', command: 'agy --dangerously-skip-permissions; tput ed' }
|
|
60
|
+
],
|
|
61
|
+
hooks: []
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
export { antigravityCliAdapter };
|
|
@@ -11,10 +11,19 @@ const claudeCodeAdapter = defineAgentClientAdapter({
|
|
|
11
11
|
commands: { level: 'integrated' },
|
|
12
12
|
hooks: { level: 'integrated' },
|
|
13
13
|
subagents: { level: 'experimental' },
|
|
14
|
-
orchestration: { level: '
|
|
14
|
+
orchestration: { level: 'unsupported' },
|
|
15
15
|
sandbox: { level: 'integrated' },
|
|
16
16
|
verification: { level: 'compatible' }
|
|
17
17
|
},
|
|
18
|
+
modelSelection: {
|
|
19
|
+
kind: 'interactive-only',
|
|
20
|
+
command: '/model',
|
|
21
|
+
guidance: 'Use the host model picker for the complete model and reasoning-effort catalog.'
|
|
22
|
+
},
|
|
23
|
+
delegationEvidence: {
|
|
24
|
+
actualModel: 'unavailable',
|
|
25
|
+
actualReasoningEffort: 'unavailable'
|
|
26
|
+
},
|
|
18
27
|
project: {
|
|
19
28
|
ownedPathPrefixes: ['.claude/'],
|
|
20
29
|
managed: ['.claude/commands/', '.claude/agents/'],
|
|
@@ -19,6 +19,15 @@ const codexAdapter = defineAgentClientAdapter({
|
|
|
19
19
|
sandbox: { level: 'integrated' },
|
|
20
20
|
verification: { level: 'compatible' }
|
|
21
21
|
},
|
|
22
|
+
modelSelection: {
|
|
23
|
+
kind: 'interactive-only',
|
|
24
|
+
command: '/model',
|
|
25
|
+
guidance: 'Use the host model picker for the complete model and reasoning-effort catalog.'
|
|
26
|
+
},
|
|
27
|
+
delegationEvidence: {
|
|
28
|
+
actualModel: 'unavailable',
|
|
29
|
+
actualReasoningEffort: 'unavailable'
|
|
30
|
+
},
|
|
22
31
|
project: {
|
|
23
32
|
ownedPathPrefixes: ['.codex/'],
|
|
24
33
|
managed: ['.codex/hooks.json', '.codex/agents/'],
|
|
@@ -2,14 +2,14 @@ import { AGENT_CLIENT_IDS } from '../types.ts';
|
|
|
2
2
|
import type { AgentClientAdapter } from '../adapter.ts';
|
|
3
3
|
import { claudeCodeAdapter } from './claude-code.ts';
|
|
4
4
|
import { codexAdapter } from './codex.ts';
|
|
5
|
-
import {
|
|
5
|
+
import { antigravityCliAdapter } from './antigravity-cli.ts';
|
|
6
6
|
import { opencodeAdapter } from './opencode.ts';
|
|
7
7
|
|
|
8
8
|
const adaptersById = new Map(
|
|
9
9
|
[
|
|
10
10
|
claudeCodeAdapter,
|
|
11
11
|
codexAdapter,
|
|
12
|
-
|
|
12
|
+
antigravityCliAdapter,
|
|
13
13
|
opencodeAdapter
|
|
14
14
|
].map((adapter) => [adapter.id, adapter])
|
|
15
15
|
);
|
|
@@ -17,6 +17,15 @@ const opencodeAdapter = defineAgentClientAdapter({
|
|
|
17
17
|
sandbox: { level: 'integrated' },
|
|
18
18
|
verification: { level: 'compatible' }
|
|
19
19
|
},
|
|
20
|
+
modelSelection: {
|
|
21
|
+
kind: 'interactive-only',
|
|
22
|
+
command: '/models',
|
|
23
|
+
guidance: 'Use the host model picker for the complete model and reasoning-effort catalog.'
|
|
24
|
+
},
|
|
25
|
+
delegationEvidence: {
|
|
26
|
+
actualModel: 'unavailable',
|
|
27
|
+
actualReasoningEffort: 'unavailable'
|
|
28
|
+
},
|
|
20
29
|
project: {
|
|
21
30
|
ownedPathPrefixes: ['.opencode/'],
|
|
22
31
|
managed: ['.opencode/commands/'],
|
|
@@ -6,7 +6,8 @@ import type {
|
|
|
6
6
|
AgentClientConfig,
|
|
7
7
|
AgentClientId,
|
|
8
8
|
AgentClientsConfig,
|
|
9
|
-
AgentClientState
|
|
9
|
+
AgentClientState,
|
|
10
|
+
OrchestrationModelPolicy
|
|
10
11
|
} from './types.ts';
|
|
11
12
|
|
|
12
13
|
type AgentClientConfigInput = Readonly<{
|
|
@@ -65,12 +66,49 @@ function fail(code: AgentClientDiagnosticCode, path: string): never {
|
|
|
65
66
|
throw new AgentClientConfigError({ code, path });
|
|
66
67
|
}
|
|
67
68
|
|
|
69
|
+
function parseExactText(value: unknown, path: string): string {
|
|
70
|
+
if (typeof value !== 'string' || value.length === 0 || value.trim() !== value) {
|
|
71
|
+
fail('INVALID_AGENT_CLIENTS', path);
|
|
72
|
+
}
|
|
73
|
+
return value;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function parseOrchestrationPolicy(value: unknown, path: string): OrchestrationModelPolicy {
|
|
77
|
+
if (!isRecord(value)) fail('INVALID_AGENT_CLIENTS', path);
|
|
78
|
+
const keys = Object.keys(value);
|
|
79
|
+
if (
|
|
80
|
+
keys.length !== 2
|
|
81
|
+
|| !hasOwn(value, 'executor')
|
|
82
|
+
|| !hasOwn(value, 'reviewer')
|
|
83
|
+
) {
|
|
84
|
+
fail('INVALID_AGENT_CLIENTS', path);
|
|
85
|
+
}
|
|
86
|
+
const parseRole = (candidate: unknown, rolePath: string) => {
|
|
87
|
+
if (
|
|
88
|
+
!isRecord(candidate)
|
|
89
|
+
|| Object.keys(candidate).length !== 2
|
|
90
|
+
|| !hasOwn(candidate, 'model')
|
|
91
|
+
|| !hasOwn(candidate, 'reasoningEffort')
|
|
92
|
+
) {
|
|
93
|
+
fail('INVALID_AGENT_CLIENTS', rolePath);
|
|
94
|
+
}
|
|
95
|
+
return Object.freeze({
|
|
96
|
+
model: parseExactText(candidate.model, `${rolePath}.model`),
|
|
97
|
+
reasoningEffort: parseExactText(candidate.reasoningEffort, `${rolePath}.reasoningEffort`)
|
|
98
|
+
});
|
|
99
|
+
};
|
|
100
|
+
const executor = parseRole(value.executor, `${path}.executor`);
|
|
101
|
+
const reviewer = parseRole(value.reviewer, `${path}.reviewer`);
|
|
102
|
+
return Object.freeze({ executor, reviewer });
|
|
103
|
+
}
|
|
104
|
+
|
|
68
105
|
function parseCanonical(value: unknown): AgentClientState {
|
|
69
106
|
if (!Array.isArray(value)) fail('INVALID_AGENT_CLIENTS', 'agentClients');
|
|
70
107
|
|
|
71
108
|
const entries = new Map<AgentClientId, Readonly<{
|
|
72
109
|
enabled: boolean;
|
|
73
110
|
installInSandbox: boolean;
|
|
111
|
+
orchestration?: OrchestrationModelPolicy;
|
|
74
112
|
}>>();
|
|
75
113
|
|
|
76
114
|
for (const [index, candidate] of value.entries()) {
|
|
@@ -79,10 +117,11 @@ function parseCanonical(value: unknown): AgentClientState {
|
|
|
79
117
|
|
|
80
118
|
const keys = Object.keys(candidate);
|
|
81
119
|
if (
|
|
82
|
-
keys.length !== 3
|
|
120
|
+
(keys.length !== 3 && keys.length !== 4)
|
|
83
121
|
|| !hasOwn(candidate, 'id')
|
|
84
122
|
|| !hasOwn(candidate, 'enabled')
|
|
85
123
|
|| !hasOwn(candidate, 'installInSandbox')
|
|
124
|
+
|| (keys.length === 4 && !hasOwn(candidate, 'orchestration'))
|
|
86
125
|
) {
|
|
87
126
|
fail('INVALID_AGENT_CLIENTS', path);
|
|
88
127
|
}
|
|
@@ -100,7 +139,10 @@ function parseCanonical(value: unknown): AgentClientState {
|
|
|
100
139
|
}
|
|
101
140
|
entries.set(candidate.id, {
|
|
102
141
|
enabled: candidate.enabled,
|
|
103
|
-
installInSandbox: candidate.installInSandbox
|
|
142
|
+
installInSandbox: candidate.installInSandbox,
|
|
143
|
+
...(hasOwn(candidate, 'orchestration')
|
|
144
|
+
? { orchestration: parseOrchestrationPolicy(candidate.orchestration, `${path}.orchestration`) }
|
|
145
|
+
: {})
|
|
104
146
|
});
|
|
105
147
|
}
|
|
106
148
|
|
|
@@ -117,7 +159,10 @@ function serializeAgentClients(state: AgentClientState): AgentClientsConfig {
|
|
|
117
159
|
return AGENT_CLIENT_IDS.map((id): AgentClientConfig => ({
|
|
118
160
|
id,
|
|
119
161
|
enabled: state[id].enabled,
|
|
120
|
-
installInSandbox: state[id].installInSandbox
|
|
162
|
+
installInSandbox: state[id].installInSandbox,
|
|
163
|
+
...(state[id].orchestration
|
|
164
|
+
? { orchestration: structuredClone(state[id].orchestration) }
|
|
165
|
+
: {})
|
|
121
166
|
}));
|
|
122
167
|
}
|
|
123
168
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { listEnabledAgentClientAdapters } from './registry.ts';
|
|
2
2
|
import { renderAgentClientInvocation } from './invocation.ts';
|
|
3
|
+
import semver from 'semver';
|
|
3
4
|
import type { CustomTUI } from './custom-tuis.ts';
|
|
4
5
|
import type { AgentClientId, AgentClientState } from './types.ts';
|
|
5
6
|
|
|
@@ -16,6 +17,7 @@ type RenderNextStepsInput = Readonly<{
|
|
|
16
17
|
customTUIs: readonly CustomTUI[];
|
|
17
18
|
skillName: string;
|
|
18
19
|
taskRef?: string;
|
|
20
|
+
version?: string;
|
|
19
21
|
}>;
|
|
20
22
|
|
|
21
23
|
const SAFE_NAME = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
|
|
@@ -35,6 +37,17 @@ function renderNextStepCommands(
|
|
|
35
37
|
if (input.taskRef !== undefined && !SAFE_TASK_REF.test(input.taskRef)) {
|
|
36
38
|
throw new Error('Invalid task ref');
|
|
37
39
|
}
|
|
40
|
+
if (
|
|
41
|
+
input.version !== undefined
|
|
42
|
+
&& (!/^[0-9]/.test(input.version) || semver.valid(input.version) !== input.version)
|
|
43
|
+
) {
|
|
44
|
+
throw new Error('Invalid version');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const args = [
|
|
48
|
+
...(input.taskRef === undefined ? [] : [input.taskRef]),
|
|
49
|
+
...(input.version === undefined ? [] : [input.version])
|
|
50
|
+
];
|
|
38
51
|
|
|
39
52
|
const builtins = listEnabledAgentClientAdapters(input.state).map(
|
|
40
53
|
(adapter): NextStepCommand => Object.freeze({
|
|
@@ -46,7 +59,7 @@ function renderNextStepCommands(
|
|
|
46
59
|
{
|
|
47
60
|
projectName: input.projectName,
|
|
48
61
|
skillName: input.skillName,
|
|
49
|
-
args
|
|
62
|
+
args
|
|
50
63
|
}
|
|
51
64
|
)
|
|
52
65
|
})
|
|
@@ -60,7 +73,7 @@ function renderNextStepCommands(
|
|
|
60
73
|
{
|
|
61
74
|
projectName: input.projectName,
|
|
62
75
|
skillName: input.skillName,
|
|
63
|
-
args
|
|
76
|
+
args
|
|
64
77
|
}
|
|
65
78
|
)
|
|
66
79
|
})
|
|
@@ -236,7 +236,8 @@ function planAgentClientReconciliation(input: Readonly<{
|
|
|
236
236
|
const actionableSeed = seedOperations.some((operation) =>
|
|
237
237
|
operation.kind === 'write' || operation.kind === 'remove'
|
|
238
238
|
);
|
|
239
|
-
const changed = JSON.stringify(nextConfig) !== JSON.stringify(input.config)
|
|
239
|
+
const changed = JSON.stringify(nextConfig) !== JSON.stringify(input.config)
|
|
240
|
+
|| actionableSeed;
|
|
240
241
|
|
|
241
242
|
return Object.freeze({
|
|
242
243
|
source: normalized.source,
|
|
@@ -104,6 +104,14 @@ function getAgentClientCapability(
|
|
|
104
104
|
return getAgentClientAdapter(id).capabilities[capability];
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
+
function getAgentClientModelSelection(id: unknown) {
|
|
108
|
+
return getAgentClientAdapter(id).modelSelection;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function getAgentClientDelegationEvidence(id: unknown) {
|
|
112
|
+
return getAgentClientAdapter(id).delegationEvidence;
|
|
113
|
+
}
|
|
114
|
+
|
|
107
115
|
function listEnabledAgentClientAdaptersByCapability(
|
|
108
116
|
state: AgentClientState,
|
|
109
117
|
capability: AgentClientCapabilityId,
|
|
@@ -137,6 +145,8 @@ export {
|
|
|
137
145
|
createAgentClientManifest,
|
|
138
146
|
getAgentClientAdapter,
|
|
139
147
|
getAgentClientCapability,
|
|
148
|
+
getAgentClientDelegationEvidence,
|
|
149
|
+
getAgentClientModelSelection,
|
|
140
150
|
listAgentClientAdapters,
|
|
141
151
|
listEnabledAgentClientAdapters,
|
|
142
152
|
listEnabledAgentClientAdaptersByCapability,
|
|
@@ -29,6 +29,15 @@ const AGENT_CLIENTS_SCHEMA = {
|
|
|
29
29
|
},
|
|
30
30
|
installInSandbox: {
|
|
31
31
|
type: 'boolean'
|
|
32
|
+
},
|
|
33
|
+
orchestration: {
|
|
34
|
+
type: 'object',
|
|
35
|
+
additionalProperties: false,
|
|
36
|
+
required: ['executor', 'reviewer'],
|
|
37
|
+
properties: {
|
|
38
|
+
executor: { $ref: '#/definitions/orchestrationRolePolicy' },
|
|
39
|
+
reviewer: { $ref: '#/definitions/orchestrationRolePolicy' }
|
|
40
|
+
}
|
|
32
41
|
}
|
|
33
42
|
}
|
|
34
43
|
}
|
|
@@ -48,6 +57,15 @@ const AGENT_CLIENTS_SCHEMA = {
|
|
|
48
57
|
}
|
|
49
58
|
},
|
|
50
59
|
definitions: {
|
|
60
|
+
orchestrationRolePolicy: {
|
|
61
|
+
type: 'object',
|
|
62
|
+
additionalProperties: false,
|
|
63
|
+
required: ['model', 'reasoningEffort'],
|
|
64
|
+
properties: {
|
|
65
|
+
model: { type: 'string', minLength: 1 },
|
|
66
|
+
reasoningEffort: { type: 'string', minLength: 1 }
|
|
67
|
+
}
|
|
68
|
+
},
|
|
51
69
|
agentClientCapabilityId: {
|
|
52
70
|
type: 'string',
|
|
53
71
|
enum: [...AGENT_CLIENT_CAPABILITY_IDS]
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// Active AI collaborator short tokens — the write-side whitelist for the
|
|
2
|
+
// activity log. Migrated from lib/task/commands/log.ts so that the write-side
|
|
3
|
+
// internal commands and the rendering side share one definition. Historical
|
|
4
|
+
// Gemini tokens remain read-only and are handled by classifyAgent below.
|
|
5
|
+
export const KNOWN_AI_AGENTS: ReadonlySet<string> =
|
|
6
|
+
new Set(['claude', 'codex', 'antigravity', 'opencode', 'cursor']);
|
|
7
|
+
|
|
8
|
+
// Long name -> short name mapping (HD-4, decision A): `claude-code` reuses the
|
|
9
|
+
// existing orchestration precedent, and `antigravity-cli` is the active
|
|
10
|
+
// client. `gemini-cli` is intentionally not writable.
|
|
11
|
+
export const AGENT_LONG_NAMES: Readonly<Record<string, string>> = {
|
|
12
|
+
'claude-code': 'claude',
|
|
13
|
+
'antigravity-cli': 'antigravity'
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const AGENT_USAGE_HINT =
|
|
17
|
+
"agent must be a short token (claude/codex/antigravity/opencode/cursor), " +
|
|
18
|
+
"a long name (claude-code -> claude, antigravity-cli -> antigravity), or 'human'";
|
|
19
|
+
|
|
20
|
+
// Read-side historical compatibility for activity-log rendering: `gemini` and
|
|
21
|
+
// `gemini-cli` stay recognizable when displaying old logs, but are never
|
|
22
|
+
// accepted by normalizeAgentToken (write side).
|
|
23
|
+
const READ_KNOWN_AI_AGENTS: ReadonlySet<string> =
|
|
24
|
+
new Set([...KNOWN_AI_AGENTS, 'gemini']);
|
|
25
|
+
|
|
26
|
+
const READ_AGENT_LONG_NAMES: Readonly<Record<string, string>> = {
|
|
27
|
+
...AGENT_LONG_NAMES,
|
|
28
|
+
'gemini-cli': 'gemini'
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Strict write-side validation: the value must be exactly a short token, a
|
|
32
|
+
// long name, or 'human'; returns the normalized short token, or null when
|
|
33
|
+
// the value is not a recognized agent.
|
|
34
|
+
export function normalizeAgentToken(value: string): string | null {
|
|
35
|
+
const trimmed = value.trim();
|
|
36
|
+
if (trimmed === 'human') return 'human';
|
|
37
|
+
if (KNOWN_AI_AGENTS.has(trimmed)) return trimmed;
|
|
38
|
+
const short = AGENT_LONG_NAMES[trimmed];
|
|
39
|
+
return short ?? null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Loose rendering-side classification: tolerates historical parenthetical
|
|
43
|
+
// annotations; unknown tokens keep the `human` grouping but get a visible
|
|
44
|
+
// signal. The "known AI token" test is `classifyAgent(value).status === 'ai'`.
|
|
45
|
+
export function classifyAgent(raw: string):
|
|
46
|
+
{ status: 'ai' | 'human' | 'unknown'; display: string } {
|
|
47
|
+
const token = raw.trim().split(/\s+/)[0]?.replace(/\(.*$/, '') ?? '';
|
|
48
|
+
if (token === '') return { status: 'unknown', display: 'human' };
|
|
49
|
+
if (token === 'human') return { status: 'human', display: 'human' };
|
|
50
|
+
if (READ_KNOWN_AI_AGENTS.has(token)) return { status: 'ai', display: token };
|
|
51
|
+
const short = READ_AGENT_LONG_NAMES[token];
|
|
52
|
+
return short ? { status: 'ai', display: short } : { status: 'unknown', display: 'human' };
|
|
53
|
+
}
|
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
const AGENT_CLIENT_IDS = [
|
|
2
2
|
'claude-code',
|
|
3
3
|
'codex',
|
|
4
|
-
'
|
|
4
|
+
'antigravity-cli',
|
|
5
5
|
'opencode'
|
|
6
6
|
] as const;
|
|
7
7
|
|
|
8
8
|
type AgentClientId = (typeof AGENT_CLIENT_IDS)[number];
|
|
9
9
|
|
|
10
|
+
type OrchestrationRolePolicy = Readonly<{
|
|
11
|
+
model: string;
|
|
12
|
+
reasoningEffort: string;
|
|
13
|
+
}>;
|
|
14
|
+
|
|
15
|
+
type OrchestrationModelPolicy = Readonly<{
|
|
16
|
+
executor: OrchestrationRolePolicy;
|
|
17
|
+
reviewer: OrchestrationRolePolicy;
|
|
18
|
+
}>;
|
|
19
|
+
|
|
10
20
|
type AgentClientConfig = Readonly<{
|
|
11
21
|
id: AgentClientId;
|
|
12
22
|
enabled: boolean;
|
|
13
23
|
installInSandbox: boolean;
|
|
24
|
+
orchestration?: OrchestrationModelPolicy;
|
|
14
25
|
}>;
|
|
15
26
|
|
|
16
27
|
type AgentClientsConfig = readonly AgentClientConfig[];
|
|
@@ -21,6 +32,7 @@ type AgentClientState = Readonly<
|
|
|
21
32
|
Readonly<{
|
|
22
33
|
enabled: boolean;
|
|
23
34
|
installInSandbox: boolean;
|
|
35
|
+
orchestration?: OrchestrationModelPolicy;
|
|
24
36
|
}>
|
|
25
37
|
>
|
|
26
38
|
>;
|
|
@@ -68,6 +80,8 @@ export {
|
|
|
68
80
|
};
|
|
69
81
|
export type {
|
|
70
82
|
AgentClientId,
|
|
83
|
+
OrchestrationRolePolicy,
|
|
84
|
+
OrchestrationModelPolicy,
|
|
71
85
|
AgentClientConfig,
|
|
72
86
|
AgentClientsConfig,
|
|
73
87
|
AgentClientState,
|
package/lib/defaults.json
CHANGED
package/lib/git/workflow.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
2
4
|
|
|
3
5
|
type CommandResult = { status: number | null; stdout: string; stderr: string };
|
|
4
6
|
type GitRunner = (args: readonly string[], cwd: string) => CommandResult;
|
|
@@ -18,6 +20,10 @@ function value(runner: GitRunner, cwd: string, args: readonly string[], trim = t
|
|
|
18
20
|
return result.status === 0 ? (trim ? result.stdout.trim() : result.stdout.replace(/\n$/, '')) : null;
|
|
19
21
|
}
|
|
20
22
|
|
|
23
|
+
function cleanMessage(message: string): string {
|
|
24
|
+
return message.replace(/(https?:\/\/)[^\s/@:]+(?::[^\s/@]*)?@/gi, '$1***@').trim();
|
|
25
|
+
}
|
|
26
|
+
|
|
21
27
|
function inspectGitWorkflow(cwd: string, runner: GitRunner = defaultRunner, remoteInput?: { remote: string; refs: readonly string[] }) {
|
|
22
28
|
const head = value(runner, cwd, ['rev-parse', 'HEAD']);
|
|
23
29
|
const branch = value(runner, cwd, ['branch', '--show-current']);
|
|
@@ -97,5 +103,63 @@ function pushGitRefs(input: { cwd: string; remote: string; refs: readonly string
|
|
|
97
103
|
return { status: failures === 0 ? 'applied' as const : failures === operations.length ? 'failed' as const : 'degraded' as const, changed: failures < operations.length, snapshot: inspectGitWorkflow(input.cwd, runner).snapshot, operations, error: failures ? { code: 'GIT_PUSH_PARTIAL', message: `${failures} ref push operation(s) failed` } : null };
|
|
98
104
|
}
|
|
99
105
|
|
|
100
|
-
|
|
101
|
-
|
|
106
|
+
type PushRebasedInput = {
|
|
107
|
+
cwd: string;
|
|
108
|
+
remote: string;
|
|
109
|
+
branch: string;
|
|
110
|
+
expectedOldHead: string;
|
|
111
|
+
newHead: string;
|
|
112
|
+
baseBranch: string;
|
|
113
|
+
expectedBaseHead: string;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
function pushRebasedBranch(input: PushRebasedInput, runner: GitRunner = defaultRunner) {
|
|
117
|
+
const sha = /^[0-9a-f]{40}$/i;
|
|
118
|
+
const refName = /^(?!-)(?!.*\.\.)(?!.*(?:^|\/)\.)(?!.*[~^:?*\[\\\s])(?:[A-Za-z0-9._-]+\/)*[A-Za-z0-9._-]+$/;
|
|
119
|
+
if (!input.remote || !refName.test(input.remote) || !refName.test(input.branch) || !refName.test(input.baseBranch) ||
|
|
120
|
+
!sha.test(input.expectedOldHead) || !sha.test(input.newHead) || !sha.test(input.expectedBaseHead)) {
|
|
121
|
+
return { status: 'failed' as const, changed: false, snapshot: null, operations: [], error: { code: 'GIT_REBASED_INPUT_INVALID', message: 'Remote, branches, and full 40-character SHAs are required' } };
|
|
122
|
+
}
|
|
123
|
+
const snapshot = inspectGitWorkflow(input.cwd, runner).snapshot;
|
|
124
|
+
if (!snapshot) return { status: 'failed' as const, changed: false, snapshot: null, operations: [], error: { code: 'GIT_INSPECT_FAILED', message: 'Unable to inspect Git repository' } };
|
|
125
|
+
if (snapshot.branch !== input.branch || snapshot.head !== input.newHead) {
|
|
126
|
+
return { status: 'failed' as const, changed: false, snapshot, operations: [], error: { code: 'GIT_LOCAL_IDENTITY_MISMATCH', message: 'Current branch or HEAD does not match the rebased intent' } };
|
|
127
|
+
}
|
|
128
|
+
const rebasePaths = ['rebase-merge', 'rebase-apply']
|
|
129
|
+
.map((name) => value(runner, input.cwd, ['rev-parse', '--git-path', name]))
|
|
130
|
+
.filter((candidate): candidate is string => Boolean(candidate));
|
|
131
|
+
if (snapshot.worktree.length > 0 || snapshot.staged.length > 0 ||
|
|
132
|
+
run(runner, input.cwd, ['rev-parse', '-q', '--verify', 'REBASE_HEAD']).status === 0 ||
|
|
133
|
+
rebasePaths.some((candidate) => fs.existsSync(path.isAbsolute(candidate) ? candidate : path.join(input.cwd, candidate)))) {
|
|
134
|
+
return { status: 'failed' as const, changed: false, snapshot, operations: [], error: { code: 'GIT_LOCAL_STATE_UNSAFE', message: 'Working tree must be clean with no rebase in progress' } };
|
|
135
|
+
}
|
|
136
|
+
const remoteRef = `refs/heads/${input.branch}`;
|
|
137
|
+
const baseRef = `refs/heads/${input.baseBranch}`;
|
|
138
|
+
const remoteHead = value(runner, input.cwd, ['ls-remote', '--exit-code', input.remote, remoteRef])?.split(/\s+/)[0] ?? null;
|
|
139
|
+
if (remoteHead !== input.expectedOldHead) {
|
|
140
|
+
return { status: 'failed' as const, changed: false, snapshot, operations: [], error: { code: 'GIT_REMOTE_HEAD_MISMATCH', message: `Expected remote head ${input.expectedOldHead}, received ${remoteHead ?? 'unavailable'}` } };
|
|
141
|
+
}
|
|
142
|
+
const baseHead = value(runner, input.cwd, ['ls-remote', '--exit-code', input.remote, baseRef])?.split(/\s+/)[0] ?? null;
|
|
143
|
+
if (baseHead !== input.expectedBaseHead) {
|
|
144
|
+
return { status: 'failed' as const, changed: false, snapshot, operations: [], error: { code: 'GIT_REMOTE_BASE_MISMATCH', message: `Expected base head ${input.expectedBaseHead}, received ${baseHead ?? 'unavailable'}` } };
|
|
145
|
+
}
|
|
146
|
+
if (run(runner, input.cwd, ['merge-base', '--is-ancestor', input.expectedBaseHead, input.newHead]).status !== 0) {
|
|
147
|
+
return { status: 'failed' as const, changed: false, snapshot, operations: [], error: { code: 'GIT_REBASED_ANCESTOR_MISMATCH', message: 'Rebased head does not contain the expected base head' } };
|
|
148
|
+
}
|
|
149
|
+
const pushed = run(runner, input.cwd, [
|
|
150
|
+
'push', `--force-with-lease=${remoteRef}:${input.expectedOldHead}`,
|
|
151
|
+
input.remote, `${input.newHead}:${remoteRef}`
|
|
152
|
+
]);
|
|
153
|
+
if (pushed.status !== 0) {
|
|
154
|
+
const message = cleanMessage(pushed.stderr) || 'Rebased branch push was rejected';
|
|
155
|
+
return { status: 'failed' as const, changed: false, snapshot: inspectGitWorkflow(input.cwd, runner).snapshot, operations: [{ name: 'push-rebased', status: 'failed' as const, ref: input.branch, message }], error: { code: 'GIT_REBASED_PUSH_REJECTED', message } };
|
|
156
|
+
}
|
|
157
|
+
const verified = value(runner, input.cwd, ['ls-remote', '--exit-code', input.remote, remoteRef])?.split(/\s+/)[0] ?? null;
|
|
158
|
+
if (verified !== input.newHead) {
|
|
159
|
+
return { status: 'failed' as const, changed: true, snapshot: inspectGitWorkflow(input.cwd, runner).snapshot, operations: [{ name: 'push-rebased', status: 'failed' as const, ref: input.branch, message: 'Remote ref verification failed' }], error: { code: 'GIT_REBASED_VERIFY_FAILED', message: `Expected pushed head ${input.newHead}, received ${verified ?? 'unavailable'}` } };
|
|
160
|
+
}
|
|
161
|
+
return { status: 'applied' as const, changed: true, snapshot: inspectGitWorkflow(input.cwd, runner).snapshot, operations: [{ name: 'push-rebased', status: 'applied' as const, ref: input.branch }], error: null };
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export { commitExplicitPaths, inspectGitWorkflow, pushGitRefs, pushRebasedBranch };
|
|
165
|
+
export type { CommandResult, GitRunner, PushRebasedInput };
|