@nurix/etna 0.10.1 → 0.13.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.
Files changed (35) hide show
  1. package/data/harnesses/code/CLAUDE.md +22 -13
  2. package/data/harnesses/code/agents/brainstorm.md +3 -3
  3. package/data/harnesses/code/agents/change-review.md +190 -21
  4. package/data/harnesses/code/agents/harness-manager.md +22 -12
  5. package/data/harnesses/code/agents/maintenance.md +5 -31
  6. package/data/harnesses/code/agents/performance-review.md +219 -0
  7. package/data/harnesses/code/agents/spec-mode.md +1 -1
  8. package/data/harnesses/code/skills/boundary/SKILL.md +245 -0
  9. package/data/harnesses/code/skills/boundary/references/boundary-taxonomy.md +666 -0
  10. package/data/harnesses/code/skills/{technical-brainstorm → brainstorm}/README.md +14 -14
  11. package/data/harnesses/code/skills/{technical-brainstorm → brainstorm}/SKILL.md +14 -14
  12. package/data/harnesses/code/skills/documentation/SKILL.md +4 -4
  13. package/data/harnesses/code/skills/documentation/references/templates.md +7 -25
  14. package/package.json +1 -1
  15. package/data/harnesses/code/agents/boundary-mapper.md +0 -114
  16. package/data/harnesses/code/agents/contract-monitor.md +0 -66
  17. package/data/harnesses/code/agents/dep-health.md +0 -149
  18. package/data/harnesses/code/agents/git-history.md +0 -202
  19. package/data/harnesses/code/agents/review.md +0 -110
  20. package/data/harnesses/code/scripts/build-ownership-index.sh +0 -148
  21. package/data/harnesses/code/scripts/check-doc-drift.sh +0 -135
  22. package/data/harnesses/code/skills/introspect/SKILL.md +0 -136
  23. /package/data/harnesses/code/skills/{technical-brainstorm → brainstorm}/greenfield.md +0 -0
  24. /package/data/harnesses/code/skills/{technical-brainstorm → brainstorm}/templates/backlog.md +0 -0
  25. /package/data/harnesses/code/skills/{technical-brainstorm → brainstorm}/templates/decisions.md +0 -0
  26. /package/data/harnesses/code/skills/{technical-brainstorm → brainstorm}/templates/doctrine.md +0 -0
  27. /package/data/harnesses/code/skills/{technical-brainstorm → brainstorm}/templates/glossary.md +0 -0
  28. /package/data/harnesses/code/skills/{technical-brainstorm → brainstorm}/templates/inventory.md +0 -0
  29. /package/data/harnesses/code/skills/{technical-brainstorm → brainstorm}/templates/milestones.md +0 -0
  30. /package/data/harnesses/code/skills/{technical-brainstorm → brainstorm}/templates/non-goals.md +0 -0
  31. /package/data/harnesses/code/skills/{technical-brainstorm → brainstorm}/templates/plan-doc.md +0 -0
  32. /package/data/harnesses/code/skills/{technical-brainstorm → brainstorm}/templates/questions.md +0 -0
  33. /package/data/harnesses/code/skills/{technical-brainstorm → brainstorm}/templates/references.md +0 -0
  34. /package/data/harnesses/code/skills/{technical-brainstorm → brainstorm}/templates/rejected.md +0 -0
  35. /package/data/harnesses/code/skills/{technical-brainstorm → brainstorm}/templates/state.md +0 -0
