@evalops/maestro 0.10.50 → 0.10.51
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/dist/agent/agent-outcome.d.ts +54 -0
- package/dist/agent/agent-outcome.d.ts.map +1 -0
- package/dist/agent/agent-outcome.js +142 -0
- package/dist/agent/agent-outcome.js.map +1 -0
- package/dist/agent/agent-resume.d.ts.map +1 -1
- package/dist/agent/agent-resume.js +3 -3
- package/dist/agent/agent-resume.js.map +1 -1
- package/dist/agent/agent-run-summary.d.ts +37 -0
- package/dist/agent/agent-run-summary.d.ts.map +1 -0
- package/dist/agent/agent-run-summary.js +15 -0
- package/dist/agent/agent-run-summary.js.map +1 -0
- package/dist/agent/agent-work-board.d.ts +82 -0
- package/dist/agent/agent-work-board.d.ts.map +1 -0
- package/dist/agent/agent-work-board.js +312 -0
- package/dist/agent/agent-work-board.js.map +1 -0
- package/dist/agent/auto-compaction.d.ts +7 -2
- package/dist/agent/auto-compaction.d.ts.map +1 -1
- package/dist/agent/auto-compaction.js +23 -10
- package/dist/agent/auto-compaction.js.map +1 -1
- package/dist/agent/mission-artifacts.d.ts +62 -0
- package/dist/agent/mission-artifacts.d.ts.map +1 -0
- package/dist/agent/mission-artifacts.js +438 -0
- package/dist/agent/mission-artifacts.js.map +1 -0
- package/dist/agent/mission-manifest.d.ts +139 -3
- package/dist/agent/mission-manifest.d.ts.map +1 -1
- package/dist/agent/mission-manifest.js +549 -3
- package/dist/agent/mission-manifest.js.map +1 -1
- package/dist/agent/mission-store.d.ts +80 -0
- package/dist/agent/mission-store.d.ts.map +1 -0
- package/dist/agent/mission-store.js +603 -0
- package/dist/agent/mission-store.js.map +1 -0
- package/dist/agent/modes.d.ts +2 -2
- package/dist/agent/modes.d.ts.map +1 -1
- package/dist/agent/modes.js +10 -3
- package/dist/agent/modes.js.map +1 -1
- package/dist/agent/providers/codex-app-server.d.ts.map +1 -1
- package/dist/agent/providers/codex-app-server.js +1 -3
- package/dist/agent/providers/codex-app-server.js.map +1 -1
- package/dist/agent/providers/google-gemini-cli.js +203 -107
- package/dist/agent/providers/google.js +100 -41
- package/dist/agent/providers/scripted.d.ts.map +1 -1
- package/dist/agent/providers/scripted.js +1 -3
- package/dist/agent/providers/scripted.js.map +1 -1
- package/dist/agent/providers/validation.d.ts.map +1 -1
- package/dist/agent/providers/validation.js +1 -3
- package/dist/agent/providers/validation.js.map +1 -1
- package/dist/agent/providers/vertex.js +203 -107
- package/dist/agent/snapshot-store.d.ts +32 -0
- package/dist/agent/snapshot-store.d.ts.map +1 -0
- package/dist/agent/snapshot-store.js +195 -0
- package/dist/agent/snapshot-store.js.map +1 -0
- package/dist/agent/specialist-profiles.d.ts +36 -0
- package/dist/agent/specialist-profiles.d.ts.map +1 -0
- package/dist/agent/specialist-profiles.js +159 -0
- package/dist/agent/specialist-profiles.js.map +1 -0
- package/dist/agent/subagent-specs.d.ts +4 -1
- package/dist/agent/subagent-specs.d.ts.map +1 -1
- package/dist/agent/subagent-specs.js +81 -8
- package/dist/agent/subagent-specs.js.map +1 -1
- package/dist/agent/swarm/coverage-gate.d.ts +37 -0
- package/dist/agent/swarm/coverage-gate.d.ts.map +1 -0
- package/dist/agent/swarm/coverage-gate.js +48 -0
- package/dist/agent/swarm/coverage-gate.js.map +1 -0
- package/dist/agent/swarm/executor.d.ts +1 -0
- package/dist/agent/swarm/executor.d.ts.map +1 -1
- package/dist/agent/swarm/executor.js +151 -15
- package/dist/agent/swarm/executor.js.map +1 -1
- package/dist/agent/swarm/orchestrator-prompt.d.ts +25 -0
- package/dist/agent/swarm/orchestrator-prompt.d.ts.map +1 -0
- package/dist/agent/swarm/orchestrator-prompt.js +48 -0
- package/dist/agent/swarm/orchestrator-prompt.js.map +1 -0
- package/dist/agent/swarm/plan-parser.d.ts.map +1 -1
- package/dist/agent/swarm/plan-parser.js +27 -2
- package/dist/agent/swarm/plan-parser.js.map +1 -1
- package/dist/agent/swarm/types.d.ts +17 -0
- package/dist/agent/swarm/types.d.ts.map +1 -1
- package/dist/agent/swarm/types.js.map +1 -1
- package/dist/agent/swarm/validation-directive.d.ts +21 -0
- package/dist/agent/swarm/validation-directive.d.ts.map +1 -0
- package/dist/agent/swarm/validation-directive.js +25 -0
- package/dist/agent/swarm/validation-directive.js.map +1 -0
- package/dist/agent/transport/tool-execution-bridge.d.ts.map +1 -1
- package/dist/agent/transport/tool-execution-bridge.js +4 -1
- package/dist/agent/transport/tool-execution-bridge.js.map +1 -1
- package/dist/api/enterprise-routes.d.ts.map +1 -1
- package/dist/api/enterprise-routes.js +87 -10
- package/dist/api/enterprise-routes.js.map +1 -1
- package/dist/api/org-settings-merge.d.ts +12 -0
- package/dist/api/org-settings-merge.d.ts.map +1 -0
- package/dist/api/org-settings-merge.js +38 -0
- package/dist/api/org-settings-merge.js.map +1 -0
- package/dist/api/user-settings-merge.d.ts +16 -0
- package/dist/api/user-settings-merge.d.ts.map +1 -0
- package/dist/api/user-settings-merge.js +37 -0
- package/dist/api/user-settings-merge.js.map +1 -0
- package/dist/app-server/daemon-lifecycle-api.d.ts.map +1 -1
- package/dist/app-server/daemon-lifecycle-api.js +1 -3
- package/dist/app-server/daemon-lifecycle-api.js.map +1 -1
- package/dist/app-server/external-agent-import-api.d.ts.map +1 -1
- package/dist/app-server/external-agent-import-api.js +1 -3
- package/dist/app-server/external-agent-import-api.js.map +1 -1
- package/dist/app-server/network-governance-api.d.ts.map +1 -1
- package/dist/app-server/network-governance-api.js +1 -3
- package/dist/app-server/network-governance-api.js.map +1 -1
- package/dist/app-server/plugin-bundle-api.d.ts.map +1 -1
- package/dist/app-server/plugin-bundle-api.js +1 -3
- package/dist/app-server/plugin-bundle-api.js.map +1 -1
- package/dist/app-server/policy-control-api.d.ts.map +1 -1
- package/dist/app-server/policy-control-api.js +1 -3
- package/dist/app-server/policy-control-api.js.map +1 -1
- package/dist/app-server/protocol-modes-api.d.ts.map +1 -1
- package/dist/app-server/protocol-modes-api.js +1 -3
- package/dist/app-server/protocol-modes-api.js.map +1 -1
- package/dist/cli/args.d.ts +2 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +15 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/commands/a2a.d.ts.map +1 -1
- package/dist/cli/commands/a2a.js +1 -3
- package/dist/cli/commands/a2a.js.map +1 -1
- package/dist/cli/commands/agents.d.ts +4 -0
- package/dist/cli/commands/agents.d.ts.map +1 -1
- package/dist/cli/commands/agents.js +149 -0
- package/dist/cli/commands/agents.js.map +1 -1
- package/dist/cli/commands/mission.d.ts +4 -0
- package/dist/cli/commands/mission.d.ts.map +1 -0
- package/dist/cli/commands/mission.js +196 -0
- package/dist/cli/commands/mission.js.map +1 -0
- package/dist/cli/commands/value.d.ts +10 -0
- package/dist/cli/commands/value.d.ts.map +1 -0
- package/dist/cli/commands/value.js +33 -0
- package/dist/cli/commands/value.js.map +1 -0
- package/dist/cli/headless-protocol.d.ts.map +1 -1
- package/dist/cli/headless-protocol.js +1 -3
- package/dist/cli/headless-protocol.js.map +1 -1
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +10 -0
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/system-prompt.d.ts.map +1 -1
- package/dist/cli/system-prompt.js +38 -7
- package/dist/cli/system-prompt.js.map +1 -1
- package/dist/cli-runtime.js +7756 -2800
- package/dist/cli-tui/client-tools/client-tool-controller.d.ts.map +1 -1
- package/dist/cli-tui/client-tools/client-tool-controller.js +1 -3
- package/dist/cli-tui/client-tools/client-tool-controller.js.map +1 -1
- package/dist/cli-tui/commands/undo-handlers.d.ts.map +1 -1
- package/dist/cli-tui/commands/undo-handlers.js +7 -2
- package/dist/cli-tui/commands/undo-handlers.js.map +1 -1
- package/dist/cli-tui/tui-renderer/skills-controller.d.ts +3 -0
- package/dist/cli-tui/tui-renderer/skills-controller.d.ts.map +1 -1
- package/dist/cli-tui/tui-renderer/skills-controller.js +77 -33
- package/dist/cli-tui/tui-renderer/skills-controller.js.map +1 -1
- package/dist/codex/app-server-client.d.ts.map +1 -1
- package/dist/codex/app-server-client.js +1 -3
- package/dist/codex/app-server-client.js.map +1 -1
- package/dist/codex/compatibility.d.ts.map +1 -1
- package/dist/codex/compatibility.js +1 -3
- package/dist/codex/compatibility.js.map +1 -1
- package/dist/codex/subagent-dispatch-table.d.ts +8 -0
- package/dist/codex/subagent-dispatch-table.d.ts.map +1 -1
- package/dist/codex/subagent-dispatch-table.js +23 -0
- package/dist/codex/subagent-dispatch-table.js.map +1 -1
- package/dist/context/manifest.d.ts.map +1 -1
- package/dist/context/manifest.js +1 -3
- package/dist/context/manifest.js.map +1 -1
- package/dist/conversation/render-model.d.ts +0 -36
- package/dist/conversation/render-model.d.ts.map +1 -1
- package/dist/conversation/render-model.js +1 -3
- package/dist/conversation/render-model.js.map +1 -1
- package/dist/customer-value/ambient-learning.d.ts +75 -0
- package/dist/customer-value/ambient-learning.d.ts.map +1 -0
- package/dist/customer-value/ambient-learning.js +472 -0
- package/dist/customer-value/ambient-learning.js.map +1 -0
- package/dist/customer-value/internal-helpers.d.ts +13 -0
- package/dist/customer-value/internal-helpers.d.ts.map +1 -0
- package/dist/customer-value/internal-helpers.js +70 -0
- package/dist/customer-value/internal-helpers.js.map +1 -0
- package/dist/customer-value/report.d.ts +282 -0
- package/dist/customer-value/report.d.ts.map +1 -0
- package/dist/customer-value/report.js +2085 -0
- package/dist/customer-value/report.js.map +1 -0
- package/dist/db/schema.d.ts +5 -1
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js.map +1 -1
- package/dist/evalops/agent-bootstrap.d.ts.map +1 -1
- package/dist/evalops/agent-bootstrap.js +1 -3
- package/dist/evalops/agent-bootstrap.js.map +1 -1
- package/dist/evalops/agent-mcp-metadata.d.ts.map +1 -1
- package/dist/evalops/agent-mcp-metadata.js +1 -3
- package/dist/evalops/agent-mcp-metadata.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/installers/maestro-review-workflow.d.ts +38 -0
- package/dist/installers/maestro-review-workflow.d.ts.map +1 -0
- package/dist/installers/maestro-review-workflow.js +163 -0
- package/dist/installers/maestro-review-workflow.js.map +1 -0
- package/dist/load-env.d.ts.map +1 -1
- package/dist/load-env.js +2 -1
- package/dist/load-env.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +92 -3
- package/dist/main.js.map +1 -1
- package/dist/mcp/config.d.ts.map +1 -1
- package/dist/mcp/config.js +1 -3
- package/dist/mcp/config.js.map +1 -1
- package/dist/mcp/elicitation.d.ts.map +1 -1
- package/dist/mcp/elicitation.js +1 -3
- package/dist/mcp/elicitation.js.map +1 -1
- package/dist/mcp/official-registry.d.ts.map +1 -1
- package/dist/mcp/official-registry.js +1 -3
- package/dist/mcp/official-registry.js.map +1 -1
- package/dist/mcp/workspace-trust.d.ts.map +1 -1
- package/dist/mcp/workspace-trust.js +1 -3
- package/dist/mcp/workspace-trust.js.map +1 -1
- package/dist/memory/service-client.d.ts.map +1 -1
- package/dist/memory/service-client.js +1 -3
- package/dist/memory/service-client.js.map +1 -1
- package/dist/models/config-loader.d.ts.map +1 -1
- package/dist/models/config-loader.js +1 -3
- package/dist/models/config-loader.js.map +1 -1
- package/dist/node_modules/@evalops/contracts/dist/index.d.ts +1 -0
- package/dist/node_modules/@evalops/contracts/dist/index.d.ts.map +1 -1
- package/dist/node_modules/@evalops/contracts/dist/index.js +1 -0
- package/dist/node_modules/@evalops/contracts/dist/index.js.map +1 -1
- package/dist/node_modules/@evalops/contracts/dist/maestro-settings.d.ts +61 -0
- package/dist/node_modules/@evalops/contracts/dist/maestro-settings.d.ts.map +1 -0
- package/dist/node_modules/@evalops/contracts/dist/maestro-settings.js +183 -0
- package/dist/node_modules/@evalops/contracts/dist/maestro-settings.js.map +1 -0
- package/dist/node_modules/@evalops/contracts/package.json +1 -1
- package/dist/node_modules/@evalops/tui/package.json +1 -1
- package/dist/oauth/connectors.d.ts.map +1 -1
- package/dist/oauth/connectors.js +1 -3
- package/dist/oauth/connectors.js.map +1 -1
- package/dist/oauth/evalops.d.ts.map +1 -1
- package/dist/oauth/evalops.js +1 -3
- package/dist/oauth/evalops.js.map +1 -1
- package/dist/platform/a2a-client.d.ts.map +1 -1
- package/dist/platform/a2a-client.js +1 -3
- package/dist/platform/a2a-client.js.map +1 -1
- package/dist/platform/a2a-cockpit.d.ts +1 -0
- package/dist/platform/a2a-cockpit.d.ts.map +1 -1
- package/dist/platform/a2a-cockpit.js +42 -11
- package/dist/platform/a2a-cockpit.js.map +1 -1
- package/dist/platform/a2a-completion-audit.d.ts +1 -1
- package/dist/platform/a2a-completion-audit.d.ts.map +1 -1
- package/dist/platform/a2a-completion-audit.js +7 -11
- package/dist/platform/a2a-completion-audit.js.map +1 -1
- package/dist/platform/a2a-maestro-peer.js +16 -0
- package/dist/platform/a2a-maestro-peer.js.map +1 -1
- package/dist/platform/a2a-peer-pairing.d.ts.map +1 -1
- package/dist/platform/a2a-peer-pairing.js +1 -3
- package/dist/platform/a2a-peer-pairing.js.map +1 -1
- package/dist/platform/a2a-peer-registry.d.ts.map +1 -1
- package/dist/platform/a2a-peer-registry.js +1 -3
- package/dist/platform/a2a-peer-registry.js.map +1 -1
- package/dist/platform/a2a-task-ledger.d.ts +20 -0
- package/dist/platform/a2a-task-ledger.d.ts.map +1 -1
- package/dist/platform/a2a-task-ledger.js +207 -11
- package/dist/platform/a2a-task-ledger.js.map +1 -1
- package/dist/platform/a2a-work-graph.d.ts.map +1 -1
- package/dist/platform/a2a-work-graph.js +1 -3
- package/dist/platform/a2a-work-graph.js.map +1 -1
- package/dist/platform/operating-layer.d.ts.map +1 -1
- package/dist/platform/operating-layer.js +14 -8
- package/dist/platform/operating-layer.js.map +1 -1
- package/dist/platform/tool-execution-client.d.ts.map +1 -1
- package/dist/platform/tool-execution-client.js +19 -2
- package/dist/platform/tool-execution-client.js.map +1 -1
- package/dist/providers/auth.d.ts.map +1 -1
- package/dist/providers/auth.js +1 -3
- package/dist/providers/auth.js.map +1 -1
- package/dist/runtime/env.d.ts +9 -1
- package/dist/runtime/env.d.ts.map +1 -1
- package/dist/runtime/env.js +63 -1
- package/dist/runtime/env.js.map +1 -1
- package/dist/safety/policy.d.ts.map +1 -1
- package/dist/safety/policy.js +1 -4
- package/dist/safety/policy.js.map +1 -1
- package/dist/sandbox/docker-sandbox.d.ts.map +1 -1
- package/dist/sandbox/docker-sandbox.js +6 -1
- package/dist/sandbox/docker-sandbox.js.map +1 -1
- package/dist/server/handlers/hosted-runner-drain.d.ts.map +1 -1
- package/dist/server/handlers/hosted-runner-drain.js +1 -3
- package/dist/server/handlers/hosted-runner-drain.js.map +1 -1
- package/dist/server/handlers/platform-a2a-push.d.ts.map +1 -1
- package/dist/server/handlers/platform-a2a-push.js +53 -2
- package/dist/server/handlers/platform-a2a-push.js.map +1 -1
- package/dist/server/handlers/runtime-app-server-ws.d.ts.map +1 -1
- package/dist/server/handlers/runtime-app-server-ws.js +1 -3
- package/dist/server/handlers/runtime-app-server-ws.js.map +1 -1
- package/dist/server/headless-runtime-service.d.ts +16 -0
- package/dist/server/headless-runtime-service.d.ts.map +1 -1
- package/dist/server/headless-runtime-service.js +232 -206
- package/dist/server/headless-runtime-service.js.map +1 -1
- package/dist/server/hosted-agent-runtime-progress.d.ts.map +1 -1
- package/dist/server/hosted-agent-runtime-progress.js +12 -3
- package/dist/server/hosted-agent-runtime-progress.js.map +1 -1
- package/dist/server/pending-request-payload.d.ts.map +1 -1
- package/dist/server/pending-request-payload.js +1 -3
- package/dist/server/pending-request-payload.js.map +1 -1
- package/dist/server/route-auth.d.ts.map +1 -1
- package/dist/server/route-auth.js +2 -0
- package/dist/server/route-auth.js.map +1 -1
- package/dist/server/session-serialization.d.ts.map +1 -1
- package/dist/server/session-serialization.js +1 -3
- package/dist/server/session-serialization.js.map +1 -1
- package/dist/services/compliance/normalize.d.ts.map +1 -1
- package/dist/services/compliance/normalize.js +1 -3
- package/dist/services/compliance/normalize.js.map +1 -1
- package/dist/services/intelligent-router/normalize.d.ts.map +1 -1
- package/dist/services/intelligent-router/normalize.js +1 -3
- package/dist/services/intelligent-router/normalize.js.map +1 -1
- package/dist/services/revenue-attribution/normalize.d.ts.map +1 -1
- package/dist/services/revenue-attribution/normalize.js +1 -3
- package/dist/services/revenue-attribution/normalize.js.map +1 -1
- package/dist/services/traces/normalize.d.ts.map +1 -1
- package/dist/services/traces/normalize.js +1 -3
- package/dist/services/traces/normalize.js.map +1 -1
- package/dist/services/workspace-config/normalize.d.ts.map +1 -1
- package/dist/services/workspace-config/normalize.js +1 -3
- package/dist/services/workspace-config/normalize.js.map +1 -1
- package/dist/skills/composer.d.ts.map +1 -1
- package/dist/skills/composer.js +13 -1
- package/dist/skills/composer.js.map +1 -1
- package/dist/skills/index.d.ts +1 -0
- package/dist/skills/index.d.ts.map +1 -1
- package/dist/skills/index.js +1 -0
- package/dist/skills/index.js.map +1 -1
- package/dist/skills/learned-guidelines.d.ts +33 -0
- package/dist/skills/learned-guidelines.d.ts.map +1 -0
- package/dist/skills/learned-guidelines.js +291 -0
- package/dist/skills/learned-guidelines.js.map +1 -0
- package/dist/skills/linter.d.ts.map +1 -1
- package/dist/skills/linter.js +1 -3
- package/dist/skills/linter.js.map +1 -1
- package/dist/skills/runtime-activation.d.ts +1 -0
- package/dist/skills/runtime-activation.d.ts.map +1 -1
- package/dist/skills/runtime-activation.js +2 -3
- package/dist/skills/runtime-activation.js.map +1 -1
- package/dist/skills/tool.d.ts.map +1 -1
- package/dist/skills/tool.js +26 -21
- package/dist/skills/tool.js.map +1 -1
- package/dist/skills/trust-cache.d.ts +7 -0
- package/dist/skills/trust-cache.d.ts.map +1 -1
- package/dist/skills/trust-cache.js +16 -0
- package/dist/skills/trust-cache.js.map +1 -1
- package/dist/telemetry/agent-workforce-native-event.d.ts.map +1 -1
- package/dist/telemetry/agent-workforce-native-event.js +1 -3
- package/dist/telemetry/agent-workforce-native-event.js.map +1 -1
- package/dist/telemetry/maestro-event-bus.d.ts.map +1 -1
- package/dist/telemetry/maestro-event-bus.js +42 -81
- package/dist/telemetry/maestro-event-bus.js.map +1 -1
- package/dist/telemetry/maestro-platform-replay-fixture.d.ts.map +1 -1
- package/dist/telemetry/maestro-platform-replay-fixture.js +1 -3
- package/dist/telemetry/maestro-platform-replay-fixture.js.map +1 -1
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +54 -43
- package/dist/telemetry.js.map +1 -1
- package/dist/theme/theme-loader.d.ts.map +1 -1
- package/dist/theme/theme-loader.js +1 -3
- package/dist/theme/theme-loader.js.map +1 -1
- package/dist/tools/apply-patch.d.ts.map +1 -1
- package/dist/tools/apply-patch.js +76 -8
- package/dist/tools/apply-patch.js.map +1 -1
- package/dist/tools/diff-preview.d.ts.map +1 -1
- package/dist/tools/diff-preview.js +10 -1
- package/dist/tools/diff-preview.js.map +1 -1
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js +17 -0
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/write.d.ts.map +1 -1
- package/dist/tools/write.js +9 -0
- package/dist/tools/write.js.map +1 -1
- package/dist/undo/tracker.d.ts +5 -0
- package/dist/undo/tracker.d.ts.map +1 -1
- package/dist/undo/tracker.js +13 -0
- package/dist/undo/tracker.js.map +1 -1
- package/dist/utils/fs.d.ts +1 -1
- package/dist/utils/fs.d.ts.map +1 -1
- package/dist/utils/fs.js +29 -2
- package/dist/utils/fs.js.map +1 -1
- package/dist/utils/git-stash.d.ts.map +1 -1
- package/dist/utils/git-stash.js +15 -8
- package/dist/utils/git-stash.js.map +1 -1
- package/dist/utils/json.d.ts +11 -0
- package/dist/utils/json.d.ts.map +1 -1
- package/dist/utils/json.js +9 -0
- package/dist/utils/json.js.map +1 -1
- package/dist/utils/shell-env.d.ts.map +1 -1
- package/dist/utils/shell-env.js +2 -0
- package/dist/utils/shell-env.js.map +1 -1
- package/dist/utils/url-extractor-git.d.ts +26 -0
- package/dist/utils/url-extractor-git.d.ts.map +1 -0
- package/dist/utils/url-extractor-git.js +259 -0
- package/dist/utils/url-extractor-git.js.map +1 -0
- package/dist/utils/url-extractor.d.ts.map +1 -1
- package/dist/utils/url-extractor.js +23 -251
- package/dist/utils/url-extractor.js.map +1 -1
- package/dist/version.json +2 -2
- package/package.json +310 -306
- package/skills/incident-triage/SKILL.md +19 -1
- package/skills/install-code-review/SKILL.md +69 -0
- package/skills/security-review/SKILL.md +68 -0
- package/skills/security-review/reference/rubric.md +85 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpathSync, rmSync, rmdirSync, } from "node:fs";
|
|
3
|
+
import { basename, dirname, isAbsolute, join, relative, resolve, } from "node:path";
|
|
4
|
+
import { PATHS } from "../config/constants.js";
|
|
5
|
+
import { defaultRuntimeEnv } from "../runtime/env.js";
|
|
6
|
+
import { writeTextFileAtomic } from "../utils/fs.js";
|
|
7
|
+
const SNAPSHOT_SHA256_PATTERN = /^(?:sha256:)?[a-f0-9]{64}$/iu;
|
|
8
|
+
export function getSnapshotBlobRoot(rootDir) {
|
|
9
|
+
return (rootDir ??
|
|
10
|
+
defaultRuntimeEnv().snapshotBlobDir ??
|
|
11
|
+
join(PATHS.MAESTRO_HOME, "snapshots", "blobs"));
|
|
12
|
+
}
|
|
13
|
+
export function sha256Content(content) {
|
|
14
|
+
return createHash("sha256").update(content).digest("hex");
|
|
15
|
+
}
|
|
16
|
+
export class SnapshotBlobStore {
|
|
17
|
+
constructor(config = {}) {
|
|
18
|
+
this.rootDir = getSnapshotBlobRoot(config.rootDir);
|
|
19
|
+
}
|
|
20
|
+
put(content) {
|
|
21
|
+
const buffer = Buffer.isBuffer(content)
|
|
22
|
+
? content
|
|
23
|
+
: Buffer.from(content, "utf-8");
|
|
24
|
+
const contentSha256 = sha256Content(buffer);
|
|
25
|
+
const path = this.getPath(contentSha256);
|
|
26
|
+
if (!existsSync(path)) {
|
|
27
|
+
writeBlobFileAtomic(path, buffer);
|
|
28
|
+
}
|
|
29
|
+
return { contentSha256, size: buffer.byteLength };
|
|
30
|
+
}
|
|
31
|
+
get(contentSha256) {
|
|
32
|
+
const path = this.getPath(contentSha256);
|
|
33
|
+
if (!existsSync(path)) {
|
|
34
|
+
throw new Error(`snapshot blob not found: ${contentSha256}`);
|
|
35
|
+
}
|
|
36
|
+
return readFileSync(path);
|
|
37
|
+
}
|
|
38
|
+
has(contentSha256) {
|
|
39
|
+
return existsSync(this.getPath(contentSha256));
|
|
40
|
+
}
|
|
41
|
+
getPath(contentSha256) {
|
|
42
|
+
const clean = normalizeSnapshotContentSha256(contentSha256);
|
|
43
|
+
return join(this.rootDir, clean.slice(0, 2), clean);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export function executeRewindPlan(options) {
|
|
47
|
+
const store = options.store ?? new SnapshotBlobStore();
|
|
48
|
+
const restored = [];
|
|
49
|
+
const deleted = [];
|
|
50
|
+
let bytesRestored = 0;
|
|
51
|
+
const workspaceRoot = realpathSync(resolve(options.workspaceDir));
|
|
52
|
+
const preparedOps = options.plan.ops.map((op) => {
|
|
53
|
+
const workspacePath = resolveWorkspacePlanPath(workspaceRoot, op.path);
|
|
54
|
+
if (op.kind === "delete") {
|
|
55
|
+
return { kind: "delete", path: op.path, workspacePath };
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
kind: "restore",
|
|
59
|
+
path: op.path,
|
|
60
|
+
workspacePath,
|
|
61
|
+
content: readRestoreBlob(op, store),
|
|
62
|
+
size: op.size,
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
const plannedDeletePaths = new Set(preparedOps.flatMap((op) => op.kind === "delete" ? [op.workspacePath] : []));
|
|
66
|
+
preflightBlockingRestoreDirectories(preparedOps, plannedDeletePaths);
|
|
67
|
+
for (const op of preparedOps) {
|
|
68
|
+
if (op.kind === "delete") {
|
|
69
|
+
if (!options.dryRun) {
|
|
70
|
+
rmSync(op.workspacePath, { force: true, recursive: false });
|
|
71
|
+
}
|
|
72
|
+
deleted.push(op.path);
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (!options.dryRun) {
|
|
76
|
+
pruneBlockingRestoreDirectory(op.workspacePath);
|
|
77
|
+
writeBlobFileAtomic(op.workspacePath, op.content);
|
|
78
|
+
}
|
|
79
|
+
restored.push(op.path);
|
|
80
|
+
bytesRestored += op.size;
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
targetIndex: options.plan.targetIndex,
|
|
84
|
+
fromIndex: options.plan.fromIndex,
|
|
85
|
+
restored,
|
|
86
|
+
deleted,
|
|
87
|
+
bytesRestored,
|
|
88
|
+
dryRun: options.dryRun === true,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function resolveWorkspacePlanPath(workspaceRoot, opPath) {
|
|
92
|
+
if (!opPath || isAbsolute(opPath)) {
|
|
93
|
+
throw new Error(`rewind plan path must be relative: ${opPath}`);
|
|
94
|
+
}
|
|
95
|
+
if (isParentDirectoryRelPath(opPath)) {
|
|
96
|
+
throw new Error(`rewind plan path escapes workspace: ${opPath}`);
|
|
97
|
+
}
|
|
98
|
+
const resolvedPath = resolve(workspaceRoot, opPath);
|
|
99
|
+
const rel = relative(workspaceRoot, resolvedPath);
|
|
100
|
+
if (!rel || isParentDirectoryRelPath(rel) || isAbsolute(rel)) {
|
|
101
|
+
throw new Error(`rewind plan path escapes workspace: ${opPath}`);
|
|
102
|
+
}
|
|
103
|
+
const workspaceRealRoot = realpathSync(workspaceRoot);
|
|
104
|
+
const parentRealPath = resolveRealPath(dirname(resolvedPath));
|
|
105
|
+
const parentRel = relative(workspaceRealRoot, parentRealPath);
|
|
106
|
+
if ((parentRealPath !== workspaceRealRoot && !parentRel) ||
|
|
107
|
+
isParentDirectoryRelPath(parentRel) ||
|
|
108
|
+
isAbsolute(parentRel)) {
|
|
109
|
+
throw new Error(`rewind plan path escapes workspace: ${opPath}`);
|
|
110
|
+
}
|
|
111
|
+
return resolvedPath;
|
|
112
|
+
}
|
|
113
|
+
function isParentDirectoryRelPath(relPath) {
|
|
114
|
+
return (relPath === ".." || relPath.startsWith("../") || relPath.startsWith("..\\"));
|
|
115
|
+
}
|
|
116
|
+
function resolveRealPath(path) {
|
|
117
|
+
const suffix = [];
|
|
118
|
+
let current = path;
|
|
119
|
+
while (true) {
|
|
120
|
+
if (existsSync(current)) {
|
|
121
|
+
const realBase = realpathSync(current);
|
|
122
|
+
return suffix.length === 0
|
|
123
|
+
? realBase
|
|
124
|
+
: join(realBase, ...suffix.reverse());
|
|
125
|
+
}
|
|
126
|
+
const parent = dirname(current);
|
|
127
|
+
if (parent === current) {
|
|
128
|
+
return path;
|
|
129
|
+
}
|
|
130
|
+
suffix.push(basename(current));
|
|
131
|
+
current = parent;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
function preflightBlockingRestoreDirectories(ops, plannedDeletePaths) {
|
|
135
|
+
for (const op of ops) {
|
|
136
|
+
if (op.kind !== "restore")
|
|
137
|
+
continue;
|
|
138
|
+
assertRestoreDirectoryPrunable(op.workspacePath, op.path, plannedDeletePaths);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function assertRestoreDirectoryPrunable(path, planPath, plannedDeletePaths) {
|
|
142
|
+
if (!existsSync(path))
|
|
143
|
+
return;
|
|
144
|
+
const stat = lstatSync(path);
|
|
145
|
+
if (!stat.isDirectory())
|
|
146
|
+
return;
|
|
147
|
+
for (const entry of readdirSync(path, { withFileTypes: true })) {
|
|
148
|
+
const childPath = join(path, entry.name);
|
|
149
|
+
if (plannedDeletePaths.has(childPath))
|
|
150
|
+
continue;
|
|
151
|
+
if (entry.isDirectory()) {
|
|
152
|
+
assertRestoreDirectoryPrunable(childPath, planPath, plannedDeletePaths);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
throw new Error(`rewind restore target is blocked by unplanned workspace entry: ${planPath}`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function pruneBlockingRestoreDirectory(path) {
|
|
159
|
+
if (!existsSync(path))
|
|
160
|
+
return;
|
|
161
|
+
const stat = lstatSync(path);
|
|
162
|
+
if (!stat.isDirectory())
|
|
163
|
+
return;
|
|
164
|
+
for (const entry of readdirSync(path, { withFileTypes: true })) {
|
|
165
|
+
const childPath = join(path, entry.name);
|
|
166
|
+
if (entry.isDirectory())
|
|
167
|
+
pruneBlockingRestoreDirectory(childPath);
|
|
168
|
+
}
|
|
169
|
+
rmdirSync(path);
|
|
170
|
+
}
|
|
171
|
+
function readRestoreBlob(op, store) {
|
|
172
|
+
const expectedSha256 = normalizeSnapshotContentSha256(op.contentSha256);
|
|
173
|
+
const content = store.get(op.contentSha256);
|
|
174
|
+
if (content.byteLength !== op.size) {
|
|
175
|
+
throw new Error(`snapshot blob size mismatch for ${op.path}: expected ${op.size}, got ${content.byteLength}`);
|
|
176
|
+
}
|
|
177
|
+
const actualSha256 = sha256Content(content);
|
|
178
|
+
if (actualSha256 !== expectedSha256) {
|
|
179
|
+
throw new Error(`snapshot blob hash mismatch for ${op.path}: expected ${expectedSha256}, got ${actualSha256}`);
|
|
180
|
+
}
|
|
181
|
+
return content;
|
|
182
|
+
}
|
|
183
|
+
function normalizeSnapshotContentSha256(contentSha256) {
|
|
184
|
+
if (!SNAPSHOT_SHA256_PATTERN.test(contentSha256)) {
|
|
185
|
+
throw new Error(`invalid snapshot blob sha256: ${contentSha256}`);
|
|
186
|
+
}
|
|
187
|
+
return contentSha256.replace(/^sha256:/iu, "").toLowerCase();
|
|
188
|
+
}
|
|
189
|
+
function writeBlobFileAtomic(path, content) {
|
|
190
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
191
|
+
writeTextFileAtomic(path, content.toString("binary"), {
|
|
192
|
+
encoding: "binary",
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=snapshot-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot-store.js","sourceRoot":"","sources":["../../src/agent/snapshot-store.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport {\n\texistsSync,\n\tlstatSync,\n\tmkdirSync,\n\treadFileSync,\n\treaddirSync,\n\trealpathSync,\n\trmSync,\n\trmdirSync,\n} from \"node:fs\";\nimport {\n\tbasename,\n\tdirname,\n\tisAbsolute,\n\tjoin,\n\trelative,\n\tresolve,\n} from \"node:path\";\nimport { PATHS } from \"../config/constants.js\";\nimport { defaultRuntimeEnv } from \"../runtime/env.js\";\nimport { writeTextFileAtomic } from \"../utils/fs.js\";\nimport type { RewindPlan, RewindRestoreOp } from \"./snapshot-rewind-plan.js\";\n\nconst SNAPSHOT_SHA256_PATTERN = /^(?:sha256:)?[a-f0-9]{64}$/iu;\n\nexport interface SnapshotBlobStoreConfig {\n\trootDir?: string;\n}\n\nexport interface RewindExecutionResult {\n\ttargetIndex: number;\n\tfromIndex: number;\n\trestored: string[];\n\tdeleted: string[];\n\tbytesRestored: number;\n\tdryRun: boolean;\n}\n\ntype PreparedRewindOp =\n\t| {\n\t\t\tkind: \"delete\";\n\t\t\tpath: string;\n\t\t\tworkspacePath: string;\n\t }\n\t| {\n\t\t\tkind: \"restore\";\n\t\t\tpath: string;\n\t\t\tworkspacePath: string;\n\t\t\tcontent: Buffer;\n\t\t\tsize: number;\n\t };\n\nexport function getSnapshotBlobRoot(rootDir?: string): string {\n\treturn (\n\t\trootDir ??\n\t\tdefaultRuntimeEnv().snapshotBlobDir ??\n\t\tjoin(PATHS.MAESTRO_HOME, \"snapshots\", \"blobs\")\n\t);\n}\n\nexport function sha256Content(content: string | Buffer): string {\n\treturn createHash(\"sha256\").update(content).digest(\"hex\");\n}\n\nexport class SnapshotBlobStore {\n\tprivate readonly rootDir: string;\n\n\tconstructor(config: SnapshotBlobStoreConfig = {}) {\n\t\tthis.rootDir = getSnapshotBlobRoot(config.rootDir);\n\t}\n\n\tput(content: string | Buffer): { contentSha256: string; size: number } {\n\t\tconst buffer = Buffer.isBuffer(content)\n\t\t\t? content\n\t\t\t: Buffer.from(content, \"utf-8\");\n\t\tconst contentSha256 = sha256Content(buffer);\n\t\tconst path = this.getPath(contentSha256);\n\t\tif (!existsSync(path)) {\n\t\t\twriteBlobFileAtomic(path, buffer);\n\t\t}\n\t\treturn { contentSha256, size: buffer.byteLength };\n\t}\n\n\tget(contentSha256: string): Buffer {\n\t\tconst path = this.getPath(contentSha256);\n\t\tif (!existsSync(path)) {\n\t\t\tthrow new Error(`snapshot blob not found: ${contentSha256}`);\n\t\t}\n\t\treturn readFileSync(path);\n\t}\n\n\thas(contentSha256: string): boolean {\n\t\treturn existsSync(this.getPath(contentSha256));\n\t}\n\n\tgetPath(contentSha256: string): string {\n\t\tconst clean = normalizeSnapshotContentSha256(contentSha256);\n\t\treturn join(this.rootDir, clean.slice(0, 2), clean);\n\t}\n}\n\nexport function executeRewindPlan(options: {\n\tplan: RewindPlan;\n\tworkspaceDir: string;\n\tstore?: SnapshotBlobStore;\n\tdryRun?: boolean;\n}): RewindExecutionResult {\n\tconst store = options.store ?? new SnapshotBlobStore();\n\tconst restored: string[] = [];\n\tconst deleted: string[] = [];\n\tlet bytesRestored = 0;\n\tconst workspaceRoot = realpathSync(resolve(options.workspaceDir));\n\tconst preparedOps = options.plan.ops.map((op): PreparedRewindOp => {\n\t\tconst workspacePath = resolveWorkspacePlanPath(workspaceRoot, op.path);\n\t\tif (op.kind === \"delete\") {\n\t\t\treturn { kind: \"delete\", path: op.path, workspacePath };\n\t\t}\n\t\treturn {\n\t\t\tkind: \"restore\",\n\t\t\tpath: op.path,\n\t\t\tworkspacePath,\n\t\t\tcontent: readRestoreBlob(op, store),\n\t\t\tsize: op.size,\n\t\t};\n\t});\n\tconst plannedDeletePaths = new Set(\n\t\tpreparedOps.flatMap((op) =>\n\t\t\top.kind === \"delete\" ? [op.workspacePath] : [],\n\t\t),\n\t);\n\tpreflightBlockingRestoreDirectories(preparedOps, plannedDeletePaths);\n\tfor (const op of preparedOps) {\n\t\tif (op.kind === \"delete\") {\n\t\t\tif (!options.dryRun) {\n\t\t\t\trmSync(op.workspacePath, { force: true, recursive: false });\n\t\t\t}\n\t\t\tdeleted.push(op.path);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!options.dryRun) {\n\t\t\tpruneBlockingRestoreDirectory(op.workspacePath);\n\t\t\twriteBlobFileAtomic(op.workspacePath, op.content);\n\t\t}\n\t\trestored.push(op.path);\n\t\tbytesRestored += op.size;\n\t}\n\treturn {\n\t\ttargetIndex: options.plan.targetIndex,\n\t\tfromIndex: options.plan.fromIndex,\n\t\trestored,\n\t\tdeleted,\n\t\tbytesRestored,\n\t\tdryRun: options.dryRun === true,\n\t};\n}\n\nfunction resolveWorkspacePlanPath(\n\tworkspaceRoot: string,\n\topPath: string,\n): string {\n\tif (!opPath || isAbsolute(opPath)) {\n\t\tthrow new Error(`rewind plan path must be relative: ${opPath}`);\n\t}\n\tif (isParentDirectoryRelPath(opPath)) {\n\t\tthrow new Error(`rewind plan path escapes workspace: ${opPath}`);\n\t}\n\tconst resolvedPath = resolve(workspaceRoot, opPath);\n\tconst rel = relative(workspaceRoot, resolvedPath);\n\tif (!rel || isParentDirectoryRelPath(rel) || isAbsolute(rel)) {\n\t\tthrow new Error(`rewind plan path escapes workspace: ${opPath}`);\n\t}\n\tconst workspaceRealRoot = realpathSync(workspaceRoot);\n\tconst parentRealPath = resolveRealPath(dirname(resolvedPath));\n\tconst parentRel = relative(workspaceRealRoot, parentRealPath);\n\tif (\n\t\t(parentRealPath !== workspaceRealRoot && !parentRel) ||\n\t\tisParentDirectoryRelPath(parentRel) ||\n\t\tisAbsolute(parentRel)\n\t) {\n\t\tthrow new Error(`rewind plan path escapes workspace: ${opPath}`);\n\t}\n\treturn resolvedPath;\n}\n\nfunction isParentDirectoryRelPath(relPath: string): boolean {\n\treturn (\n\t\trelPath === \"..\" || relPath.startsWith(\"../\") || relPath.startsWith(\"..\\\\\")\n\t);\n}\n\nfunction resolveRealPath(path: string): string {\n\tconst suffix: string[] = [];\n\tlet current = path;\n\twhile (true) {\n\t\tif (existsSync(current)) {\n\t\t\tconst realBase = realpathSync(current);\n\t\t\treturn suffix.length === 0\n\t\t\t\t? realBase\n\t\t\t\t: join(realBase, ...suffix.reverse());\n\t\t}\n\t\tconst parent = dirname(current);\n\t\tif (parent === current) {\n\t\t\treturn path;\n\t\t}\n\t\tsuffix.push(basename(current));\n\t\tcurrent = parent;\n\t}\n}\n\nfunction preflightBlockingRestoreDirectories(\n\tops: readonly PreparedRewindOp[],\n\tplannedDeletePaths: ReadonlySet<string>,\n): void {\n\tfor (const op of ops) {\n\t\tif (op.kind !== \"restore\") continue;\n\t\tassertRestoreDirectoryPrunable(\n\t\t\top.workspacePath,\n\t\t\top.path,\n\t\t\tplannedDeletePaths,\n\t\t);\n\t}\n}\n\nfunction assertRestoreDirectoryPrunable(\n\tpath: string,\n\tplanPath: string,\n\tplannedDeletePaths: ReadonlySet<string>,\n): void {\n\tif (!existsSync(path)) return;\n\tconst stat = lstatSync(path);\n\tif (!stat.isDirectory()) return;\n\tfor (const entry of readdirSync(path, { withFileTypes: true })) {\n\t\tconst childPath = join(path, entry.name);\n\t\tif (plannedDeletePaths.has(childPath)) continue;\n\t\tif (entry.isDirectory()) {\n\t\t\tassertRestoreDirectoryPrunable(childPath, planPath, plannedDeletePaths);\n\t\t\tcontinue;\n\t\t}\n\t\tthrow new Error(\n\t\t\t`rewind restore target is blocked by unplanned workspace entry: ${planPath}`,\n\t\t);\n\t}\n}\n\nfunction pruneBlockingRestoreDirectory(path: string): void {\n\tif (!existsSync(path)) return;\n\tconst stat = lstatSync(path);\n\tif (!stat.isDirectory()) return;\n\tfor (const entry of readdirSync(path, { withFileTypes: true })) {\n\t\tconst childPath = join(path, entry.name);\n\t\tif (entry.isDirectory()) pruneBlockingRestoreDirectory(childPath);\n\t}\n\trmdirSync(path);\n}\n\nfunction readRestoreBlob(\n\top: RewindRestoreOp,\n\tstore: SnapshotBlobStore,\n): Buffer {\n\tconst expectedSha256 = normalizeSnapshotContentSha256(op.contentSha256);\n\tconst content = store.get(op.contentSha256);\n\tif (content.byteLength !== op.size) {\n\t\tthrow new Error(\n\t\t\t`snapshot blob size mismatch for ${op.path}: expected ${op.size}, got ${content.byteLength}`,\n\t\t);\n\t}\n\tconst actualSha256 = sha256Content(content);\n\tif (actualSha256 !== expectedSha256) {\n\t\tthrow new Error(\n\t\t\t`snapshot blob hash mismatch for ${op.path}: expected ${expectedSha256}, got ${actualSha256}`,\n\t\t);\n\t}\n\treturn content;\n}\n\nfunction normalizeSnapshotContentSha256(contentSha256: string): string {\n\tif (!SNAPSHOT_SHA256_PATTERN.test(contentSha256)) {\n\t\tthrow new Error(`invalid snapshot blob sha256: ${contentSha256}`);\n\t}\n\treturn contentSha256.replace(/^sha256:/iu, \"\").toLowerCase();\n}\n\nfunction writeBlobFileAtomic(path: string, content: Buffer): void {\n\tmkdirSync(dirname(path), { recursive: true });\n\twriteTextFileAtomic(path, content.toString(\"binary\"), {\n\t\tencoding: \"binary\",\n\t});\n}\n"]}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export type SpecialistProfileScope = "project" | "user";
|
|
2
|
+
export interface SpecialistProfile {
|
|
3
|
+
name: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
prompt: string;
|
|
6
|
+
tools?: string[];
|
|
7
|
+
model?: string;
|
|
8
|
+
scope: SpecialistProfileScope;
|
|
9
|
+
path: string;
|
|
10
|
+
createdAt?: string;
|
|
11
|
+
updatedAt?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function normalizeSpecialistProfileName(name: string): string;
|
|
14
|
+
export declare function getSpecialistProfileDir(scope: SpecialistProfileScope, workspaceDir?: string): string;
|
|
15
|
+
export declare function getSpecialistProfilePath(name: string, scope: SpecialistProfileScope, workspaceDir?: string): string;
|
|
16
|
+
export declare function createSpecialistProfile(options: {
|
|
17
|
+
name: string;
|
|
18
|
+
description?: string;
|
|
19
|
+
prompt: string;
|
|
20
|
+
tools?: string[];
|
|
21
|
+
model?: string;
|
|
22
|
+
scope?: SpecialistProfileScope;
|
|
23
|
+
workspaceDir?: string;
|
|
24
|
+
now?: string;
|
|
25
|
+
overwrite?: boolean;
|
|
26
|
+
}): SpecialistProfile;
|
|
27
|
+
export declare function readSpecialistProfile(path: string, scope: SpecialistProfileScope): SpecialistProfile;
|
|
28
|
+
export declare function listSpecialistProfiles(workspaceDir?: string): SpecialistProfile[];
|
|
29
|
+
export declare function resolveSpecialistProfile(name: string, workspaceDir?: string): SpecialistProfile | null;
|
|
30
|
+
export declare function deleteSpecialistProfile(options: {
|
|
31
|
+
name: string;
|
|
32
|
+
scope?: SpecialistProfileScope;
|
|
33
|
+
workspaceDir?: string;
|
|
34
|
+
}): boolean;
|
|
35
|
+
export declare function applySpecialistProfileToPrompt(prompt: string, profile: SpecialistProfile | null | undefined): string;
|
|
36
|
+
//# sourceMappingURL=specialist-profiles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"specialist-profiles.d.ts","sourceRoot":"","sources":["../../src/agent/specialist-profiles.ts"],"names":[],"mappings":"AAeA,MAAM,MAAM,sBAAsB,GAAG,SAAS,GAAG,MAAM,CAAC;AAExD,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,sBAAsB,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAYnE;AAED,wBAAgB,uBAAuB,CACtC,KAAK,EAAE,sBAAsB,EAC7B,YAAY,SAAgB,GAC1B,MAAM,CAIR;AAED,wBAAgB,wBAAwB,CACvC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,sBAAsB,EAC7B,YAAY,SAAgB,GAC1B,MAAM,CAKR;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,sBAAsB,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,OAAO,CAAC;CACpB,GAAG,iBAAiB,CAmCpB;AAED,wBAAgB,qBAAqB,CACpC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,sBAAsB,GAC3B,iBAAiB,CAkCnB;AAED,wBAAgB,sBAAsB,CACrC,YAAY,SAAgB,GAC1B,iBAAiB,EAAE,CAsBrB;AAED,wBAAgB,wBAAwB,CACvC,IAAI,EAAE,MAAM,EACZ,YAAY,SAAgB,GAC1B,iBAAiB,GAAG,IAAI,CAO1B;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,sBAAsB,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAUV;AAED,wBAAgB,8BAA8B,CAC7C,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,iBAAiB,GAAG,IAAI,GAAG,SAAS,GAC3C,MAAM,CAaR"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, unlinkSync, } from "node:fs";
|
|
2
|
+
import { basename, join } from "node:path";
|
|
3
|
+
import YAML from "yaml";
|
|
4
|
+
import { PATHS } from "../config/constants.js";
|
|
5
|
+
import { writeTextFileAtomic } from "../utils/fs.js";
|
|
6
|
+
import { createLogger } from "../utils/logger.js";
|
|
7
|
+
const logger = createLogger("agent:specialist-profiles");
|
|
8
|
+
export function normalizeSpecialistProfileName(name) {
|
|
9
|
+
const normalized = name
|
|
10
|
+
.trim()
|
|
11
|
+
.toLowerCase()
|
|
12
|
+
.replace(/[^a-z0-9-]+/g, "-");
|
|
13
|
+
const stripped = normalized.replace(/^-+|-+$/g, "");
|
|
14
|
+
if (!stripped || stripped.length > 64) {
|
|
15
|
+
throw new Error("profile name must be 1-64 lowercase letters, numbers, or hyphens");
|
|
16
|
+
}
|
|
17
|
+
return stripped;
|
|
18
|
+
}
|
|
19
|
+
export function getSpecialistProfileDir(scope, workspaceDir = process.cwd()) {
|
|
20
|
+
return scope === "project"
|
|
21
|
+
? join(workspaceDir, ".maestro", "agent-profiles")
|
|
22
|
+
: join(PATHS.MAESTRO_HOME, "agent-profiles");
|
|
23
|
+
}
|
|
24
|
+
export function getSpecialistProfilePath(name, scope, workspaceDir = process.cwd()) {
|
|
25
|
+
return join(getSpecialistProfileDir(scope, workspaceDir), `${normalizeSpecialistProfileName(name)}.md`);
|
|
26
|
+
}
|
|
27
|
+
export function createSpecialistProfile(options) {
|
|
28
|
+
const scope = options.scope ?? "project";
|
|
29
|
+
const name = normalizeSpecialistProfileName(options.name);
|
|
30
|
+
const path = getSpecialistProfilePath(name, scope, options.workspaceDir);
|
|
31
|
+
if (existsSync(path) && !options.overwrite) {
|
|
32
|
+
throw new Error(`specialist profile already exists: ${name}`);
|
|
33
|
+
}
|
|
34
|
+
const now = options.now ?? new Date().toISOString();
|
|
35
|
+
const prompt = options.prompt.trim();
|
|
36
|
+
if (!prompt) {
|
|
37
|
+
throw new Error("profile prompt is required");
|
|
38
|
+
}
|
|
39
|
+
mkdirSync(getSpecialistProfileDir(scope, options.workspaceDir), {
|
|
40
|
+
recursive: true,
|
|
41
|
+
});
|
|
42
|
+
const frontmatter = YAML.stringify({
|
|
43
|
+
name,
|
|
44
|
+
description: options.description,
|
|
45
|
+
tools: options.tools,
|
|
46
|
+
model: options.model,
|
|
47
|
+
createdAt: now,
|
|
48
|
+
updatedAt: now,
|
|
49
|
+
});
|
|
50
|
+
writeTextFileAtomic(path, `---\n${frontmatter}---\n\n${prompt}\n`);
|
|
51
|
+
return {
|
|
52
|
+
name,
|
|
53
|
+
description: options.description,
|
|
54
|
+
prompt,
|
|
55
|
+
tools: options.tools,
|
|
56
|
+
model: options.model,
|
|
57
|
+
scope,
|
|
58
|
+
path,
|
|
59
|
+
createdAt: now,
|
|
60
|
+
updatedAt: now,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export function readSpecialistProfile(path, scope) {
|
|
64
|
+
const content = readFileSync(path, "utf-8");
|
|
65
|
+
const parsed = parseProfileMarkdown(content);
|
|
66
|
+
const name = typeof parsed.metadata.name === "string"
|
|
67
|
+
? normalizeSpecialistProfileName(parsed.metadata.name)
|
|
68
|
+
: normalizeSpecialistProfileName(basename(path, ".md"));
|
|
69
|
+
return {
|
|
70
|
+
name,
|
|
71
|
+
description: typeof parsed.metadata.description === "string"
|
|
72
|
+
? parsed.metadata.description
|
|
73
|
+
: undefined,
|
|
74
|
+
prompt: parsed.body.trim(),
|
|
75
|
+
tools: Array.isArray(parsed.metadata.tools)
|
|
76
|
+
? parsed.metadata.tools.filter((tool) => typeof tool === "string")
|
|
77
|
+
: undefined,
|
|
78
|
+
model: typeof parsed.metadata.model === "string"
|
|
79
|
+
? parsed.metadata.model
|
|
80
|
+
: undefined,
|
|
81
|
+
scope,
|
|
82
|
+
path,
|
|
83
|
+
createdAt: typeof parsed.metadata.createdAt === "string"
|
|
84
|
+
? parsed.metadata.createdAt
|
|
85
|
+
: undefined,
|
|
86
|
+
updatedAt: typeof parsed.metadata.updatedAt === "string"
|
|
87
|
+
? parsed.metadata.updatedAt
|
|
88
|
+
: undefined,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
export function listSpecialistProfiles(workspaceDir = process.cwd()) {
|
|
92
|
+
const byName = new Map();
|
|
93
|
+
for (const scope of ["user", "project"]) {
|
|
94
|
+
const dir = getSpecialistProfileDir(scope, workspaceDir);
|
|
95
|
+
if (!existsSync(dir))
|
|
96
|
+
continue;
|
|
97
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
98
|
+
if (!entry.isFile() || !entry.name.endsWith(".md"))
|
|
99
|
+
continue;
|
|
100
|
+
try {
|
|
101
|
+
const profile = readSpecialistProfile(join(dir, entry.name), scope);
|
|
102
|
+
byName.set(profile.name, profile);
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
logger.debug("Failed to read specialist profile", {
|
|
106
|
+
file: entry.name,
|
|
107
|
+
scope,
|
|
108
|
+
error,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return [...byName.values()].sort((left, right) => left.name.localeCompare(right.name));
|
|
114
|
+
}
|
|
115
|
+
export function resolveSpecialistProfile(name, workspaceDir = process.cwd()) {
|
|
116
|
+
const normalized = normalizeSpecialistProfileName(name);
|
|
117
|
+
return (listSpecialistProfiles(workspaceDir).find((profile) => profile.name === normalized) ?? null);
|
|
118
|
+
}
|
|
119
|
+
export function deleteSpecialistProfile(options) {
|
|
120
|
+
const scope = options.scope ?? "project";
|
|
121
|
+
const path = getSpecialistProfilePath(options.name, scope, options.workspaceDir);
|
|
122
|
+
if (!existsSync(path))
|
|
123
|
+
return false;
|
|
124
|
+
unlinkSync(path);
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
export function applySpecialistProfileToPrompt(prompt, profile) {
|
|
128
|
+
if (!profile)
|
|
129
|
+
return prompt;
|
|
130
|
+
return [
|
|
131
|
+
`Specialist profile: ${profile.name}`,
|
|
132
|
+
profile.description ? `Description: ${profile.description}` : "",
|
|
133
|
+
"Profile instructions:",
|
|
134
|
+
profile.prompt,
|
|
135
|
+
"",
|
|
136
|
+
"Assigned task:",
|
|
137
|
+
prompt,
|
|
138
|
+
]
|
|
139
|
+
.filter(Boolean)
|
|
140
|
+
.join("\n");
|
|
141
|
+
}
|
|
142
|
+
function parseProfileMarkdown(content) {
|
|
143
|
+
if (!content.startsWith("---\n")) {
|
|
144
|
+
return { metadata: {}, body: content };
|
|
145
|
+
}
|
|
146
|
+
const end = content.indexOf("\n---", 4);
|
|
147
|
+
if (end === -1)
|
|
148
|
+
return { metadata: {}, body: content };
|
|
149
|
+
const frontmatter = content.slice(4, end);
|
|
150
|
+
const body = content.slice(end + 4).replace(/^\r?\n/u, "");
|
|
151
|
+
const metadata = YAML.parse(frontmatter);
|
|
152
|
+
return {
|
|
153
|
+
metadata: metadata && typeof metadata === "object"
|
|
154
|
+
? metadata
|
|
155
|
+
: {},
|
|
156
|
+
body,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=specialist-profiles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"specialist-profiles.js","sourceRoot":"","sources":["../../src/agent/specialist-profiles.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\texistsSync,\n\tmkdirSync,\n\treadFileSync,\n\treaddirSync,\n\tunlinkSync,\n} from \"node:fs\";\nimport { basename, join } from \"node:path\";\nimport YAML from \"yaml\";\nimport { PATHS } from \"../config/constants.js\";\nimport { writeTextFileAtomic } from \"../utils/fs.js\";\nimport { createLogger } from \"../utils/logger.js\";\n\nconst logger = createLogger(\"agent:specialist-profiles\");\n\nexport type SpecialistProfileScope = \"project\" | \"user\";\n\nexport interface SpecialistProfile {\n\tname: string;\n\tdescription?: string;\n\tprompt: string;\n\ttools?: string[];\n\tmodel?: string;\n\tscope: SpecialistProfileScope;\n\tpath: string;\n\tcreatedAt?: string;\n\tupdatedAt?: string;\n}\n\nexport function normalizeSpecialistProfileName(name: string): string {\n\tconst normalized = name\n\t\t.trim()\n\t\t.toLowerCase()\n\t\t.replace(/[^a-z0-9-]+/g, \"-\");\n\tconst stripped = normalized.replace(/^-+|-+$/g, \"\");\n\tif (!stripped || stripped.length > 64) {\n\t\tthrow new Error(\n\t\t\t\"profile name must be 1-64 lowercase letters, numbers, or hyphens\",\n\t\t);\n\t}\n\treturn stripped;\n}\n\nexport function getSpecialistProfileDir(\n\tscope: SpecialistProfileScope,\n\tworkspaceDir = process.cwd(),\n): string {\n\treturn scope === \"project\"\n\t\t? join(workspaceDir, \".maestro\", \"agent-profiles\")\n\t\t: join(PATHS.MAESTRO_HOME, \"agent-profiles\");\n}\n\nexport function getSpecialistProfilePath(\n\tname: string,\n\tscope: SpecialistProfileScope,\n\tworkspaceDir = process.cwd(),\n): string {\n\treturn join(\n\t\tgetSpecialistProfileDir(scope, workspaceDir),\n\t\t`${normalizeSpecialistProfileName(name)}.md`,\n\t);\n}\n\nexport function createSpecialistProfile(options: {\n\tname: string;\n\tdescription?: string;\n\tprompt: string;\n\ttools?: string[];\n\tmodel?: string;\n\tscope?: SpecialistProfileScope;\n\tworkspaceDir?: string;\n\tnow?: string;\n\toverwrite?: boolean;\n}): SpecialistProfile {\n\tconst scope = options.scope ?? \"project\";\n\tconst name = normalizeSpecialistProfileName(options.name);\n\tconst path = getSpecialistProfilePath(name, scope, options.workspaceDir);\n\tif (existsSync(path) && !options.overwrite) {\n\t\tthrow new Error(`specialist profile already exists: ${name}`);\n\t}\n\tconst now = options.now ?? new Date().toISOString();\n\tconst prompt = options.prompt.trim();\n\tif (!prompt) {\n\t\tthrow new Error(\"profile prompt is required\");\n\t}\n\tmkdirSync(getSpecialistProfileDir(scope, options.workspaceDir), {\n\t\trecursive: true,\n\t});\n\tconst frontmatter = YAML.stringify({\n\t\tname,\n\t\tdescription: options.description,\n\t\ttools: options.tools,\n\t\tmodel: options.model,\n\t\tcreatedAt: now,\n\t\tupdatedAt: now,\n\t});\n\twriteTextFileAtomic(path, `---\\n${frontmatter}---\\n\\n${prompt}\\n`);\n\treturn {\n\t\tname,\n\t\tdescription: options.description,\n\t\tprompt,\n\t\ttools: options.tools,\n\t\tmodel: options.model,\n\t\tscope,\n\t\tpath,\n\t\tcreatedAt: now,\n\t\tupdatedAt: now,\n\t};\n}\n\nexport function readSpecialistProfile(\n\tpath: string,\n\tscope: SpecialistProfileScope,\n): SpecialistProfile {\n\tconst content = readFileSync(path, \"utf-8\");\n\tconst parsed = parseProfileMarkdown(content);\n\tconst name =\n\t\ttypeof parsed.metadata.name === \"string\"\n\t\t\t? normalizeSpecialistProfileName(parsed.metadata.name)\n\t\t\t: normalizeSpecialistProfileName(basename(path, \".md\"));\n\treturn {\n\t\tname,\n\t\tdescription:\n\t\t\ttypeof parsed.metadata.description === \"string\"\n\t\t\t\t? parsed.metadata.description\n\t\t\t\t: undefined,\n\t\tprompt: parsed.body.trim(),\n\t\ttools: Array.isArray(parsed.metadata.tools)\n\t\t\t? parsed.metadata.tools.filter(\n\t\t\t\t\t(tool): tool is string => typeof tool === \"string\",\n\t\t\t\t)\n\t\t\t: undefined,\n\t\tmodel:\n\t\t\ttypeof parsed.metadata.model === \"string\"\n\t\t\t\t? parsed.metadata.model\n\t\t\t\t: undefined,\n\t\tscope,\n\t\tpath,\n\t\tcreatedAt:\n\t\t\ttypeof parsed.metadata.createdAt === \"string\"\n\t\t\t\t? parsed.metadata.createdAt\n\t\t\t\t: undefined,\n\t\tupdatedAt:\n\t\t\ttypeof parsed.metadata.updatedAt === \"string\"\n\t\t\t\t? parsed.metadata.updatedAt\n\t\t\t\t: undefined,\n\t};\n}\n\nexport function listSpecialistProfiles(\n\tworkspaceDir = process.cwd(),\n): SpecialistProfile[] {\n\tconst byName = new Map<string, SpecialistProfile>();\n\tfor (const scope of [\"user\", \"project\"] as const) {\n\t\tconst dir = getSpecialistProfileDir(scope, workspaceDir);\n\t\tif (!existsSync(dir)) continue;\n\t\tfor (const entry of readdirSync(dir, { withFileTypes: true })) {\n\t\t\tif (!entry.isFile() || !entry.name.endsWith(\".md\")) continue;\n\t\t\ttry {\n\t\t\t\tconst profile = readSpecialistProfile(join(dir, entry.name), scope);\n\t\t\t\tbyName.set(profile.name, profile);\n\t\t\t} catch (error) {\n\t\t\t\tlogger.debug(\"Failed to read specialist profile\", {\n\t\t\t\t\tfile: entry.name,\n\t\t\t\t\tscope,\n\t\t\t\t\terror,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\treturn [...byName.values()].sort((left, right) =>\n\t\tleft.name.localeCompare(right.name),\n\t);\n}\n\nexport function resolveSpecialistProfile(\n\tname: string,\n\tworkspaceDir = process.cwd(),\n): SpecialistProfile | null {\n\tconst normalized = normalizeSpecialistProfileName(name);\n\treturn (\n\t\tlistSpecialistProfiles(workspaceDir).find(\n\t\t\t(profile) => profile.name === normalized,\n\t\t) ?? null\n\t);\n}\n\nexport function deleteSpecialistProfile(options: {\n\tname: string;\n\tscope?: SpecialistProfileScope;\n\tworkspaceDir?: string;\n}): boolean {\n\tconst scope = options.scope ?? \"project\";\n\tconst path = getSpecialistProfilePath(\n\t\toptions.name,\n\t\tscope,\n\t\toptions.workspaceDir,\n\t);\n\tif (!existsSync(path)) return false;\n\tunlinkSync(path);\n\treturn true;\n}\n\nexport function applySpecialistProfileToPrompt(\n\tprompt: string,\n\tprofile: SpecialistProfile | null | undefined,\n): string {\n\tif (!profile) return prompt;\n\treturn [\n\t\t`Specialist profile: ${profile.name}`,\n\t\tprofile.description ? `Description: ${profile.description}` : \"\",\n\t\t\"Profile instructions:\",\n\t\tprofile.prompt,\n\t\t\"\",\n\t\t\"Assigned task:\",\n\t\tprompt,\n\t]\n\t\t.filter(Boolean)\n\t\t.join(\"\\n\");\n}\n\nfunction parseProfileMarkdown(content: string): {\n\tmetadata: Record<string, unknown>;\n\tbody: string;\n} {\n\tif (!content.startsWith(\"---\\n\")) {\n\t\treturn { metadata: {}, body: content };\n\t}\n\tconst end = content.indexOf(\"\\n---\", 4);\n\tif (end === -1) return { metadata: {}, body: content };\n\tconst frontmatter = content.slice(4, end);\n\tconst body = content.slice(end + 4).replace(/^\\r?\\n/u, \"\");\n\tconst metadata = YAML.parse(frontmatter);\n\treturn {\n\t\tmetadata:\n\t\t\tmetadata && typeof metadata === \"object\"\n\t\t\t\t? (metadata as Record<string, unknown>)\n\t\t\t\t: {},\n\t\tbody,\n\t};\n}\n"]}
|
|
@@ -8,13 +8,14 @@
|
|
|
8
8
|
* - coder: Full coding capabilities
|
|
9
9
|
* - reviewer: Read-only with web access for reviewing code
|
|
10
10
|
* - researcher: Web search and fetch focused
|
|
11
|
+
* - browser-qa: Browser-based product QA with screenshots and repro evidence
|
|
11
12
|
*
|
|
12
13
|
* Inspired by Amp's subagentSpec/subagentType system.
|
|
13
14
|
*/
|
|
14
15
|
/**
|
|
15
16
|
* Available subagent types.
|
|
16
17
|
*/
|
|
17
|
-
export type SubagentType = "explorer" | "planner" | "coder" | "reviewer" | "researcher" | "minimal" | "custom";
|
|
18
|
+
export type SubagentType = "explorer" | "planner" | "coder" | "reviewer" | "test-runner" | "researcher" | "browser-qa" | "minimal" | "custom";
|
|
18
19
|
/**
|
|
19
20
|
* Tool categories for easier specification.
|
|
20
21
|
*/
|
|
@@ -27,6 +28,8 @@ export declare const TOOL_CATEGORIES: {
|
|
|
27
28
|
readonly shell: readonly ["bash", "background_tasks"];
|
|
28
29
|
/** Web and external tools */
|
|
29
30
|
readonly web: readonly ["websearch", "webfetch", "codesearch"];
|
|
31
|
+
/** Browser/product QA tools */
|
|
32
|
+
readonly browser: readonly ["agent_browser", "browser_open", "browser_snapshot", "browser_click", "browser_fill", "browser_type", "browser_screenshot", "browser_console", "browser_record", "read_page", "search_page", "find_on_page", "extract_links", "wait_for_selector", "click_element", "type_text", "scroll_page", "select_element", "navigate_to", "open_links_in_tabs", "highlight_element", "browser_operator", "mouse_action", "pointer_action", "keyboard_action", "extract_table_data", "capture_network", "capture_console_errors", "collect_diagnostics", "extract_document", "capture_screenshot", "native_click", "native_type", "native_press", "native_key_down", "native_key_up"];
|
|
30
33
|
/** Interactive tools */
|
|
31
34
|
readonly interactive: readonly ["ask_user", "todo"];
|
|
32
35
|
/** GitHub tools */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subagent-specs.d.ts","sourceRoot":"","sources":["../../src/agent/subagent-specs.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"subagent-specs.d.ts","sourceRoot":"","sources":["../../src/agent/subagent-specs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAQH;;GAEG;AACH,MAAM,MAAM,YAAY,GACrB,UAAU,GACV,SAAS,GACT,OAAO,GACP,UAAU,GACV,aAAa,GACb,YAAY,GACZ,YAAY,GACZ,SAAS,GACT,QAAQ,CAAC;AAWZ;;GAEG;AACH,eAAO,MAAM,eAAe;IAC3B,kCAAkC;;IAUlC,8BAA8B;;IAE9B,sBAAsB;;IAEtB,6BAA6B;;IAE7B,+BAA+B;;IAuC/B,wBAAwB;;IAExB,mBAAmB;;IAEnB,qBAAqB;;CAEZ,CAAC;AAeX;;GAEG;AACH,MAAM,WAAW,YAAY;IAC5B,mBAAmB;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,+CAA+C;IAC/C,WAAW,EAAE,MAAM,CAAC;IACpB,yCAAyC;IACzC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,0DAA0D;IAC1D,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,uDAAuD;IACvD,QAAQ,EAAE,OAAO,CAAC;IAClB,wCAAwC;IACxC,YAAY,EAAE,OAAO,CAAC;IACtB,4CAA4C;IAC5C,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,8DAA8D;IAC9D,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,YAAY,EAAE,YAAY,CAwG7D,CAAC;AAEF;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,YAAY,GAAG,YAAY,CAEhE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC5B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,YAAY,EAClB,UAAU,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAChC,OAAO,CAeT;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC9B,IAAI,EAAE,YAAY,EAClB,UAAU,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAChC,MAAM,EAAE,CAgBV;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAChE,KAAK,EAAE,CAAC,EAAE,EACV,IAAI,EAAE,YAAY,EAClB,UAAU,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAChC,CAAC,EAAE,CAOL;AAOD;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,YAAY,CAErD;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAG/D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAQtE;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,YAAY,CAErD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAGhE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,KAAK,CAAC;IAC5C,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,EAAE,YAAY,CAAC;CACnB,CAAC,CAOD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC/B,QAAQ,EAAE,YAAY,EACtB,SAAS,EAAE,OAAO,CAAC,YAAY,CAAC,GAC9B,YAAY,CAOd;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,MAAM,EAAE,CAYlE"}
|
|
@@ -8,12 +8,22 @@
|
|
|
8
8
|
* - coder: Full coding capabilities
|
|
9
9
|
* - reviewer: Read-only with web access for reviewing code
|
|
10
10
|
* - researcher: Web search and fetch focused
|
|
11
|
+
* - browser-qa: Browser-based product QA with screenshots and repro evidence
|
|
11
12
|
*
|
|
12
13
|
* Inspired by Amp's subagentSpec/subagentType system.
|
|
13
14
|
*/
|
|
15
|
+
import { codexSubagentLaneForType } from "../codex/subagent-dispatch-table.js";
|
|
14
16
|
import { createLogger } from "../utils/logger.js";
|
|
15
17
|
import { normalizeToolNameForSafety } from "../utils/safety-normalization.js";
|
|
16
18
|
const logger = createLogger("agent:subagent-specs");
|
|
19
|
+
const CODEX_LANE_SUBAGENT_TYPES = {
|
|
20
|
+
"code-writer": "coder",
|
|
21
|
+
"code-review": "reviewer",
|
|
22
|
+
"test-runner": "test-runner",
|
|
23
|
+
"browser-qa": "browser-qa",
|
|
24
|
+
"repo-explorer": "explorer",
|
|
25
|
+
"release-shepherd": "coder",
|
|
26
|
+
};
|
|
17
27
|
/**
|
|
18
28
|
* Tool categories for easier specification.
|
|
19
29
|
*/
|
|
@@ -34,6 +44,45 @@ export const TOOL_CATEGORIES = {
|
|
|
34
44
|
shell: ["bash", "background_tasks"],
|
|
35
45
|
/** Web and external tools */
|
|
36
46
|
web: ["websearch", "webfetch", "codesearch"],
|
|
47
|
+
/** Browser/product QA tools */
|
|
48
|
+
browser: [
|
|
49
|
+
"agent_browser",
|
|
50
|
+
"browser_open",
|
|
51
|
+
"browser_snapshot",
|
|
52
|
+
"browser_click",
|
|
53
|
+
"browser_fill",
|
|
54
|
+
"browser_type",
|
|
55
|
+
"browser_screenshot",
|
|
56
|
+
"browser_console",
|
|
57
|
+
"browser_record",
|
|
58
|
+
"read_page",
|
|
59
|
+
"search_page",
|
|
60
|
+
"find_on_page",
|
|
61
|
+
"extract_links",
|
|
62
|
+
"wait_for_selector",
|
|
63
|
+
"click_element",
|
|
64
|
+
"type_text",
|
|
65
|
+
"scroll_page",
|
|
66
|
+
"select_element",
|
|
67
|
+
"navigate_to",
|
|
68
|
+
"open_links_in_tabs",
|
|
69
|
+
"highlight_element",
|
|
70
|
+
"browser_operator",
|
|
71
|
+
"mouse_action",
|
|
72
|
+
"pointer_action",
|
|
73
|
+
"keyboard_action",
|
|
74
|
+
"extract_table_data",
|
|
75
|
+
"capture_network",
|
|
76
|
+
"capture_console_errors",
|
|
77
|
+
"collect_diagnostics",
|
|
78
|
+
"extract_document",
|
|
79
|
+
"capture_screenshot",
|
|
80
|
+
"native_click",
|
|
81
|
+
"native_type",
|
|
82
|
+
"native_press",
|
|
83
|
+
"native_key_down",
|
|
84
|
+
"native_key_up",
|
|
85
|
+
],
|
|
37
86
|
/** Interactive tools */
|
|
38
87
|
interactive: ["ask_user", "todo"],
|
|
39
88
|
/** GitHub tools */
|
|
@@ -92,6 +141,18 @@ export const SUBAGENT_SPECS = {
|
|
|
92
141
|
maxToolCallsPerTurn: 15,
|
|
93
142
|
requireConfirmation: false,
|
|
94
143
|
},
|
|
144
|
+
"test-runner": {
|
|
145
|
+
displayName: "Test Runner",
|
|
146
|
+
description: "Test execution mode - can run checks and inspect results",
|
|
147
|
+
allowedTools: [
|
|
148
|
+
...toolsFromCategories("read", "shell", "interactive"),
|
|
149
|
+
"webfetch",
|
|
150
|
+
],
|
|
151
|
+
allowMcp: false,
|
|
152
|
+
allowToolbox: false,
|
|
153
|
+
maxToolCallsPerTurn: 20,
|
|
154
|
+
requireConfirmation: false,
|
|
155
|
+
},
|
|
95
156
|
researcher: {
|
|
96
157
|
displayName: "Researcher",
|
|
97
158
|
description: "Research mode - focused on web search and analysis",
|
|
@@ -101,6 +162,20 @@ export const SUBAGENT_SPECS = {
|
|
|
101
162
|
maxToolCallsPerTurn: 20,
|
|
102
163
|
requireConfirmation: false,
|
|
103
164
|
},
|
|
165
|
+
"browser-qa": {
|
|
166
|
+
displayName: "Browser QA",
|
|
167
|
+
description: "Product QA mode - explores web surfaces and captures repro evidence",
|
|
168
|
+
allowedTools: [
|
|
169
|
+
...toolsFromCategories("read", "web", "browser"),
|
|
170
|
+
"bash",
|
|
171
|
+
"ask_user",
|
|
172
|
+
"todo",
|
|
173
|
+
],
|
|
174
|
+
allowMcp: true,
|
|
175
|
+
allowToolbox: true,
|
|
176
|
+
maxToolCallsPerTurn: 25,
|
|
177
|
+
requireConfirmation: false,
|
|
178
|
+
},
|
|
104
179
|
minimal: {
|
|
105
180
|
displayName: "Minimal",
|
|
106
181
|
description: "Minimal capabilities - only basic read operations",
|
|
@@ -189,20 +264,18 @@ export function setCurrentSubagentType(type) {
|
|
|
189
264
|
*/
|
|
190
265
|
export function parseSubagentType(typeStr) {
|
|
191
266
|
const normalized = normalizeToolNameForSafety(typeStr);
|
|
192
|
-
|
|
193
|
-
|
|
267
|
+
const hyphenated = normalized.replace(/_/g, "-");
|
|
268
|
+
if (hyphenated in SUBAGENT_SPECS) {
|
|
269
|
+
return hyphenated;
|
|
194
270
|
}
|
|
195
|
-
|
|
271
|
+
const lane = codexSubagentLaneForType(typeStr);
|
|
272
|
+
return lane ? (CODEX_LANE_SUBAGENT_TYPES[lane.laneId] ?? null) : null;
|
|
196
273
|
}
|
|
197
274
|
/**
|
|
198
275
|
* Get subagent type from environment variable.
|
|
199
276
|
*/
|
|
200
277
|
export function getSubagentTypeFromEnv() {
|
|
201
|
-
|
|
202
|
-
if (envType && envType in SUBAGENT_SPECS) {
|
|
203
|
-
return envType;
|
|
204
|
-
}
|
|
205
|
-
return "coder";
|
|
278
|
+
return parseSubagentType(process.env.MAESTRO_SUBAGENT_TYPE ?? "") ?? "coder";
|
|
206
279
|
}
|
|
207
280
|
/**
|
|
208
281
|
* Format subagent type for display.
|