@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,2085 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { existsSync, readdirSync, realpathSync, statSync, } from "node:fs";
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
import { basename, extname, isAbsolute, join, relative, resolve, sep, } from "node:path";
|
|
5
|
+
import { buildAgentWorkBoard, } from "../agent/agent-work-board.js";
|
|
6
|
+
import { getMissionDir, listMissionStoreSnapshots, sanitizeMissionId, } from "../agent/mission-store.js";
|
|
7
|
+
import { PATHS, SESSION_CONFIG } from "../config/constants.js";
|
|
8
|
+
import { classifyTaskState, summarizeA2ACockpit, } from "../platform/a2a-cockpit.js";
|
|
9
|
+
import { getA2ATaskLedgerPath, isAuditReadyA2ADelegationTask, isFinalA2AState, loadA2ATaskLedger, summarizeA2ATaskLedger, } from "../platform/a2a-task-ledger.js";
|
|
10
|
+
import { formatA2AWorkGraphCodexSubagents, formatA2AWorkGraphSummary, } from "../platform/a2a-work-graph.js";
|
|
11
|
+
import { defaultRuntimeEnv } from "../runtime/env.js";
|
|
12
|
+
import { buildSessionFileInfo, safeReadSessionEntries, } from "../session/session-context.js";
|
|
13
|
+
import { loadStore } from "../tools/todo.js";
|
|
14
|
+
import { getUsageEntries, } from "../tracking/cost-tracker.js";
|
|
15
|
+
import { writeTextFileAtomic } from "../utils/fs.js";
|
|
16
|
+
import { sanitizeWithStaticMask } from "../utils/secret-redactor.js";
|
|
17
|
+
import { ambientLearnerPresenceCommand, buildAmbientCustomerValue, flushAmbientLearnerBeforeRead, flushAmbientLearnerForReport, summarizeAmbientLearning, } from "./ambient-learning.js";
|
|
18
|
+
import { isTimestampInRange, parseTimestampMs, redactLine, sanitizeA2ALabel, sum, truncate, } from "./internal-helpers.js";
|
|
19
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
20
|
+
const USAGE_ACTIVITY_GRACE_MS = 5 * 60 * 1000;
|
|
21
|
+
const CUSTOMER_VALUE_MANIFEST_VERSION = "maestro.customer-value.manifest.v1";
|
|
22
|
+
export function resolveCustomerValueRange(period, now = Date.now()) {
|
|
23
|
+
switch (period ?? "30d") {
|
|
24
|
+
case "today":
|
|
25
|
+
return {
|
|
26
|
+
label: "Today",
|
|
27
|
+
since: new Date(now).setHours(0, 0, 0, 0),
|
|
28
|
+
};
|
|
29
|
+
case "yesterday": {
|
|
30
|
+
const start = new Date(now);
|
|
31
|
+
start.setDate(start.getDate() - 1);
|
|
32
|
+
const end = new Date(now);
|
|
33
|
+
return {
|
|
34
|
+
label: "Yesterday",
|
|
35
|
+
since: start.setHours(0, 0, 0, 0),
|
|
36
|
+
until: end.setHours(0, 0, 0, 0),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
case "week":
|
|
40
|
+
case "7d":
|
|
41
|
+
return { label: "Last 7 Days", since: now - 7 * DAY_MS };
|
|
42
|
+
case "all":
|
|
43
|
+
return { label: "All Time" };
|
|
44
|
+
case "month":
|
|
45
|
+
case "30d":
|
|
46
|
+
return { label: "Last 30 Days", since: now - 30 * DAY_MS };
|
|
47
|
+
default:
|
|
48
|
+
return { label: "Last 30 Days", since: now - 30 * DAY_MS };
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export async function buildCustomerValueReport(options = {}) {
|
|
52
|
+
const now = options.now ?? Date.now();
|
|
53
|
+
const range = resolveCustomerValueRange(options.period, now);
|
|
54
|
+
const sessionDir = options.sessionDir ?? SESSION_CONFIG.DEFAULT_DIR;
|
|
55
|
+
const telemetryPath = options.telemetryPath ?? PATHS.TELEMETRY_LOG;
|
|
56
|
+
const a2aTasksPath = getA2ATaskLedgerPath(options.a2aTasksPath);
|
|
57
|
+
const env = options.env ?? defaultRuntimeEnv();
|
|
58
|
+
const requestedAmbientLearnerPath = options.ambientLearnerPath ??
|
|
59
|
+
env.ambientLearnerFile ??
|
|
60
|
+
env.ambientLearnerDefaultFile;
|
|
61
|
+
const workspaceDir = options.workspaceDir ?? process.cwd();
|
|
62
|
+
const usageEntries = getUsageEntries(usageFilters(range));
|
|
63
|
+
const usageEntriesBySession = groupUsageEntriesBySession(usageEntries);
|
|
64
|
+
const trustCards = collectTrustCards({
|
|
65
|
+
sessionDir,
|
|
66
|
+
range,
|
|
67
|
+
limit: options.sessionLimit,
|
|
68
|
+
usageEntriesBySession,
|
|
69
|
+
});
|
|
70
|
+
const ambientLearningPromise = (async () => {
|
|
71
|
+
const flushResult = options.flushAmbientLearner === false
|
|
72
|
+
? undefined
|
|
73
|
+
: await flushAmbientLearnerForReport(env, requestedAmbientLearnerPath, options.ambientLearnerFlush ?? flushAmbientLearnerBeforeRead);
|
|
74
|
+
return summarizeAmbientLearning(flushResult?.learnerPath ?? requestedAmbientLearnerPath, range, flushResult, requestedAmbientLearnerPath);
|
|
75
|
+
})();
|
|
76
|
+
const [telemetry, multiAgent, ambientLearning] = await Promise.all([
|
|
77
|
+
summarizeTelemetry(telemetryPath, range),
|
|
78
|
+
summarizeMultiAgentValue(a2aTasksPath, range),
|
|
79
|
+
ambientLearningPromise,
|
|
80
|
+
]);
|
|
81
|
+
const memoryItems = trustCards
|
|
82
|
+
.filter((card) => card.evidence.memoryExtractionHash)
|
|
83
|
+
.map((card) => ({
|
|
84
|
+
sessionId: card.sessionId,
|
|
85
|
+
title: card.title,
|
|
86
|
+
...(card.cwd ? { cwd: card.cwd } : {}),
|
|
87
|
+
memoryExtractionHash: card.evidence.memoryExtractionHash,
|
|
88
|
+
sessionPath: card.evidence.sessionPath,
|
|
89
|
+
}));
|
|
90
|
+
const todoStore = options.todoStore
|
|
91
|
+
? sanitizeCustomerValueTodoStore(options.todoStore)
|
|
92
|
+
: await loadCustomerValueTodoStore();
|
|
93
|
+
const handoffs = buildCustomerValueHandoffs(trustCards, todoStore);
|
|
94
|
+
const ambient = buildAmbientCustomerValue({
|
|
95
|
+
learning: ambientLearning,
|
|
96
|
+
multiAgent,
|
|
97
|
+
trustCards,
|
|
98
|
+
handoffs,
|
|
99
|
+
});
|
|
100
|
+
const agentWorkBoard = await buildCustomerValueWorkBoard({
|
|
101
|
+
tasksPath: a2aTasksPath,
|
|
102
|
+
range,
|
|
103
|
+
workspaceDir,
|
|
104
|
+
missions: options.missionManifests,
|
|
105
|
+
todos: todoStore,
|
|
106
|
+
handoffs: handoffs.sessions,
|
|
107
|
+
openWork: handoffs.openWork,
|
|
108
|
+
githubTasks: options.githubTasks,
|
|
109
|
+
missionStoreDir: env.missionStoreDir,
|
|
110
|
+
now,
|
|
111
|
+
});
|
|
112
|
+
const summary = summarizeCustomerValue({
|
|
113
|
+
ambient,
|
|
114
|
+
multiAgent,
|
|
115
|
+
trustCards,
|
|
116
|
+
});
|
|
117
|
+
const workflows = buildWorkflowOpportunities(trustCards, multiAgent, ambient);
|
|
118
|
+
const admin = buildAdminControls({
|
|
119
|
+
ambient,
|
|
120
|
+
multiAgent,
|
|
121
|
+
trustCards,
|
|
122
|
+
telemetry,
|
|
123
|
+
sessionDir,
|
|
124
|
+
});
|
|
125
|
+
const collectionGaps = buildCollectionGaps({
|
|
126
|
+
multiAgent,
|
|
127
|
+
trustCards,
|
|
128
|
+
telemetry,
|
|
129
|
+
usageEntries,
|
|
130
|
+
ambient,
|
|
131
|
+
});
|
|
132
|
+
return {
|
|
133
|
+
generatedAt: new Date(now).toISOString(),
|
|
134
|
+
range,
|
|
135
|
+
sources: {
|
|
136
|
+
sessionDir,
|
|
137
|
+
telemetryPath,
|
|
138
|
+
usagePath: PATHS.USAGE_FILE,
|
|
139
|
+
a2aTasksPath,
|
|
140
|
+
ambientLearnerPath: ambientLearning.learnerPath,
|
|
141
|
+
},
|
|
142
|
+
summary,
|
|
143
|
+
trustCards,
|
|
144
|
+
multiAgent,
|
|
145
|
+
ambient,
|
|
146
|
+
workflows,
|
|
147
|
+
memory: {
|
|
148
|
+
provenanceCount: memoryItems.length,
|
|
149
|
+
items: memoryItems,
|
|
150
|
+
},
|
|
151
|
+
handoffs,
|
|
152
|
+
agentWorkBoard,
|
|
153
|
+
admin,
|
|
154
|
+
telemetry,
|
|
155
|
+
collectionGaps,
|
|
156
|
+
referenceLearnings: [
|
|
157
|
+
"Effectiveness reports should be generated from persisted evidence, not self-assessment.",
|
|
158
|
+
"Customer metrics need stable names and operator-facing rollups close to tool execution.",
|
|
159
|
+
"Session artifacts should be named, durable, and replayable enough for another human to audit.",
|
|
160
|
+
"Workflow templates are most useful when they state the customer outcome and required evidence.",
|
|
161
|
+
"Multi-agent value is clearest when delegated task ledgers show owner, peer, state, transcript, and work graph evidence.",
|
|
162
|
+
"Durable customer value comes from structured handoffs: delivered work, unfinished work, blockers, and next action.",
|
|
163
|
+
"Ambient automation should wake the agent only when local evidence says there is customer-visible work to deliver.",
|
|
164
|
+
"Learning loops should persist durable playbooks and explicitly quarantine transient environment failures.",
|
|
165
|
+
],
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
export function formatCustomerValueReport(report) {
|
|
169
|
+
const lines = [
|
|
170
|
+
`Customer Value Report (${report.range.label})`,
|
|
171
|
+
"=====================",
|
|
172
|
+
"",
|
|
173
|
+
`Generated: ${report.generatedAt}`,
|
|
174
|
+
`Sessions: ${report.summary.sessionCount}`,
|
|
175
|
+
`Trust cards: ${report.summary.trustCardCount}`,
|
|
176
|
+
`Messages: ${report.summary.messageCount}`,
|
|
177
|
+
`Tool calls: ${report.summary.toolCallCount}`,
|
|
178
|
+
`Failed tool results: ${report.summary.failedToolResultCount}`,
|
|
179
|
+
`Usage: ${report.summary.usageRequests} requests, ${formatNumber(report.summary.totalTokens)} tokens, $${report.summary.totalCostUsd.toFixed(4)}`,
|
|
180
|
+
`Estimated value: ${report.summary.estimatedHoursSaved.toFixed(1)} hours / $${report.summary.estimatedValueUsd.toFixed(2)}${report.summary.valueMultiple === null ? "" : ` (${report.summary.valueMultiple.toFixed(1)}x spend)`}`,
|
|
181
|
+
`Multi-agent realized value: ${report.summary.multiAgentEstimatedHoursSaved.toFixed(1)} hours / $${report.summary.multiAgentEstimatedValueUsd.toFixed(2)}`,
|
|
182
|
+
`Memory-backed sessions: ${report.summary.memoryBackedSessionCount}`,
|
|
183
|
+
`Multi-agent tasks: ${report.summary.multiAgentTaskCount} across ${report.summary.multiAgentPeerCount} peer(s), ${report.summary.multiAgentWorkGraphTaskCount} with work graphs, ${report.summary.multiAgentChildRunCount} child run(s)`,
|
|
184
|
+
`Ambient opportunities: ${report.summary.ambientAutomationOpportunityCount} automation(s), ${report.summary.playbookLearningOpportunityCount} playbook update(s), ${report.summary.ambientLearnerOutcomeCount} learner outcome(s)`,
|
|
185
|
+
`Agent work board: ${report.agentWorkBoard.counts.total} item(s), ${report.agentWorkBoard.counts.blocked} blocked, ${report.agentWorkBoard.counts.waiting} waiting`,
|
|
186
|
+
"",
|
|
187
|
+
"Top Trust Cards",
|
|
188
|
+
"---------------",
|
|
189
|
+
];
|
|
190
|
+
if (report.trustCards.length === 0) {
|
|
191
|
+
lines.push("No sessions found for this range.", "");
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
for (const card of report.trustCards.slice(0, 5)) {
|
|
195
|
+
lines.push(`- ${card.title} (${card.sessionId})`, ` ${card.messageCount} messages, ${card.toolCallCount} tool calls, $${card.usage.costUsd.toFixed(4)} spend`, ` Evidence: ${card.evidence.sessionPath}`);
|
|
196
|
+
if (card.summary) {
|
|
197
|
+
lines.push(` Summary: ${card.summary}`);
|
|
198
|
+
}
|
|
199
|
+
if (card.riskSignals.length > 0) {
|
|
200
|
+
lines.push(` Risk: ${card.riskSignals.join("; ")}`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
lines.push("");
|
|
204
|
+
}
|
|
205
|
+
lines.push("Multi-Agent Coordination", "------------------------");
|
|
206
|
+
if (report.multiAgent.taskCount === 0) {
|
|
207
|
+
lines.push(...(report.multiAgent.collectionGaps.length > 0
|
|
208
|
+
? report.multiAgent.collectionGaps.map((gap) => `- ${gap}`)
|
|
209
|
+
: ["No A2A delegated tasks found for this range."]), "");
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
lines.push(`Decision: ${multiAgentDecisionLine(report.multiAgent)}`, `Realized value: ${report.multiAgent.realizedHoursSaved.toFixed(1)} hours / $${report.multiAgent.realizedValueUsd.toFixed(2)} from completed delegated work`, `Pending work: ${report.multiAgent.delegatedPendingTaskCount} task(s), ${report.multiAgent.delegatedEvidenceGapCount} evidence gap(s), ${report.multiAgent.auditReadyTaskCount} audit-ready task(s)`, `Tasks: ${report.multiAgent.taskCount} total, ${report.multiAgent.completedTaskCount} completed, ${report.multiAgent.failedTaskCount} failed, ${report.multiAgent.actionRequiredTaskCount} waiting on input`, `Peers: ${report.multiAgent.peerCount}; workGraph-backed tasks: ${report.multiAgent.workGraphTaskCount}`, `Work graph pressure: ${report.multiAgent.workGraphBlockedItemCount} blocked item(s), ${report.multiAgent.workGraphWaitingItemCount} waiting item(s), ${report.multiAgent.workGraphPendingToolCallCount} pending tool call(s), ${report.multiAgent.workGraphChildRunCount} child run(s)`, `Evidence: ${report.multiAgent.tasksPath}`);
|
|
213
|
+
if (report.multiAgent.topPeers.length > 0) {
|
|
214
|
+
lines.push("Peer rollup:");
|
|
215
|
+
for (const peer of report.multiAgent.topPeers) {
|
|
216
|
+
lines.push(`- ${peer.displayName ?? peer.peer}: ${peer.taskCount} task(s), ${peer.completedTaskCount} completed, ${peer.failedTaskCount} failed, ${peer.actionRequiredTaskCount} waiting`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (report.multiAgent.nextActions.length > 0) {
|
|
220
|
+
lines.push("Next actions:");
|
|
221
|
+
for (const action of report.multiAgent.nextActions) {
|
|
222
|
+
lines.push(`- [${action.severity}] ${action.label}`, ` Command: ${action.command}`, ` Reason: ${action.reason}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
for (const task of report.multiAgent.recentTasks) {
|
|
226
|
+
lines.push(`- ${task.peerDisplayName ?? task.peer}: ${task.status} (${task.state})`, ` ${task.text}`);
|
|
227
|
+
if (task.responseText) {
|
|
228
|
+
lines.push(` Response: ${task.responseText}`);
|
|
229
|
+
}
|
|
230
|
+
if (task.workGraphSummary) {
|
|
231
|
+
lines.push(` ${task.workGraphSummary}`);
|
|
232
|
+
}
|
|
233
|
+
if (task.codexSubagents) {
|
|
234
|
+
lines.push(` ${task.codexSubagents}`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
lines.push("");
|
|
238
|
+
}
|
|
239
|
+
lines.push("Durable Handoffs", "-----------------", `Delivered: ${report.handoffs.deliveredCount}, follow-up: ${report.handoffs.followupCount}, blocked: ${report.handoffs.blockedCount}, open work: ${report.handoffs.openWorkCount}`);
|
|
240
|
+
for (const handoff of report.handoffs.sessions.slice(0, 5)) {
|
|
241
|
+
lines.push(`- ${handoff.title} (${handoff.status})`, ` Delivered: ${handoff.delivered}`, ` Next: ${handoff.nextAction}`, ` Evidence: ${handoff.evidence.sessionPath}`);
|
|
242
|
+
if (handoff.unfinished) {
|
|
243
|
+
lines.push(` Unfinished: ${handoff.unfinished}`);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
if (report.handoffs.openWork.length > 0) {
|
|
247
|
+
lines.push(" Open work:");
|
|
248
|
+
for (const item of report.handoffs.openWork.slice(0, 5)) {
|
|
249
|
+
const blockers = item.blockers.length > 0
|
|
250
|
+
? ` blocked by ${item.blockers.join(", ")}`
|
|
251
|
+
: "";
|
|
252
|
+
lines.push(` - [${item.status}] ${item.content} (${item.goal}, ${item.priority})${blockers}`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
lines.push("");
|
|
256
|
+
lines.push("Ambient Automation", "-------------------", `Learner outcomes: ${report.ambient.outcomeCount}, success rate: ${report.ambient.successRate === null ? "n/a" : `${(report.ambient.successRate * 100).toFixed(1)}%`}, protected transient failures: ${report.ambient.protectedTransientFailureCount}`, `Learner evidence: ${report.ambient.learnerPath}`);
|
|
257
|
+
if (report.ambient.automationOpportunities.length === 0) {
|
|
258
|
+
lines.push("No ambient automation opportunities found for this range.");
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
for (const opportunity of report.ambient.automationOpportunities) {
|
|
262
|
+
lines.push(`- ${opportunity.id}: ${opportunity.customerOutcome}`, ` Trigger: ${opportunity.triggerEvidence}`, ` Cadence: ${opportunity.recommendedCadence}; gate: ${opportunity.scriptGate}`, ` Delivery: ${opportunity.delivery}`);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
lines.push("");
|
|
266
|
+
lines.push("Playbook Learning", "-----------------");
|
|
267
|
+
if (report.ambient.playbookLearningOpportunities.length === 0) {
|
|
268
|
+
lines.push("No playbook learning opportunities found for this range.");
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
for (const opportunity of report.ambient.playbookLearningOpportunities) {
|
|
272
|
+
lines.push(`- ${opportunity.id}: ${opportunity.customerOutcome}`, ` Evidence: ${opportunity.evidenceSignal}`, ` Guardrail: ${opportunity.guardrail}`, ` Artifact: ${opportunity.recommendedArtifact}`);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
lines.push("");
|
|
276
|
+
lines.push("Agent Work Board", "----------------", `Items: ${report.agentWorkBoard.counts.total}; blocked: ${report.agentWorkBoard.counts.blocked}; waiting: ${report.agentWorkBoard.counts.waiting}; running: ${report.agentWorkBoard.counts.running}`);
|
|
277
|
+
for (const item of report.agentWorkBoard.items.slice(0, 8)) {
|
|
278
|
+
lines.push(`- [${item.source}/${item.status}] ${item.title}`);
|
|
279
|
+
if (item.owner) {
|
|
280
|
+
lines.push(` Owner: ${item.owner}`);
|
|
281
|
+
}
|
|
282
|
+
if (item.nextAction) {
|
|
283
|
+
lines.push(` Next: ${item.nextAction.label}${item.nextAction.command ? ` (${item.nextAction.command})` : ""}`);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
lines.push("");
|
|
287
|
+
lines.push("Workflow Opportunities", "----------------------");
|
|
288
|
+
for (const workflow of report.workflows) {
|
|
289
|
+
lines.push(`- ${workflow.name}: ${workflow.customerOutcome}`, ` Evidence: ${workflow.evidenceSignal}`, ` Surface: ${workflow.recommendedSurface}`, ` Template: ${workflow.workflowTemplate.path}`);
|
|
290
|
+
}
|
|
291
|
+
lines.push("");
|
|
292
|
+
lines.push("Admin Controls", "--------------");
|
|
293
|
+
for (const control of report.admin.controls) {
|
|
294
|
+
lines.push(`- ${control.name}: ${control.status}`, ` Evidence: ${control.evidence}`);
|
|
295
|
+
}
|
|
296
|
+
lines.push("");
|
|
297
|
+
if (report.collectionGaps.length > 0) {
|
|
298
|
+
lines.push("Collection Gaps", "---------------");
|
|
299
|
+
for (const gap of report.collectionGaps) {
|
|
300
|
+
lines.push(`- ${gap}`);
|
|
301
|
+
}
|
|
302
|
+
lines.push("");
|
|
303
|
+
}
|
|
304
|
+
return lines.join("\n").trimEnd();
|
|
305
|
+
}
|
|
306
|
+
export function formatCustomerValueMarkdown(report) {
|
|
307
|
+
const lines = [
|
|
308
|
+
`# Customer Value Report (${report.range.label})`,
|
|
309
|
+
"",
|
|
310
|
+
`Generated: ${report.generatedAt}`,
|
|
311
|
+
"",
|
|
312
|
+
"## Summary",
|
|
313
|
+
"",
|
|
314
|
+
`- Sessions: ${report.summary.sessionCount}`,
|
|
315
|
+
`- Trust cards: ${report.summary.trustCardCount}`,
|
|
316
|
+
`- Tool calls: ${report.summary.toolCallCount}`,
|
|
317
|
+
`- Failed tool results: ${report.summary.failedToolResultCount}`,
|
|
318
|
+
`- Usage: ${report.summary.usageRequests} requests, ${formatNumber(report.summary.totalTokens)} tokens, $${report.summary.totalCostUsd.toFixed(4)}`,
|
|
319
|
+
`- Estimated value: ${report.summary.estimatedHoursSaved.toFixed(1)} hours / $${report.summary.estimatedValueUsd.toFixed(2)}`,
|
|
320
|
+
`- Multi-agent realized value: ${report.summary.multiAgentEstimatedHoursSaved.toFixed(1)} hours / $${report.summary.multiAgentEstimatedValueUsd.toFixed(2)}`,
|
|
321
|
+
`- Multi-agent tasks: ${report.summary.multiAgentTaskCount} across ${report.summary.multiAgentPeerCount} peer(s), ${report.summary.multiAgentWorkGraphTaskCount} with work graphs, ${report.summary.multiAgentChildRunCount} child run(s)`,
|
|
322
|
+
`- Ambient opportunities: ${report.summary.ambientAutomationOpportunityCount} automation(s), ${report.summary.playbookLearningOpportunityCount} playbook update(s)`,
|
|
323
|
+
`- Ambient learner outcomes: ${report.summary.ambientLearnerOutcomeCount}`,
|
|
324
|
+
"",
|
|
325
|
+
"## Trust Cards",
|
|
326
|
+
"",
|
|
327
|
+
];
|
|
328
|
+
for (const card of report.trustCards) {
|
|
329
|
+
lines.push(`### ${card.title}`, "", `- Session: \`${card.sessionId}\``, `- Evidence: \`${card.evidence.sessionPath}\``, `- Messages/tool calls: ${card.messageCount}/${card.toolCallCount}`, `- Usage: ${card.usage.requests} requests, ${formatNumber(card.usage.tokens)} tokens, $${card.usage.costUsd.toFixed(4)}`);
|
|
330
|
+
if (card.summary)
|
|
331
|
+
lines.push(`- Summary: ${card.summary}`);
|
|
332
|
+
if (card.customerSignals.length > 0) {
|
|
333
|
+
lines.push(`- Customer signals: ${card.customerSignals.join("; ")}`);
|
|
334
|
+
}
|
|
335
|
+
if (card.riskSignals.length > 0) {
|
|
336
|
+
lines.push(`- Risk signals: ${card.riskSignals.join("; ")}`);
|
|
337
|
+
}
|
|
338
|
+
lines.push("");
|
|
339
|
+
}
|
|
340
|
+
lines.push("## Multi-Agent Coordination", "");
|
|
341
|
+
if (report.multiAgent.taskCount === 0) {
|
|
342
|
+
lines.push(...(report.multiAgent.collectionGaps.length > 0
|
|
343
|
+
? report.multiAgent.collectionGaps.map((gap) => `- ${gap}`)
|
|
344
|
+
: ["- No A2A delegated tasks found for this range."]), "");
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
lines.push(`- Decision: ${multiAgentDecisionLine(report.multiAgent)}`, `- Realized value: ${report.multiAgent.realizedHoursSaved.toFixed(1)} hours / $${report.multiAgent.realizedValueUsd.toFixed(2)} from completed delegated work`, `- Pending work: ${report.multiAgent.delegatedPendingTaskCount} task(s)`, `- Audit-ready tasks: ${report.multiAgent.auditReadyTaskCount}`, `- Evidence gaps: ${report.multiAgent.delegatedEvidenceGapCount}`, `- Evidence: \`${report.multiAgent.tasksPath}\``, `- Tasks: ${report.multiAgent.taskCount} total, ${report.multiAgent.completedTaskCount} completed, ${report.multiAgent.failedTaskCount} failed, ${report.multiAgent.actionRequiredTaskCount} waiting on input`, `- Peers: ${report.multiAgent.peerCount}`, `- WorkGraph-backed tasks: ${report.multiAgent.workGraphTaskCount}`, `- Child runs: ${report.multiAgent.workGraphChildRunCount}`, `- Blocked/waiting work graph items: ${report.multiAgent.workGraphBlockedItemCount}/${report.multiAgent.workGraphWaitingItemCount}`, `- Pending tool calls: ${report.multiAgent.workGraphPendingToolCallCount}`, `- Codex subagent lifecycle edges: ${report.multiAgent.codexSubagentEdgeCount}`, `- Transcript messages: ${report.multiAgent.transcriptMessageCount}`, "");
|
|
348
|
+
if (report.multiAgent.topPeers.length > 0) {
|
|
349
|
+
lines.push("### Peer Rollup", "");
|
|
350
|
+
for (const peer of report.multiAgent.topPeers) {
|
|
351
|
+
lines.push(`- ${peer.displayName ?? peer.peer}: ${peer.taskCount} task(s), ${peer.completedTaskCount} completed, ${peer.failedTaskCount} failed, ${peer.actionRequiredTaskCount} waiting`);
|
|
352
|
+
}
|
|
353
|
+
lines.push("");
|
|
354
|
+
}
|
|
355
|
+
if (report.multiAgent.nextActions.length > 0) {
|
|
356
|
+
lines.push("### Next Actions", "");
|
|
357
|
+
for (const action of report.multiAgent.nextActions) {
|
|
358
|
+
lines.push(`- **${action.severity}** ${action.label}`, ` - Command: \`${action.command}\``, ` - Reason: ${action.reason}`);
|
|
359
|
+
}
|
|
360
|
+
lines.push("");
|
|
361
|
+
}
|
|
362
|
+
for (const task of report.multiAgent.recentTasks) {
|
|
363
|
+
lines.push(`### ${task.peerDisplayName ?? task.peer}: ${task.status}`, "", `- Task: \`${task.id}\``, `- State: ${task.state}`, `- Updated: ${task.updatedAt}`, `- Work graph: ${task.workGraph ? "yes" : "no"}`, `- Request: ${task.text}`);
|
|
364
|
+
if (task.responseText)
|
|
365
|
+
lines.push(`- Response: ${task.responseText}`);
|
|
366
|
+
if (task.workGraphSummary)
|
|
367
|
+
lines.push(`- ${task.workGraphSummary}`);
|
|
368
|
+
if (task.codexSubagents)
|
|
369
|
+
lines.push(`- ${task.codexSubagents}`);
|
|
370
|
+
lines.push("");
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
lines.push("## Durable Handoffs", "");
|
|
374
|
+
lines.push(`- Delivered: ${report.handoffs.deliveredCount}`, `- Needs follow-up: ${report.handoffs.followupCount}`, `- Blocked: ${report.handoffs.blockedCount}`, `- Open work items: ${report.handoffs.openWorkCount}`, "");
|
|
375
|
+
for (const handoff of report.handoffs.sessions) {
|
|
376
|
+
lines.push(`### ${handoff.title}`, "", `- Status: ${handoff.status}`, `- Delivered: ${handoff.delivered}`, `- Next action: ${handoff.nextAction}`, `- Evidence: \`${handoff.evidence.sessionPath}\``);
|
|
377
|
+
if (handoff.unfinished) {
|
|
378
|
+
lines.push(`- Unfinished: ${handoff.unfinished}`);
|
|
379
|
+
}
|
|
380
|
+
if (handoff.blockers.length > 0) {
|
|
381
|
+
lines.push(`- Blockers: ${handoff.blockers.join("; ")}`);
|
|
382
|
+
}
|
|
383
|
+
lines.push("");
|
|
384
|
+
}
|
|
385
|
+
if (report.handoffs.openWork.length > 0) {
|
|
386
|
+
lines.push("### Open Work", "");
|
|
387
|
+
for (const item of report.handoffs.openWork) {
|
|
388
|
+
const blockers = item.blockers.length > 0
|
|
389
|
+
? `; blocked by ${item.blockers.join(", ")}`
|
|
390
|
+
: "";
|
|
391
|
+
lines.push(`- [${item.status}] ${item.content} (${item.goal}; ${item.priority}${blockers})`);
|
|
392
|
+
}
|
|
393
|
+
lines.push("");
|
|
394
|
+
}
|
|
395
|
+
lines.push("## Ambient Automation", "");
|
|
396
|
+
lines.push(`- Learner evidence: \`${report.ambient.learnerPath}\``, `- Outcomes: ${report.ambient.outcomeCount}`, `- Success rate: ${report.ambient.successRate === null ? "n/a" : `${(report.ambient.successRate * 100).toFixed(1)}%`}`, `- Patterns: ${report.ambient.patternCount}`, `- Protected transient failures: ${report.ambient.protectedTransientFailureCount}`, "");
|
|
397
|
+
if (report.ambient.automationOpportunities.length === 0) {
|
|
398
|
+
lines.push("- No ambient automation opportunities found for this range.", "");
|
|
399
|
+
}
|
|
400
|
+
else {
|
|
401
|
+
for (const opportunity of report.ambient.automationOpportunities) {
|
|
402
|
+
lines.push(`### ${opportunity.id}`, "", `- Outcome: ${opportunity.customerOutcome}`, `- Trigger: ${opportunity.triggerEvidence}`, `- Cadence: ${opportunity.recommendedCadence}`, `- Script gate: \`${opportunity.scriptGate}\``, `- Delivery: ${opportunity.delivery}`, "");
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
lines.push("## Playbook Learning", "");
|
|
406
|
+
if (report.ambient.playbookLearningOpportunities.length === 0) {
|
|
407
|
+
lines.push("- No playbook learning opportunities found for this range.", "");
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
for (const opportunity of report.ambient.playbookLearningOpportunities) {
|
|
411
|
+
lines.push(`### ${opportunity.id}`, "", `- Outcome: ${opportunity.customerOutcome}`, `- Evidence: ${opportunity.evidenceSignal}`, `- Guardrail: ${opportunity.guardrail}`, `- Artifact: \`${opportunity.recommendedArtifact}\``, "");
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
lines.push("## Agent Work Board", "");
|
|
415
|
+
lines.push(`- Items: ${report.agentWorkBoard.counts.total}`, `- Blocked: ${report.agentWorkBoard.counts.blocked}`, `- Waiting: ${report.agentWorkBoard.counts.waiting}`, `- Running: ${report.agentWorkBoard.counts.running}`, "");
|
|
416
|
+
for (const item of report.agentWorkBoard.items.slice(0, 8)) {
|
|
417
|
+
lines.push(`- **${item.source}/${item.status}** ${item.title}`);
|
|
418
|
+
if (item.owner) {
|
|
419
|
+
lines.push(` - Owner: ${item.owner}`);
|
|
420
|
+
}
|
|
421
|
+
if (item.nextAction) {
|
|
422
|
+
lines.push(` - Next: ${item.nextAction.label}`);
|
|
423
|
+
if (item.nextAction.command) {
|
|
424
|
+
lines.push(` - Command: \`${item.nextAction.command}\``);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
lines.push("");
|
|
429
|
+
lines.push("## Workflows", "");
|
|
430
|
+
for (const workflow of report.workflows) {
|
|
431
|
+
lines.push(`### ${workflow.name}`, "", workflow.customerOutcome, "", `- Evidence: ${workflow.evidenceSignal}`, `- Surface: ${workflow.recommendedSurface}`, `- Template: \`${workflow.workflowTemplate.path}\``, "", "```yaml", workflow.workflowTemplate.yaml.trimEnd(), "```", "");
|
|
432
|
+
}
|
|
433
|
+
lines.push("## Memory Provenance", "");
|
|
434
|
+
if (report.memory.items.length === 0) {
|
|
435
|
+
lines.push("- No memory-backed sessions found.");
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
438
|
+
for (const item of report.memory.items) {
|
|
439
|
+
lines.push(`- ${item.title}: \`${item.memoryExtractionHash}\` from \`${item.sessionPath}\``);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
lines.push("", "## Admin Controls", "");
|
|
443
|
+
for (const control of report.admin.controls) {
|
|
444
|
+
lines.push(`- **${control.name}** (${control.status}): ${control.evidence}`);
|
|
445
|
+
}
|
|
446
|
+
if (report.collectionGaps.length > 0) {
|
|
447
|
+
lines.push("", "## Collection Gaps", "");
|
|
448
|
+
for (const gap of report.collectionGaps) {
|
|
449
|
+
lines.push(`- ${gap}`);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
return lines.join("\n").trimEnd();
|
|
453
|
+
}
|
|
454
|
+
export async function writeCustomerValueArtifacts(report, options = {}) {
|
|
455
|
+
const outputDir = options.outputDir ?? join(PATHS.MAESTRO_HOME, "value-reports");
|
|
456
|
+
const baseName = nextCustomerValueArtifactBaseName(outputDir, customerValueArtifactBaseName(report));
|
|
457
|
+
const reportJsonPath = join(outputDir, `${baseName}.json`);
|
|
458
|
+
const reportMarkdownPath = join(outputDir, `${baseName}.md`);
|
|
459
|
+
const manifestPath = join(outputDir, `${baseName}.manifest.json`);
|
|
460
|
+
const reportJson = `${JSON.stringify(report, null, 2)}\n`;
|
|
461
|
+
const reportMarkdown = `${formatCustomerValueMarkdown(report)}\n`;
|
|
462
|
+
const reportJsonSha256 = sha256(reportJson);
|
|
463
|
+
const reportMarkdownSha256 = sha256(reportMarkdown);
|
|
464
|
+
const manifest = {
|
|
465
|
+
protocolVersion: CUSTOMER_VALUE_MANIFEST_VERSION,
|
|
466
|
+
generatedAt: report.generatedAt,
|
|
467
|
+
range: report.range,
|
|
468
|
+
artifacts: {
|
|
469
|
+
reportJsonPath,
|
|
470
|
+
reportMarkdownPath,
|
|
471
|
+
},
|
|
472
|
+
hashes: {
|
|
473
|
+
reportJsonSha256,
|
|
474
|
+
reportMarkdownSha256,
|
|
475
|
+
},
|
|
476
|
+
sources: {
|
|
477
|
+
...report.sources,
|
|
478
|
+
sessionPaths: report.trustCards.map((card) => card.evidence.sessionPath),
|
|
479
|
+
},
|
|
480
|
+
summary: report.summary,
|
|
481
|
+
coverage: {
|
|
482
|
+
trustCardCount: report.trustCards.length,
|
|
483
|
+
memoryProvenanceCount: report.memory.provenanceCount,
|
|
484
|
+
multiAgentTaskCount: report.multiAgent.taskCount,
|
|
485
|
+
multiAgentWorkGraphTaskCount: report.multiAgent.workGraphTaskCount,
|
|
486
|
+
policyApprovalAuditEvents: report.telemetry.policyApprovalAuditEvents,
|
|
487
|
+
collectionGapCount: report.collectionGaps.length,
|
|
488
|
+
handoffCount: report.handoffs.sessions.length,
|
|
489
|
+
openWorkCount: report.handoffs.openWorkCount,
|
|
490
|
+
ambientAutomationOpportunityCount: report.ambient.automationOpportunities.length,
|
|
491
|
+
playbookLearningOpportunityCount: report.ambient.playbookLearningOpportunities.length,
|
|
492
|
+
agentWorkItemCount: report.agentWorkBoard.counts.total,
|
|
493
|
+
},
|
|
494
|
+
controls: report.admin.controls.map((control) => ({
|
|
495
|
+
id: control.id,
|
|
496
|
+
status: control.status,
|
|
497
|
+
})),
|
|
498
|
+
};
|
|
499
|
+
const manifestJson = `${JSON.stringify(manifest, null, 2)}\n`;
|
|
500
|
+
writeTextFileAtomic(reportJsonPath, reportJson, { encoding: "utf-8" });
|
|
501
|
+
writeTextFileAtomic(reportMarkdownPath, reportMarkdown, {
|
|
502
|
+
encoding: "utf-8",
|
|
503
|
+
});
|
|
504
|
+
writeTextFileAtomic(manifestPath, manifestJson, { encoding: "utf-8" });
|
|
505
|
+
return {
|
|
506
|
+
outputDir,
|
|
507
|
+
reportJsonPath,
|
|
508
|
+
reportMarkdownPath,
|
|
509
|
+
manifestPath,
|
|
510
|
+
reportJsonSha256,
|
|
511
|
+
reportMarkdownSha256,
|
|
512
|
+
manifestSha256: sha256(manifestJson),
|
|
513
|
+
manifest,
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
function customerValueArtifactBaseName(report) {
|
|
517
|
+
const timestamp = report.generatedAt
|
|
518
|
+
.replace(/[^0-9A-Za-z]+/g, "-")
|
|
519
|
+
.replace(/^-|-$/g, "");
|
|
520
|
+
const range = report.range.label
|
|
521
|
+
.toLowerCase()
|
|
522
|
+
.replace(/[^0-9a-z]+/g, "-")
|
|
523
|
+
.replace(/^-|-$/g, "");
|
|
524
|
+
return `customer-value-${range || "report"}-${timestamp}`;
|
|
525
|
+
}
|
|
526
|
+
function nextCustomerValueArtifactBaseName(outputDir, baseName) {
|
|
527
|
+
for (let attempt = 0; attempt < 1000; attempt += 1) {
|
|
528
|
+
const candidate = attempt === 0 ? baseName : `${baseName}-${attempt + 1}`;
|
|
529
|
+
if (!existsSync(join(outputDir, `${candidate}.json`)) &&
|
|
530
|
+
!existsSync(join(outputDir, `${candidate}.md`)) &&
|
|
531
|
+
!existsSync(join(outputDir, `${candidate}.manifest.json`))) {
|
|
532
|
+
return candidate;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
throw new Error(`Could not allocate a unique customer value artifact filename for ${baseName}`);
|
|
536
|
+
}
|
|
537
|
+
function sha256(content) {
|
|
538
|
+
return createHash("sha256").update(content).digest("hex");
|
|
539
|
+
}
|
|
540
|
+
function usageFilters(range) {
|
|
541
|
+
return {
|
|
542
|
+
since: range.since,
|
|
543
|
+
// Customer-value ranges treat `until` as exclusive, while usage filters
|
|
544
|
+
// treat it as inclusive.
|
|
545
|
+
until: range.until === undefined ? undefined : Math.max(range.until - 1, 0),
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
function collectTrustCards(params) {
|
|
549
|
+
const cards = findSessionFiles(params.sessionDir)
|
|
550
|
+
.map((sessionPath) => analyzeSession(sessionPath, params.range, params.usageEntriesBySession))
|
|
551
|
+
.filter((analysis) => analysis !== null)
|
|
552
|
+
.sort((left, right) => right.timestamp - left.timestamp)
|
|
553
|
+
.map((analysis) => analysis.card);
|
|
554
|
+
return typeof params.limit === "number"
|
|
555
|
+
? cards.slice(0, params.limit)
|
|
556
|
+
: cards;
|
|
557
|
+
}
|
|
558
|
+
function analyzeSession(sessionPath, range, usageEntriesBySession) {
|
|
559
|
+
let stats;
|
|
560
|
+
try {
|
|
561
|
+
stats = statSync(sessionPath);
|
|
562
|
+
}
|
|
563
|
+
catch {
|
|
564
|
+
return null;
|
|
565
|
+
}
|
|
566
|
+
const entries = safeReadSessionEntries(sessionPath);
|
|
567
|
+
const info = buildSessionFileInfo(entries, stats, { messagesView: "full" });
|
|
568
|
+
if (!info || info.id === "unknown")
|
|
569
|
+
return null;
|
|
570
|
+
const scopedEntries = scopedSessionEntries(entries, range);
|
|
571
|
+
if (scopedEntries.length === 0)
|
|
572
|
+
return null;
|
|
573
|
+
const toolStats = collectToolStats(scopedEntries);
|
|
574
|
+
const activityRange = sessionActivityRange(scopedEntries);
|
|
575
|
+
const usage = summarizeUsageEntries(scopeUsageEntriesToActivity(usageEntriesBySession.get(info.id) ?? [], range, activityRange));
|
|
576
|
+
const scopedMetadata = collectScopedMetadata(scopedEntries);
|
|
577
|
+
const scopedTask = redactLine(firstUserMessageText(scopedEntries) ?? "");
|
|
578
|
+
const bounded = isBoundedRange(range);
|
|
579
|
+
const titleSource = (bounded
|
|
580
|
+
? scopedMetadata.title || scopedTask
|
|
581
|
+
: info.title?.trim() || info.subject?.trim() || info.firstMessage) ||
|
|
582
|
+
basename(sessionPath);
|
|
583
|
+
const title = truncate(redactLine(titleSource), 80) || basename(sessionPath);
|
|
584
|
+
const summary = redactLine(bounded
|
|
585
|
+
? (scopedMetadata.resumeSummary ?? scopedMetadata.summary ?? "")
|
|
586
|
+
: (info.resumeSummary ?? info.summary ?? ""));
|
|
587
|
+
const task = bounded ? scopedTask : redactLine(info.firstMessage);
|
|
588
|
+
const memoryExtractionHash = bounded
|
|
589
|
+
? scopedMetadata.memoryExtractionHash
|
|
590
|
+
: info.memoryExtractionHash;
|
|
591
|
+
const riskSignals = buildRiskSignals(toolStats, memoryExtractionHash);
|
|
592
|
+
const customerSignals = buildCustomerSignals({
|
|
593
|
+
toolStats,
|
|
594
|
+
summary,
|
|
595
|
+
usage,
|
|
596
|
+
hasMemory: Boolean(memoryExtractionHash),
|
|
597
|
+
});
|
|
598
|
+
return {
|
|
599
|
+
timestamp: latestEntryTimestamp(scopedEntries) ?? stats.mtimeMs,
|
|
600
|
+
card: {
|
|
601
|
+
sessionId: info.id,
|
|
602
|
+
title,
|
|
603
|
+
...(info.cwd ? { cwd: info.cwd } : {}),
|
|
604
|
+
createdAt: info.created.toISOString(),
|
|
605
|
+
updatedAt: stats.mtime.toISOString(),
|
|
606
|
+
messageCount: scopedEntries.filter((entry) => entry.type === "message")
|
|
607
|
+
.length,
|
|
608
|
+
assistantTurnCount: scopedEntries.filter((entry) => entry.type === "message" && entry.message.role === "assistant").length,
|
|
609
|
+
toolCallCount: toolStats.toolCallCount,
|
|
610
|
+
failedToolResultCount: toolStats.failedToolResultCount,
|
|
611
|
+
topTools: toolStats.topTools,
|
|
612
|
+
...(summary ? { summary } : {}),
|
|
613
|
+
...(task ? { task } : {}),
|
|
614
|
+
usage,
|
|
615
|
+
evidence: {
|
|
616
|
+
sessionPath,
|
|
617
|
+
hasSummary: Boolean(summary),
|
|
618
|
+
hasMemoryProvenance: Boolean(memoryExtractionHash),
|
|
619
|
+
...(memoryExtractionHash ? { memoryExtractionHash } : {}),
|
|
620
|
+
},
|
|
621
|
+
customerSignals,
|
|
622
|
+
riskSignals,
|
|
623
|
+
},
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
function collectToolStats(entries) {
|
|
627
|
+
const tools = new Map();
|
|
628
|
+
let toolCallCount = 0;
|
|
629
|
+
let failedToolResultCount = 0;
|
|
630
|
+
for (const entry of entries) {
|
|
631
|
+
if (entry.type !== "message")
|
|
632
|
+
continue;
|
|
633
|
+
const message = entry.message;
|
|
634
|
+
if (message.role === "assistant" && Array.isArray(message.content)) {
|
|
635
|
+
for (const block of message.content) {
|
|
636
|
+
if (block?.type === "toolCall") {
|
|
637
|
+
toolCallCount += 1;
|
|
638
|
+
tools.set(block.name, (tools.get(block.name) ?? 0) + 1);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
if (message.role === "toolResult") {
|
|
643
|
+
tools.set(message.toolName, (tools.get(message.toolName) ?? 0) + 1);
|
|
644
|
+
if (message.isError)
|
|
645
|
+
failedToolResultCount += 1;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
return {
|
|
649
|
+
toolCallCount,
|
|
650
|
+
failedToolResultCount,
|
|
651
|
+
topTools: [...tools.entries()]
|
|
652
|
+
.map(([name, count]) => ({ name, count }))
|
|
653
|
+
.sort((left, right) => right.count - left.count)
|
|
654
|
+
.slice(0, 5),
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
function scopedSessionEntries(entries, range) {
|
|
658
|
+
if (range.since === undefined && range.until === undefined)
|
|
659
|
+
return entries;
|
|
660
|
+
return entries.filter((entry) => isTimestampInRange(entryTimestampMs(entry), range));
|
|
661
|
+
}
|
|
662
|
+
function latestEntryTimestamp(entries) {
|
|
663
|
+
let latest;
|
|
664
|
+
for (const entry of entries) {
|
|
665
|
+
const timestamp = entryTimestampMs(entry);
|
|
666
|
+
if (timestamp === undefined)
|
|
667
|
+
continue;
|
|
668
|
+
latest = latest === undefined ? timestamp : Math.max(latest, timestamp);
|
|
669
|
+
}
|
|
670
|
+
return latest;
|
|
671
|
+
}
|
|
672
|
+
function sessionActivityRange(entries) {
|
|
673
|
+
let since;
|
|
674
|
+
let latest;
|
|
675
|
+
for (const entry of entries) {
|
|
676
|
+
const timestamp = entryTimestampMs(entry);
|
|
677
|
+
if (timestamp === undefined)
|
|
678
|
+
continue;
|
|
679
|
+
since = since === undefined ? timestamp : Math.min(since, timestamp);
|
|
680
|
+
latest = latest === undefined ? timestamp : Math.max(latest, timestamp);
|
|
681
|
+
}
|
|
682
|
+
return {
|
|
683
|
+
...(since === undefined ? {} : { since }),
|
|
684
|
+
// Usage records are often written just after the final assistant entry.
|
|
685
|
+
...(latest === undefined
|
|
686
|
+
? {}
|
|
687
|
+
: { untilExclusive: latest + USAGE_ACTIVITY_GRACE_MS }),
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
function entryTimestampMs(entry) {
|
|
691
|
+
const timestamp = parseTimestampMs(entry.timestamp);
|
|
692
|
+
if (timestamp !== undefined)
|
|
693
|
+
return timestamp;
|
|
694
|
+
if (entry.type !== "message")
|
|
695
|
+
return undefined;
|
|
696
|
+
return parseTimestampMs(entry.message.timestamp);
|
|
697
|
+
}
|
|
698
|
+
function collectScopedMetadata(entries) {
|
|
699
|
+
const metadata = {};
|
|
700
|
+
for (const entry of entries) {
|
|
701
|
+
if (entry.type !== "session_meta")
|
|
702
|
+
continue;
|
|
703
|
+
if (typeof entry.title === "string" && entry.title.trim()) {
|
|
704
|
+
metadata.title = entry.title.trim();
|
|
705
|
+
}
|
|
706
|
+
if (typeof entry.summary === "string" && entry.summary.trim()) {
|
|
707
|
+
metadata.summary = entry.summary;
|
|
708
|
+
}
|
|
709
|
+
if (typeof entry.resumeSummary === "string" && entry.resumeSummary.trim()) {
|
|
710
|
+
metadata.resumeSummary = entry.resumeSummary;
|
|
711
|
+
}
|
|
712
|
+
if (typeof entry.memoryExtractionHash === "string" &&
|
|
713
|
+
entry.memoryExtractionHash.trim()) {
|
|
714
|
+
metadata.memoryExtractionHash = entry.memoryExtractionHash;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
return metadata;
|
|
718
|
+
}
|
|
719
|
+
function firstUserMessageText(entries) {
|
|
720
|
+
for (const entry of entries) {
|
|
721
|
+
if (entry.type !== "message" || entry.message.role !== "user")
|
|
722
|
+
continue;
|
|
723
|
+
const text = messageText(entry.message.content);
|
|
724
|
+
if (text)
|
|
725
|
+
return text;
|
|
726
|
+
}
|
|
727
|
+
return undefined;
|
|
728
|
+
}
|
|
729
|
+
function messageText(content) {
|
|
730
|
+
if (typeof content === "string")
|
|
731
|
+
return content;
|
|
732
|
+
if (!Array.isArray(content))
|
|
733
|
+
return "";
|
|
734
|
+
return content
|
|
735
|
+
.map((block) => {
|
|
736
|
+
if (block &&
|
|
737
|
+
typeof block === "object" &&
|
|
738
|
+
"type" in block &&
|
|
739
|
+
block.type === "text" &&
|
|
740
|
+
"text" in block &&
|
|
741
|
+
typeof block.text === "string") {
|
|
742
|
+
return block.text;
|
|
743
|
+
}
|
|
744
|
+
return "";
|
|
745
|
+
})
|
|
746
|
+
.filter(Boolean)
|
|
747
|
+
.join(" ");
|
|
748
|
+
}
|
|
749
|
+
function isBoundedRange(range) {
|
|
750
|
+
return range.since !== undefined || range.until !== undefined;
|
|
751
|
+
}
|
|
752
|
+
function emptySessionUsage() {
|
|
753
|
+
return { requests: 0, tokens: 0, costUsd: 0 };
|
|
754
|
+
}
|
|
755
|
+
function groupUsageEntriesBySession(entries) {
|
|
756
|
+
const grouped = new Map();
|
|
757
|
+
for (const entry of entries) {
|
|
758
|
+
if (!entry.sessionId)
|
|
759
|
+
continue;
|
|
760
|
+
const current = grouped.get(entry.sessionId) ?? [];
|
|
761
|
+
current.push(entry);
|
|
762
|
+
grouped.set(entry.sessionId, current);
|
|
763
|
+
}
|
|
764
|
+
return grouped;
|
|
765
|
+
}
|
|
766
|
+
function scopeUsageEntriesToActivity(entries, range, activityRange) {
|
|
767
|
+
if (!isBoundedRange(range))
|
|
768
|
+
return entries;
|
|
769
|
+
return entries.filter((entry) => {
|
|
770
|
+
if (activityRange.since !== undefined &&
|
|
771
|
+
entry.timestamp < activityRange.since) {
|
|
772
|
+
return false;
|
|
773
|
+
}
|
|
774
|
+
if (activityRange.untilExclusive !== undefined &&
|
|
775
|
+
entry.timestamp >= activityRange.untilExclusive) {
|
|
776
|
+
return false;
|
|
777
|
+
}
|
|
778
|
+
return true;
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
function summarizeUsageEntries(entries) {
|
|
782
|
+
const usage = emptySessionUsage();
|
|
783
|
+
for (const entry of entries) {
|
|
784
|
+
usage.requests += 1;
|
|
785
|
+
usage.tokens +=
|
|
786
|
+
entry.tokensInput +
|
|
787
|
+
entry.tokensOutput +
|
|
788
|
+
(entry.tokensCacheRead ?? 0) +
|
|
789
|
+
(entry.tokensCacheWrite ?? 0);
|
|
790
|
+
usage.costUsd += entry.cost;
|
|
791
|
+
}
|
|
792
|
+
return usage;
|
|
793
|
+
}
|
|
794
|
+
async function summarizeMultiAgentValue(tasksPath, range) {
|
|
795
|
+
let tasks = [];
|
|
796
|
+
const collectionGaps = [];
|
|
797
|
+
try {
|
|
798
|
+
const ledger = await loadA2ATaskLedger({ path: tasksPath });
|
|
799
|
+
tasks = ledger.tasks.filter((task) => isA2ATaskInRange(task, range));
|
|
800
|
+
}
|
|
801
|
+
catch (error) {
|
|
802
|
+
collectionGaps.push(`A2A task ledger could not be read: ${sanitizeWithStaticMask(error instanceof Error ? error.message : String(error))}.`);
|
|
803
|
+
}
|
|
804
|
+
const peerSummaries = summarizeMultiAgentPeers(tasks);
|
|
805
|
+
const rollup = summarizeA2ATaskLedger(tasks);
|
|
806
|
+
const delegatedTasks = tasks.filter((task) => task.kind === "delegation");
|
|
807
|
+
const delegatedRollup = summarizeA2ATaskLedger(delegatedTasks);
|
|
808
|
+
const workGraphs = tasks
|
|
809
|
+
.map((task) => task.workGraph)
|
|
810
|
+
.filter((graph) => Boolean(graph));
|
|
811
|
+
const completedDelegations = delegatedTasks.filter(isAuditReadyA2ADelegationTask);
|
|
812
|
+
const realizedHoursSaved = Number((completedDelegations.length * 0.25 +
|
|
813
|
+
completedDelegations.filter((task) => Boolean(task.workGraph)).length *
|
|
814
|
+
0.1).toFixed(2));
|
|
815
|
+
if (tasks.length === 0 && collectionGaps.length === 0) {
|
|
816
|
+
collectionGaps.push(range.since === undefined && range.until === undefined
|
|
817
|
+
? `No A2A delegated task evidence found in ${tasksPath}.`
|
|
818
|
+
: `No A2A delegated task evidence found in ${tasksPath} for the selected range.`);
|
|
819
|
+
}
|
|
820
|
+
return {
|
|
821
|
+
tasksPath,
|
|
822
|
+
taskCount: rollup.taskCount,
|
|
823
|
+
delegatedTaskCount: rollup.delegatedTaskCount,
|
|
824
|
+
peerCount: new Set(tasks.map((task) => task.peer)).size,
|
|
825
|
+
completedTaskCount: rollup.completedTaskCount,
|
|
826
|
+
failedTaskCount: rollup.failedTaskCount,
|
|
827
|
+
actionRequiredTaskCount: rollup.actionRequiredTaskCount,
|
|
828
|
+
workGraphTaskCount: rollup.workGraphTaskCount,
|
|
829
|
+
workGraphChildRunCount: sum(workGraphs, (graph) => workGraphChildRunCount(graph)),
|
|
830
|
+
workGraphBlockedItemCount: sum(workGraphs, (graph) => graph.blockedItemCount ?? 0),
|
|
831
|
+
workGraphWaitingItemCount: sum(workGraphs, (graph) => graph.waitingItemCount ?? 0),
|
|
832
|
+
workGraphPendingToolCallCount: sum(workGraphs, (graph) => graph.pendingToolCallCount ?? 0),
|
|
833
|
+
codexSubagentEdgeCount: sum(workGraphs, (graph) => graph.codexSubagents?.edgeCount ??
|
|
834
|
+
graph.codexSubagents?.edges?.length ??
|
|
835
|
+
0),
|
|
836
|
+
transcriptMessageCount: rollup.transcriptMessageCount,
|
|
837
|
+
realizedHoursSaved,
|
|
838
|
+
realizedValueUsd: realizedHoursSaved * 150,
|
|
839
|
+
pendingTaskCount: rollup.actionRequiredTaskCount + rollup.runningTaskCount,
|
|
840
|
+
auditReadyTaskCount: rollup.auditReadyTaskCount,
|
|
841
|
+
evidenceGapCount: rollup.evidenceGapCount,
|
|
842
|
+
delegatedFailedTaskCount: delegatedRollup.failedTaskCount,
|
|
843
|
+
delegatedPendingTaskCount: delegatedRollup.actionRequiredTaskCount +
|
|
844
|
+
delegatedRollup.runningTaskCount,
|
|
845
|
+
delegatedEvidenceGapCount: delegatedRollup.evidenceGapCount,
|
|
846
|
+
nextActions: summarizeMultiAgentNextActions(delegatedTasks, tasksPath),
|
|
847
|
+
topPeers: peerSummaries,
|
|
848
|
+
recentTasks: tasks
|
|
849
|
+
.slice()
|
|
850
|
+
.sort((left, right) => taskSortTimestamp(right) - taskSortTimestamp(left))
|
|
851
|
+
.slice(0, 5)
|
|
852
|
+
.map((task) => ({
|
|
853
|
+
id: sanitizeA2ALabel(task.taskId, 120),
|
|
854
|
+
peer: sanitizeA2ALabel(task.peer, 80),
|
|
855
|
+
...(task.peerDisplayName
|
|
856
|
+
? { peerDisplayName: sanitizeA2ALabel(task.peerDisplayName, 100) }
|
|
857
|
+
: {}),
|
|
858
|
+
state: sanitizeA2ALabel(task.state, 80),
|
|
859
|
+
status: a2aTaskStatus(task),
|
|
860
|
+
text: truncate(redactLine(task.text), 140),
|
|
861
|
+
updatedAt: task.updatedAt,
|
|
862
|
+
...(task.completedAt ? { completedAt: task.completedAt } : {}),
|
|
863
|
+
workGraph: Boolean(task.workGraph),
|
|
864
|
+
...(taskWorkGraphSummary(task)
|
|
865
|
+
? { workGraphSummary: taskWorkGraphSummary(task) }
|
|
866
|
+
: {}),
|
|
867
|
+
...(taskCodexSubagentsSummary(task)
|
|
868
|
+
? {
|
|
869
|
+
codexSubagents: taskCodexSubagentsSummary(task),
|
|
870
|
+
}
|
|
871
|
+
: {}),
|
|
872
|
+
...(task.responseText
|
|
873
|
+
? { responseText: truncate(redactLine(task.responseText), 180) }
|
|
874
|
+
: {}),
|
|
875
|
+
})),
|
|
876
|
+
collectionGaps,
|
|
877
|
+
};
|
|
878
|
+
}
|
|
879
|
+
function workGraphChildRunCount(graph) {
|
|
880
|
+
return Math.max(graph.childRunCount ?? 0, graph.childRunIds.length, graph.codexSubagents?.childRunIds.length ?? 0);
|
|
881
|
+
}
|
|
882
|
+
function taskWorkGraphSummary(task) {
|
|
883
|
+
const summary = formatA2AWorkGraphSummary(task.workGraph);
|
|
884
|
+
return summary ? sanitizeA2ALabel(summary, 320) : undefined;
|
|
885
|
+
}
|
|
886
|
+
function taskCodexSubagentsSummary(task) {
|
|
887
|
+
const summary = formatA2AWorkGraphCodexSubagents(task.workGraph);
|
|
888
|
+
return summary ? sanitizeA2ALabel(summary, 420) : undefined;
|
|
889
|
+
}
|
|
890
|
+
function summarizeMultiAgentPeers(tasks) {
|
|
891
|
+
const peers = new Map();
|
|
892
|
+
for (const task of tasks) {
|
|
893
|
+
const peer = sanitizeA2ALabel(task.peer, 80);
|
|
894
|
+
const displayName = task.peerDisplayName
|
|
895
|
+
? sanitizeA2ALabel(task.peerDisplayName, 100)
|
|
896
|
+
: undefined;
|
|
897
|
+
const current = peers.get(task.peer) ?? {
|
|
898
|
+
peer,
|
|
899
|
+
...(displayName ? { displayName } : {}),
|
|
900
|
+
taskCount: 0,
|
|
901
|
+
completedTaskCount: 0,
|
|
902
|
+
failedTaskCount: 0,
|
|
903
|
+
actionRequiredTaskCount: 0,
|
|
904
|
+
};
|
|
905
|
+
if (displayName && !current.displayName) {
|
|
906
|
+
current.displayName = displayName;
|
|
907
|
+
}
|
|
908
|
+
current.taskCount += 1;
|
|
909
|
+
const status = a2aTaskStatus(task);
|
|
910
|
+
if (status === "completed")
|
|
911
|
+
current.completedTaskCount += 1;
|
|
912
|
+
if (status === "failed")
|
|
913
|
+
current.failedTaskCount += 1;
|
|
914
|
+
if (status === "waiting")
|
|
915
|
+
current.actionRequiredTaskCount += 1;
|
|
916
|
+
peers.set(task.peer, current);
|
|
917
|
+
}
|
|
918
|
+
return [...peers.values()]
|
|
919
|
+
.sort((left, right) => right.taskCount - left.taskCount || left.peer.localeCompare(right.peer))
|
|
920
|
+
.slice(0, 5);
|
|
921
|
+
}
|
|
922
|
+
function summarizeMultiAgentNextActions(tasks, tasksPath) {
|
|
923
|
+
if (tasks.length === 0) {
|
|
924
|
+
return [];
|
|
925
|
+
}
|
|
926
|
+
const cockpit = summarizeA2ACockpit({
|
|
927
|
+
fleet: syntheticA2AFleetSummary(tasks, tasksPath),
|
|
928
|
+
ledger: { tasks },
|
|
929
|
+
limit: 5,
|
|
930
|
+
generatedAt: new Date(0).toISOString(),
|
|
931
|
+
});
|
|
932
|
+
return cockpit.nextActions
|
|
933
|
+
.filter((action) => Boolean(action.taskId))
|
|
934
|
+
.map((action) => ({
|
|
935
|
+
id: sanitizeA2ALabel(action.id, 160),
|
|
936
|
+
label: sanitizeA2ALabel(action.label, 180),
|
|
937
|
+
command: sanitizeA2ALabel(exportableMultiAgentCommand(action.command), 240),
|
|
938
|
+
severity: action.severity,
|
|
939
|
+
peer: sanitizeA2ALabel(action.peer, 80),
|
|
940
|
+
taskId: sanitizeA2ALabel(action.taskId, 120),
|
|
941
|
+
reason: sanitizeA2ALabel(action.reason, 240),
|
|
942
|
+
}));
|
|
943
|
+
}
|
|
944
|
+
function exportableMultiAgentCommand(command) {
|
|
945
|
+
return command.replace(/<response>/gu, "'RESPONSE_TEXT'");
|
|
946
|
+
}
|
|
947
|
+
async function buildCustomerValueWorkBoard(input) {
|
|
948
|
+
let tasks = [];
|
|
949
|
+
try {
|
|
950
|
+
const ledger = await loadA2ATaskLedger({ path: input.tasksPath });
|
|
951
|
+
tasks = ledger.tasks.filter((task) => task.kind === "delegation" && isA2ATaskInRange(task, input.range));
|
|
952
|
+
}
|
|
953
|
+
catch {
|
|
954
|
+
tasks = [];
|
|
955
|
+
}
|
|
956
|
+
const a2a = tasks.length > 0
|
|
957
|
+
? summarizeA2ACockpit({
|
|
958
|
+
fleet: syntheticA2AFleetSummary(tasks, input.tasksPath),
|
|
959
|
+
ledger: { tasks },
|
|
960
|
+
limit: 25,
|
|
961
|
+
generatedAt: new Date(input.now).toISOString(),
|
|
962
|
+
})
|
|
963
|
+
: undefined;
|
|
964
|
+
const todos = sanitizeTodoStoreForWorkBoard(input.todos);
|
|
965
|
+
const [missions, githubTasks] = await Promise.all([
|
|
966
|
+
input.missions
|
|
967
|
+
? Promise.resolve(input.missions)
|
|
968
|
+
: collectMissionManifests(input.workspaceDir),
|
|
969
|
+
input.githubTasks
|
|
970
|
+
? Promise.resolve(input.githubTasks)
|
|
971
|
+
: collectGitHubAgentWork(input.workspaceDir),
|
|
972
|
+
]);
|
|
973
|
+
return redactAgentWorkBoard(buildAgentWorkBoard({
|
|
974
|
+
missions,
|
|
975
|
+
missionSnapshots: missionStoreSnapshotsForWorkspace(listMissionStoreSnapshots(input.missionStoreDir ?? undefined), missions, input.workspaceDir, input.missionStoreDir ?? undefined),
|
|
976
|
+
a2a,
|
|
977
|
+
todos,
|
|
978
|
+
handoffs: input.handoffs,
|
|
979
|
+
openWork: hasOpenTodoItems(todos) ? [] : input.openWork,
|
|
980
|
+
githubTasks,
|
|
981
|
+
}, new Date(input.now)));
|
|
982
|
+
}
|
|
983
|
+
function missionStoreSnapshotsForWorkspace(snapshots, missions, workspaceDir, missionStoreDir) {
|
|
984
|
+
const workspaceMissionIds = new Set();
|
|
985
|
+
for (const mission of missions) {
|
|
986
|
+
workspaceMissionIds.add(mission.missionId);
|
|
987
|
+
try {
|
|
988
|
+
workspaceMissionIds.add(sanitizeMissionId(mission.missionId));
|
|
989
|
+
}
|
|
990
|
+
catch {
|
|
991
|
+
// Ignore malformed mission ids from workspace manifests.
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
if (workspaceMissionIds.size > 0) {
|
|
995
|
+
return snapshots.filter((snapshot) => {
|
|
996
|
+
const isWorkspaceOwned = isMissionStoreSnapshotOwnedByWorkspace(snapshot, workspaceDir, missionStoreDir);
|
|
997
|
+
return ((isWorkspaceOwned || !missionStoreDir) &&
|
|
998
|
+
(workspaceMissionIds.has(snapshot.missionId) ||
|
|
999
|
+
(snapshot.sourceMissionId
|
|
1000
|
+
? workspaceMissionIds.has(snapshot.sourceMissionId)
|
|
1001
|
+
: false)));
|
|
1002
|
+
});
|
|
1003
|
+
}
|
|
1004
|
+
const workspaceOwnedSnapshots = snapshots.filter((snapshot) => isMissionStoreSnapshotOwnedByWorkspace(snapshot, workspaceDir, missionStoreDir));
|
|
1005
|
+
if (workspaceOwnedSnapshots.length > 0)
|
|
1006
|
+
return workspaceOwnedSnapshots;
|
|
1007
|
+
return missionStoreDir ? [] : [...snapshots];
|
|
1008
|
+
}
|
|
1009
|
+
function isMissionStoreSnapshotOwnedByWorkspace(snapshot, workspaceDir, missionStoreDir) {
|
|
1010
|
+
const workspaceRoot = realPathIfExists(workspaceDir);
|
|
1011
|
+
const missionDir = realPathIfExists(getMissionDir(snapshot.missionId, missionStoreDir));
|
|
1012
|
+
const rel = relative(workspaceRoot, missionDir);
|
|
1013
|
+
return Boolean(rel) && !isParentDirectoryRelPath(rel) && !isAbsolute(rel);
|
|
1014
|
+
}
|
|
1015
|
+
function realPathIfExists(path) {
|
|
1016
|
+
const absolute = resolve(path);
|
|
1017
|
+
return existsSync(absolute) ? realpathSync(absolute) : absolute;
|
|
1018
|
+
}
|
|
1019
|
+
function isParentDirectoryRelPath(relPath) {
|
|
1020
|
+
return relPath === ".." || relPath.startsWith(`..${sep}`);
|
|
1021
|
+
}
|
|
1022
|
+
function sanitizeTodoStoreForWorkBoard(store) {
|
|
1023
|
+
const sanitized = {};
|
|
1024
|
+
for (const [key, goal] of Object.entries(store ?? {})) {
|
|
1025
|
+
if (!goal ||
|
|
1026
|
+
typeof goal !== "object" ||
|
|
1027
|
+
typeof goal.goal !== "string" ||
|
|
1028
|
+
typeof goal.updatedAt !== "string" ||
|
|
1029
|
+
!Array.isArray(goal.items)) {
|
|
1030
|
+
continue;
|
|
1031
|
+
}
|
|
1032
|
+
const items = goal.items
|
|
1033
|
+
.filter((item) => item &&
|
|
1034
|
+
typeof item === "object" &&
|
|
1035
|
+
typeof item.id === "string" &&
|
|
1036
|
+
typeof item.content === "string" &&
|
|
1037
|
+
typeof item.status === "string" &&
|
|
1038
|
+
isTodoStoreStatus(item.status) &&
|
|
1039
|
+
typeof item.priority === "string" &&
|
|
1040
|
+
isOpenTodoPriority(item.priority))
|
|
1041
|
+
.map((item) => ({
|
|
1042
|
+
id: item.id,
|
|
1043
|
+
content: compactHandoffText(item.content),
|
|
1044
|
+
status: item.status,
|
|
1045
|
+
priority: item.priority,
|
|
1046
|
+
...(Array.isArray(item.blockedBy)
|
|
1047
|
+
? {
|
|
1048
|
+
blockedBy: item.blockedBy
|
|
1049
|
+
.filter((blockedBy) => typeof blockedBy === "string")
|
|
1050
|
+
.map(compactHandoffText),
|
|
1051
|
+
}
|
|
1052
|
+
: {}),
|
|
1053
|
+
}));
|
|
1054
|
+
if (items.length > 0) {
|
|
1055
|
+
sanitized[key] = {
|
|
1056
|
+
goal: compactHandoffText(goal.goal),
|
|
1057
|
+
updatedAt: goal.updatedAt,
|
|
1058
|
+
items,
|
|
1059
|
+
};
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
return Object.keys(sanitized).length > 0 ? sanitized : undefined;
|
|
1063
|
+
}
|
|
1064
|
+
function hasOpenTodoItems(todos) {
|
|
1065
|
+
return Object.values(todos ?? {}).some((goal) => Array.isArray(goal?.items)
|
|
1066
|
+
? goal.items.some((item) => item.status !== "completed")
|
|
1067
|
+
: false);
|
|
1068
|
+
}
|
|
1069
|
+
function redactAgentWorkBoard(board) {
|
|
1070
|
+
return {
|
|
1071
|
+
...board,
|
|
1072
|
+
items: board.items.map((item) => ({
|
|
1073
|
+
...item,
|
|
1074
|
+
id: redactLine(item.id),
|
|
1075
|
+
title: redactLine(item.title),
|
|
1076
|
+
...(item.owner ? { owner: redactLine(item.owner) } : {}),
|
|
1077
|
+
blockers: item.blockers.map(redactLine),
|
|
1078
|
+
nextAction: item.nextAction
|
|
1079
|
+
? {
|
|
1080
|
+
label: redactLine(item.nextAction.label),
|
|
1081
|
+
...(item.nextAction.command
|
|
1082
|
+
? { command: redactLine(item.nextAction.command) }
|
|
1083
|
+
: {}),
|
|
1084
|
+
}
|
|
1085
|
+
: undefined,
|
|
1086
|
+
evidence: item.evidence.map((evidence) => ({
|
|
1087
|
+
...evidence,
|
|
1088
|
+
label: redactLine(evidence.label),
|
|
1089
|
+
...(evidence.path ? { path: redactLine(evidence.path) } : {}),
|
|
1090
|
+
...(evidence.url ? { url: redactLine(evidence.url) } : {}),
|
|
1091
|
+
})),
|
|
1092
|
+
})),
|
|
1093
|
+
};
|
|
1094
|
+
}
|
|
1095
|
+
function syntheticA2AFleetSummary(tasks, tasksPath) {
|
|
1096
|
+
const peers = [...new Map(tasks.map((task) => [task.peer, task])).values()]
|
|
1097
|
+
.sort((left, right) => left.peer.localeCompare(right.peer))
|
|
1098
|
+
.map((task) => ({
|
|
1099
|
+
name: task.peer,
|
|
1100
|
+
...(task.peerDisplayName ? { displayName: task.peerDisplayName } : {}),
|
|
1101
|
+
url: `ledger://${task.peer}`,
|
|
1102
|
+
status: "online",
|
|
1103
|
+
}));
|
|
1104
|
+
return {
|
|
1105
|
+
generatedAt: new Date(0).toISOString(),
|
|
1106
|
+
registryPath: "local A2A task ledger",
|
|
1107
|
+
tasksPath,
|
|
1108
|
+
peers,
|
|
1109
|
+
};
|
|
1110
|
+
}
|
|
1111
|
+
function isA2ATaskInRange(task, range) {
|
|
1112
|
+
if (["failed", "waiting", "running"].includes(a2aTaskStatus(task))) {
|
|
1113
|
+
return true;
|
|
1114
|
+
}
|
|
1115
|
+
if (range.since === undefined && range.until === undefined)
|
|
1116
|
+
return true;
|
|
1117
|
+
const activeRange = getA2ATaskActiveRange(task);
|
|
1118
|
+
if (!activeRange) {
|
|
1119
|
+
return false;
|
|
1120
|
+
}
|
|
1121
|
+
if (range.until !== undefined && activeRange.start >= range.until) {
|
|
1122
|
+
return false;
|
|
1123
|
+
}
|
|
1124
|
+
if (range.since !== undefined && activeRange.end < range.since) {
|
|
1125
|
+
return false;
|
|
1126
|
+
}
|
|
1127
|
+
return true;
|
|
1128
|
+
}
|
|
1129
|
+
function getA2ATaskActiveRange(task) {
|
|
1130
|
+
const timestamps = [
|
|
1131
|
+
parseTimestampMs(task.createdAt),
|
|
1132
|
+
parseTimestampMs(task.updatedAt),
|
|
1133
|
+
parseTimestampMs(task.completedAt),
|
|
1134
|
+
].filter((timestamp) => timestamp !== undefined);
|
|
1135
|
+
if (timestamps.length === 0) {
|
|
1136
|
+
return undefined;
|
|
1137
|
+
}
|
|
1138
|
+
const start = Math.min(...timestamps);
|
|
1139
|
+
if (!isFinalA2AState(task.state)) {
|
|
1140
|
+
return { start, end: Number.POSITIVE_INFINITY };
|
|
1141
|
+
}
|
|
1142
|
+
return { start, end: Math.max(...timestamps) };
|
|
1143
|
+
}
|
|
1144
|
+
function taskSortTimestamp(task) {
|
|
1145
|
+
return (parseTimestampMs(task.completedAt) ??
|
|
1146
|
+
parseTimestampMs(task.updatedAt) ??
|
|
1147
|
+
parseTimestampMs(task.createdAt) ??
|
|
1148
|
+
0);
|
|
1149
|
+
}
|
|
1150
|
+
function a2aTaskStatus(task) {
|
|
1151
|
+
return classifyTaskState(task.state);
|
|
1152
|
+
}
|
|
1153
|
+
function multiAgentDecisionLine(multiAgent) {
|
|
1154
|
+
const nextAction = multiAgent.nextActions[0];
|
|
1155
|
+
if (nextAction) {
|
|
1156
|
+
return `${nextAction.label} (${nextAction.command})`;
|
|
1157
|
+
}
|
|
1158
|
+
if (multiAgent.delegatedFailedTaskCount > 0) {
|
|
1159
|
+
return "Refresh or inspect failed delegated work before claiming value.";
|
|
1160
|
+
}
|
|
1161
|
+
if (multiAgent.delegatedPendingTaskCount > 0) {
|
|
1162
|
+
return "Wait for running delegated work before counting realized value.";
|
|
1163
|
+
}
|
|
1164
|
+
if (multiAgent.delegatedEvidenceGapCount > 0) {
|
|
1165
|
+
return multiAgent.auditReadyTaskCount > 0
|
|
1166
|
+
? "Some delegated work is audit-ready, but evidence gaps remain to close."
|
|
1167
|
+
: "Completed delegated work is missing audit evidence; collect work graphs, responses, or transcripts before claiming value.";
|
|
1168
|
+
}
|
|
1169
|
+
if (multiAgent.realizedHoursSaved <= 0) {
|
|
1170
|
+
return "No completed delegated work found; delegate and complete A2A work before claiming realized multi-agent value.";
|
|
1171
|
+
}
|
|
1172
|
+
return "No action required; completed delegated work is ready for audit.";
|
|
1173
|
+
}
|
|
1174
|
+
function summarizeCustomerValue(params) {
|
|
1175
|
+
const messageCount = sum(params.trustCards, (card) => card.messageCount);
|
|
1176
|
+
const assistantTurnCount = sum(params.trustCards, (card) => card.assistantTurnCount);
|
|
1177
|
+
const toolCallCount = sum(params.trustCards, (card) => card.toolCallCount);
|
|
1178
|
+
const failedToolResultCount = sum(params.trustCards, (card) => card.failedToolResultCount);
|
|
1179
|
+
const estimatedHoursSaved = estimateHoursSaved({
|
|
1180
|
+
assistantTurnCount,
|
|
1181
|
+
toolCallCount,
|
|
1182
|
+
});
|
|
1183
|
+
const usageRequests = sum(params.trustCards, (card) => card.usage.requests);
|
|
1184
|
+
const totalTokens = sum(params.trustCards, (card) => card.usage.tokens);
|
|
1185
|
+
const totalCostUsd = sum(params.trustCards, (card) => card.usage.costUsd);
|
|
1186
|
+
const multiAgentEstimatedHoursSaved = params.multiAgent.realizedHoursSaved;
|
|
1187
|
+
const totalEstimatedHoursSaved = estimatedHoursSaved + multiAgentEstimatedHoursSaved;
|
|
1188
|
+
const totalEstimatedValueUsd = totalEstimatedHoursSaved * 150;
|
|
1189
|
+
return {
|
|
1190
|
+
sessionCount: params.trustCards.length,
|
|
1191
|
+
trustCardCount: params.trustCards.length,
|
|
1192
|
+
messageCount,
|
|
1193
|
+
assistantTurnCount,
|
|
1194
|
+
toolCallCount,
|
|
1195
|
+
failedToolResultCount,
|
|
1196
|
+
usageRequests,
|
|
1197
|
+
totalTokens,
|
|
1198
|
+
totalCostUsd,
|
|
1199
|
+
estimatedHoursSaved: totalEstimatedHoursSaved,
|
|
1200
|
+
estimatedValueUsd: totalEstimatedValueUsd,
|
|
1201
|
+
valueMultiple: totalCostUsd > 0 ? totalEstimatedValueUsd / totalCostUsd : null,
|
|
1202
|
+
memoryBackedSessionCount: params.trustCards.filter((card) => card.evidence.hasMemoryProvenance).length,
|
|
1203
|
+
multiAgentEstimatedHoursSaved,
|
|
1204
|
+
multiAgentEstimatedValueUsd: multiAgentEstimatedHoursSaved * 150,
|
|
1205
|
+
multiAgentTaskCount: params.multiAgent.taskCount,
|
|
1206
|
+
multiAgentPeerCount: params.multiAgent.peerCount,
|
|
1207
|
+
multiAgentWorkGraphTaskCount: params.multiAgent.workGraphTaskCount,
|
|
1208
|
+
multiAgentChildRunCount: params.multiAgent.workGraphChildRunCount,
|
|
1209
|
+
ambientAutomationOpportunityCount: params.ambient.automationOpportunities.length,
|
|
1210
|
+
playbookLearningOpportunityCount: params.ambient.playbookLearningOpportunities.length,
|
|
1211
|
+
ambientLearnerOutcomeCount: params.ambient.outcomeCount,
|
|
1212
|
+
ambientProtectedTransientFailureCount: params.ambient.protectedTransientFailureCount,
|
|
1213
|
+
};
|
|
1214
|
+
}
|
|
1215
|
+
function buildCustomerValueHandoffs(trustCards, todoStore) {
|
|
1216
|
+
const sessions = trustCards.map(buildSessionHandoff);
|
|
1217
|
+
const openWork = collectOpenTodoWork(todoStore);
|
|
1218
|
+
return {
|
|
1219
|
+
deliveredCount: sessions.filter((handoff) => handoff.status === "delivered")
|
|
1220
|
+
.length,
|
|
1221
|
+
followupCount: sessions.filter((handoff) => handoff.status === "needs-followup").length,
|
|
1222
|
+
blockedCount: sessions.filter((handoff) => handoff.status === "blocked")
|
|
1223
|
+
.length,
|
|
1224
|
+
openWorkCount: openWork.length,
|
|
1225
|
+
sessions,
|
|
1226
|
+
openWork,
|
|
1227
|
+
};
|
|
1228
|
+
}
|
|
1229
|
+
async function loadCustomerValueTodoStore() {
|
|
1230
|
+
try {
|
|
1231
|
+
return sanitizeCustomerValueTodoStore(await loadStore());
|
|
1232
|
+
}
|
|
1233
|
+
catch {
|
|
1234
|
+
return {};
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
function buildSessionHandoff(card) {
|
|
1238
|
+
const blockers = card.riskSignals.filter((signal) => signal.includes("failed") ||
|
|
1239
|
+
signal.includes("no durable memory") ||
|
|
1240
|
+
signal.includes("no tool evidence"));
|
|
1241
|
+
const status = card.failedToolResultCount > 0
|
|
1242
|
+
? "blocked"
|
|
1243
|
+
: card.riskSignals.length > 0
|
|
1244
|
+
? "needs-followup"
|
|
1245
|
+
: "delivered";
|
|
1246
|
+
const unfinished = card.riskSignals.length > 0
|
|
1247
|
+
? card.riskSignals.join("; ")
|
|
1248
|
+
: card.evidence.hasMemoryProvenance
|
|
1249
|
+
? undefined
|
|
1250
|
+
: "No durable memory provenance was captured for this session.";
|
|
1251
|
+
return {
|
|
1252
|
+
sessionId: card.sessionId,
|
|
1253
|
+
title: card.title,
|
|
1254
|
+
status,
|
|
1255
|
+
delivered: compactHandoffText(card.summary ||
|
|
1256
|
+
card.task ||
|
|
1257
|
+
card.customerSignals.join("; ") ||
|
|
1258
|
+
card.title),
|
|
1259
|
+
...(unfinished ? { unfinished: compactHandoffText(unfinished) } : {}),
|
|
1260
|
+
blockers,
|
|
1261
|
+
nextAction: nextHandoffAction(card, status),
|
|
1262
|
+
evidence: {
|
|
1263
|
+
sessionPath: card.evidence.sessionPath,
|
|
1264
|
+
updatedAt: card.updatedAt,
|
|
1265
|
+
summaryStored: card.evidence.hasSummary,
|
|
1266
|
+
memoryBacked: card.evidence.hasMemoryProvenance,
|
|
1267
|
+
},
|
|
1268
|
+
};
|
|
1269
|
+
}
|
|
1270
|
+
function collectOpenTodoWork(store) {
|
|
1271
|
+
const items = [];
|
|
1272
|
+
for (const goal of Object.values(store)) {
|
|
1273
|
+
for (const item of goal.items) {
|
|
1274
|
+
if (!isOpenTodoStatus(item.status)) {
|
|
1275
|
+
continue;
|
|
1276
|
+
}
|
|
1277
|
+
items.push({
|
|
1278
|
+
goal: compactHandoffText(goal.goal),
|
|
1279
|
+
id: item.id,
|
|
1280
|
+
content: compactHandoffText(item.content),
|
|
1281
|
+
status: item.status,
|
|
1282
|
+
priority: item.priority,
|
|
1283
|
+
updatedAt: goal.updatedAt,
|
|
1284
|
+
blockers: item.blockedBy?.map(compactHandoffText) ?? [],
|
|
1285
|
+
});
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
return items.sort(compareOpenWorkItems);
|
|
1289
|
+
}
|
|
1290
|
+
function sanitizeCustomerValueTodoStore(store) {
|
|
1291
|
+
const sanitized = {};
|
|
1292
|
+
for (const [goalKey, goal] of Object.entries(store)) {
|
|
1293
|
+
if (!goal ||
|
|
1294
|
+
typeof goal !== "object" ||
|
|
1295
|
+
typeof goal.goal !== "string" ||
|
|
1296
|
+
typeof goal.updatedAt !== "string" ||
|
|
1297
|
+
!Array.isArray(goal.items)) {
|
|
1298
|
+
continue;
|
|
1299
|
+
}
|
|
1300
|
+
sanitized[goalKey] = {
|
|
1301
|
+
goal: goal.goal,
|
|
1302
|
+
updatedAt: goal.updatedAt,
|
|
1303
|
+
items: goal.items.flatMap((item) => {
|
|
1304
|
+
if (!item ||
|
|
1305
|
+
typeof item !== "object" ||
|
|
1306
|
+
typeof item.id !== "string" ||
|
|
1307
|
+
typeof item.content !== "string" ||
|
|
1308
|
+
typeof item.status !== "string" ||
|
|
1309
|
+
!isTodoStoreStatus(item.status) ||
|
|
1310
|
+
typeof item.priority !== "string" ||
|
|
1311
|
+
!isOpenTodoPriority(item.priority)) {
|
|
1312
|
+
return [];
|
|
1313
|
+
}
|
|
1314
|
+
const blockedBy = Array.isArray(item.blockedBy)
|
|
1315
|
+
? item.blockedBy.filter((blocker) => typeof blocker === "string")
|
|
1316
|
+
: undefined;
|
|
1317
|
+
return [
|
|
1318
|
+
{
|
|
1319
|
+
id: item.id,
|
|
1320
|
+
content: item.content,
|
|
1321
|
+
status: item.status,
|
|
1322
|
+
priority: item.priority,
|
|
1323
|
+
...(typeof item.notes === "string" ? { notes: item.notes } : {}),
|
|
1324
|
+
...(typeof item.due === "string" ? { due: item.due } : {}),
|
|
1325
|
+
...(blockedBy ? { blockedBy } : {}),
|
|
1326
|
+
},
|
|
1327
|
+
];
|
|
1328
|
+
}),
|
|
1329
|
+
};
|
|
1330
|
+
}
|
|
1331
|
+
return sanitized;
|
|
1332
|
+
}
|
|
1333
|
+
async function collectMissionManifests(workspaceDir) {
|
|
1334
|
+
const parsed = await readJsonFileIfExists(join(workspaceDir, "features.json"));
|
|
1335
|
+
return isMissionManifest(parsed) ? [parsed] : [];
|
|
1336
|
+
}
|
|
1337
|
+
function isMissionManifest(value) {
|
|
1338
|
+
if (!value || typeof value !== "object") {
|
|
1339
|
+
return false;
|
|
1340
|
+
}
|
|
1341
|
+
const manifest = value;
|
|
1342
|
+
return (typeof manifest.version === "number" &&
|
|
1343
|
+
typeof manifest.missionId === "string" &&
|
|
1344
|
+
Array.isArray(manifest.milestones) &&
|
|
1345
|
+
Array.isArray(manifest.features) &&
|
|
1346
|
+
typeof manifest.createdAt === "string" &&
|
|
1347
|
+
typeof manifest.updatedAt === "string" &&
|
|
1348
|
+
manifest.milestones.every(isMissionMilestone) &&
|
|
1349
|
+
manifest.features.every(isMissionFeature));
|
|
1350
|
+
}
|
|
1351
|
+
function isMissionMilestone(value) {
|
|
1352
|
+
if (!value || typeof value !== "object") {
|
|
1353
|
+
return false;
|
|
1354
|
+
}
|
|
1355
|
+
const milestone = value;
|
|
1356
|
+
return typeof milestone.id === "string" && typeof milestone.name === "string";
|
|
1357
|
+
}
|
|
1358
|
+
function isMissionFeature(value) {
|
|
1359
|
+
if (!value || typeof value !== "object") {
|
|
1360
|
+
return false;
|
|
1361
|
+
}
|
|
1362
|
+
const feature = value;
|
|
1363
|
+
return (typeof feature.id === "string" &&
|
|
1364
|
+
typeof feature.description === "string" &&
|
|
1365
|
+
typeof feature.status === "string" &&
|
|
1366
|
+
isMissionFeatureStatus(feature.status) &&
|
|
1367
|
+
Array.isArray(feature.fulfills) &&
|
|
1368
|
+
feature.fulfills.every((item) => typeof item === "string") &&
|
|
1369
|
+
optionalString(feature.milestone) &&
|
|
1370
|
+
optionalString(feature.skillName) &&
|
|
1371
|
+
optionalString(feature.handoffSourceFeatureId) &&
|
|
1372
|
+
optionalMissionHandoffItemKind(feature.handoffFollowUpKind) &&
|
|
1373
|
+
optionalString(feature.handoffItemKey) &&
|
|
1374
|
+
(feature.handoff === undefined ||
|
|
1375
|
+
isMissionWorkerHandoff(feature.handoff)) &&
|
|
1376
|
+
(feature.handoffDismissals === undefined ||
|
|
1377
|
+
(Array.isArray(feature.handoffDismissals) &&
|
|
1378
|
+
feature.handoffDismissals.every(isMissionHandoffDismissal))) &&
|
|
1379
|
+
(feature.trackedHandoffItems === undefined ||
|
|
1380
|
+
(Array.isArray(feature.trackedHandoffItems) &&
|
|
1381
|
+
feature.trackedHandoffItems.every(isMissionTrackedHandoffItem))));
|
|
1382
|
+
}
|
|
1383
|
+
function isMissionFeatureStatus(value) {
|
|
1384
|
+
return (value === "pending" ||
|
|
1385
|
+
value === "in-progress" ||
|
|
1386
|
+
value === "passed" ||
|
|
1387
|
+
value === "failed" ||
|
|
1388
|
+
value === "preempted");
|
|
1389
|
+
}
|
|
1390
|
+
function isMissionWorkerHandoff(value) {
|
|
1391
|
+
if (!value || typeof value !== "object") {
|
|
1392
|
+
return false;
|
|
1393
|
+
}
|
|
1394
|
+
const handoff = value;
|
|
1395
|
+
return (typeof handoff.workerId === "string" &&
|
|
1396
|
+
typeof handoff.success === "boolean" &&
|
|
1397
|
+
typeof handoff.handedOffAt === "string" &&
|
|
1398
|
+
optionalString(handoff.repoPath) &&
|
|
1399
|
+
optionalString(handoff.commitId) &&
|
|
1400
|
+
optionalString(handoff.summary) &&
|
|
1401
|
+
optionalString(handoff.whatWasImplemented) &&
|
|
1402
|
+
optionalString(handoff.whatWasLeftUndone) &&
|
|
1403
|
+
(handoff.discoveredIssues === undefined ||
|
|
1404
|
+
(Array.isArray(handoff.discoveredIssues) &&
|
|
1405
|
+
handoff.discoveredIssues.every(isMissionDiscoveredIssue))) &&
|
|
1406
|
+
(handoff.verification === undefined ||
|
|
1407
|
+
isMissionVerification(handoff.verification)));
|
|
1408
|
+
}
|
|
1409
|
+
function isMissionDiscoveredIssue(value) {
|
|
1410
|
+
if (!value || typeof value !== "object") {
|
|
1411
|
+
return false;
|
|
1412
|
+
}
|
|
1413
|
+
const issue = value;
|
|
1414
|
+
return ((issue.severity === "blocking" || issue.severity === "non_blocking") &&
|
|
1415
|
+
typeof issue.description === "string" &&
|
|
1416
|
+
optionalString(issue.suggestedFix));
|
|
1417
|
+
}
|
|
1418
|
+
function isMissionVerification(value) {
|
|
1419
|
+
if (!value || typeof value !== "object") {
|
|
1420
|
+
return false;
|
|
1421
|
+
}
|
|
1422
|
+
const verification = value;
|
|
1423
|
+
return (verification.commandsRun === undefined ||
|
|
1424
|
+
(Array.isArray(verification.commandsRun) &&
|
|
1425
|
+
verification.commandsRun.every(isMissionVerificationCommand)));
|
|
1426
|
+
}
|
|
1427
|
+
function isMissionVerificationCommand(value) {
|
|
1428
|
+
if (!value || typeof value !== "object") {
|
|
1429
|
+
return false;
|
|
1430
|
+
}
|
|
1431
|
+
const command = value;
|
|
1432
|
+
return (typeof command.command === "string" &&
|
|
1433
|
+
(command.exitCode === undefined || typeof command.exitCode === "number") &&
|
|
1434
|
+
optionalString(command.observation));
|
|
1435
|
+
}
|
|
1436
|
+
function isMissionHandoffDismissal(value) {
|
|
1437
|
+
if (!value || typeof value !== "object") {
|
|
1438
|
+
return false;
|
|
1439
|
+
}
|
|
1440
|
+
const dismissal = value;
|
|
1441
|
+
return (isMissionHandoffItemKind(dismissal.kind) &&
|
|
1442
|
+
typeof dismissal.key === "string" &&
|
|
1443
|
+
typeof dismissal.justification === "string" &&
|
|
1444
|
+
typeof dismissal.dismissedAt === "string");
|
|
1445
|
+
}
|
|
1446
|
+
function isMissionTrackedHandoffItem(value) {
|
|
1447
|
+
if (!value || typeof value !== "object") {
|
|
1448
|
+
return false;
|
|
1449
|
+
}
|
|
1450
|
+
const tracked = value;
|
|
1451
|
+
return (typeof tracked.sourceFeatureId === "string" &&
|
|
1452
|
+
isMissionHandoffItemKind(tracked.kind) &&
|
|
1453
|
+
typeof tracked.key === "string" &&
|
|
1454
|
+
typeof tracked.trackedAt === "string" &&
|
|
1455
|
+
optionalString(tracked.note));
|
|
1456
|
+
}
|
|
1457
|
+
function isMissionHandoffItemKind(value) {
|
|
1458
|
+
return value === "unfinished_work" || value === "discovered_issue";
|
|
1459
|
+
}
|
|
1460
|
+
function optionalMissionHandoffItemKind(value) {
|
|
1461
|
+
return value === undefined || isMissionHandoffItemKind(value);
|
|
1462
|
+
}
|
|
1463
|
+
function optionalString(value) {
|
|
1464
|
+
return value === undefined || typeof value === "string";
|
|
1465
|
+
}
|
|
1466
|
+
async function collectGitHubAgentWork(workspaceDir) {
|
|
1467
|
+
const memoryDir = join(workspaceDir, "memory");
|
|
1468
|
+
const [tasksJson, outcomesJson] = await Promise.all([
|
|
1469
|
+
readJsonFileIfExists(join(memoryDir, "tasks.json")),
|
|
1470
|
+
readJsonFileIfExists(join(memoryDir, "outcomes.json")),
|
|
1471
|
+
]);
|
|
1472
|
+
if (!tasksJson || typeof tasksJson !== "object") {
|
|
1473
|
+
return [];
|
|
1474
|
+
}
|
|
1475
|
+
const outcomes = outcomesJson && typeof outcomesJson === "object"
|
|
1476
|
+
? outcomesJson
|
|
1477
|
+
: {};
|
|
1478
|
+
return Object.entries(tasksJson)
|
|
1479
|
+
.map(([taskKey, task]) => projectGitHubAgentTask(taskKey, task, outcomes[taskKey]))
|
|
1480
|
+
.filter((task) => task !== undefined)
|
|
1481
|
+
.sort((left, right) => Date.parse(right.updatedAt ?? "") - Date.parse(left.updatedAt ?? "") ||
|
|
1482
|
+
left.id.localeCompare(right.id));
|
|
1483
|
+
}
|
|
1484
|
+
function projectGitHubAgentTask(taskKey, task, outcome) {
|
|
1485
|
+
if (!task || typeof task !== "object") {
|
|
1486
|
+
return undefined;
|
|
1487
|
+
}
|
|
1488
|
+
const taskRecord = task;
|
|
1489
|
+
if (typeof taskRecord.title !== "string" || !taskRecord.title.trim()) {
|
|
1490
|
+
return undefined;
|
|
1491
|
+
}
|
|
1492
|
+
const result = taskRecord.result && typeof taskRecord.result === "object"
|
|
1493
|
+
? taskRecord.result
|
|
1494
|
+
: undefined;
|
|
1495
|
+
const projectedStatus = projectGitHubAgentStatus(taskRecord, result, outcome);
|
|
1496
|
+
if (!projectedStatus) {
|
|
1497
|
+
return undefined;
|
|
1498
|
+
}
|
|
1499
|
+
const prUrl = typeof result?.prUrl === "string" && result.prUrl.trim()
|
|
1500
|
+
? result.prUrl
|
|
1501
|
+
: undefined;
|
|
1502
|
+
const branch = typeof result?.branch === "string" && result.branch.trim()
|
|
1503
|
+
? result.branch
|
|
1504
|
+
: undefined;
|
|
1505
|
+
const updatedAt = firstNonEmptyString(typeof outcome?.updatedAt === "string"
|
|
1506
|
+
? outcome.updatedAt
|
|
1507
|
+
: undefined, typeof taskRecord.lastAttemptAt === "string"
|
|
1508
|
+
? taskRecord.lastAttemptAt
|
|
1509
|
+
: undefined, typeof taskRecord.createdAt === "string" ? taskRecord.createdAt : undefined);
|
|
1510
|
+
const error = typeof result?.error === "string" && result.error.trim()
|
|
1511
|
+
? result.error
|
|
1512
|
+
: undefined;
|
|
1513
|
+
return {
|
|
1514
|
+
id: typeof taskRecord.id === "string" && taskRecord.id.trim()
|
|
1515
|
+
? taskRecord.id
|
|
1516
|
+
: taskKey,
|
|
1517
|
+
title: taskRecord.title,
|
|
1518
|
+
status: projectedStatus,
|
|
1519
|
+
...(branch ? { branch } : {}),
|
|
1520
|
+
...(prUrl ? { prUrl } : {}),
|
|
1521
|
+
...(updatedAt ? { updatedAt } : {}),
|
|
1522
|
+
...(error ? { error } : {}),
|
|
1523
|
+
};
|
|
1524
|
+
}
|
|
1525
|
+
function projectGitHubAgentStatus(task, result, outcome) {
|
|
1526
|
+
const outcomeStatus = outcome && typeof outcome === "object" && "status" in outcome
|
|
1527
|
+
? outcome.status
|
|
1528
|
+
: undefined;
|
|
1529
|
+
if (outcomeStatus === "merged") {
|
|
1530
|
+
return "completed";
|
|
1531
|
+
}
|
|
1532
|
+
if (outcomeStatus === "changes_requested") {
|
|
1533
|
+
return "blocked";
|
|
1534
|
+
}
|
|
1535
|
+
if (outcomeStatus === "pending") {
|
|
1536
|
+
return "waiting";
|
|
1537
|
+
}
|
|
1538
|
+
if (outcomeStatus === "closed") {
|
|
1539
|
+
return "failed";
|
|
1540
|
+
}
|
|
1541
|
+
if (task.status === "pending") {
|
|
1542
|
+
return "pending";
|
|
1543
|
+
}
|
|
1544
|
+
if (task.status === "in_progress") {
|
|
1545
|
+
return "running";
|
|
1546
|
+
}
|
|
1547
|
+
if (task.status === "failed") {
|
|
1548
|
+
return "failed";
|
|
1549
|
+
}
|
|
1550
|
+
if (task.status === "completed") {
|
|
1551
|
+
if (result?.prUrl && typeof result.prUrl === "string") {
|
|
1552
|
+
return "waiting";
|
|
1553
|
+
}
|
|
1554
|
+
if (result?.success === false) {
|
|
1555
|
+
return "failed";
|
|
1556
|
+
}
|
|
1557
|
+
return "completed";
|
|
1558
|
+
}
|
|
1559
|
+
return undefined;
|
|
1560
|
+
}
|
|
1561
|
+
async function readJsonFileIfExists(path) {
|
|
1562
|
+
try {
|
|
1563
|
+
return JSON.parse(await readFile(path, "utf8"));
|
|
1564
|
+
}
|
|
1565
|
+
catch {
|
|
1566
|
+
return undefined;
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
function firstNonEmptyString(...values) {
|
|
1570
|
+
return values.find((value) => typeof value === "string" && value.trim());
|
|
1571
|
+
}
|
|
1572
|
+
function isOpenTodoStatus(status) {
|
|
1573
|
+
return status === "pending" || status === "in_progress";
|
|
1574
|
+
}
|
|
1575
|
+
function isTodoStoreStatus(status) {
|
|
1576
|
+
return (status === "pending" || status === "in_progress" || status === "completed");
|
|
1577
|
+
}
|
|
1578
|
+
function isOpenTodoPriority(priority) {
|
|
1579
|
+
return priority === "high" || priority === "medium" || priority === "low";
|
|
1580
|
+
}
|
|
1581
|
+
function compareOpenWorkItems(left, right) {
|
|
1582
|
+
const statusOrder = { in_progress: 0, pending: 1 };
|
|
1583
|
+
const priorityOrder = { high: 0, medium: 1, low: 2 };
|
|
1584
|
+
return (statusOrder[left.status] - statusOrder[right.status] ||
|
|
1585
|
+
priorityOrder[left.priority] - priorityOrder[right.priority] ||
|
|
1586
|
+
Date.parse(right.updatedAt) - Date.parse(left.updatedAt) ||
|
|
1587
|
+
left.content.localeCompare(right.content));
|
|
1588
|
+
}
|
|
1589
|
+
function nextHandoffAction(card, status) {
|
|
1590
|
+
if (status === "blocked") {
|
|
1591
|
+
return "Review the failed tool evidence and decide whether to rerun or split follow-up work.";
|
|
1592
|
+
}
|
|
1593
|
+
if (!card.evidence.hasMemoryProvenance) {
|
|
1594
|
+
return "Capture memory provenance so this work can compound into future sessions.";
|
|
1595
|
+
}
|
|
1596
|
+
if (status === "needs-followup") {
|
|
1597
|
+
return "Convert the risk signal into a tracked todo or workflow before moving on.";
|
|
1598
|
+
}
|
|
1599
|
+
return "Ready for customer-facing summary, reuse, or release notes.";
|
|
1600
|
+
}
|
|
1601
|
+
function compactHandoffText(text) {
|
|
1602
|
+
const normalized = redactLine(text);
|
|
1603
|
+
return normalized.length > 240
|
|
1604
|
+
? `${normalized.slice(0, 237)}...`
|
|
1605
|
+
: normalized;
|
|
1606
|
+
}
|
|
1607
|
+
function estimateHoursSaved(input) {
|
|
1608
|
+
return Number((input.assistantTurnCount * 0.08 + input.toolCallCount * 0.03).toFixed(2));
|
|
1609
|
+
}
|
|
1610
|
+
function buildWorkflowOpportunities(cards, multiAgent, ambient) {
|
|
1611
|
+
const totalToolCalls = sum(cards, (card) => card.toolCallCount);
|
|
1612
|
+
const failedToolResults = sum(cards, (card) => card.failedToolResultCount);
|
|
1613
|
+
const memoryBacked = cards.filter((card) => card.evidence.hasMemoryProvenance).length;
|
|
1614
|
+
return [
|
|
1615
|
+
{
|
|
1616
|
+
id: "fix-failing-ci",
|
|
1617
|
+
name: "Fix failing CI",
|
|
1618
|
+
customerOutcome: "Turn failed checks into reviewed PRs with attached command/test evidence.",
|
|
1619
|
+
evidenceSignal: failedToolResults > 0
|
|
1620
|
+
? `${failedToolResults} failed tool result(s) are already visible in trust cards.`
|
|
1621
|
+
: "No failed tool results observed locally; keep this as a ready workflow.",
|
|
1622
|
+
recommendedSurface: "GitHub agent, CLI, and Slack handoff.",
|
|
1623
|
+
workflowTemplate: workflowTemplate("fix-failing-ci"),
|
|
1624
|
+
},
|
|
1625
|
+
{
|
|
1626
|
+
id: "review-pr",
|
|
1627
|
+
name: "Review this PR",
|
|
1628
|
+
customerOutcome: "Give reviewers a concise risk summary with replayable evidence.",
|
|
1629
|
+
evidenceSignal: `${cards.length} session(s) can already produce trust-card evidence.`,
|
|
1630
|
+
recommendedSurface: "GitHub PR comment plus `maestro value --format md` attachment.",
|
|
1631
|
+
workflowTemplate: workflowTemplate("review-pr"),
|
|
1632
|
+
},
|
|
1633
|
+
{
|
|
1634
|
+
id: "coordinate-agent-swarm",
|
|
1635
|
+
name: "Coordinate agent swarm",
|
|
1636
|
+
customerOutcome: "Split work across peer agents while preserving ownership, transcript, and workGraph evidence.",
|
|
1637
|
+
evidenceSignal: multiAgent.delegatedTaskCount > 0
|
|
1638
|
+
? `${multiAgent.delegatedTaskCount} A2A delegated task(s) across ${multiAgent.peerCount} peer(s); ${multiAgent.workGraphTaskCount} of ${multiAgent.taskCount} total ledger row(s) include workGraph metadata.`
|
|
1639
|
+
: multiAgent.taskCount > 0
|
|
1640
|
+
? `${multiAgent.taskCount} A2A ledger row(s) observed, but no delegated tasks; use this workflow to start collecting delegated multi-agent evidence.`
|
|
1641
|
+
: "No A2A delegated tasks observed locally; use this workflow to start collecting multi-agent evidence.",
|
|
1642
|
+
recommendedSurface: "`maestro a2a cockpit`, `maestro a2a delegate --work-graph`, and `maestro value --format md`.",
|
|
1643
|
+
workflowTemplate: workflowTemplate("coordinate-agent-swarm"),
|
|
1644
|
+
},
|
|
1645
|
+
{
|
|
1646
|
+
id: "ambient-nightly-watchdog",
|
|
1647
|
+
name: "Ambient nightly watchdog",
|
|
1648
|
+
customerOutcome: "Run unattended checks only when local evidence says there is customer-visible work to deliver.",
|
|
1649
|
+
evidenceSignal: ambient.automationOpportunities.length > 0
|
|
1650
|
+
? `${ambient.automationOpportunities.length} ambient automation opportunity/opportunities found; ${ambient.outcomeCount} learner outcome(s) available.`
|
|
1651
|
+
: "No ambient automation opportunities observed yet; use this as the default setup workflow.",
|
|
1652
|
+
recommendedSurface: "Ambient agent schedule, Slack/CLI delivery, and `maestro value --format md`.",
|
|
1653
|
+
workflowTemplate: workflowTemplate("ambient-nightly-watchdog"),
|
|
1654
|
+
},
|
|
1655
|
+
{
|
|
1656
|
+
id: "playbook-learning-review",
|
|
1657
|
+
name: "Playbook learning review",
|
|
1658
|
+
customerOutcome: "Promote repeated successes into playbooks while quarantining transient failures.",
|
|
1659
|
+
evidenceSignal: ambient.playbookLearningOpportunities.length > 0
|
|
1660
|
+
? `${ambient.playbookLearningOpportunities.length} playbook learning opportunity/opportunities found; ${ambient.protectedTransientFailureCount} transient failure(s) protected.`
|
|
1661
|
+
: "No playbook learning opportunities observed yet; keep the review path ready.",
|
|
1662
|
+
recommendedSurface: "Weekly customer-value report plus `.maestro/playbooks/` review.",
|
|
1663
|
+
workflowTemplate: workflowTemplate("playbook-learning-review", ambient.learnerPath),
|
|
1664
|
+
},
|
|
1665
|
+
{
|
|
1666
|
+
id: "cut-release",
|
|
1667
|
+
name: "Cut release",
|
|
1668
|
+
customerOutcome: "Verify publish readiness and produce a release audit trail.",
|
|
1669
|
+
evidenceSignal: `${totalToolCalls} local tool call(s) can feed release proof cards.`,
|
|
1670
|
+
recommendedSurface: "CLI release workflow and GitHub release automation.",
|
|
1671
|
+
workflowTemplate: workflowTemplate("cut-release"),
|
|
1672
|
+
},
|
|
1673
|
+
{
|
|
1674
|
+
id: "triage-dependabot",
|
|
1675
|
+
name: "Triage Dependabot",
|
|
1676
|
+
customerOutcome: "Separate safe dependency bumps from ones needing human security review.",
|
|
1677
|
+
evidenceSignal: "Use trust cards to show dependency files read, tests run, and approvals requested.",
|
|
1678
|
+
recommendedSurface: "Ambient GitHub agent.",
|
|
1679
|
+
workflowTemplate: workflowTemplate("triage-dependabot"),
|
|
1680
|
+
},
|
|
1681
|
+
{
|
|
1682
|
+
id: "refactor-with-tests",
|
|
1683
|
+
name: "Refactor with tests",
|
|
1684
|
+
customerOutcome: "Make codebase improvements repeatable with explicit verification.",
|
|
1685
|
+
evidenceSignal: memoryBacked > 0
|
|
1686
|
+
? `${memoryBacked} session(s) include memory provenance for follow-up context.`
|
|
1687
|
+
: "No memory-backed sessions observed; report flags this as a collection gap.",
|
|
1688
|
+
recommendedSurface: "TUI/CLI workflow template.",
|
|
1689
|
+
workflowTemplate: workflowTemplate("refactor-with-tests"),
|
|
1690
|
+
},
|
|
1691
|
+
];
|
|
1692
|
+
}
|
|
1693
|
+
function workflowTemplate(id, ambientLearnerPath = "") {
|
|
1694
|
+
return {
|
|
1695
|
+
path: `.maestro/workflows/${id}.yaml`,
|
|
1696
|
+
yaml: id === "playbook-learning-review"
|
|
1697
|
+
? WORKFLOW_TEMPLATE_YAML[id].replace("__AMBIENT_LEARNER_PRESENCE_COMMAND__", ambientLearnerPresenceCommand(ambientLearnerPath))
|
|
1698
|
+
: WORKFLOW_TEMPLATE_YAML[id],
|
|
1699
|
+
};
|
|
1700
|
+
}
|
|
1701
|
+
const WORKFLOW_TEMPLATE_YAML = {
|
|
1702
|
+
"fix-failing-ci": `name: fix-failing-ci
|
|
1703
|
+
description: Diagnose failing checks, run focused tests, and produce evidence for a trust card.
|
|
1704
|
+
version: "1"
|
|
1705
|
+
default_on_error: stop
|
|
1706
|
+
steps:
|
|
1707
|
+
- id: preflight
|
|
1708
|
+
tool: bash
|
|
1709
|
+
description: Capture branch and dirty files before changing anything.
|
|
1710
|
+
params:
|
|
1711
|
+
command: git status --short && git branch --show-current
|
|
1712
|
+
- id: likely_checks
|
|
1713
|
+
tool: bash
|
|
1714
|
+
description: List local check scripts that are likely to mirror CI.
|
|
1715
|
+
params:
|
|
1716
|
+
command: node -e "const p=require('./package.json'); console.log(Object.keys(p.scripts||{}).filter(k=>/test|lint|check|build/.test(k)).map(k=>'npm run '+k).join('\\\\n'))"
|
|
1717
|
+
- id: value_report
|
|
1718
|
+
tool: bash
|
|
1719
|
+
description: Emit current customer-value evidence for handoff.
|
|
1720
|
+
params:
|
|
1721
|
+
command: maestro value week --format md`,
|
|
1722
|
+
"review-pr": `name: review-pr
|
|
1723
|
+
description: Produce a concise PR risk summary with replayable local evidence.
|
|
1724
|
+
version: "1"
|
|
1725
|
+
default_on_error: continue
|
|
1726
|
+
steps:
|
|
1727
|
+
- id: pr_context
|
|
1728
|
+
tool: bash
|
|
1729
|
+
description: Read PR metadata when GitHub CLI context is available.
|
|
1730
|
+
params:
|
|
1731
|
+
command: gh pr view --json number,title,author,headRefName,baseRefName,reviewDecision,statusCheckRollup
|
|
1732
|
+
- id: diff_summary
|
|
1733
|
+
tool: bash
|
|
1734
|
+
description: Capture changed files for risk review.
|
|
1735
|
+
params:
|
|
1736
|
+
command: git diff --stat origin/$(git branch --show-current)...HEAD || git diff --stat
|
|
1737
|
+
- id: value_report
|
|
1738
|
+
tool: bash
|
|
1739
|
+
description: Attach trust-card evidence from local sessions.
|
|
1740
|
+
params:
|
|
1741
|
+
command: maestro value week --format md`,
|
|
1742
|
+
"coordinate-agent-swarm": `name: coordinate-agent-swarm
|
|
1743
|
+
description: Coordinate delegated work across A2A peers and preserve customer-visible evidence.
|
|
1744
|
+
version: "1"
|
|
1745
|
+
default_on_error: stop
|
|
1746
|
+
steps:
|
|
1747
|
+
- id: cockpit
|
|
1748
|
+
tool: bash
|
|
1749
|
+
description: Show peer health, task ownership, and delegated work.
|
|
1750
|
+
params:
|
|
1751
|
+
command: maestro a2a cockpit
|
|
1752
|
+
- id: task_graphs
|
|
1753
|
+
tool: bash
|
|
1754
|
+
description: Show workGraph-backed delegated work and peer ownership from the local ledger.
|
|
1755
|
+
params:
|
|
1756
|
+
command: maestro a2a tasks --work-graph
|
|
1757
|
+
- id: delegate
|
|
1758
|
+
tool: bash
|
|
1759
|
+
description: Delegate one objective to the selected peer with workGraph evidence.
|
|
1760
|
+
params:
|
|
1761
|
+
command: test -n "$MAESTRO_A2A_PEER" && test -n "$MAESTRO_A2A_OBJECTIVE" && maestro a2a delegate "$MAESTRO_A2A_PEER" "$MAESTRO_A2A_OBJECTIVE" --wait --work-graph
|
|
1762
|
+
- id: value_report
|
|
1763
|
+
tool: bash
|
|
1764
|
+
description: Emit customer-visible multi-agent value evidence after coordination.
|
|
1765
|
+
params:
|
|
1766
|
+
command: maestro value week --format md`,
|
|
1767
|
+
"ambient-nightly-watchdog": `name: ambient-nightly-watchdog
|
|
1768
|
+
description: Run unattended evidence checks and deliver only when there is customer-visible work.
|
|
1769
|
+
version: "1"
|
|
1770
|
+
default_on_error: continue
|
|
1771
|
+
steps:
|
|
1772
|
+
- id: ambient_status
|
|
1773
|
+
tool: bash
|
|
1774
|
+
description: Check whether the ambient daemon is reachable.
|
|
1775
|
+
params:
|
|
1776
|
+
command: ambient status || true
|
|
1777
|
+
- id: a2a_pressure
|
|
1778
|
+
tool: bash
|
|
1779
|
+
description: Capture delegated work that needs an operator.
|
|
1780
|
+
params:
|
|
1781
|
+
command: maestro a2a cockpit || true
|
|
1782
|
+
- id: value_report
|
|
1783
|
+
tool: bash
|
|
1784
|
+
description: Produce the customer-visible watchdog report.
|
|
1785
|
+
params:
|
|
1786
|
+
command: maestro value week --format md`,
|
|
1787
|
+
"playbook-learning-review": `name: playbook-learning-review
|
|
1788
|
+
description: Promote durable ambient lessons and quarantine transient setup failures.
|
|
1789
|
+
version: "1"
|
|
1790
|
+
default_on_error: continue
|
|
1791
|
+
steps:
|
|
1792
|
+
- id: learner_presence
|
|
1793
|
+
tool: bash
|
|
1794
|
+
description: Check whether ambient learner evidence exists.
|
|
1795
|
+
params:
|
|
1796
|
+
command: __AMBIENT_LEARNER_PRESENCE_COMMAND__
|
|
1797
|
+
- id: learner_flush
|
|
1798
|
+
tool: bash
|
|
1799
|
+
description: Flush any in-memory learner outcomes before rendering the report.
|
|
1800
|
+
params:
|
|
1801
|
+
command: ambient flush || true
|
|
1802
|
+
- id: value_report
|
|
1803
|
+
tool: bash
|
|
1804
|
+
description: Render automation and playbook learning opportunities.
|
|
1805
|
+
params:
|
|
1806
|
+
command: maestro value week --format md
|
|
1807
|
+
- id: playbook_dir
|
|
1808
|
+
tool: bash
|
|
1809
|
+
description: Show current local playbooks for human review.
|
|
1810
|
+
params:
|
|
1811
|
+
command: find .maestro/playbooks -maxdepth 1 -type f 2>/dev/null || true`,
|
|
1812
|
+
"cut-release": `name: cut-release
|
|
1813
|
+
description: Verify release readiness and produce an audit trail before publishing.
|
|
1814
|
+
version: "1"
|
|
1815
|
+
default_on_error: stop
|
|
1816
|
+
steps:
|
|
1817
|
+
- id: preflight
|
|
1818
|
+
tool: bash
|
|
1819
|
+
description: Confirm branch, remote, and dirty files.
|
|
1820
|
+
params:
|
|
1821
|
+
command: git status --short && git branch --show-current && git remote -v
|
|
1822
|
+
- id: release_guardrails
|
|
1823
|
+
tool: bash
|
|
1824
|
+
description: Run release workflow guardrails when available.
|
|
1825
|
+
params:
|
|
1826
|
+
command: npm run check:workflow-footguns --if-present
|
|
1827
|
+
- id: value_report
|
|
1828
|
+
tool: bash
|
|
1829
|
+
description: Produce release proof evidence.
|
|
1830
|
+
params:
|
|
1831
|
+
command: maestro value week --format md`,
|
|
1832
|
+
"triage-dependabot": `name: triage-dependabot
|
|
1833
|
+
description: Separate safe dependency bumps from updates needing human security review.
|
|
1834
|
+
version: "1"
|
|
1835
|
+
default_on_error: continue
|
|
1836
|
+
steps:
|
|
1837
|
+
- id: dependabot_prs
|
|
1838
|
+
tool: bash
|
|
1839
|
+
description: List open Dependabot PRs when GitHub CLI context is available.
|
|
1840
|
+
params:
|
|
1841
|
+
command: gh pr list --author app/dependabot --json number,title,headRefName,labels,reviewDecision,statusCheckRollup
|
|
1842
|
+
- id: lockfile_changes
|
|
1843
|
+
tool: bash
|
|
1844
|
+
description: Show dependency file changes in the current branch.
|
|
1845
|
+
params:
|
|
1846
|
+
command: git diff --stat -- package.json package-lock.json bun.lockb pnpm-lock.yaml yarn.lock
|
|
1847
|
+
- id: value_report
|
|
1848
|
+
tool: bash
|
|
1849
|
+
description: Preserve trust-card evidence for the triage run.
|
|
1850
|
+
params:
|
|
1851
|
+
command: maestro value week --format md`,
|
|
1852
|
+
"refactor-with-tests": `name: refactor-with-tests
|
|
1853
|
+
description: Make a scoped refactor repeatable with explicit verification and memory provenance.
|
|
1854
|
+
version: "1"
|
|
1855
|
+
default_on_error: stop
|
|
1856
|
+
steps:
|
|
1857
|
+
- id: preflight
|
|
1858
|
+
tool: bash
|
|
1859
|
+
description: Capture current branch and dirty files before refactoring.
|
|
1860
|
+
params:
|
|
1861
|
+
command: git status --short && git branch --show-current
|
|
1862
|
+
- id: candidate_checks
|
|
1863
|
+
tool: bash
|
|
1864
|
+
description: List tests and checks available in this project.
|
|
1865
|
+
params:
|
|
1866
|
+
command: node -e "const p=require('./package.json'); console.log(Object.keys(p.scripts||{}).filter(k=>/test|lint|check|type/.test(k)).map(k=>'npm run '+k).join('\\\\n'))"
|
|
1867
|
+
- id: value_report
|
|
1868
|
+
tool: bash
|
|
1869
|
+
description: Emit value, evidence, and memory provenance after the refactor.
|
|
1870
|
+
params:
|
|
1871
|
+
command: maestro value week --format md`,
|
|
1872
|
+
};
|
|
1873
|
+
function buildAdminControls(params) {
|
|
1874
|
+
return {
|
|
1875
|
+
controls: [
|
|
1876
|
+
{
|
|
1877
|
+
id: "policy-and-approval-audit",
|
|
1878
|
+
name: "Policy and approval audit",
|
|
1879
|
+
status: params.telemetry.policyApprovalAuditEvents > 0 ? "available" : "gap",
|
|
1880
|
+
evidence: params.telemetry.policyApprovalAuditEvents > 0
|
|
1881
|
+
? `${params.telemetry.policyApprovalAuditEvents} policy/approval audit telemetry event(s) parsed.`
|
|
1882
|
+
: "No canonical-turn, policy, or approval telemetry found for policy rollups.",
|
|
1883
|
+
},
|
|
1884
|
+
{
|
|
1885
|
+
id: "session-evidence-retention",
|
|
1886
|
+
name: "Session evidence retention",
|
|
1887
|
+
status: params.trustCards.length > 0 ? "available" : "gap",
|
|
1888
|
+
evidence: params.trustCards.length > 0
|
|
1889
|
+
? `${params.trustCards.length} trust-card session(s) loaded from ${params.sessionDir}.`
|
|
1890
|
+
: `No session JSONL files found in ${params.sessionDir}.`,
|
|
1891
|
+
},
|
|
1892
|
+
{
|
|
1893
|
+
id: "spend-and-routing",
|
|
1894
|
+
name: "Spend and routing",
|
|
1895
|
+
status: params.trustCards.some((card) => card.usage.requests > 0)
|
|
1896
|
+
? "available"
|
|
1897
|
+
: "gap",
|
|
1898
|
+
evidence: "Uses local usage records keyed by session id.",
|
|
1899
|
+
},
|
|
1900
|
+
{
|
|
1901
|
+
id: "team-memory-provenance",
|
|
1902
|
+
name: "Team memory provenance",
|
|
1903
|
+
status: params.trustCards.some((card) => card.evidence.hasMemoryProvenance)
|
|
1904
|
+
? "available"
|
|
1905
|
+
: "gap",
|
|
1906
|
+
evidence: "Uses session memory extraction hashes when present.",
|
|
1907
|
+
},
|
|
1908
|
+
{
|
|
1909
|
+
id: "multi-agent-delegation-ledger",
|
|
1910
|
+
name: "Multi-agent delegation ledger",
|
|
1911
|
+
status: params.multiAgent.delegatedTaskCount > 0 ? "available" : "gap",
|
|
1912
|
+
evidence: params.multiAgent.taskCount > 0
|
|
1913
|
+
? `${params.multiAgent.delegatedTaskCount} A2A delegated task(s) and ${params.multiAgent.taskCount} total A2A ledger row(s) loaded from ${params.multiAgent.tasksPath}.`
|
|
1914
|
+
: (params.multiAgent.collectionGaps[0] ??
|
|
1915
|
+
`No A2A delegated task evidence found in ${params.multiAgent.tasksPath}.`),
|
|
1916
|
+
},
|
|
1917
|
+
{
|
|
1918
|
+
id: "ambient-learning-loop",
|
|
1919
|
+
name: "Ambient learning loop",
|
|
1920
|
+
status: params.ambient.outcomeCount > 0 ? "available" : "gap",
|
|
1921
|
+
evidence: params.ambient.outcomeCount > 0
|
|
1922
|
+
? `${params.ambient.outcomeCount} ambient learner outcome(s), ${params.ambient.actionablePatternCount} actionable pattern(s), and ${params.ambient.protectedTransientFailureCount} protected transient failure(s) loaded from ${params.ambient.learnerPath}.`
|
|
1923
|
+
: (params.ambient.collectionGaps[0] ??
|
|
1924
|
+
`No ambient learner evidence found in ${params.ambient.learnerPath}.`),
|
|
1925
|
+
},
|
|
1926
|
+
],
|
|
1927
|
+
};
|
|
1928
|
+
}
|
|
1929
|
+
async function summarizeTelemetry(path, range) {
|
|
1930
|
+
const summary = {
|
|
1931
|
+
parsedEventCount: 0,
|
|
1932
|
+
malformedLineCount: 0,
|
|
1933
|
+
toolExecutionEvents: 0,
|
|
1934
|
+
evaluationEvents: 0,
|
|
1935
|
+
canonicalTurnEvents: 0,
|
|
1936
|
+
policyApprovalAuditEvents: 0,
|
|
1937
|
+
collectionGaps: [],
|
|
1938
|
+
};
|
|
1939
|
+
if (!existsSync(path)) {
|
|
1940
|
+
summary.collectionGaps.push(`Telemetry log not found at ${path}.`);
|
|
1941
|
+
return summary;
|
|
1942
|
+
}
|
|
1943
|
+
let raw = "";
|
|
1944
|
+
try {
|
|
1945
|
+
raw = await readFile(path, "utf8");
|
|
1946
|
+
}
|
|
1947
|
+
catch (error) {
|
|
1948
|
+
summary.collectionGaps.push(`Telemetry log could not be read: ${sanitizeWithStaticMask(error instanceof Error ? error.message : String(error))}.`);
|
|
1949
|
+
return summary;
|
|
1950
|
+
}
|
|
1951
|
+
for (const line of raw.split("\n")) {
|
|
1952
|
+
const trimmed = line.trim();
|
|
1953
|
+
if (!trimmed)
|
|
1954
|
+
continue;
|
|
1955
|
+
try {
|
|
1956
|
+
const event = JSON.parse(trimmed);
|
|
1957
|
+
if (!isTelemetryEventInRange(event, range))
|
|
1958
|
+
continue;
|
|
1959
|
+
summary.parsedEventCount += 1;
|
|
1960
|
+
if (event.type === "tool-execution")
|
|
1961
|
+
summary.toolExecutionEvents += 1;
|
|
1962
|
+
if (event.type === "evaluation")
|
|
1963
|
+
summary.evaluationEvents += 1;
|
|
1964
|
+
if (event.type === "canonical-turn")
|
|
1965
|
+
summary.canonicalTurnEvents += 1;
|
|
1966
|
+
if (isPolicyApprovalAuditEvent(event)) {
|
|
1967
|
+
summary.policyApprovalAuditEvents += 1;
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
catch {
|
|
1971
|
+
summary.malformedLineCount += 1;
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
if (summary.parsedEventCount === 0) {
|
|
1975
|
+
summary.collectionGaps.push(range.since === undefined && range.until === undefined
|
|
1976
|
+
? "Telemetry log exists but has no parsed events."
|
|
1977
|
+
: "Telemetry log exists but has no parsed events in the selected range.");
|
|
1978
|
+
}
|
|
1979
|
+
else if (summary.policyApprovalAuditEvents === 0) {
|
|
1980
|
+
summary.collectionGaps.push("Telemetry log has parsed events but no canonical-turn, policy, or approval audit events.");
|
|
1981
|
+
}
|
|
1982
|
+
return summary;
|
|
1983
|
+
}
|
|
1984
|
+
function isPolicyApprovalAuditEvent(event) {
|
|
1985
|
+
if (!event || typeof event !== "object")
|
|
1986
|
+
return false;
|
|
1987
|
+
const record = event;
|
|
1988
|
+
const candidates = [
|
|
1989
|
+
record.type,
|
|
1990
|
+
record.event,
|
|
1991
|
+
record.name,
|
|
1992
|
+
record.subject,
|
|
1993
|
+
record.kind,
|
|
1994
|
+
]
|
|
1995
|
+
.filter((value) => typeof value === "string")
|
|
1996
|
+
.map((value) => value.toLowerCase());
|
|
1997
|
+
return candidates.some((value) => value === "canonical-turn" ||
|
|
1998
|
+
value === "policy.decision" ||
|
|
1999
|
+
value === "policy-decision" ||
|
|
2000
|
+
value === "approval" ||
|
|
2001
|
+
value === "approval-request" ||
|
|
2002
|
+
value === "approval_hit" ||
|
|
2003
|
+
value === "action_approval_required" ||
|
|
2004
|
+
value === "action_approval_resolved" ||
|
|
2005
|
+
value.includes(".approval_") ||
|
|
2006
|
+
value.includes(".policy."));
|
|
2007
|
+
}
|
|
2008
|
+
function isTelemetryEventInRange(event, range) {
|
|
2009
|
+
if (range.since === undefined && range.until === undefined)
|
|
2010
|
+
return true;
|
|
2011
|
+
if (!event || typeof event !== "object")
|
|
2012
|
+
return false;
|
|
2013
|
+
const record = event;
|
|
2014
|
+
const timestamp = parseTimestampMs(record.timestamp ?? record.time ?? record.createdAt);
|
|
2015
|
+
return isTimestampInRange(timestamp, range);
|
|
2016
|
+
}
|
|
2017
|
+
function buildCollectionGaps(params) {
|
|
2018
|
+
const gaps = [
|
|
2019
|
+
...params.telemetry.collectionGaps,
|
|
2020
|
+
...params.multiAgent.collectionGaps,
|
|
2021
|
+
...params.ambient.collectionGaps,
|
|
2022
|
+
];
|
|
2023
|
+
if (params.trustCards.length === 0) {
|
|
2024
|
+
gaps.push("No session trust cards were available for the selected range.");
|
|
2025
|
+
}
|
|
2026
|
+
if (params.usageEntries.length === 0) {
|
|
2027
|
+
gaps.push("No usage entries were available for the selected range.");
|
|
2028
|
+
}
|
|
2029
|
+
if (!params.trustCards.some((card) => card.evidence.hasSummary)) {
|
|
2030
|
+
gaps.push("No trust cards had persisted session summaries.");
|
|
2031
|
+
}
|
|
2032
|
+
if (!params.trustCards.some((card) => card.evidence.hasMemoryProvenance)) {
|
|
2033
|
+
gaps.push("No trust cards had memory extraction provenance.");
|
|
2034
|
+
}
|
|
2035
|
+
return [...new Set(gaps)];
|
|
2036
|
+
}
|
|
2037
|
+
function buildRiskSignals(toolStats, memoryExtractionHash) {
|
|
2038
|
+
const signals = [];
|
|
2039
|
+
if (toolStats.failedToolResultCount > 0) {
|
|
2040
|
+
signals.push(`${toolStats.failedToolResultCount} failed tool result(s)`);
|
|
2041
|
+
}
|
|
2042
|
+
if (toolStats.toolCallCount === 0) {
|
|
2043
|
+
signals.push("no tool evidence captured");
|
|
2044
|
+
}
|
|
2045
|
+
if (!memoryExtractionHash) {
|
|
2046
|
+
signals.push("no durable memory provenance");
|
|
2047
|
+
}
|
|
2048
|
+
return signals;
|
|
2049
|
+
}
|
|
2050
|
+
function buildCustomerSignals(input) {
|
|
2051
|
+
const signals = [];
|
|
2052
|
+
if (input.summary)
|
|
2053
|
+
signals.push("persisted summary");
|
|
2054
|
+
if (input.toolStats.toolCallCount > 0) {
|
|
2055
|
+
signals.push(`${input.toolStats.toolCallCount} tool-backed action(s)`);
|
|
2056
|
+
}
|
|
2057
|
+
if (input.usage.requests > 0) {
|
|
2058
|
+
signals.push(`${input.usage.requests} model request(s) costed`);
|
|
2059
|
+
}
|
|
2060
|
+
if (input.hasMemory)
|
|
2061
|
+
signals.push("durable memory provenance");
|
|
2062
|
+
return signals;
|
|
2063
|
+
}
|
|
2064
|
+
function findSessionFiles(root) {
|
|
2065
|
+
if (!existsSync(root))
|
|
2066
|
+
return [];
|
|
2067
|
+
const files = [];
|
|
2068
|
+
const visit = (dir) => {
|
|
2069
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
2070
|
+
const path = join(dir, entry.name);
|
|
2071
|
+
if (entry.isDirectory()) {
|
|
2072
|
+
visit(path);
|
|
2073
|
+
}
|
|
2074
|
+
else if (entry.isFile() && extname(entry.name) === ".jsonl") {
|
|
2075
|
+
files.push(path);
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
};
|
|
2079
|
+
visit(root);
|
|
2080
|
+
return files;
|
|
2081
|
+
}
|
|
2082
|
+
function formatNumber(value) {
|
|
2083
|
+
return new Intl.NumberFormat("en-US").format(value);
|
|
2084
|
+
}
|
|
2085
|
+
//# sourceMappingURL=report.js.map
|