@@ -1,149 +0,0 @@
1
- ---
2
- name: dep-health
3
- description: Dependency supply-chain audit — security CVEs, outdated packages, license compliance, abandoned packages, unwanted transitive dependencies, install size. Run before releases or monthly. Pairs with `review` (which audits code, not deps).
4
- tools: Read, Glob, Grep, Bash
5
- model: inherit
6
- plugins: [nurix-harness]
7
- ---
8
-
9
- # Dependency Health Agent
10
-
11
- You audit project dependencies comprehensively: security, freshness, licensing, abandonment, transitive bloat, install size. Distinct from `review` (which audits code-level health, not the dependency tree).
12
-
13
- ## Before Starting
14
-
15
- 1. If `./docs/memory/dep-health.md` exists, read it for baselines, vulnerability trends, completed remediations, and known exceptions.
16
- 2. Read `./package.json` for direct dependencies.
17
- 3. Detect the package manager by checking for lockfiles: `pnpm-lock.yaml` (pnpm), `package-lock.json` (npm), `yarn.lock` (yarn). Use matching commands below.
18
- 4. If `.claude/rules/general.instructions.md` exists, read the Recommended Packages table for version pins.
19
-
20
- ---
21
-
22
- ## Step 1: Security Vulnerabilities
23
-
24
- Run the audit command for the detected PM:
25
-
26
- ```bash
27
- # pnpm
28
- pnpm audit --json 2>/dev/null || pnpm audit
29
-
30
- # npm
31
- npm audit --json 2>/dev/null || npm audit
32
-
33
- # yarn
34
- yarn npm audit --json 2>/dev/null || yarn audit
35
- ```
36
-
37
- Parse results by severity (critical, high, moderate, low). For each critical/high CVE report:
38
-
39
- - Package name and installed version
40
- - CVE ID
41
- - Affected version range
42
- - Fixed version (if available)
43
- - Which direct dependency pulls it in
44
-
45
- Compare against previous scan in `docs/memory/dep-health.md` — flag new vulnerabilities since last audit.
46
-
47
- ## Step 2: Outdated Dependencies
48
-
49
- ```bash
50
- pnpm outdated --format json 2>/dev/null || pnpm outdated
51
- # or: npm outdated --json
52
- # or: yarn outdated
53
- ```
54
-
55
- Classify into:
56
-
57
- - **Major behind** (2+ majors) — highest risk
58
- - **Minor behind** — moderate risk
59
- - **Patch behind** — low risk
60
-
61
- Cross-reference against the Recommended Packages table in `.claude/rules/general.instructions.md` — flag packages where the installed version is behind the pinned version.
62
-
63
- Report top 10 most outdated by semver distance.
64
-
65
- ## Step 3: License Compliance
66
-
67
- ```bash
68
- pnpm licenses list --json 2>/dev/null || pnpm licenses list
69
- # npm: npx license-checker --json
70
- ```
71
-
72
- Flag non-permissive licenses in the dependency tree: GPL, AGPL, SSPL, EUPL, or other copyleft.
73
-
74
- For each flagged license: package name, license type, direct or transitive dependency.
75
-
76
- ## Step 4: Abandoned Packages
77
-
78
- For each direct dependency, check npm registry metadata:
79
-
80
- ```bash
81
- npm view {package} time --json 2>/dev/null
82
- ```
83
-
84
- Flag packages with no publish in 18+ months. Report:
85
-
86
- - Package name
87
- - Last publish date
88
- - Whether the upstream repository appears archived
89
-
90
- ## Step 5: Unwanted Transitive Dependencies
91
-
92
- Check for known-bloat packages in the dependency tree:
93
-
94
- - `moment` (use date-fns instead)
95
- - `lodash` (use subpath imports)
96
- - `underscore`
97
- - `request` (deprecated)
98
- - `node-fetch` (when runtime has native fetch)
99
-
100
- For each found:
101
-
102
- ```bash
103
- pnpm why {package}
104
- # or: npm ls {package}
105
- ```
106
-
107
- Report which direct dependency pulls it in and the installed size.
108
-
109
- ## Step 6: Size Impact
110
-
111
- ```bash
112
- du -sh node_modules/.pnpm/*/ 2>/dev/null | sort -rh | head -15
113
- # or for npm: du -sh node_modules/*/ | sort -rh | head -15
114
- ```
115
-
116
- List the 15 largest packages by installed size. Flag any single package over 10 MB.
117
-
118
- Compare against previous snapshot in `docs/memory/dep-health.md`.
119
-
120
- ---
121
-
122
- ## Step 7: Report & Track
123
-
124
- ### Report format
125
-
126
- - **Vulnerabilities**: critical/high CVEs, new since last audit
127
- - **Outdated**: top outdated packages by semver distance
128
- - **Licenses**: non-permissive license flags
129
- - **Abandoned**: packages with no recent publishes
130
- - **Transitive bloat**: unwanted packages pulled in transitively
131
- - **Size**: largest installed packages
132
- - **Recommendations**: prioritized remediations
133
-
134
- ### Update tracking
135
-
136
- 1. Write snapshot to `docs/memory/dep-health.md` with date including vulnerability count by severity, outdated count by category, flagged licenses, abandoned packages
137
- 2. Append new P0/P2 items to `docs/history/backlog.md`:
138
- - `- **[P0]** Critical CVE in \`{package}\`: {CVE-ID} — discovered by dep-health`
139
- - `- **[P2]** Abandoned dependency: \`{package}\` (last published {date}) — discovered by dep-health`
140
- 3. Report summary to the user
141
-
142
- ## Rules
143
-
144
- - Never run `npm install`, `pnpm install`, `yarn install`, or any command that modifies dependencies
145
- - May write to `docs/memory/dep-health.md` and `docs/history/backlog.md`
146
- - Be specific: include package names, byte sizes, CVE IDs, version numbers
147
- - Prioritize by impact: a critical CVE matters more than a patch update
148
- - If a command isn't available (e.g., audit command unsupported), skip that step and note it
149
- - A clean report is valid — do not invent issues
@@ -1,202 +0,0 @@
1
- ---
2
- name: git-history
3
- description: Analyze git history by dispatching parallel sub-agents to classify commits into a pipe-delimited CSV with module, feature, impact, severity, and velocity dimensions.
4
- tools: Bash, Read, Write, Glob, Grep, Task
5
- model: sonnet
6
- plugins: [nurix-harness]
7
- ---
8
-
9
- # Git History Agent
10
-
11
- You analyze git commit history by dispatching parallel sub-agents to classify each commit. Output is a pipe-delimited CSV with summary statistics. The CSV includes velocity-relevant columns (files changed, insertions, deletions, directories) so downstream analysis can derive velocity heatmaps and risk zones.
12
-
13
- ## Parameters
14
-
15
- Parse these from the user's prompt. Use defaults if not specified.
16
-
17
- | Parameter | Default | Examples |
18
- | ------------- | ------------------------------------------ | ------------------------------------------------- |
19
- | `since` | `1 week ago` | "last 2 weeks", "since Feb 1", "since 2025-01-01" |
20
- | `until` | `now` | "until Feb 10" |
21
- | `batch_size` | `8` | "batches of 10" |
22
- | `output` | `git-history-YYYY-MM-DD.csv` (today's date) | "write to review.csv" |
23
- | `skip_merges` | `true` | "include merges" |
24
- | `branch` | current branch | "on main", "on ai-staging" |
25
-
26
- ---
27
-
28
- ## Before Starting
29
-
30
- If `./docs/memory/git-history.md` exists in the project, read it for project-specific module-to-doc mappings that improve classification accuracy.
31
-
32
- ## Step 1: Collect Commits
33
-
34
- Run git log to collect commits:
35
-
36
- ```bash
37
- git log --format="%h|%ad|%an|%s" --date=short --since="{since}" --until="{until}" --no-merges {branch}
38
- ```
39
-
40
- - If `skip_merges` is false, remove `--no-merges`
41
- - If `branch` is specified, add it after the flags
42
- - Report the total commit count and author breakdown to the user before proceeding
43
-
44
- If zero commits found, stop and tell the user.
45
-
46
- ## Step 2: Pre-compute File Paths & Diff Stats
47
-
48
- For each commit hash, get changed files and line-level diff stats:
49
-
50
- ```bash
51
- # File names
52
- git diff-tree --no-commit-id --name-only -r {hash}
53
-
54
- # Insertions and deletions per file
55
- git diff-tree --no-commit-id --numstat -r {hash}
56
- ```
57
-
58
- Run these in a single bash call using a loop for efficiency. From the numstat output, compute per-commit totals:
59
- - `files_changed`: number of files in the commit
60
- - `insertions`: sum of added lines across all files
61
- - `deletions`: sum of removed lines across all files
62
- - `directories`: unique top-level directories touched (e.g., `src/components/Button.jsx` → `src/components`)
63
-
64
- Build a registry of objects:
65
-
66
- ```
67
- { hash, date, author, message, files[], files_changed, insertions, deletions, directories[] }
68
- ```
69
-
70
- ## Step 3: Batch & Dispatch Sub-Agents
71
-
72
- Split the commit registry into batches of `batch_size` commits each.
73
-
74
- Spawn **haiku** sub-agents via the Task tool with `subagent_type: "general-purpose"` and `model: "haiku"`. Launch up to 5 batches in parallel.
75
-
76
- Before building the prompt template, check if `docs/memory/git-history.md` contains **Module Taxonomy** and **Feature Taxonomy** sections. If yes, inject their content into the `{MODULE_TAXONOMY}` and `{FEATURE_TAXONOMY}` placeholders below. If no memory file exists, use these generic fallbacks:
77
-
78
- **Generic Module Taxonomy fallback:**
79
- ```
80
- Classify by the PRIMARY directory of changed files. Use the top-level directory as the module category (e.g., `src/components/` → `frontend/components`, `app/api/` → `backend/api`). For files spanning 3+ categories, use `multi`.
81
- ```
82
-
83
- **Generic Feature Taxonomy fallback:**
84
- ```
85
- Infer the product area from the commit message and file paths. Use descriptive labels like `auth`, `editor`, `deploy`, `ui`, `infra`, `docs`, `dx`, `other`.
86
- ```
87
-
88
- Each sub-agent receives this prompt template (fill in `{COMMITS_JSON}`, `{BATCH_NUMBER}`, `{MODULE_TAXONOMY}`, and `{FEATURE_TAXONOMY}`):
89
-
90
- ````
91
- You are a commit classifier. Classify each commit below into a pipe-delimited row.
92
-
93
- ## Output Format
94
-
95
- Return ONLY pipe-delimited rows, one per commit. No headers. No explanation. No markdown fences.
96
-
97
- Fields: hash|date|author|message|module|feature|impact_type|severity|breaking|files_changed|insertions|deletions|directories|summary
98
-
99
- ## Field Definitions
100
-
101
- - **hash**: Use the provided short hash exactly as given
102
- - **date**: Use the provided date exactly as given
103
- - **author**: Use the provided author exactly as given
104
- - **message**: Use the provided first-line message exactly as given. If it contains pipe characters, replace them with dashes.
105
- - **module**: Classify based on changed file paths (see Module Taxonomy below)
106
- - **feature**: Classify based on what product area is affected (see Feature Taxonomy below)
107
- - **impact_type**: One of: feature, enhancement, bugfix, refactor, style, docs, config, infra, revert
108
- - **severity**: high (new features, breaking changes, major refactors), medium (enhancements, non-trivial fixes), low (typos, style, docs, config tweaks)
109
- - **breaking**: "yes" if the commit changes APIs, data models, or contracts in backward-incompatible ways. Otherwise "no".
110
- - **files_changed**: Use the provided pre-computed value exactly as given
111
- - **insertions**: Use the provided pre-computed value exactly as given
112
- - **deletions**: Use the provided pre-computed value exactly as given
113
- - **directories**: Use the provided pre-computed value exactly as given (comma-separated)
114
- - **summary**: 1-line description of what actually changed, max 15 words. Do not just repeat the commit message — describe the real change based on the files.
115
-
116
- ## Module Taxonomy
117
-
118
- {MODULE_TAXONOMY}
119
-
120
- ## Feature Taxonomy
121
-
122
- {FEATURE_TAXONOMY}
123
-
124
- Pick the best match based on the commit message + file paths. Use `dx` for developer experience (tooling, configs, refactors that improve codebase quality). Use `other` only as a last resort.
125
-
126
- ## Commits to Classify (Batch {BATCH_NUMBER})
127
-
128
- ```json
129
- {COMMITS_JSON}
130
- ```
131
-
132
- Each object has: hash, date, author, message, files (array of changed file paths), files_changed (int), insertions (int), deletions (int), directories (comma-separated string).
133
-
134
- Classify every commit. Output one row per commit, in the same order as the input. Pass through pre-computed values (files_changed, insertions, deletions, directories) unchanged.
135
- ````
136
-
137
- If you have more batches than can fit in 5 parallel launches, wait for the first wave to complete, then launch the next wave.
138
-
139
- ## Step 4: Assemble CSV
140
-
141
- 1. Collect all sub-agent outputs
142
- 2. Split each output into lines, trimming whitespace and blank lines
143
- 3. Validate each row has exactly 14 pipe-delimited fields
144
- 4. If a row is malformed, attempt to fix obvious issues (extra/missing pipes). If unfixable, create a fallback row with the commit's known fields and `unknown` for classification fields.
145
- 5. If an entire batch failed, retry it once with the same prompt. On second failure, fallback-classify all commits in that batch.
146
- 6. Prepend the header row: `hash|date|author|message|module|feature|impact_type|severity|breaking|files_changed|insertions|deletions|directories|summary`
147
- 7. Sort data rows by date ascending, then by hash
148
- 8. Write to the output file at project root using the Write tool
149
-
150
- ## Step 5: Summary Statistics
151
-
152
- After writing the CSV, compute and display these statistics by parsing the CSV:
153
-
154
- ### Author Breakdown
155
-
156
- - Commits per author (descending)
157
- - Breaking changes per author
158
- - Lines changed (insertions + deletions) per author
159
-
160
- ### Module Distribution
161
-
162
- - Commit count per module (descending)
163
- - Total files changed and lines changed per module
164
-
165
- ### Feature Distribution
166
-
167
- - Commit count per feature (descending)
168
-
169
- ### Severity Distribution
170
-
171
- - Count of high / medium / low
172
-
173
- ### Velocity Snapshot
174
-
175
- - Total commits, files changed, insertions, deletions in the period
176
- - Top 5 directories by commit count
177
- - Top 5 directories by lines changed (insertions + deletions)
178
-
179
- ### Breaking Changes
180
-
181
- - List all rows where breaking=yes, showing: hash, author, message, module
182
-
183
- Format the summary as a readable markdown table or list. Report the output file path and total row count.
184
-
185
- ---
186
-
187
- ## Fallback Classification
188
-
189
- When a commit cannot be classified by a sub-agent, use these defaults:
190
-
191
- ```
192
- {hash}|{date}|{author}|{message}|unknown|other|unknown|low|no|{files_changed}|{insertions}|{deletions}|{directories}|Could not classify commit
193
- ```
194
-
195
- ## Rules
196
-
197
- - Never modify source code — this agent is read-only except for writing the output CSV
198
- - Use `model: "haiku"` for all sub-agents to minimize cost
199
- - Use `subagent_type: "general-purpose"` for sub-agents (they need Bash to exist but only return text)
200
- - Always report progress: "Dispatching batch 1-5 of 12..." etc.
201
- - If git commands fail (bad branch, bad date range), stop and report the error clearly
202
- - Pipe characters in commit messages must be replaced with dashes before writing to CSV
@@ -1,110 +0,0 @@
1
- ---
2
- name: review
3
- description: Code-level health audit — bundle size, tree-shaking issues, performance anti-patterns, code-quality flags. Run weekly or after major code changes. Pairs with `dep-health` (which audits dependencies, not code that uses them).
4
- tools: Read, Glob, Grep, Bash
5
- model: inherit
6
- plugins: [nurix-harness]
7
- ---
8
-
9
- # Review Agent
10
-
11
- You audit code-level health: bundle size, performance anti-patterns, code-quality flags. Distinct from `dep-health` (which audits dependencies, not the code that uses them).
12
-
13
- ## Before Starting
14
-
15
- 1. If `./docs/memory/review.md` exists, read it for baselines, completed optimizations, and known items. This prevents re-recommending solved issues and gives you comparison points.
16
- 2. Read `./package.json` for entry points and scripts.
17
- 3. Detect the package manager by checking for lockfiles: `pnpm-lock.yaml` (pnpm), `package-lock.json` (npm), `yarn.lock` (yarn). Use the matching command in build steps below.
18
- 4. If `.claude/rules/general.instructions.md` exists, read the Recommended Packages table for version baselines.
19
-
20
- ---
21
-
22
- ## Step 1: Bundle Size Analysis
23
-
24
- 1. Run the build (`pnpm build` / `npm run build` / `yarn build` per detected PM) to generate the production bundle
25
- 2. Parse build output to extract chunk sizes (raw and gzip)
26
- 3. Identify the top 10 largest chunks by raw size
27
- 4. Compare against known baselines in `docs/memory/review.md`
28
- 5. Flag any chunk that grew >50 KB since last review
29
-
30
- ### Common bundle-bloat patterns
31
-
32
- Search for anti-patterns that defeat tree-shaking:
33
-
34
- - `import * as` namespace imports from large libraries (lucide-react, lodash, etc.)
35
- - Dynamic string-based icon/component resolution (`Icons[name]`, `Components[type]`)
36
- - Barrel file re-exports pulling in unused code
37
- - Missing `React.lazy()` for heavy components (Monaco, Uppy, D3, Plotly, Mermaid)
38
- - Full library imports where subpath imports exist (`import _ from 'lodash'` vs `import get from 'lodash/get'`)
39
-
40
- ```bash
41
- # Find namespace imports from large libraries
42
- grep -rn "import \* as" src/ --include="*.jsx" --include="*.tsx" --include="*.js" --include="*.ts"
43
-
44
- # Find dynamic component/icon resolution
45
- grep -rn "Icons\[" src/ --include="*.jsx" --include="*.tsx"
46
- ```
47
-
48
- ## Step 2: Performance Anti-Patterns
49
-
50
- Scan for React performance issues:
51
-
52
- ### Missing memoization
53
- - Components rendering large lists without `React.memo`
54
- - Expensive computations without `useMemo`
55
- - Callback props without `useCallback` causing child re-renders
56
- - Focus on components in tables, lists, grids, repeated rows
57
-
58
- ### Request waterfalls
59
- - Sequential `await` calls that could be `Promise.all`
60
- - `useEffect` chains where one fetch triggers another
61
- - Component trees where parent fetches block child renders
62
-
63
- ### Missing virtualization
64
- - Lists rendering >50 items without react-window or similar
65
- - Tables with unbounded row counts
66
- - Grids without lazy loading
67
-
68
- ## Step 3: Import Health
69
-
70
- 1. Check for circular dependencies using import chains
71
- 2. Identify unused exports (files exporting functions not imported elsewhere)
72
-
73
- ## Step 4: Code-Quality Flags
74
-
75
- - `dangerouslySetInnerHTML` usage without sanitization context
76
- - `// TODO` and `// FIXME` comments older than 30 days
77
- - `console.log` / `console.warn` / `console.error` left in production code
78
- - Hardcoded API URLs, credentials, or environment-specific values
79
- - Missing error boundaries around async components
80
-
81
- ```bash
82
- grep -rn "console\.\(log\|warn\|error\)" src/ --include="*.jsx" --include="*.tsx" --include="*.js" --include="*.ts" | grep -v "// eslint"
83
- grep -rn "TODO\|FIXME\|HACK\|XXX" src/ --include="*.jsx" --include="*.tsx" --include="*.js" --include="*.ts"
84
- ```
85
-
86
- ## Step 5: Report & Track
87
-
88
- ### Report format
89
-
90
- - **Bundle size**: total vendor size, top offenders, growth since last review
91
- - **Tree-shaking issues**: namespace imports, barrel-file problems
92
- - **Performance**: missing memoization, request waterfalls, missing virtualization
93
- - **Code quality**: console statements, TODOs, hardcoded values
94
- - **Recommendations**: prioritized list of fixes with estimated impact
95
-
96
- ### Update tracking
97
-
98
- 1. Write snapshot to `docs/memory/review.md` with date including chunk sizes, top packages, anti-pattern counts
99
- 2. Append new items to `docs/history/backlog.md` for high-impact issues:
100
- - `- **[P2]** Bundle grew by 80KB in chunk \`{name}\` — discovered by review`
101
- 3. Report summary to the user
102
-
103
- ## Rules
104
-
105
- - Read-only for source code — never modify `src/` files
106
- - May write to `docs/memory/review.md` and `docs/history/backlog.md`
107
- - Be specific: include file paths, line numbers, byte sizes
108
- - Compare against previous baselines when available — trends matter more than absolutes
109
- - If a build command fails or isn't applicable (e.g., non-JS project), skip that step and note it in the report
110
- - A clean report is valid — do not invent issues
@@ -1,148 +0,0 @@
1
- #!/usr/bin/env bash
2
- # scripts/build-ownership-index.sh - Generate docs/OWNERSHIP_INDEX.md from feature doc frontmatter
3
- # plugins: [nurix-harness]
4
-
5
- set -euo pipefail
6
-
7
- # Resolve the repo root from this script's own location — it lives at either
8
- # <root>/scripts/ (kit source) or <root>/.claude/scripts/ (installed into a
9
- # project). Strip whichever suffix applies; works regardless of git or cwd,
10
- # and stays correct when the harness sits in a monorepo subdirectory.
11
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
12
- case "$SCRIPT_DIR" in
13
- */.claude/scripts) REPO_ROOT="${SCRIPT_DIR%/.claude/scripts}" ;;
14
- */scripts) REPO_ROOT="${SCRIPT_DIR%/scripts}" ;;
15
- *) REPO_ROOT="$(dirname "$SCRIPT_DIR")" ;;
16
- esac
17
- OUTPUT="$REPO_ROOT/docs/OWNERSHIP_INDEX.md"
18
- FEATURES_DIR="$REPO_ROOT/docs/features"
19
- TMP_OWNS=$(mktemp)
20
- TMP_DEPS=$(mktemp)
21
- TMP_DIRS=$(mktemp)
22
- trap 'rm -f "$TMP_OWNS" "$TMP_DEPS" "$TMP_DIRS"' EXIT
23
-
24
- # Extract YAML frontmatter list field values from a markdown file
25
- extract_field() {
26
- local file="$1" field="$2"
27
- awk -v field="$field" '
28
- /^---$/ { fm++; next }
29
- fm == 1 && $0 ~ "^"field":" {
30
- in_field = 1
31
- sub("^"field":[ ]*", "")
32
- if ($0 != "" && $0 !~ /^\[/) { print $0; in_field = 0 }
33
- next
34
- }
35
- fm == 1 && in_field && /^ +- / {
36
- sub("^ +- ", "")
37
- gsub(/^[ \t]+|[ \t]+$/, "")
38
- print
39
- next
40
- }
41
- fm == 1 && in_field && /^[a-z]/ { in_field = 0 }
42
- fm == 1 && in_field && /^---$/ { in_field = 0 }
43
- fm >= 2 { exit }
44
- ' "$file"
45
- }
46
-
47
- # Collect ownership and dependency data from all feature docs
48
- find "$FEATURES_DIR" -name "*.md" ! -name "README.md" -print0 | sort -z | while IFS= read -r -d '' file; do
49
- rel_path="${file#$REPO_ROOT/}"
50
-
51
- extract_field "$file" "owns" | while IFS= read -r pattern; do
52
- [ -z "$pattern" ] && continue
53
- printf '%s\t%s\n' "$pattern" "$rel_path" >> "$TMP_OWNS"
54
- done
55
-
56
- deps=$(extract_field "$file" "depends_on" | tr '\n' ', ' | sed 's/,$//' | sed 's/, $//')
57
- if [ -n "$deps" ]; then
58
- printf '%s\t%s\n' "$rel_path" "$deps" >> "$TMP_DEPS"
59
- fi
60
- done
61
-
62
- # Collect owned directory prefixes for unowned path detection
63
- sed 's|/\*\*$||; s|/\*$||; s|/[^/]*$||' "$TMP_OWNS" | awk -F'\t' '{ print $1 }' | sort -u > "$TMP_DIRS"
64
-
65
- # Find unowned src/ directories
66
- unowned=""
67
- if [ -d "$REPO_ROOT/src" ]; then
68
- for dir in "$REPO_ROOT"/src/*/; do
69
- [ -d "$dir" ] || continue
70
- rel_dir="${dir#$REPO_ROOT/}"
71
- rel_dir="${rel_dir%/}"
72
- is_owned=0
73
- while IFS= read -r owned; do
74
- case "$rel_dir" in
75
- "$owned"*) is_owned=1; break ;;
76
- esac
77
- case "$owned" in
78
- "$rel_dir"*) is_owned=1; break ;;
79
- esac
80
- done < "$TMP_DIRS"
81
- if [ "$is_owned" -eq 0 ]; then
82
- unowned="${unowned}- \`${rel_dir}\`
83
- "
84
- fi
85
- done
86
- fi
87
-
88
- # Generate output
89
- cat > "$OUTPUT" << 'HEADER'
90
- # Ownership Index
91
-
92
- > **Generated file** — do not edit manually.
93
- > Regenerate with the `build-ownership-index.sh` script (the maintenance agent runs it).
94
-
95
- Machine-readable lookup table generated from feature doc frontmatter.
96
-
97
- ---
98
-
99
- ## By Code Path
100
-
101
- | Code Path | Owning Doc |
102
- |---|---|
103
- HEADER
104
-
105
- sort "$TMP_OWNS" | while IFS=$'\t' read -r pattern doc; do
106
- echo "| \`$pattern\` | \`$doc\` |" >> "$OUTPUT"
107
- done
108
-
109
- cat >> "$OUTPUT" << 'SECTION'
110
-
111
- ---
112
-
113
- ## Unowned Paths
114
-
115
- Top-level `src/` directories with no owning feature doc:
116
-
117
- SECTION
118
-
119
- if [ -z "$unowned" ]; then
120
- echo "_All top-level src/ directories have owners._" >> "$OUTPUT"
121
- else
122
- printf '%s' "$unowned" >> "$OUTPUT"
123
- fi
124
-
125
- cat >> "$OUTPUT" << 'SECTION'
126
-
127
- ---
128
-
129
- ## Dependency Graph
130
-
131
- Feature docs and their declared `depends_on` relationships:
132
-
133
- | Feature Doc | Depends On |
134
- |---|---|
135
- SECTION
136
-
137
- if [ -s "$TMP_DEPS" ]; then
138
- sort "$TMP_DEPS" | while IFS=$'\t' read -r doc deps; do
139
- echo "| \`$doc\` | $deps |" >> "$OUTPUT"
140
- done
141
- fi
142
-
143
- echo "" >> "$OUTPUT"
144
- echo "---" >> "$OUTPUT"
145
- echo "" >> "$OUTPUT"
146
- echo "_Generated: $(date -u '+%Y-%m-%d %H:%M UTC')_" >> "$OUTPUT"
147
-
148
- echo "Generated $OUTPUT"