opencode-skills-collection 3.0.45 → 3.0.47
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/bundled-skills/.antigravity-install-manifest.json +10 -1
- package/bundled-skills/2slides-ppt-generator/SKILL.md +1 -1
- package/bundled-skills/2slides-ppt-generator/scripts/create_pdf_slides.py +2 -1
- package/bundled-skills/2slides-ppt-generator/scripts/generate_narration.py +2 -1
- package/bundled-skills/2slides-ppt-generator/scripts/generate_slides.py +13 -7
- package/bundled-skills/android-dev/references/hybrid.md +7 -4
- package/bundled-skills/android-dev/references/react-native.md +5 -2
- package/bundled-skills/atlas-contract/SKILL.md +4 -4
- package/bundled-skills/atlas-ledger/SKILL.md +10 -7
- package/bundled-skills/bun-development/SKILL.md +1 -1
- package/bundled-skills/cloud-penetration-testing/SKILL.md +1 -1
- package/bundled-skills/codebase-to-wordpress-converter/SKILL.md +1 -0
- package/bundled-skills/docs/integrations/jetski-cortex.md +3 -3
- package/bundled-skills/docs/integrations/jetski-gemini-loader/README.md +1 -1
- package/bundled-skills/docs/maintainers/repo-growth-seo.md +3 -3
- package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
- package/bundled-skills/docs/users/bundles.md +1 -1
- package/bundled-skills/docs/users/claude-code-skills.md +1 -1
- package/bundled-skills/docs/users/gemini-cli-skills.md +1 -1
- package/bundled-skills/docs/users/getting-started.md +1 -1
- package/bundled-skills/docs/users/kiro-integration.md +1 -1
- package/bundled-skills/docs/users/usage.md +4 -4
- package/bundled-skills/docs/users/visual-guide.md +4 -4
- package/bundled-skills/dos-verify-done-claims/SKILL.md +173 -0
- package/bundled-skills/ecl-harness-engineer/LICENSE +21 -0
- package/bundled-skills/ecl-harness-engineer/SKILL.md +714 -0
- package/bundled-skills/ecl-harness-engineer/agents/analyzer.md +119 -0
- package/bundled-skills/ecl-harness-engineer/agents/auditor.md +212 -0
- package/bundled-skills/ecl-harness-engineer/agents/creator-config.md +343 -0
- package/bundled-skills/ecl-harness-engineer/agents/creator-docs.md +201 -0
- package/bundled-skills/ecl-harness-engineer/agents/creator-linters.md +123 -0
- package/bundled-skills/ecl-harness-engineer/references/adapters/adapter-schema.md +204 -0
- package/bundled-skills/ecl-harness-engineer/references/adapters/generic.md +156 -0
- package/bundled-skills/ecl-harness-engineer/references/adapters/go.md +212 -0
- package/bundled-skills/ecl-harness-engineer/references/adapters/java.md +205 -0
- package/bundled-skills/ecl-harness-engineer/references/adapters/python.md +225 -0
- package/bundled-skills/ecl-harness-engineer/references/adapters/rust.md +220 -0
- package/bundled-skills/ecl-harness-engineer/references/adapters/typescript.md +245 -0
- package/bundled-skills/ecl-harness-engineer/references/architecture-diagrams.md +420 -0
- package/bundled-skills/ecl-harness-engineer/references/audit-templates.md +649 -0
- package/bundled-skills/ecl-harness-engineer/references/capability-registry.md +485 -0
- package/bundled-skills/ecl-harness-engineer/references/darwin-eval-prompts.md +373 -0
- package/bundled-skills/ecl-harness-engineer/references/documentation-templates.md +741 -0
- package/bundled-skills/ecl-harness-engineer/references/durability-patterns.md +423 -0
- package/bundled-skills/ecl-harness-engineer/references/ecl-harness.md +1431 -0
- package/bundled-skills/ecl-harness-engineer/references/environment-config-guide.md +534 -0
- package/bundled-skills/ecl-harness-engineer/references/environment-detection-guide.md +751 -0
- package/bundled-skills/ecl-harness-engineer/references/eval-templates.md +377 -0
- package/bundled-skills/ecl-harness-engineer/references/gc-templates.md +798 -0
- package/bundled-skills/ecl-harness-engineer/references/greenfield-templates.md +1385 -0
- package/bundled-skills/ecl-harness-engineer/references/linter-templates.md +448 -0
- package/bundled-skills/ecl-harness-engineer/references/observability-templates.md +315 -0
- package/bundled-skills/environment-setup-guide/SKILL.md +2 -2
- package/bundled-skills/evolution/SKILL.md +1 -1
- package/bundled-skills/gitops-workflow/SKILL.md +1 -1
- package/bundled-skills/linkerd-patterns/SKILL.md +1 -1
- package/bundled-skills/loki-mode/examples/todo-app-generated/frontend/package-lock.json +504 -1317
- package/bundled-skills/loki-mode/examples/todo-app-generated/frontend/package.json +2 -2
- package/bundled-skills/lovable-cleanup/SKILL.md +416 -0
- package/bundled-skills/monopoly/SKILL.md +397 -0
- package/bundled-skills/monopoly/patterns/SKILL.md +331 -0
- package/bundled-skills/monopoly/scale-benchmarks/SKILL.md +174 -0
- package/bundled-skills/monopoly/security-checklist/SKILL.md +69 -0
- package/bundled-skills/monopoly/tech-matrix/SKILL.md +268 -0
- package/bundled-skills/pagespeed-enhancer/SKILL.md +579 -0
- package/bundled-skills/polis-protocol/SKILL.md +6 -3
- package/bundled-skills/unship/SKILL.md +11 -5
- package/bundled-skills/uv-package-manager/resources/implementation-playbook.md +1 -1
- package/bundled-skills/varlock/SKILL.md +2 -2
- package/package.json +1 -1
- package/skills_index.json +204 -4
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
# Linter Templates
|
|
2
|
+
|
|
3
|
+
Go linter patterns for mechanical architecture enforcement.
|
|
4
|
+
|
|
5
|
+
## Dependency Direction Linter
|
|
6
|
+
|
|
7
|
+
Validates that package imports respect the layer hierarchy.
|
|
8
|
+
|
|
9
|
+
```go
|
|
10
|
+
// scripts/lint-deps.go
|
|
11
|
+
//
|
|
12
|
+
// Validates that package dependencies follow the layer hierarchy.
|
|
13
|
+
// Each layer can only import from lower layers.
|
|
14
|
+
//
|
|
15
|
+
// Usage: go run scripts/lint-deps.go
|
|
16
|
+
package main
|
|
17
|
+
|
|
18
|
+
import (
|
|
19
|
+
"fmt"
|
|
20
|
+
"go/parser"
|
|
21
|
+
"go/token"
|
|
22
|
+
"os"
|
|
23
|
+
"path/filepath"
|
|
24
|
+
"strings"
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
// CUSTOMIZE: Set your module path
|
|
28
|
+
const modulePath = "your-module-path"
|
|
29
|
+
|
|
30
|
+
// CUSTOMIZE: Define your layer hierarchy (lower index = lower layer)
|
|
31
|
+
var layers = [][]string{
|
|
32
|
+
// Layer 0: No internal dependencies
|
|
33
|
+
{"core/types"},
|
|
34
|
+
// Layer 1: Depends on Layer 0
|
|
35
|
+
{"core/utils"},
|
|
36
|
+
// Layer 2: Depends on Layers 0-1
|
|
37
|
+
{"core/config", "core/logging"},
|
|
38
|
+
// Layer 3: Depends on Layers 0-2
|
|
39
|
+
{"core/business"},
|
|
40
|
+
// Layer 4: Depends on core/ but NOT each other
|
|
41
|
+
{"ui", "sdk", "integrations"},
|
|
42
|
+
// Layer 5: Can depend on everything
|
|
43
|
+
{"cmd"},
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// CUSTOMIZE: Packages that must not import each other
|
|
47
|
+
var mutuallyExclusive = [][]string{
|
|
48
|
+
{"ui", "sdk", "integrations"},
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
type Violation struct {
|
|
52
|
+
File string
|
|
53
|
+
Package string
|
|
54
|
+
Imports string
|
|
55
|
+
Message string
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
func main() {
|
|
59
|
+
violations := checkDependencies()
|
|
60
|
+
|
|
61
|
+
if len(violations) == 0 {
|
|
62
|
+
fmt.Println("✓ All package dependencies follow the layer hierarchy")
|
|
63
|
+
os.Exit(0)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
fmt.Printf("✗ Found %d dependency violations:\n\n", len(violations))
|
|
67
|
+
for _, v := range violations {
|
|
68
|
+
fmt.Printf("%s:\n Package: %s\n Imports: %s\n Error: %s\n\n",
|
|
69
|
+
v.File, v.Package, v.Imports, v.Message)
|
|
70
|
+
}
|
|
71
|
+
os.Exit(1)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
func checkDependencies() []Violation {
|
|
75
|
+
var violations []Violation
|
|
76
|
+
layerMap := buildLayerMap()
|
|
77
|
+
|
|
78
|
+
filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
|
|
79
|
+
if err != nil || info.IsDir() {
|
|
80
|
+
if info != nil && info.IsDir() {
|
|
81
|
+
name := info.Name()
|
|
82
|
+
if strings.HasPrefix(name, ".") || name == "vendor" || name == "dist" {
|
|
83
|
+
return filepath.SkipDir
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return nil
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if !strings.HasSuffix(path, ".go") || strings.HasSuffix(path, "_test.go") {
|
|
90
|
+
return nil
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
violations = append(violations, checkFile(path, layerMap)...)
|
|
94
|
+
return nil
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
return violations
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
func buildLayerMap() map[string]int {
|
|
101
|
+
m := make(map[string]int)
|
|
102
|
+
for idx, pkgs := range layers {
|
|
103
|
+
for _, pkg := range pkgs {
|
|
104
|
+
m[pkg] = idx
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return m
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
func checkFile(path string, layerMap map[string]int) []Violation {
|
|
111
|
+
var violations []Violation
|
|
112
|
+
|
|
113
|
+
fset := token.NewFileSet()
|
|
114
|
+
node, err := parser.ParseFile(fset, path, nil, parser.ImportsOnly)
|
|
115
|
+
if err != nil {
|
|
116
|
+
return violations
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
dir := filepath.ToSlash(filepath.Dir(path))
|
|
120
|
+
dir = strings.TrimPrefix(dir, "./")
|
|
121
|
+
pkgLayer := findLayer(dir, layerMap)
|
|
122
|
+
if pkgLayer < 0 {
|
|
123
|
+
return violations
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
for _, imp := range node.Imports {
|
|
127
|
+
importPath := strings.Trim(imp.Path.Value, `"`)
|
|
128
|
+
if !strings.HasPrefix(importPath, modulePath) {
|
|
129
|
+
continue
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
relImport := strings.TrimPrefix(importPath, modulePath+"/")
|
|
133
|
+
importLayer := findLayer(relImport, layerMap)
|
|
134
|
+
if importLayer < 0 {
|
|
135
|
+
continue
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if importLayer >= pkgLayer {
|
|
139
|
+
// Check if same base package (allowed)
|
|
140
|
+
if getBase(dir) == getBase(relImport) {
|
|
141
|
+
continue
|
|
142
|
+
}
|
|
143
|
+
violations = append(violations, Violation{
|
|
144
|
+
File: path, Package: dir, Imports: relImport,
|
|
145
|
+
Message: fmt.Sprintf("Layer %d cannot import layer %d", pkgLayer, importLayer),
|
|
146
|
+
})
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return violations
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
func findLayer(pkg string, layerMap map[string]int) int {
|
|
154
|
+
if layer, ok := layerMap[pkg]; ok {
|
|
155
|
+
return layer
|
|
156
|
+
}
|
|
157
|
+
for key, layer := range layerMap {
|
|
158
|
+
if strings.HasPrefix(pkg, key+"/") {
|
|
159
|
+
return layer
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return -1
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
func getBase(pkg string) string {
|
|
166
|
+
parts := strings.SplitN(pkg, "/", 3)
|
|
167
|
+
if len(parts) >= 2 {
|
|
168
|
+
return parts[0] + "/" + parts[1]
|
|
169
|
+
}
|
|
170
|
+
return parts[0]
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Quality Linter
|
|
175
|
+
|
|
176
|
+
Validates golden principles like structured logging, file sizes, and naming.
|
|
177
|
+
|
|
178
|
+
```go
|
|
179
|
+
// scripts/lint-quality.go
|
|
180
|
+
//
|
|
181
|
+
// Validates golden principles:
|
|
182
|
+
// - No raw log.Printf (use structured logging)
|
|
183
|
+
// - File size limits (max 1000 lines)
|
|
184
|
+
// - No hardcoded brand strings
|
|
185
|
+
//
|
|
186
|
+
// Usage: go run scripts/lint-quality.go
|
|
187
|
+
package main
|
|
188
|
+
|
|
189
|
+
import (
|
|
190
|
+
"bufio"
|
|
191
|
+
"fmt"
|
|
192
|
+
"os"
|
|
193
|
+
"path/filepath"
|
|
194
|
+
"regexp"
|
|
195
|
+
"strings"
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
const maxFileLines = 1000
|
|
199
|
+
|
|
200
|
+
// CUSTOMIZE: Patterns to flag
|
|
201
|
+
var rawLogPatterns = []*regexp.Regexp{
|
|
202
|
+
regexp.MustCompile(`\blog\.Printf\b`),
|
|
203
|
+
regexp.MustCompile(`\blog\.Println\b`),
|
|
204
|
+
regexp.MustCompile(`\blog\.Fatalf\b`),
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// CUSTOMIZE: Directories to skip
|
|
208
|
+
var skipDirs = map[string]bool{
|
|
209
|
+
".git": true, "dist": true, "vendor": true,
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
type Violation struct {
|
|
213
|
+
File string
|
|
214
|
+
Line int
|
|
215
|
+
Rule string
|
|
216
|
+
Message string
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
func main() {
|
|
220
|
+
var violations []Violation
|
|
221
|
+
|
|
222
|
+
walkGoFiles(func(path string, content []byte) {
|
|
223
|
+
if strings.HasSuffix(path, "_test.go") {
|
|
224
|
+
return
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Check structured logging
|
|
228
|
+
lines := strings.Split(string(content), "\n")
|
|
229
|
+
for lineNum, line := range lines {
|
|
230
|
+
trimmed := strings.TrimSpace(line)
|
|
231
|
+
if strings.HasPrefix(trimmed, "//") {
|
|
232
|
+
continue
|
|
233
|
+
}
|
|
234
|
+
for _, pattern := range rawLogPatterns {
|
|
235
|
+
if pattern.MatchString(line) {
|
|
236
|
+
violations = append(violations, Violation{
|
|
237
|
+
File: path, Line: lineNum + 1,
|
|
238
|
+
Rule: "structured-logging",
|
|
239
|
+
Message: "Use structured logging instead of raw log calls",
|
|
240
|
+
})
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Check file size
|
|
246
|
+
scanner := bufio.NewScanner(strings.NewReader(string(content)))
|
|
247
|
+
lineCount := 0
|
|
248
|
+
for scanner.Scan() {
|
|
249
|
+
lineCount++
|
|
250
|
+
}
|
|
251
|
+
if lineCount > maxFileLines {
|
|
252
|
+
violations = append(violations, Violation{
|
|
253
|
+
File: path, Rule: "file-size",
|
|
254
|
+
Message: fmt.Sprintf("File has %d lines (max %d)", lineCount, maxFileLines),
|
|
255
|
+
})
|
|
256
|
+
}
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
if len(violations) == 0 {
|
|
260
|
+
fmt.Println("✓ All quality checks passed")
|
|
261
|
+
os.Exit(0)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
fmt.Printf("✗ Found %d quality violations:\n\n", len(violations))
|
|
265
|
+
for _, v := range violations {
|
|
266
|
+
fmt.Printf("%s:%d [%s]: %s\n", v.File, v.Line, v.Rule, v.Message)
|
|
267
|
+
}
|
|
268
|
+
os.Exit(1)
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
func walkGoFiles(fn func(path string, content []byte)) {
|
|
272
|
+
filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
|
|
273
|
+
if err != nil || info.IsDir() {
|
|
274
|
+
if info != nil && info.IsDir() && skipDirs[filepath.Base(path)] {
|
|
275
|
+
return filepath.SkipDir
|
|
276
|
+
}
|
|
277
|
+
return nil
|
|
278
|
+
}
|
|
279
|
+
if !strings.HasSuffix(path, ".go") {
|
|
280
|
+
return nil
|
|
281
|
+
}
|
|
282
|
+
content, err := os.ReadFile(path)
|
|
283
|
+
if err != nil {
|
|
284
|
+
return nil
|
|
285
|
+
}
|
|
286
|
+
fn(path, content)
|
|
287
|
+
return nil
|
|
288
|
+
})
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## Template Linter
|
|
293
|
+
|
|
294
|
+
Validates template files (.tpl) are valid and referenced.
|
|
295
|
+
|
|
296
|
+
```go
|
|
297
|
+
// scripts/lint-prompts.go
|
|
298
|
+
//
|
|
299
|
+
// Validates template files: parseable, referenced, no orphans.
|
|
300
|
+
//
|
|
301
|
+
// Usage: go run scripts/lint-prompts.go
|
|
302
|
+
package main
|
|
303
|
+
|
|
304
|
+
import (
|
|
305
|
+
"fmt"
|
|
306
|
+
"os"
|
|
307
|
+
"path/filepath"
|
|
308
|
+
"regexp"
|
|
309
|
+
"strings"
|
|
310
|
+
"text/template"
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
// CUSTOMIZE: Directories containing template files
|
|
314
|
+
var templateDirs = []string{"templates", "prompts"}
|
|
315
|
+
|
|
316
|
+
func main() {
|
|
317
|
+
var violations int
|
|
318
|
+
|
|
319
|
+
for _, dir := range templateDirs {
|
|
320
|
+
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
|
321
|
+
if err != nil || info == nil || info.IsDir() || !strings.HasSuffix(path, ".tpl") {
|
|
322
|
+
return nil
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
content, err := os.ReadFile(path)
|
|
326
|
+
if err != nil {
|
|
327
|
+
fmt.Printf("%s: cannot read: %v\n", path, err)
|
|
328
|
+
violations++
|
|
329
|
+
return nil
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
_, err = template.New(filepath.Base(path)).
|
|
333
|
+
Option("missingkey=zero").
|
|
334
|
+
Parse(string(content))
|
|
335
|
+
if err != nil {
|
|
336
|
+
fmt.Printf("%s: invalid template: %v\n", path, err)
|
|
337
|
+
violations++
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
return nil
|
|
341
|
+
})
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Check for orphan templates
|
|
345
|
+
embedPattern := regexp.MustCompile(`//go:embed\s+(\S+\.tpl)`)
|
|
346
|
+
tplFiles := make(map[string]bool)
|
|
347
|
+
|
|
348
|
+
for _, dir := range templateDirs {
|
|
349
|
+
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
|
350
|
+
if err != nil || info == nil {
|
|
351
|
+
return nil
|
|
352
|
+
}
|
|
353
|
+
if !info.IsDir() && strings.HasSuffix(path, ".tpl") {
|
|
354
|
+
tplFiles[filepath.Base(path)] = false
|
|
355
|
+
}
|
|
356
|
+
return nil
|
|
357
|
+
})
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
|
|
361
|
+
if err != nil || info.IsDir() || !strings.HasSuffix(path, ".go") {
|
|
362
|
+
return nil
|
|
363
|
+
}
|
|
364
|
+
content, _ := os.ReadFile(path)
|
|
365
|
+
for _, match := range embedPattern.FindAllSubmatch(content, -1) {
|
|
366
|
+
tplFiles[string(match[1])] = true
|
|
367
|
+
}
|
|
368
|
+
return nil
|
|
369
|
+
})
|
|
370
|
+
|
|
371
|
+
for name, referenced := range tplFiles {
|
|
372
|
+
if !referenced {
|
|
373
|
+
fmt.Printf("WARNING: %s may be orphaned\n", name)
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if violations == 0 {
|
|
378
|
+
fmt.Printf("✓ All template files are valid\n")
|
|
379
|
+
os.Exit(0)
|
|
380
|
+
}
|
|
381
|
+
os.Exit(1)
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
## Makefile Integration
|
|
386
|
+
|
|
387
|
+
```makefile
|
|
388
|
+
# Architecture checks
|
|
389
|
+
.PHONY: lint-arch
|
|
390
|
+
lint-arch:
|
|
391
|
+
@echo "Checking architecture constraints..."
|
|
392
|
+
@go run scripts/lint-deps.go
|
|
393
|
+
@go run scripts/lint-prompts.go
|
|
394
|
+
@go run scripts/lint-quality.go
|
|
395
|
+
@echo "✓ Architecture checks passed"
|
|
396
|
+
|
|
397
|
+
# Combined lint
|
|
398
|
+
.PHONY: lint
|
|
399
|
+
lint: lint-arch
|
|
400
|
+
@if command -v golangci-lint >/dev/null 2>&1; then \
|
|
401
|
+
golangci-lint run; \
|
|
402
|
+
fi
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
## Adaptation Notes
|
|
406
|
+
|
|
407
|
+
### For TypeScript Projects
|
|
408
|
+
|
|
409
|
+
Read `references/adapters/typescript.md` before creating files. Prefer package-manager scripts and
|
|
410
|
+
Node-native harness linters over Go examples:
|
|
411
|
+
|
|
412
|
+
- Create `scripts/lint-deps.mjs` or an equivalent Node script for layer/import checks.
|
|
413
|
+
- Create `scripts/lint-quality.mjs` for project-specific quality checks.
|
|
414
|
+
- Add npm/pnpm/yarn/bun scripts such as `lint:deps`, `lint:quality`, `lint:arch`, and `lint:harness`.
|
|
415
|
+
- Keep CI strict: include existing `lint`, `typecheck`, `test`, and `build` gates when available.
|
|
416
|
+
- Do not weaken CI because baseline commands are red; report those as pre-existing project debt.
|
|
417
|
+
|
|
418
|
+
For small projects, ESLint import restrictions may be enough:
|
|
419
|
+
```js
|
|
420
|
+
// .eslintrc.js - import restrictions
|
|
421
|
+
module.exports = {
|
|
422
|
+
rules: {
|
|
423
|
+
'no-restricted-imports': ['error', {
|
|
424
|
+
patterns: [
|
|
425
|
+
{ group: ['../ui/*'], message: 'Core cannot import UI' },
|
|
426
|
+
{ group: ['../cmd/*'], message: 'Core cannot import CLI' },
|
|
427
|
+
]
|
|
428
|
+
}]
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### For Python Projects
|
|
434
|
+
|
|
435
|
+
Use custom pylint checkers or ruff rules:
|
|
436
|
+
```python
|
|
437
|
+
# scripts/lint_deps.py
|
|
438
|
+
import ast, sys, pathlib
|
|
439
|
+
|
|
440
|
+
LAYER_ORDER = {
|
|
441
|
+
'models': 0,
|
|
442
|
+
'utils': 1,
|
|
443
|
+
'services': 2,
|
|
444
|
+
'api': 3,
|
|
445
|
+
'cli': 4,
|
|
446
|
+
}
|
|
447
|
+
# ... validate imports against layer order
|
|
448
|
+
```
|