@codepassion/skills 1.0.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/LICENSE +21 -0
- package/README.md +918 -0
- package/SKILLS.md +19 -0
- package/bin/c9n-skills.js +36 -0
- package/install.sh +15 -0
- package/package.json +55 -0
- package/schemas/skill.schema.json +16 -0
- package/scripts/build-combined.mjs +36 -0
- package/scripts/lint-skills.mjs +39 -0
- package/skills/c9n/SKILL.md +174 -0
- package/skills/c9n-clean-code-typescript/SKILL.md +15 -0
- package/skills/c9n-code-formatting/SKILL.md +17 -0
- package/skills/c9n-code-review/SKILL.md +12 -0
- package/skills/c9n-commit-messages/SKILL.md +13 -0
- package/skills/c9n-development-workflow/SKILL.md +12 -0
- package/skills/c9n-git-branching/SKILL.md +12 -0
- package/skills/c9n-go-no-go-release/SKILL.md +13 -0
- package/skills/c9n-jsonapi/SKILL.md +17 -0
- package/skills/c9n-pull-requests/SKILL.md +10 -0
- package/skills/c9n-semver-deployment/SKILL.md +14 -0
- package/skills/c9n-typescript-eslint/SKILL.md +16 -0
package/SKILLS.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# C9N Agent Skills
|
|
2
|
+
|
|
3
|
+
Agent skills (SKILL.md) based on the CodePassion (C9N) conventions.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
npx @codepassion/c9n-skills install claude # ~/.claude/skills
|
|
8
|
+
npx @codepassion/c9n-skills install codex # ~/.codex/skills
|
|
9
|
+
npx @codepassion/c9n-skills install project # ./.agents/skills
|
|
10
|
+
npx @codepassion/c9n-skills install combined # one combined skill
|
|
11
|
+
|
|
12
|
+
Or: ./install.sh {claude|codex|project|combined}
|
|
13
|
+
|
|
14
|
+
## Edit
|
|
15
|
+
|
|
16
|
+
Per-topic SKILL.md files in skills/c9n-* are the source of truth.
|
|
17
|
+
skills/c9n/SKILL.md is auto-generated — run npm run build.
|
|
18
|
+
npm test validates frontmatter against schemas/skill.schema.json.
|
|
19
|
+
CI runs the same on every push and PR.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { cp, mkdir, readdir, stat } from 'node:fs/promises'
|
|
3
|
+
import { existsSync } from 'node:fs'
|
|
4
|
+
import { homedir } from 'node:os'
|
|
5
|
+
import { dirname, join, resolve } from 'node:path'
|
|
6
|
+
import { fileURLToPath } from 'node:url'
|
|
7
|
+
const SRC = resolve(dirname(fileURLToPath(import.meta.url)), '..', 'skills')
|
|
8
|
+
const [,, cmd='install', target='claude', ...rest] = process.argv
|
|
9
|
+
if (cmd==='help'||cmd==='--help'||cmd==='-h'){ help(); process.exit(0) }
|
|
10
|
+
if (cmd!=='install'){ help(); process.exit(1) }
|
|
11
|
+
const flags={dest:null,force:false,dryRun:false}
|
|
12
|
+
for (let i=0;i<rest.length;i++){ const a=rest[i]
|
|
13
|
+
if (a==='--force') flags.force=true
|
|
14
|
+
else if (a==='--dry-run') flags.dryRun=true
|
|
15
|
+
else if (a==='--dest') flags.dest=resolve(rest[++i]??'') }
|
|
16
|
+
const dest = flags.dest ?? defaultDest(target)
|
|
17
|
+
if (!dest){ help(); process.exit(1) }
|
|
18
|
+
const sources = await resolveSources(target)
|
|
19
|
+
if (!sources.length){ console.error('No skills found'); process.exit(1) }
|
|
20
|
+
console.log(`Installing ${sources.length} skill(s) into ${dest}${flags.dryRun?' (dry-run)':''}`)
|
|
21
|
+
if (!flags.dryRun) await mkdir(dest,{recursive:true})
|
|
22
|
+
for (const src of sources){ const n=src.split(/[\\/]/).pop(); const t=join(dest,n)
|
|
23
|
+
if (existsSync(t) && !flags.force){ console.log(` skip ${n}`); continue }
|
|
24
|
+
console.log(` copy ${n}`); if (!flags.dryRun) await cp(src,t,{recursive:true,force:true}) }
|
|
25
|
+
console.log('Done.')
|
|
26
|
+
async function resolveSources(t){
|
|
27
|
+
if (t==='combined'){ const c=join(SRC,'c9n'); return existsSync(c)?[c]:[] }
|
|
28
|
+
const out=[]; for (const e of await readdir(SRC)){ if (!e.startsWith('c9n-')) continue
|
|
29
|
+
const f=join(SRC,e); if ((await stat(f)).isDirectory()) out.push(f) }
|
|
30
|
+
return out }
|
|
31
|
+
function defaultDest(t){ const h=homedir()
|
|
32
|
+
if (t==='claude'||t==='combined') return join(h,'.claude','skills')
|
|
33
|
+
if (t==='codex') return join(h,'.codex','skills')
|
|
34
|
+
if (t==='project') return join(process.cwd(),'.agents','skills')
|
|
35
|
+
return null }
|
|
36
|
+
function help(){ console.log('c9n-skills install [claude|codex|project|combined] [--dest <dir>] [--force] [--dry-run]') }
|
package/install.sh
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
SRC="$(cd "$(dirname "$0")" && pwd)/skills"
|
|
4
|
+
MODE="${1:-claude}"
|
|
5
|
+
case "$MODE" in
|
|
6
|
+
claude) DEST="${TARGET_DIR:-$HOME/.claude/skills}" ;;
|
|
7
|
+
codex) DEST="${TARGET_DIR:-$HOME/.codex/skills}" ;;
|
|
8
|
+
project) DEST="${TARGET_DIR:-$PWD/.agents/skills}" ;;
|
|
9
|
+
combined) DEST="${TARGET_DIR:-$HOME/.claude/skills}" ;;
|
|
10
|
+
*) echo "Use: claude | codex | project | combined"; exit 1 ;;
|
|
11
|
+
esac
|
|
12
|
+
mkdir -p "$DEST"
|
|
13
|
+
if [ "$MODE" = "combined" ]; then cp -R "$SRC/c9n" "$DEST/"
|
|
14
|
+
else for d in "$SRC"/c9n-*; do [ -d "$d" ] && cp -R "$d" "$DEST/"; done; fi
|
|
15
|
+
echo "Installed into $DEST"
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@codepassion/skills",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Agent skills (SKILL.md) for CodePassion (C9N) engineering conventions.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"c9n-skills": "bin/c9n-skills.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"bin",
|
|
12
|
+
"scripts",
|
|
13
|
+
"schemas",
|
|
14
|
+
"skills",
|
|
15
|
+
"install.sh",
|
|
16
|
+
"LICENSE",
|
|
17
|
+
"SKILLS.md"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "node scripts/build-combined.mjs",
|
|
21
|
+
"lint": "node scripts/lint-skills.mjs",
|
|
22
|
+
"test": "npm run build && npm run lint",
|
|
23
|
+
"prepack": "npm run build && npm run lint",
|
|
24
|
+
"prepare": "husky || true"
|
|
25
|
+
},
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=18"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@commitlint/cli": "^19.0.0",
|
|
31
|
+
"@commitlint/config-conventional": "^19.0.0",
|
|
32
|
+
"husky": "^9.0.0"
|
|
33
|
+
},
|
|
34
|
+
"keywords": [
|
|
35
|
+
"claude",
|
|
36
|
+
"codex",
|
|
37
|
+
"agent",
|
|
38
|
+
"skills",
|
|
39
|
+
"skill.md",
|
|
40
|
+
"codepassion",
|
|
41
|
+
"c9n",
|
|
42
|
+
"conventional-commits",
|
|
43
|
+
"semver",
|
|
44
|
+
"json-api",
|
|
45
|
+
"typescript"
|
|
46
|
+
],
|
|
47
|
+
"repository": {
|
|
48
|
+
"type": "git",
|
|
49
|
+
"url": "git+https://github.com/codepassion-team/c9n.git"
|
|
50
|
+
},
|
|
51
|
+
"homepage": "https://github.com/codepassion-team/c9n#readme",
|
|
52
|
+
"bugs": {
|
|
53
|
+
"url": "https://github.com/codepassion-team/c9n/issues"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://codepassion.co/schemas/skill.schema.json",
|
|
4
|
+
"title": "SKILL.md frontmatter",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["name", "description"],
|
|
7
|
+
"additionalProperties": true,
|
|
8
|
+
"properties": {
|
|
9
|
+
"name": { "type": "string", "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$", "minLength": 2, "maxLength": 64 },
|
|
10
|
+
"description": { "type": "string", "minLength": 20, "maxLength": 2000 },
|
|
11
|
+
"version": { "type": "string", "pattern": "^v?\\d+\\.\\d+\\.\\d+(-[A-Za-z0-9.-]+)?(\\+[A-Za-z0-9.-]+)?$" },
|
|
12
|
+
"tags": { "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 32 }, "uniqueItems": true, "maxItems": 20 },
|
|
13
|
+
"homepage": { "type": "string", "format": "uri" },
|
|
14
|
+
"license": { "type": "string" }
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { mkdir, readFile, readdir, stat, writeFile } from 'node:fs/promises'
|
|
3
|
+
import { dirname, join, resolve } from 'node:path'
|
|
4
|
+
import { fileURLToPath } from 'node:url'
|
|
5
|
+
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..')
|
|
6
|
+
const SKILLS = join(ROOT, 'skills')
|
|
7
|
+
const OUT = join(SKILLS, 'c9n', 'SKILL.md')
|
|
8
|
+
const HDR = `---
|
|
9
|
+
name: c9n
|
|
10
|
+
description: CodePassion (C9N) engineering conventions — a single skill
|
|
11
|
+
covering workflow, branching, commits, PRs, code review, Clean Code TS,
|
|
12
|
+
ESLint, formatting, JSON:API, Go/No Go, and SemVer 2.0.0.
|
|
13
|
+
version: 1.0.0
|
|
14
|
+
tags: [c9n, codepassion, conventions]
|
|
15
|
+
homepage: https://github.com/codepassion-team/c9n
|
|
16
|
+
license: MIT
|
|
17
|
+
---
|
|
18
|
+
<!-- AUTO-GENERATED. Edit skills/c9n-*/SKILL.md, then: npm run build -->
|
|
19
|
+
# C9N — CodePassion Engineering Conventions (combined)
|
|
20
|
+
`
|
|
21
|
+
const ORDER = ['c9n-development-workflow','c9n-git-branching','c9n-commit-messages','c9n-pull-requests','c9n-code-review','c9n-clean-code-typescript','c9n-typescript-eslint','c9n-code-formatting','c9n-jsonapi','c9n-go-no-go-release','c9n-semver-deployment']
|
|
22
|
+
const out = [HDR]
|
|
23
|
+
const all = (await readdir(SKILLS)).filter((n) => n.startsWith('c9n-'))
|
|
24
|
+
const list = [...ORDER, ...all.filter((n) => !ORDER.includes(n)).sort()]
|
|
25
|
+
for (const n of list) {
|
|
26
|
+
const f = join(SKILLS, n, 'SKILL.md')
|
|
27
|
+
try { if (!(await stat(f)).isFile()) continue } catch { continue }
|
|
28
|
+
const t = await readFile(f, 'utf8')
|
|
29
|
+
const i = t.indexOf('\n---', 3)
|
|
30
|
+
const body = i === -1 ? t : t.slice(i + 4).replace(/^\r?\n/, '')
|
|
31
|
+
const title = n.replace(/^c9n-/, '').split('-').map((w) => w[0].toUpperCase() + w.slice(1)).join(' ')
|
|
32
|
+
out.push(`\n---\n\n## ${title}\n\n${body.replace(/^#\s+/gm, '## ').trimStart()}\n`)
|
|
33
|
+
}
|
|
34
|
+
await mkdir(dirname(OUT), { recursive: true })
|
|
35
|
+
await writeFile(OUT, out.join('\n'), 'utf8')
|
|
36
|
+
console.log('Wrote', OUT)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFile, readdir, stat } from 'node:fs/promises'
|
|
3
|
+
import { dirname, join, relative, resolve } from 'node:path'
|
|
4
|
+
import { fileURLToPath } from 'node:url'
|
|
5
|
+
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..')
|
|
6
|
+
const SCHEMA = JSON.parse(await readFile(join(ROOT, 'schemas/skill.schema.json'), 'utf8'))
|
|
7
|
+
const files = []; const fails = []
|
|
8
|
+
async function collect(d){ let es; try{es=await readdir(d)}catch{return}
|
|
9
|
+
for (const e of es){ const f=join(d,e); const s=await stat(f)
|
|
10
|
+
if (s.isDirectory()) await collect(f); else if (e==='SKILL.md') files.push(f) } }
|
|
11
|
+
await collect(join(ROOT,'skills'))
|
|
12
|
+
for (const f of files){
|
|
13
|
+
const rel=relative(process.cwd(),f); const t=await readFile(f,'utf8')
|
|
14
|
+
if (!t.startsWith('---')){ fails.push([rel,'missing frontmatter']); continue }
|
|
15
|
+
const end=t.indexOf('\n---',3); if (end===-1){ fails.push([rel,'unterminated frontmatter']); continue }
|
|
16
|
+
const meta=parse(t.slice(3,end))
|
|
17
|
+
for (const e of validate(meta,SCHEMA,'')) fails.push([rel,e])
|
|
18
|
+
}
|
|
19
|
+
if (fails.length){ for (const [f,m] of fails) console.error(`✗ ${f}: ${m}`); process.exit(1) }
|
|
20
|
+
console.log(`✓ ${files.length} SKILL.md passed`)
|
|
21
|
+
function parse(src){ const o={}; let k=null
|
|
22
|
+
for (const r of src.split(/\r?\n/)){ const l=r.replace(/\s+$/,''); if(!l) continue
|
|
23
|
+
const m=l.match(/^([A-Za-z_][\w-]*):\s?(.*)$/)
|
|
24
|
+
if (m && !l.startsWith(' ')){ k=m[1]; const v=(m[2]??'').trim()
|
|
25
|
+
o[k]=v.startsWith('[')&&v.endsWith(']') ? v.slice(1,-1).split(',').map(s=>s.trim().replace(/^['"]|['"]$/g,'')).filter(Boolean) : v.replace(/^['"]|['"]$/g,'')
|
|
26
|
+
} else if (k && /^\s+\S/.test(r) && typeof o[k]==='string'){ o[k]=`${o[k]} ${r.trim()}`.trim() } }
|
|
27
|
+
return o }
|
|
28
|
+
function validate(v,s,p){ const e=[]
|
|
29
|
+
if (s.type==='object'){ for (const r of s.required??[]) if (v?.[r]===undefined||v?.[r]==='') e.push(`missing required: ${r}`)
|
|
30
|
+
for (const [k,sub] of Object.entries(s.properties??{})) if (v?.[k]!==undefined) e.push(...validate(v[k],sub,p?`${p}.${k}`:k)) }
|
|
31
|
+
if (s.type==='string' && typeof v==='string'){
|
|
32
|
+
if (s.minLength!==undefined && v.length<s.minLength) e.push(`${p} too short`)
|
|
33
|
+
if (s.maxLength!==undefined && v.length>s.maxLength) e.push(`${p} too long`)
|
|
34
|
+
if (s.pattern && !new RegExp(s.pattern).test(v)) e.push(`${p} pattern mismatch`)
|
|
35
|
+
if (s.format==='uri'){ try{new URL(v)}catch{e.push(`${p} bad URI`)} } }
|
|
36
|
+
if (s.type==='array' && Array.isArray(v)){
|
|
37
|
+
if (s.uniqueItems && new Set(v).size!==v.length) e.push(`${p} duplicates`)
|
|
38
|
+
if (s.items) v.forEach((x,i)=>e.push(...validate(x,s.items,`${p}[${i}]`))) }
|
|
39
|
+
return e }
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: c9n
|
|
3
|
+
description: CodePassion (C9N) engineering conventions — a single skill
|
|
4
|
+
covering workflow, branching, commits, PRs, code review, Clean Code TS,
|
|
5
|
+
ESLint, formatting, JSON:API, Go/No Go, and SemVer 2.0.0.
|
|
6
|
+
version: 1.0.0
|
|
7
|
+
tags: [c9n, codepassion, conventions]
|
|
8
|
+
homepage: https://github.com/codepassion-team/c9n
|
|
9
|
+
license: MIT
|
|
10
|
+
---
|
|
11
|
+
<!-- AUTO-GENERATED. Edit skills/c9n-*/SKILL.md, then: npm run build -->
|
|
12
|
+
# C9N — CodePassion Engineering Conventions (combined)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Development Workflow
|
|
18
|
+
|
|
19
|
+
## Workflow
|
|
20
|
+
1. Pick up ticket. 2. Clarify requirements. 3. Analyze ("To Analyze").
|
|
21
|
+
4. Estimate. 5. "Ready for Dev". 6. "Dev in Progress" + draft PR.
|
|
22
|
+
7. Update status. 8. Write tests. 9. "Ready for Code Review".
|
|
23
|
+
10. Address feedback, merge. 11. "Ready to Deploy", tag vX.Y.Z.
|
|
24
|
+
12. Validate in Alpha. 13. "Ready for QA". 14. Pass → Done; fail → Reopened.
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Git Branching
|
|
31
|
+
|
|
32
|
+
## Format: `<type>/<description>`
|
|
33
|
+
Types: `feature/`|`feat/`, `bugfix/`|`fix/`, `hotfix/`, `release/`, `chore/`.
|
|
34
|
+
Rules: lowercase; hyphens only; no special chars; no consecutive or leading/
|
|
35
|
+
trailing separators; dots only in `release/`; include ticket ID; be specific;
|
|
36
|
+
no personal names; under 50 chars.
|
|
37
|
+
Reference: https://conventional-branch.github.io
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Commit Messages
|
|
44
|
+
|
|
45
|
+
## Format
|
|
46
|
+
`<type>[scope]: <description>` + optional body + optional footer.
|
|
47
|
+
Types/SemVer: `feat`→MINOR, `fix`/`perf`→PATCH, others→none.
|
|
48
|
+
Breaking: `feat!:` or `BREAKING CHANGE:` footer → MAJOR.
|
|
49
|
+
Rules: imperative; lowercase after colon; no trailing period; ≤50 char
|
|
50
|
+
subject; one scope; reference tickets in footer (`Closes #123`).
|
|
51
|
+
Reference: https://www.conventionalcommits.org
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Pull Requests
|
|
58
|
+
|
|
59
|
+
## Subject: `#[Ticket_ID] PR description`
|
|
60
|
+
Rules: ticket prefix; imperative mood; capitalize first word; no trailing
|
|
61
|
+
period; body covers what/why/changes/testing + `Closes #TICKET`; open as
|
|
62
|
+
draft until tests are written.
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Code Review
|
|
69
|
+
|
|
70
|
+
## Format: `<label> [decorations]: <subject>`
|
|
71
|
+
Labels: praise, nitpick, suggestion, issue, question, todo, chore.
|
|
72
|
+
Decorations: (non-blocking), (blocking), (if-minor).
|
|
73
|
+
Pair `issue` with `(blocking)` when must-fix. Use GitHub suggestion blocks.
|
|
74
|
+
Batch with "Start a review". Never approve your own PR.
|
|
75
|
+
Reference: https://conventionalcomments.org
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Clean Code Typescript
|
|
82
|
+
|
|
83
|
+
## Rules
|
|
84
|
+
Variables: meaningful names, named constants, default args.
|
|
85
|
+
Functions: ≤2 args (options object), one thing, one abstraction level.
|
|
86
|
+
Objects: `readonly`, type aliases.
|
|
87
|
+
Classes: composition over inheritance, access modifiers, SRP.
|
|
88
|
+
SOLID: SRP, Open/Closed, Liskov, Interface Segregation, Dependency Inversion.
|
|
89
|
+
Errors: subclass `Error`; never strings; never empty `catch`.
|
|
90
|
+
Tests: one concept per test; descriptive names; Arrange-Act-Assert.
|
|
91
|
+
Reference: https://github.com/labs42io/clean-code-typescript
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Typescript Eslint
|
|
98
|
+
|
|
99
|
+
## Required rules
|
|
100
|
+
no-explicit-any (err), explicit-function-return-type (warn),
|
|
101
|
+
no-unused-vars w/ ^_ (err), consistent-type-imports (err),
|
|
102
|
+
no-floating-promises (err), strict-boolean-expressions (warn),
|
|
103
|
+
naming-convention (err), no-non-null-assertion (err),
|
|
104
|
+
no-misused-promises (err), prefer-nullish-coalescing (warn).
|
|
105
|
+
tsconfig strict flags: strict, noUncheckedIndexedAccess, noImplicitOverride,
|
|
106
|
+
noPropertyAccessFromIndexSignature, forceConsistentCasingInFileNames,
|
|
107
|
+
verbatimModuleSyntax, exactOptionalPropertyTypes.
|
|
108
|
+
Reference: https://typescript-eslint.io
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Code Formatting
|
|
115
|
+
|
|
116
|
+
## Prettier
|
|
117
|
+
semi false; singleQuote true; trailingComma none; printWidth 100;
|
|
118
|
+
tabWidth 2; useTabs false; bracketSpacing true; arrowParens always;
|
|
119
|
+
endOfLine lf.
|
|
120
|
+
## EditorConfig
|
|
121
|
+
UTF-8, 2-space indent, LF, trim trailing whitespace (except *.md), final
|
|
122
|
+
newline.
|
|
123
|
+
## lint-staged
|
|
124
|
+
*.{ts,tsx}: prettier --write, eslint --fix.
|
|
125
|
+
*.{json,md,yaml}: prettier --write.
|
|
126
|
+
Rule: ESLint never enforces formatting; Prettier owns formatting.
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Jsonapi
|
|
133
|
+
|
|
134
|
+
## Top-level
|
|
135
|
+
data | errors | meta | links | included | jsonapi. Never mix data+errors.
|
|
136
|
+
## Resource
|
|
137
|
+
Every resource has type+id. Data in attributes; connections in
|
|
138
|
+
relationships; hyperlinks in links.
|
|
139
|
+
## Errors
|
|
140
|
+
status, title, detail, source.pointer.
|
|
141
|
+
## Rules
|
|
142
|
+
Plural type names; sparse fieldsets (?fields[articles]=title,body); meta
|
|
143
|
+
for non-standard info — no invented top-level members.
|
|
144
|
+
Reference: https://jsonapi.org
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Go No Go Release
|
|
151
|
+
|
|
152
|
+
## Gate
|
|
153
|
+
Every item must be Go; one No Go blocks the release.
|
|
154
|
+
Participants: Tech Lead (decision), Developer, QA, Product Owner.
|
|
155
|
+
Checklist: PRs merged + CI green + no critical/high bugs; acceptance
|
|
156
|
+
verified + regression + perf OK; release notes + migrations + rollback +
|
|
157
|
+
env config; PO approval + support briefed + release window agreed.
|
|
158
|
+
Outcomes: Go → tag vX.Y.Z, deploy, monitor; No Go → log blockers, no tag.
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Semver Deployment
|
|
165
|
+
|
|
166
|
+
## Format: vMAJOR.MINOR.PATCH (lowercase v always)
|
|
167
|
+
MAJOR=incompatible API change; MINOR=backwards-compatible feature;
|
|
168
|
+
PATCH=backwards-compatible fix/security/perf.
|
|
169
|
+
Pre-release: v1.5.0-alpha|beta|rc.1 (lower precedence).
|
|
170
|
+
Build meta: v1.5.0+20250401.sha.abc1234 (informational).
|
|
171
|
+
Alpha: tag from develop, `git tag -a vX.Y.Z -m "Release vX.Y.Z" && git push origin vX.Y.Z`.
|
|
172
|
+
Production: confirm Go → pull release branch → create release → CI deploys → monitor.
|
|
173
|
+
Reference: https://semver.org/spec/v2.0.0.html
|
|
174
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: c9n-clean-code-typescript
|
|
3
|
+
description: Clean Code principles adapted for TypeScript by the C9N team.
|
|
4
|
+
Use whenever writing or refactoring TypeScript — naming, functions,
|
|
5
|
+
classes, SOLID, error handling, and testing.
|
|
6
|
+
---
|
|
7
|
+
# Rules
|
|
8
|
+
Variables: meaningful names, named constants, default args.
|
|
9
|
+
Functions: ≤2 args (options object), one thing, one abstraction level.
|
|
10
|
+
Objects: `readonly`, type aliases.
|
|
11
|
+
Classes: composition over inheritance, access modifiers, SRP.
|
|
12
|
+
SOLID: SRP, Open/Closed, Liskov, Interface Segregation, Dependency Inversion.
|
|
13
|
+
Errors: subclass `Error`; never strings; never empty `catch`.
|
|
14
|
+
Tests: one concept per test; descriptive names; Arrange-Act-Assert.
|
|
15
|
+
Reference: https://github.com/labs42io/clean-code-typescript
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: c9n-code-formatting
|
|
3
|
+
description: C9N's Prettier, EditorConfig, and lint-staged setup for
|
|
4
|
+
consistent formatting. Use when bootstrapping a repo or fixing
|
|
5
|
+
formatting drift.
|
|
6
|
+
---
|
|
7
|
+
# Prettier
|
|
8
|
+
semi false; singleQuote true; trailingComma none; printWidth 100;
|
|
9
|
+
tabWidth 2; useTabs false; bracketSpacing true; arrowParens always;
|
|
10
|
+
endOfLine lf.
|
|
11
|
+
# EditorConfig
|
|
12
|
+
UTF-8, 2-space indent, LF, trim trailing whitespace (except *.md), final
|
|
13
|
+
newline.
|
|
14
|
+
# lint-staged
|
|
15
|
+
*.{ts,tsx}: prettier --write, eslint --fix.
|
|
16
|
+
*.{json,md,yaml}: prettier --write.
|
|
17
|
+
Rule: ESLint never enforces formatting; Prettier owns formatting.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: c9n-code-review
|
|
3
|
+
description: Conventional Comments labels for C9N code review. Use whenever
|
|
4
|
+
leaving review feedback or summarizing review comments, to ensure each
|
|
5
|
+
comment is actionable and unambiguous.
|
|
6
|
+
---
|
|
7
|
+
# Format: `<label> [decorations]: <subject>`
|
|
8
|
+
Labels: praise, nitpick, suggestion, issue, question, todo, chore.
|
|
9
|
+
Decorations: (non-blocking), (blocking), (if-minor).
|
|
10
|
+
Pair `issue` with `(blocking)` when must-fix. Use GitHub suggestion blocks.
|
|
11
|
+
Batch with "Start a review". Never approve your own PR.
|
|
12
|
+
Reference: https://conventionalcomments.org
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: c9n-commit-messages
|
|
3
|
+
description: Conventional Commits for the C9N team — generates and validates
|
|
4
|
+
commit messages that drive automated Semantic Versioning. Use whenever
|
|
5
|
+
composing, squashing, or amending commits.
|
|
6
|
+
---
|
|
7
|
+
# Format
|
|
8
|
+
`<type>[scope]: <description>` + optional body + optional footer.
|
|
9
|
+
Types/SemVer: `feat`→MINOR, `fix`/`perf`→PATCH, others→none.
|
|
10
|
+
Breaking: `feat!:` or `BREAKING CHANGE:` footer → MAJOR.
|
|
11
|
+
Rules: imperative; lowercase after colon; no trailing period; ≤50 char
|
|
12
|
+
subject; one scope; reference tickets in footer (`Closes #123`).
|
|
13
|
+
Reference: https://www.conventionalcommits.org
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: c9n-development-workflow
|
|
3
|
+
description: C9N ticket-driven workflow — guides the agent from Jira "Pick up"
|
|
4
|
+
to "Done", covering clarification, analysis, estimation, draft PRs, tests,
|
|
5
|
+
code review, Alpha deployment, and QA handoff.
|
|
6
|
+
---
|
|
7
|
+
# Workflow
|
|
8
|
+
1. Pick up ticket. 2. Clarify requirements. 3. Analyze ("To Analyze").
|
|
9
|
+
4. Estimate. 5. "Ready for Dev". 6. "Dev in Progress" + draft PR.
|
|
10
|
+
7. Update status. 8. Write tests. 9. "Ready for Code Review".
|
|
11
|
+
10. Address feedback, merge. 11. "Ready to Deploy", tag vX.Y.Z.
|
|
12
|
+
12. Validate in Alpha. 13. "Ready for QA". 14. Pass → Done; fail → Reopened.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: c9n-git-branching
|
|
3
|
+
description: Conventional Branch naming for the C9N team. Use whenever
|
|
4
|
+
creating, renaming, or reviewing a Git branch. Enforces lowercase,
|
|
5
|
+
hyphenated <type>/<description>.
|
|
6
|
+
---
|
|
7
|
+
# Format: `<type>/<description>`
|
|
8
|
+
Types: `feature/`|`feat/`, `bugfix/`|`fix/`, `hotfix/`, `release/`, `chore/`.
|
|
9
|
+
Rules: lowercase; hyphens only; no special chars; no consecutive or leading/
|
|
10
|
+
trailing separators; dots only in `release/`; include ticket ID; be specific;
|
|
11
|
+
no personal names; under 50 chars.
|
|
12
|
+
Reference: https://conventional-branch.github.io
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: c9n-go-no-go-release
|
|
3
|
+
description: C9N's Go/No Go release decision gate held after QA sign-off and
|
|
4
|
+
before production deployment. Use whenever preparing a production release
|
|
5
|
+
or running a release meeting.
|
|
6
|
+
---
|
|
7
|
+
# Gate
|
|
8
|
+
Every item must be Go; one No Go blocks the release.
|
|
9
|
+
Participants: Tech Lead (decision), Developer, QA, Product Owner.
|
|
10
|
+
Checklist: PRs merged + CI green + no critical/high bugs; acceptance
|
|
11
|
+
verified + regression + perf OK; release notes + migrations + rollback +
|
|
12
|
+
env config; PO approval + support briefed + release window agreed.
|
|
13
|
+
Outcomes: Go → tag vX.Y.Z, deploy, monitor; No Go → log blockers, no tag.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: c9n-jsonapi
|
|
3
|
+
description: JSON:API specification as adopted by the C9N team. Use whenever
|
|
4
|
+
designing, implementing, or reviewing RESTful endpoints, payloads, or
|
|
5
|
+
API client code.
|
|
6
|
+
---
|
|
7
|
+
# Top-level
|
|
8
|
+
data | errors | meta | links | included | jsonapi. Never mix data+errors.
|
|
9
|
+
# Resource
|
|
10
|
+
Every resource has type+id. Data in attributes; connections in
|
|
11
|
+
relationships; hyperlinks in links.
|
|
12
|
+
# Errors
|
|
13
|
+
status, title, detail, source.pointer.
|
|
14
|
+
# Rules
|
|
15
|
+
Plural type names; sparse fieldsets (?fields[articles]=title,body); meta
|
|
16
|
+
for non-standard info — no invented top-level members.
|
|
17
|
+
Reference: https://jsonapi.org
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: c9n-pull-requests
|
|
3
|
+
description: C9N pull-request title and body conventions. Use whenever
|
|
4
|
+
opening a PR, editing a PR title/description, or reviewing PR hygiene.
|
|
5
|
+
Enforces ticket-prefixed, imperative subjects.
|
|
6
|
+
---
|
|
7
|
+
# Subject: `#[Ticket_ID] PR description`
|
|
8
|
+
Rules: ticket prefix; imperative mood; capitalize first word; no trailing
|
|
9
|
+
period; body covers what/why/changes/testing + `Closes #TICKET`; open as
|
|
10
|
+
draft until tests are written.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: c9n-semver-deployment
|
|
3
|
+
description: C9N's Semantic Versioning 2.0.0 policy and deployment steps
|
|
4
|
+
for Alpha and Production. Use whenever bumping a version, tagging a
|
|
5
|
+
release, or deploying.
|
|
6
|
+
---
|
|
7
|
+
# Format: vMAJOR.MINOR.PATCH (lowercase v always)
|
|
8
|
+
MAJOR=incompatible API change; MINOR=backwards-compatible feature;
|
|
9
|
+
PATCH=backwards-compatible fix/security/perf.
|
|
10
|
+
Pre-release: v1.5.0-alpha|beta|rc.1 (lower precedence).
|
|
11
|
+
Build meta: v1.5.0+20250401.sha.abc1234 (informational).
|
|
12
|
+
Alpha: tag from develop, `git tag -a vX.Y.Z -m "Release vX.Y.Z" && git push origin vX.Y.Z`.
|
|
13
|
+
Production: confirm Go → pull release branch → create release → CI deploys → monitor.
|
|
14
|
+
Reference: https://semver.org/spec/v2.0.0.html
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: c9n-typescript-eslint
|
|
3
|
+
description: C9N's recommended ESLint (typescript-eslint) and tsconfig
|
|
4
|
+
settings. Use when bootstrapping a TypeScript project, fixing lint
|
|
5
|
+
errors, or auditing type safety.
|
|
6
|
+
---
|
|
7
|
+
# Required rules
|
|
8
|
+
no-explicit-any (err), explicit-function-return-type (warn),
|
|
9
|
+
no-unused-vars w/ ^_ (err), consistent-type-imports (err),
|
|
10
|
+
no-floating-promises (err), strict-boolean-expressions (warn),
|
|
11
|
+
naming-convention (err), no-non-null-assertion (err),
|
|
12
|
+
no-misused-promises (err), prefer-nullish-coalescing (warn).
|
|
13
|
+
tsconfig strict flags: strict, noUncheckedIndexedAccess, noImplicitOverride,
|
|
14
|
+
noPropertyAccessFromIndexSignature, forceConsistentCasingInFileNames,
|
|
15
|
+
verbatimModuleSyntax, exactOptionalPropertyTypes.
|
|
16
|
+
Reference: https://typescript-eslint.io
|