agent-tune-kit 2.4.0__tar.gz → 2.4.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/.codex-plugin/plugin.json +1 -1
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/PKG-INFO +1 -1
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/__init__.py +1 -1
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/visualize/assets/trace/app.js +27 -18
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/visualize/assets/trace/page.html +1 -2
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/visualize/assets/trace/styles.css +13 -2
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/visualize/assets/traces/app.js +9 -4
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/visualize/trace.py +3 -1
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/docs/trace-dashboard-design.md +6 -6
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/docs/trace-swimlane-design.md +7 -2
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/docs/trace-tuning.md +9 -5
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/pyproject.toml +1 -1
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/scripts/validate_skill_pack.py +1 -1
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_install_plugin.py +1 -1
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_release_scripts.py +1 -1
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_visualize_trace.py +30 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/trace-dashboard.cjs +11 -1
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/trace-event-layout.cjs +18 -6
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/trace-fragments.cjs +39 -4
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/trace-stage-cards.cjs +19 -1
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/.gitignore +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/README.en.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/README.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/cli/__init__.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/cli/__main__.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/cli/dataset.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/cli/evaluation.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/cli/main.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/cli/output.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/cli/results.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/cli/trace.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/cli/visualize.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/datasets/__init__.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/datasets/prepare.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/datasets/truth.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/datasets/updates.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/datasets/validation.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/errors.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/execution/__init__.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/execution/calibration.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/execution/logs.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/execution/rules.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/execution/runner.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/execution/runtime.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/execution/tracing.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/installer.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/results/__init__.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/results/assessment.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/results/evidence.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/results/judgments.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/results/summary.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/results/versions.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/traces/__init__.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/traces/archive.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/traces/capture.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/traces/categories.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/traces/langfuse.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/traces/migrate.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/traces/progress.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/traces/projects.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/traces/query.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/traces/records.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/traces/segments.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/traces/store.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/utils/__init__.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/utils/csv_io.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/utils/files.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/visualize/__init__.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/visualize/assets/dataset/app.js +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/visualize/assets/dataset/page.html +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/visualize/assets/dataset/styles.css +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/visualize/assets/dataset/vendor/echarts.min.js +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/visualize/assets/failures/app.js +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/visualize/assets/failures/page.html +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/visualize/assets/failures/styles.css +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/visualize/assets/shared/base.css +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/visualize/assets/trace/lanes.js +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/visualize/assets/trace/vendor/markdown-it.LICENSE +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/visualize/assets/trace/vendor/markdown-it.min.js +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/visualize/assets/traces/page.html +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/visualize/assets/traces/styles.css +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/visualize/dataset.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/visualize/failures.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/visualize/fields.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/visualize/history.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/visualize/render.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/visualize/timeline.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/visualize/traces.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/workspace.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/docs/assets/agent_tune_kit_evaluation.png +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/docs/assets/agent_tune_kit_trace.png +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/docs/assets/arch-en.png +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/docs/assets/arch.png +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/docs/assets/architecture.en.svg +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/docs/assets/architecture.svg +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/docs/ato-atk-project-boundary-recommendation-2026-11-05.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/docs/cli-skill-modularization-plan.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/docs/codex_agent_tuning_prd.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/docs/execution-evidence-and-tracing-plan.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/docs/ground-truth-and-grading-assessment-2026-10-25.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/docs/local-context.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/docs/shared-versioning-and-confirmation.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/docs/skill-template-pack-usage.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/docs/surginame-atk-capability-review-2026-10-27.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/docs/trace-change-verification-readability-diagnosis.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/docs/trace-project-attribution-design.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/docs/trace-tuning-validation.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/docs/truth-and-assessment.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/scripts/check-release.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/scripts/dev-refresh-install.sh +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/scripts/install_plugin.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/scripts/publish-pypi.sh +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/scripts/publish-release.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/scripts/release-version.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/scripts/release-version.sh +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/skills/atk-dataset/SKILL.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/skills/atk-dataset/scripts/update_dataset.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/skills/atk-diagnose/SKILL.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/skills/atk-eval/SKILL.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/skills/atk-init/SKILL.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/skills/atk-optimize/SKILL.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/skills/atk-report/SKILL.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/skills/atk-trace-capture/SKILL.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/skills/atk-trace-detect/SKILL.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/skills/atk-trace-diagnose/SKILL.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/skills/atk-trace-init/SKILL.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/skills/atk-trace-optimize/SKILL.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/skills/atk-trace-verify/SKILL.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/skills/atk-visualize-dataset/SKILL.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/skills/atk-visualize-dataset/scripts/generate_dataset_browser.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/skills/atk-visualize-failures/SKILL.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/skills/atk-visualize-failures/scripts/generate_failure_browser.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/skills/atk-visualize-trace/SKILL.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/templates/.atk/runner/eval_runner.py.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/templates/.atk/runner/failure_rule.py.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/templates/.atk/runner/import_evidence.py.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/templates/.gitkeep +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/__init__.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/conftest.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/fixtures/legacy_eval_runner.py.txt +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/fixtures/managed_v1.py.md +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_assessment_contract.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_atk_init_contract.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_cli_workflow.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_dataset_updates.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_diagnosis.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_evidence_import.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_evidence_judgments.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_evidence_packaging.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_evidence_versions.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_execution_evidence.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_execution_outcomes.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_execution_tracing.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_generate_dataset_browser.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_generate_failure_browser.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_judge_calibration.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_local_context.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_plugin_cache.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_runner_output_columns.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_runner_template_row_logging.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_runtime_contracts.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_snapshot_reads.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_trace_capture.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_trace_categories.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_trace_cli.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_trace_event_list.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_trace_langfuse.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_trace_progress.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_trace_projects.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_trace_query.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_trace_records.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_trace_scroll_layout.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_trace_segments.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_trace_store.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_truth_browser.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_truth_cli.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_truth_contract.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_truth_runner.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_v2_progress.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/test_visualize_traces.py +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/trace-controls.cjs +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/trace-event-detail.cjs +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/trace-event-list.cjs +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/trace-event-wheel.cjs +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/trace-issue-cards.cjs +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/trace-preview-scroll.cjs +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/trace-projects.cjs +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/trace-scroll-layout.cjs +0 -0
- {agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/tests/trace-selection-reason.cjs +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-tune-kit",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.1",
|
|
4
4
|
"description": "Local Codex plugin for batch Agent evaluation and session trace tuning with evidence-backed issues, focused changes, verification and offline review.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "hustyichi",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: agent-tune-kit
|
|
3
|
-
Version: 2.4.
|
|
3
|
+
Version: 2.4.1
|
|
4
4
|
Summary: Local Codex plugin for iterative Agent tuning with guided Skills, reusable runner templates, versioned results, and static validation.
|
|
5
5
|
Project-URL: Homepage, https://github.com/hustyichi/agent-tune-kit
|
|
6
6
|
Project-URL: Repository, https://github.com/hustyichi/agent-tune-kit
|
|
@@ -423,7 +423,7 @@
|
|
|
423
423
|
const issue = item.record;
|
|
424
424
|
openDrawer(`${issue.id} · ${issue.title || "问题详情"}`, "issue");
|
|
425
425
|
const tabs = el("nav", undefined, "stage-tabs"); tabs.setAttribute("aria-label", "问题处理阶段");
|
|
426
|
-
for (const [key, label] of [["issue", "
|
|
426
|
+
for (const [key, label] of [["issue", "问题详情"], ["diagnoses", "诊断与方案"], ["changes", "修改候选"], ["verifications", "实际验证"]]) {
|
|
427
427
|
const tab = button(label, () => showIssue(item, key), key === stage ? "active" : "");
|
|
428
428
|
tab.setAttribute("aria-pressed", String(key === stage)); tabs.append(tab);
|
|
429
429
|
}
|
|
@@ -439,17 +439,6 @@
|
|
|
439
439
|
}
|
|
440
440
|
const segments = issue.segments || [];
|
|
441
441
|
if (!segments.length) $("drawer-content").append(el("p", "该问题尚未圈定片段,可查看已记录的关联证据。", "muted"));
|
|
442
|
-
if (segments.length) {
|
|
443
|
-
const box = section("关联片段");
|
|
444
|
-
segments.forEach((segment, index) => {
|
|
445
|
-
const row = el("div", undefined, "detail-section");
|
|
446
|
-
const title = `${segment.id || `S${index + 1}`} · ${segment.summary || "未命名片段"}`;
|
|
447
|
-
row.append(button(title, () => startIssue(item, item.fragments.findIndex(part => part.id === segment.id || (!part.id && index === item.fragments.indexOf(part))))));
|
|
448
|
-
appendReferences(row, segment.evidence || []);
|
|
449
|
-
box.append(row);
|
|
450
|
-
});
|
|
451
|
-
$("drawer-content").append(box);
|
|
452
|
-
}
|
|
453
442
|
if ((issue.evidence || []).length) {
|
|
454
443
|
const evidence = section(segments.length ? "额外证据" : "关联证据");
|
|
455
444
|
appendReferences(evidence, issue.evidence);
|
|
@@ -631,16 +620,31 @@
|
|
|
631
620
|
return (left.at ?? Infinity) - (right.at ?? Infinity) || left.track - right.track || a - b;
|
|
632
621
|
});
|
|
633
622
|
}
|
|
634
|
-
|
|
623
|
+
const rows = candidates.filter(i => {
|
|
635
624
|
const n = currentCapture.nodes[i];
|
|
636
625
|
if ((track !== null && n.track !== track) || (type && n.type !== type)) return false;
|
|
637
|
-
if (mode === "error" && !eventState(n).failed) return false;
|
|
638
626
|
if (query) {
|
|
639
627
|
if (!searchable.has(n)) searchable.set(n, pretty(n).toLocaleLowerCase());
|
|
640
628
|
return searchable.get(n).includes(query);
|
|
641
629
|
}
|
|
642
630
|
return true;
|
|
643
631
|
});
|
|
632
|
+
// The failure switch shows its count before it is chosen, so count within every other active scope and filter.
|
|
633
|
+
const failed = rows.filter(i => eventState(currentCapture.nodes[i]).failed);
|
|
634
|
+
return {rows: mode === "error" ? failed : rows, total: rows.length, failed: failed.length};
|
|
635
|
+
}
|
|
636
|
+
function syncRecordMode(failed) {
|
|
637
|
+
const only = $("record-mode").value === "error";
|
|
638
|
+
$("record-all").setAttribute("aria-pressed", String(!only));
|
|
639
|
+
$("record-failed").setAttribute("aria-pressed", String(only));
|
|
640
|
+
$("record-failed-count").textContent = String(failed);
|
|
641
|
+
// Keep an active switch usable at zero so the selection stays visible; otherwise zero means nothing to look at.
|
|
642
|
+
$("record-failed").disabled = !only && failed === 0;
|
|
643
|
+
$("record-failed").title = failed || only ? `只看执行失败的事件(${failed} 条)` : "当前范围没有执行失败的事件";
|
|
644
|
+
}
|
|
645
|
+
function setRecordMode(mode) {
|
|
646
|
+
$("record-mode").value = mode;
|
|
647
|
+
renderTraces();
|
|
644
648
|
}
|
|
645
649
|
function eventState(n) {
|
|
646
650
|
const out = n.output, input = n.input;
|
|
@@ -859,7 +863,7 @@
|
|
|
859
863
|
if (state.failed) {
|
|
860
864
|
row.classList.add("is-error");
|
|
861
865
|
const icon = el("span", "⚠", "event-error-icon");
|
|
862
|
-
icon.setAttribute("role", "img"); icon.setAttribute("aria-label", "
|
|
866
|
+
icon.setAttribute("role", "img"); icon.setAttribute("aria-label", "执行失败"); icon.title = "执行失败";
|
|
863
867
|
label.append(icon);
|
|
864
868
|
}
|
|
865
869
|
label.append(el("span", name, "node-name"));
|
|
@@ -963,9 +967,12 @@
|
|
|
963
967
|
$("summary").textContent = notes.join(" · ");
|
|
964
968
|
$("session-stats").textContent = `${native.length} Trace · ${order.length} 条事件 · ${data.issues.length} 问题`;
|
|
965
969
|
scroller.parentElement.classList.toggle("single", tracks.length === 1 || displayedScope !== null);
|
|
966
|
-
|
|
970
|
+
const filtered = filteredRows();
|
|
971
|
+
streamRows = filtered.rows;
|
|
972
|
+
syncRecordMode(filtered.failed);
|
|
967
973
|
displayRows = buildDisplayRows(streamRows);
|
|
968
|
-
$("trace-count").textContent =
|
|
974
|
+
$("trace-count").textContent = $("record-mode").value === "error"
|
|
975
|
+
? `失败 ${streamRows.length} / ${filtered.total} 条` : `${streamRows.length} 条`;
|
|
969
976
|
if (eventFocus) $("trace-count").textContent = streamRows.length === eventFocus.indices.length
|
|
970
977
|
? `${streamRows.length} 条事件` : `${streamRows.length} / ${eventFocus.indices.length} 条事件`;
|
|
971
978
|
const related = new Set((investigation?.item.fragments || []).filter(p => p.capture_id === currentCapture?.id).flatMap(p => p.anchors));
|
|
@@ -1289,7 +1296,9 @@
|
|
|
1289
1296
|
if (currentCapture) $("capture-filter").value = currentCapture.id;
|
|
1290
1297
|
$("capture-filter").onchange = () => { investigation = null; scopeBefore = null; railFilter = null; chooseCapture(); renderIssueRail(); renderTraces(); };
|
|
1291
1298
|
$("trace-filter").onchange = () => focusTrace(scope());
|
|
1292
|
-
for (const id of ["trace-search","type-filter"
|
|
1299
|
+
for (const id of ["trace-search","type-filter"]) $(id).addEventListener(id === "trace-search" ? "input" : "change", () => renderTraces());
|
|
1300
|
+
$("record-all").onclick = () => setRecordMode("");
|
|
1301
|
+
$("record-failed").onclick = () => setRecordMode("error");
|
|
1293
1302
|
$("issue-search").oninput = () => { railFilter = null; renderIssueRail(); };
|
|
1294
1303
|
const collapsed = localStorage.getItem(RAIL_KEY) === "1";
|
|
1295
1304
|
document.body.classList.toggle("rail-collapsed", collapsed);
|
{agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/visualize/assets/trace/page.html
RENAMED
|
@@ -60,9 +60,8 @@
|
|
|
60
60
|
</section>
|
|
61
61
|
<section class="record-panel" aria-labelledby="records-title">
|
|
62
62
|
<div class="records-heading">
|
|
63
|
-
<div class="records-title"><h2 id="records-title">事件</h2><span id="event-range" class="muted" hidden></span><span id="trace-count" class="muted" aria-live="polite"></span><button id="event-reset" type="button" hidden>返回全部</button></div>
|
|
63
|
+
<div class="records-title"><h2 id="records-title">事件</h2><div class="record-mode" role="group" aria-label="事件范围"><input id="record-mode" type="hidden" value=""><button id="record-all" type="button" aria-pressed="true">全部</button><button id="record-failed" type="button" aria-pressed="false"><span class="record-failed-icon" aria-hidden="true">⚠</span>失败 <span id="record-failed-count" class="record-failed-count">0</span></button></div><span id="event-range" class="muted" hidden></span><span id="trace-count" class="muted" aria-live="polite"></span><button id="event-reset" type="button" hidden>返回全部</button></div>
|
|
64
64
|
<div class="toolbar record-filters">
|
|
65
|
-
<label><span class="sr-only">事件范围</span><select id="record-mode"><option value="">全部事件</option><option value="error">仅看异常</option></select></label>
|
|
66
65
|
<label><span class="sr-only">类型</span><select id="type-filter"></select></label>
|
|
67
66
|
<label class="search-label"><span class="sr-only">搜索事件</span><input id="trace-search" type="search" placeholder="搜索事件或输入输出"></label>
|
|
68
67
|
</div>
|
{agent_tune_kit-2.4.0 → agent_tune_kit-2.4.1}/agent_tune_kit/visualize/assets/trace/styles.css
RENAMED
|
@@ -153,13 +153,24 @@ body.rail-collapsed .rail-list { padding-inline: 4px }
|
|
|
153
153
|
.toolbar { flex-wrap: wrap; gap: 8px }
|
|
154
154
|
.record-filters { gap: 8px; max-width: 100% }
|
|
155
155
|
.record-filters label { display: block; min-width: 0 }
|
|
156
|
-
|
|
156
|
+
/* Failure-only viewing is a visible two-state switch next to the title, not a dropdown, so the failure count shows
|
|
157
|
+
before anyone filters. */
|
|
158
|
+
.record-mode { display: inline-flex; flex-shrink: 0; border: 1px solid var(--line); border-radius: 6px; overflow: hidden; background: white }
|
|
159
|
+
.record-mode button { display: inline-flex; align-items: center; gap: 4px; min-height: 26px; padding: 2px 10px; border: 0; border-radius: 0; background: transparent; color: var(--muted); font-size: 12px; white-space: nowrap }
|
|
160
|
+
.record-mode button + button { border-left: 1px solid var(--line) }
|
|
161
|
+
.record-mode button:hover:not(:disabled) { background: var(--tint) }
|
|
162
|
+
.record-mode button[aria-pressed=true] { background: var(--tint); color: var(--accent); font-weight: 600 }
|
|
163
|
+
.record-mode #record-failed[aria-pressed=true] { background: #fff2f1; color: #b12c21; box-shadow: inset 0 -2px #c0392b }
|
|
164
|
+
.record-failed-icon, .record-failed-count { color: #b12c21 }
|
|
165
|
+
.record-failed-count { font-weight: 600; font-variant-numeric: tabular-nums }
|
|
166
|
+
.record-mode button:disabled { opacity: 1; color: #9aa8b2 }
|
|
167
|
+
.record-mode button:disabled :is(.record-failed-icon, .record-failed-count) { color: inherit; font-weight: 400 }
|
|
157
168
|
#type-filter { width: 142px }
|
|
158
169
|
#trace-search { width: 208px }
|
|
159
170
|
.toolbar select:has(option:checked:not([value=""])) { border-color: #deb493; color: var(--accent) }
|
|
160
171
|
@container (max-width: 650px) {
|
|
161
172
|
.record-filters { display: grid; width: 100%; grid-template-columns: repeat(2,minmax(0,1fr)) }
|
|
162
|
-
.record-filters :is(#
|
|
173
|
+
.record-filters :is(#type-filter,#trace-search) { width: 100% }
|
|
163
174
|
.record-filters .search-label { grid-column: 1/-1 }
|
|
164
175
|
}
|
|
165
176
|
.stream { overflow: hidden; max-height: 100vh; max-height: 100dvh }
|
|
@@ -74,8 +74,13 @@
|
|
|
74
74
|
|
|
75
75
|
// --- small building blocks ------------------------------------------------------------------------------------
|
|
76
76
|
const countBy = issues => { const counts = new Map(); for (const issue of issues) counts.set(issue.progress, (counts.get(issue.progress) || 0) + 1); return counts; };
|
|
77
|
-
const topProgress = counts => [...counts].sort((a, b) => b[1] - a[1] || ORDER.get(a[0]) - ORDER.get(b[0])).slice(0, 2).map(([key, n]) => `${LABEL.get(key)} ${n}`).join(" · ");
|
|
78
77
|
const flag = (text, bad) => el("span", text, bad ? "flag bad" : "flag");
|
|
78
|
+
// Cards do not repeat routine progress (the state filter and drawers carry it); they only flag the same results the
|
|
79
|
+
// session attention notes call out: failed verification and inconclusive verdicts.
|
|
80
|
+
const attentionFlags = counts => [
|
|
81
|
+
...(counts.get("fail") ? [flag(`验证失败 ${counts.get("fail")}`, true)] : []),
|
|
82
|
+
...(counts.get("inconclusive") ? [flag(`无法判断 ${counts.get("inconclusive")}`)] : []),
|
|
83
|
+
];
|
|
79
84
|
const copyText = async text => {
|
|
80
85
|
try { await navigator.clipboard.writeText(text); return true; } catch { /* file:// pages may refuse; fall back below */ }
|
|
81
86
|
try {
|
|
@@ -262,7 +267,7 @@
|
|
|
262
267
|
if (matched.length) {
|
|
263
268
|
const counts = countBy(matched);
|
|
264
269
|
const row = el("div", undefined, "card-count");
|
|
265
|
-
row.append(el("strong", `${matched.length} 个问题`),
|
|
270
|
+
row.append(el("strong", `${matched.length} 个问题`), ...attentionFlags(counts));
|
|
266
271
|
card.append(row);
|
|
267
272
|
} else card.append(el("div", "无保留问题(不代表会话正确)", "card-count muted"));
|
|
268
273
|
const perCategory = new Map(); let none = 0;
|
|
@@ -308,9 +313,9 @@
|
|
|
308
313
|
card.append(head, el("div", info ? info.definition : "分类词表中没有这条分类,按分类 ID 显示。", "card-definition"));
|
|
309
314
|
const counts = countBy(items.map(item => item.issue));
|
|
310
315
|
const row = el("div", undefined, "card-count");
|
|
311
|
-
row.append(el("strong", `${new Set(items.map(item => item.s.dir)).size} 个会话 · ${items.length} 个问题`), el("span", latestOf(items) < 0 ? "发生时间未记录" : `最近发生 ${when(latestOf(items))}`, "muted"));
|
|
316
|
+
row.append(el("strong", `${new Set(items.map(item => item.s.dir)).size} 个会话 · ${items.length} 个问题`), el("span", latestOf(items) < 0 ? "发生时间未记录" : `最近发生 ${when(latestOf(items))}`, "muted"), ...attentionFlags(counts));
|
|
312
317
|
card.append(projectLine(items.map(({issue}) => issue)));
|
|
313
|
-
card.append(row
|
|
318
|
+
card.append(row);
|
|
314
319
|
return card;
|
|
315
320
|
}
|
|
316
321
|
// The distinct projects behind a group of issues; each offered name narrows the issue view to that project.
|
|
@@ -251,7 +251,9 @@ def build_trace_data(project_root, *, session_id, source=None):
|
|
|
251
251
|
display_refs = list(record.get("evidence", []))
|
|
252
252
|
for segment in record.get("segments", []):
|
|
253
253
|
display_refs.extend(segment.get("evidence", []))
|
|
254
|
-
evidence
|
|
254
|
+
# Shared evidence keeps one display index so it cannot reappear as an unclaimed point.
|
|
255
|
+
display_keys = dict.fromkeys(_reference_key(ref) for ref in display_refs)
|
|
256
|
+
evidence = [references[key] for key in display_keys if key in references]
|
|
255
257
|
# Fragment refs index into this combined list (top-level + segment evidence).
|
|
256
258
|
item["evidence"] = evidence
|
|
257
259
|
segments = record.get("segments") or []
|
|
@@ -149,7 +149,7 @@
|
|
|
149
149
|
| 会话卡片、分类卡片 | 与 `.issue-card` 相同:白底、`--line` 边框、8px 圆角;悬停时 `--tint` 底色和 `#e4b89b` 边框;选中时左侧 3px `--brand` 内描边 |
|
|
150
150
|
| ID 文本 | `.issue-id-text`:`--accent` 色、等宽、12px 粗体 |
|
|
151
151
|
| 分类标签 | `.seg-chip` 配色:`#fff8f1` 底、`--accent` 文字、4px 圆角 |
|
|
152
|
-
| 进度条 | 不使用(2026-11-11
|
|
152
|
+
| 进度条 | 不使用(2026-11-11 确认):页签顶部不展示通用进度条或概况指标块,会话卡片和分类卡片也不展示进度条或常规进度文字,只用提醒标记写验证失败和无法判断 |
|
|
153
153
|
| 提醒 | 与 `.warning` 相同的黄底边框;卡片内使用紧凑版 |
|
|
154
154
|
| 抽屉 | 同一 `.drawer`:右侧覆盖、非模态、默认 480px、可拖宽;窄屏从底部弹出;`Esc` 关闭。大盘的抽屉是进入会话页前的预览(2026-11-10 起):点击页面空白处、再次点击当前卡片或按 `Esc` 关闭,点击其他卡片直接切换;点击抽屉内、筛选、搜索、页签和链接不关闭;出现时有 0.18 秒滑入,系统要求减少动效时不播放。单会话页抽屉不变 |
|
|
155
155
|
| 抽屉中的问题列表 | 行样式参照 `.trace-row`:40px 行高、`#edf0f3` 分隔线、悬停 `#f5f9fa`;进度用 `.progress-dot` |
|
|
@@ -172,7 +172,7 @@
|
|
|
172
172
|
|
|
173
173
|
- **维度切换**:默认显示会话维度,当前维度写入 URL hash。
|
|
174
174
|
- **顶栏统计**(2026-11-11 确认):只写会话数、问题数;所有会话环境相同时追加“环境 <environment>”。不写获取方式(`source.type`,如 `local` 本地导入),也不写页面生成时间。
|
|
175
|
-
- **页签内容**(2026-11-11
|
|
175
|
+
- **页签内容**(2026-11-11 确认):不展示四块概况指标或通用进度条。会话页只在存在无法判断、验证失败或记录读取失败时显示按会话去重的关注提示;问题页保留紧凑的处理状态筛选。下方卡片及详情抽屉保留。卡片不重复常规进度(待诊断、已诊断、验证通过等),只在存在验证失败或无法判断时在数量行末加提醒标记,口径与会话页关注提示一致(2026-11-11 确认)。按状态查看用处理状态筛选,单个问题的进度在抽屉列表中显示。
|
|
176
176
|
- **筛选**:搜索(Session ID、Issue ID、标题、分类名)和来源在两个维度间共享。处理状态和关联项目仅作用于问题页,切回时恢复选择;状态选项包含“全部”和数量不为 0 的状态,再次点击已选状态或选择“全部”取消状态筛选。项目有多个来源时才显示来源/环境下拉框。
|
|
177
177
|
- **数量口径**:状态选项数量按搜索、来源及关联项目范围统计,便于切换状态;分类卡片、排序、未分类通栏及抽屉中的匹配数量按全部当前筛选计算。只有筛选生效时显示结果数量和“清除筛选”,该按钮清除当前维度生效的筛选。
|
|
178
178
|
|
|
@@ -183,7 +183,7 @@
|
|
|
183
183
|
│ SES_…830912 ⧉ │ │ cb27cb0f-… ⧉ │
|
|
184
184
|
│ 发生于 11-06 12:55 │ │ 发生于 11-09 15:01 │
|
|
185
185
|
│ │ │ │
|
|
186
|
-
│ 11 个问题
|
|
186
|
+
│ 11 个问题 │ │ 3 个问题 [无法判断 1] │
|
|
187
187
|
│ │ │ ⚠ 预览需刷新 │
|
|
188
188
|
│ 未分类 11 │ │ 未分类 3 │
|
|
189
189
|
└──────────────────────────────┘ └──────────────────────────────┘
|
|
@@ -196,7 +196,7 @@
|
|
|
196
196
|
| 会话身份 | 缩短的 Session ID,悬停显示全称,可复制 |
|
|
197
197
|
| 发生时间 | 会话本身的开始时间:保留轨迹中最早的事件时间,悬停显示开始至结束;无可用事件时间时写“发生时间未记录”。不显示导入、检测、诊断、修复等处理时间,后者只用于判断预览是否需刷新。无时区的事件时间按运行 ATK 的机器时区解释,与单会话页一致 |
|
|
198
198
|
| 来源 | 仅在存在多个来源时显示,写“环境 <environment>”;环境重名时追加实例,与来源下拉框同样的标签 |
|
|
199
|
-
|
|
|
199
|
+
| 问题数与提醒 | 只写问题数;存在验证失败或无法判断时行末加“验证失败 N”(红色)或“无法判断 N”(黄色)标记。不展示进度条或常规进度 |
|
|
200
200
|
| 主要分类 | 最多 3 个分类标签及数量,其余显示为 `+N`;点击标签切到问题维度并定位该分类 |
|
|
201
201
|
| 提醒 | 仅在需要处理时出现:预览需刷新、记录读取失败 |
|
|
202
202
|
|
|
@@ -234,14 +234,14 @@
|
|
|
234
234
|
│ Shell 路径/参数传递导致反复重试 │ │ 宣称完成但验收证据不足 │
|
|
235
235
|
│ 工具调用因相对路径、stdin 或变量… │ │ 交付结论缺少同条件的行为验证… │
|
|
236
236
|
│ 4 个会话 · 4 个问题 最近发生 11-09│ │ 3 个会话 · 5 个问题 最近发生 11-09│
|
|
237
|
-
│
|
|
237
|
+
│ │ │ [验证失败 1] │
|
|
238
238
|
└──────────────────────────────────┘ └──────────────────────────────────┘
|
|
239
239
|
┌ 未分类 · 37 个问题 · 相关会话下次检测时补充 ──────────────────────────────┐
|
|
240
240
|
```
|
|
241
241
|
|
|
242
242
|
(示意。Magic 现有问题在补分类前都在“未分类”中。)
|
|
243
243
|
|
|
244
|
-
-
|
|
244
|
+
- 分类卡片:分类名、一行定义(超出截断)、会话数与问题数、最近发生时间(所含会话中最晚的开始时间),以及与会话卡片相同的验证失败/无法判断提醒。已弃用的分类加“已弃用”标记,排在正常分类之后。
|
|
245
245
|
- 排序:按筛选后涉及的会话数倒序,相同时依次按问题数、最近发生时间。
|
|
246
246
|
- “未分类”是最后一条通栏,不与正常分类混排。
|
|
247
247
|
|
|
@@ -64,7 +64,11 @@
|
|
|
64
64
|
- 默认按会话时间连续列出全部事件。被任意 Issue 引用的行,末尾显示窄标签(如 `001`),不单独占列。
|
|
65
65
|
- 点击聚合刻痕后,列表只展示该刻痕包含的事件,标题显示所属 Trace、所选时段和事件数;无时间事件显示“时间未知”。列表仍可搜索和筛选,计数显示命中数与组内总数。所选事件集合固定,窗口缩放不会改变成员。
|
|
66
66
|
- “返回全部”恢复进入前的选中事件、滚动位置和筛选;原先有筛选时标为“返回筛选结果”,从问题定位进入时标为“返回问题片段”或“返回问题上下文”。连续点击另一聚合刻痕只替换当前集合,返回目标保持不变。切换 Trace 或快照清除该集合。
|
|
67
|
-
- 聚焦 Trace 后标题显示“事件 · T2
|
|
67
|
+
- 聚焦 Trace 后标题显示“事件 · T2”及当前事件数。事件工具栏仅保留类型和搜索,只筛选列表;Trace 切换位于泳道上方。
|
|
68
|
+
- 事件范围(2026-11-11 确认):不用下拉框,在“事件”标题旁放分段切换 `全部 | ⚠ 失败 N`,用词与状态列的“失败”一致,判定口径与失败行标红相同。
|
|
69
|
+
- N 按当前 Trace 聚焦、聚合刻痕事件集合、类型和搜索统计,不含切换本身,选择前即可看到。
|
|
70
|
+
- N 为 0 且未选中时保留显示但不可点击,表明当前范围没有失败事件;已选中时始终可点,便于看清和取消。
|
|
71
|
+
- 选中时计数写“失败 N / M 条”,M 为同一范围内的事件总数。它与类型、搜索同属列表筛选:进入问题定位或聚合刻痕时清除,退出时按进入前状态恢复。
|
|
68
72
|
- 选中 Issue 后:
|
|
69
73
|
- 恢复完整会话范围,呈现跨 Trace 的所有问题片段;退出问题定位后恢复原来的 Trace 聚焦状态。
|
|
70
74
|
- 范围内行加左侧色条,并插入段头行,显示片段摘要、事件数和时长。
|
|
@@ -97,9 +101,10 @@
|
|
|
97
101
|
|
|
98
102
|
**问题详情**(从问题栏打开):
|
|
99
103
|
|
|
100
|
-
-
|
|
104
|
+
- 顺序:问题详情 → 诊断与方案 → 修改候选 → 实际验证。
|
|
101
105
|
- 正文中的 `ISSUE-001/S2` 是可点击链接,点击后主区定位该片段,抽屉保持打开。
|
|
102
106
|
- 从问题证据进入事件后可返回原问题;问题入口保留在问题栏与片段导航中。
|
|
107
|
+
- “问题详情”展示问题描述、关联项目与保留理由,不重复列出全部关联片段。片段从左栏和主区导航;主区“片段证据(N)”按需在抽屉展示本段引用。无法放入片段的额外证据,以及无片段旧问题的关联证据,仍在问题详情中可访问。
|
|
103
108
|
|
|
104
109
|
### 导航与状态
|
|
105
110
|
|
|
@@ -222,6 +222,8 @@ CLI validation assigns stable `S1`, `S2`, … identifiers within the Issue, reje
|
|
|
222
222
|
|
|
223
223
|
Detection should write one segment per distinct location, using the smallest scope that still explains the problem, and must split across Traces. Diagnosis, change and verification records stay under the Issue; their Markdown may cite `ISSUE-001/S2` so the preview can link back to that segment.
|
|
224
224
|
|
|
225
|
+
Segments are ordered by their scoped observations' start times. For a final answer, scope the actual result/message event after confirming its content, rather than the enclosing Agent turn: that turn starts before the answer exists, even when its `output` contains the answer. Keep the enclosing turn as context when needed. Shared evidence may belong to multiple segments; the preview uses one display reference for it and does not add another standalone fragment.
|
|
226
|
+
|
|
225
227
|
Issue IDs are stable within the session. Omitting an old issue during new detection does not resolve it. Exclusion/correction needs a reason while preserving history. Detection coverage includes zero findings, checked/unread nodes, partial work and interruptions; an empty issue list does not prove correctness. Re-capture creates new unanalyzed material rather than rewriting previous coverage.
|
|
226
228
|
|
|
227
229
|
Diagnoses are immutable Markdown and include an issue snapshot (including segments when present). Adopted diagnoses bind path and digest. Change `target_issues` may list several issues and `diagnoses` maps each target issue to its adopted reference. Save a shared modification once under its owner issue; the other issues explicitly reference that owner-relative change path. Completed candidates are frozen; a new diagnosis/candidate is a new record.
|
|
@@ -297,7 +299,7 @@ Explicit visualization opens the browser by default. Options include `--source`,
|
|
|
297
299
|
|
|
298
300
|
In session mode, `$atk-visualize-trace` also runs `atk visualize traces --overwrite --no-open --json` after successful preview generation, using the same archive project root, to refresh `.atk/traces/index.html` without opening another page. This also applies to a custom preview output path. The standalone `atk visualize trace` command only generates the preview. If dashboard refresh fails, the Skill delivers the preview and reports the dashboard as unavailable or stale.
|
|
299
301
|
|
|
300
|
-
The page opens on the complete session. The UI consistently calls each observation an event (**事件**) across lanes, lists, details, counts and filters; native types and archive fields are unchanged. Selecting a grouped time mark focuses its exact events in the existing list, with the Trace, time range (or **时间未知**) and event count in the heading. It opens no drawer until an event row is selected. Search and type filters apply within this fixed group, whose membership survives resizing. **返回全部** restores the prior selection, filters and scroll position; its label becomes **返回筛选结果**, **返回问题片段** or **返回问题上下文** when returning to that context. Selecting another group preserves the original return destination; switching Trace or capture clears the group. Layout: a collapsible issue rail on the left, a compact swimlane chart above the event list in the center, and an overlay drawer on the right for event or Issue detail. Each Trace has one lane on the session clock with no permanent issue tracks. Scroll the event list to read all events in chronological order, including concurrent Traces. Select a lane heading or a time mark to find its events. Use **聚焦** to focus both the swimlane and event list on one Trace, with the time axis fitted to that Trace. While focused, switch Traces from the title above the swimlane; **返回完整会话** restores the prior filters, selected event, and scroll position. The event heading identifies the focused Trace, and its toolbar filters only the event list. Opening an Issue restores the complete session scope so its fragments across Traces remain accessible; exiting restores the previous view. A single Trace opens at full scale without focus controls. Child lanes require an explicit subtask identity. Undated events remain accessible. Search and type filters are optional.
|
|
302
|
+
The page opens on the complete session. The UI consistently calls each observation an event (**事件**) across lanes, lists, details, counts and filters; native types and archive fields are unchanged. Selecting a grouped time mark focuses its exact events in the existing list, with the Trace, time range (or **时间未知**) and event count in the heading. It opens no drawer until an event row is selected. Search and type filters apply within this fixed group, whose membership survives resizing. **返回全部** restores the prior selection, filters and scroll position; its label becomes **返回筛选结果**, **返回问题片段** or **返回问题上下文** when returning to that context. Selecting another group preserves the original return destination; switching Trace or capture clears the group. Layout: a collapsible issue rail on the left, a compact swimlane chart above the event list in the center, and an overlay drawer on the right for event or Issue detail. Each Trace has one lane on the session clock with no permanent issue tracks. Scroll the event list to read all events in chronological order, including concurrent Traces. Select a lane heading or a time mark to find its events. Use **聚焦** to focus both the swimlane and event list on one Trace, with the time axis fitted to that Trace. While focused, switch Traces from the title above the swimlane; **返回完整会话** restores the prior filters, selected event, and scroll position. The event heading identifies the focused Trace, and its toolbar filters only the event list. Opening an Issue restores the complete session scope so its fragments across Traces remain accessible; exiting restores the previous view. A single Trace opens at full scale without focus controls. Child lanes require an explicit subtask identity. Undated events remain accessible. Search and type filters are optional. Next to the event heading, a two-part **全部 | ⚠ 失败 N** switch shows events whose execution failed. N counts failures within the current Trace, grouped events, type filter and search, so you can see it before choosing. With no failures it stays visible but disabled. While it is on, the count reads **失败 N / M 条**.
|
|
301
303
|
|
|
302
304
|
Select an Issue title, **定位**, or a segment in the left rail to focus that Issue's fragments automatically. Recorded segments overlay as bands on their own Trace rows; the event list inserts segment headers and folds unrelated events, including interleaved concurrent Traces. Counts distinguish fragment events, folded events and locally expanded context. Each folded group can be expanded separately. **查看完整上下文** shows all events while retaining the Issue and its highlights; **返回问题片段** folds context again. **退出问题定位** restores the prior filters and scroll position. Cross-Trace retries stay as separate segments with the idle gap preserved. Issues without `segments` explicitly say “该问题尚未圈定片段” and navigate to existing evidence nodes or archived references; the page does not invent ranges. Row badges mark events cited by any Issue. Above the rail's issue cards, a single-choice **关联项目** row lists **全部** and the projects this session's issues link to, with issue counts that follow the rail search. It follows the dashboard's rules, carries `#project=<id>` both ways, and is hidden when no project is linked or one project holds every issue. The rail has no processing-state selector; each card shows its progress, and the search also matches progress labels and project names.
|
|
303
305
|
|
|
@@ -309,6 +311,8 @@ The diagnosis tab shows the latest structured diagnosis under Issue description,
|
|
|
309
311
|
|
|
310
312
|
In a local preview, a diagnosis link such as `[Project setup](src/project.py#L42)` opens a file resolved against the project root at generation time. ATK checks that the file exists under that root and excludes hidden paths. Older absolute `path:line` links use the same checks. Unresolved paths have a copy control. The line fragment marks the cited line, and scrolling to it depends on the file viewer.
|
|
311
313
|
|
|
314
|
+
The **问题详情** tab shows the description, linked projects and selection reason without repeating the full segment directory. Navigate segments in the rail or center, then use **片段证据(N)** to inspect the selected segment's references in the drawer. Extra evidence and legacy issues without segments keep their evidence links in Issue detail.
|
|
315
|
+
|
|
312
316
|
### Actual progress
|
|
313
317
|
|
|
314
318
|
The preview, its issue filter and the dashboard all show actual progress derived from saved records. The declared issue `status` is ignored, except that `excluded` always shows **已排除**. Otherwise the first matching rule applies:
|
|
@@ -335,11 +339,11 @@ atk visualize traces --overwrite --no-open --json
|
|
|
335
339
|
|
|
336
340
|
The dashboard is `.atk/traces/index.html`, one offline page covering every archived session in the project. To open it, ask `$atk-visualize-trace` for the dashboard or run the command without `--no-open`. Initialization does not create it. Options are `--project-root`, authorized `--overwrite`, `--open` and `--no-open`. The JSON summary reports session, issue and category counts, progress counts, stale previews, warnings and whether a browser opened. Failure keeps the previous page and does not undo the stage.
|
|
337
341
|
|
|
338
|
-
- **会话** (default) shows one card per session with when the session ran, its issue count
|
|
339
|
-
- **问题** shows one card per category, with session and issue counts and its
|
|
340
|
-
- Neither view has overview metric blocks or progress bars, on the page or on cards. The session view shows compact attention notes for inconclusive or failed verification results and unreadable records, counting each affected session once per note. The issue view has a **关联项目** row and processing-state buttons, each including **全部**, above the category cards.
|
|
342
|
+
- **会话** (default) shows one card per session with when the session ran, its issue count and category tags. The run time is the earliest event time in the retained trace (hover for start and end), using the same timezone rules as the session page; cards are ordered by it, newest first, with unknown times last. Import and processing times are not shown. The header gives the session and issue totals and, when every session shares one, the environment; how material was obtained (for example local import) is not shown. Cards name their environment only when sessions come from more than one source. Sessions with unreadable records, no retained issues or a missing or stale preview stay visible with that state. No retained issues does not mean the session was correct.
|
|
343
|
+
- **问题** shows one card per category, with session and issue counts and its latest session run time. Uncategorized issues are grouped in one strip at the bottom; they are categorized when their session is detected again.
|
|
344
|
+
- Neither view has overview metric blocks or progress bars, on the page or on cards. Cards do not repeat routine progress such as pending, diagnosed or passed; session and category cards flag only **验证失败 N** and **无法判断 N**, matching the attention notes. Use the processing-state filter or a drawer to see each issue's progress. The session view shows compact attention notes for inconclusive or failed verification results and unreadable records, counting each affected session once per note. The issue view has a **关联项目** row and processing-state buttons, each including **全部**, above the category cards.
|
|
341
345
|
- **关联项目** is a single choice: **全部** or one project. It lists only projects that at least one issue links to, each with its issue count and session count, ordered by count; a registered project without linked issues is not offered, and there is no empty-association choice. Counts follow source and search but not the project or processing-state choice, so an issue linked to several projects counts once in each and the counts must not be added up. Choosing the current project again returns to **全部**. The row is hidden when no project is linked, or when one project holds every issue. Project names on category cards choose that project as well. A linked ID missing from the registry stays offered, marked **未登记**.
|
|
342
|
-
- Processing-state and associated-project filters apply only to the issue view and are remembered when switching tabs. Processing-state counts follow the chosen project. Search and source filters are shared between views. Search matches Session IDs, issue IDs, titles and category names; a source filter appears only when sessions come from more than one source. Category
|
|
346
|
+
- Processing-state and associated-project filters apply only to the issue view and are remembered when switching tabs. Processing-state counts follow the chosen project. Search and source filters are shared between views. Search matches Session IDs, issue IDs, titles and category names; a source filter appears only when sessions come from more than one source. Category ordering, uncategorized counts and drawer match counts follow the current filters. **清除筛选** appears with active filters and clears those used by the current view.
|
|
343
347
|
- A card opens a right-side drawer listing its issues, unfinished first. Each issue links to its place in the session preview (`preview.html#issue=…`). A session drawer also shows capture and detection coverage and the command to generate a missing or stale preview.
|
|
344
348
|
- Deep links: `#view=session&session=<dir>`, `#view=category&category=<id>` and `#view=category&project=<id>`. A link with several `project` values keeps the first one still offered; one that is no longer offered means **全部**. When the dashboard exists beside a default preview, the preview shows **← 大盘** and its category tags link to the dashboard.
|
|
345
349
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "agent-tune-kit"
|
|
7
|
-
version = "2.4.
|
|
7
|
+
version = "2.4.1"
|
|
8
8
|
description = "Local Codex plugin for iterative Agent tuning with guided Skills, reusable runner templates, versioned results, and static validation."
|
|
9
9
|
readme = "README.en.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -125,7 +125,7 @@ REQUIRED_FILES += TRACE_SKILL_FILES + [
|
|
|
125
125
|
]
|
|
126
126
|
|
|
127
127
|
PER_FILE_PHRASES = {
|
|
128
|
-
".codex-plugin/plugin.json": ['"name": "agent-tune-kit"', '"version": "2.4.
|
|
128
|
+
".codex-plugin/plugin.json": ['"name": "agent-tune-kit"', '"version": "2.4.1"', '"skills": "./skills/"'],
|
|
129
129
|
"skills/atk-dataset/SKILL.md": [
|
|
130
130
|
"## Purpose",
|
|
131
131
|
"## Inputs",
|
|
@@ -104,7 +104,7 @@ class InstallPluginCliTests(unittest.TestCase):
|
|
|
104
104
|
for args in [("--version",), ("version",)]:
|
|
105
105
|
result = run_cli(*args)
|
|
106
106
|
self.assertEqual(result.returncode, 0, result.stderr)
|
|
107
|
-
self.assertEqual(result.stdout.strip(), "agent-tune-kit 2.4.
|
|
107
|
+
self.assertEqual(result.stdout.strip(), "agent-tune-kit 2.4.1")
|
|
108
108
|
self.assertEqual(result.stderr, "")
|
|
109
109
|
|
|
110
110
|
def test_script_wrapper_delegates_to_atk_cli(self) -> None:
|
|
@@ -64,7 +64,7 @@ class ReleaseScriptTests(unittest.TestCase):
|
|
|
64
64
|
check_release = load_script("check-release.py")
|
|
65
65
|
identity = check_release.read_project_identity()
|
|
66
66
|
self.assertEqual(identity.name, "agent-tune-kit")
|
|
67
|
-
self.assertEqual(identity.version, "2.4.
|
|
67
|
+
self.assertEqual(identity.version, "2.4.1")
|
|
68
68
|
check_release.assert_versions_aligned(identity)
|
|
69
69
|
|
|
70
70
|
def test_skill_pack_validation_does_not_phrase_scan_readmes(self) -> None:
|
|
@@ -653,6 +653,36 @@ def test_recorded_segments_render_as_fragments(tmp_path):
|
|
|
653
653
|
assert data["issues"][0]["evidence"]
|
|
654
654
|
|
|
655
655
|
|
|
656
|
+
def test_shared_segment_evidence_does_not_create_extra_fragments(tmp_path):
|
|
657
|
+
result = capture(tmp_path)
|
|
658
|
+
session_dir = Path(result["session_dir"])
|
|
659
|
+
path = "captures/CAP-001/raw/trace.json"
|
|
660
|
+
scope = store.evidence_ref(session_dir, path, "/trace/observations/0")
|
|
661
|
+
shared = store.evidence_ref(session_dir, path, "/trace/observations/1/output")
|
|
662
|
+
extra = store.evidence_ref(session_dir, path, "/trace/input")
|
|
663
|
+
records.save_issue(
|
|
664
|
+
session_dir,
|
|
665
|
+
{
|
|
666
|
+
"title": "Shared evidence",
|
|
667
|
+
"description": "Two segments refer to the same output",
|
|
668
|
+
"evidence": [extra],
|
|
669
|
+
"segments": [
|
|
670
|
+
{"summary": summary, "scope": {"node": scope}, "evidence": [shared]}
|
|
671
|
+
for summary in ("First perspective", "Second perspective")
|
|
672
|
+
],
|
|
673
|
+
},
|
|
674
|
+
)
|
|
675
|
+
before = digests(session_dir)
|
|
676
|
+
_, data = trace.build_trace_data(tmp_path, session_id=SESSION_ID)
|
|
677
|
+
item = data["issues"][0]
|
|
678
|
+
assert len(item["evidence"]) == 2
|
|
679
|
+
assert len(item["fragments"]) == 3 # Two segments and the genuine extra Trace reference.
|
|
680
|
+
segments = [part for part in item["fragments"] if part.get("scope_kind")]
|
|
681
|
+
assert [part["id"] for part in segments] == ["S1", "S2"]
|
|
682
|
+
assert segments[0]["refs"] == segments[1]["refs"] == [1]
|
|
683
|
+
assert digests(session_dir) == before
|
|
684
|
+
|
|
685
|
+
|
|
656
686
|
def test_issue_rail_hover_does_not_rebuild_rail_or_event_list():
|
|
657
687
|
# Rebuilding the rail under the pointer replaced the buttons between mousedown and mouseup,
|
|
658
688
|
# so clicks on 定位 / segment chips never fired. Hover may redraw the swimlanes only.
|
|
@@ -135,6 +135,12 @@ assert.ok(app.cards().every(card => text(metaOf(card)) === "发生时间未记
|
|
|
135
135
|
assert.equal(app.$("progress-legend").hidden, true);
|
|
136
136
|
assert.equal(app.$("filter-note").hidden, true, "no redundant summary before filtering");
|
|
137
137
|
assert.match(text(app.$("session-attention")), /1 个会话存在验证失败的问题/);
|
|
138
|
+
// Cards flag only results that need attention; routine progress lives in the state filter and the drawers.
|
|
139
|
+
const flagsOf = card => all(card).filter(node => node.className.startsWith("flag")).map(node => [text(node), node.className]);
|
|
140
|
+
const sessionCardOf = id => app.cards().find(card => card.dataset.key === byDir(base, id).dir);
|
|
141
|
+
assert.deepEqual(flagsOf(sessionCardOf("session-b")), [["验证失败 1", "flag bad"]], "a failed verification is flagged on its session");
|
|
142
|
+
assert.deepEqual(flagsOf(sessionCardOf("session-a")), [], "pending, diagnosed and passing issues raise no flag");
|
|
143
|
+
assert.ok(app.cards().every(card => !/待诊断|已诊断|验证通过/.test(text(card))), "session cards do not repeat routine progress");
|
|
138
144
|
|
|
139
145
|
// --- issue filters stay in their own view and counts follow the visible rows -----------------------------
|
|
140
146
|
app.$("tab-category").onclick();
|
|
@@ -305,7 +311,7 @@ assert.equal(metaOf(timedCard).title, "11-06 12:55 – 11-06 13:19", "hover show
|
|
|
305
311
|
app.$("tab-category").onclick();
|
|
306
312
|
assert.match(text(app.cards()[0]), /最近发生 11-06 12:55/, "category cards name the latest session run");
|
|
307
313
|
assert.ok(app.cards().every(card => !all(card).some(node => node.className.includes("mini-bar"))), "category cards have no progress bar");
|
|
308
|
-
assert.
|
|
314
|
+
assert.ok(app.cards().every(card => !/待诊断|已诊断|验证通过/.test(text(card))), "category cards do not repeat routine progress");
|
|
309
315
|
app.$("tab-session").onclick();
|
|
310
316
|
assert.ok(app.cards().every(card => !all(card).some(node => node.className.includes("mini-bar") || node.attrs.role === "img")), "session cards have no progress bar");
|
|
311
317
|
|
|
@@ -506,6 +512,10 @@ const uncertain = JSON.parse(JSON.stringify(base));
|
|
|
506
512
|
uncertain.sessions[0].issues.forEach(issue => { issue.progress = "inconclusive"; });
|
|
507
513
|
app = boot(uncertain);
|
|
508
514
|
assert.match(text(app.$("session-attention")), /1 个会话存在“无法判断”的验证结论/);
|
|
515
|
+
assert.ok(app.cards().some(card => flagsOf(card).some(([label, cls]) => /^无法判断 \d+$/.test(label) && cls === "flag")), "inconclusive verdicts are flagged on the session card");
|
|
516
|
+
app.$("tab-category").onclick();
|
|
517
|
+
assert.ok(app.cards().some(card => flagsOf(card).some(([label]) => /^无法判断 \d+$/.test(label))), "and on the category card");
|
|
518
|
+
app.$("tab-session").onclick();
|
|
509
519
|
app.search("nothing-matches-this");
|
|
510
520
|
assert.equal(app.$("session-attention").hidden, true);
|
|
511
521
|
all(app.$("filter-note")).find(node => node.tag === "button").onclick();
|
|
@@ -128,21 +128,33 @@ const {chromium} = require("playwright");
|
|
|
128
128
|
} else {
|
|
129
129
|
assert.equal(await page.locator(".lane-zoom").count(), 0);
|
|
130
130
|
}
|
|
131
|
-
await page.locator("#record-mode").
|
|
131
|
+
assert.equal(await page.locator("select#record-mode").count(), 0, "Failure-only viewing is not a dropdown");
|
|
132
|
+
const failedSwitch = page.getByRole("button", {name:/^⚠?\s*失败 \d+$/});
|
|
133
|
+
const failedCount = Number(await page.locator("#record-failed-count").textContent());
|
|
134
|
+
assert.ok(failedCount > 0);
|
|
135
|
+
assert.ok(await failedSwitch.isVisible());
|
|
136
|
+
assert.ok(await page.locator("#record-failed").evaluate(el =>
|
|
137
|
+
el.getBoundingClientRect().top < document.getElementById("trace-scroll").getBoundingClientRect().top), "Switch sits in the heading");
|
|
138
|
+
await failedSwitch.click();
|
|
139
|
+
assert.equal(await page.locator("#record-failed").getAttribute("aria-pressed"), "true");
|
|
140
|
+
assert.match(await page.locator("#trace-count").textContent(), new RegExp(`^失败 ${failedCount} / \\d+ 条$`));
|
|
132
141
|
assert.ok(await page.locator(".trace-row.is-error").count());
|
|
133
142
|
assert.equal(await page.locator(".trace-row:not(.is-error)").count(), 0);
|
|
134
143
|
await page.locator("#trace-search").fill("no matching event");
|
|
135
|
-
assert.equal(await page.locator("#trace-count").textContent(), "0 条");
|
|
144
|
+
assert.equal(await page.locator("#trace-count").textContent(), "失败 0 / 0 条");
|
|
145
|
+
assert.equal(await page.locator("#record-failed").isEnabled(), true, "An active switch stays usable at zero");
|
|
136
146
|
assert.equal(await page.locator("#trace-list .empty").textContent(), "没有符合筛选条件的事件。");
|
|
137
|
-
await page.locator("#record-
|
|
147
|
+
await page.locator("#record-all").click();
|
|
148
|
+
assert.equal(await page.locator("#record-failed").isEnabled(), false, "Zero failures disable the inactive switch");
|
|
138
149
|
await page.locator("#trace-search").fill("");
|
|
139
150
|
assert.ok(await page.locator(".trace-row:not(.is-error)").count());
|
|
140
|
-
await page.locator("#record-
|
|
151
|
+
await page.locator("#record-failed").click();
|
|
152
|
+
assert.ok(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth), "failure switch overflows horizontally");
|
|
141
153
|
await page.locator("#trace-search").fill(failure.id);
|
|
142
154
|
const row = page.locator(`.trace-row[data-node-index="${failure.index}"]`);
|
|
143
155
|
await row.waitFor();
|
|
144
156
|
assert.ok((await row.getAttribute("class")).includes("is-error"));
|
|
145
|
-
assert.ok(await row.getByRole("img",{name:"
|
|
157
|
+
assert.ok(await row.getByRole("img",{name:"执行失败"}).isVisible());
|
|
146
158
|
assert.equal(await row.locator(".event-status").textContent(), "失败");
|
|
147
159
|
assert.equal(await row.locator(".event-meta").isVisible(), width > 800);
|
|
148
160
|
const appearance = () => row.evaluate(el => {
|
|
@@ -168,7 +180,7 @@ const {chromium} = require("playwright");
|
|
|
168
180
|
await row.evaluate(el => el.classList.add("in-fragment"));
|
|
169
181
|
const fragment = await appearance();
|
|
170
182
|
assert.ok(fragment.redTint && fragment.marker);
|
|
171
|
-
assert.ok(await row.getByRole("img",{name:"
|
|
183
|
+
assert.ok(await row.getByRole("img",{name:"执行失败"}).isVisible());
|
|
172
184
|
assert.deepEqual(errors,[]);
|
|
173
185
|
assert.deepEqual(requests,[], "Event previews must stay offline");
|
|
174
186
|
console.log(`${width}px: column sizing, failure states, selection and offline rendering passed`);
|
|
@@ -11,8 +11,9 @@ function boot() {
|
|
|
11
11
|
const elements = new Map();
|
|
12
12
|
const $ = id => {
|
|
13
13
|
if (!elements.has(id)) elements.set(id, {
|
|
14
|
-
value: "", hidden: false, style: {}, scrollTop: 0, textContent: "",
|
|
14
|
+
value: "", hidden: false, disabled: false, title: "", style: {}, scrollTop: 0, textContent: "", attrs: {},
|
|
15
15
|
parentElement: {classList: {toggle() {}}}, focus() {}, scrollIntoView() {},
|
|
16
|
+
setAttribute(name, value) { this.attrs[name] = String(value); }, getAttribute(name) { return this.attrs[name] ?? null; },
|
|
16
17
|
});
|
|
17
18
|
return elements.get(id);
|
|
18
19
|
};
|
|
@@ -152,7 +153,7 @@ test("failure-only filtering matches error styling and combines with Trace, type
|
|
|
152
153
|
app.$("record-mode").value = "error";
|
|
153
154
|
app.context.renderTraces();
|
|
154
155
|
assert.deepEqual(visible(app.rows()), [0, 2, 3, 4]);
|
|
155
|
-
assert.equal(app.$("trace-count").textContent, "4 条");
|
|
156
|
+
assert.equal(app.$("trace-count").textContent, "失败 4 / 12 条");
|
|
156
157
|
app.$("trace-search").value = "read";
|
|
157
158
|
app.context.renderTraces();
|
|
158
159
|
assert.deepEqual(visible(app.rows()), [0, 2, 3, 4], "Search must not include matching normal Events");
|
|
@@ -162,7 +163,7 @@ test("failure-only filtering matches error styling and combines with Trace, type
|
|
|
162
163
|
app.$("trace-filter").value = "1";
|
|
163
164
|
app.context.renderTraces();
|
|
164
165
|
assert.deepEqual(visible(app.rows()), []);
|
|
165
|
-
assert.equal(app.$("trace-count").textContent, "0 条");
|
|
166
|
+
assert.equal(app.$("trace-count").textContent, "失败 0 / 5 条", "The total counts T1 EVENT rows; node 3 is a TOOL");
|
|
166
167
|
app.$("type-filter").value = "TOOL";
|
|
167
168
|
app.context.renderTraces();
|
|
168
169
|
assert.deepEqual(visible(app.rows()), [3]);
|
|
@@ -188,7 +189,41 @@ test("issue navigation restores failure-only filtering and fragment expansion ca
|
|
|
188
189
|
app.context.exitIssue();
|
|
189
190
|
assert.equal(app.$("record-mode").value, "error");
|
|
190
191
|
assert.deepEqual(visible(app.rows()), [2, 4, 7]);
|
|
191
|
-
assert.equal(app.$("trace-count").textContent, "3 条");
|
|
192
|
+
assert.equal(app.$("trace-count").textContent, "失败 3 / 12 条");
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
test("the failure switch counts within the other filters, stays visible at zero and restores with the view", () => {
|
|
196
|
+
const app = boot();
|
|
197
|
+
const pressed = () => [app.$("record-all").getAttribute("aria-pressed"), app.$("record-failed").getAttribute("aria-pressed")];
|
|
198
|
+
assert.equal(app.$("record-failed-count").textContent, "0");
|
|
199
|
+
assert.equal(app.$("record-failed").disabled, true, "Zero failures are shown, not hidden, and cannot be chosen");
|
|
200
|
+
assert.deepEqual(pressed(), ["true", "false"]);
|
|
201
|
+
for (const i of [1, 2, 4]) app.capture.nodes[i].level = "ERROR";
|
|
202
|
+
app.context.renderTraces();
|
|
203
|
+
assert.equal(app.$("record-failed-count").textContent, "3");
|
|
204
|
+
assert.equal(app.$("record-failed").disabled, false);
|
|
205
|
+
assert.equal(app.$("trace-count").textContent, "12 条", "Counting failures must not filter the list");
|
|
206
|
+
app.$("trace-filter").value = "0";
|
|
207
|
+
app.context.renderTraces();
|
|
208
|
+
assert.equal(app.$("record-failed-count").textContent, "2", "Count follows the focused Trace before the switch is used");
|
|
209
|
+
app.context.setRecordMode("error");
|
|
210
|
+
assert.deepEqual(pressed(), ["false", "true"]);
|
|
211
|
+
assert.deepEqual(visible(app.rows()), [2, 4]);
|
|
212
|
+
assert.equal(app.$("trace-count").textContent, "失败 2 / 6 条");
|
|
213
|
+
app.$("trace-search").value = "no match";
|
|
214
|
+
app.context.renderTraces();
|
|
215
|
+
assert.equal(app.$("record-failed-count").textContent, "0");
|
|
216
|
+
assert.equal(app.$("record-failed").disabled, false, "An active switch stays usable at zero so the selection is visible");
|
|
217
|
+
app.$("trace-search").value = "";
|
|
218
|
+
app.context.focusEvents([0, 2, 6]);
|
|
219
|
+
assert.equal(app.$("record-mode").value, "", "Opening an event group clears the switch like other record filters");
|
|
220
|
+
assert.equal(app.$("record-failed-count").textContent, "1", "Count stays inside the chosen group");
|
|
221
|
+
app.context.exitEventFocus();
|
|
222
|
+
assert.equal(app.$("record-mode").value, "error");
|
|
223
|
+
assert.deepEqual(pressed(), ["false", "true"]);
|
|
224
|
+
app.context.setRecordMode("");
|
|
225
|
+
assert.deepEqual(pressed(), ["true", "false"]);
|
|
226
|
+
assert.deepEqual(visible(app.rows()), [0, 2, 4, 6, 8, 10]);
|
|
192
227
|
});
|
|
193
228
|
|
|
194
229
|
test("selecting an issue focuses all its fragments and preserves interleaved records", () => {
|