@warren-dean/code-kit 0.8.1 → 0.9.1
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +29 -0
- package/README.md +63 -37
- package/bin/code-kit.mjs +278 -4
- package/hooks/guard-bash.mjs +64 -0
- package/hooks/guard-paths.mjs +19 -0
- package/hooks/lib/adapters/context-graph.mjs +5 -0
- package/hooks/lib/adapters/index.mjs +12 -0
- package/hooks/lib/config.mjs +15 -1
- package/hooks/lib/next.mjs +75 -3
- package/hooks/lib/plan.mjs +3 -1
- package/hooks/lib/storymap.mjs +62 -0
- package/hooks/lib/team.mjs +943 -0
- package/hooks/lib/teamfacts.mjs +187 -0
- package/hooks/mod/codemap.mjs +16 -1
- package/hooks/mod/decisions.mjs +24 -1
- package/hooks/mod/loop.mjs +20 -4
- package/hooks/mod/panes.mjs +99 -50
- package/hooks/mod/register.mjs +70 -1
- package/hooks/mod/register.test.ts +231 -2
- package/hooks/mod/teamview.mjs +243 -0
- package/hooks/mod/view.mjs +5 -1
- package/package.json +1 -1
- package/skills/design/SKILL.md +56 -0
- package/skills/dispatch/SKILL.md +9 -1
- package/skills/init/SKILL.md +19 -6
- package/skills/next/SKILL.md +3 -0
- package/skills/review/SKILL.md +1 -0
- package/skills/spec-design/SKILL.md +9 -3
- package/templates/plan.md +1 -1
package/hooks/lib/plan.mjs
CHANGED
|
@@ -14,6 +14,8 @@ const STORY_HEADING = /^###\s+(ST-\d+)\b\s*(.*)$/;
|
|
|
14
14
|
const REQUIREMENT_HEADING = /^###\s+((?!ST-)[A-Z][A-Z0-9]*-\d+)\b\s*(.*)$/;
|
|
15
15
|
export const STATES = ['todo', 'in progress', 'review', 'done'];
|
|
16
16
|
export const LEAD = 'lead';
|
|
17
|
+
/** ONB-2: the pseudo-lane for design stories, which the lead designs with the person before any screen is built. */
|
|
18
|
+
export const DESIGN = 'design';
|
|
17
19
|
// Test files, by the usual conventions. Tests name the requirement IDs they prove.
|
|
18
20
|
const TEST =
|
|
19
21
|
/(^|\/)(tests?|__tests__|e2e)\/|\.(test|spec)\.[^/]+$|_test\.(go|py)$|(^|\/)test_[^/]+\.py$/;
|
|
@@ -185,7 +187,7 @@ export function traceProblems(requirements, stories, lanes) {
|
|
|
185
187
|
if (storyIds.has(s.id)) problems.push(`${s.id} is in the plan more than once`);
|
|
186
188
|
storyIds.add(s.id);
|
|
187
189
|
if (!s.lane) problems.push(`${s.id} has no **Lane:**`);
|
|
188
|
-
else if (s.lane !== LEAD && !lanes.includes(s.lane))
|
|
190
|
+
else if (s.lane !== LEAD && s.lane !== DESIGN && !lanes.includes(s.lane))
|
|
189
191
|
problems.push(`${s.id} names an unknown lane "${s.lane}"`);
|
|
190
192
|
if (!s.requirements.length && !s.noRequirements)
|
|
191
193
|
problems.push(`${s.id} cites no requirements (write "none" if it delivers none)`);
|
package/hooks/lib/storymap.mjs
CHANGED
|
@@ -153,3 +153,65 @@ export function trail(root, status, from) {
|
|
|
153
153
|
};
|
|
154
154
|
});
|
|
155
155
|
}
|
|
156
|
+
|
|
157
|
+
/** The code map of no story in particular: the whole project. */
|
|
158
|
+
export const PROJECT = 'project';
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* MAP-5: the whole project's code, for when no story is at work: its folders (`depth` deep, shallower
|
|
162
|
+
* when that makes more than `most`) by the layer most of their files sit in, with the imports between
|
|
163
|
+
* folders. The same shape as a story's map, each node a folder with its file count.
|
|
164
|
+
*/
|
|
165
|
+
export function projectMap(root, config, tracked, { depth = 3, most = 60 } = {}) {
|
|
166
|
+
const code = tracked.filter(isCode);
|
|
167
|
+
const set = new Set(code);
|
|
168
|
+
const aliases = config.importAliases ?? {};
|
|
169
|
+
const folderAt = (d) => (rel) => {
|
|
170
|
+
const parts = rel.split('/');
|
|
171
|
+
return parts.length === 1 ? '.' : parts.slice(0, Math.min(d, parts.length - 1)).join('/');
|
|
172
|
+
};
|
|
173
|
+
let d = depth;
|
|
174
|
+
while (d > 1 && new Set(code.map(folderAt(d))).size > most) d -= 1;
|
|
175
|
+
const folderOf = folderAt(d);
|
|
176
|
+
const nodes = new Map();
|
|
177
|
+
for (const rel of code) {
|
|
178
|
+
const path = folderOf(rel);
|
|
179
|
+
const node = nodes.get(path) ?? {
|
|
180
|
+
path,
|
|
181
|
+
lane: laneOfFile(rel, config),
|
|
182
|
+
layers: new Map(),
|
|
183
|
+
imports: new Set(),
|
|
184
|
+
files: 0,
|
|
185
|
+
};
|
|
186
|
+
nodes.set(path, node);
|
|
187
|
+
const layer = TEST.test(rel) ? 'tests' : (layerOf(rel, config.layers)?.name ?? 'other');
|
|
188
|
+
node.layers.set(layer, (node.layers.get(layer) ?? 0) + 1);
|
|
189
|
+
node.files += 1;
|
|
190
|
+
let source = '';
|
|
191
|
+
try {
|
|
192
|
+
source = readFileSync(join(root, rel), 'utf8');
|
|
193
|
+
} catch {
|
|
194
|
+
// unreadable: no imports
|
|
195
|
+
}
|
|
196
|
+
for (const spec of importsOf(source)) {
|
|
197
|
+
const target = resolveIn(spec, rel, aliases, set);
|
|
198
|
+
if (target && folderOf(target) !== path) node.imports.add(folderOf(target));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
const files = [...nodes.values()]
|
|
202
|
+
.map((n) => ({
|
|
203
|
+
path: n.path,
|
|
204
|
+
layer: [...n.layers.entries()].sort((a, b) => b[1] - a[1])[0][0],
|
|
205
|
+
lane: n.lane,
|
|
206
|
+
imports: [...n.imports].sort(),
|
|
207
|
+
files: n.files,
|
|
208
|
+
}))
|
|
209
|
+
.sort((a, b) => a.path.localeCompare(b.path));
|
|
210
|
+
const used = new Set(files.map((f) => f.layer));
|
|
211
|
+
const layers = [...config.layers.map((l) => l.name), 'tests', 'other'].filter((l) => used.has(l));
|
|
212
|
+
return {
|
|
213
|
+
story: { id: PROJECT, title: 'The whole project', lane: null, state: null },
|
|
214
|
+
layers,
|
|
215
|
+
files,
|
|
216
|
+
};
|
|
217
|
+
}
|