get-tbd 0.1.13 → 0.1.15
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/README.md +47 -28
- package/dist/bin.mjs +410 -170
- package/dist/bin.mjs.map +1 -1
- package/dist/cli.mjs +202 -94
- package/dist/cli.mjs.map +1 -1
- package/dist/docs/README.md +47 -28
- package/dist/docs/SKILL.md +61 -18
- package/dist/docs/guidelines/bun-monorepo-patterns.md +2096 -0
- package/dist/docs/guidelines/cli-agent-skill-patterns.md +79 -5
- package/dist/docs/guidelines/error-handling-rules.md +66 -0
- package/dist/docs/guidelines/pnpm-monorepo-patterns.md +2868 -0
- package/dist/docs/guidelines/release-notes-guidelines.md +140 -0
- package/dist/docs/guidelines/{sync-troubleshooting.md → tbd-sync-troubleshooting.md} +1 -1
- package/dist/docs/guidelines/typescript-sorting-patterns.md +234 -0
- package/dist/docs/guidelines/typescript-yaml-handling-rules.md +195 -0
- package/dist/docs/install/claude-header.md +13 -6
- package/dist/docs/shortcuts/standard/agent-handoff.md +1 -0
- package/dist/docs/shortcuts/standard/checkout-third-party-repo.md +50 -0
- package/dist/docs/shortcuts/standard/{cleanup-all.md → code-cleanup-all.md} +3 -2
- package/dist/docs/shortcuts/standard/{cleanup-update-docstrings.md → code-cleanup-docstrings.md} +1 -0
- package/dist/docs/shortcuts/standard/{cleanup-remove-trivial-tests.md → code-cleanup-tests.md} +1 -0
- package/dist/docs/shortcuts/standard/{commit-code.md → code-review-and-commit.md} +1 -0
- package/dist/docs/shortcuts/standard/coding-spike.md +54 -0
- package/dist/docs/shortcuts/standard/create-or-update-pr-simple.md +1 -0
- package/dist/docs/shortcuts/standard/create-or-update-pr-with-validation-plan.md +1 -0
- package/dist/docs/shortcuts/standard/implement-beads.md +1 -0
- package/dist/docs/shortcuts/standard/merge-upstream.md +1 -0
- package/dist/docs/shortcuts/standard/new-architecture-doc.md +1 -0
- package/dist/docs/shortcuts/standard/new-guideline.md +8 -0
- package/dist/docs/shortcuts/standard/new-plan-spec.md +1 -0
- package/dist/docs/shortcuts/standard/new-research-brief.md +1 -0
- package/dist/docs/shortcuts/standard/new-shortcut.md +27 -1
- package/dist/docs/shortcuts/standard/new-validation-plan.md +1 -0
- package/dist/docs/shortcuts/standard/plan-implementation-with-beads.md +1 -0
- package/dist/docs/shortcuts/standard/precommit-process.md +1 -0
- package/dist/docs/shortcuts/standard/review-code-python.md +1 -0
- package/dist/docs/shortcuts/standard/review-code-typescript.md +1 -0
- package/dist/docs/shortcuts/standard/review-code.md +1 -0
- package/dist/docs/shortcuts/standard/review-github-pr.md +89 -17
- package/dist/docs/shortcuts/standard/revise-all-architecture-docs.md +1 -0
- package/dist/docs/shortcuts/standard/revise-architecture-doc.md +1 -0
- package/dist/docs/shortcuts/standard/setup-github-cli.md +1 -0
- package/dist/docs/shortcuts/standard/sync-failure-recovery.md +6 -53
- package/dist/docs/shortcuts/standard/update-specs-status.md +1 -0
- package/dist/docs/shortcuts/standard/welcome-user.md +2 -1
- package/dist/docs/shortcuts/system/skill-brief.md +1 -1
- package/dist/docs/shortcuts/system/skill.md +48 -12
- package/dist/docs/skill-brief.md +1 -1
- package/dist/docs/tbd-design.md +13 -1
- package/dist/index.d.mts +20 -6
- package/dist/index.mjs +2 -2
- package/dist/{src-BfhjLZXE.mjs → src-Ct16P2Ox.mjs} +154 -22
- package/dist/src-Ct16P2Ox.mjs.map +1 -0
- package/dist/tbd +410 -170
- package/package.json +1 -1
- package/dist/docs/guidelines/typescript-monorepo-patterns.md +0 -72
- package/dist/src-BfhjLZXE.mjs.map +0 -1
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Release Notes Guidelines
|
|
3
|
+
description: Guidelines for writing clear, accurate release notes
|
|
4
|
+
---
|
|
5
|
+
# Release Notes Guidelines
|
|
6
|
+
|
|
7
|
+
Write release notes that are accurate, scannable, and useful to users deciding whether
|
|
8
|
+
to upgrade.
|
|
9
|
+
|
|
10
|
+
## Structure
|
|
11
|
+
|
|
12
|
+
Use these sections in order (omit empty sections):
|
|
13
|
+
|
|
14
|
+
```markdown
|
|
15
|
+
## What's Changed
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
- New capabilities users can now do
|
|
19
|
+
|
|
20
|
+
### Fixes
|
|
21
|
+
- Bug fixes and corrections
|
|
22
|
+
|
|
23
|
+
### Refactoring
|
|
24
|
+
- Internal improvements (only if user-visible impact)
|
|
25
|
+
|
|
26
|
+
### Documentation
|
|
27
|
+
- Doc improvements (only notable ones)
|
|
28
|
+
|
|
29
|
+
**Full commit history**: [link to compare]
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Core Principle: Describe the Delta
|
|
33
|
+
|
|
34
|
+
**Think in terms of two points in time:**
|
|
35
|
+
|
|
36
|
+
1. The state of the application at the previous release
|
|
37
|
+
2. The state of the application at this release
|
|
38
|
+
|
|
39
|
+
Release notes describe the **aggregate difference** between these two states.
|
|
40
|
+
Don’t recap individual commits or intermediate changes - describe what’s different now
|
|
41
|
+
compared to before.
|
|
42
|
+
|
|
43
|
+
**Example:** If a feature was added and then bug-fixed before release, don’t list the
|
|
44
|
+
bug fix separately.
|
|
45
|
+
Describe the feature as it now works (the complete, working version).
|
|
46
|
+
|
|
47
|
+
## Writing Principles
|
|
48
|
+
|
|
49
|
+
### 1. Consolidate Related Changes
|
|
50
|
+
|
|
51
|
+
Group sub-features, fixes, and improvements with their parent feature rather than
|
|
52
|
+
listing them separately.
|
|
53
|
+
If a bug fix is for a feature added in the same release, incorporate it into the feature
|
|
54
|
+
description.
|
|
55
|
+
|
|
56
|
+
**Bad:**
|
|
57
|
+
|
|
58
|
+
```markdown
|
|
59
|
+
### Features
|
|
60
|
+
- **Workspace sync**: New tbd save command
|
|
61
|
+
- **Workspace list**: Show saved workspaces
|
|
62
|
+
|
|
63
|
+
### Fixes
|
|
64
|
+
- **Workspace mappings**: Save now filters mappings correctly
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Good:**
|
|
68
|
+
|
|
69
|
+
```markdown
|
|
70
|
+
### Features
|
|
71
|
+
- **Workspace sync feature**: New commands for managing local workspace backups:
|
|
72
|
+
- `tbd save` to export issues (filters mappings correctly)
|
|
73
|
+
- `tbd workspace list` to show saved workspaces with counts
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 2. Write From the User’s Perspective
|
|
77
|
+
|
|
78
|
+
Describe capabilities users now have, not implementation details.
|
|
79
|
+
A user reading the notes should understand what they can do differently after upgrading.
|
|
80
|
+
|
|
81
|
+
### 3. Be Specific About Impact
|
|
82
|
+
|
|
83
|
+
Include the user-facing impact, not just the implementation detail.
|
|
84
|
+
|
|
85
|
+
**Bad:**
|
|
86
|
+
|
|
87
|
+
> Increased git maxBuffer
|
|
88
|
+
|
|
89
|
+
**Good:**
|
|
90
|
+
|
|
91
|
+
> Git maxBuffer overflow: Increased buffer from 1MB to 50MB to prevent sync failures on
|
|
92
|
+
> large repos
|
|
93
|
+
|
|
94
|
+
### 4. Use Consistent Formatting
|
|
95
|
+
|
|
96
|
+
- Bold the feature/fix name
|
|
97
|
+
- Use bullet points for sub-items
|
|
98
|
+
- Include command names in backticks
|
|
99
|
+
- Keep descriptions concise (1-2 lines)
|
|
100
|
+
|
|
101
|
+
### 5. Skip Internal-Only Changes
|
|
102
|
+
|
|
103
|
+
Don’t include:
|
|
104
|
+
|
|
105
|
+
- Test-only changes (unless they fix flaky tests users noticed)
|
|
106
|
+
- Pure refactoring with no user impact
|
|
107
|
+
- CI/tooling changes
|
|
108
|
+
- Minor doc typo fixes
|
|
109
|
+
|
|
110
|
+
## Review Checklist
|
|
111
|
+
|
|
112
|
+
Before finalizing release notes:
|
|
113
|
+
|
|
114
|
+
- [ ] Does each item describe the aggregate delta from the previous release?
|
|
115
|
+
- [ ] Are related changes (features + their fixes) consolidated under one heading?
|
|
116
|
+
- [ ] Would a user understand what’s different after upgrading?
|
|
117
|
+
- [ ] Are feature names/commands in consistent format?
|
|
118
|
+
- [ ] Are internal-only changes excluded?
|
|
119
|
+
|
|
120
|
+
## Example
|
|
121
|
+
|
|
122
|
+
```markdown
|
|
123
|
+
## What's Changed
|
|
124
|
+
|
|
125
|
+
### Features
|
|
126
|
+
|
|
127
|
+
- **Workspace sync feature**: New commands for managing local workspace backups:
|
|
128
|
+
- `tbd save` to export issues to workspace directories (supports `--updates-only`)
|
|
129
|
+
- `tbd workspace list` to show saved workspaces with issue counts
|
|
130
|
+
- `tbd import --workspace` to restore from workspace backups
|
|
131
|
+
- **Child bead ordering**: New `child_order` field allows explicit ordering of child
|
|
132
|
+
beads
|
|
133
|
+
|
|
134
|
+
### Fixes
|
|
135
|
+
|
|
136
|
+
- **Git maxBuffer overflow**: Increased buffer from 1MB to 50MB to prevent sync
|
|
137
|
+
failures on large repos
|
|
138
|
+
|
|
139
|
+
**Full commit history**: https://github.com/org/repo/compare/v0.1.12...v0.1.13
|
|
140
|
+
```
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: TypeScript Sorting Patterns
|
|
3
|
+
description: Deterministic sorting patterns and comparison chains for TypeScript
|
|
4
|
+
author: Joshua Levy (github.com/jlevy) with LLM assistance
|
|
5
|
+
---
|
|
6
|
+
# TypeScript Sorting Patterns
|
|
7
|
+
|
|
8
|
+
**Related**: `tbd guidelines typescript-rules`, `tbd guidelines general-testing-rules`
|
|
9
|
+
|
|
10
|
+
## 1. Always Make Sorting Deterministic
|
|
11
|
+
|
|
12
|
+
Never leave a sort with only a primary key.
|
|
13
|
+
When two items have the same primary sort value, the output order is undefined and will
|
|
14
|
+
vary across runs, platforms, and data sizes.
|
|
15
|
+
This causes flaky tests, confusing UI, and unreproducible bugs.
|
|
16
|
+
|
|
17
|
+
**Always add a secondary (or tertiary) sort key that is guaranteed unique**, such as an
|
|
18
|
+
ID or timestamp.
|
|
19
|
+
|
|
20
|
+
### BAD: Primary sort only
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
// If two issues share the same priority, order is random.
|
|
24
|
+
issues.sort((a, b) => a.priority - b.priority);
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### GOOD: Secondary sort for determinism
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
issues.sort((a, b) => {
|
|
31
|
+
const cmp = a.priority - b.priority;
|
|
32
|
+
if (cmp !== 0) return cmp;
|
|
33
|
+
return a.id.localeCompare(b.id);
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
This pattern applies everywhere: UI lists, CLI output, test assertions, API responses.
|
|
38
|
+
If you can’t guarantee uniqueness of the primary key, you need a tiebreaker.
|
|
39
|
+
|
|
40
|
+
## 2. Use Comparison Chains for Multi-Field Sorts
|
|
41
|
+
|
|
42
|
+
Hand-written multi-field comparators are verbose and error-prone.
|
|
43
|
+
A **comparison chain** (inspired by Google Guava’s `ComparisonChain`) provides a fluent
|
|
44
|
+
API that’s easier to read, write, and maintain.
|
|
45
|
+
|
|
46
|
+
### Before: Manual multi-field sort with nulls
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
items.sort((a, b) => {
|
|
50
|
+
// Primary: priority ascending
|
|
51
|
+
if (a.priority !== b.priority) return a.priority - b.priority;
|
|
52
|
+
// Secondary: title, nulls last
|
|
53
|
+
if (a.title === null && b.title !== null) return 1;
|
|
54
|
+
if (a.title !== null && b.title === null) return -1;
|
|
55
|
+
if (a.title !== null && b.title !== null) {
|
|
56
|
+
const cmp = a.title.localeCompare(b.title);
|
|
57
|
+
if (cmp !== 0) return cmp;
|
|
58
|
+
}
|
|
59
|
+
// Tertiary: ID for determinism
|
|
60
|
+
return a.id.localeCompare(b.id);
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### After: Comparison chain
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
items.sort(
|
|
68
|
+
comparisonChain<Item>()
|
|
69
|
+
.compare((i) => i.priority)
|
|
70
|
+
.compare((i) => i.title, ordering.nullsLast)
|
|
71
|
+
.compare((i) => i.id)
|
|
72
|
+
.result(),
|
|
73
|
+
);
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The chain short-circuits: once a `.compare()` step returns non-zero, subsequent steps
|
|
77
|
+
are skipped. This matches the semantics of manual `if (cmp !== 0) return cmp` chains.
|
|
78
|
+
|
|
79
|
+
## 3. Comparison Chain Reference Implementation
|
|
80
|
+
|
|
81
|
+
The following is a standalone, dependency-free utility.
|
|
82
|
+
Copy it into your project:
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
export type Selector<T, K> = (item: T) => K;
|
|
86
|
+
export type Comparator<T> = (a: T, b: T) => number;
|
|
87
|
+
|
|
88
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
89
|
+
const defaultCompare: Comparator<any> = (a, b) => {
|
|
90
|
+
if (typeof a === 'string' && typeof b === 'string') {
|
|
91
|
+
return a.localeCompare(b);
|
|
92
|
+
}
|
|
93
|
+
if (a < b) return -1;
|
|
94
|
+
if (a > b) return 1;
|
|
95
|
+
return 0;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
99
|
+
const nullLastCompare: Comparator<any> = (a, b) => {
|
|
100
|
+
if (a == null) return b == null ? 0 : 1;
|
|
101
|
+
if (b == null) return -1;
|
|
102
|
+
return defaultCompare(a, b);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
106
|
+
const nullFirstCompare: Comparator<any> = (a, b) => {
|
|
107
|
+
if (a == null) return b == null ? 0 : -1;
|
|
108
|
+
if (b == null) return 1;
|
|
109
|
+
return defaultCompare(a, b);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* A Google Guava-style comparison chain for fluent multi-field sorting.
|
|
114
|
+
*
|
|
115
|
+
* items.sort(comparisonChain<Item>()
|
|
116
|
+
* .compare(item => item.title, ordering.nullsLast)
|
|
117
|
+
* .compare(item => item.url)
|
|
118
|
+
* .result());
|
|
119
|
+
*/
|
|
120
|
+
export const comparisonChain = <T>() => {
|
|
121
|
+
let compare: Comparator<T> = () => 0;
|
|
122
|
+
|
|
123
|
+
const chain: {
|
|
124
|
+
compare: <K>(selector: Selector<T, K>, comparator?: Comparator<K>) => typeof chain;
|
|
125
|
+
result: () => Comparator<T>;
|
|
126
|
+
} = {
|
|
127
|
+
compare: <K>(selector: Selector<T, K>, comparator: Comparator<K> = defaultCompare) => {
|
|
128
|
+
const prevCompare = compare;
|
|
129
|
+
compare = (a, b) => prevCompare(a, b) || comparator(selector(a), selector(b));
|
|
130
|
+
return chain;
|
|
131
|
+
},
|
|
132
|
+
result: () => compare,
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
return chain;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
export const reverse =
|
|
139
|
+
<T>(comparator: Comparator<T>) =>
|
|
140
|
+
(a: T, b: T) =>
|
|
141
|
+
comparator(b, a);
|
|
142
|
+
|
|
143
|
+
const manualOrderComparator = <T>(order: readonly T[]): Comparator<T> => {
|
|
144
|
+
const orderMap = new Map(order.map((value, index) => [value, index]));
|
|
145
|
+
return (a: T, b: T): number => {
|
|
146
|
+
const indexA = orderMap.get(a);
|
|
147
|
+
const indexB = orderMap.get(b);
|
|
148
|
+
if (indexA === undefined) return indexB === undefined ? 0 : 1;
|
|
149
|
+
if (indexB === undefined) return -1;
|
|
150
|
+
return indexA - indexB;
|
|
151
|
+
};
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
export const ordering = {
|
|
155
|
+
nullsLast: nullLastCompare,
|
|
156
|
+
nullsFirst: nullFirstCompare,
|
|
157
|
+
default: defaultCompare,
|
|
158
|
+
reversed: reverse(defaultCompare),
|
|
159
|
+
manual: manualOrderComparator,
|
|
160
|
+
};
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## 4. Common Ordering Strategies
|
|
164
|
+
|
|
165
|
+
| Ordering | Behavior |
|
|
166
|
+
| --- | --- |
|
|
167
|
+
| `ordering.default` | Strings via `localeCompare`, numbers via `<`/`>` |
|
|
168
|
+
| `ordering.reversed` | Reverse of default (descending) |
|
|
169
|
+
| `ordering.nullsLast` | `null`/`undefined` sort after all non-null values |
|
|
170
|
+
| `ordering.nullsFirst` | `null`/`undefined` sort before all non-null values |
|
|
171
|
+
| `ordering.manual(…)` | Sort by position in an explicit array; unlisted go last |
|
|
172
|
+
| `reverse(cmp)` | Wrap any comparator to invert its direction |
|
|
173
|
+
|
|
174
|
+
## 5. Usage Examples
|
|
175
|
+
|
|
176
|
+
### Simple priority + ID sort
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
issues.sort(
|
|
180
|
+
comparisonChain<Issue>()
|
|
181
|
+
.compare((i) => i.priority)
|
|
182
|
+
.compare((i) => i.id)
|
|
183
|
+
.result(),
|
|
184
|
+
);
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Descending date with ID tiebreaker
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
staleItems.sort(
|
|
191
|
+
comparisonChain<StaleItem>()
|
|
192
|
+
.compare((s) => s.daysSinceUpdate, ordering.reversed)
|
|
193
|
+
.compare((s) => s.issue.id)
|
|
194
|
+
.result(),
|
|
195
|
+
);
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Multi-field with nulls
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
items.sort(
|
|
202
|
+
comparisonChain<Item>()
|
|
203
|
+
.compare((i) => i.title, ordering.nullsLast)
|
|
204
|
+
.compare((i) => i.url, ordering.nullsLast)
|
|
205
|
+
.compare((i) => i.sequenceNum, ordering.nullsLast)
|
|
206
|
+
.result(),
|
|
207
|
+
);
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Custom enum ordering
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
const statusOrder = ['active', 'pending', 'archived'] as const;
|
|
214
|
+
|
|
215
|
+
items.sort(
|
|
216
|
+
comparisonChain<Item>()
|
|
217
|
+
.compare((i) => i.status, ordering.manual(statusOrder))
|
|
218
|
+
.compare((i) => i.name)
|
|
219
|
+
.result(),
|
|
220
|
+
);
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### With a custom comparator (e.g. natural sort)
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
import { naturalCompare } from './sort.js';
|
|
227
|
+
|
|
228
|
+
items.sort(
|
|
229
|
+
comparisonChain<Item>()
|
|
230
|
+
.compare((i) => i.priority)
|
|
231
|
+
.compare((i) => getShortId(i), (a, b) => naturalCompare(a, b))
|
|
232
|
+
.result(),
|
|
233
|
+
);
|
|
234
|
+
```
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: TypeScript YAML Handling Rules
|
|
3
|
+
description: Best practices for parsing and serializing YAML in TypeScript
|
|
4
|
+
author: Joshua Levy (github.com/jlevy) with LLM assistance
|
|
5
|
+
globs: "*.ts"
|
|
6
|
+
---
|
|
7
|
+
# TypeScript YAML Handling Rules
|
|
8
|
+
|
|
9
|
+
These guidelines ensure consistent, safe, and readable YAML handling across TypeScript
|
|
10
|
+
codebases. YAML is deceptively tricky—inconsistent quoting, serialization differences,
|
|
11
|
+
and lack of validation cause subtle bugs.
|
|
12
|
+
|
|
13
|
+
## Use the Right Package
|
|
14
|
+
|
|
15
|
+
- **Use `yaml` (v2.x)**, not `js-yaml`. The `yaml` package has better TypeScript
|
|
16
|
+
support, more control over output formatting, and proper handling of edge cases.
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
// Good
|
|
20
|
+
import { parse, stringify } from 'yaml';
|
|
21
|
+
|
|
22
|
+
// Avoid
|
|
23
|
+
import yaml from 'js-yaml';
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Centralize Serialization Options
|
|
27
|
+
|
|
28
|
+
- **Externalize settings to a central file** instead of scattering `stringify()` calls
|
|
29
|
+
with ad-hoc options throughout the codebase.
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
// lib/settings.ts
|
|
33
|
+
export const DEFAULT_YAML_LINE_WIDTH = 88;
|
|
34
|
+
|
|
35
|
+
// Readable YAML output:
|
|
36
|
+
// - No forced quoting (YAML only quotes when necessary)
|
|
37
|
+
// - Line wrapping at 88 chars for readability
|
|
38
|
+
// - Sorted keys for deterministic diffs
|
|
39
|
+
export const YAML_STRINGIFY_OPTIONS = {
|
|
40
|
+
lineWidth: DEFAULT_YAML_LINE_WIDTH,
|
|
41
|
+
defaultStringType: 'PLAIN',
|
|
42
|
+
defaultKeyType: 'PLAIN',
|
|
43
|
+
sortMapEntries: true,
|
|
44
|
+
} as const;
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
- **Use the centralized options** wherever you serialize YAML:
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
// serialize.ts
|
|
51
|
+
import { stringify } from 'yaml';
|
|
52
|
+
import { YAML_STRINGIFY_OPTIONS } from '../lib/settings.js';
|
|
53
|
+
|
|
54
|
+
const yamlStr = stringify(frontmatterObj, YAML_STRINGIFY_OPTIONS);
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
- **Optionally create wrapper functions** for additional convenience:
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
// utils/yaml-utils.ts
|
|
61
|
+
import { stringify } from 'yaml';
|
|
62
|
+
import { YAML_STRINGIFY_OPTIONS } from '../lib/settings.js';
|
|
63
|
+
|
|
64
|
+
export function stringifyYaml(data: unknown, options?: object): string {
|
|
65
|
+
return stringify(data, { ...YAML_STRINGIFY_OPTIONS, ...options });
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Recommended Defaults
|
|
70
|
+
|
|
71
|
+
These defaults produce clean, readable YAML without unnecessary quoting:
|
|
72
|
+
|
|
73
|
+
| Option | Value | Rationale |
|
|
74
|
+
| --- | --- | --- |
|
|
75
|
+
| `lineWidth` | 88 | Line wrapping for readability (matches Black formatter) |
|
|
76
|
+
| `defaultStringType` | `'PLAIN'` | No quotes unless necessary (e.g., special chars, colons) |
|
|
77
|
+
| `defaultKeyType` | `'PLAIN'` | Unquoted keys: `name:` not `"name":` |
|
|
78
|
+
| `sortMapEntries` | `true` | Deterministic output for clean diffs |
|
|
79
|
+
|
|
80
|
+
The key insight: YAML is designed to be human-readable.
|
|
81
|
+
Forcing quotes everywhere (e.g., `"value"` instead of `value`) defeats this purpose.
|
|
82
|
+
Use `PLAIN` types to let YAML quote only when semantically required.
|
|
83
|
+
|
|
84
|
+
## Validate with Zod
|
|
85
|
+
|
|
86
|
+
- **Always validate parsed YAML** with a Zod schema.
|
|
87
|
+
Raw `parse()` returns `unknown` and provides no guarantees about structure.
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
// Good
|
|
91
|
+
import { z } from 'zod';
|
|
92
|
+
import { parse } from 'yaml';
|
|
93
|
+
|
|
94
|
+
const ConfigSchema = z.object({
|
|
95
|
+
name: z.string(),
|
|
96
|
+
version: z.string(),
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const rawData = parse(content);
|
|
100
|
+
const result = ConfigSchema.safeParse(rawData);
|
|
101
|
+
if (!result.success) {
|
|
102
|
+
throw new Error(`Invalid config: ${result.error.message}`);
|
|
103
|
+
}
|
|
104
|
+
const config = result.data; // Typed and validated
|
|
105
|
+
|
|
106
|
+
// Avoid
|
|
107
|
+
const config = parse(content) as Config; // Type assertion with no runtime validation
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Handle Merge Conflicts
|
|
111
|
+
|
|
112
|
+
- **Check for git merge conflict markers** before parsing user-editable files.
|
|
113
|
+
Conflict markers cause cryptic YAML parse errors.
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
export function parseYamlWithConflictDetection<T>(content: string, filePath?: string): T {
|
|
117
|
+
if (/^<<<<<<< /m.test(content) || /^=======/m.test(content) || /^>>>>>>> /m.test(content)) {
|
|
118
|
+
throw new MergeConflictError(
|
|
119
|
+
`File contains unresolved git merge conflict markers`,
|
|
120
|
+
filePath
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
return parse(content) as T;
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Common Antipatterns
|
|
128
|
+
|
|
129
|
+
### Antipattern: Manual String Building
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
// Bad: Manual YAML string construction
|
|
133
|
+
const yaml = `name: ${name}\nversion: ${version}`;
|
|
134
|
+
|
|
135
|
+
// Good: Use stringify()
|
|
136
|
+
const yaml = stringifyYaml({ name, version });
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Antipattern: Inconsistent Quoting
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
// Bad: Inconsistent options across codebase
|
|
143
|
+
stringify(data1, { lineWidth: 80 });
|
|
144
|
+
stringify(data2, { lineWidth: 100, defaultStringType: 'QUOTE_DOUBLE' });
|
|
145
|
+
stringify(data3); // No options
|
|
146
|
+
|
|
147
|
+
// Good: Use centralized wrapper
|
|
148
|
+
stringifyYaml(data1);
|
|
149
|
+
stringifyYaml(data2);
|
|
150
|
+
stringifyYaml(data3);
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Antipattern: Unvalidated Parsing
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
// Bad: Type assertion without validation
|
|
157
|
+
const config = parse(content) as Config;
|
|
158
|
+
|
|
159
|
+
// Good: Runtime validation
|
|
160
|
+
const config = ConfigSchema.parse(parse(content));
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Antipattern: Using gray-matter Directly for Serialization
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
// Bad: gray-matter.stringify() has limited formatting control
|
|
167
|
+
import matter from 'gray-matter';
|
|
168
|
+
const output = matter.stringify(body, frontmatter);
|
|
169
|
+
|
|
170
|
+
// Good: Use gray-matter for parsing, yaml package for serialization
|
|
171
|
+
import matter from 'gray-matter';
|
|
172
|
+
import { stringifyYaml } from './yaml-utils.js';
|
|
173
|
+
|
|
174
|
+
const { data, content } = matter(input);
|
|
175
|
+
const output = `---\n${stringifyYaml(data)}---\n\n${content}`;
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Testing YAML Output
|
|
179
|
+
|
|
180
|
+
- **Don’t rely on key order in tests** when using `sortMapEntries: true`. Keys are
|
|
181
|
+
sorted alphabetically.
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
// Fragile: Depends on key order
|
|
185
|
+
expect(yaml).toMatch(/^---\nname: foo\nversion: 1/);
|
|
186
|
+
|
|
187
|
+
// Robust: Tests presence, not order
|
|
188
|
+
expect(yaml).toContain('name: foo');
|
|
189
|
+
expect(yaml).toContain('version: 1');
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Related Guidelines
|
|
193
|
+
|
|
194
|
+
- For general TypeScript rules, see `tbd guidelines typescript-rules`
|
|
195
|
+
- For error handling patterns, see `tbd guidelines error-handling-rules`
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: tbd
|
|
3
3
|
description: >-
|
|
4
|
-
Git-native issue tracking (beads), coding guidelines, and spec-driven
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
Git-native issue tracking (beads), coding guidelines, knowledge injection, and spec-driven
|
|
5
|
+
planning for AI agents. Drop-in replacement for bd/Beads with simpler architecture.
|
|
6
|
+
|
|
7
|
+
Use for: tracking issues/beads with dependencies, creating bugs/features/tasks, planning specs,
|
|
8
|
+
implementing features from specs, code reviews, committing code, creating PRs, loading coding
|
|
9
|
+
guidelines (TypeScript, Python, TDD, golden testing, Convex, monorepo patterns), code cleanup,
|
|
10
|
+
research briefs, architecture docs, agent handoffs, and checking out third-party library source code.
|
|
11
|
+
|
|
12
|
+
Invoke when user mentions: tbd, beads, bd, shortcuts, issues, bugs, tasks, features, epics, todo,
|
|
13
|
+
tracking, specs, planning, implementation, validation, guidelines, templates, commit, PR, pull request,
|
|
14
|
+
code review, testing, TDD, test-driven, golden testing, snapshot testing, TypeScript, Python, Convex,
|
|
15
|
+
monorepo, cleanup, dead code, refactor, handoff, research, architecture, labels, search, checkout library,
|
|
16
|
+
source code review, or any workflow shortcut.
|
|
10
17
|
allowed-tools: Bash(tbd:*), Read, Write
|
|
11
18
|
---
|
|
12
19
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Checkout Third-Party Repo
|
|
3
|
+
description: Get source code for libraries and third-party repos using git. Essential for reliable source code review. Prefer this to web searches or fetching of web pages from github.com as it is far more effective (github.com blocks web scraping from main website).
|
|
4
|
+
category: research
|
|
5
|
+
author: Joshua Levy (github.com/jlevy) with LLM assistance
|
|
6
|
+
---
|
|
7
|
+
Clone a third-party library or tool’s repository locally to review its source code.
|
|
8
|
+
|
|
9
|
+
## Why This Approach
|
|
10
|
+
|
|
11
|
+
**Do not** use web search or try to scrape GitHub.com for source code.
|
|
12
|
+
GitHub blocks scraping, results are messy, and you lose full codebase context.
|
|
13
|
+
Cloning locally gives you reliable, complete, searchable access to the exact version you
|
|
14
|
+
need.
|
|
15
|
+
|
|
16
|
+
## Steps
|
|
17
|
+
|
|
18
|
+
1. **Create attic directory** (if not exists):
|
|
19
|
+
```bash
|
|
20
|
+
mkdir -p attic
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
2. **Add to .gitignore** (if not already):
|
|
24
|
+
```bash
|
|
25
|
+
echo "attic/" >> .gitignore
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
3. **Identify the version in use**: Check `package.json`, `requirements.txt`,
|
|
29
|
+
`Cargo.toml`, etc. for the exact version of the dependency you’re investigating.
|
|
30
|
+
|
|
31
|
+
4. **Clone the repo**:
|
|
32
|
+
```bash
|
|
33
|
+
git clone <repo-url> attic/<repo-name>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
5. **Checkout the matching version**: Find the tag or branch matching your project’s
|
|
37
|
+
version:
|
|
38
|
+
```bash
|
|
39
|
+
cd attic/<repo-name>
|
|
40
|
+
git tag -l | grep <version> # Find matching tag
|
|
41
|
+
git checkout <tag-or-branch>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
6. **Explore**: Now use standard tools (Grep, Read, Glob) to investigate the source.
|
|
45
|
+
|
|
46
|
+
## Notes
|
|
47
|
+
|
|
48
|
+
- The `attic/` directory is gitignored—cloned repos won’t pollute your project
|
|
49
|
+
- You can clone multiple repos into attic/ as needed
|
|
50
|
+
- Delete cloned repos when done to save disk space
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Clean Up All Code
|
|
3
3
|
description: Full cleanup cycle including duplicate removal, dead code, and code quality improvements
|
|
4
|
+
category: cleanup
|
|
4
5
|
author: Joshua Levy (github.com/jlevy) with LLM assistance
|
|
5
6
|
---
|
|
6
7
|
# Shortcut: Clean Up Code
|
|
@@ -52,9 +53,9 @@ cycle afterwords, fixing all build or test issues.
|
|
|
52
53
|
- Review types and eliminate use of optional types as possible so we don’t spread
|
|
53
54
|
state checks throughout the codebase.
|
|
54
55
|
|
|
55
|
-
7. **Remove trivial tests**: Follow `tbd shortcut cleanup-
|
|
56
|
+
7. **Remove trivial tests**: Follow `tbd shortcut code-cleanup-tests`.
|
|
56
57
|
|
|
57
|
-
8. **Update docstrings**: Follow `tbd shortcut cleanup-
|
|
58
|
+
8. **Update docstrings**: Follow `tbd shortcut code-cleanup-docstrings`.
|
|
58
59
|
|
|
59
60
|
9. **Consolidate constants and settings**: Determine what files hold shared settings
|
|
60
61
|
(such as `settings.ts` or similar).
|