@event4u/agent-config 2.0.0 → 2.2.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/fix/{pr-bots.md → pr-bot-comments.md} +3 -3
- package/.agent-src/commands/fix/{pr.md → pr-comments.md} +6 -6
- package/.agent-src/commands/fix/{pr-developers.md → pr-developer-comments.md} +3 -3
- package/.agent-src/commands/fix.md +6 -6
- package/.agent-src/contexts/communication/rules-auto/slash-command-routing-policy-mechanics.md +2 -2
- package/.agent-src/rules/no-cheap-questions.md +11 -2
- package/.agent-src/skills/readme-writing-package/SKILL.md +24 -0
- package/.claude-plugin/marketplace.json +4 -4
- package/CHANGELOG.md +79 -0
- package/README.md +76 -12
- package/docs/architecture.md +2 -2
- package/docs/catalog.md +3 -3
- package/docs/contracts/command-clusters.md +3 -3
- package/docs/contracts/file-ownership-matrix.json +9 -9
- package/docs/contracts/tier-3-contrib-plugin.md +129 -0
- package/docs/decisions/ADR-007-agent-discovery-scopes.md +278 -0
- package/docs/decisions/ADR-008-installed-tools-manifest.md +160 -0
- package/docs/decisions/INDEX.md +2 -0
- package/docs/getting-started.md +16 -25
- package/docs/guidelines/agent-infra/asking-and-brevity-examples.md +32 -0
- package/docs/guidelines/agent-infra/installed-tools-manifest.md +135 -0
- package/docs/installation.md +116 -49
- package/docs/migrations/commands-1.15.0.md +3 -3
- package/docs/setup/per-ide/claude-desktop.md +8 -4
- package/docs/skills-catalog.md +23 -2
- package/docs/troubleshooting.md +20 -32
- package/llms.txt +22 -1
- package/package.json +1 -1
- package/scripts/_cli/cmd_export.py +157 -0
- package/scripts/_cli/cmd_sync.py +162 -0
- package/scripts/_cli/cmd_update.py +23 -1
- package/scripts/_cli/cmd_validate.py +164 -0
- package/scripts/_lib/installed_lock.py +160 -0
- package/scripts/_lib/installed_tools.py +237 -0
- package/scripts/agent-config +62 -0
- package/scripts/install +68 -13
- package/scripts/install.py +984 -33
- package/scripts/install.sh +6 -11
- package/templates/agent-config-wrapper.sh +40 -25
- package/templates/consumer-settings/README.md +2 -2
- package/scripts/setup.sh +0 -230
package/docs/troubleshooting.md
CHANGED
|
@@ -30,11 +30,11 @@ If any of these are missing or empty, the installer either didn't run or
|
|
|
30
30
|
was interrupted. Re-run it:
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
|
-
php vendor/bin/install.php --verbose
|
|
34
|
-
# or
|
|
35
33
|
bash scripts/install --verbose
|
|
36
34
|
# or, to regenerate everything (overwrites existing bridge files):
|
|
37
35
|
bash scripts/install --force
|
|
36
|
+
# or, for one-shot installs without a local node_modules tree:
|
|
37
|
+
npx @event4u/create-agent-config init --tools=claude-code,cursor
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
### Check 2: Does your agent actually read these directories?
|
|
@@ -61,44 +61,34 @@ version explicitly and reinstall the plugin.
|
|
|
61
61
|
|
|
62
62
|
---
|
|
63
63
|
|
|
64
|
-
##
|
|
64
|
+
## Installer ran but no files appeared
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
The v2 distribution does **not** ship a `postinstall` hook — installing
|
|
67
|
+
`@event4u/agent-config` via `npm install -g` only puts the `agent-config`
|
|
68
|
+
binary on `$PATH`; it does not seed any project files. Run the
|
|
69
|
+
orchestrator explicitly inside the project root:
|
|
67
70
|
|
|
68
71
|
```bash
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
ignore-scripts=true
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
In that case, the post-install hook never runs. Execute the installer
|
|
75
|
-
manually:
|
|
72
|
+
# One-shot, no local checkout required (recommended)
|
|
73
|
+
npx @event4u/create-agent-config init --tools=claude-code,cursor
|
|
76
74
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
# or for npm — invoke the orchestrator directly:
|
|
80
|
-
bash node_modules/@event4u/agent-config/scripts/install
|
|
75
|
+
# When the global CLI is installed
|
|
76
|
+
agent-config install --tools=claude-code,cursor
|
|
81
77
|
```
|
|
82
78
|
|
|
83
|
-
The [`scripts/postinstall.sh`](../scripts/postinstall.sh) wrapper prints a
|
|
84
|
-
loud error block when the underlying installer fails, so if you saw no
|
|
85
|
-
output at all, scripts are likely disabled on your side.
|
|
86
|
-
|
|
87
79
|
---
|
|
88
80
|
|
|
89
|
-
## Broken symlinks after
|
|
81
|
+
## Broken symlinks after upgrading the package
|
|
90
82
|
|
|
91
83
|
When the package version changes, symlinks that pointed to the old
|
|
92
|
-
|
|
84
|
+
package path may break. Re-run the installer — it is idempotent:
|
|
93
85
|
|
|
94
86
|
```bash
|
|
95
|
-
|
|
96
|
-
# or
|
|
97
|
-
bash scripts/install
|
|
87
|
+
npx @event4u/create-agent-config init --tools=claude-code,cursor
|
|
98
88
|
```
|
|
99
89
|
|
|
100
90
|
The installer replaces stale symlinks with fresh ones pointing at the
|
|
101
|
-
current
|
|
91
|
+
current package path.
|
|
102
92
|
|
|
103
93
|
---
|
|
104
94
|
|
|
@@ -108,8 +98,8 @@ Native Windows is not a first-class target. The installer relies on Bash
|
|
|
108
98
|
and Unix-style symlinks. Recommended setup:
|
|
109
99
|
|
|
110
100
|
1. **WSL2** (preferred): install Ubuntu or a distribution of your choice,
|
|
111
|
-
clone the project inside the WSL filesystem, and run
|
|
112
|
-
|
|
101
|
+
clone the project inside the WSL filesystem, and run
|
|
102
|
+
`npx @event4u/create-agent-config init` from WSL.
|
|
113
103
|
2. **Git Bash**: works for the basic install, but symlinks require
|
|
114
104
|
Developer Mode (Windows 10 1703+) or admin privileges. Without either,
|
|
115
105
|
Git Bash falls back to copies, which means updates will not propagate
|
|
@@ -142,15 +132,13 @@ There is no dedicated uninstall command yet. Remove the package and
|
|
|
142
132
|
clean up manually:
|
|
143
133
|
|
|
144
134
|
```bash
|
|
145
|
-
# 1. Remove the dependency
|
|
146
|
-
composer remove event4u/agent-config
|
|
147
|
-
# or
|
|
135
|
+
# 1. Remove the dependency (skip when installed via npx / -g)
|
|
148
136
|
npm uninstall @event4u/agent-config
|
|
149
137
|
|
|
150
138
|
# 2. Remove generated content from the project
|
|
151
139
|
rm -rf .augment .claude .cursor .clinerules .windsurfrules GEMINI.md
|
|
152
140
|
rm -f .agent-settings .agent-settings.yml .agent-settings.backup.key-value
|
|
153
|
-
rm -f .github/copilot-instructions.md
|
|
141
|
+
rm -f .github/copilot-instructions.md agent-config
|
|
154
142
|
# Remove the "# event4u/agent-config" block from .gitignore manually
|
|
155
143
|
```
|
|
156
144
|
|
|
@@ -163,5 +151,5 @@ Keep `AGENTS.md` if you customized it — it is yours, not the package's.
|
|
|
163
151
|
Open an [issue](https://github.com/event4u-app/agent-config/issues) with:
|
|
164
152
|
|
|
165
153
|
- your OS and shell,
|
|
166
|
-
-
|
|
154
|
+
- Node / Python versions,
|
|
167
155
|
- full output of `bash scripts/install --verbose --dry-run`.
|
package/llms.txt
CHANGED
|
@@ -6,6 +6,7 @@ Machine-readable index of all skills in this package. Each line:
|
|
|
6
6
|
Source: .agent-src/skills/<name>/SKILL.md
|
|
7
7
|
Catalog: docs/skills-catalog.md
|
|
8
8
|
|
|
9
|
+
accessibility-auditor: Use when reviewing UI for accessibility — WCAG 2.2 AA, keyboard nav, focus, ARIA, contrast, screen-reader semantics — even on 'is this a11y-OK?' or 'mach das barrierefrei'.
|
|
9
10
|
adr-create: Use when capturing an architectural decision — naming the file, picking the next ADR number, filling Status / Context / Decision / Consequences, and regenerating the index — even without saying 'ADR'.
|
|
10
11
|
adversarial-review: ONLY when user explicitly requests adversarial review, devil's advocate analysis, stress-testing a plan, or 'poke holes in this' — NOT for regular code review or design feedback.
|
|
11
12
|
agent-docs-writing: Use when reading, creating, or updating agent documentation, module docs, roadmaps, or AGENTS.md. Understands the full .augment/, agents/, and copilot-instructions structure.
|
|
@@ -16,6 +17,7 @@ analysis-skill-router: Use when picking which analysis or project-analysis-* ski
|
|
|
16
17
|
api-design: Use when designing APIs, planning endpoints, REST conventions, versioning, or deprecation — even when the user just says 'expose this as an endpoint' without naming API design.
|
|
17
18
|
api-endpoint: Use when the user says "create endpoint", "new API route", or "add controller". Creates a complete endpoint with Controller, FormRequest, Resource, route, and OpenAPI docs.
|
|
18
19
|
api-testing: Use when writing API endpoint tests — integration tests, contract validation, response assertions, mocked external services — even when the user says 'test this route' without naming API testing.
|
|
20
|
+
architecture-review-lens: Use when a diff may break system boundaries, dependency direction, or cross-service contracts — fifth judge dispatched by /review-changes alongside the four standard judges.
|
|
19
21
|
artisan-commands: Use when creating or modifying Artisan commands. Covers clear signatures, safe execution flow, helpful output, and project conventions for console tooling.
|
|
20
22
|
async-python-patterns: Use when writing Python asyncio code — picking between gather / TaskGroup / wait, structured concurrency, timeouts, cancellation, sync-bridging — decision framework only, cookbook externalized.
|
|
21
23
|
authz-review: Use when reviewing authorization end-to-end — route → gate → policy → query scope → response filter — before changes to permissions, tenants, ownership, or admin flows.
|
|
@@ -28,16 +30,19 @@ code-refactoring: Use when the user says "refactor this", "rename class", or "mo
|
|
|
28
30
|
code-review: Use when the user says "review this", "check my code", or wants feedback on changes. Reviews for correctness, quality, security, and coding standards.
|
|
29
31
|
command-routing: Use when the user invokes a slash command like /create-pr, /commit, /fix-ci, or pastes command file content — routes to the right command with context inference and GitHub API patterns.
|
|
30
32
|
command-writing: Use when creating or editing a slash command in .agent-src.uncompressed/commands/ — frontmatter, numbered steps, safety gates — even when the user just says 'add a /command for X'.
|
|
33
|
+
competitive-positioning: Use when comparing this package to a peer / competitor — ours-vs-theirs verdict table, axis selection, adoption queue. Triggers on 'how do we compare to X', 'should we adopt their pattern'.
|
|
31
34
|
composer-packages: Use when building or maintaining a Composer library — versioning, Laravel integration, autoloading, publishing to private registries — even when the user says 'release a new version'.
|
|
32
35
|
context-authoring: Use when filling in knowledge-layer context files — auth-model, tenant-boundaries, data-sensitivity, deployment-order, observability — interactive walkthrough that turns templates into reviewer fuel.
|
|
33
36
|
context-document: Use when the user says "create context", "document this area", or wants a structured snapshot of a codebase area for agent orientation.
|
|
34
37
|
conventional-commits-writing: Use when writing commit messages or squash-merge titles — `feat:`, `fix:`, `chore:`, scopes, breaking changes — even when the user just says 'commit this' without naming Conventional Commits.
|
|
35
38
|
copilot-agents-optimization: Use when optimizing AGENTS.md or copilot-instructions.md — deduplicates against .augment/ content, enforces line budgets, and focuses each file on its audience.
|
|
36
39
|
copilot-config: Use when configuring GitHub Copilot — copilot-instructions.md, PR review patterns, output optimization — even when the user just says 'tune Copilot' or 'why is Copilot commenting on X'.
|
|
40
|
+
customer-research: Use when shaping a discovery slice — JTBD-framed interview guide, switch-event focus, verbatim quotes not summaries. Triggers on 'talk to users', 'why did they cancel', 'before we build X'.
|
|
37
41
|
dashboard-design: Use when designing monitoring dashboards — visualization selection, layout principles, observability strategies (RED/USE/Golden Signals), and data storytelling.
|
|
38
42
|
data-flow-mapper: Use BEFORE editing code that touches user data — traces the value from entry → validation → transformation → storage → egress, every hop cited with file:line.
|
|
39
43
|
database: Use when working with database architecture, MariaDB/MySQL tuning, indexing strategies, slow queries, or multi-connection patterns — even when the user just says 'this query is slow'.
|
|
40
44
|
dcf-modeling: Wing-4 valuation cognition for a CFO / finance-partner. Use when a deal, internal investment, or board ask names DCF, intrinsic value, WACC, terminal value, or 'what's it worth on a 5-year hold'.
|
|
45
|
+
decision-record: Use when locking a trade-off, structuring an ADR draft, or wiring supersession chains — frames options · trade-offs · consequences before the file is written by `adr-create`.
|
|
41
46
|
deep-reading-analyst: Deep analysis of articles/long-form via thinking frameworks (SCQA, mental models, inversion) — 'analyze article', 'deep dive', 'extract insights', URL/text wanting depth not summary.
|
|
42
47
|
defense-in-depth: Use when validation needs entry, business-logic, environment, and instrumentation guards so a bad value cannot reach the failure point — turns a local bug fix into a structural one.
|
|
43
48
|
dependency-upgrade: Use when upgrading dependencies — "update Laravel", "bump PHP version", or "upgrade packages". Covers changelog review, breaking change detection, and verification.
|
|
@@ -45,6 +50,7 @@ description-assist: Use when polishing a skill/rule/command/guideline frontmatte
|
|
|
45
50
|
design-review: Use when the user says "review the design", "check the UI", or wants a comprehensive UI/UX review. Uses a 7-phase methodology covering interaction, responsiveness, accessibility, and more.
|
|
46
51
|
devcontainer: Use when configuring DevContainers or GitHub Codespaces — devcontainer.json, custom images, secrets, VS Code features — even when the user just says 'why does my Codespace not start'.
|
|
47
52
|
developer-like-execution: Use when implementing, debugging, refactoring, or reviewing code — enforces the think → analyze → verify → execute workflow — even when the user just says 'implement X' without naming it.
|
|
53
|
+
discovery-interview: Use when running discovery interviews — question-bank build, bias audit, insight extraction. Triggers on 'audit my guide', 'extract insights from transcript', 'is my hypothesis falsifiable'.
|
|
48
54
|
docker: Use when working with Docker — Dockerfile edits, docker-compose services, containers, or the dual-container (fast + Xdebug) setup — even when the user just says 'my container won't start'.
|
|
49
55
|
dto-creator: Use when the user says "create a DTO", "new data transfer object", or needs to convert request/response data into a typed PHP class. Creates DTOs with SimpleDto base class and attribute mapping.
|
|
50
56
|
eloquent: Use when writing Eloquent models, relationships, scopes, or queries via Model:: — 'fetch users with their orders'. NOT for PHPStan output, non-Eloquent services, or raw SQL questions.
|
|
@@ -56,11 +62,13 @@ feature-planning: Use when the user says "plan a feature", "brainstorm", "explor
|
|
|
56
62
|
file-editor: Use when opening edited files in the user's IDE. Reads settings from .agent-settings.yml to determine IDE and whether auto-open is enabled.
|
|
57
63
|
finishing-a-development-branch: Use when the feature is implementation-complete and the next step is 'ship it' — verifies, cleans up, and routes to merge/PR/park/discard — even when the user just says 'I'm done, what now?'.
|
|
58
64
|
flux: Use when the project uses `livewire/flux` — dispatched by `directives/ui/{apply,review,polish}.py`. Covers Flux components, slots, variants, and form primitives.
|
|
65
|
+
form-handler: Use when designing or reviewing a form — validation timing, error display, submission lifecycle, optimistic UI, dirty/pristine state, idempotency — even on 'why does submit double-fire?'.
|
|
59
66
|
funnel-analysis: Use when diagnosing where a SaaS or product funnel leaks — visitor → signup → activation → paid → retained — channel-agnostic, conversion-rate-driven.
|
|
60
67
|
git-workflow: Use when working with Git — branch naming, commit messages, PR creation, rebasing, or the code review process — even when the user says 'push this' or 'merge the branch' without naming Git.
|
|
61
68
|
github-ci: Use when working with GitHub Actions — workflow YAML, quality gates, test matrices, deployment triggers, reusable workflows — even when the user just says 'my CI is failing' or 'add a check'.
|
|
62
69
|
grafana: Use when working with Grafana — dashboards, Loki LogQL queries, alerting rules, monitoring panels — even when the user just says 'build me a dashboard' or 'query the logs' without naming Grafana.
|
|
63
70
|
guideline-writing: Use when creating or editing a guideline in docs/guidelines/ — reference material cited by skills, no auto-triggers — even when the user just says 'write up our naming conventions'.
|
|
71
|
+
incident-commander: Use during or right after an incident — frames severity, sets comms cadence, drafts the post-mortem skeleton — even when the user just says 'production is down' or 'wir haben einen Vorfall'.
|
|
64
72
|
jira-integration: Use when the user says "check Jira", "create ticket", "update issue", or needs JQL queries, ticket transitions, or branch-to-ticket linking.
|
|
65
73
|
jobs-events: Use when creating Laravel jobs, queued workflows, events, or listeners. Covers clear responsibilities, safe serialization, and retry/failure handling.
|
|
66
74
|
judge-bug-hunter: Use when a diff needs correctness review — null-safety, edge cases, off-by-one, races, error handling — dispatched by /review-changes, /do-and-judge, /judge, even without 'judge'.
|
|
@@ -77,15 +85,19 @@ laravel-pulse: Use when setting up Laravel Pulse — real-time dashboard, built-
|
|
|
77
85
|
laravel-reverb: Use when configuring Laravel Reverb — the first-party WebSocket server with Pusher protocol compatibility, horizontal scaling, and Pulse monitoring.
|
|
78
86
|
laravel-scheduling: Use when configuring Laravel task scheduling — cron expressions, frequency helpers, overlap prevention, maintenance mode, or output handling.
|
|
79
87
|
laravel-validation: Use when writing validation — Form Requests, rules, custom rule objects, request-boundary design — even when the user just says 'validate this input' or 'check the request' without naming it.
|
|
88
|
+
launch-readiness: Use before merging a release-shaped PR — pre-merge checklist, rollout plan, rollback criteria, ops handoff. Triggers on 'ready to ship', 'launch checklist', 'rollout plan for X'.
|
|
80
89
|
learning-to-rule-or-skill: Use when a repeated learning, mistake, or successful pattern should be turned into a new rule or skill. Also use after completing a task to capture learnings from the work.
|
|
81
90
|
lint-skills: Use when running the package's skill linter against all skills and rules to validate frontmatter, required sections, and execution metadata.
|
|
82
91
|
livewire: Use when the project's frontend stack is Livewire — dispatched by `directives/ui/{apply,review,polish}.py`. Covers reactive state, events, lifecycle hooks, and component/view separation.
|
|
92
|
+
livewire-architect: Use when shaping a Livewire component before code — full-page vs partial, parent/child split, event flow, state-vs-props boundary, hydration cost — even on 'add this Livewire component'.
|
|
83
93
|
logging-monitoring: Use when working with logging or monitoring — Sentry error tracking, Grafana/Loki log aggregation, structured logging channels, or monitoring helpers.
|
|
84
94
|
markitdown: Use when converting PDF, DOCX, XLSX, PPTX, EPUB, images, or audio to Markdown for LLM ingestion via the upstream markitdown-mcp server — 'extract this PDF', 'OCR this image', 'transcribe this audio'.
|
|
85
95
|
mcp: Use when working with MCP (Model Context Protocol) servers — their tools, capabilities, and best practices for effective agent workflows.
|
|
86
96
|
mcp-builder: Use when building an MCP server in Python (FastMCP) or Node/TypeScript (MCP SDK) — agent-centric tool design, input schemas, error handling, and the 10-question evaluation harness.
|
|
87
97
|
md-language-check: Use BEFORE saving any .md under .augment/, .agent-src*/, or agents/ — scans umlauts, German function words, and quoted German phrases outside DE:/EN: anchor blocks. Hard gate per language-and-tone.
|
|
98
|
+
memory-consolidation: Use when consolidating session signals into curated memory — four-phase loop ORIENT → GATHER → CONSOLIDATE → PRUNE. Triggers on 'mine my sessions', 'consolidate memory', 'review intake signals'.
|
|
88
99
|
merge-conflicts: Use when the user has merge conflicts or says "resolve conflicts". Understands conflict markers, resolution strategies, and verification workflow.
|
|
100
|
+
migration-architect: Use when shaping a non-trivial migration — rollout phases, dual-write windows, cutover sequencing, deprecation cycles — hands off to `migration-creator` for DDL once locked.
|
|
89
101
|
migration-creator: Use when the user says "create migration", "add column", or "new table". Creates migrations with correct table prefixes, column naming, and multi-tenant awareness.
|
|
90
102
|
mobile-e2e-strategy: Use when picking a mobile E2E framework — Detox / Appium / Maestro / XCUITest / Espresso — or planning iOS Simulator / Android Emulator coverage in CI for RN, Expo, or native apps.
|
|
91
103
|
module-management: Use when the user says "create module", "explore module", or works within app/Modules/. Understands module structure, auto-loading, route registration, and namespace conventions.
|
|
@@ -100,7 +112,9 @@ pest-testing: Use when writing, generating, or improving Pest tests for Laravel
|
|
|
100
112
|
php-coder: Writes or edits PHP code — controllers, classes, type hints, SOLID refactors, modern idioms — even without naming PHP. NOT for writing tests (use pest-testing) or explaining PHP concepts.
|
|
101
113
|
php-debugging: Use when debugging PHP with Xdebug — breakpoints, step-through, dual-container setup, IDE configuration, header-based routing — even when the user just says 'why does this blow up on request X'.
|
|
102
114
|
php-service: Use when the user says 'create service', 'new service class', or needs a PHP service following SOLID principles with proper DI and repository usage.
|
|
115
|
+
playwright-architect: Use when shaping a Playwright suite — locator strategy, Page Object boundaries, fixture composition, flake-prevention architecture, CI-vs-local split — even on 'design our E2E tests'.
|
|
103
116
|
playwright-testing: Use when writing Playwright E2E tests — browser automation, visual regression testing, Page Objects, fixtures, and reliable test patterns.
|
|
117
|
+
po-discovery: Use when shaping a fuzzy product ask into a refined backlog item — problem framing, user-story rewrite, AC tightening — even if the user just says 'help me write this ticket'.
|
|
104
118
|
project-analysis-core: Use for the universal deep-analysis workflow: project discovery, version resolution, docs loading, architecture mapping, execution flow, and package research.
|
|
105
119
|
project-analysis-hypothesis-driven: Use when a bug has multiple plausible causes across layers — competing hypotheses, validation loops, evidence-based conclusions — even when the user just says 'why is this happening?'.
|
|
106
120
|
project-analysis-laravel: Use for deep Laravel project analysis: boot flow, request lifecycle, container usage, Eloquent/data flow, async systems, and Laravel-specific failure patterns.
|
|
@@ -122,10 +136,12 @@ readme-writing-package: Use when creating or rewriting a README for a reusable p
|
|
|
122
136
|
receiving-code-review: Use when processing code review feedback (bot or human) before changing anything — triages, verifies, and pushes back with technical reasoning — even when the user just says 'fix the comments'.
|
|
123
137
|
"refine-prompt": Reconstruct a free-form prompt into actionable AC + assumptions + confidence band before the engine plans — '/work \"…\"', 'baue X', 'ist der Prompt klar genug für die Engine?'.
|
|
124
138
|
"refine-ticket": Refine a Jira/Linear ticket before planning — 'refine ticket', 'tighten AC on PROJ-123', 'ist das Ticket klar?' — rewritten ticket, Top-5 risks, persona voices, sub-skills orchestrated, close-prompt.
|
|
139
|
+
release-comms: Use when turning a shipped changelog into a release narrative — value-not-feature framing, audience-segmented surfaces, one source of truth. Triggers on 'announce the release', 'write changelog post'.
|
|
125
140
|
repomix-packer: Use when packaging a codebase to a single AI-friendly file for LLM analysis — local or remote, XML/Markdown/JSON, token counting, gitignore filtering, peer-side `repomix` CLI.
|
|
126
141
|
requesting-code-review: Use when asking for a review or creating a PR — self-review first, frame the right context, test plan included — even when the user just says 'open a PR' or 'ready to merge'.
|
|
127
142
|
review-routing: Use when preparing a PR description, suggesting reviewers, or flagging risk — produces owner-mapped roles plus historical bug-pattern matches from project-local YAML.
|
|
128
143
|
rice-prioritization: Use when ranking competing initiatives for a roadmap, breaking a tie between two features, or auditing a backlog for hidden low-value work via Reach × Impact × Confidence ÷ Effort.
|
|
144
|
+
risk-officer: Use when surfacing and prioritising risk before commit — blast-radius framing, mitigations, residual-risk verdict — even if the user just says 'what could go wrong here?'.
|
|
129
145
|
roadmap-management: Use when the user says "create roadmap", "show roadmap", or "execute roadmap". Creates, reads, and manages roadmap files with phase tracking.
|
|
130
146
|
roadmap-writing: Use when authoring or rewriting a roadmap in agents/roadmaps/ — phase prose, goal sentence, acceptance criteria, council notes — even when the user just says 'write a plan for X' or 'draft a roadmap'.
|
|
131
147
|
rtk-output-filtering: Use when running verbose CLI commands — wraps them with rtk (Rust Token Killer) for 60-90% token savings. Covers installation, configuration, and usage patterns.
|
|
@@ -141,8 +157,11 @@ skill-management: Use when compressing, decompressing, refactoring, or improving
|
|
|
141
157
|
skill-reviewer: Use when reviewing, auditing, or optimizing skills — validates against the 7 Skill Killers checklist and produces fix recommendations.
|
|
142
158
|
skill-writing: Use when deciding 'should this be a skill or a rule?', creating/improving/reviewing agent skills, SKILL.md frontmatter, or procedure sections — even without saying 'skill-writing'.
|
|
143
159
|
sql-writing: Use when writing raw SQL — MariaDB/MySQL syntax, parameterization, raw migrations, seeders with `DB::statement` — even when the user just pastes a query and asks 'why is this slow' without naming SQL.
|
|
144
|
-
|
|
160
|
+
stakeholder-tradeoff: Use when stakeholders pull a decision in different directions — frames each lens, builds a trade-off matrix, surfaces the cost of every choice — even if the user just says 'PO and ops disagree'.
|
|
161
|
+
subagent-orchestration: Use when orchestrating implementer/judge subagents — seven modes (do-and-judge ±two-stage, do-in-steps/parallel/worktrees, do-competitively, judge-with-debate) — models from .agent-settings.yml.
|
|
145
162
|
systematic-debugging: Use when hitting a bug, test failure, crash, or unexpected behavior — enforces reproduce → isolate → hypothesize → verify before any fix — even when the user just says 'this is broken' or 'quick fix'.
|
|
163
|
+
tailwind-engineer: Use when writing or reviewing Tailwind CSS — utility-first, design-token discipline, no inline-style drift, responsive variants, dark mode — even on 'style this' or 'mach das hübsch'.
|
|
164
|
+
tech-debt-tracker: Use when surfacing tech debt as trackable items — interest-vs-principal framing, prioritisation by carrying cost, repayment plan — even if the user just says 'this codebase is a mess'.
|
|
146
165
|
technical-specification: Use when the user says "write a spec", "create RFC", "write a PRD", or "document this decision". Writes technical specifications, PRDs, RFCs, and ADRs with clear structure.
|
|
147
166
|
terraform: Use when writing Terraform — AWS modules, resources, variables, outputs, remote state — even when the user just says 'provision this infra' or 'add an S3 bucket' without naming Terraform.
|
|
148
167
|
terragrunt: Use when working with Terragrunt — DRY multi-env configs, module dependencies, remote state orchestration — even when the user just says 'deploy this to staging and prod' without naming Terragrunt.
|
|
@@ -152,10 +171,12 @@ testing-anti-patterns: Use BEFORE writing or changing tests, adding mocks, or pu
|
|
|
152
171
|
threat-modeling: Use when adding auth, webhooks, uploads, queues, secrets, tenant boundaries, or public endpoints — produces trust boundaries + abuse cases mapped to files, BEFORE implementation.
|
|
153
172
|
token-optimizer: Use BEFORE any verbose CLI run, large file read, doc conversion, or near-context handoff — single decision tree keyed by intent that cites the canonical token-saving asset. Consult before the action.
|
|
154
173
|
traefik: Use when setting up Traefik as a local reverse proxy — real domains on 127.0.0.1, trusted HTTPS via mkcert, automatic service discovery, and multi-project routing.
|
|
174
|
+
ui-component-architect: Use when shaping a UI component tree — composition vs inheritance, slot patterns, prop API design, controlled vs uncontrolled, polymorphic — even on 'split this component'.
|
|
155
175
|
unit-economics-modeling: Use when modeling CAC, LTV, gross-margin payback, or contribution margin per customer — for SaaS, marketplace, or transactional businesses.
|
|
156
176
|
universal-project-analysis: ONLY when user explicitly requests: full project analysis, deep codebase audit, or comprehensive architecture review. Routes to core and framework-specific analysis skills.
|
|
157
177
|
upstream-contribute: Use when a learning, new skill, rule improvement, or bug fix from a consumer project should be contributed back to the shared agent-config package.
|
|
158
178
|
using-git-worktrees: Use when starting parallel work in isolation from the current branch — spawn a git worktree with ignore-safety checks and a clean test baseline — even when the user says 'try this on the side'.
|
|
159
179
|
"validate-feature-fit": Validate whether a feature request fits the existing codebase — check for duplicates, contradictions, scope creep, and architectural misfit
|
|
160
180
|
verify-completion-evidence: Use when claiming 'done', suggesting a commit, push, or PR — runs the evidence gate so completion claims come from fresh output in this message, not memory or earlier runs.
|
|
181
|
+
voc-extract: Use when extracting Voice-of-Customer themes from existing artefacts — GH issues, PR threads, Sentry patterns. Triggers on 'what are users saying', 'recurring complaints', 'top themes'.
|
|
161
182
|
websocket: Use when building real-time features — WebSocket broadcasting, live updates, presence channels, connection state — even when the user just says 'push this to the client live'.
|
package/package.json
CHANGED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"""``agent-config export`` — eject a tool's canonical content into the project.
|
|
2
|
+
|
|
3
|
+
Phase 1.5 of road-to-global-first-install.md (ADR-007 D3). Replaces the
|
|
4
|
+
rejected symlink-bridge subcommand: writes a real file with the resolved
|
|
5
|
+
content for a named tool into a user-chosen path so it can be committed,
|
|
6
|
+
shared with the team, or customized in place. Idempotent by default;
|
|
7
|
+
``--force`` overrides content drift. No canonical-path defaults.
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import argparse
|
|
12
|
+
import hashlib
|
|
13
|
+
import sys
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Callable, Optional
|
|
16
|
+
|
|
17
|
+
from scripts.install import (
|
|
18
|
+
AIDER_MARKER,
|
|
19
|
+
CLAUDE_DESKTOP_MARKER,
|
|
20
|
+
CODEX_MARKER,
|
|
21
|
+
CONTINUE_MARKER,
|
|
22
|
+
JETBRAINS_MARKER,
|
|
23
|
+
KILOCODE_MARKER,
|
|
24
|
+
KIRO_MARKER,
|
|
25
|
+
ROOCODE_MARKER,
|
|
26
|
+
ZED_MARKER,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
PACKAGE_ROOT = Path(__file__).resolve().parents[2]
|
|
30
|
+
TEMPLATES_DIR = PACKAGE_ROOT / ".agent-src" / "templates"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _from_template(rel: str) -> Callable[[], str]:
|
|
34
|
+
def _read() -> str:
|
|
35
|
+
path = TEMPLATES_DIR / rel
|
|
36
|
+
if not path.is_file():
|
|
37
|
+
raise FileNotFoundError(
|
|
38
|
+
f"template missing from package: {path} "
|
|
39
|
+
f"(reinstall @event4u/agent-config or report a bug)"
|
|
40
|
+
)
|
|
41
|
+
return path.read_text(encoding="utf-8")
|
|
42
|
+
return _read
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _from_constant(value: str) -> Callable[[], str]:
|
|
46
|
+
def _read() -> str:
|
|
47
|
+
return value
|
|
48
|
+
return _read
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# tool_id → (description, content_provider).
|
|
52
|
+
EXPORT_REGISTRY: "dict[str, tuple[str, Callable[[], str]]]" = {
|
|
53
|
+
"roocode": ("Roo Code marker (.roo/rules/agent-config.md body)",
|
|
54
|
+
_from_constant(ROOCODE_MARKER)),
|
|
55
|
+
"claude-desktop": ("Claude Desktop marker (informational, global-scope tool)",
|
|
56
|
+
_from_constant(CLAUDE_DESKTOP_MARKER)),
|
|
57
|
+
"aider": ("Aider marker (manual `read:` wiring documented inline)",
|
|
58
|
+
_from_constant(AIDER_MARKER)),
|
|
59
|
+
"codex": ("Codex CLI marker (informational — AGENTS.md is canonical)",
|
|
60
|
+
_from_constant(CODEX_MARKER)),
|
|
61
|
+
"continue": ("Continue.dev marker (.continue/rules/agent-config.md body)",
|
|
62
|
+
_from_constant(CONTINUE_MARKER)),
|
|
63
|
+
"kilocode": ("Kilo Code marker (.kilocode/rules/agent-config.md body)",
|
|
64
|
+
_from_constant(KILOCODE_MARKER)),
|
|
65
|
+
"zed": ("Zed marker (informational — .rules at repo root is canonical)",
|
|
66
|
+
_from_constant(ZED_MARKER)),
|
|
67
|
+
"jetbrains": ("JetBrains AI Assistant marker (.jetbrains/agent-config.md body)",
|
|
68
|
+
_from_constant(JETBRAINS_MARKER)),
|
|
69
|
+
"kiro": ("Kiro marker (.kiro/steering/agent-config.md body)",
|
|
70
|
+
_from_constant(KIRO_MARKER)),
|
|
71
|
+
"agents-md": ("AGENTS.md template (Thin-Root entry point — consumer scaffold)",
|
|
72
|
+
_from_template("AGENTS.md")),
|
|
73
|
+
"copilot-instructions": ("GitHub Copilot Code Review instructions template",
|
|
74
|
+
_from_template("copilot-instructions.md")),
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _list_tools(out) -> int:
|
|
79
|
+
print("Available tools for `agent-config export --tool <id>`:", file=out)
|
|
80
|
+
width = max(len(t) for t in EXPORT_REGISTRY) + 2
|
|
81
|
+
for tool_id, (desc, _) in sorted(EXPORT_REGISTRY.items()):
|
|
82
|
+
print(f" {tool_id:<{width}}{desc}", file=out)
|
|
83
|
+
return 0
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _hash(content: str) -> str:
|
|
87
|
+
return hashlib.sha256(content.encode("utf-8")).hexdigest()
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _rel(path: Path) -> Path:
|
|
91
|
+
try:
|
|
92
|
+
return path.relative_to(Path.cwd())
|
|
93
|
+
except ValueError:
|
|
94
|
+
return path
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _write(output: Path, content: str, *, force: bool, out, err) -> int:
|
|
98
|
+
if output.exists():
|
|
99
|
+
existing = output.read_text(encoding="utf-8")
|
|
100
|
+
if _hash(existing) == _hash(content):
|
|
101
|
+
print(f"ℹ️ {_rel(output)} already exported (content matches).", file=out)
|
|
102
|
+
return 0
|
|
103
|
+
if not force:
|
|
104
|
+
print(
|
|
105
|
+
f"❌ refusing to overwrite {output} — content differs. "
|
|
106
|
+
f"Pass --force to replace.",
|
|
107
|
+
file=err,
|
|
108
|
+
)
|
|
109
|
+
return 1
|
|
110
|
+
output.parent.mkdir(parents=True, exist_ok=True)
|
|
111
|
+
output.write_text(content, encoding="utf-8")
|
|
112
|
+
print(f"✅ exported to {_rel(output)}", file=out)
|
|
113
|
+
return 0
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def main(argv: Optional[list[str]] = None, *, out=sys.stdout, err=sys.stderr) -> int:
|
|
117
|
+
parser = argparse.ArgumentParser(
|
|
118
|
+
prog="agent-config export",
|
|
119
|
+
description="Eject a tool's resolved content into a user-chosen path.",
|
|
120
|
+
)
|
|
121
|
+
parser.add_argument("--tool", metavar="ID",
|
|
122
|
+
help="Tool to export (see --list for the catalog).")
|
|
123
|
+
parser.add_argument("--output", metavar="PATH",
|
|
124
|
+
help="Destination path (relative to CWD).")
|
|
125
|
+
parser.add_argument("--force", action="store_true",
|
|
126
|
+
help="Overwrite an existing file with non-matching content.")
|
|
127
|
+
parser.add_argument("--list", action="store_true",
|
|
128
|
+
help="Print supported tool IDs with descriptions and exit.")
|
|
129
|
+
args = parser.parse_args(argv)
|
|
130
|
+
|
|
131
|
+
if args.list:
|
|
132
|
+
return _list_tools(out)
|
|
133
|
+
if not args.tool:
|
|
134
|
+
print("❌ --tool is required (see --list for the catalog).", file=err)
|
|
135
|
+
return 2
|
|
136
|
+
if not args.output:
|
|
137
|
+
print("❌ --output is required (no canonical-path defaults).", file=err)
|
|
138
|
+
return 2
|
|
139
|
+
|
|
140
|
+
entry = EXPORT_REGISTRY.get(args.tool)
|
|
141
|
+
if entry is None:
|
|
142
|
+
print(f"❌ unknown tool: {args.tool} (see --list)", file=err)
|
|
143
|
+
return 2
|
|
144
|
+
|
|
145
|
+
_, provider = entry
|
|
146
|
+
try:
|
|
147
|
+
content = provider()
|
|
148
|
+
except FileNotFoundError as exc:
|
|
149
|
+
print(f"❌ {exc}", file=err)
|
|
150
|
+
return 1
|
|
151
|
+
|
|
152
|
+
output = Path(args.output).expanduser().resolve()
|
|
153
|
+
return _write(output, content, force=args.force, out=out, err=err)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
if __name__ == "__main__": # pragma: no cover
|
|
157
|
+
sys.exit(main())
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"""``agent-config sync`` — replay the installed-tools manifest (ADR-008).
|
|
2
|
+
|
|
3
|
+
Phase 3.3 of road-to-global-first-install.md. Reads
|
|
4
|
+
``agents/installed-tools.lock``, then re-runs the bridge install for every
|
|
5
|
+
tool whose ``bridge_marker`` is missing on disk. Tools whose marker already
|
|
6
|
+
exists are skipped — the typical clone-and-sync flow is therefore idempotent
|
|
7
|
+
on the second invocation.
|
|
8
|
+
|
|
9
|
+
Sync never edits the manifest itself; ``init`` is the only writer. Sync only
|
|
10
|
+
calls the installer with ``--scope`` / ``--tools`` derived from the manifest
|
|
11
|
+
entries, so the manifest is the single source of truth.
|
|
12
|
+
"""
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import argparse
|
|
16
|
+
import os
|
|
17
|
+
import sys
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import Iterable
|
|
20
|
+
|
|
21
|
+
from scripts._lib import installed_tools
|
|
22
|
+
from scripts.install import main as install_main
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _marker_exists(project_root: Path, bridge_marker: str, scope: str) -> bool:
|
|
26
|
+
if not bridge_marker:
|
|
27
|
+
return True # substrate-only entries (rare); treat as present
|
|
28
|
+
if scope == "global":
|
|
29
|
+
target = Path(bridge_marker).expanduser()
|
|
30
|
+
else:
|
|
31
|
+
# Project-scope: relative to the project root unless absolute.
|
|
32
|
+
candidate = Path(bridge_marker)
|
|
33
|
+
target = candidate if candidate.is_absolute() else (project_root / candidate)
|
|
34
|
+
return target.exists()
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _group_by_scope(
|
|
38
|
+
entries: Iterable[dict],
|
|
39
|
+
project_root: Path,
|
|
40
|
+
) -> tuple[dict[str, list[str]], list[tuple[str, str]]]:
|
|
41
|
+
"""Return ({scope: [tool_names]}, [(name, marker_path)]) for missing tools.
|
|
42
|
+
|
|
43
|
+
The second list is the human-readable summary of what will be replayed.
|
|
44
|
+
"""
|
|
45
|
+
missing: dict[str, list[str]] = {"project": [], "global": []}
|
|
46
|
+
surfaced: list[tuple[str, str]] = []
|
|
47
|
+
for entry in entries:
|
|
48
|
+
name = str(entry.get("name", "")).strip()
|
|
49
|
+
scope = str(entry.get("scope", "")).strip()
|
|
50
|
+
bridge_marker = str(entry.get("bridge_marker", "")).strip()
|
|
51
|
+
if not name or scope not in ("project", "global"):
|
|
52
|
+
continue
|
|
53
|
+
if _marker_exists(project_root, bridge_marker, scope):
|
|
54
|
+
continue
|
|
55
|
+
missing[scope].append(name)
|
|
56
|
+
surfaced.append((name, bridge_marker))
|
|
57
|
+
return missing, surfaced
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _run_install(scope: str, tools: list[str], project_root: Path, *, force: bool, dry_run: bool) -> int:
|
|
61
|
+
if not tools:
|
|
62
|
+
return 0
|
|
63
|
+
argv = [f"--scope={scope}", f"--tools={','.join(sorted(set(tools)))}"]
|
|
64
|
+
if scope == "project":
|
|
65
|
+
argv += [f"--project={project_root}", "--no-smoke"]
|
|
66
|
+
if force:
|
|
67
|
+
argv.append("--force")
|
|
68
|
+
if dry_run:
|
|
69
|
+
argv.append("--skip-bridges")
|
|
70
|
+
return install_main(argv)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _parse(argv: list[str]) -> argparse.Namespace:
|
|
74
|
+
parser = argparse.ArgumentParser(
|
|
75
|
+
prog="agent-config sync",
|
|
76
|
+
description=(
|
|
77
|
+
"Replay agents/installed-tools.lock — re-installs any tool whose "
|
|
78
|
+
"bridge marker is missing locally. Idempotent."
|
|
79
|
+
),
|
|
80
|
+
)
|
|
81
|
+
parser.add_argument(
|
|
82
|
+
"--project",
|
|
83
|
+
default=None,
|
|
84
|
+
help="Override the project root (defaults to PROJECT_ROOT or cwd).",
|
|
85
|
+
)
|
|
86
|
+
parser.add_argument(
|
|
87
|
+
"--dry-run",
|
|
88
|
+
action="store_true",
|
|
89
|
+
help="Print the planned replay set without touching bridges.",
|
|
90
|
+
)
|
|
91
|
+
parser.add_argument(
|
|
92
|
+
"--force",
|
|
93
|
+
action="store_true",
|
|
94
|
+
help="Forwarded to the installer (overwrites existing bridge files).",
|
|
95
|
+
)
|
|
96
|
+
parser.add_argument(
|
|
97
|
+
"--quiet",
|
|
98
|
+
action="store_true",
|
|
99
|
+
help="Suppress non-essential output.",
|
|
100
|
+
)
|
|
101
|
+
return parser.parse_args(argv)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _emit(quiet: bool, msg: str) -> None:
|
|
105
|
+
if not quiet:
|
|
106
|
+
print(msg)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def main(argv: list[str]) -> int:
|
|
110
|
+
opts = _parse(argv)
|
|
111
|
+
project_root = Path(
|
|
112
|
+
opts.project or os.environ.get("PROJECT_ROOT") or os.getcwd()
|
|
113
|
+
).resolve()
|
|
114
|
+
manifest = installed_tools.manifest_path(project_root)
|
|
115
|
+
data = installed_tools.read_manifest(manifest)
|
|
116
|
+
|
|
117
|
+
if data is None:
|
|
118
|
+
_emit(opts.quiet, f"❌ No manifest found at {manifest}")
|
|
119
|
+
_emit(opts.quiet, " Run `./agent-config init --tools=<id>` to create one.")
|
|
120
|
+
return 1
|
|
121
|
+
|
|
122
|
+
entries = list(data.get("tools") or [])
|
|
123
|
+
if not entries:
|
|
124
|
+
_emit(opts.quiet, f"ℹ️ Manifest is empty: {manifest}")
|
|
125
|
+
return 0
|
|
126
|
+
|
|
127
|
+
missing, surfaced = _group_by_scope(entries, project_root)
|
|
128
|
+
total_missing = sum(len(v) for v in missing.values())
|
|
129
|
+
total_present = len(entries) - total_missing
|
|
130
|
+
|
|
131
|
+
_emit(opts.quiet, f"Manifest: {manifest}")
|
|
132
|
+
_emit(opts.quiet, f"Tools: {len(entries)} listed, {total_present} present, {total_missing} missing")
|
|
133
|
+
if total_missing == 0:
|
|
134
|
+
_emit(opts.quiet, "✅ All bridges already installed. Nothing to do.")
|
|
135
|
+
return 0
|
|
136
|
+
|
|
137
|
+
for name, marker in surfaced:
|
|
138
|
+
_emit(opts.quiet, f" • {name:<15} → {marker} (missing)")
|
|
139
|
+
|
|
140
|
+
if opts.dry_run:
|
|
141
|
+
_emit(opts.quiet, "")
|
|
142
|
+
_emit(opts.quiet, "Dry-run: no bridges written.")
|
|
143
|
+
return 0
|
|
144
|
+
|
|
145
|
+
_emit(opts.quiet, "")
|
|
146
|
+
for scope in ("project", "global"):
|
|
147
|
+
tools = missing[scope]
|
|
148
|
+
if not tools:
|
|
149
|
+
continue
|
|
150
|
+
_emit(opts.quiet, f"Replaying scope={scope}: {', '.join(sorted(tools))}")
|
|
151
|
+
rc = _run_install(scope, tools, project_root, force=opts.force, dry_run=False)
|
|
152
|
+
if rc != 0:
|
|
153
|
+
_emit(opts.quiet, f"❌ Installer failed for scope={scope} (rc={rc}); aborting.")
|
|
154
|
+
return rc
|
|
155
|
+
|
|
156
|
+
_emit(opts.quiet, "")
|
|
157
|
+
_emit(opts.quiet, "✅ Sync complete.")
|
|
158
|
+
return 0
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
if __name__ == "__main__":
|
|
162
|
+
sys.exit(main(sys.argv[1:]))
|
|
@@ -36,7 +36,7 @@ from datetime import datetime, timezone
|
|
|
36
36
|
from pathlib import Path
|
|
37
37
|
from typing import Optional
|
|
38
38
|
|
|
39
|
-
from scripts._lib import update_check
|
|
39
|
+
from scripts._lib import installed_lock, update_check
|
|
40
40
|
from scripts._lib.agent_settings import (
|
|
41
41
|
DEFAULT_PROJECT_FILE,
|
|
42
42
|
_resolve_cascade_paths,
|
|
@@ -205,9 +205,31 @@ def main(
|
|
|
205
205
|
|
|
206
206
|
cache_warmer(latest)
|
|
207
207
|
_refresh_state(latest, latest, state_path)
|
|
208
|
+
_refresh_global_lockfile(latest, out=out)
|
|
208
209
|
return 0
|
|
209
210
|
|
|
210
211
|
|
|
212
|
+
def _refresh_global_lockfile(version: str, *, out=sys.stdout) -> None:
|
|
213
|
+
"""Update ``~/.config/agent-config/installed.lock`` if it exists.
|
|
214
|
+
|
|
215
|
+
Phase 1.6 — the lockfile is only present when the user has run a
|
|
216
|
+
global install; we never create one here, but we keep it in lockstep
|
|
217
|
+
when ``update`` flips the pin. Atomic write goes through
|
|
218
|
+
``installed_lock.write_lockfile``.
|
|
219
|
+
"""
|
|
220
|
+
lock_path = installed_lock.lockfile_path()
|
|
221
|
+
existing = installed_lock.read_lockfile(path=lock_path)
|
|
222
|
+
if existing is None:
|
|
223
|
+
return
|
|
224
|
+
recorded = existing.get("agent_config_version")
|
|
225
|
+
tools = list(existing.get("tools", []))
|
|
226
|
+
if recorded == version:
|
|
227
|
+
print(f"ℹ️ {lock_path} already records {version}.", file=out)
|
|
228
|
+
return
|
|
229
|
+
installed_lock.write_lockfile(version, tools, path=lock_path)
|
|
230
|
+
print(f"✅ Refreshed global lockfile at {lock_path}.", file=out)
|
|
231
|
+
|
|
232
|
+
|
|
211
233
|
def _detect_installed_version() -> str:
|
|
212
234
|
"""Read ``version`` from the package's own ``package.json``."""
|
|
213
235
|
pkg_json = Path(__file__).resolve().parents[2] / "package.json"
|