taskledger 0.3.0__tar.gz → 0.3.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.
- {taskledger-0.3.0 → taskledger-0.3.1}/.taskledger.toml +1 -1
- {taskledger-0.3.0 → taskledger-0.3.1}/API.md +3 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/CHANGELOG.md +63 -0
- {taskledger-0.3.0/taskledger.egg-info → taskledger-0.3.1}/PKG-INFO +21 -1
- {taskledger-0.3.0 → taskledger-0.3.1}/README.md +20 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/docs/api.rst +3 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/docs/command_contract.rst +30 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/docs/public_surface.rst +1 -1
- {taskledger-0.3.0 → taskledger-0.3.1}/docs/transfer.rst +32 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/docs/usage.rst +25 -2
- {taskledger-0.3.0 → taskledger-0.3.1}/pyproject.toml +1 -1
- {taskledger-0.3.0 → taskledger-0.3.1}/skills/taskledger/SKILL.md +6 -2
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/_version.py +3 -3
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/api/plans.py +8 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/api/project.py +7 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/cli.py +97 -5
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/cli_implement.py +5 -1
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/cli_plan.py +84 -3
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/command_inventory.py +9 -0
- taskledger-0.3.1/taskledger/domain/check.py +111 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/domain/models.py +1 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/domain/run.py +3 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/exchange.py +415 -22
- taskledger-0.3.1/taskledger/services/check_tracking.py +126 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/dashboard.py +43 -5
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/handoff.py +40 -5
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/implementation_flow.py +13 -7
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/navigation.py +12 -9
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/plan_materialization.py +4 -0
- taskledger-0.3.1/taskledger/services/plan_review.py +429 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/planning_flow.py +4 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/serve_read_model.py +4 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/task_reports.py +70 -2
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/tasks.py +12 -9
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/storage/task_store.py +42 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/web_assets/dashboard.js +41 -0
- {taskledger-0.3.0 → taskledger-0.3.1/taskledger.egg-info}/PKG-INFO +21 -1
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger.egg-info/SOURCES.txt +5 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_command_inventory.py +8 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_docs_and_skill.py +4 -0
- taskledger-0.3.1/tests/test_implementation_checks.py +349 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_no_log_feature.py +6 -0
- taskledger-0.3.1/tests/test_plan_review.py +267 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_plan_revision_workflow.py +6 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_service_boundaries.py +2 -2
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_taskledger_v2_cli.py +22 -3
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_taskledger_v2_exchange.py +549 -1
- {taskledger-0.3.0 → taskledger-0.3.1}/.codecrate.toml +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/.github/workflows/codecov.yml +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/.github/workflows/pre-commit.yml +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/.github/workflows/python-publish.yml +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/.github/workflows/tests.yml +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/.gitignore +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/.pre-commit-config.yaml +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/.readthedocs.yaml +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/.ruff.toml +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/AGENTS.md +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/LICENSE +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/Makefile +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/docs/Makefile +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/docs/architecture_taskledger_split.rst +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/docs/build.sh +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/docs/conf.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/docs/full_task_cycle.rst +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/docs/index.rst +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/docs/multi_repo.rst +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/docs/requirements.txt +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/docs/service_boundary_whitelist.rst +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/setup.cfg +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/setup.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/__init__.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/__main__.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/api/__init__.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/api/handoff.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/api/introductions.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/api/locks.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/api/questions.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/api/releases.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/api/search.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/api/task_runs.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/api/tasks.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/cli_actor.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/cli_common.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/cli_ledger.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/cli_migrate.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/cli_misc.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/cli_question.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/cli_release.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/cli_task.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/cli_validate.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/domain/__init__.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/domain/_model_utils.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/domain/active_state.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/domain/actor.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/domain/change.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/domain/event.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/domain/handoff.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/domain/lock.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/domain/plan.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/domain/policies.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/domain/question.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/domain/release.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/domain/sidecars.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/domain/states.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/domain/task.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/errors.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/ids.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/launcher.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/py.typed +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/search.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/__init__.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/actors.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/agent_logging.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/agent_transcripts.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/change_tracking.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/command_runner.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/doctor.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/doctor_checks/migration_checks.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/doctor_checks/project_scan.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/doctor_checks/task_checks.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/handoff_lifecycle.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/next_action_model.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/phase5_lock_transfer.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/plan_editing.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/plan_hash.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/plan_lint.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/releases.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/run_store.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/task_archive.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/task_collections.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/task_lifecycle.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/task_queries.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/task_repair.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/tree.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/validation.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/validation_flow.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/web_dashboard.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/services/workflow_guidance.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/storage/__init__.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/storage/agent_logs.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/storage/atomic.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/storage/common.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/storage/events.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/storage/frontmatter.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/storage/indexes.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/storage/init.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/storage/ledger_config.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/storage/locks.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/storage/meta.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/storage/migrations.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/storage/paths.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/storage/project_config.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/storage/project_identity.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/storage/repos.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/timeutils.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/web_assets/__init__.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger/web_assets/dashboard.css +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger.egg-info/dependency_links.txt +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger.egg-info/entry_points.txt +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger.egg-info/requires.txt +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/taskledger.egg-info/top_level.txt +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/__init__.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/conftest.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/support/__init__.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/support/builders.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_active_task.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_actor_harness_state.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_agent_command_logging.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_agent_session_protocol.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_atomic_fast_io.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_cli_command_contract.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_cli_import_resilience.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_command_example_linter.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_compact_mutation_output.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_delta_remaining_contracts.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_doctor.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_domain_policies.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_events.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_handoff_lifecycle.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_help_subprocess.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_implementation_change_scan.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_json_contracts.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_legacy_cleanup_contracts.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_lifecycle_policies.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_locks_audit.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_models_v1_schema.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_next_action_expired_lock.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_plan_approval_contract.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_plan_lint.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_plan_todo_materialization.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_project_root_config.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_question_add_many.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_question_filter_answers.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_question_plan_regeneration.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_release_changelog.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_search.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_serve_dashboard.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_services_dashboard.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_sidecar_collections.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_storage_bundle_layout.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_storage_common.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_storage_init.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_storage_migration.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_storage_repos.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_task_archive.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_task_events.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_task_report.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_taskledger_branch_scoped_ledgers.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_taskledger_cli_api_parity.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_tasks_service_static.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_todo_implementation_gate.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_tree_command.py +0 -0
- {taskledger-0.3.0 → taskledger-0.3.1}/tests/test_workflow_guidance.py +0 -0
|
@@ -9,7 +9,7 @@ project_uuid = "081c7c05-2d10-42b7-9b37-3d814c2f400a"
|
|
|
9
9
|
# Taskledger branch-scoped state. This block is intentionally safe to commit.
|
|
10
10
|
ledger_ref = "main"
|
|
11
11
|
ledger_parent_ref = ""
|
|
12
|
-
ledger_next_task_number =
|
|
12
|
+
ledger_next_task_number = 84
|
|
13
13
|
ledger_branch_guard = "off"
|
|
14
14
|
|
|
15
15
|
[prompt_profiles.planning]
|
|
@@ -104,6 +104,9 @@ from taskledger.errors import (
|
|
|
104
104
|
- `propose_plan`
|
|
105
105
|
- `plan_template`
|
|
106
106
|
- `upsert_plan`
|
|
107
|
+
- `PlanReviewOptions`
|
|
108
|
+
- `build_plan_review_payload`
|
|
109
|
+
- `render_plan_review`
|
|
107
110
|
- `export_plan`
|
|
108
111
|
- `amend_plan`
|
|
109
112
|
- `regenerate_plan_from_answers`
|
|
@@ -1,5 +1,68 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v0.3.1 - 2026-05-12
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Added task-scoped export/import with `--task` positional ref on export, safe ID remapping (`--id-policy preserve|renumber`), counter repair, and artifact path remapping on import. Full-ledger export remains the default; single-task archives filter task-scoped records and clear `active_task`.
|
|
8
|
+
- Added `taskledger plan review` command to show the current or specified plan version with structured JSON output and content rendering.
|
|
9
|
+
- Added `next-action` routing to recommend `plan review --version N` when a plan is awaiting approval.
|
|
10
|
+
|
|
11
|
+
### Documentation
|
|
12
|
+
|
|
13
|
+
- Updated README, command contract, and SKILL.md for task-scoped transfer workflow and `plan review` command.
|
|
14
|
+
|
|
15
|
+
### Quality
|
|
16
|
+
|
|
17
|
+
- Added regression coverage for task-scoped export/import ID mapping, conflict policy, counter repair, artifact remap, and plan review end-to-end.
|
|
18
|
+
- Full suite: 878 tests passing, ruff and mypy clean.
|
|
19
|
+
|
|
20
|
+
## v0.3.0 - 2026-05-05
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- Added agent command transcript logging: opt-in config, append-only NDJSON storage, CLI stdout/stderr tee capture, managed-shell capture, `task transcript` command, and `task report --include command-log` section. Export/import preserves transcript archives.
|
|
25
|
+
- Added planning guidance profiles: `plan guidance` command, `--include-guidance` plan template injection, and `prompt_profiles.planning` config with advisory required-fields rendering.
|
|
26
|
+
- Added transcript review mode as the default `task transcript` output, with `--raw` flag for the original table view, duplicate log ID warnings, and logical-row grouping for wrapper/managed-shell pairs.
|
|
27
|
+
- Added enriched command metadata: tier, deprecated, replaced_by, ledger_effect, workspace_effect, external_effect, and agent_safe fields on CommandSpec. Added `--tier` and `--include-deprecated` CLI filters. Deprecated `lock break` in favor of `repair lock`.
|
|
28
|
+
- Added first-class expired-lock resume path: `implement resume --repair-expired-lock` releases expired implementation locks with audit trail, and `next-action` emits `expired-lock-resume` when applicable.
|
|
29
|
+
- Added task-resource positional refs for read-only commands (`task show`, `task view`, etc.) with explicit `--task` required for destructive commands (`task cancel`, `task uncancel`, `task edit`).
|
|
30
|
+
- Added JSON usage-error envelopes for workflow positional-ref rejection and CLI parse errors.
|
|
31
|
+
- Added soft task archive: `task archive`/`task unarchive` commands, archived-task visibility filtering across list/tree/status, and slug reuse semantics.
|
|
32
|
+
- Added export/import project metadata guard, dry-run safety, and include-flag controls.
|
|
33
|
+
- Added plan revision workflow: `plan export`, `plan amend`, and `--auto-revise` with safe plan input path guard and plan.amended audit events.
|
|
34
|
+
- Added plan approval provenance: approval_source and approved_plan_hash stored on acceptance, with hash-mismatch warnings in reports.
|
|
35
|
+
- Added implement finish warning for missing git change scans.
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- Split run/lock helpers into `services/run_store.py` from the tasks.py monolith; `tasks.py` re-exports for backward compatibility.
|
|
40
|
+
- Wrapper commands now mirror inner exit status by default instead of always succeeding.
|
|
41
|
+
- Planning guidance recommendation is now integrated into `plan start` and `next-action` with a one-time viewed marker.
|
|
42
|
+
- Plan lint human output now renders summary and issue details instead of bare pass/fail.
|
|
43
|
+
- Question `answer-many` now validates repeat inputs, aliases, and provenance.
|
|
44
|
+
- Doctor mismatch guidance and verbose output improved with actionable repair hints.
|
|
45
|
+
|
|
46
|
+
### Fixed
|
|
47
|
+
|
|
48
|
+
- Fixed task report Plans section so non-accepted plans show reviewable details instead of being omitted.
|
|
49
|
+
- Fixed pre-commit `--all-files` regressions across test files.
|
|
50
|
+
|
|
51
|
+
### Documentation
|
|
52
|
+
|
|
53
|
+
- Documented planning guidance profiles in README, usage, command contract, API, and skill.
|
|
54
|
+
- Documented transcript logging, managed command capture, and review mode in usage and skill.
|
|
55
|
+
- Documented expired-lock-resume path and `--repair-expired-lock` in SKILL.md.
|
|
56
|
+
- Documented command-surface safety guidance, task-resource positional refs, and destructive-target rules in SKILL.md and command contract.
|
|
57
|
+
- Documented plan revision workflow commands and safety semantics in SKILL.md and command examples.
|
|
58
|
+
- Updated failure-review remediation hints for known mistakes in docs and skill.
|
|
59
|
+
|
|
60
|
+
### Quality
|
|
61
|
+
|
|
62
|
+
- Added regression test modules for agent command logging, expired-lock resume, task archive, and plan revision workflow.
|
|
63
|
+
- Expanded command inventory, CLI contract, JSON contract, and docs/skill tests for metadata enrichment, deprecation, targeting, and envelope behavior.
|
|
64
|
+
- Full suite: 770+ tests passing, ruff and mypy clean.
|
|
65
|
+
|
|
3
66
|
## v0.2.0 - 2026-05-03
|
|
4
67
|
|
|
5
68
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: taskledger
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Durable project-state storage and CLI for coding workflows
|
|
5
5
|
Author: Taskledger Contributors
|
|
6
6
|
Maintainer: Holger Nahrstaedt
|
|
@@ -164,6 +164,7 @@ taskledger question answer-many --text $'q-0001: Yes.\nq-0002: No.'
|
|
|
164
164
|
taskledger question status
|
|
165
165
|
taskledger plan template --from-answers --file ./plan.md
|
|
166
166
|
taskledger plan upsert --from-answers --file ./plan.md
|
|
167
|
+
taskledger plan review --version 1
|
|
167
168
|
taskledger plan lint --version 1
|
|
168
169
|
taskledger plan accept --version 1 --note "Ready."
|
|
169
170
|
|
|
@@ -512,7 +513,10 @@ for task-first handoff guidance.
|
|
|
512
513
|
```bash
|
|
513
514
|
taskledger init --project-name "Taskledger"
|
|
514
515
|
taskledger export
|
|
516
|
+
taskledger export --task task-0040
|
|
517
|
+
taskledger export task-0040
|
|
515
518
|
taskledger import ./taskledger-transfer.tar.gz --dry-run
|
|
519
|
+
taskledger import ./taskledger-task-planledger-main-task-0040-20260509T101500Z.tar.gz
|
|
516
520
|
taskledger import ./taskledger-transfer.tar.gz --replace
|
|
517
521
|
taskledger snapshot ./artifacts
|
|
518
522
|
```
|
|
@@ -521,6 +525,7 @@ Default export filenames use this policy:
|
|
|
521
525
|
|
|
522
526
|
```text
|
|
523
527
|
taskledger-export-{project_slug}-{ledger_ref}-{timestamp}.tar.gz
|
|
528
|
+
taskledger-task-{project_slug}-{ledger_ref}-{task_id}-{timestamp}.tar.gz
|
|
524
529
|
```
|
|
525
530
|
|
|
526
531
|
`project_slug` is derived from `project_name` in `taskledger.toml`. If
|
|
@@ -543,6 +548,21 @@ taskledger implement resume --reason "Continue imported implementation."
|
|
|
543
548
|
|
|
544
549
|
Use `--lock-policy keep` only for diagnostic full-fidelity lock restoration.
|
|
545
550
|
|
|
551
|
+
Single-task transfer from a config-only checkout:
|
|
552
|
+
|
|
553
|
+
```bash
|
|
554
|
+
# fresh checkout on another PC
|
|
555
|
+
taskledger init
|
|
556
|
+
taskledger task create "Fix import edge case" --slug fix-import-edge-case --description "..."
|
|
557
|
+
# ... normal plan / implementation / validation lifecycle ...
|
|
558
|
+
taskledger export task-0040
|
|
559
|
+
|
|
560
|
+
# main dev repo
|
|
561
|
+
taskledger import ./taskledger-task-planledger-main-task-0040-20260509T101500Z.tar.gz
|
|
562
|
+
taskledger task list
|
|
563
|
+
taskledger task show task-0040
|
|
564
|
+
```
|
|
565
|
+
|
|
546
566
|
## Skill packaging
|
|
547
567
|
|
|
548
568
|
Agent workflows work best when the `taskledger` skill is installed in the
|
|
@@ -121,6 +121,7 @@ taskledger question answer-many --text $'q-0001: Yes.\nq-0002: No.'
|
|
|
121
121
|
taskledger question status
|
|
122
122
|
taskledger plan template --from-answers --file ./plan.md
|
|
123
123
|
taskledger plan upsert --from-answers --file ./plan.md
|
|
124
|
+
taskledger plan review --version 1
|
|
124
125
|
taskledger plan lint --version 1
|
|
125
126
|
taskledger plan accept --version 1 --note "Ready."
|
|
126
127
|
|
|
@@ -469,7 +470,10 @@ for task-first handoff guidance.
|
|
|
469
470
|
```bash
|
|
470
471
|
taskledger init --project-name "Taskledger"
|
|
471
472
|
taskledger export
|
|
473
|
+
taskledger export --task task-0040
|
|
474
|
+
taskledger export task-0040
|
|
472
475
|
taskledger import ./taskledger-transfer.tar.gz --dry-run
|
|
476
|
+
taskledger import ./taskledger-task-planledger-main-task-0040-20260509T101500Z.tar.gz
|
|
473
477
|
taskledger import ./taskledger-transfer.tar.gz --replace
|
|
474
478
|
taskledger snapshot ./artifacts
|
|
475
479
|
```
|
|
@@ -478,6 +482,7 @@ Default export filenames use this policy:
|
|
|
478
482
|
|
|
479
483
|
```text
|
|
480
484
|
taskledger-export-{project_slug}-{ledger_ref}-{timestamp}.tar.gz
|
|
485
|
+
taskledger-task-{project_slug}-{ledger_ref}-{task_id}-{timestamp}.tar.gz
|
|
481
486
|
```
|
|
482
487
|
|
|
483
488
|
`project_slug` is derived from `project_name` in `taskledger.toml`. If
|
|
@@ -500,6 +505,21 @@ taskledger implement resume --reason "Continue imported implementation."
|
|
|
500
505
|
|
|
501
506
|
Use `--lock-policy keep` only for diagnostic full-fidelity lock restoration.
|
|
502
507
|
|
|
508
|
+
Single-task transfer from a config-only checkout:
|
|
509
|
+
|
|
510
|
+
```bash
|
|
511
|
+
# fresh checkout on another PC
|
|
512
|
+
taskledger init
|
|
513
|
+
taskledger task create "Fix import edge case" --slug fix-import-edge-case --description "..."
|
|
514
|
+
# ... normal plan / implementation / validation lifecycle ...
|
|
515
|
+
taskledger export task-0040
|
|
516
|
+
|
|
517
|
+
# main dev repo
|
|
518
|
+
taskledger import ./taskledger-task-planledger-main-task-0040-20260509T101500Z.tar.gz
|
|
519
|
+
taskledger task list
|
|
520
|
+
taskledger task show task-0040
|
|
521
|
+
```
|
|
522
|
+
|
|
503
523
|
## Skill packaging
|
|
504
524
|
|
|
505
525
|
Agent workflows work best when the `taskledger` skill is installed in the
|
|
@@ -84,6 +84,22 @@ storage, and ``taskledger plan amend`` applies structured plan-review edits:
|
|
|
84
84
|
Plan proposal commands that accept ``--file`` reject file paths under
|
|
85
85
|
``.taskledger/`` because that directory is private durable ledger state.
|
|
86
86
|
|
|
87
|
+
Plan review command
|
|
88
|
+
-------------------
|
|
89
|
+
|
|
90
|
+
``taskledger plan review`` is a read-only approval-facing plan renderer:
|
|
91
|
+
|
|
92
|
+
.. code-block:: bash
|
|
93
|
+
|
|
94
|
+
taskledger plan review [--task TASK_REF] [--version N] [--format markdown|json] [-o PATH]
|
|
95
|
+
|
|
96
|
+
Rules:
|
|
97
|
+
|
|
98
|
+
* defaults to the active task when ``--task`` is omitted;
|
|
99
|
+
* defaults to the latest proposed plan in ``plan_review`` stage when ``--version`` is omitted;
|
|
100
|
+
* renders Markdown by default and can emit JSON-formatted content with ``--format json``;
|
|
101
|
+
* when ``-o/--output`` is provided, writes rendered content to a file path.
|
|
102
|
+
|
|
87
103
|
Archive import lock policy
|
|
88
104
|
--------------------------
|
|
89
105
|
|
|
@@ -92,6 +108,7 @@ Archive imports support explicit lock handling:
|
|
|
92
108
|
.. code-block:: bash
|
|
93
109
|
|
|
94
110
|
taskledger import ./taskledger-transfer.tar.gz --replace [--lock-policy drop|quarantine|keep]
|
|
111
|
+
taskledger import ./taskledger-task-<project>-<ledger>-task-0040-<ts>.tar.gz [--id-policy preserve|renumber-on-conflict|fail-on-conflict]
|
|
95
112
|
|
|
96
113
|
The default is ``quarantine`` so imported source-machine runtime locks are not
|
|
97
114
|
restored as active ``lock.yaml`` files. ``keep`` is diagnostic-only behavior
|
|
@@ -122,6 +139,19 @@ still authoritative for import safety.
|
|
|
122
139
|
``taskledger import --dry-run`` must not mutate taskledger state for either
|
|
123
140
|
archive or JSON payload imports.
|
|
124
141
|
|
|
142
|
+
Export task selection
|
|
143
|
+
---------------------
|
|
144
|
+
|
|
145
|
+
Taskledger export supports full-ledger and task-scoped archives:
|
|
146
|
+
|
|
147
|
+
.. code-block:: bash
|
|
148
|
+
|
|
149
|
+
taskledger export
|
|
150
|
+
taskledger export ./backup.tar.gz
|
|
151
|
+
taskledger export --task task-0040
|
|
152
|
+
taskledger export task-0040
|
|
153
|
+
taskledger export task-0040 -o ./task0040.tar.gz
|
|
154
|
+
|
|
125
155
|
Positional Resource Refs
|
|
126
156
|
------------------------
|
|
127
157
|
|
|
@@ -39,7 +39,7 @@ question subcommands
|
|
|
39
39
|
plan subcommands
|
|
40
40
|
----------------
|
|
41
41
|
|
|
42
|
-
- ``plan start``, ``plan propose``, ``plan template``, ``plan upsert``, ``plan lint``, ``plan approve``, ``plan accept``, ``plan reject``, ``plan show``, ``plan diff``
|
|
42
|
+
- ``plan start``, ``plan propose``, ``plan template``, ``plan upsert``, ``plan review``, ``plan lint``, ``plan approve``, ``plan accept``, ``plan reject``, ``plan show``, ``plan diff``
|
|
43
43
|
- ``plan regenerate --from-answers``, ``plan materialize-todos``, ``plan command -- ...``
|
|
44
44
|
|
|
45
45
|
task reporting and transcripts
|
|
@@ -24,9 +24,41 @@ When no output path is passed to ``taskledger export``, taskledger writes:
|
|
|
24
24
|
|
|
25
25
|
taskledger-export-{project_slug}-{ledger_ref}-{timestamp}.tar.gz
|
|
26
26
|
|
|
27
|
+
For task-scoped exports:
|
|
28
|
+
|
|
29
|
+
.. code-block:: text
|
|
30
|
+
|
|
31
|
+
taskledger-task-{project_slug}-{ledger_ref}-{task_id}-{timestamp}.tar.gz
|
|
32
|
+
|
|
27
33
|
``project_slug`` comes from ``project_name`` (or workspace fallback). Import
|
|
28
34
|
safety still depends on UUID checks, not name matching.
|
|
29
35
|
|
|
36
|
+
Single-task transfer from a config-only checkout
|
|
37
|
+
------------------------------------------------
|
|
38
|
+
|
|
39
|
+
.. code-block:: bash
|
|
40
|
+
|
|
41
|
+
# fresh checkout on another PC
|
|
42
|
+
taskledger init
|
|
43
|
+
taskledger task create "Fix import edge case" --slug fix-import-edge-case --description "..."
|
|
44
|
+
# ... normal plan/implement/validate workflow ...
|
|
45
|
+
taskledger export task-0040
|
|
46
|
+
|
|
47
|
+
# main dev repo
|
|
48
|
+
taskledger import ./taskledger-task-planledger-main-task-0040-20260509T101500Z.tar.gz
|
|
49
|
+
taskledger task list
|
|
50
|
+
taskledger task show task-0040
|
|
51
|
+
|
|
52
|
+
Rules:
|
|
53
|
+
|
|
54
|
+
- Keep ``project_uuid`` committed in ``taskledger.toml`` / ``.taskledger.toml``.
|
|
55
|
+
- ``.taskledger/`` is local operational state and can be absent on another PC.
|
|
56
|
+
- Run ``taskledger init`` after cloning to create local state.
|
|
57
|
+
- ``taskledger export --task TASK_REF`` and ``taskledger export TASK_REF`` export task-scoped archives.
|
|
58
|
+
- Task-scoped import is additive by default; if the task id already exists locally, import renumbers and reports an id map.
|
|
59
|
+
- ``--replace`` is for full-state replacement, not the normal single-task workflow.
|
|
60
|
+
- Import repairs ``ledger_next_task_number`` so future ``task create`` ids remain unique.
|
|
61
|
+
|
|
30
62
|
Dry-run import
|
|
31
63
|
--------------
|
|
32
64
|
|
|
@@ -56,8 +56,9 @@ Task-first workflow
|
|
|
56
56
|
taskledger question add --text "Should exports include v2?"
|
|
57
57
|
taskledger question answer-many --text "q-0001: Yes."
|
|
58
58
|
taskledger plan upsert --from-answers --criterion "Accepted workflow is implemented." --file ./plan.md
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
taskledger plan review --version 1
|
|
60
|
+
taskledger plan lint --version 1
|
|
61
|
+
taskledger plan accept --version 1 --note "Ready."
|
|
61
62
|
|
|
62
63
|
Planning guidance profiles
|
|
63
64
|
--------------------------
|
|
@@ -192,6 +193,7 @@ parent and run the normal lifecycle on that child:
|
|
|
192
193
|
taskledger task follow-up rewrite-v2 "Rename submit label" --description "Small post-completion delta." --activate
|
|
193
194
|
taskledger plan start
|
|
194
195
|
taskledger plan upsert --file ./plan.md
|
|
196
|
+
taskledger plan review --version 1
|
|
195
197
|
taskledger plan accept --version 1 --note "Ready."
|
|
196
198
|
taskledger implement start
|
|
197
199
|
taskledger validate start
|
|
@@ -474,7 +476,11 @@ Export and snapshots
|
|
|
474
476
|
|
|
475
477
|
taskledger init --project-name "Taskledger"
|
|
476
478
|
taskledger export
|
|
479
|
+
taskledger export --task task-0040
|
|
480
|
+
taskledger export task-0040
|
|
477
481
|
taskledger import ./taskledger-transfer.tar.gz --dry-run
|
|
482
|
+
taskledger import ./taskledger-task-planledger-main-task-0040-20260509T101500Z.tar.gz
|
|
483
|
+
taskledger import ./taskledger-task-planledger-main-task-0040-20260509T101500Z.tar.gz --id-policy fail-on-conflict
|
|
478
484
|
taskledger import ./taskledger-transfer.tar.gz --replace
|
|
479
485
|
taskledger snapshot ./artifacts
|
|
480
486
|
|
|
@@ -483,6 +489,7 @@ Default export filenames are project-specific:
|
|
|
483
489
|
.. code-block:: text
|
|
484
490
|
|
|
485
491
|
taskledger-export-{project_slug}-{ledger_ref}-{timestamp}.tar.gz
|
|
492
|
+
taskledger-task-{project_slug}-{ledger_ref}-{task_id}-{timestamp}.tar.gz
|
|
486
493
|
|
|
487
494
|
``project_slug`` is derived from ``project_name`` in ``taskledger.toml``.
|
|
488
495
|
If unset, taskledger falls back to the workspace directory name.
|
|
@@ -503,3 +510,19 @@ runtime locks by default. For an imported in-progress implementation, run:
|
|
|
503
510
|
|
|
504
511
|
Use ``--lock-policy keep`` only when you explicitly want diagnostic lock
|
|
505
512
|
restoration behavior.
|
|
513
|
+
|
|
514
|
+
Single-task transfer from a config-only checkout
|
|
515
|
+
------------------------------------------------
|
|
516
|
+
|
|
517
|
+
.. code-block:: bash
|
|
518
|
+
|
|
519
|
+
# fresh checkout on another PC
|
|
520
|
+
taskledger init
|
|
521
|
+
taskledger task create "Fix import edge case" --slug fix-import-edge-case --description "..."
|
|
522
|
+
# ... normal plan / implementation / validation lifecycle ...
|
|
523
|
+
taskledger export task-0040
|
|
524
|
+
|
|
525
|
+
# main dev repo
|
|
526
|
+
taskledger import ./taskledger-task-planledger-main-task-0040-20260509T101500Z.tar.gz
|
|
527
|
+
taskledger task list
|
|
528
|
+
taskledger task show task-0040
|
|
@@ -121,7 +121,7 @@ If any `taskledger ...` command fails with a Python traceback before taskledger
|
|
|
121
121
|
19. A proposed plan must include concrete `acceptance_criteria` and `todos` in front matter unless the user explicitly says the task is trivial.
|
|
122
122
|
20. After writing the plan, do not run `taskledger repair lock`; planning locks are released by plan proposal/upsert. Run `taskledger next-action`.
|
|
123
123
|
21. After `taskledger plan upsert --from-answers`, run `taskledger question status`. If it still reports `Plan regeneration needed: True`, do not ask for approval. Inspect `taskledger question answers`, `taskledger plan show --version N`, and `taskledger doctor`.
|
|
124
|
-
22. Before asking the user to approve, run `taskledger plan
|
|
124
|
+
22. Before asking the user to approve, run `taskledger plan review --version N` and paste or summarize the rendered review. Then run `taskledger plan lint --version N` if the review did not include lint. Do not record approval until the user explicitly approves.
|
|
125
125
|
23. Record approval only with clear user intent such as approve, accept, go ahead, or start implementation. Prefer `taskledger plan accept --version N --note "User approved in harness: ..."` for normal chat approval. Use `taskledger plan approve --version N --actor user --approval-source explicit_chat --note "..."` only when explicit actor/source metadata is needed (advanced).
|
|
126
126
|
24. Never replace a user-provided rich plan with only generated YAML criteria and todos. Preserve the user's plan body after the front matter and use front matter only to expose machine-readable fields to Taskledger.
|
|
127
127
|
25. A Taskledger plan is not just YAML front matter. The YAML block is for machine-readable `goal`, `acceptance_criteria`, `todos`, file links, and test commands. The rich human plan must remain as Markdown after the second `---`. Before approval, inspect `taskledger plan show --version N` or the saved `plan-vN.md` and verify that the accepted plan body is non-empty and contains the implementation rationale.
|
|
@@ -142,7 +142,7 @@ The plan file should use version ids like `plan-v1`, `plan-v2` in references. Do
|
|
|
142
142
|
- `taskledger implement change --path ... --kind edit --summary "..."`
|
|
143
143
|
- Run verification through `taskledger implement command -- ...` so exit code and output are recorded.
|
|
144
144
|
- `implement command` mirrors the inner command exit code by default. Use `--allow-failure` when you intentionally want to record a non-zero command without failing the wrapper command.
|
|
145
|
-
- Mark each todo done only after the relevant command or inspection evidence exists: `taskledger todo done <todo-id> --evidence "
|
|
145
|
+
- Mark each todo done only after the relevant command or inspection evidence exists: `taskledger todo done <todo-id> --evidence "check-NNNN exited 0"`.
|
|
146
146
|
- Optional: add `--source planner|implementer|user` to override the inferred source, though this is rarely needed.
|
|
147
147
|
6. `taskledger implement checklist` after each meaningful change to track progress.
|
|
148
148
|
7. In Git workspaces, prefer `taskledger implement scan-changes --from-git --summary "..."` before `implement finish` so change evidence includes a git-backed reconciliation checkpoint.
|
|
@@ -321,6 +321,7 @@ taskledger next-action
|
|
|
321
321
|
taskledger plan guidance
|
|
322
322
|
taskledger plan template --from-answers --file ./plan.md
|
|
323
323
|
taskledger plan upsert --from-answers --file ./plan.md
|
|
324
|
+
taskledger plan review --version 1
|
|
324
325
|
taskledger plan lint --version 1
|
|
325
326
|
taskledger plan accept --version 1 --note "User approved in harness."
|
|
326
327
|
taskledger context --for implementation --format markdown
|
|
@@ -330,6 +331,9 @@ taskledger context --for code-reviewer --run run-0008
|
|
|
330
331
|
taskledger release tag 0.4.1 --at-task task-0030 --note "0.4.1 released"
|
|
331
332
|
taskledger release changelog 0.4.2 --since 0.4.1 --until-task task-0035 --output /tmp/taskledger-0.4.2-changelog-source.md
|
|
332
333
|
taskledger import ./taskledger-transfer.tar.gz --dry-run
|
|
334
|
+
taskledger export --task task-0040
|
|
335
|
+
taskledger export task-0040 -o ./task0040.tar.gz
|
|
336
|
+
taskledger import ./task0040.tar.gz --id-policy renumber-on-conflict
|
|
333
337
|
taskledger ledger status
|
|
334
338
|
taskledger ledger fork feature-a
|
|
335
339
|
taskledger ledger switch main
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.3.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 3,
|
|
21
|
+
__version__ = version = '0.3.1'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 3, 1)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g9f557bd45'
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
2
|
|
|
3
3
|
from taskledger.services.plan_lint import lint_plan
|
|
4
|
+
from taskledger.services.plan_review import (
|
|
5
|
+
PlanReviewOptions,
|
|
6
|
+
build_plan_review_payload,
|
|
7
|
+
render_plan_review,
|
|
8
|
+
)
|
|
4
9
|
from taskledger.services.tasks import (
|
|
5
10
|
amend_plan,
|
|
6
11
|
approve_plan,
|
|
@@ -36,6 +41,9 @@ __all__ = [
|
|
|
36
41
|
"revise_plan",
|
|
37
42
|
"run_planning_command",
|
|
38
43
|
"lint_plan",
|
|
44
|
+
"PlanReviewOptions",
|
|
45
|
+
"build_plan_review_payload",
|
|
46
|
+
"render_plan_review",
|
|
39
47
|
"plan_guidance",
|
|
40
48
|
]
|
|
41
49
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from collections.abc import Sequence
|
|
3
4
|
from pathlib import Path
|
|
4
5
|
from typing import Any, cast
|
|
5
6
|
|
|
@@ -265,6 +266,8 @@ def project_export_archive(
|
|
|
265
266
|
output_path: Path | None = None,
|
|
266
267
|
include_bodies: bool = True,
|
|
267
268
|
include_run_artifacts: bool = False,
|
|
269
|
+
task_refs: Sequence[str] = (),
|
|
270
|
+
overwrite: bool = False,
|
|
268
271
|
) -> dict[str, object]:
|
|
269
272
|
"""Export current-ledger state into a compressed archive file."""
|
|
270
273
|
return write_project_archive(
|
|
@@ -272,6 +275,8 @@ def project_export_archive(
|
|
|
272
275
|
output_path=output_path,
|
|
273
276
|
include_bodies=include_bodies,
|
|
274
277
|
include_run_artifacts=include_run_artifacts,
|
|
278
|
+
task_refs=task_refs,
|
|
279
|
+
overwrite=overwrite,
|
|
275
280
|
)
|
|
276
281
|
|
|
277
282
|
|
|
@@ -282,6 +287,7 @@ def project_import_archive(
|
|
|
282
287
|
replace: bool = False,
|
|
283
288
|
dry_run: bool = False,
|
|
284
289
|
lock_policy: str = "quarantine",
|
|
290
|
+
id_policy: str = "preserve",
|
|
285
291
|
) -> dict[str, object]:
|
|
286
292
|
"""Import a taskledger archive into the current project."""
|
|
287
293
|
return import_project_archive(
|
|
@@ -290,6 +296,7 @@ def project_import_archive(
|
|
|
290
296
|
replace=replace,
|
|
291
297
|
dry_run=dry_run,
|
|
292
298
|
lock_policy=lock_policy,
|
|
299
|
+
id_policy=id_policy,
|
|
293
300
|
)
|
|
294
301
|
|
|
295
302
|
|
|
@@ -1090,12 +1090,41 @@ def repair_task_dirs_command(ctx: typer.Context) -> None:
|
|
|
1090
1090
|
)
|
|
1091
1091
|
|
|
1092
1092
|
|
|
1093
|
+
def _looks_like_archive_output_target(value: str) -> bool:
|
|
1094
|
+
candidate = value.strip()
|
|
1095
|
+
lowered = candidate.lower()
|
|
1096
|
+
if (
|
|
1097
|
+
lowered.endswith(".tar.gz")
|
|
1098
|
+
or lowered.endswith(".tgz")
|
|
1099
|
+
or lowered.endswith(".json")
|
|
1100
|
+
):
|
|
1101
|
+
return True
|
|
1102
|
+
path = Path(candidate)
|
|
1103
|
+
if path.is_absolute():
|
|
1104
|
+
return True
|
|
1105
|
+
if "/" in candidate or "\\" in candidate:
|
|
1106
|
+
return True
|
|
1107
|
+
if path.parent != Path("."):
|
|
1108
|
+
return True
|
|
1109
|
+
return False
|
|
1110
|
+
|
|
1111
|
+
|
|
1093
1112
|
@app.command("export")
|
|
1094
1113
|
def export_command(
|
|
1095
1114
|
ctx: typer.Context,
|
|
1115
|
+
target_or_output: Annotated[
|
|
1116
|
+
str | None,
|
|
1117
|
+
typer.Argument(
|
|
1118
|
+
help="Task ref convenience selector or output archive path (.tar.gz)."
|
|
1119
|
+
),
|
|
1120
|
+
] = None,
|
|
1121
|
+
task_ref: Annotated[
|
|
1122
|
+
str | None,
|
|
1123
|
+
typer.Option("--task", help="Task ref to export as task-scoped archive."),
|
|
1124
|
+
] = None,
|
|
1096
1125
|
output: Annotated[
|
|
1097
1126
|
Path | None,
|
|
1098
|
-
typer.
|
|
1127
|
+
typer.Option("--output", "-o", help="Output archive path (.tar.gz)."),
|
|
1099
1128
|
] = None,
|
|
1100
1129
|
include_bodies: Annotated[
|
|
1101
1130
|
bool,
|
|
@@ -1118,20 +1147,61 @@ def export_command(
|
|
|
1118
1147
|
) -> None:
|
|
1119
1148
|
state = ctx.obj
|
|
1120
1149
|
assert isinstance(state, CLIState)
|
|
1121
|
-
|
|
1150
|
+
resolved_output = output
|
|
1151
|
+
task_refs: list[str] = []
|
|
1152
|
+
if task_ref is not None:
|
|
1153
|
+
task_refs = [resolve_cli_task(state.cwd, task_ref).id]
|
|
1154
|
+
if target_or_output is not None:
|
|
1155
|
+
if output is not None:
|
|
1156
|
+
emit_error(
|
|
1157
|
+
ctx,
|
|
1158
|
+
LaunchError(
|
|
1159
|
+
"export received both positional output and --output. Use one."
|
|
1160
|
+
),
|
|
1161
|
+
)
|
|
1162
|
+
raise typer.Exit(code=2)
|
|
1163
|
+
resolved_output = Path(target_or_output)
|
|
1164
|
+
elif target_or_output is not None:
|
|
1165
|
+
if _looks_like_archive_output_target(target_or_output):
|
|
1166
|
+
if output is not None:
|
|
1167
|
+
emit_error(
|
|
1168
|
+
ctx,
|
|
1169
|
+
LaunchError(
|
|
1170
|
+
"export received both positional output and --output. Use one."
|
|
1171
|
+
),
|
|
1172
|
+
)
|
|
1173
|
+
raise typer.Exit(code=2)
|
|
1174
|
+
resolved_output = Path(target_or_output)
|
|
1175
|
+
else:
|
|
1176
|
+
try:
|
|
1177
|
+
task_refs = [resolve_cli_task(state.cwd, target_or_output).id]
|
|
1178
|
+
except LaunchError as exc:
|
|
1179
|
+
emit_error(
|
|
1180
|
+
ctx,
|
|
1181
|
+
LaunchError(
|
|
1182
|
+
f"No task found for '{target_or_output}'. To write an archive "
|
|
1183
|
+
"to that filename, use: taskledger export -o "
|
|
1184
|
+
f"{target_or_output}.tar.gz"
|
|
1185
|
+
),
|
|
1186
|
+
)
|
|
1187
|
+
raise typer.Exit(code=launch_error_exit_code(exc)) from exc
|
|
1188
|
+
if resolved_output is not None and resolved_output.exists() and not overwrite:
|
|
1122
1189
|
emit_error(
|
|
1123
1190
|
ctx,
|
|
1124
1191
|
LaunchError(
|
|
1125
|
-
|
|
1192
|
+
"Output file already exists: "
|
|
1193
|
+
f"{resolved_output}. Use --overwrite to replace."
|
|
1126
1194
|
),
|
|
1127
1195
|
)
|
|
1128
1196
|
raise typer.Exit(code=1)
|
|
1129
1197
|
try:
|
|
1130
1198
|
payload = project_export_archive(
|
|
1131
1199
|
state.cwd,
|
|
1132
|
-
output_path=
|
|
1200
|
+
output_path=resolved_output,
|
|
1133
1201
|
include_bodies=include_bodies,
|
|
1134
1202
|
include_run_artifacts=include_run_artifacts,
|
|
1203
|
+
task_refs=task_refs,
|
|
1204
|
+
overwrite=overwrite,
|
|
1135
1205
|
)
|
|
1136
1206
|
except LaunchError as exc:
|
|
1137
1207
|
emit_error(ctx, exc)
|
|
@@ -1148,6 +1218,7 @@ def export_command(
|
|
|
1148
1218
|
f"exported taskledger archive: {payload['path']}\n"
|
|
1149
1219
|
f"project: {project_label}\n"
|
|
1150
1220
|
f"ledger: {payload['ledger_ref']}\n"
|
|
1221
|
+
f"scope: {payload.get('archive_scope', 'ledger')}\n"
|
|
1151
1222
|
f"tasks: {counts.get('tasks', 0)}"
|
|
1152
1223
|
)
|
|
1153
1224
|
emit_payload(ctx, payload, human=human)
|
|
@@ -1172,6 +1243,16 @@ def import_command(
|
|
|
1172
1243
|
help="How imported live locks are handled: drop, quarantine, keep.",
|
|
1173
1244
|
),
|
|
1174
1245
|
] = "quarantine",
|
|
1246
|
+
id_policy: Annotated[
|
|
1247
|
+
str,
|
|
1248
|
+
typer.Option(
|
|
1249
|
+
"--id-policy",
|
|
1250
|
+
help=(
|
|
1251
|
+
"Task ID conflict policy for task archives: "
|
|
1252
|
+
"preserve, renumber-on-conflict, fail-on-conflict."
|
|
1253
|
+
),
|
|
1254
|
+
),
|
|
1255
|
+
] = "preserve",
|
|
1175
1256
|
) -> None:
|
|
1176
1257
|
state = ctx.obj
|
|
1177
1258
|
assert isinstance(state, CLIState)
|
|
@@ -1210,6 +1291,7 @@ def import_command(
|
|
|
1210
1291
|
replace=replace,
|
|
1211
1292
|
dry_run=dry_run,
|
|
1212
1293
|
lock_policy=lock_policy,
|
|
1294
|
+
id_policy=id_policy,
|
|
1213
1295
|
)
|
|
1214
1296
|
except LaunchError as exc:
|
|
1215
1297
|
emit_error(ctx, exc)
|
|
@@ -1234,8 +1316,18 @@ def import_command(
|
|
|
1234
1316
|
f"imported taskledger archive: {source}\n"
|
|
1235
1317
|
f"project: {project_label}\n"
|
|
1236
1318
|
f"ledger: {payload['ledger_ref']}\n"
|
|
1237
|
-
f"replace: {payload['replace']}"
|
|
1319
|
+
f"replace: {payload['replace']}\n"
|
|
1320
|
+
f"scope: {payload.get('archive_scope', 'ledger')}"
|
|
1238
1321
|
)
|
|
1322
|
+
task_id_map = payload.get("task_id_map")
|
|
1323
|
+
if isinstance(task_id_map, dict) and task_id_map:
|
|
1324
|
+
id_lines = ["id map:"]
|
|
1325
|
+
for source_id, target_id in sorted(task_id_map.items()):
|
|
1326
|
+
if source_id == target_id:
|
|
1327
|
+
id_lines.append(f" {source_id} -> {target_id}")
|
|
1328
|
+
else:
|
|
1329
|
+
id_lines.append(f" {source_id} -> {target_id} renumbered")
|
|
1330
|
+
human = f"{human}\n" + "\n".join(id_lines)
|
|
1239
1331
|
if isinstance(payload.get("next_command"), str):
|
|
1240
1332
|
human = f"{human}\nnext: {payload['next_command']}"
|
|
1241
1333
|
emit_payload(ctx, payload, human=human)
|
|
@@ -307,10 +307,14 @@ def command_command(
|
|
|
307
307
|
except LaunchError as exc:
|
|
308
308
|
emit_error(ctx, exc)
|
|
309
309
|
raise typer.Exit(code=launch_error_exit_code(exc)) from exc
|
|
310
|
+
check_data = payload.get("check") or {}
|
|
310
311
|
emit_payload(
|
|
311
312
|
ctx,
|
|
312
313
|
payload,
|
|
313
|
-
human=
|
|
314
|
+
human=(
|
|
315
|
+
f"recorded check {check_data.get('check_id', '?')}"
|
|
316
|
+
f" exit={payload['exit_code']}"
|
|
317
|
+
),
|
|
314
318
|
)
|
|
315
319
|
raw_exit_code = payload.get("exit_code", 0)
|
|
316
320
|
if isinstance(raw_exit_code, int):
|