@event4u/agent-config 1.19.0 → 1.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agent-src/commands/agent-handoff.md +14 -10
- package/.agent-src/commands/agents.md +1 -1
- package/.agent-src/commands/bug-fix.md +1 -1
- package/.agent-src/commands/bug-investigate.md +2 -2
- package/.agent-src/commands/chat-history/import.md +166 -0
- package/.agent-src/commands/chat-history/learn.md +178 -0
- package/.agent-src/commands/chat-history/show.md +17 -18
- package/.agent-src/commands/chat-history.md +26 -25
- package/.agent-src/commands/compress.md +12 -0
- package/.agent-src/commands/context/create.md +2 -2
- package/.agent-src/commands/context.md +1 -1
- package/.agent-src/commands/copilot-agents.md +1 -1
- package/.agent-src/commands/council/default.md +21 -12
- package/.agent-src/commands/council.md +1 -1
- package/.agent-src/commands/create-pr.md +28 -8
- package/.agent-src/commands/e2e-heal.md +1 -1
- package/.agent-src/commands/e2e-plan.md +1 -1
- package/.agent-src/commands/feature/dev.md +3 -3
- package/.agent-src/commands/feature.md +1 -1
- package/.agent-src/commands/fix/seeder.md +2 -2
- package/.agent-src/commands/fix.md +1 -1
- package/.agent-src/commands/jira-ticket.md +1 -1
- package/.agent-src/commands/judge.md +2 -2
- package/.agent-src/commands/memory.md +1 -1
- package/.agent-src/commands/mode.md +5 -5
- package/.agent-src/commands/module.md +1 -1
- package/.agent-src/commands/onboard.md +4 -4
- package/.agent-src/commands/optimize/augmentignore.md +1 -1
- package/.agent-src/commands/optimize-prompt.md +61 -0
- package/.agent-src/commands/optimize.md +1 -1
- package/.agent-src/commands/override.md +1 -1
- package/.agent-src/commands/review-changes.md +1 -1
- package/.agent-src/commands/review-routing.md +1 -1
- package/.agent-src/commands/roadmap.md +1 -1
- package/.agent-src/commands/set-cost-profile.md +3 -3
- package/.agent-src/commands/sync-agent-settings.md +2 -2
- package/.agent-src/commands/sync-gitignore.md +1 -1
- package/.agent-src/commands/tests/create.md +2 -2
- package/.agent-src/commands/tests.md +1 -1
- package/.agent-src/commands/threat-model.md +4 -4
- package/.agent-src/contexts/authority/commit-mechanics.md +14 -1
- package/.agent-src/contexts/authority/destructive-mechanics.md +14 -1
- package/.agent-src/contexts/authority/scope-mechanics.md +5 -0
- package/.agent-src/contexts/communication/rules-auto/guidelines-mechanics.md +76 -0
- package/.agent-src/contexts/communication/rules-auto/skill-quality-mechanics.md +76 -0
- package/.agent-src/contexts/communication/rules-auto/slash-command-routing-policy-mechanics.md +4 -4
- package/.agent-src/contexts/communication/rules-auto/think-before-action-mechanics.md +98 -0
- package/.agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +93 -0
- package/.agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +125 -9
- package/.agent-src/contexts/execution/autonomy-mechanics.md +44 -0
- package/.agent-src/contexts/model-recommendations.md +2 -2
- package/.agent-src/contexts/override-system.md +1 -1
- package/.agent-src/personas/product-owner.md +2 -2
- package/.agent-src/personas/qa.md +1 -1
- package/.agent-src/rules/agent-authority.md +5 -6
- package/.agent-src/rules/agent-docs.md +11 -53
- package/.agent-src/rules/analysis-skill-routing.md +10 -40
- package/.agent-src/rules/architecture.md +6 -1
- package/.agent-src/rules/artifact-drafting-protocol.md +5 -0
- package/.agent-src/rules/artifact-engagement-recording.md +23 -59
- package/.agent-src/rules/ask-when-uncertain.md +24 -47
- package/.agent-src/rules/augment-portability.md +14 -62
- package/.agent-src/rules/augment-source-of-truth.md +10 -1
- package/.agent-src/rules/autonomous-execution.md +17 -98
- package/.agent-src/rules/capture-learnings.md +9 -80
- package/.agent-src/rules/cli-output-handling.md +12 -42
- package/.agent-src/rules/command-suggestion-policy.md +25 -73
- package/.agent-src/rules/commit-conventions.md +9 -58
- package/.agent-src/rules/commit-policy.md +16 -47
- package/.agent-src/rules/context-hygiene.md +5 -0
- package/.agent-src/rules/direct-answers.md +21 -42
- package/.agent-src/rules/docker-commands.md +11 -45
- package/.agent-src/rules/docs-sync.md +10 -56
- package/.agent-src/rules/downstream-changes.md +5 -0
- package/.agent-src/rules/e2e-testing.md +9 -44
- package/.agent-src/rules/guidelines.md +13 -75
- package/.agent-src/rules/improve-before-implement.md +10 -2
- package/.agent-src/rules/language-and-tone.md +35 -69
- package/.agent-src/rules/laravel-translations.md +11 -40
- package/.agent-src/rules/markdown-safe-codeblocks.md +4 -0
- package/.agent-src/rules/minimal-safe-diff.md +4 -0
- package/.agent-src/rules/missing-tool-handling.md +4 -0
- package/.agent-src/rules/model-recommendation.md +9 -61
- package/.agent-src/rules/no-attribution-footers.md +53 -0
- package/.agent-src/rules/no-cheap-questions.md +11 -27
- package/.agent-src/rules/no-council-references.md +76 -0
- package/.agent-src/rules/no-roadmap-references.md +8 -1
- package/.agent-src/rules/non-destructive-by-default.md +13 -43
- package/.agent-src/rules/onboarding-gate.md +9 -117
- package/.agent-src/rules/package-ci-checks.md +10 -37
- package/.agent-src/rules/php-coding.md +10 -55
- package/.agent-src/rules/preservation-guard.md +9 -0
- package/.agent-src/rules/review-routing-awareness.md +9 -97
- package/.agent-src/rules/reviewer-awareness.md +8 -83
- package/.agent-src/rules/roadmap-progress-sync.md +7 -170
- package/.agent-src/rules/role-mode-adherence.md +6 -2
- package/.agent-src/rules/rule-type-governance.md +8 -66
- package/.agent-src/rules/runtime-safety.md +5 -0
- package/.agent-src/rules/scope-control.md +17 -62
- package/.agent-src/rules/security-sensitive-stop.md +7 -1
- package/.agent-src/rules/size-enforcement.md +6 -1
- package/.agent-src/rules/skill-improvement-trigger.md +9 -49
- package/.agent-src/rules/skill-quality.md +7 -64
- package/.agent-src/rules/slash-command-routing-policy.md +11 -63
- package/.agent-src/rules/think-before-action.md +22 -87
- package/.agent-src/rules/token-efficiency.md +10 -74
- package/.agent-src/rules/token-optimizer-maintenance.md +68 -0
- package/.agent-src/rules/tool-safety.md +4 -0
- package/.agent-src/rules/ui-audit-gate.md +25 -61
- package/.agent-src/rules/upstream-proposal.md +9 -67
- package/.agent-src/rules/user-interaction.md +25 -95
- package/.agent-src/rules/verify-before-complete.md +1 -1
- package/.agent-src/skills/agent-docs-writing/SKILL.md +1 -1
- package/.agent-src/skills/ai-council/SKILL.md +69 -5
- package/.agent-src/skills/analysis-autonomous-mode/SKILL.md +1 -1
- package/.agent-src/skills/analysis-skill-router/SKILL.md +3 -3
- package/.agent-src/skills/artisan-commands/SKILL.md +2 -2
- package/.agent-src/skills/authz-review/SKILL.md +1 -1
- package/.agent-src/skills/aws-infrastructure/SKILL.md +5 -5
- package/.agent-src/skills/blast-radius-analyzer/SKILL.md +8 -8
- package/.agent-src/skills/bug-analyzer/SKILL.md +5 -5
- package/.agent-src/skills/code-refactoring/SKILL.md +4 -4
- package/.agent-src/skills/code-review/SKILL.md +2 -2
- package/.agent-src/skills/command-writing/SKILL.md +11 -0
- package/.agent-src/skills/composer-packages/SKILL.md +2 -2
- package/.agent-src/skills/context-authoring/SKILL.md +11 -0
- package/.agent-src/skills/context-document/SKILL.md +1 -1
- package/.agent-src/skills/copilot-agents-optimization/SKILL.md +23 -0
- package/.agent-src/skills/copilot-config/SKILL.md +1 -1
- package/.agent-src/skills/dcf-modeling/SKILL.md +89 -0
- package/.agent-src/skills/dependency-upgrade/SKILL.md +2 -2
- package/.agent-src/skills/devcontainer/SKILL.md +2 -2
- package/.agent-src/skills/developer-like-execution/SKILL.md +1 -1
- package/.agent-src/skills/docker/SKILL.md +1 -1
- package/.agent-src/skills/dto-creator/SKILL.md +1 -1
- package/.agent-src/skills/estimate-ticket/SKILL.md +2 -2
- package/.agent-src/skills/fe-design/SKILL.md +4 -4
- package/.agent-src/skills/feature-planning/SKILL.md +5 -5
- package/.agent-src/skills/funnel-analysis/SKILL.md +100 -0
- package/.agent-src/skills/laravel/SKILL.md +1 -1
- package/.agent-src/skills/laravel-notifications/SKILL.md +5 -5
- package/.agent-src/skills/laravel-pennant/SKILL.md +1 -1
- package/.agent-src/skills/laravel-pulse/SKILL.md +4 -4
- package/.agent-src/skills/laravel-reverb/SKILL.md +2 -2
- package/.agent-src/skills/laravel-scheduling/SKILL.md +1 -1
- package/.agent-src/skills/md-language-check/SKILL.md +1 -1
- package/.agent-src/skills/migration-creator/SKILL.md +7 -7
- package/.agent-src/skills/multi-tenancy/SKILL.md +8 -8
- package/.agent-src/skills/okr-tree-modeling/SKILL.md +93 -0
- package/.agent-src/skills/performance-analysis/SKILL.md +3 -3
- package/.agent-src/skills/pest-testing/SKILL.md +6 -6
- package/.agent-src/skills/php-service/SKILL.md +2 -2
- package/.agent-src/skills/project-analysis-hypothesis-driven/SKILL.md +3 -3
- package/.agent-src/skills/project-analysis-react/SKILL.md +1 -1
- package/.agent-src/skills/project-analysis-symfony/SKILL.md +1 -1
- package/.agent-src/skills/project-analysis-zend-laminas/SKILL.md +2 -2
- package/.agent-src/skills/project-analyzer/SKILL.md +4 -4
- package/.agent-src/skills/prompt-optimizer/SKILL.md +108 -0
- package/.agent-src/skills/readme-reviewer/SKILL.md +1 -1
- package/.agent-src/skills/rice-prioritization/SKILL.md +100 -0
- package/.agent-src/skills/rule-writing/SKILL.md +33 -0
- package/.agent-src/skills/sentry-integration/SKILL.md +1 -1
- package/.agent-src/skills/skill-writing/SKILL.md +14 -0
- package/.agent-src/skills/subagent-orchestration/SKILL.md +34 -2
- package/.agent-src/skills/terraform/SKILL.md +2 -2
- package/.agent-src/skills/terragrunt/SKILL.md +8 -8
- package/.agent-src/skills/test-performance/SKILL.md +5 -5
- package/.agent-src/skills/threat-modeling/SKILL.md +2 -2
- package/.agent-src/skills/token-optimizer/SKILL.md +110 -0
- package/.agent-src/skills/unit-economics-modeling/SKILL.md +104 -0
- package/.agent-src/skills/universal-project-analysis/SKILL.md +1 -1
- package/.agent-src/skills/using-git-worktrees/SKILL.md +1 -0
- package/.agent-src/templates/AGENTS.md +1 -1
- package/.agent-src/templates/agent-settings.md +25 -41
- package/.agent-src/templates/contexts/tenant-boundaries.md +2 -2
- package/.agent-src/templates/contexts.md +1 -1
- package/.agent-src/templates/copilot-instructions.md +21 -0
- package/.agent-src/templates/copilot-review-instructions.md +76 -0
- package/.agent-src/templates/features.md +1 -1
- package/.agent-src/templates/rule.md +127 -0
- package/.agent-src/templates/scripts/work_engine/hook_bootstrap.py +7 -5
- package/.agent-src/templates/scripts/work_engine/hooks/__init__.py +0 -4
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/__init__.py +0 -4
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/_chat_history_base.py +7 -51
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_append.py +1 -2
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_halt_append.py +1 -2
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.py +2 -3
- package/.agent-src/templates/skill.md +30 -1
- package/.claude-plugin/marketplace.json +11 -4
- package/AGENTS.md +71 -3
- package/CHANGELOG.md +180 -3
- package/README.md +24 -23
- package/config/agent-settings.template.yml +63 -23
- package/config/gitignore-block.txt +11 -4
- package/docs/architecture.md +84 -3
- package/docs/catalog.md +23 -11
- package/docs/contracts/adr-chat-history-split.md +10 -1
- package/docs/contracts/agent-memory-contract.md +1 -1
- package/docs/contracts/command-clusters.md +1 -1
- package/docs/contracts/context-paths.md +2 -1
- package/docs/contracts/cross-wing-handoff.md +133 -0
- package/docs/contracts/file-ownership-matrix.json +678 -609
- package/docs/contracts/hook-architecture-v1.md +8 -1
- package/docs/contracts/iron-law-overrides.txt +25 -0
- package/docs/contracts/kernel-membership.md +273 -0
- package/docs/contracts/load-context-schema.md +26 -11
- package/docs/contracts/memory-visibility-v1.md +8 -24
- package/docs/contracts/pilot/agent-authority.md +24 -0
- package/docs/contracts/pilot/direct-answers.md +70 -0
- package/docs/contracts/pilot/language-and-tone.md +63 -0
- package/docs/contracts/rule-classification.md +170 -0
- package/docs/contracts/rule-router.md +153 -0
- package/docs/customization.md +18 -7
- package/docs/decisions/ADR-001-kernel-swap-deferred.md +109 -0
- package/docs/decisions/ADR-002-kernel-bucket-overrides.md +124 -0
- package/docs/decisions/ADR-rule-kernel-and-router.md +122 -0
- package/docs/getting-started.md +19 -27
- package/docs/guidelines/agent-infra/ask-when-uncertain-demos.md +1 -1
- package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +176 -0
- package/docs/guidelines/agent-infra/rule-type-governance.md +73 -0
- package/docs/guidelines/agent-infra/size-and-scope.md +13 -2
- package/docs/guidelines/agent-infra/skill-quality-checklist.md +119 -0
- package/docs/guidelines/augment-portability-patterns.md +68 -0
- package/docs/guidelines/php/php-coding-patterns.md +62 -0
- package/docs/hook-payload-capture.md +221 -0
- package/docs/migrations/commands-1.15.0.md +17 -12
- package/docs/skills-catalog.md +5 -4
- package/llms.txt +4 -3
- package/package.json +1 -1
- package/scripts/_p43_bodies.py +235 -0
- package/scripts/_p43_compress.py +118 -0
- package/scripts/_p4_migrate.py +199 -0
- package/scripts/_pilot_council_question.py +57 -0
- package/scripts/_pilot_measure.py +53 -0
- package/scripts/agent-config +1 -1
- package/scripts/ai_council/_default_prices.py +4 -4
- package/scripts/ai_council/clients.py +1 -1
- package/scripts/ai_council/modes.py +3 -4
- package/scripts/ai_council/pricing.py +10 -9
- package/scripts/ai_council/session.py +107 -5
- package/scripts/build_linear_digest.py +3 -5
- package/scripts/build_rule_trigger_matrix.py +1 -9
- package/scripts/chat_history.py +952 -596
- package/scripts/check_always_budget.py +39 -6
- package/scripts/check_compressed_paths.py +213 -0
- package/scripts/check_compression.py +15 -0
- package/scripts/check_context_paths.py +1 -0
- package/scripts/check_council_layout.py +105 -0
- package/scripts/check_council_references.py +145 -0
- package/scripts/check_portability.py +2 -0
- package/scripts/check_references.py +14 -2
- package/scripts/check_token_optimizer_freshness.py +131 -0
- package/scripts/compile_router.py +148 -0
- package/scripts/compress.py +219 -11
- package/scripts/council_cli.py +63 -9
- package/scripts/council_prune.py +81 -0
- package/scripts/count_token_optimizer_usage.sh +54 -0
- package/scripts/hook_manifest.yaml +33 -0
- package/scripts/hooks/augment-chat-history.sh +10 -0
- package/scripts/hooks/cowork-dispatcher.sh +98 -0
- package/scripts/hooks/dispatch_hook.py +35 -0
- package/scripts/hooks_status.py +12 -1
- package/scripts/install-hooks.sh +2 -2
- package/scripts/install.sh +81 -2
- package/scripts/iron_law_sha.py +98 -0
- package/scripts/lint_handoffs.py +214 -0
- package/scripts/lint_hook_manifest.py +2 -1
- package/scripts/lint_load_context.py +35 -5
- package/scripts/measure_rule_budget.py +314 -0
- package/scripts/prototype_lint_contradictions.py +150 -0
- package/scripts/redact_hook_capture.py +148 -0
- package/scripts/schemas/rule.schema.json +55 -6
- package/scripts/schemas/skill.schema.json +5 -0
- package/scripts/skill_linter.py +359 -7
- package/scripts/smoke_path_resolution.py +93 -0
- package/scripts/update_prices.py +3 -3
- package/scripts/validate_frontmatter.py +41 -1
- package/.agent-src/commands/chat-history/checkpoint.md +0 -126
- package/.agent-src/commands/chat-history/clear.md +0 -103
- package/.agent-src/commands/chat-history/resume.md +0 -183
- package/.agent-src/contexts/communication/rules-auto/artifact-engagement-recording-mechanics.md +0 -72
- package/.agent-src/contexts/communication/rules-auto/augment-portability-mechanics.md +0 -79
- package/.agent-src/contexts/communication/rules-auto/cli-output-handling-mechanics.md +0 -87
- package/.agent-src/contexts/communication/rules-auto/command-suggestion-policy-mechanics.md +0 -62
- package/.agent-src/contexts/communication/rules-auto/docs-sync-mechanics.md +0 -78
- package/.agent-src/contexts/communication/rules-auto/package-ci-checks-mechanics.md +0 -85
- package/.agent-src/contexts/communication/rules-auto/review-routing-awareness-mechanics.md +0 -65
- package/.agent-src/contexts/communication/rules-auto/roadmap-progress-sync-mechanics.md +0 -78
- package/.agent-src/contexts/communication/rules-auto/ui-audit-gate-mechanics.md +0 -53
- package/.agent-src/rules/chat-history-cadence.md +0 -143
- package/.agent-src/rules/chat-history-ownership.md +0 -124
- package/.agent-src/rules/chat-history-visibility.md +0 -97
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_heartbeat.py +0 -50
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_turn_check.py +0 -49
- package/scripts/check_phase_coupling.py +0 -148
- /package/{docs → .agent-src/contexts}/contracts/artifact-engagement-flow.md +0 -0
- /package/{docs → .agent-src/contexts}/contracts/command-suggestion-flow.md +0 -0
package/scripts/council_cli.py
CHANGED
|
@@ -62,12 +62,17 @@ def build_members(
|
|
|
62
62
|
settings: dict[str, Any],
|
|
63
63
|
*,
|
|
64
64
|
invocation_mode: str | None = None,
|
|
65
|
+
model_overrides: dict[str, str] | None = None,
|
|
65
66
|
) -> list[ExternalAIClient]:
|
|
66
67
|
"""Construct enabled council members from settings.
|
|
67
68
|
|
|
68
69
|
Honours `ai_council.enabled` (master switch) and per-member
|
|
69
70
|
`enabled` flags. Raises `CouncilDisabledError` when the council is
|
|
70
71
|
off or no member is wired up.
|
|
72
|
+
|
|
73
|
+
`model_overrides` is a per-invocation `{member_name: model_id}`
|
|
74
|
+
map that wins over the per-member `model` in settings. Members not
|
|
75
|
+
listed fall back to the settings value, then the per-client default.
|
|
71
76
|
"""
|
|
72
77
|
ai = (settings.get("ai_council") or {}) if isinstance(settings, dict) else {}
|
|
73
78
|
if not ai.get("enabled"):
|
|
@@ -77,6 +82,13 @@ def build_members(
|
|
|
77
82
|
)
|
|
78
83
|
members_cfg = ai.get("members") or {}
|
|
79
84
|
global_mode = ai.get("mode")
|
|
85
|
+
overrides = model_overrides or {}
|
|
86
|
+
unknown = set(overrides) - set(members_cfg)
|
|
87
|
+
if unknown:
|
|
88
|
+
raise CouncilDisabledError(
|
|
89
|
+
f"--model targets unknown member(s) {sorted(unknown)!r}; "
|
|
90
|
+
f"known members: {sorted(members_cfg)!r}."
|
|
91
|
+
)
|
|
80
92
|
members: list[ExternalAIClient] = []
|
|
81
93
|
for name, cfg in members_cfg.items():
|
|
82
94
|
cfg = cfg or {}
|
|
@@ -88,7 +100,7 @@ def build_members(
|
|
|
88
100
|
member_settings=cfg,
|
|
89
101
|
global_mode=global_mode,
|
|
90
102
|
)
|
|
91
|
-
model = cfg.get("model")
|
|
103
|
+
model = overrides.get(name) or cfg.get("model")
|
|
92
104
|
if mode == "api" and name == "anthropic":
|
|
93
105
|
members.append(AnthropicClient(model=model or "claude-sonnet-4-5",
|
|
94
106
|
api_key=load_anthropic_key()))
|
|
@@ -163,7 +175,11 @@ def cmd_estimate(
|
|
|
163
175
|
if settings is None:
|
|
164
176
|
settings = load_settings()
|
|
165
177
|
if members is None:
|
|
166
|
-
members = build_members(
|
|
178
|
+
members = build_members(
|
|
179
|
+
settings,
|
|
180
|
+
invocation_mode=args.mode_override,
|
|
181
|
+
model_overrides=_parse_model_overrides(getattr(args, "model", None)),
|
|
182
|
+
)
|
|
167
183
|
if table is None:
|
|
168
184
|
table = load_prices()
|
|
169
185
|
question, _ = build_question(
|
|
@@ -219,7 +235,11 @@ def cmd_run(
|
|
|
219
235
|
if settings is None:
|
|
220
236
|
settings = load_settings()
|
|
221
237
|
if members is None:
|
|
222
|
-
members = build_members(
|
|
238
|
+
members = build_members(
|
|
239
|
+
settings,
|
|
240
|
+
invocation_mode=args.mode_override,
|
|
241
|
+
model_overrides=_parse_model_overrides(getattr(args, "model", None)),
|
|
242
|
+
)
|
|
223
243
|
if table is None:
|
|
224
244
|
table = load_prices()
|
|
225
245
|
question, artefact = build_question(
|
|
@@ -243,17 +263,19 @@ def cmd_run(
|
|
|
243
263
|
)
|
|
244
264
|
return 0
|
|
245
265
|
|
|
246
|
-
|
|
266
|
+
ai_cfg = settings.get("ai_council") or {}
|
|
267
|
+
cost_cfg = ai_cfg.get("cost_budget") or {}
|
|
247
268
|
budget = CostBudget(
|
|
248
269
|
max_input_tokens=int(cost_cfg.get("max_input_tokens", 50_000)),
|
|
249
270
|
max_output_tokens=int(cost_cfg.get("max_output_tokens", 20_000)),
|
|
250
271
|
max_calls=int(cost_cfg.get("max_calls", 10)),
|
|
251
272
|
max_total_usd=float(cost_cfg.get("max_total_usd", 0.0) or 0.0),
|
|
252
273
|
)
|
|
274
|
+
rounds = args.rounds if args.rounds is not None else int(ai_cfg.get("min_rounds", 2))
|
|
253
275
|
responses = consult(
|
|
254
276
|
members, question, budget,
|
|
255
277
|
table=table, project=project,
|
|
256
|
-
original_ask=args.original_ask, rounds=
|
|
278
|
+
original_ask=args.original_ask, rounds=rounds,
|
|
257
279
|
)
|
|
258
280
|
estimated_total = sum(e.total_usd for e in estimates)
|
|
259
281
|
actual_total = 0.0
|
|
@@ -268,7 +290,7 @@ def cmd_run(
|
|
|
268
290
|
"artefact": artefact,
|
|
269
291
|
"original_ask": args.original_ask,
|
|
270
292
|
"members": [f"{m.name}/{m.model}" for m in members],
|
|
271
|
-
"rounds":
|
|
293
|
+
"rounds": rounds,
|
|
272
294
|
"cost_usd_estimated": round(estimated_total, 6),
|
|
273
295
|
"cost_usd_actual": round(actual_total, 6),
|
|
274
296
|
"responses": _serialise_responses(responses),
|
|
@@ -295,6 +317,28 @@ def cmd_render(args: argparse.Namespace) -> int:
|
|
|
295
317
|
# ── argparse + main ─────────────────────────────────────────────────
|
|
296
318
|
|
|
297
319
|
|
|
320
|
+
def _parse_model_overrides(items: list[str] | None) -> dict[str, str]:
|
|
321
|
+
"""Parse repeated `--model name=model-id` flags into a dict.
|
|
322
|
+
|
|
323
|
+
Empty/None list → empty dict (no override). Bad shape raises
|
|
324
|
+
`argparse.ArgumentTypeError` so the CLI surfaces the error.
|
|
325
|
+
"""
|
|
326
|
+
out: dict[str, str] = {}
|
|
327
|
+
for raw in items or []:
|
|
328
|
+
if "=" not in raw:
|
|
329
|
+
raise argparse.ArgumentTypeError(
|
|
330
|
+
f"--model expects '<member>=<model-id>', got {raw!r}."
|
|
331
|
+
)
|
|
332
|
+
name, model = raw.split("=", 1)
|
|
333
|
+
name, model = name.strip(), model.strip()
|
|
334
|
+
if not name or not model:
|
|
335
|
+
raise argparse.ArgumentTypeError(
|
|
336
|
+
f"--model member and model-id must both be non-empty: {raw!r}."
|
|
337
|
+
)
|
|
338
|
+
out[name] = model
|
|
339
|
+
return out
|
|
340
|
+
|
|
341
|
+
|
|
298
342
|
def _add_common_input_args(p: argparse.ArgumentParser) -> None:
|
|
299
343
|
p.add_argument("question", type=str,
|
|
300
344
|
help="Path to the question file (text or roadmap).")
|
|
@@ -305,6 +349,13 @@ def _add_common_input_args(p: argparse.ArgumentParser) -> None:
|
|
|
305
349
|
help="Per-member output budget (default: 1024).")
|
|
306
350
|
p.add_argument("--mode-override", choices=["api", "manual"], default=None,
|
|
307
351
|
help="Override every member's transport mode.")
|
|
352
|
+
p.add_argument("--model", action="append", default=None, dest="model",
|
|
353
|
+
metavar="MEMBER=MODEL_ID",
|
|
354
|
+
help="Per-invocation model override, e.g. "
|
|
355
|
+
"--model anthropic=claude-sonnet-4-5. Repeatable. "
|
|
356
|
+
"Wins over `ai_council.members.<name>.model` in "
|
|
357
|
+
".agent-settings.yml; the settings file is not "
|
|
358
|
+
"modified.")
|
|
308
359
|
p.add_argument("--original-ask", default="",
|
|
309
360
|
help="The user's framing sentence (flows into handoff).")
|
|
310
361
|
|
|
@@ -325,8 +376,10 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
325
376
|
help="Path to write the responses JSON.")
|
|
326
377
|
p_run.add_argument("--confirm", action="store_true",
|
|
327
378
|
help="Required to actually invoke the council.")
|
|
328
|
-
p_run.add_argument("--rounds", type=int, default=
|
|
329
|
-
help="Number of debate rounds (1-3)."
|
|
379
|
+
p_run.add_argument("--rounds", type=int, default=None,
|
|
380
|
+
help="Number of debate rounds (1-3). Defaults to "
|
|
381
|
+
"ai_council.min_rounds in .agent-settings.yml "
|
|
382
|
+
"(or 2 if unset).")
|
|
330
383
|
|
|
331
384
|
p_ren = sub.add_parser("render", help="Re-render a saved responses JSON.")
|
|
332
385
|
p_ren.add_argument("responses",
|
|
@@ -347,7 +400,8 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
347
400
|
except CouncilDisabledError as exc:
|
|
348
401
|
sys.stderr.write(f"❌ council:{args.cmd}: {exc}\n")
|
|
349
402
|
return 2
|
|
350
|
-
except (BundleTooLarge, InvalidModeError, FileNotFoundError
|
|
403
|
+
except (BundleTooLarge, InvalidModeError, FileNotFoundError,
|
|
404
|
+
argparse.ArgumentTypeError) as exc:
|
|
351
405
|
sys.stderr.write(f"❌ council:{args.cmd}: {exc}\n")
|
|
352
406
|
return 2
|
|
353
407
|
return 1
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Manual pruner for council artefacts.
|
|
3
|
+
|
|
4
|
+
Deletes council files older than `ai_council.session_retention_days`
|
|
5
|
+
(default 7) across all four artefact directories:
|
|
6
|
+
|
|
7
|
+
- agents/council-sessions/ (timestamp subdirs + root files)
|
|
8
|
+
- agents/council-questions/ (mtime-based)
|
|
9
|
+
- agents/council-responses/ (mtime-based)
|
|
10
|
+
|
|
11
|
+
Same logic as the auto-prune that runs on every `council save()`,
|
|
12
|
+
exposed as a Task target so the user can sweep on demand.
|
|
13
|
+
|
|
14
|
+
Invocation (from project root):
|
|
15
|
+
python3 scripts/council_prune.py [--days N] [--dry-run]
|
|
16
|
+
|
|
17
|
+
Exit code 0 always — pruning is a hygiene operation, never a build
|
|
18
|
+
gate. Disk failures are logged to stderr by the underlying pruner.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
import argparse
|
|
24
|
+
import sys
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
|
|
27
|
+
# Bootstrap import path so `python3 scripts/council_prune.py` works
|
|
28
|
+
# from the project root without an editable install.
|
|
29
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
|
30
|
+
|
|
31
|
+
from scripts.ai_council.session import ( # noqa: E402
|
|
32
|
+
_load_retention_days,
|
|
33
|
+
prune_all_council_artifacts,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def main() -> int:
|
|
38
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
39
|
+
parser.add_argument(
|
|
40
|
+
"--days",
|
|
41
|
+
type=int,
|
|
42
|
+
default=None,
|
|
43
|
+
help="Override retention_days (default: from .agent-settings.yml)",
|
|
44
|
+
)
|
|
45
|
+
parser.add_argument(
|
|
46
|
+
"--dry-run",
|
|
47
|
+
action="store_true",
|
|
48
|
+
help="List what would be deleted without removing anything.",
|
|
49
|
+
)
|
|
50
|
+
args = parser.parse_args()
|
|
51
|
+
|
|
52
|
+
days = args.days if args.days is not None else _load_retention_days()
|
|
53
|
+
if days <= 0:
|
|
54
|
+
print(f"council-prune: retention_days={days} → pruning disabled.")
|
|
55
|
+
return 0
|
|
56
|
+
|
|
57
|
+
if args.dry_run:
|
|
58
|
+
# The pruner doesn't have a true dry-run mode; we approximate
|
|
59
|
+
# by reporting current contents and the cutoff.
|
|
60
|
+
print(f"council-prune: dry-run, cutoff = retention_days={days}")
|
|
61
|
+
print("council-prune: actual deletion requires omitting --dry-run")
|
|
62
|
+
return 0
|
|
63
|
+
|
|
64
|
+
print(f"council-prune: retention_days={days}")
|
|
65
|
+
result = prune_all_council_artifacts(retention_days=days)
|
|
66
|
+
total = 0
|
|
67
|
+
for label, removed in result.items():
|
|
68
|
+
if removed:
|
|
69
|
+
print(f" {label}: {len(removed)} pruned")
|
|
70
|
+
for p in removed:
|
|
71
|
+
print(f" - {p}")
|
|
72
|
+
total += len(removed)
|
|
73
|
+
if total == 0:
|
|
74
|
+
print("council-prune: nothing to prune.")
|
|
75
|
+
else:
|
|
76
|
+
print(f"council-prune: pruned {total} entries total.")
|
|
77
|
+
return 0
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
if __name__ == "__main__":
|
|
81
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Token-Optimizer telemetry counter.
|
|
3
|
+
#
|
|
4
|
+
# Per `road-to-token-optimization.md` P1.4: counts uncommented TELEMETRY
|
|
5
|
+
# lines inside the token-optimizer skill body. Each consult bumps a line.
|
|
6
|
+
# Decision rule: <5 consults / 2 weeks → P3.1 sunset audit fires.
|
|
7
|
+
#
|
|
8
|
+
# Output: 7-day count, 30-day count, total. Stdout only, no side effects.
|
|
9
|
+
|
|
10
|
+
set -euo pipefail
|
|
11
|
+
|
|
12
|
+
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
13
|
+
SKILL="$REPO_ROOT/.agent-src.uncompressed/skills/token-optimizer/SKILL.md"
|
|
14
|
+
|
|
15
|
+
if [[ ! -f "$SKILL" ]]; then
|
|
16
|
+
echo "ERROR: $SKILL not found" >&2
|
|
17
|
+
exit 1
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
# Active TELEMETRY lines = those NOT inside an HTML comment.
|
|
21
|
+
# Pattern: lines that contain "TELEMETRY: consulted=" and start with neither "<!--" nor whitespace.
|
|
22
|
+
total=$(grep -cE '^TELEMETRY: consulted=' "$SKILL" || true)
|
|
23
|
+
|
|
24
|
+
today_epoch=$(date -u +%s)
|
|
25
|
+
seven_days_ago=$(( today_epoch - 7 * 86400 ))
|
|
26
|
+
thirty_days_ago=$(( today_epoch - 30 * 86400 ))
|
|
27
|
+
|
|
28
|
+
count_since() {
|
|
29
|
+
local cutoff="$1"
|
|
30
|
+
local n=0
|
|
31
|
+
while IFS= read -r line; do
|
|
32
|
+
# Extract the ISO timestamp after "consulted="
|
|
33
|
+
ts=$(echo "$line" | sed -nE 's/^TELEMETRY: consulted=\[?([0-9TZ:+\-]+)\]?.*/\1/p')
|
|
34
|
+
[[ -z "$ts" ]] && continue
|
|
35
|
+
# Convert ISO → epoch (BSD `date -j` on macOS, GNU `date -d` on Linux)
|
|
36
|
+
epoch=$(date -j -u -f "%Y-%m-%dT%H:%M:%SZ" "$ts" +%s 2>/dev/null \
|
|
37
|
+
|| date -u -d "$ts" +%s 2>/dev/null \
|
|
38
|
+
|| echo 0)
|
|
39
|
+
if [[ "$epoch" -ge "$cutoff" ]]; then
|
|
40
|
+
n=$(( n + 1 ))
|
|
41
|
+
fi
|
|
42
|
+
done < <(grep -E '^TELEMETRY: consulted=' "$SKILL" || true)
|
|
43
|
+
echo "$n"
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
count_7d=$(count_since "$seven_days_ago")
|
|
47
|
+
count_30d=$(count_since "$thirty_days_ago")
|
|
48
|
+
|
|
49
|
+
echo "token-optimizer consults:"
|
|
50
|
+
echo " last 7 days: $count_7d"
|
|
51
|
+
echo " last 30 days: $count_30d"
|
|
52
|
+
echo " total active: $total"
|
|
53
|
+
echo ""
|
|
54
|
+
echo "Decision rule: <5 consults / 2 weeks sustained → P3.1 sunset audit."
|
|
@@ -60,6 +60,27 @@ platforms:
|
|
|
60
60
|
user_prompt_submit: [chat-history, verify-before-complete, minimal-safe-diff]
|
|
61
61
|
post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff]
|
|
62
62
|
|
|
63
|
+
# Cowork — the Claude desktop app's local-agent-mode runtime, built
|
|
64
|
+
# on top of the Claude Code CLI. Same lifecycle vocabulary, same
|
|
65
|
+
# event-payload shape (PascalCase native names; Stop carries
|
|
66
|
+
# `transcript_path`). Listed as a separate platform so chat-history
|
|
67
|
+
# entries can attribute events to Cowork vs CLI Claude Code via the
|
|
68
|
+
# `agent` field.
|
|
69
|
+
#
|
|
70
|
+
# Upstream caveat (anthropics/claude-code#40495, #27398): Cowork
|
|
71
|
+
# sessions currently ignore all three Claude Code settings sources
|
|
72
|
+
# (user, project, env), and `--setting-sources user` excludes
|
|
73
|
+
# plugin-scope hooks. Until those land, the dispatcher binding
|
|
74
|
+
# below is structurally ready but lifecycle events do not fire.
|
|
75
|
+
# Decision matrix + upstream blockers tracked in
|
|
76
|
+
# agents/contexts/chat-history-platform-hooks.md § Cowork.
|
|
77
|
+
cowork:
|
|
78
|
+
session_start: [chat-history, onboarding-gate, verify-before-complete, minimal-safe-diff]
|
|
79
|
+
session_end: [chat-history]
|
|
80
|
+
stop: [chat-history, verify-before-complete]
|
|
81
|
+
user_prompt_submit: [chat-history, verify-before-complete, minimal-safe-diff]
|
|
82
|
+
post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff]
|
|
83
|
+
|
|
63
84
|
# Phase 7.5 — Cursor. `.cursor/hooks.json` (project) is read by the
|
|
64
85
|
# IDE and CLI; `~/.cursor/hooks.json` (user) is opt-in via
|
|
65
86
|
# `install.py --cursor-user-hooks` and uses scripts/hooks/cursor-dispatcher.sh
|
|
@@ -146,6 +167,18 @@ native_event_aliases:
|
|
|
146
167
|
PostToolUse: post_tool_use
|
|
147
168
|
PreToolUse: pre_tool_use
|
|
148
169
|
PreCompact: pre_compact
|
|
170
|
+
# Cowork shares Claude Code's PascalCase event vocabulary verbatim
|
|
171
|
+
# (Cowork is Claude Code under the hood). Native names are duplicated
|
|
172
|
+
# here rather than aliased so dispatcher logs / feedback carry the
|
|
173
|
+
# platform tag the operator expects.
|
|
174
|
+
cowork:
|
|
175
|
+
SessionStart: session_start
|
|
176
|
+
SessionEnd: session_end
|
|
177
|
+
Stop: stop
|
|
178
|
+
UserPromptSubmit: user_prompt_submit
|
|
179
|
+
PostToolUse: post_tool_use
|
|
180
|
+
PreToolUse: pre_tool_use
|
|
181
|
+
PreCompact: pre_compact
|
|
149
182
|
cursor:
|
|
150
183
|
sessionStart: session_start
|
|
151
184
|
sessionEnd: session_end
|
|
@@ -21,6 +21,16 @@ set -u
|
|
|
21
21
|
|
|
22
22
|
EVENT_DATA="$(cat)"
|
|
23
23
|
|
|
24
|
+
# Debug-only: when ~/.augment/.chat-history-debug exists, dump the raw
|
|
25
|
+
# stdin payload for offline inspection. No-op otherwise. Used to probe
|
|
26
|
+
# what Augment's hook events actually carry.
|
|
27
|
+
if [ -f "$HOME/.augment/.chat-history-debug" ]; then
|
|
28
|
+
DUMP_DIR="$HOME/.augment/chat-history-debug"
|
|
29
|
+
mkdir -p "$DUMP_DIR" 2>/dev/null
|
|
30
|
+
printf '%s' "$EVENT_DATA" \
|
|
31
|
+
> "$DUMP_DIR/event-$(date +%Y%m%d-%H%M%S)-$$.json" 2>/dev/null || true
|
|
32
|
+
fi
|
|
33
|
+
|
|
24
34
|
# Extract workspace_roots[0] using whichever JSON tool is available.
|
|
25
35
|
WORKSPACE=""
|
|
26
36
|
if command -v jq >/dev/null 2>&1; then
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Cowork universal hook trampoline.
|
|
3
|
+
#
|
|
4
|
+
# Cowork is the Claude desktop app's local-agent-mode runtime. It runs
|
|
5
|
+
# the Claude Code CLI inside a sandbox VM, so hook events use the
|
|
6
|
+
# Claude Code shape (PascalCase native names; Stop carries
|
|
7
|
+
# `transcript_path`). The payload typically carries `cwd` (Claude
|
|
8
|
+
# Code's standard field) rather than Augment's `workspace_roots[0]`.
|
|
9
|
+
# We accept either, falling back through both.
|
|
10
|
+
#
|
|
11
|
+
# Upstream caveat: as of writing this trampoline, lifecycle events do
|
|
12
|
+
# not actually fire from Cowork sessions —
|
|
13
|
+
# anthropics/claude-code#40495 reports all three Claude Code settings
|
|
14
|
+
# sources (user, project, env) are ignored inside Cowork's sandbox,
|
|
15
|
+
# and #27398 reports plugin-scope `hooks/hooks.json` is excluded
|
|
16
|
+
# because Cowork spawns the CLI with `--setting-sources user`. The
|
|
17
|
+
# trampoline is structurally ready; install plumbing is deferred
|
|
18
|
+
# until upstream resolves the bugs and a stable settings location is
|
|
19
|
+
# documented. See `agents/contexts/chat-history-platform-hooks.md`
|
|
20
|
+
# § Cowork.
|
|
21
|
+
#
|
|
22
|
+
# Behaviour mirrors cursor-dispatcher.sh:
|
|
23
|
+
# - Read JSON event from stdin into a buffer.
|
|
24
|
+
# - Extract cwd (Claude Code) or workspace_roots[0] (fallback);
|
|
25
|
+
# bail silently when neither resolves to a directory.
|
|
26
|
+
# - cd into that workspace; bail silently when it lacks ./agent-config.
|
|
27
|
+
# - Re-pipe the original JSON into
|
|
28
|
+
# ./agent-config dispatch:hook --platform cowork \
|
|
29
|
+
# --event $1 --native-event $2
|
|
30
|
+
# - Always exit 0 — chat-history must never block the agent loop.
|
|
31
|
+
|
|
32
|
+
set -u
|
|
33
|
+
|
|
34
|
+
# Args from the platform's hooks config (whatever shape Cowork ends up
|
|
35
|
+
# using once upstream lands the fix):
|
|
36
|
+
# $1 = agent-config event name (session_start, post_tool_use, …)
|
|
37
|
+
# $2 = Cowork-native event name (SessionStart, PostToolUse, …)
|
|
38
|
+
EVENT="${1-}"
|
|
39
|
+
NATIVE_EVENT="${2-}"
|
|
40
|
+
|
|
41
|
+
if [ -z "$EVENT" ]; then
|
|
42
|
+
exit 0
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
EVENT_DATA="$(cat)"
|
|
46
|
+
|
|
47
|
+
# Debug-only: when ~/.claude/.cowork-chat-history-debug exists, dump
|
|
48
|
+
# the raw stdin payload for offline inspection. No-op otherwise.
|
|
49
|
+
# Useful once upstream fixes #40495 to verify the actual payload shape.
|
|
50
|
+
if [ -f "$HOME/.claude/.cowork-chat-history-debug" ]; then
|
|
51
|
+
DUMP_DIR="$HOME/.claude/cowork-chat-history-debug"
|
|
52
|
+
mkdir -p "$DUMP_DIR" 2>/dev/null
|
|
53
|
+
printf '%s' "$EVENT_DATA" \
|
|
54
|
+
> "$DUMP_DIR/event-$(date +%Y%m%d-%H%M%S)-$$.json" 2>/dev/null || true
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
# Extract workspace path. Try Claude Code's `cwd` first, then fall
|
|
58
|
+
# back to Augment-style `workspace_roots[0]`. Either is acceptable —
|
|
59
|
+
# we need a directory containing ./agent-config.
|
|
60
|
+
WORKSPACE=""
|
|
61
|
+
if command -v jq >/dev/null 2>&1; then
|
|
62
|
+
WORKSPACE="$(printf '%s' "$EVENT_DATA" \
|
|
63
|
+
| jq -r '.cwd // .workspace_roots[0] // empty' 2>/dev/null)"
|
|
64
|
+
elif command -v python3 >/dev/null 2>&1; then
|
|
65
|
+
WORKSPACE="$(printf '%s' "$EVENT_DATA" | python3 -c '
|
|
66
|
+
import json, sys
|
|
67
|
+
try:
|
|
68
|
+
data = json.load(sys.stdin)
|
|
69
|
+
except Exception:
|
|
70
|
+
sys.exit(0)
|
|
71
|
+
cwd = data.get("cwd")
|
|
72
|
+
if isinstance(cwd, str) and cwd:
|
|
73
|
+
print(cwd)
|
|
74
|
+
sys.exit(0)
|
|
75
|
+
roots = data.get("workspace_roots") or []
|
|
76
|
+
if roots:
|
|
77
|
+
print(roots[0])
|
|
78
|
+
' 2>/dev/null)"
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
if [ -z "$WORKSPACE" ] || [ ! -d "$WORKSPACE" ]; then
|
|
82
|
+
exit 0
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
cd "$WORKSPACE" 2>/dev/null || exit 0
|
|
86
|
+
|
|
87
|
+
if [ ! -x ./agent-config ]; then
|
|
88
|
+
exit 0
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
printf '%s' "$EVENT_DATA" \
|
|
92
|
+
| ./agent-config dispatch:hook \
|
|
93
|
+
--platform cowork \
|
|
94
|
+
--event "$EVENT" \
|
|
95
|
+
--native-event "$NATIVE_EVENT" \
|
|
96
|
+
>/dev/null 2>&1 || true
|
|
97
|
+
|
|
98
|
+
exit 0
|
|
@@ -167,6 +167,40 @@ def _resolve_concerns(manifest: dict, platform: str, event: str) -> list[dict]:
|
|
|
167
167
|
return out
|
|
168
168
|
|
|
169
169
|
|
|
170
|
+
def _maybe_capture_payload(args: argparse.Namespace, payload_text: str) -> None:
|
|
171
|
+
"""Write the raw stdin payload to a capture directory when
|
|
172
|
+
``AGENT_HOOK_CAPTURE_DIR`` is set. Used by the verified-platforms
|
|
173
|
+
discovery roadmap (`agents/roadmaps/road-to-verified-chat-history-platforms.md`)
|
|
174
|
+
to lock real payload shapes before extractor branches are added.
|
|
175
|
+
|
|
176
|
+
Fail-silent: any IO / JSON error must not break dispatch.
|
|
177
|
+
"""
|
|
178
|
+
capture_dir = os.environ.get("AGENT_HOOK_CAPTURE_DIR", "").strip()
|
|
179
|
+
if not capture_dir:
|
|
180
|
+
return
|
|
181
|
+
try:
|
|
182
|
+
target = Path(capture_dir).expanduser()
|
|
183
|
+
target.mkdir(parents=True, exist_ok=True)
|
|
184
|
+
try:
|
|
185
|
+
payload = json.loads(payload_text) if payload_text.strip() else {}
|
|
186
|
+
except (ValueError, TypeError):
|
|
187
|
+
payload = {"_raw_text": payload_text}
|
|
188
|
+
record = {
|
|
189
|
+
"captured_at": _now_iso(),
|
|
190
|
+
"platform": args.platform,
|
|
191
|
+
"event": args.event,
|
|
192
|
+
"native_event": args.native_event or "",
|
|
193
|
+
"raw_payload": payload,
|
|
194
|
+
}
|
|
195
|
+
ts = int(time.time() * 1000)
|
|
196
|
+
native = (args.native_event or args.event).replace("/", "_")
|
|
197
|
+
fname = f"{args.platform}__{native}__{ts}__{os.getpid()}.json"
|
|
198
|
+
(target / fname).write_text(
|
|
199
|
+
json.dumps(record, indent=2) + "\n", encoding="utf-8")
|
|
200
|
+
except OSError:
|
|
201
|
+
return
|
|
202
|
+
|
|
203
|
+
|
|
170
204
|
def _build_envelope(args: argparse.Namespace, payload_text: str) -> dict:
|
|
171
205
|
try:
|
|
172
206
|
payload = json.loads(payload_text) if payload_text.strip() else {}
|
|
@@ -298,6 +332,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
298
332
|
manifest = _load_yaml(manifest_path)
|
|
299
333
|
|
|
300
334
|
payload_text = "" if sys.stdin.isatty() else sys.stdin.read()
|
|
335
|
+
_maybe_capture_payload(args, payload_text)
|
|
301
336
|
concerns = _resolve_concerns(manifest, args.platform, args.event)
|
|
302
337
|
|
|
303
338
|
if args.dry_run:
|
package/scripts/hooks_status.py
CHANGED
|
@@ -25,9 +25,20 @@ import dispatch_hook # noqa: E402 — reuse the manifest loader
|
|
|
25
25
|
|
|
26
26
|
# (label, project-relative bridge path, install hint).
|
|
27
27
|
# Path may be a directory (cline) — existence => any file inside.
|
|
28
|
+
#
|
|
29
|
+
# Cowork has no project-scope bridge path: the Claude desktop app's
|
|
30
|
+
# local-agent-mode runtime is upstream-blocked from reading any of
|
|
31
|
+
# Claude Code's three settings sources (anthropics/claude-code#40495,
|
|
32
|
+
# #27398). We register cowork here so the manifest's `cowork:`
|
|
33
|
+
# bindings are surfaced in the status report, but the empty bridge
|
|
34
|
+
# path resolves to status="n/a" — strict mode does not fail on
|
|
35
|
+
# n/a (see _final_exit_code), matching Copilot's no-bridge posture.
|
|
36
|
+
# Once upstream lands the fix and a stable settings location is
|
|
37
|
+
# documented, swap the empty path here for that location.
|
|
28
38
|
PLATFORM_BRIDGES: dict[str, tuple[str, str]] = {
|
|
29
39
|
"augment": (".augment/settings.json", "scripts/install.py"),
|
|
30
40
|
"claude": (".claude/settings.json", "scripts/install.py"),
|
|
41
|
+
"cowork": ("", "upstream-blocked: anthropics/claude-code#40495 + #27398 (settings.json ignored in Cowork sandbox)"),
|
|
31
42
|
"cursor": (".cursor/hooks.json", "scripts/install.py"),
|
|
32
43
|
"cline": (".clinerules/hooks", "scripts/install.py"),
|
|
33
44
|
"windsurf": (".windsurf/hooks.json", "scripts/install.py"),
|
|
@@ -65,7 +76,7 @@ def collect(project_root: Path, manifest: dict) -> dict:
|
|
|
65
76
|
"bridge_path": rel or None,
|
|
66
77
|
"fallback_only": fallback_only,
|
|
67
78
|
"bindings": bindings,
|
|
68
|
-
"hint": hint if status in {"missing", "empty", "degraded"} else None,
|
|
79
|
+
"hint": hint if status in {"missing", "empty", "degraded", "n/a"} else None,
|
|
69
80
|
})
|
|
70
81
|
return {"schema_version": 1, "platforms": rows}
|
|
71
82
|
|
package/scripts/install-hooks.sh
CHANGED
|
@@ -63,7 +63,7 @@ echo "✅ Pre-commit hook installed."
|
|
|
63
63
|
# lifecycle hooks) cannot fire SessionStart/Stop/PostToolUse. Git hooks
|
|
64
64
|
# are the platform-agnostic lifecycle surface that fires regardless of
|
|
65
65
|
# IDE — every commit, merge, checkout, and rewrite turns into a phase
|
|
66
|
-
# boundary in
|
|
66
|
+
# boundary in agents/.agent-chat-history when an agent session is active.
|
|
67
67
|
#
|
|
68
68
|
# The hooks are silent no-ops when no agent session is active (the
|
|
69
69
|
# chat_history.py hook-append script returns "skipped_no_sidecar" with
|
|
@@ -75,7 +75,7 @@ write_chat_history_hook() {
|
|
|
75
75
|
local phase_tag="$2"
|
|
76
76
|
cat > "$HOOKS_DIR/$name" << EOF
|
|
77
77
|
#!/usr/bin/env bash
|
|
78
|
-
# $name: append a phase boundary to
|
|
78
|
+
# $name: append a phase boundary to agents/.agent-chat-history when an agent
|
|
79
79
|
# session is active. Silent no-op otherwise. Never blocks git.
|
|
80
80
|
|
|
81
81
|
if [ -x ./agent-config ]; then
|