agentpack-cli 0.3.17__tar.gz → 0.3.19__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.
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/PKG-INFO +5 -5
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/README.md +4 -4
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/pyproject.toml +1 -1
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/__init__.py +1 -1
- agentpack_cli-0.3.19/src/agentpack/analysis/python_ast.py +12 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/analysis/python_imports.py +3 -1
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/analysis/role_inference.py +2 -1
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/analysis/symbols.py +2 -1
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/application/pack_service.py +49 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/cli.py +10 -0
- agentpack_cli-0.3.19/src/agentpack/commands/compress_output.py +33 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/init.py +19 -11
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/learn.py +113 -4
- agentpack_cli-0.3.19/src/agentpack/commands/memory.py +45 -0
- agentpack_cli-0.3.19/src/agentpack/commands/perf.py +69 -0
- agentpack_cli-0.3.19/src/agentpack/commands/release_check.py +278 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/release_cmd.py +11 -1
- agentpack_cli-0.3.19/src/agentpack/commands/retrieve.py +53 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/stats.py +13 -0
- agentpack_cli-0.3.19/src/agentpack/commands/wrap.py +114 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/core/config.py +24 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/core/models.py +1 -0
- agentpack_cli-0.3.19/src/agentpack/core/pack_registry.py +259 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/dashboard/collectors.py +187 -2
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/dashboard/models.py +3 -0
- agentpack_cli-0.3.19/src/agentpack/dashboard/renderers.py +382 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/learning/collector.py +29 -1
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/learning/extractor.py +90 -2
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/learning/feedback.py +110 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/learning/models.py +12 -0
- agentpack_cli-0.3.19/src/agentpack/learning/provider.py +180 -0
- agentpack_cli-0.3.19/src/agentpack/learning/renderers.py +366 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/mcp_server.py +57 -0
- agentpack_cli-0.3.19/src/agentpack/output_compression/__init__.py +3 -0
- agentpack_cli-0.3.19/src/agentpack/output_compression/core.py +161 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/renderers/compact.py +11 -7
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/renderers/markdown.py +39 -28
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/router/models.py +1 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/router/parser.py +1 -0
- agentpack_cli-0.3.19/src/agentpack/session/events.py +63 -0
- agentpack_cli-0.3.17/src/agentpack/commands/release_check.py +0 -119
- agentpack_cli-0.3.17/src/agentpack/dashboard/renderers.py +0 -275
- agentpack_cli-0.3.17/src/agentpack/learning/provider.py +0 -52
- agentpack_cli-0.3.17/src/agentpack/learning/renderers.py +0 -235
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/.gitignore +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/LICENSE +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/adapters/__init__.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/adapters/antigravity.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/adapters/base.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/adapters/claude.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/adapters/codex.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/adapters/cursor.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/adapters/detect.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/adapters/generic.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/adapters/windsurf.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/analysis/__init__.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/analysis/dependency_graph.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/analysis/go_imports.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/analysis/java_imports.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/analysis/js_ts_imports.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/analysis/monorepo.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/analysis/naming_signals.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/analysis/ranking.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/analysis/repo_map.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/analysis/rust_imports.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/analysis/task_classifier.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/analysis/tests.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/application/__init__.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/__init__.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/_shared.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/benchmark.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/ci_cmd.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/claude_cmd.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/dashboard.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/dev_check.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/diagnose_selection.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/diff.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/doctor.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/eval_cmd.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/explain.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/guard.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/hook_cmd.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/ignore_cmd.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/install.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/mcp_cmd.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/migrate.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/monitor.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/next_cmd.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/pack.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/quickstart.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/repair.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/route.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/scan.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/skills.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/start_cmd.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/state_cmd.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/status.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/summarize.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/task_cmd.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/threads.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/tune.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/verify_wheel.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/watch.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/commands/workflow_cmd.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/core/__init__.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/core/bootstrap.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/core/cache.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/core/changed_paths.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/core/context_pack.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/core/diff.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/core/evals.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/core/execution_state.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/core/git.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/core/git_hooks.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/core/global_install.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/core/ignore.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/core/loop_protocol.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/core/merkle.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/core/redactor.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/core/scanner.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/core/snapshot.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/core/task_freshness.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/core/thread_context.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/core/token_estimator.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/core/vscode_tasks.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/dashboard/__init__.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/data/agentpack.md +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/installers/__init__.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/installers/antigravity.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/installers/claude.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/installers/codex.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/installers/cursor.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/installers/windsurf.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/integrations/__init__.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/integrations/agents.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/integrations/git_hooks.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/integrations/global_install.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/integrations/platform.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/integrations/vscode_tasks.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/learning/__init__.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/learning/lesson_ranker.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/learning/quality.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/learning/skill_map.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/renderers/__init__.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/renderers/receipts.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/router/__init__.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/router/discovery.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/router/prompt_builder.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/router/scoring.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/router/service.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/router/skills_index.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/session/__init__.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/session/state.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/summaries/__init__.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/summaries/base.py +0 -0
- {agentpack_cli-0.3.17 → agentpack_cli-0.3.19}/src/agentpack/summaries/offline.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentpack-cli
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.19
|
|
4
4
|
Summary: Local MCP context router for Claude Code, Codex, Cursor, and AI coding agents.
|
|
5
5
|
License: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -55,7 +55,7 @@ Claude Code, Codex, Cursor, and other coding agents can waste tool calls redisco
|
|
|
55
55
|
|
|
56
56
|
AgentPack gives them a ranked map of likely relevant files, tests, rules, and skills for each task. It analyzes your repo locally and packages compact context for CLI and MCP workflows.
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
How it works: AgentPack compresses repo context into ranked packs, caches scans/summaries/pack metadata for fast refreshes, and retrieves exact file or symbol blocks later when an agent needs more detail. Rendered packs also put stable instructions before volatile task, timestamp, git, and file sections so provider prompt-prefix caches can reuse the front of repeated refreshes. No cloud indexing, embeddings, or API calls are required for scan, summarize, rank, pack, stats, or benchmark.
|
|
59
59
|
|
|
60
60
|
Try the read-only task router without writing context files:
|
|
61
61
|
|
|
@@ -141,12 +141,12 @@ Suggested commands:
|
|
|
141
141
|
|
|
142
142
|
- **Task-focused packing**: ranks files from git changes, task terms, symbols, imports, related tests, configs, churn, repo history, and deterministic offline summaries.
|
|
143
143
|
- **Budget-aware compression**: emits `full`, `diff`, `symbols`, `skeleton`, or `summary` views instead of all-or-nothing file dumps.
|
|
144
|
-
- **Rendered-token accounting**: budgets against
|
|
145
|
-
- **Reserve buckets**: changed files, tests, docs, and dependencies each get protected selection capacity so one dirty area cannot starve the others.
|
|
144
|
+
- **Rendered-token accounting and reserve buckets**: budgets against actual markdown while protecting changed files, tests, docs, and dependencies.
|
|
146
145
|
- **Execution state**: optional task state files and git-derived fallback status show whether work is planned, in progress, blocked, done, committed, or committed but not pushed.
|
|
147
146
|
- **Thread-scoped context**: explicit `--thread <id>` or `--thread auto` isolates task/context files for multiple agents in one repo and warns on same-branch file overlap.
|
|
148
147
|
- **Task router**: MCP and CLI surfaces route a task to relevant files, scoped rules, installed skills, suggested commands, and safety warnings without executing skills automatically.
|
|
149
|
-
- **
|
|
148
|
+
- **Reversible registry and learning layer**: retrieves packed context by block ID, writes developer lessons, and feeds bounded selected-file miss feedback into future ranking.
|
|
149
|
+
- **Runtime scorecard and output compression**: `perf --history` tracks activity, while `compress-output` preserves failures, paths, diffs, and search hits from noisy logs.
|
|
150
150
|
- **Agent integrations**: installs Claude Code, Cursor, Windsurf, Codex, Antigravity, VS Code tasks, git hooks, and MCP configuration.
|
|
151
151
|
- **Local and measurable**: no API calls for scan, summarize, rank, pack, stats, or benchmark; quality is measured with expected-file evals.
|
|
152
152
|
|
|
@@ -14,7 +14,7 @@ Claude Code, Codex, Cursor, and other coding agents can waste tool calls redisco
|
|
|
14
14
|
|
|
15
15
|
AgentPack gives them a ranked map of likely relevant files, tests, rules, and skills for each task. It analyzes your repo locally and packages compact context for CLI and MCP workflows.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
How it works: AgentPack compresses repo context into ranked packs, caches scans/summaries/pack metadata for fast refreshes, and retrieves exact file or symbol blocks later when an agent needs more detail. Rendered packs also put stable instructions before volatile task, timestamp, git, and file sections so provider prompt-prefix caches can reuse the front of repeated refreshes. No cloud indexing, embeddings, or API calls are required for scan, summarize, rank, pack, stats, or benchmark.
|
|
18
18
|
|
|
19
19
|
Try the read-only task router without writing context files:
|
|
20
20
|
|
|
@@ -100,12 +100,12 @@ Suggested commands:
|
|
|
100
100
|
|
|
101
101
|
- **Task-focused packing**: ranks files from git changes, task terms, symbols, imports, related tests, configs, churn, repo history, and deterministic offline summaries.
|
|
102
102
|
- **Budget-aware compression**: emits `full`, `diff`, `symbols`, `skeleton`, or `summary` views instead of all-or-nothing file dumps.
|
|
103
|
-
- **Rendered-token accounting**: budgets against
|
|
104
|
-
- **Reserve buckets**: changed files, tests, docs, and dependencies each get protected selection capacity so one dirty area cannot starve the others.
|
|
103
|
+
- **Rendered-token accounting and reserve buckets**: budgets against actual markdown while protecting changed files, tests, docs, and dependencies.
|
|
105
104
|
- **Execution state**: optional task state files and git-derived fallback status show whether work is planned, in progress, blocked, done, committed, or committed but not pushed.
|
|
106
105
|
- **Thread-scoped context**: explicit `--thread <id>` or `--thread auto` isolates task/context files for multiple agents in one repo and warns on same-branch file overlap.
|
|
107
106
|
- **Task router**: MCP and CLI surfaces route a task to relevant files, scoped rules, installed skills, suggested commands, and safety warnings without executing skills automatically.
|
|
108
|
-
- **
|
|
107
|
+
- **Reversible registry and learning layer**: retrieves packed context by block ID, writes developer lessons, and feeds bounded selected-file miss feedback into future ranking.
|
|
108
|
+
- **Runtime scorecard and output compression**: `perf --history` tracks activity, while `compress-output` preserves failures, paths, diffs, and search hits from noisy logs.
|
|
109
109
|
- **Agent integrations**: installs Claude Code, Cursor, Windsurf, Codex, Antigravity, VS Code tasks, git hooks, and MCP configuration.
|
|
110
110
|
- **Local and measurable**: no API calls for scan, summarize, rank, pack, stats, or benchmark; quality is measured with expected-file evals.
|
|
111
111
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import ast
|
|
4
|
+
import warnings
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def parse_python_source(source: str, path: Path | str) -> ast.Module:
|
|
9
|
+
"""Parse scanned Python source without surfacing user-code SyntaxWarnings."""
|
|
10
|
+
with warnings.catch_warnings():
|
|
11
|
+
warnings.simplefilter("ignore", SyntaxWarning)
|
|
12
|
+
return ast.parse(source, filename=str(path))
|
|
@@ -3,11 +3,13 @@ from __future__ import annotations
|
|
|
3
3
|
import ast
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
|
|
6
|
+
from agentpack.analysis.python_ast import parse_python_source
|
|
7
|
+
|
|
6
8
|
|
|
7
9
|
def extract_imports(path: Path, text: str | None = None) -> list[str]:
|
|
8
10
|
try:
|
|
9
11
|
source = text if text is not None else path.read_text(errors="replace")
|
|
10
|
-
tree =
|
|
12
|
+
tree = parse_python_source(source, path)
|
|
11
13
|
except SyntaxError:
|
|
12
14
|
return []
|
|
13
15
|
|
|
@@ -6,6 +6,7 @@ from collections import defaultdict
|
|
|
6
6
|
from dataclasses import dataclass, field
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
|
|
9
|
+
from agentpack.analysis.python_ast import parse_python_source
|
|
9
10
|
from agentpack.core.models import Symbol
|
|
10
11
|
|
|
11
12
|
|
|
@@ -239,7 +240,7 @@ def extract_failure_hints(text: str) -> list[str]:
|
|
|
239
240
|
|
|
240
241
|
def _python_intelligence(path: str, text: str, symbols: list[Symbol]) -> CodeIntelligence:
|
|
241
242
|
try:
|
|
242
|
-
tree =
|
|
243
|
+
tree = parse_python_source(text, path)
|
|
243
244
|
except SyntaxError:
|
|
244
245
|
return CodeIntelligence(defines=[s.name for s in symbols[:40]])
|
|
245
246
|
|
|
@@ -4,13 +4,14 @@ import ast
|
|
|
4
4
|
import re
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
|
|
7
|
+
from agentpack.analysis.python_ast import parse_python_source
|
|
7
8
|
from agentpack.core.models import Symbol
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
def extract_python_symbols(path: Path) -> list[Symbol]:
|
|
11
12
|
try:
|
|
12
13
|
source = path.read_text(errors="replace")
|
|
13
|
-
tree =
|
|
14
|
+
tree = parse_python_source(source, path)
|
|
14
15
|
except (SyntaxError, OSError):
|
|
15
16
|
return []
|
|
16
17
|
|
|
@@ -27,6 +27,7 @@ from agentpack.core.models import (
|
|
|
27
27
|
ScanResult,
|
|
28
28
|
SelectedFile,
|
|
29
29
|
)
|
|
30
|
+
from agentpack.core.pack_registry import save_pack_registry
|
|
30
31
|
from agentpack.core.task_freshness import read_task_md, task_metadata
|
|
31
32
|
from agentpack.core.thread_context import (
|
|
32
33
|
append_thread_index,
|
|
@@ -36,6 +37,7 @@ from agentpack.core.thread_context import (
|
|
|
36
37
|
thread_paths,
|
|
37
38
|
)
|
|
38
39
|
from agentpack.core.token_estimator import estimate_tokens
|
|
40
|
+
from agentpack.learning.feedback import ranking_feedback_boosts
|
|
39
41
|
from agentpack.renderers.markdown import render_claude, render_generic
|
|
40
42
|
from agentpack.analysis.ranking import (
|
|
41
43
|
build_keyword_plan,
|
|
@@ -59,6 +61,7 @@ from agentpack.analysis.task_classifier import classify_task
|
|
|
59
61
|
from agentpack.analysis.tests import find_related_tests
|
|
60
62
|
from agentpack.analysis import dependency_graph as dep_graph_mod
|
|
61
63
|
from agentpack.summaries.base import build_all_summaries
|
|
64
|
+
from agentpack.session.events import record_event
|
|
62
65
|
|
|
63
66
|
|
|
64
67
|
@dataclass
|
|
@@ -267,6 +270,7 @@ class FileRanker:
|
|
|
267
270
|
changes.all_changed,
|
|
268
271
|
generic_ratio=generic_ratio,
|
|
269
272
|
)
|
|
273
|
+
scored = _apply_ranking_feedback_boosts(root, scored, task, changes.all_changed)
|
|
270
274
|
return RankResult(
|
|
271
275
|
keywords=keywords,
|
|
272
276
|
keyword_plan=keyword_plan,
|
|
@@ -673,6 +677,9 @@ class AdapterRegistry:
|
|
|
673
677
|
cfg.learning.dashboard_output,
|
|
674
678
|
cfg.learning.team_lessons_output,
|
|
675
679
|
cfg.learning.feedback_output,
|
|
680
|
+
cfg.learning.ranking_feedback_output,
|
|
681
|
+
cfg.runtime.pack_registry_output,
|
|
682
|
+
cfg.runtime.session_events_output,
|
|
676
683
|
}
|
|
677
684
|
)
|
|
678
685
|
return paths
|
|
@@ -789,6 +796,29 @@ class PackService:
|
|
|
789
796
|
concurrent_context=pack_obj.concurrent_context,
|
|
790
797
|
metadata_path=scoped_paths.metadata if scoped_paths else None,
|
|
791
798
|
)
|
|
799
|
+
save_pack_registry(
|
|
800
|
+
root,
|
|
801
|
+
pack_obj,
|
|
802
|
+
packable,
|
|
803
|
+
output_path=cfg.runtime.pack_registry_output,
|
|
804
|
+
max_records=cfg.runtime.max_registry_records,
|
|
805
|
+
)
|
|
806
|
+
record_event(
|
|
807
|
+
root,
|
|
808
|
+
"pack",
|
|
809
|
+
{
|
|
810
|
+
"task": request.task,
|
|
811
|
+
"agent": request.agent,
|
|
812
|
+
"mode": plan.mode,
|
|
813
|
+
"packed_tokens": packed_tokens,
|
|
814
|
+
"raw_tokens": all_tokens,
|
|
815
|
+
"selected_files": len(pack_obj.selected_files),
|
|
816
|
+
"omitted_files": len(pack_obj.omitted_relevant_files),
|
|
817
|
+
"changed_files": len(pack_obj.changed_files),
|
|
818
|
+
"context_path": str(out_path.relative_to(root)),
|
|
819
|
+
},
|
|
820
|
+
output_path=cfg.runtime.session_events_output,
|
|
821
|
+
)
|
|
792
822
|
if thread_row:
|
|
793
823
|
append_thread_index(root, thread_row)
|
|
794
824
|
excluded_receipts = [r for r in pack_obj.receipts if r.action == "excluded"]
|
|
@@ -1145,6 +1175,25 @@ def _apply_history_penalties(
|
|
|
1145
1175
|
return adjusted
|
|
1146
1176
|
|
|
1147
1177
|
|
|
1178
|
+
def _apply_ranking_feedback_boosts(
|
|
1179
|
+
root: Path,
|
|
1180
|
+
scored: list[tuple[Any, float, list[str]]],
|
|
1181
|
+
task: str,
|
|
1182
|
+
changed_paths: set[str],
|
|
1183
|
+
) -> list[tuple[Any, float, list[str]]]:
|
|
1184
|
+
boosts = ranking_feedback_boosts(root, task)
|
|
1185
|
+
if not boosts:
|
|
1186
|
+
return scored
|
|
1187
|
+
adjusted: list[tuple[Any, float, list[str]]] = []
|
|
1188
|
+
for fi, score, reasons in scored:
|
|
1189
|
+
boost = boosts.get(fi.path, 0.0)
|
|
1190
|
+
if boost <= 0 or fi.path in changed_paths:
|
|
1191
|
+
adjusted.append((fi, score, reasons))
|
|
1192
|
+
continue
|
|
1193
|
+
adjusted.append((fi, score + boost, [*reasons, f"learning feedback miss boost +{boost:.0f}"]))
|
|
1194
|
+
return adjusted
|
|
1195
|
+
|
|
1196
|
+
|
|
1148
1197
|
def _history_noise_counts(root: Path, *, window: int = 20) -> dict[str, int]:
|
|
1149
1198
|
metrics_path = root / ".agentpack" / "metrics.jsonl"
|
|
1150
1199
|
if not metrics_path.exists():
|
|
@@ -5,6 +5,7 @@ from agentpack.commands import (
|
|
|
5
5
|
benchmark,
|
|
6
6
|
claude_cmd,
|
|
7
7
|
ci_cmd,
|
|
8
|
+
compress_output,
|
|
8
9
|
dashboard,
|
|
9
10
|
dev_check,
|
|
10
11
|
diagnose_selection,
|
|
@@ -18,14 +19,17 @@ from agentpack.commands import (
|
|
|
18
19
|
init,
|
|
19
20
|
install,
|
|
20
21
|
learn,
|
|
22
|
+
memory,
|
|
21
23
|
mcp_cmd,
|
|
22
24
|
migrate,
|
|
23
25
|
monitor,
|
|
24
26
|
next_cmd,
|
|
25
27
|
pack,
|
|
28
|
+
perf,
|
|
26
29
|
quickstart,
|
|
27
30
|
release_cmd,
|
|
28
31
|
release_check,
|
|
32
|
+
retrieve,
|
|
29
33
|
repair,
|
|
30
34
|
route,
|
|
31
35
|
scan,
|
|
@@ -40,6 +44,7 @@ from agentpack.commands import (
|
|
|
40
44
|
tune,
|
|
41
45
|
verify_wheel,
|
|
42
46
|
watch,
|
|
47
|
+
wrap,
|
|
43
48
|
workflow_cmd,
|
|
44
49
|
)
|
|
45
50
|
from agentpack import __version__
|
|
@@ -73,8 +78,11 @@ for mod in [
|
|
|
73
78
|
stats,
|
|
74
79
|
dashboard,
|
|
75
80
|
summarize,
|
|
81
|
+
compress_output,
|
|
76
82
|
learn,
|
|
83
|
+
memory,
|
|
77
84
|
pack,
|
|
85
|
+
perf,
|
|
78
86
|
install,
|
|
79
87
|
repair,
|
|
80
88
|
route,
|
|
@@ -99,7 +107,9 @@ for mod in [
|
|
|
99
107
|
skills,
|
|
100
108
|
release_check,
|
|
101
109
|
release_cmd,
|
|
110
|
+
retrieve,
|
|
102
111
|
start_cmd,
|
|
112
|
+
wrap,
|
|
103
113
|
workflow_cmd,
|
|
104
114
|
]:
|
|
105
115
|
mod.register(app)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from agentpack.commands._shared import _root
|
|
8
|
+
from agentpack.core.config import load_config
|
|
9
|
+
from agentpack.output_compression import compress_output
|
|
10
|
+
from agentpack.session.events import record_event
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def register(app: typer.Typer) -> None:
|
|
14
|
+
@app.command("compress-output")
|
|
15
|
+
def compress_output_cmd(
|
|
16
|
+
file: str = typer.Argument("-", help="Output file to summarize, or '-' for stdin."),
|
|
17
|
+
kind: str = typer.Option("auto", "--kind", help="Output kind: auto|pytest|npm|git-diff|rg|ls."),
|
|
18
|
+
) -> None:
|
|
19
|
+
"""Summarize noisy command output while preserving actionable lines."""
|
|
20
|
+
root = _root()
|
|
21
|
+
cfg = load_config(root)
|
|
22
|
+
if file == "-":
|
|
23
|
+
content = sys.stdin.read()
|
|
24
|
+
else:
|
|
25
|
+
content = (root / file).read_text(encoding="utf-8", errors="replace")
|
|
26
|
+
result = compress_output(content, kind=kind, max_items=cfg.runtime.max_output_summary_items)
|
|
27
|
+
record_event(
|
|
28
|
+
root,
|
|
29
|
+
"compress_output",
|
|
30
|
+
{"kind": kind, "input_chars": len(content), "output_chars": len(result)},
|
|
31
|
+
output_path=cfg.runtime.session_events_output,
|
|
32
|
+
)
|
|
33
|
+
typer.echo(result, nl=False)
|
|
@@ -55,13 +55,9 @@ def _repo_gitignore_entries(share_cache: bool = False, agent: str = "generic") -
|
|
|
55
55
|
".agentpack/snapshots/",
|
|
56
56
|
".agentpack/context*",
|
|
57
57
|
".agentpack/metrics.jsonl",
|
|
58
|
+
".agentpack/session-events.jsonl",
|
|
58
59
|
".agentpack/pack_metadata.json",
|
|
59
|
-
".agentpack/
|
|
60
|
-
".agentpack/.gitignore",
|
|
61
|
-
".agentpack/.mcp_reminded",
|
|
62
|
-
".agentpack/session.json",
|
|
63
|
-
".agentpack/task.md",
|
|
64
|
-
".agentpack/benchmark_results.jsonl",
|
|
60
|
+
".agentpack/pack-registry.json",
|
|
65
61
|
".agentpack/learning.md",
|
|
66
62
|
".agentpack/daily-summary.md",
|
|
67
63
|
".agentpack/skills-progress.json",
|
|
@@ -71,6 +67,14 @@ def _repo_gitignore_entries(share_cache: bool = False, agent: str = "generic") -
|
|
|
71
67
|
".agentpack/learning-dashboard.html",
|
|
72
68
|
".agentpack/team-lessons.md",
|
|
73
69
|
".agentpack/learning-feedback.jsonl",
|
|
70
|
+
".agentpack/ranking-feedback.jsonl",
|
|
71
|
+
".agentpack/learning-inputs.json",
|
|
72
|
+
".agentpack/activity.log",
|
|
73
|
+
".agentpack/.gitignore",
|
|
74
|
+
".agentpack/.mcp_reminded",
|
|
75
|
+
".agentpack/session.json",
|
|
76
|
+
".agentpack/task.md",
|
|
77
|
+
".agentpack/benchmark_results.jsonl",
|
|
74
78
|
".agentpack/loop_state.json",
|
|
75
79
|
".agentpack/progress.md",
|
|
76
80
|
".agentpack/loop_events.jsonl",
|
|
@@ -101,12 +105,9 @@ def _agentpack_gitignore_content(share_cache: bool = False) -> str:
|
|
|
101
105
|
"snapshots/",
|
|
102
106
|
"context.*",
|
|
103
107
|
"metrics.jsonl",
|
|
108
|
+
"session-events.jsonl",
|
|
104
109
|
"pack_metadata.json",
|
|
105
|
-
"
|
|
106
|
-
".mcp_reminded",
|
|
107
|
-
"session.json",
|
|
108
|
-
"task.md",
|
|
109
|
-
"benchmark_results.jsonl",
|
|
110
|
+
"pack-registry.json",
|
|
110
111
|
"learning.md",
|
|
111
112
|
"daily-summary.md",
|
|
112
113
|
"skills-progress.json",
|
|
@@ -116,6 +117,13 @@ def _agentpack_gitignore_content(share_cache: bool = False) -> str:
|
|
|
116
117
|
"learning-dashboard.html",
|
|
117
118
|
"team-lessons.md",
|
|
118
119
|
"learning-feedback.jsonl",
|
|
120
|
+
"ranking-feedback.jsonl",
|
|
121
|
+
"learning-inputs.json",
|
|
122
|
+
"activity.log",
|
|
123
|
+
".mcp_reminded",
|
|
124
|
+
"session.json",
|
|
125
|
+
"task.md",
|
|
126
|
+
"benchmark_results.jsonl",
|
|
119
127
|
"loop_state.json",
|
|
120
128
|
"progress.md",
|
|
121
129
|
"loop_events.jsonl",
|
|
@@ -6,12 +6,19 @@ from datetime import datetime
|
|
|
6
6
|
import typer
|
|
7
7
|
|
|
8
8
|
from agentpack.commands._shared import _atomic_write, _root, console
|
|
9
|
+
from agentpack.commands.dashboard import _open_file
|
|
9
10
|
from agentpack.core.config import load_config
|
|
10
11
|
from agentpack.learning.collector import collect_learning_inputs
|
|
11
12
|
from agentpack.learning.extractor import build_learning_report
|
|
12
|
-
from agentpack.learning.feedback import
|
|
13
|
+
from agentpack.learning.feedback import (
|
|
14
|
+
apply_feedback_to_report,
|
|
15
|
+
load_feedback_summary,
|
|
16
|
+
record_direct_learning_feedback,
|
|
17
|
+
record_learning_feedback,
|
|
18
|
+
record_ranking_feedback,
|
|
19
|
+
)
|
|
13
20
|
from agentpack.learning.lesson_ranker import rank_agent_lessons
|
|
14
|
-
from agentpack.learning.provider import LearningProviderError, run_provider_command
|
|
21
|
+
from agentpack.learning.provider import LearningProviderError, run_concept_provider_command, run_provider_command
|
|
15
22
|
from agentpack.learning.quality import score_learning_report
|
|
16
23
|
from agentpack.learning.renderers import (
|
|
17
24
|
learning_report_to_dict,
|
|
@@ -26,11 +33,14 @@ from agentpack.learning.renderers import (
|
|
|
26
33
|
render_team_lessons_markdown,
|
|
27
34
|
)
|
|
28
35
|
from agentpack.learning.skill_map import apply_skill_feedback, recommend_practice_drills, render_skill_summary, update_skill_map
|
|
36
|
+
from agentpack.session.events import record_event
|
|
29
37
|
|
|
30
38
|
|
|
31
39
|
def register(app: typer.Typer) -> None:
|
|
32
40
|
@app.command()
|
|
33
41
|
def learn(
|
|
42
|
+
action: str = typer.Argument("", help="Optional action: feedback."),
|
|
43
|
+
value: str = typer.Argument("", help="Feedback value for `agentpack learn feedback`: helpful|not-helpful."),
|
|
34
44
|
task: str = typer.Option("auto", "--task", help="Task source. Only 'auto' is supported."),
|
|
35
45
|
since: str | None = typer.Option(None, "--since", help="Git ref to compare against, e.g. HEAD~1 or main."),
|
|
36
46
|
today: bool = typer.Option(False, "--today", help="Use today's work scope label for the report."),
|
|
@@ -40,14 +50,30 @@ def register(app: typer.Typer) -> None:
|
|
|
40
50
|
pr_comment: bool = typer.Option(False, "--pr-comment", help="Write a PR-comment-ready learning summary artifact."),
|
|
41
51
|
provider_preview: bool = typer.Option(False, "--provider-preview", help="Print the bounded provider payload without making a network call."),
|
|
42
52
|
provider_command: str = typer.Option("", "--provider-command", help="Run a local JSON-in/JSON-out provider command to enrich the report."),
|
|
53
|
+
concept_provider_command: str = typer.Option(
|
|
54
|
+
"",
|
|
55
|
+
"--concept-provider-command",
|
|
56
|
+
help="Run a local JSON-in/JSON-out provider command to enrich detected learning concepts.",
|
|
57
|
+
),
|
|
58
|
+
no_concept_provider: bool = typer.Option(
|
|
59
|
+
False,
|
|
60
|
+
"--no-concept-provider",
|
|
61
|
+
help="Disable configured concept provider enrichment for this run.",
|
|
62
|
+
),
|
|
43
63
|
dashboard: bool = typer.Option(False, "--dashboard", help="Write a static HTML learning dashboard artifact."),
|
|
64
|
+
open_dashboard: bool = typer.Option(False, "--open", help="Open the generated learning dashboard in a browser."),
|
|
44
65
|
team_export: bool = typer.Option(False, "--team-export", help="Write an opt-in team lesson export without personal skill history."),
|
|
45
66
|
ci: bool = typer.Option(False, "--ci", help="Fail when learning quality is below the configured threshold."),
|
|
46
67
|
skills: bool = typer.Option(False, "--skills", help="Print the local skill memory summary and exit."),
|
|
47
68
|
drills: bool = typer.Option(False, "--drills", help="Print recommended practice drills from local skill memory and exit."),
|
|
48
69
|
feedback: str = typer.Option("", "--feedback", help="Record feedback for this learning output (helpful|not-helpful)."),
|
|
49
|
-
feedback_note: str = typer.Option("", "--feedback-note", help="Optional note stored with --feedback."),
|
|
50
|
-
feedback_target: str = typer.Option(
|
|
70
|
+
feedback_note: str = typer.Option("", "--feedback-note", "--note", help="Optional note stored with --feedback."),
|
|
71
|
+
feedback_target: str = typer.Option(
|
|
72
|
+
"",
|
|
73
|
+
"--feedback-target",
|
|
74
|
+
"--target",
|
|
75
|
+
help="Optional target such as skill:CLI design, lesson:retry, rename:old=>new, or merge:old=>new.",
|
|
76
|
+
),
|
|
51
77
|
suppress_skill: str = typer.Option("", "--suppress-skill", help="Suppress a noisy skill in future skill views and generation."),
|
|
52
78
|
rename_skill: str = typer.Option("", "--rename-skill", help="Rename a skill using old=>new."),
|
|
53
79
|
merge_skill: str = typer.Option("", "--merge-skill", help="Merge a skill using old=>new."),
|
|
@@ -62,6 +88,32 @@ def register(app: typer.Typer) -> None:
|
|
|
62
88
|
|
|
63
89
|
root = _root()
|
|
64
90
|
cfg = load_config(root)
|
|
91
|
+
if action:
|
|
92
|
+
if action != "feedback":
|
|
93
|
+
console.print("[red]Unknown learn action. Supported action: feedback.[/]")
|
|
94
|
+
raise typer.Exit(2)
|
|
95
|
+
if not value:
|
|
96
|
+
console.print("[red]Feedback value required: helpful|not-helpful.[/]")
|
|
97
|
+
raise typer.Exit(2)
|
|
98
|
+
try:
|
|
99
|
+
payload = record_direct_learning_feedback(
|
|
100
|
+
root / cfg.learning.feedback_output,
|
|
101
|
+
value,
|
|
102
|
+
task=_task_text(root),
|
|
103
|
+
note=feedback_note,
|
|
104
|
+
target=feedback_target,
|
|
105
|
+
)
|
|
106
|
+
except ValueError as exc:
|
|
107
|
+
console.print(f"[red]{exc}[/]")
|
|
108
|
+
raise typer.Exit(2) from exc
|
|
109
|
+
record_event(
|
|
110
|
+
root,
|
|
111
|
+
"learn_feedback",
|
|
112
|
+
{"feedback": payload["feedback"], "target": payload["target"]},
|
|
113
|
+
output_path=cfg.runtime.session_events_output,
|
|
114
|
+
)
|
|
115
|
+
console.print(f"[green]✓[/] Recorded learning feedback in {cfg.learning.feedback_output}")
|
|
116
|
+
return
|
|
65
117
|
skill_map_path = root / cfg.learning.skill_map_output
|
|
66
118
|
if skills:
|
|
67
119
|
typer.echo(render_skill_summary(skill_map_path), nl=False)
|
|
@@ -100,6 +152,11 @@ def register(app: typer.Typer) -> None:
|
|
|
100
152
|
feedback_summary = load_feedback_summary(root / cfg.learning.feedback_output)
|
|
101
153
|
report = apply_feedback_to_report(report, feedback_summary)
|
|
102
154
|
report.agent_lessons = rank_agent_lessons(report, feedback_summary, limit=cfg.learning.max_cards)
|
|
155
|
+
ranking_feedback_count = record_ranking_feedback(
|
|
156
|
+
root,
|
|
157
|
+
report,
|
|
158
|
+
output_path=cfg.learning.ranking_feedback_output,
|
|
159
|
+
)
|
|
103
160
|
if today:
|
|
104
161
|
report.scope = "today"
|
|
105
162
|
if since_date:
|
|
@@ -109,6 +166,21 @@ def register(app: typer.Typer) -> None:
|
|
|
109
166
|
typer.echo(render_provider_preview_markdown(report), nl=False)
|
|
110
167
|
return
|
|
111
168
|
|
|
169
|
+
concept_command = concept_provider_command or ("" if no_concept_provider else cfg.learning.concept_provider_command)
|
|
170
|
+
if concept_command:
|
|
171
|
+
try:
|
|
172
|
+
report = run_concept_provider_command(
|
|
173
|
+
concept_command,
|
|
174
|
+
inputs,
|
|
175
|
+
report,
|
|
176
|
+
timeout_seconds=cfg.learning.concept_provider_timeout_seconds,
|
|
177
|
+
)
|
|
178
|
+
except LearningProviderError as exc:
|
|
179
|
+
if concept_provider_command or cfg.learning.concept_provider_required:
|
|
180
|
+
console.print(f"[red]Concept provider command failed:[/] {exc}")
|
|
181
|
+
raise typer.Exit(1) from exc
|
|
182
|
+
console.print(f"[yellow]Concept provider skipped:[/] {exc}")
|
|
183
|
+
|
|
112
184
|
command = provider_command or cfg.learning.provider_command
|
|
113
185
|
if command:
|
|
114
186
|
try:
|
|
@@ -134,10 +206,15 @@ def register(app: typer.Typer) -> None:
|
|
|
134
206
|
pr_path = root / cfg.learning.pr_comment_output
|
|
135
207
|
pr_path.parent.mkdir(parents=True, exist_ok=True)
|
|
136
208
|
_atomic_write(pr_path, render_pr_comment_markdown(report))
|
|
209
|
+
if open_dashboard:
|
|
210
|
+
dashboard = True
|
|
137
211
|
if dashboard:
|
|
138
212
|
dashboard_path = root / cfg.learning.dashboard_output
|
|
139
213
|
dashboard_path.parent.mkdir(parents=True, exist_ok=True)
|
|
140
214
|
_atomic_write(dashboard_path, render_dashboard_html(report))
|
|
215
|
+
console.print(f"[green]✓[/] Wrote {dashboard_path.relative_to(root)}")
|
|
216
|
+
if open_dashboard:
|
|
217
|
+
_open_file(dashboard_path)
|
|
141
218
|
if team_export:
|
|
142
219
|
team_path = root / cfg.learning.team_lessons_output
|
|
143
220
|
team_path.parent.mkdir(parents=True, exist_ok=True)
|
|
@@ -147,6 +224,12 @@ def register(app: typer.Typer) -> None:
|
|
|
147
224
|
console.print("[red]--feedback must be helpful or not-helpful.[/]")
|
|
148
225
|
raise typer.Exit(2)
|
|
149
226
|
record_learning_feedback(root / cfg.learning.feedback_output, report, feedback, feedback_note, feedback_target)
|
|
227
|
+
record_event(
|
|
228
|
+
root,
|
|
229
|
+
"learn_feedback",
|
|
230
|
+
{"feedback": feedback, "target": feedback_target},
|
|
231
|
+
output_path=cfg.runtime.session_events_output,
|
|
232
|
+
)
|
|
150
233
|
if ci:
|
|
151
234
|
typer.echo(render_quality_markdown(report, quality.score, quality.issues), nl=False)
|
|
152
235
|
if quality.score < cfg.learning.min_groundedness_score:
|
|
@@ -160,6 +243,19 @@ def register(app: typer.Typer) -> None:
|
|
|
160
243
|
out_path = root / (output or default_output)
|
|
161
244
|
out_path.parent.mkdir(parents=True, exist_ok=True)
|
|
162
245
|
_atomic_write(out_path, render_learning_markdown(report))
|
|
246
|
+
record_event(
|
|
247
|
+
root,
|
|
248
|
+
"learn",
|
|
249
|
+
{
|
|
250
|
+
"task": report.task,
|
|
251
|
+
"changed_files": len(report.source_files),
|
|
252
|
+
"concepts": report.concepts,
|
|
253
|
+
"selected_hits": len(report.selected_hits),
|
|
254
|
+
"selected_misses": len(report.selected_misses),
|
|
255
|
+
"ranking_feedback_paths": ranking_feedback_count,
|
|
256
|
+
},
|
|
257
|
+
output_path=cfg.runtime.session_events_output,
|
|
258
|
+
)
|
|
163
259
|
console.print(f"[green]✓[/] Wrote {out_path.relative_to(root)}")
|
|
164
260
|
|
|
165
261
|
|
|
@@ -168,6 +264,19 @@ def _today_start_iso() -> str:
|
|
|
168
264
|
return now.replace(hour=0, minute=0, second=0, microsecond=0).isoformat()
|
|
169
265
|
|
|
170
266
|
|
|
267
|
+
def _task_text(root) -> str:
|
|
268
|
+
task_path = root / ".agentpack" / "task.md"
|
|
269
|
+
if task_path.exists():
|
|
270
|
+
lines = [
|
|
271
|
+
line.strip()
|
|
272
|
+
for line in task_path.read_text(encoding="utf-8").splitlines()
|
|
273
|
+
if line.strip() and not line.startswith("#")
|
|
274
|
+
]
|
|
275
|
+
if lines:
|
|
276
|
+
return lines[0]
|
|
277
|
+
return "Current work"
|
|
278
|
+
|
|
279
|
+
|
|
171
280
|
def _split_mapping(value: str, flag: str) -> tuple[str, str]:
|
|
172
281
|
if "=>" not in value:
|
|
173
282
|
console.print(f"[red]{flag} expects old=>new.[/]")
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from collections import Counter
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
from rich.table import Table
|
|
8
|
+
from rich import box
|
|
9
|
+
|
|
10
|
+
from agentpack.commands._shared import _root, console
|
|
11
|
+
from agentpack.core.config import load_config
|
|
12
|
+
from agentpack.session.events import read_events
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def register(app: typer.Typer) -> None:
|
|
16
|
+
@app.command()
|
|
17
|
+
def memory(json_output: bool = typer.Option(False, "--json", help="Print JSON.")) -> None:
|
|
18
|
+
"""Show local cross-agent task memory from events and learning artifacts."""
|
|
19
|
+
root = _root()
|
|
20
|
+
cfg = load_config(root)
|
|
21
|
+
events = read_events(root, output_path=cfg.runtime.session_events_output, limit=500)
|
|
22
|
+
tasks = [str(event.get("task")) for event in events if event.get("task")]
|
|
23
|
+
concepts = Counter(
|
|
24
|
+
concept
|
|
25
|
+
for event in events
|
|
26
|
+
for concept in (event.get("concepts") or [])
|
|
27
|
+
if isinstance(concept, str)
|
|
28
|
+
)
|
|
29
|
+
payload = {
|
|
30
|
+
"recent_tasks": tasks[-20:],
|
|
31
|
+
"top_concepts": concepts.most_common(20),
|
|
32
|
+
"event_count": len(events),
|
|
33
|
+
}
|
|
34
|
+
if json_output:
|
|
35
|
+
typer.echo(json.dumps(payload, indent=2))
|
|
36
|
+
return
|
|
37
|
+
table = Table(title="AgentPack Memory", box=box.SIMPLE, show_header=True, padding=(0, 1))
|
|
38
|
+
table.add_column("kind", style="dim")
|
|
39
|
+
table.add_column("value")
|
|
40
|
+
table.add_row("events", str(len(events)))
|
|
41
|
+
for task in tasks[-10:]:
|
|
42
|
+
table.add_row("task", task)
|
|
43
|
+
for concept, count in concepts.most_common(10):
|
|
44
|
+
table.add_row("concept", f"{concept} ({count})")
|
|
45
|
+
console.print(table)
|