agents-inc 0.158.0 → 0.160.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/CHANGELOG.md +34 -0
- package/dist/{chunk-P6OKOH62.js → chunk-4APXK7ZY.js} +2 -2
- package/dist/{chunk-QNAMXQKF.js → chunk-4VVKVOOP.js} +2 -2
- package/dist/{chunk-DAUY2SB3.js → chunk-5K33RJ7Z.js} +70 -25
- package/dist/chunk-5K33RJ7Z.js.map +1 -0
- package/dist/{chunk-G6G2FT2G.js → chunk-5KB4I5J7.js} +2 -5
- package/dist/chunk-5KB4I5J7.js.map +1 -0
- package/dist/{chunk-2PN4QXON.js → chunk-6CP3CLDE.js} +5 -10
- package/dist/chunk-6CP3CLDE.js.map +1 -0
- package/dist/{chunk-TUXXBEBB.js → chunk-7JQPIMKD.js} +3 -3
- package/dist/{chunk-KUZBMEWR.js → chunk-AU5FS3QK.js} +3 -3
- package/dist/{chunk-WMVOJY6V.js → chunk-C5P7RUDR.js} +4 -4
- package/dist/{chunk-H4CL23HG.js → chunk-CICB4AKA.js} +3 -3
- package/dist/{chunk-KVVXINCJ.js → chunk-CWQLRKWB.js} +3 -3
- package/dist/{chunk-L4FHSOL5.js → chunk-DEWI5HDF.js} +5 -5
- package/dist/{chunk-JG3B47P3.js → chunk-EPBUWEW4.js} +8 -8
- package/dist/{chunk-EEAX7E2X.js → chunk-GWPKIXBM.js} +2 -2
- package/dist/{chunk-DP6YQFVO.js → chunk-IJ7GWQUR.js} +5 -5
- package/dist/{chunk-TZRXWFF5.js → chunk-ITEJARWI.js} +3 -3
- package/dist/{chunk-TPQ5M3BW.js → chunk-IWUFZ6NR.js} +3 -3
- package/dist/{chunk-PNRLBPGS.js → chunk-J7Q5VYR7.js} +12 -12
- package/dist/{chunk-4ABNXKAR.js → chunk-JQDN7KAZ.js} +2 -2
- package/dist/{chunk-Q7CAE5NN.js → chunk-K6MQV6SK.js} +3 -3
- package/dist/{chunk-54QLV3OH.js → chunk-KCN5N3PB.js} +34 -6
- package/dist/chunk-KCN5N3PB.js.map +1 -0
- package/dist/{chunk-X52QUV4U.js → chunk-LJ6V54NR.js} +5 -5
- package/dist/{chunk-H25VRR2T.js → chunk-LX7UXZBN.js} +6 -6
- package/dist/{chunk-VZRO7RYT.js → chunk-OI2H6M5I.js} +1 -103
- package/dist/chunk-OI2H6M5I.js.map +1 -0
- package/dist/{chunk-VTIDLRNA.js → chunk-OJIQOVWB.js} +2 -2
- package/dist/{chunk-OQB2CKBT.js → chunk-OJR3ASZI.js} +7 -7
- package/dist/{chunk-3PJLLBUS.js → chunk-OUG6TCQ4.js} +220 -345
- package/dist/chunk-OUG6TCQ4.js.map +1 -0
- package/dist/{chunk-WCZNQECQ.js → chunk-PEHYVSJG.js} +2 -2
- package/dist/{chunk-6DBE562W.js → chunk-PIUCYRLP.js} +5 -15
- package/dist/chunk-PIUCYRLP.js.map +1 -0
- package/dist/{chunk-PZNXBORZ.js → chunk-PWPKZNCV.js} +4 -4
- package/dist/{chunk-SJ4T5YLG.js → chunk-Q2HB5SWU.js} +5 -5
- package/dist/{chunk-H2DHTJKW.js → chunk-RJ3JYZJ7.js} +9 -9
- package/dist/chunk-RJ3JYZJ7.js.map +1 -0
- package/dist/{chunk-DZD25NHW.js → chunk-SITF5EZM.js} +2 -2
- package/dist/{chunk-IK6YOXZH.js → chunk-SLB2SFTX.js} +4 -28
- package/dist/chunk-SLB2SFTX.js.map +1 -0
- package/dist/{chunk-LKI3ENGQ.js → chunk-VH6P7UGF.js} +4 -4
- package/dist/{chunk-3Q2N7CSY.js → chunk-VI4X5DN5.js} +6 -6
- package/dist/{chunk-YXI3BTQQ.js → chunk-X5PLVOJS.js} +2 -2
- package/dist/{chunk-XNYHMRVJ.js → chunk-XDNGMXOZ.js} +4 -4
- package/dist/{chunk-3NBXQSW2.js → chunk-XSULY25W.js} +6 -6
- package/dist/{chunk-7Z4N4JWQ.js → chunk-XX657S4U.js} +1 -103
- package/dist/chunk-XX657S4U.js.map +1 -0
- package/dist/{chunk-4DMFK67G.js → chunk-YKRPWZ3G.js} +2 -2
- package/dist/commands/build/marketplace.js +8 -8
- package/dist/commands/build/plugins.js +8 -8
- package/dist/commands/compile.js +11 -11
- package/dist/commands/doctor.js +13 -13
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/edit.js +59 -68
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +11 -11
- package/dist/commands/init.js +41 -37
- package/dist/commands/list.js +9 -9
- package/dist/commands/new/marketplace.js +8 -9
- package/dist/commands/new/marketplace.js.map +1 -1
- package/dist/commands/search.js +11 -11
- package/dist/commands/share.js +100 -16
- package/dist/commands/share.js.map +1 -1
- package/dist/commands/uninstall.js +12 -12
- package/dist/commands/update.js +7 -7
- package/dist/components/common/removal-plan-confirm.js +2 -2
- package/dist/components/common/select-list.js +2 -2
- package/dist/components/wizard/category-grid.js +4 -4
- package/dist/components/wizard/checkbox-grid.js +4 -4
- package/dist/components/wizard/domain-selection.js +10 -10
- package/dist/components/wizard/run-wizard-session.js +27 -27
- package/dist/components/wizard/scroll-affordance.js +2 -2
- package/dist/components/wizard/skill-agent-summary.js +6 -6
- package/dist/components/wizard/source-grid.js +5 -5
- package/dist/components/wizard/stack-selection.js +8 -8
- package/dist/components/wizard/step-agents.js +9 -9
- package/dist/components/wizard/step-build.js +8 -8
- package/dist/components/wizard/step-confirm.js +10 -10
- package/dist/components/wizard/step-sources.js +9 -9
- package/dist/components/wizard/step-stack.js +9 -9
- package/dist/components/wizard/summary-panel.js +9 -9
- package/dist/components/wizard/toast.js +2 -2
- package/dist/components/wizard/wizard-layout.js +13 -13
- package/dist/components/wizard/wizard-tabs.js +2 -2
- package/dist/components/wizard/wizard.js +26 -26
- package/dist/config-exports.js +1 -1
- package/dist/hooks/init.js +37 -37
- package/dist/load-agent-defs-KWHG7P7G.js +13 -0
- package/dist/recompile-project-agents-5FTDDHX7.js +17 -0
- package/dist/{source-loader-CO2FZ3OO.js → source-loader-CDYH2NIM.js} +5 -5
- package/dist/src/agents/_templates/methodologies/anti-over-engineering.liquid +14 -0
- package/dist/src/agents/_templates/methodologies/context-management.liquid +7 -154
- package/dist/src/agents/_templates/methodologies/investigation-requirements.liquid +12 -0
- package/dist/src/agents/_templates/methodologies/success-criteria.liquid +10 -0
- package/dist/stores/wizard-store.js +5 -5
- package/package.json +1 -1
- package/src/agents/_templates/methodologies/anti-over-engineering.liquid +14 -0
- package/src/agents/_templates/methodologies/context-management.liquid +7 -154
- package/src/agents/_templates/methodologies/investigation-requirements.liquid +12 -0
- package/src/agents/_templates/methodologies/success-criteria.liquid +10 -0
- package/src/schemas/project-source-config.schema.json +0 -3
- package/dist/chunk-2PN4QXON.js.map +0 -1
- package/dist/chunk-3PJLLBUS.js.map +0 -1
- package/dist/chunk-54QLV3OH.js.map +0 -1
- package/dist/chunk-6DBE562W.js.map +0 -1
- package/dist/chunk-7Z4N4JWQ.js.map +0 -1
- package/dist/chunk-DAUY2SB3.js.map +0 -1
- package/dist/chunk-G6G2FT2G.js.map +0 -1
- package/dist/chunk-H2DHTJKW.js.map +0 -1
- package/dist/chunk-IK6YOXZH.js.map +0 -1
- package/dist/chunk-VZRO7RYT.js.map +0 -1
- package/dist/load-agent-defs-2VYAV5GL.js +0 -13
- package/dist/recompile-project-agents-NG5DCPHJ.js +0 -17
- /package/dist/{chunk-P6OKOH62.js.map → chunk-4APXK7ZY.js.map} +0 -0
- /package/dist/{chunk-QNAMXQKF.js.map → chunk-4VVKVOOP.js.map} +0 -0
- /package/dist/{chunk-TUXXBEBB.js.map → chunk-7JQPIMKD.js.map} +0 -0
- /package/dist/{chunk-KUZBMEWR.js.map → chunk-AU5FS3QK.js.map} +0 -0
- /package/dist/{chunk-WMVOJY6V.js.map → chunk-C5P7RUDR.js.map} +0 -0
- /package/dist/{chunk-H4CL23HG.js.map → chunk-CICB4AKA.js.map} +0 -0
- /package/dist/{chunk-KVVXINCJ.js.map → chunk-CWQLRKWB.js.map} +0 -0
- /package/dist/{chunk-L4FHSOL5.js.map → chunk-DEWI5HDF.js.map} +0 -0
- /package/dist/{chunk-JG3B47P3.js.map → chunk-EPBUWEW4.js.map} +0 -0
- /package/dist/{chunk-EEAX7E2X.js.map → chunk-GWPKIXBM.js.map} +0 -0
- /package/dist/{chunk-DP6YQFVO.js.map → chunk-IJ7GWQUR.js.map} +0 -0
- /package/dist/{chunk-TZRXWFF5.js.map → chunk-ITEJARWI.js.map} +0 -0
- /package/dist/{chunk-TPQ5M3BW.js.map → chunk-IWUFZ6NR.js.map} +0 -0
- /package/dist/{chunk-PNRLBPGS.js.map → chunk-J7Q5VYR7.js.map} +0 -0
- /package/dist/{chunk-4ABNXKAR.js.map → chunk-JQDN7KAZ.js.map} +0 -0
- /package/dist/{chunk-Q7CAE5NN.js.map → chunk-K6MQV6SK.js.map} +0 -0
- /package/dist/{chunk-X52QUV4U.js.map → chunk-LJ6V54NR.js.map} +0 -0
- /package/dist/{chunk-H25VRR2T.js.map → chunk-LX7UXZBN.js.map} +0 -0
- /package/dist/{chunk-VTIDLRNA.js.map → chunk-OJIQOVWB.js.map} +0 -0
- /package/dist/{chunk-OQB2CKBT.js.map → chunk-OJR3ASZI.js.map} +0 -0
- /package/dist/{chunk-WCZNQECQ.js.map → chunk-PEHYVSJG.js.map} +0 -0
- /package/dist/{chunk-PZNXBORZ.js.map → chunk-PWPKZNCV.js.map} +0 -0
- /package/dist/{chunk-SJ4T5YLG.js.map → chunk-Q2HB5SWU.js.map} +0 -0
- /package/dist/{chunk-DZD25NHW.js.map → chunk-SITF5EZM.js.map} +0 -0
- /package/dist/{chunk-LKI3ENGQ.js.map → chunk-VH6P7UGF.js.map} +0 -0
- /package/dist/{chunk-3Q2N7CSY.js.map → chunk-VI4X5DN5.js.map} +0 -0
- /package/dist/{chunk-YXI3BTQQ.js.map → chunk-X5PLVOJS.js.map} +0 -0
- /package/dist/{chunk-XNYHMRVJ.js.map → chunk-XDNGMXOZ.js.map} +0 -0
- /package/dist/{chunk-3NBXQSW2.js.map → chunk-XSULY25W.js.map} +0 -0
- /package/dist/{chunk-4DMFK67G.js.map → chunk-YKRPWZ3G.js.map} +0 -0
- /package/dist/{load-agent-defs-2VYAV5GL.js.map → load-agent-defs-KWHG7P7G.js.map} +0 -0
- /package/dist/{recompile-project-agents-NG5DCPHJ.js.map → recompile-project-agents-5FTDDHX7.js.map} +0 -0
- /package/dist/{source-loader-CO2FZ3OO.js.map → source-loader-CDYH2NIM.js.map} +0 -0
|
@@ -87,6 +87,20 @@ Analyze thoroughly and examine similar areas of the codebase to ensure your prop
|
|
|
87
87
|
- **(Do not change anything not explicitly mentioned in the specification)**
|
|
88
88
|
- This prevents 70%+ of unwanted refactoring
|
|
89
89
|
|
|
90
|
+
### The Class Is the Unit of Repair
|
|
91
|
+
|
|
92
|
+
**A defect found in one place is usually one instance of a class.** The same mistake tends to be repeated wherever the same pattern was written, so the file you found it in is where it surfaced rather than the extent of it. A fix scoped to that one file leaves working siblings of a defect you have already diagnosed.
|
|
93
|
+
|
|
94
|
+
Before calling a fix done:
|
|
95
|
+
|
|
96
|
+
- **Census the class** - Run the search that would find its siblings, keyed on the shape of the mistake rather than the name of the file
|
|
97
|
+
- **Read the whole result** - The first screen is a sample, not an answer
|
|
98
|
+
- **Fix them, or name them** - Repair the ones you safely can and list the rest with their locations
|
|
99
|
+
|
|
100
|
+
**Silence reads as "there were none."** A report that mentions no siblings tells its reader the class was checked and came back empty, so state the search you ran and what it returned - including when it returned nothing.
|
|
101
|
+
|
|
102
|
+
**This does not widen your scope.** The class is what is broken and the instance is only where it was found, so repairing the siblings of one diagnosed defect finishes the job rather than adding to it. Adding an abstraction, a helper, or a capability nobody asked for is still out of scope, and so is a different defect you happened to notice along the way.
|
|
103
|
+
|
|
90
104
|
</anti_over_engineering>
|
|
91
105
|
|
|
92
106
|
---
|
|
@@ -1,162 +1,15 @@
|
|
|
1
1
|
<context_management>
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## What Survives the Session
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Your report is the only part of this work that outlives it. Whatever you learned and did not write down is lost the moment the task ends, and the next person to touch this code pays for it a second time.
|
|
6
6
|
|
|
7
|
-
**
|
|
7
|
+
**Carry three things out of every task:**
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
.
|
|
11
|
-
|
|
12
|
-
decisions.md # Architectural decisions and rationale
|
|
13
|
-
insights.md # Lessons learned, gotchas discovered
|
|
14
|
-
tests.json # Structured test tracking (NEVER remove tests)
|
|
15
|
-
patterns.md # Codebase conventions being followed
|
|
16
|
-
```
|
|
9
|
+
- **Decisions, with the reason** - Where more than one route was open, name the one you took and why. A choice with no recorded reason is indistinguishable from an accident, so the next person to reach it will either re-argue it or quietly undo it.
|
|
10
|
+
- **Gotchas you hit** - Non-obvious behaviour, a constraint that only appears at runtime, an approach that looked correct and was not. This is the part nobody can reconstruct by reading the finished code.
|
|
11
|
+
- **Work you deliberately left** - What you did not do, and what stopped you. This is not the same as a criterion you failed to meet: it is the work no criterion named, which stays invisible unless you say it out loud.
|
|
17
12
|
|
|
18
|
-
**
|
|
19
|
-
|
|
20
|
-
### At Session Start
|
|
21
|
-
|
|
22
|
-
```xml
|
|
23
|
-
<session_start>
|
|
24
|
-
1. Call pwd to verify working directory
|
|
25
|
-
2. Read all context files in .claude/ directory:
|
|
26
|
-
- progress.md: What's been accomplished, what's next
|
|
27
|
-
- decisions.md: Past architectural choices and why
|
|
28
|
-
- insights.md: Important learnings from previous sessions
|
|
29
|
-
- tests.json: Test status (never modify test data)
|
|
30
|
-
3. Review git logs for recent changes
|
|
31
|
-
4. Understand current state from filesystem, not just chat history
|
|
32
|
-
</session_start>
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
### During Work
|
|
36
|
-
|
|
37
|
-
```xml
|
|
38
|
-
<during_work>
|
|
39
|
-
After each significant change or decision:
|
|
40
|
-
|
|
41
|
-
1. Update progress.md:
|
|
42
|
-
- What you just accomplished
|
|
43
|
-
- Current status of the task
|
|
44
|
-
- Next steps to take
|
|
45
|
-
- Any blockers or questions
|
|
46
|
-
|
|
47
|
-
2. Log decisions in decisions.md:
|
|
48
|
-
- What choice was made
|
|
49
|
-
- Why (rationale)
|
|
50
|
-
- Alternatives considered
|
|
51
|
-
- Implications for future work
|
|
52
|
-
|
|
53
|
-
3. Document insights in insights.md:
|
|
54
|
-
- Gotchas discovered
|
|
55
|
-
- Patterns that work well
|
|
56
|
-
- Things to avoid
|
|
57
|
-
- Non-obvious behaviors
|
|
58
|
-
|
|
59
|
-
Format:
|
|
60
|
-
## [Date] - [Brief Title]
|
|
61
|
-
|
|
62
|
-
**Decision/Insight:**
|
|
63
|
-
[What happened or what you learned]
|
|
64
|
-
|
|
65
|
-
**Context:**
|
|
66
|
-
[Why this matters]
|
|
67
|
-
|
|
68
|
-
**Impact:**
|
|
69
|
-
[What this means going forward]
|
|
70
|
-
</during_work>
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
### At Session End
|
|
74
|
-
|
|
75
|
-
```xml
|
|
76
|
-
<session_end>
|
|
77
|
-
Before finishing, ensure:
|
|
78
|
-
|
|
79
|
-
1. progress.md reflects current state accurately
|
|
80
|
-
2. All decisions are logged with rationale
|
|
81
|
-
3. Any discoveries are documented in insights.md
|
|
82
|
-
4. tests.json is updated (never remove test entries)
|
|
83
|
-
5. Git commits have descriptive messages
|
|
84
|
-
|
|
85
|
-
Leave the project in a state where the next session can start immediately without context loss.
|
|
86
|
-
</session_end>
|
|
87
|
-
```
|
|
13
|
+
**Write these into your report, not into files nobody asked for.** Notes, logs and tracking files the task did not request leave clutter in someone's repository and a maintenance burden they never agreed to.
|
|
88
14
|
|
|
89
15
|
</context_management>
|
|
90
|
-
|
|
91
|
-
---
|
|
92
|
-
|
|
93
|
-
<context_overload_prevention>
|
|
94
|
-
|
|
95
|
-
### Context Overload Prevention
|
|
96
|
-
|
|
97
|
-
**CRITICAL:** Don't try to load everything into context at once.
|
|
98
|
-
|
|
99
|
-
**Instead:**
|
|
100
|
-
|
|
101
|
-
- Provide high-level summaries in progress.md
|
|
102
|
-
- Link to specific files for details
|
|
103
|
-
- Use git log for historical changes
|
|
104
|
-
- Request specific files as needed during work
|
|
105
|
-
|
|
106
|
-
**Example progress.md:**
|
|
107
|
-
|
|
108
|
-
```markdown
|
|
109
|
-
# Current Status
|
|
110
|
-
|
|
111
|
-
## Completed
|
|
112
|
-
|
|
113
|
-
- User profile editing UI (see ProfileEditor.tsx)
|
|
114
|
-
- Form validation (see validation.ts)
|
|
115
|
-
- Tests for happy path (see profile-editor.test.ts)
|
|
116
|
-
|
|
117
|
-
## In Progress
|
|
118
|
-
|
|
119
|
-
- Error handling for network failures
|
|
120
|
-
- Next: Add retry logic following pattern in api-client.ts
|
|
121
|
-
- Tests: Need to add network error scenarios
|
|
122
|
-
|
|
123
|
-
## Blocked
|
|
124
|
-
|
|
125
|
-
- Avatar upload feature
|
|
126
|
-
- Reason: Waiting for S3 configuration from DevOps
|
|
127
|
-
- Tracking: Issue #456
|
|
128
|
-
|
|
129
|
-
## Next Session
|
|
130
|
-
|
|
131
|
-
Start with: Implementing retry logic in ProfileEditor.tsx
|
|
132
|
-
Reference: api-client.ts lines 89-112 for the retry pattern
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
This approach lets you maintain continuity without context bloat.
|
|
136
|
-
|
|
137
|
-
</context_overload_prevention>
|
|
138
|
-
|
|
139
|
-
---
|
|
140
|
-
|
|
141
|
-
<fresh_start_approach>
|
|
142
|
-
|
|
143
|
-
## Fresh Start Approach
|
|
144
|
-
|
|
145
|
-
Start each session as if it's the first:
|
|
146
|
-
|
|
147
|
-
1. Read .claude/ context files to understand state
|
|
148
|
-
2. Use git log to see recent changes
|
|
149
|
-
3. Examine filesystem to discover what exists
|
|
150
|
-
4. Run integration tests to verify current behavior
|
|
151
|
-
|
|
152
|
-
This "fresh start" approach works better than trying to maintain long chat history.
|
|
153
|
-
|
|
154
|
-
**Give the RIGHT context, not MORE context.**
|
|
155
|
-
|
|
156
|
-
- For a React component task: Provide that component + immediate dependencies
|
|
157
|
-
- For a store update: Provide the store + related stores
|
|
158
|
-
- For API work: Provide the endpoint + client utilities
|
|
159
|
-
|
|
160
|
-
Don't dump the entire codebase - focus context on what's relevant for the specific task.
|
|
161
|
-
|
|
162
|
-
</fresh_start_approach>
|
|
@@ -46,4 +46,16 @@ Based on standard authentication patterns, I'll implement...
|
|
|
46
46
|
|
|
47
47
|
Always choose the good approach.
|
|
48
48
|
|
|
49
|
+
### The Specification Is a Claim, Not a Fact
|
|
50
|
+
|
|
51
|
+
**Reading the files a specification names is not the same as checking it was right about them.** Every path, symbol, signature, line reference and count in a specification was measured against a codebase that has since moved. Re-derive each one against the code in front of you.
|
|
52
|
+
|
|
53
|
+
When an instruction does not describe what you find:
|
|
54
|
+
|
|
55
|
+
- **Stop on that item** - An instruction whose subject is not there cannot be implemented
|
|
56
|
+
- **Report it with the evidence** - The command you ran and what it returned, not your conclusion about it
|
|
57
|
+
- **Move on to the next item** - Never invent work to make the instruction true, and never quietly widen it into something that is
|
|
58
|
+
|
|
59
|
+
**Corrections are a required field of your report.** List everything in the specification that proved false, and write "Corrections: nothing" explicitly when nothing did - a report that stays silent is indistinguishable from a specification that held.
|
|
60
|
+
|
|
49
61
|
</investigation_requirement>
|
|
@@ -108,4 +108,14 @@ PASS Verified: git diff shows no changes to auth.py or related files
|
|
|
108
108
|
Evidence: `git diff main...feature-branch -- auth.py` returns empty
|
|
109
109
|
```
|
|
110
110
|
|
|
111
|
+
### Name What Would Catch It
|
|
112
|
+
|
|
113
|
+
Verification proves a criterion holds now. Nothing about it says the criterion will still hold after the next change, and those are two different claims.
|
|
114
|
+
|
|
115
|
+
**When your work lands a rule, a convention or an invariant, state what would catch a violation of it** - the test that fails, the type that stops compiling, the check that reports, the build step that breaks. Name the specific one rather than the category.
|
|
116
|
+
|
|
117
|
+
**When nothing would catch it, say so in as many words.** Saying nothing is read as "something covers it," so a gap has to be stated to be visible at all.
|
|
118
|
+
|
|
119
|
+
A rule that nothing mechanically checks will eventually be broken, most often by someone who never read it - and because the rule is written down, everyone will believe the matter is handled. Writing a rule and enforcing a rule are separate pieces of work, and only the first is finished when the sentence exists.
|
|
120
|
+
|
|
111
121
|
</verification_process>
|
|
@@ -7,11 +7,11 @@ import {
|
|
|
7
7
|
hydrateWizardStore,
|
|
8
8
|
showWarningsAsToast,
|
|
9
9
|
useWizardStore
|
|
10
|
-
} from "../chunk-
|
|
11
|
-
import "../chunk-
|
|
12
|
-
import "../chunk-
|
|
13
|
-
import "../chunk-
|
|
14
|
-
import "../chunk-
|
|
10
|
+
} from "../chunk-SLB2SFTX.js";
|
|
11
|
+
import "../chunk-OUG6TCQ4.js";
|
|
12
|
+
import "../chunk-XX657S4U.js";
|
|
13
|
+
import "../chunk-5KB4I5J7.js";
|
|
14
|
+
import "../chunk-OI2H6M5I.js";
|
|
15
15
|
export {
|
|
16
16
|
DOMAIN_AGENTS,
|
|
17
17
|
WIZARD_STEP_ORDER,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agents-inc",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.160.0",
|
|
4
4
|
"description": "CLI for managing Agents Inc. skills, stacks, and agents for Claude Code",
|
|
5
5
|
"//generate": "The write path for all three generators, in dependency order: generate:types reads the skills marketplace and writes src/cli/types/generated/, then generate:schemas copies SKILL_SLUGS and CATEGORIES out of it into metadata.schema.json's enums, then generate:matrix vendors the same directory into packages/matrix. A marketplace change drifts all three, so every caller runs all three — .github/workflows/regenerate-catalog.yml spells the sequence out step by step and could call this instead. It replaces the write path only: the :check variants stay separate because CI deliberately runs different subsets of them in different jobs.",
|
|
6
6
|
"//no-shared-vitest-config": "A three-project suite — unit, integration and commands, each with its own include and the retry that separates them — behind one root config that also carries vitest.setup.ts, disableConsoleIntercept for @oclif/test and ink-testing-library, and its own timeouts. @workspace/vitest-config is a single-project node config that turns globals off, which this suite needs on, so merging it in would contradict as much as it contributed. e2e/vitest.config.ts stands under the same decision. Read by scripts/check-shared-vitest-config.ts in packages/cli.",
|
|
@@ -87,6 +87,20 @@ Analyze thoroughly and examine similar areas of the codebase to ensure your prop
|
|
|
87
87
|
- **(Do not change anything not explicitly mentioned in the specification)**
|
|
88
88
|
- This prevents 70%+ of unwanted refactoring
|
|
89
89
|
|
|
90
|
+
### The Class Is the Unit of Repair
|
|
91
|
+
|
|
92
|
+
**A defect found in one place is usually one instance of a class.** The same mistake tends to be repeated wherever the same pattern was written, so the file you found it in is where it surfaced rather than the extent of it. A fix scoped to that one file leaves working siblings of a defect you have already diagnosed.
|
|
93
|
+
|
|
94
|
+
Before calling a fix done:
|
|
95
|
+
|
|
96
|
+
- **Census the class** - Run the search that would find its siblings, keyed on the shape of the mistake rather than the name of the file
|
|
97
|
+
- **Read the whole result** - The first screen is a sample, not an answer
|
|
98
|
+
- **Fix them, or name them** - Repair the ones you safely can and list the rest with their locations
|
|
99
|
+
|
|
100
|
+
**Silence reads as "there were none."** A report that mentions no siblings tells its reader the class was checked and came back empty, so state the search you ran and what it returned - including when it returned nothing.
|
|
101
|
+
|
|
102
|
+
**This does not widen your scope.** The class is what is broken and the instance is only where it was found, so repairing the siblings of one diagnosed defect finishes the job rather than adding to it. Adding an abstraction, a helper, or a capability nobody asked for is still out of scope, and so is a different defect you happened to notice along the way.
|
|
103
|
+
|
|
90
104
|
</anti_over_engineering>
|
|
91
105
|
|
|
92
106
|
---
|
|
@@ -1,162 +1,15 @@
|
|
|
1
1
|
<context_management>
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## What Survives the Session
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Your report is the only part of this work that outlives it. Whatever you learned and did not write down is lost the moment the task ends, and the next person to touch this code pays for it a second time.
|
|
6
6
|
|
|
7
|
-
**
|
|
7
|
+
**Carry three things out of every task:**
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
.
|
|
11
|
-
|
|
12
|
-
decisions.md # Architectural decisions and rationale
|
|
13
|
-
insights.md # Lessons learned, gotchas discovered
|
|
14
|
-
tests.json # Structured test tracking (NEVER remove tests)
|
|
15
|
-
patterns.md # Codebase conventions being followed
|
|
16
|
-
```
|
|
9
|
+
- **Decisions, with the reason** - Where more than one route was open, name the one you took and why. A choice with no recorded reason is indistinguishable from an accident, so the next person to reach it will either re-argue it or quietly undo it.
|
|
10
|
+
- **Gotchas you hit** - Non-obvious behaviour, a constraint that only appears at runtime, an approach that looked correct and was not. This is the part nobody can reconstruct by reading the finished code.
|
|
11
|
+
- **Work you deliberately left** - What you did not do, and what stopped you. This is not the same as a criterion you failed to meet: it is the work no criterion named, which stays invisible unless you say it out loud.
|
|
17
12
|
|
|
18
|
-
**
|
|
19
|
-
|
|
20
|
-
### At Session Start
|
|
21
|
-
|
|
22
|
-
```xml
|
|
23
|
-
<session_start>
|
|
24
|
-
1. Call pwd to verify working directory
|
|
25
|
-
2. Read all context files in .claude/ directory:
|
|
26
|
-
- progress.md: What's been accomplished, what's next
|
|
27
|
-
- decisions.md: Past architectural choices and why
|
|
28
|
-
- insights.md: Important learnings from previous sessions
|
|
29
|
-
- tests.json: Test status (never modify test data)
|
|
30
|
-
3. Review git logs for recent changes
|
|
31
|
-
4. Understand current state from filesystem, not just chat history
|
|
32
|
-
</session_start>
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
### During Work
|
|
36
|
-
|
|
37
|
-
```xml
|
|
38
|
-
<during_work>
|
|
39
|
-
After each significant change or decision:
|
|
40
|
-
|
|
41
|
-
1. Update progress.md:
|
|
42
|
-
- What you just accomplished
|
|
43
|
-
- Current status of the task
|
|
44
|
-
- Next steps to take
|
|
45
|
-
- Any blockers or questions
|
|
46
|
-
|
|
47
|
-
2. Log decisions in decisions.md:
|
|
48
|
-
- What choice was made
|
|
49
|
-
- Why (rationale)
|
|
50
|
-
- Alternatives considered
|
|
51
|
-
- Implications for future work
|
|
52
|
-
|
|
53
|
-
3. Document insights in insights.md:
|
|
54
|
-
- Gotchas discovered
|
|
55
|
-
- Patterns that work well
|
|
56
|
-
- Things to avoid
|
|
57
|
-
- Non-obvious behaviors
|
|
58
|
-
|
|
59
|
-
Format:
|
|
60
|
-
## [Date] - [Brief Title]
|
|
61
|
-
|
|
62
|
-
**Decision/Insight:**
|
|
63
|
-
[What happened or what you learned]
|
|
64
|
-
|
|
65
|
-
**Context:**
|
|
66
|
-
[Why this matters]
|
|
67
|
-
|
|
68
|
-
**Impact:**
|
|
69
|
-
[What this means going forward]
|
|
70
|
-
</during_work>
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
### At Session End
|
|
74
|
-
|
|
75
|
-
```xml
|
|
76
|
-
<session_end>
|
|
77
|
-
Before finishing, ensure:
|
|
78
|
-
|
|
79
|
-
1. progress.md reflects current state accurately
|
|
80
|
-
2. All decisions are logged with rationale
|
|
81
|
-
3. Any discoveries are documented in insights.md
|
|
82
|
-
4. tests.json is updated (never remove test entries)
|
|
83
|
-
5. Git commits have descriptive messages
|
|
84
|
-
|
|
85
|
-
Leave the project in a state where the next session can start immediately without context loss.
|
|
86
|
-
</session_end>
|
|
87
|
-
```
|
|
13
|
+
**Write these into your report, not into files nobody asked for.** Notes, logs and tracking files the task did not request leave clutter in someone's repository and a maintenance burden they never agreed to.
|
|
88
14
|
|
|
89
15
|
</context_management>
|
|
90
|
-
|
|
91
|
-
---
|
|
92
|
-
|
|
93
|
-
<context_overload_prevention>
|
|
94
|
-
|
|
95
|
-
### Context Overload Prevention
|
|
96
|
-
|
|
97
|
-
**CRITICAL:** Don't try to load everything into context at once.
|
|
98
|
-
|
|
99
|
-
**Instead:**
|
|
100
|
-
|
|
101
|
-
- Provide high-level summaries in progress.md
|
|
102
|
-
- Link to specific files for details
|
|
103
|
-
- Use git log for historical changes
|
|
104
|
-
- Request specific files as needed during work
|
|
105
|
-
|
|
106
|
-
**Example progress.md:**
|
|
107
|
-
|
|
108
|
-
```markdown
|
|
109
|
-
# Current Status
|
|
110
|
-
|
|
111
|
-
## Completed
|
|
112
|
-
|
|
113
|
-
- User profile editing UI (see ProfileEditor.tsx)
|
|
114
|
-
- Form validation (see validation.ts)
|
|
115
|
-
- Tests for happy path (see profile-editor.test.ts)
|
|
116
|
-
|
|
117
|
-
## In Progress
|
|
118
|
-
|
|
119
|
-
- Error handling for network failures
|
|
120
|
-
- Next: Add retry logic following pattern in api-client.ts
|
|
121
|
-
- Tests: Need to add network error scenarios
|
|
122
|
-
|
|
123
|
-
## Blocked
|
|
124
|
-
|
|
125
|
-
- Avatar upload feature
|
|
126
|
-
- Reason: Waiting for S3 configuration from DevOps
|
|
127
|
-
- Tracking: Issue #456
|
|
128
|
-
|
|
129
|
-
## Next Session
|
|
130
|
-
|
|
131
|
-
Start with: Implementing retry logic in ProfileEditor.tsx
|
|
132
|
-
Reference: api-client.ts lines 89-112 for the retry pattern
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
This approach lets you maintain continuity without context bloat.
|
|
136
|
-
|
|
137
|
-
</context_overload_prevention>
|
|
138
|
-
|
|
139
|
-
---
|
|
140
|
-
|
|
141
|
-
<fresh_start_approach>
|
|
142
|
-
|
|
143
|
-
## Fresh Start Approach
|
|
144
|
-
|
|
145
|
-
Start each session as if it's the first:
|
|
146
|
-
|
|
147
|
-
1. Read .claude/ context files to understand state
|
|
148
|
-
2. Use git log to see recent changes
|
|
149
|
-
3. Examine filesystem to discover what exists
|
|
150
|
-
4. Run integration tests to verify current behavior
|
|
151
|
-
|
|
152
|
-
This "fresh start" approach works better than trying to maintain long chat history.
|
|
153
|
-
|
|
154
|
-
**Give the RIGHT context, not MORE context.**
|
|
155
|
-
|
|
156
|
-
- For a React component task: Provide that component + immediate dependencies
|
|
157
|
-
- For a store update: Provide the store + related stores
|
|
158
|
-
- For API work: Provide the endpoint + client utilities
|
|
159
|
-
|
|
160
|
-
Don't dump the entire codebase - focus context on what's relevant for the specific task.
|
|
161
|
-
|
|
162
|
-
</fresh_start_approach>
|
|
@@ -46,4 +46,16 @@ Based on standard authentication patterns, I'll implement...
|
|
|
46
46
|
|
|
47
47
|
Always choose the good approach.
|
|
48
48
|
|
|
49
|
+
### The Specification Is a Claim, Not a Fact
|
|
50
|
+
|
|
51
|
+
**Reading the files a specification names is not the same as checking it was right about them.** Every path, symbol, signature, line reference and count in a specification was measured against a codebase that has since moved. Re-derive each one against the code in front of you.
|
|
52
|
+
|
|
53
|
+
When an instruction does not describe what you find:
|
|
54
|
+
|
|
55
|
+
- **Stop on that item** - An instruction whose subject is not there cannot be implemented
|
|
56
|
+
- **Report it with the evidence** - The command you ran and what it returned, not your conclusion about it
|
|
57
|
+
- **Move on to the next item** - Never invent work to make the instruction true, and never quietly widen it into something that is
|
|
58
|
+
|
|
59
|
+
**Corrections are a required field of your report.** List everything in the specification that proved false, and write "Corrections: nothing" explicitly when nothing did - a report that stays silent is indistinguishable from a specification that held.
|
|
60
|
+
|
|
49
61
|
</investigation_requirement>
|
|
@@ -108,4 +108,14 @@ PASS Verified: git diff shows no changes to auth.py or related files
|
|
|
108
108
|
Evidence: `git diff main...feature-branch -- auth.py` returns empty
|
|
109
109
|
```
|
|
110
110
|
|
|
111
|
+
### Name What Would Catch It
|
|
112
|
+
|
|
113
|
+
Verification proves a criterion holds now. Nothing about it says the criterion will still hold after the next change, and those are two different claims.
|
|
114
|
+
|
|
115
|
+
**When your work lands a rule, a convention or an invariant, state what would catch a violation of it** - the test that fails, the type that stops compiling, the check that reports, the build step that breaks. Name the specific one rather than the category.
|
|
116
|
+
|
|
117
|
+
**When nothing would catch it, say so in as many words.** Saying nothing is read as "something covers it," so a gap has to be stated to be visible at all.
|
|
118
|
+
|
|
119
|
+
A rule that nothing mechanically checks will eventually be broken, most often by someone who never read it - and because the rule is written down, everyone will believe the matter is handled. Writing a rule and enforcing a rule are separate pieces of work, and only the first is finished when the sentence exists.
|
|
120
|
+
|
|
111
121
|
</verification_process>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/components/wizard/category-grid.tsx","../src/cli/components/hooks/use-category-grid-input.ts"],"sourcesContent":["import React, { useCallback, useEffect } from \"react\";\n\nimport { Box, Text } from \"ink\";\n\nimport { CLI_COLORS } from \"../../consts.js\";\nimport { getSkillById } from \"../../lib/matrix/matrix-provider.js\";\nimport type { Category, OptionState, SkillId, SkillScope } from \"../../types/index.js\";\nimport { useCategoryGridInput } from \"../hooks/use-category-grid-input.js\";\nimport { useFocusedListItem } from \"../hooks/use-focused-list-item.js\";\nimport { useSectionScroll } from \"../hooks/use-section-scroll.js\";\n\nexport type CategoryOption = {\n id: SkillId;\n state: OptionState;\n selected: boolean;\n local?: boolean;\n installed?: boolean;\n scope?: SkillScope;\n /** Secondary scope badge shown alongside primary (e.g. after G->P toggle, excluded tombstone) */\n secondaryScope?: SkillScope;\n source?: string;\n /** True when selected but has unmet dependency requirements (shown dimmed) */\n hasUnmetRequirements?: boolean;\n /** Explains unmet requirements (shown in label when D pressed) */\n unmetRequirementsReason?: string;\n /** Display name of the skill that requires this one (e.g. \"Next.js\") */\n requiredBy?: string;\n};\n\nexport type CategoryRow = {\n id: Category;\n displayName: string;\n required: boolean;\n exclusive: boolean;\n options: CategoryOption[];\n};\n\nexport type CategoryGridProps = {\n categories: CategoryRow[];\n /** Available height in terminal lines for the scrollable viewport. 0 = no constraint. */\n availableHeight?: number;\n showLabels: boolean;\n onToggle: (categoryId: Category, technologyId: SkillId) => void;\n onToggleLabels: () => void;\n /** Optional initial focus row (default: 0). Use with React `key` to reset. */\n defaultFocusedRow?: number;\n /** Optional initial focus col (default: 0). Use with React `key` to reset. */\n defaultFocusedCol?: number;\n /** Optional callback fired whenever the focused position changes */\n onFocusChange?: (row: number, col: number) => void;\n /** Optional callback fired with the resolved SkillId of the focused cell */\n onFocusedSkillChange?: (skillId: SkillId | null) => void;\n};\n\nconst SYMBOL_REQUIRED = \"*\";\n\n/** Next option index stepping cyclically from `currentIndex`; empty rows stay put. */\nconst wrapOptionIndex = (length: number, currentIndex: number, direction: 1 | -1): number => {\n if (length === 0) return currentIndex;\n return (currentIndex + direction + length) % length;\n};\n\ntype SkillTagProps = {\n option: CategoryOption;\n isFocused: boolean;\n showLabels: boolean;\n};\n\n/**\n * The verdict word and the reason behind it — `(incompatible: conflicts with Vue\n * Composition Api)`. Every advisory state but `normal` carries a reason, so the\n * status discriminant narrows to the two that have one to state.\n *\n * The word leads rather than the reason: it is the only carrier of the verdict\n * once colour is off, a `discourages` rule's reason is free-form author prose\n * that need not identify itself as a discouragement, and `CELL_ANNOTATION` in\n * `e2e/pages/steps/build-step.ts` anchors cell-label parsing on that keyword.\n *\n * Nothing is elided. A long reason grows the tag and wraps inside its border,\n * which is what `unmetRequirementsReason` above already does.\n */\nconst advisoryAnnotation = (state: OptionState): string | null =>\n state.status === \"normal\" ? null : `(${state.status}: ${state.reason})`;\n\nconst getCompatibilityLabel = (option: CategoryOption): string | null => {\n if (option.selected && option.hasUnmetRequirements && option.unmetRequirementsReason) {\n return `(${option.unmetRequirementsReason})`;\n }\n if (option.selected) return null;\n if (option.requiredBy) return `(required by ${option.requiredBy})`;\n return advisoryAnnotation(option.state);\n};\n\nconst STATUS_COLORS: Partial<Record<OptionState[\"status\"], string>> = {\n incompatible: CLI_COLORS.ERROR,\n discouraged: CLI_COLORS.WARNING,\n};\n\n/** Selected wins, then advisory status; `fallback` covers the plain \"normal\" state. */\nfunction resolveTagColor(option: CategoryOption, fallback: string): string {\n if (option.selected) return CLI_COLORS.PRIMARY;\n return STATUS_COLORS[option.state.status] ?? fallback;\n}\n\nconst SkillTag: React.FC<SkillTagProps> = ({ option, isFocused, showLabels }) => {\n const textColor = resolveTagColor(option, CLI_COLORS.DIM);\n const hasRequiredBy = option.selected && !!option.requiredBy;\n const hasUnmetDeps = option.selected && !!option.hasUnmetRequirements;\n const isDimmed = hasUnmetDeps || hasRequiredBy;\n const showCompatibility = hasRequiredBy || hasUnmetDeps || (showLabels && isFocused);\n const compatibilityLabel = showCompatibility ? getCompatibilityLabel(option) : null;\n\n return (\n <Box\n marginRight={1}\n borderColor={isFocused ? resolveTagColor(option, CLI_COLORS.UNFOCUSED) : textColor}\n borderDimColor={!isFocused}\n borderStyle=\"single\"\n flexShrink={0}\n paddingLeft={1}\n flexDirection=\"row\"\n >\n <>\n {option.scope && (\n <>\n {[option.scope, option.secondaryScope].filter(Boolean).map((badgeScope, i) => (\n <Text key={i} color={CLI_COLORS.WARNING} backgroundColor={CLI_COLORS.LABEL_BG}>\n {badgeScope === \"global\" ? \" G \" : \" P \"}\n </Text>\n ))}\n <Text> </Text>\n </>\n )}\n <Text color={textColor} bold dimColor={isDimmed}>\n {getSkillById(option.id).displayName}{\" \"}\n </Text>\n {compatibilityLabel && (\n <Text color={textColor} dimColor>\n {compatibilityLabel}{\" \"}\n </Text>\n )}\n </>\n </Box>\n );\n};\n\ntype CategorySectionProps = {\n isFirst: boolean;\n category: CategoryRow;\n isFocused: boolean;\n focusedOptionIndex: number;\n showLabels: boolean;\n};\n\nconst CategorySection: React.FC<CategorySectionProps> = ({\n isFirst,\n category,\n isFocused,\n focusedOptionIndex,\n showLabels,\n}) => {\n const { options } = category;\n const selectedCount = options.filter((o) => o.selected).length;\n\n const selectionCounter = category.exclusive ? `(${selectedCount} of 1)` : null;\n\n return (\n <Box flexDirection=\"column\" marginTop={isFirst ? 0 : 1}>\n <Box flexDirection=\"row\">\n {isFocused ? (\n <Text color={CLI_COLORS.WHITE} backgroundColor={CLI_COLORS.LABEL_BG}>\n {` ${category.displayName}${category.required ? ` ${SYMBOL_REQUIRED}` : \"\"}${selectionCounter ? ` ${selectionCounter}` : \"\"} `}\n </Text>\n ) : (\n <>\n <Text color={CLI_COLORS.NEUTRAL}>{category.displayName}</Text>\n {category.required && <Text color={CLI_COLORS.NEUTRAL}> {SYMBOL_REQUIRED}</Text>}\n {selectionCounter && <Text dimColor> {selectionCounter}</Text>}\n </>\n )}\n </Box>\n\n <Box flexDirection=\"row\" flexWrap=\"wrap\" marginTop={0}>\n {options.map((option, index) => (\n <SkillTag\n key={option.id}\n option={option}\n isFocused={isFocused && index === focusedOptionIndex}\n showLabels={showLabels}\n />\n ))}\n </Box>\n </Box>\n );\n};\n\nexport const CategoryGrid: React.FC<CategoryGridProps> = ({\n categories,\n availableHeight = 0,\n showLabels,\n onToggle,\n onToggleLabels,\n defaultFocusedRow = 0,\n defaultFocusedCol = 0,\n onFocusChange,\n onFocusedSkillChange,\n}) => {\n const getColCount = useCallback(\n (row: number): number => categories[row]?.options.length ?? 0,\n [categories],\n );\n\n const findValidCol = useCallback(\n (row: number, currentCol: number, direction: 1 | -1): number =>\n wrapOptionIndex(categories[row]?.options.length ?? 0, currentCol, direction),\n [categories],\n );\n\n const handleFocusChange = useCallback(\n (row: number, col: number) => {\n if (showLabels) onToggleLabels();\n onFocusChange?.(row, col);\n },\n [showLabels, onToggleLabels, onFocusChange],\n );\n\n const { focusedRow, focusedCol, setFocused, moveFocus } = useFocusedListItem(\n categories.length,\n getColCount,\n {\n wrap: true,\n findValidCol,\n onChange: handleFocusChange,\n initialRow: defaultFocusedRow,\n initialCol: defaultFocusedCol,\n },\n );\n\n useCategoryGridInput({\n categories,\n focusedRow,\n focusedCol,\n setFocused,\n moveFocus,\n onToggle,\n onToggleLabels,\n });\n\n // Report the focused cell's skill on mount and whenever it changes — including\n // category reshapes that shift the cell without a navigation event. useFocusedListItem\n // only fires onChange during navigation, so the initially highlighted cell would\n // otherwise never reach the store, leaving focusedSkillId out of sync with the visual\n // focus and making the `s` scope hotkey no-op until the first arrow key.\n const focusedSkillId = categories[focusedRow]?.options[focusedCol]?.id ?? null;\n useEffect(() => {\n onFocusedSkillChange?.(focusedSkillId);\n }, [focusedSkillId, onFocusedSkillChange]);\n\n // `hiddenAbove` / `hiddenBelow` are discarded ON PURPOSE — the build grid has\n // no `ScrollAffordance` and is not getting one (owner decision). On a grid\n // this dense a half-cut card already says \"there is more\"; a counted hint\n // would be noise, and it would cost the viewport a row to say what the\n // clipped card says for free. Do not add one on the strength of the counts\n // merely being available here.\n const { setSectionRef, scrollEnabled, scrollTopPx } = useSectionScroll({\n sectionCount: categories.length,\n focusedIndex: focusedRow,\n availableHeight,\n });\n\n if (categories.length === 0) {\n return (\n <Box flexDirection=\"column\">\n <Text dimColor>No categories to display.</Text>\n </Box>\n );\n }\n\n const noShrink = scrollEnabled ? { flexShrink: 0 } : {};\n\n const sectionElements = categories.map((category, index) => (\n <Box key={category.id} ref={(el) => setSectionRef(index, el)} {...noShrink}>\n <CategorySection\n category={category}\n isFocused={index === focusedRow}\n focusedOptionIndex={focusedCol}\n showLabels={showLabels}\n isFirst={index === 0}\n />\n </Box>\n ));\n\n return (\n <Box\n flexDirection=\"column\"\n {...(scrollEnabled\n ? { height: availableHeight, overflow: \"hidden\" as const }\n : { flexGrow: 1 })}\n >\n <Box flexDirection=\"column\" marginTop={scrollTopPx > 0 ? -scrollTopPx : 0} {...noShrink}>\n {sectionElements}\n </Box>\n </Box>\n );\n};\n","import { useCallback, useEffect, useMemo, useRef } from \"react\";\nimport { useInput, type Key } from \"ink\";\n\nimport type { Category, SkillId } from \"../../types/index.js\";\nimport type { CategoryRow } from \"../wizard/category-grid.js\";\nimport type { Direction } from \"./use-focused-list-item.js\";\nimport { HOTKEY_TOGGLE_LABELS, KEY_SPACE, isHotkey } from \"../wizard/hotkeys.js\";\n\n/** Find next section index (wrapping forward) */\nconst findNextIndex = (items: { length: number }, currentIndex: number): number => {\n const length = items.length;\n if (length === 0) return currentIndex;\n return (currentIndex + 1) % length;\n};\n\ntype UseCategoryGridInputOptions = {\n categories: CategoryRow[];\n focusedRow: number;\n focusedCol: number;\n setFocused: (row: number, col: number) => void;\n moveFocus: (direction: Direction) => void;\n onToggle: (categoryId: Category, technologyId: SkillId) => void;\n onToggleLabels: () => void;\n};\n\nexport function useCategoryGridInput({\n categories,\n focusedRow,\n focusedCol,\n setFocused,\n moveFocus,\n onToggle,\n onToggleLabels,\n}: UseCategoryGridInputOptions): void {\n const currentRow = categories[focusedRow];\n // Memoised so the effect below keys on the row actually changing — the `[]`\n // fallback used to be a fresh array every render, re-running the effect for\n // nothing whenever no row was focused.\n const currentOptions = useMemo(() => currentRow?.options ?? [], [currentRow]);\n\n // Adjust column when current row's options change externally (e.g. option becomes disabled)\n useEffect(() => {\n if (!currentRow) return;\n\n const maxCol = currentOptions.length - 1;\n if (focusedCol > maxCol) {\n const newCol = Math.max(0, maxCol);\n setFocused(focusedRow, newCol);\n }\n }, [focusedRow, currentOptions, focusedCol, setFocused, currentRow]);\n\n // Store the latest handler in a ref so that the useInput effect never needs to\n // re-register on the event emitter. This avoids a stale-closure race condition\n // where, after a domain switch (CategoryGrid remount via key={activeDomain}),\n // the useInput effect may not yet have re-registered the updated handler when\n // the first keypress arrives — causing the first space press to be silently lost.\n const handlerRef = useRef<((input: string, key: Key) => void) | null>(null);\n handlerRef.current = (input: string, key: Key) => {\n if (key.tab && key.shift) {\n onToggleLabels();\n return;\n }\n\n if (key.tab && !key.shift) {\n const nextSection = findNextIndex(categories, focusedRow);\n if (nextSection !== focusedRow) {\n setFocused(nextSection, 0);\n }\n return;\n }\n\n if (isHotkey(input, HOTKEY_TOGGLE_LABELS)) {\n onToggleLabels();\n return;\n }\n\n if (input === KEY_SPACE) {\n const currentOption = currentOptions[focusedCol];\n if (currentRow && currentOption) {\n onToggle(currentRow.id, currentOption.id);\n }\n return;\n }\n\n const isLeft = key.leftArrow || input === \"h\";\n const isRight = key.rightArrow || input === \"l\";\n const isUp = key.upArrow || input === \"k\";\n const isDown = key.downArrow || input === \"j\";\n\n if (isLeft) {\n moveFocus(\"left\");\n } else if (isRight) {\n moveFocus(\"right\");\n } else if (isUp) {\n moveFocus(\"up\");\n } else if (isDown) {\n moveFocus(\"down\");\n }\n };\n\n // Stable handler reference — never changes, so useInput's effect registers once\n const stableHandler = useCallback((input: string, key: Key) => {\n handlerRef.current?.(input, key);\n }, []);\n\n useInput(stableHandler);\n}\n"],"mappings":"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","names":["useCallback","useEffect","useCallback","useEffect"]}
|