ai-commons 0.2.10 → 0.2.12

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 CHANGED
@@ -1,78 +1,61 @@
1
1
  # ai-commons
2
2
 
3
- Общие правила для Claude Code + автосохранение диалогов. Поставляется как
4
- npm-зависимость. После `npm install` в проекте появляется:
5
-
6
- - В корневом `CLAUDE.md` — управляемый блок между метками:
7
- ```
8
- <!-- ai-commons:begin -->
9
- ... @node_modules/ai-commons/AGENTS.md ...
10
- <!-- ai-commons:end -->
11
- ```
12
- Этот блок **обновляется хуком** при каждом старте сессии. Всё, что в файле
13
- снаружи блока, — твоё, не трогается. Если `CLAUDE.md` не было — создастся
14
- с одним блоком.
15
- - Хуки в `.claude/settings.json`:
16
- - `SessionStart` — обновляет блок в `CLAUDE.md` на каждом старте сессии.
17
- - `Stop` и `SessionEnd` — сохраняют диалог в `.ai-dialogs/YYMMDD-HHII-<topic>.md`.
18
- - Запись `.ai-dialogs/` в `.gitignore`.
3
+ Общие правила для AI-агентов + автосохранение Claude-диалогов. Поставляется
4
+ как npm-зависимость и поддерживает четыре популярных таргета:
19
5
 
20
- ## Установка в новый проект
6
+ | Агент / стандарт | Файл в потребителе | Режим |
7
+ |---|---|---|
8
+ | Claude Code | `CLAUDE.md` | управляемый блок (`@AGENTS.md` import) |
9
+ | OpenAI Codex / стандартный AGENTS.md | `AGENTS.md` | управляемый блок (встроенное содержимое) |
10
+ | Cursor | `.cursor/rules/ai-commons.mdc` | весь файл принадлежит ai-commons |
21
11
 
22
- ```bash
23
- cd my-new-project
24
- npm i -D /Users/os/okneigres-repos/ai-commons
25
- ```
12
+ В файлах с управляемым блоком (`CLAUDE.md`, `AGENTS.md`) содержимое между
13
+ метками `<!-- ai-commons:begin -->` и `<!-- ai-commons:end -->`
14
+ перезаписывается; всё остальное в файле — твоё, не трогается.
26
15
 
27
- Или, если опубликовано в реестре:
16
+ Дополнительно для Claude:
28
17
 
29
- ```bash
30
- npm i -D ai-commons
31
- ```
18
+ - `SessionStart`-хук обновляет все три target-файла на каждом старте сессии.
19
+ - `Stop` / `SessionEnd`-хук сохраняет диалог в
20
+ `.ai-dialogs/YYMMDD-HHII-<topic>.md`.
21
+ - `.ai-dialogs/` добавляется в `.gitignore`.
32
22
 
33
- `postinstall` всё настраивает автоматически. Запустить вручную:
23
+ ## Установка в новый проект
34
24
 
35
25
  ```bash
36
- npx ai-commons install
26
+ cd my-new-project
27
+ npm init -y # если package.json ещё нет
28
+ npm i -D /Users/os/okneigres-repos/ai-commons
37
29
  ```
38
30
 
39
- ## Откат
31
+ `postinstall` всё настраивает автоматически. Запустить вручную:
40
32
 
41
33
  ```bash
42
- npx ai-commons uninstall
43
- # затем удалить зависимость:
44
- npm uninstall ai-commons
34
+ npx ai-commons install # идемпотентно: можно гонять сколько угодно раз
35
+ npx ai-commons uninstall # снять блоки, хуки и Cursor-файл
45
36
  ```
46
37
 
47
- `uninstall` уберёт блок `ai-commons` из `CLAUDE.md` (сам файл остаётся, если в
48
- нём есть другое содержимое — удаляется только если оказался пустым) и
49
- вычистит хуки `ai-commons` из `.claude/settings.json`, не трогая чужие хуки.
38
+ ## Правила
50
39
 
51
- ## Уровни правил
52
-
53
- `AGENTS.md` в этом репо разбит на три секции:
54
-
55
- - **MUST** — обязательно, игнорировать нельзя ни при каких обстоятельствах
56
- (например: не пушить force в main, не коммитить секреты).
57
- - **Желательно** — стандарт по умолчанию, отступать можно только с явной
58
- причиной (например: краткие ответы, без избыточных абстракций).
59
- - **Остальное** — стиль и привычки (например: `curl` одной строкой,
60
- ссылки на код в формате `path:line`).
40
+ Лежат в [`RULES.md`](RULES.md) — это публичный контракт, его содержимое
41
+ `targets.js` копирует во все target-файлы потребителей. `AGENTS.md` в
42
+ этом репо заметки для работы над самим `ai-commons`, в потребителей
43
+ не попадает.
61
44
 
62
45
  ## Как обновить правила во всех проектах
63
46
 
64
- 1. Правишь `AGENTS.md` здесь.
47
+ 1. Правишь `RULES.md` здесь.
65
48
  2. `git commit && git push` (или просто коммит, если репо локальный).
66
- 3. В каждом потребителе: `npm update ai-commons` (или `npm install`, если
67
- зависимость через `file:`).
68
-
69
- Содержимое подгружается Claude Code через `@`-импорт каждый сеанс, поэтому
70
- после обновления `node_modules/ai-commons/AGENTS.md` следующая сессия
71
- увидит новые правила автоматически.
49
+ 3. В каждом потребителе:
50
+ - **Claude**: ничего делать не надо — `SessionStart`-хук подтянет новые
51
+ правила в следующей сессии (для `file:`-зависимостей) или после
52
+ `npm update ai-commons` (для опубликованных).
53
+ - **Codex / Cursor**: `npm install` (или `npx ai-commons install`)
54
+ перепишет блоки и Cursor-файл.
72
55
 
73
- ## Сохранение диалогов
56
+ ## Сохранение диалогов (только Claude)
74
57
 
75
- После каждого Claude Stop (и при завершении сессии) хук пишет
58
+ После каждого Claude `Stop` (и при завершении сессии) хук пишет
76
59
  `.ai-dialogs/YYMMDD-HHII-<topic>.md`:
77
60
 
78
61
  - Timestamp — момент первой реплики пользователя в сессии.
@@ -89,15 +72,17 @@ npm uninstall ai-commons
89
72
 
90
73
  ```
91
74
  ai-commons/
92
- ├── AGENTS.md правила, импортируются потребителями
75
+ ├── RULES.md источник правды (правила), копируется в потребителей
76
+ ├── AGENTS.md — заметки для работы над самим ai-commons
93
77
  ├── package.json — bin + postinstall
94
78
  ├── bin/ai-commons.js — CLI: install / uninstall
95
79
  ├── scripts/
96
80
  │ ├── postinstall.js — npm-хук, запускает installer.install
97
- │ ├── installer.js — pointer-блок + merge hooks + .gitignore
98
- └── managed-block.js хелперы для блока в CLAUDE.md
81
+ │ ├── installer.js — установка/удаление в потребителе
82
+ ├── targets.js список таргет-файлов (Claude/Codex/Cursor)
83
+ │ └── managed-block.js — вставка/обновление блока в markdown
99
84
  └── hooks/
100
- ├── ensure-rules-pointer.js — SessionStart-хук
85
+ ├── ensure-rules-pointer.js — SessionStart-хук (рефреш всех таргетов)
101
86
  └── save-dialog.js — Stop / SessionEnd-хук
102
87
  ```
103
88
 
@@ -107,7 +92,9 @@ ai-commons/
107
92
 
108
93
  ## Что не делается
109
94
 
110
- - `ai-commons` **не** распространяет общие сабагенты/скиллы/слэш-команды.
111
- Этот скоуп умышленно убран если понадобится, добавим отдельной командой
112
- `ai-commons sync-agents`.
113
- - `permissions` и `env` из `settings.json` потребителя не трогаются.
95
+ - `permissions` и `env` из `settings.json` потребителя не трогаются — только
96
+ свой набор хуков (SessionStart / Stop / SessionEnd) мержится.
97
+ - Старый формат Cursor (`.cursorrules` в корне) не поддерживается — только
98
+ современный `.cursor/rules/*.mdc`.
99
+ - Автосейв диалогов реализован только для Claude (у других агентов нет
100
+ аналогичных hook'ов).
package/RULES.md ADDED
@@ -0,0 +1,5 @@
1
+ # ai-commons — общие правила
2
+
3
+ - **Установи `git-coherent` в проект**: `npm i -D git-coherent`.
4
+ - **Логи диалогов сохраняй в `.ai-dialogs/YYMMDD-HHII-short-topic-name.md`**.
5
+ - `curl`-примеры — одной строкой, без переносов `\`.
@@ -1,14 +1,11 @@
1
1
  #!/usr/bin/env node
2
- // SessionStart hook: ensures the consumer's root CLAUDE.md contains an
3
- // up-to-date ai-commons block. The block lives between
4
- // `<!-- ai-commons:begin -->` and `<!-- ai-commons:end -->` markers; any
5
- // content OUTSIDE the markers is preserved.
2
+ // SessionStart hook: re-applies ai-commons rule files in the consumer
3
+ // project. This refreshes the managed block in CLAUDE.md / AGENTS.md and
4
+ // the full .cursor/rules/ai-commons.mdc file using the latest content from
5
+ // node_modules/ai-commons/RULES.md.
6
6
 
7
7
  const fs = require('fs');
8
- const path = require('path');
9
- const { applyBlock } = require('../scripts/managed-block');
10
-
11
- const POINTER_FILE = 'CLAUDE.md';
8
+ const { applyAllTargets } = require('../scripts/targets');
12
9
 
13
10
  function readStdinJson() {
14
11
  try {
@@ -23,22 +20,14 @@ function main() {
23
20
  const input = readStdinJson();
24
21
  const cwd = input.cwd || process.env.CLAUDE_PROJECT_DIR || process.cwd();
25
22
  if (!cwd || !fs.existsSync(cwd)) {
26
- process.stderr.write('[ai-commons] no cwd, skipping pointer refresh\n');
23
+ process.stderr.write('[ai-commons] no cwd, skipping refresh\n');
27
24
  process.exit(0);
28
25
  }
29
26
 
30
- const pointerPath = path.join(cwd, POINTER_FILE);
31
- const existing = fs.existsSync(pointerPath)
32
- ? fs.readFileSync(pointerPath, 'utf8')
33
- : null;
34
- const next = applyBlock(existing);
35
-
36
- if (existing != null && next === existing) {
37
- process.exit(0);
27
+ const results = applyAllTargets(cwd);
28
+ for (const { target, result } of results) {
29
+ process.stderr.write(`[ai-commons] ${target.id}: ${target.file} ${result}\n`);
38
30
  }
39
-
40
- fs.writeFileSync(pointerPath, next);
41
- process.stderr.write(`[ai-commons] refreshed block in ${POINTER_FILE}\n`);
42
31
  process.exit(0);
43
32
  }
44
33
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-commons",
3
- "version": "0.2.10",
3
+ "version": "0.2.12",
4
4
  "description": "Shared Claude Code rules + dialog-saver hook for projects",
5
5
  "bin": {
6
6
  "ai-commons": "bin/ai-commons.js"
@@ -13,7 +13,7 @@
13
13
  "bin",
14
14
  "scripts",
15
15
  "hooks",
16
- "AGENTS.md",
16
+ "RULES.md",
17
17
  "README.md"
18
18
  ],
19
19
  "engines": {
@@ -1,5 +1,5 @@
1
1
  // Installs ai-commons into a consumer project:
2
- // - writes/refreshes the root CLAUDE.md pointer
2
+ // - writes/refreshes rule files for Claude / Codex / Cursor (see targets.js)
3
3
  // - merges our hooks into .claude/settings.json (preserving any existing hooks)
4
4
  // - ensures .ai-dialogs/ is gitignored
5
5
  //
@@ -8,10 +8,9 @@
8
8
 
9
9
  const fs = require('fs');
10
10
  const path = require('path');
11
- const { applyBlock, removeBlock } = require('./managed-block');
11
+ const { applyAllTargets, removeAllTargets } = require('./targets');
12
12
 
13
13
  const PACKAGE_NAME = require('../package.json').name;
14
- const POINTER_FILE = 'CLAUDE.md';
15
14
  const SETTINGS_FILE = path.join('.claude', 'settings.json');
16
15
  const GITIGNORE_FILE = '.gitignore';
17
16
 
@@ -39,20 +38,11 @@ function readJsonOrEmpty(p) {
39
38
  }
40
39
  }
41
40
 
42
- function writePointer(consumerRoot) {
43
- const pointerPath = path.join(consumerRoot, POINTER_FILE);
44
- const existing = fs.existsSync(pointerPath)
45
- ? fs.readFileSync(pointerPath, 'utf8')
46
- : null;
47
- const next = applyBlock(existing);
48
- if (existing != null && next === existing) return false;
49
- fs.writeFileSync(pointerPath, next);
50
- log(
51
- existing == null
52
- ? `created ${POINTER_FILE} with ai-commons block`
53
- : `refreshed ai-commons block in ${POINTER_FILE}`
54
- );
55
- return true;
41
+ function writeRuleFiles(consumerRoot) {
42
+ const results = applyAllTargets(consumerRoot);
43
+ for (const { target, result } of results) {
44
+ log(`${target.id}: ${target.file} ${result}`);
45
+ }
56
46
  }
57
47
 
58
48
  function stripManagedHooksFromEvent(eventEntries) {
@@ -101,26 +91,18 @@ function install(consumerRoot) {
101
91
  if (!consumerRoot || !fs.existsSync(consumerRoot)) {
102
92
  throw new Error(`Invalid consumer root: ${consumerRoot}`);
103
93
  }
104
- writePointer(consumerRoot);
94
+ writeRuleFiles(consumerRoot);
105
95
  mergeHooks(consumerRoot);
106
96
  ensureGitignore(consumerRoot);
107
97
  log('install complete');
108
98
  }
109
99
 
110
100
  function uninstall(consumerRoot) {
111
- // Strip our managed block from the pointer file. Leave any user-written
112
- // content intact; remove the file only if it ends up empty.
113
- const pointerPath = path.join(consumerRoot, POINTER_FILE);
114
- if (fs.existsSync(pointerPath)) {
115
- const existing = fs.readFileSync(pointerPath, 'utf8');
116
- const next = removeBlock(existing);
117
- if (next.trim() === '') {
118
- fs.rmSync(pointerPath);
119
- log(`removed empty ${POINTER_FILE}`);
120
- } else if (next !== existing) {
121
- fs.writeFileSync(pointerPath, next);
122
- log(`removed ai-commons block from ${POINTER_FILE}`);
123
- }
101
+ // Strip our managed content from each target file. Leave user content
102
+ // intact; remove block-mode files only if they end up empty.
103
+ const results = removeAllTargets(consumerRoot);
104
+ for (const { target, result } of results) {
105
+ log(`${target.id}: ${target.file} ${result}`);
124
106
  }
125
107
 
126
108
  // Strip our hooks from settings.
@@ -1,44 +1,50 @@
1
- // Shared helpers for inserting/updating the ai-commons block inside a
2
- // host markdown file (typically the consumer's CLAUDE.md).
1
+ // Helpers for inserting/updating an ai-commons block inside a host markdown
2
+ // file (CLAUDE.md, AGENTS.md, etc.). The block content is passed in by the
3
+ // caller, so this module is target-agnostic.
3
4
 
4
- const PACKAGE_NAME = 'ai-commons';
5
5
  const BEGIN = '<!-- ai-commons:begin -->';
6
6
  const END = '<!-- ai-commons:end -->';
7
7
 
8
- const BLOCK_BODY = [
9
- BEGIN,
10
- '<!-- Managed by ai-commons. Anything between these markers is overwritten -->',
11
- '<!-- on every Claude Code session start. To change rules, edit AGENTS.md -->',
12
- '<!-- in the ai-commons repo. Everything OUTSIDE these markers is yours. -->',
13
- `@node_modules/${PACKAGE_NAME}/AGENTS.md`,
14
- END,
8
+ const HEADER_COMMENTS = [
9
+ '<!-- Managed by ai-commons. Content between these markers is auto-generated. -->',
10
+ '<!-- To change rules, edit RULES.md in the ai-commons repo and re-run -->',
11
+ '<!-- `npm install` in this project (Claude users get auto-refresh on session). -->',
15
12
  ].join('\n');
16
13
 
17
14
  function escapeRegex(s) {
18
15
  return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
19
16
  }
20
17
 
21
- const BLOCK_RE = new RegExp(`${escapeRegex(BEGIN)}[\\s\\S]*?${escapeRegex(END)}`);
18
+ // Greedy on purpose: if marker strings somehow appear inside the rendered
19
+ // body, we still match the OUTERMOST begin..end pair instead of stopping
20
+ // at the first nested-looking end.
21
+ const BLOCK_RE = new RegExp(`${escapeRegex(BEGIN)}[\\s\\S]*${escapeRegex(END)}`);
22
22
 
23
- // Returns the host content with our managed block inserted/refreshed.
23
+ function buildBlock(innerContent) {
24
+ return `${BEGIN}\n${HEADER_COMMENTS}\n\n${innerContent}\n${END}`;
25
+ }
26
+
27
+ // Returns the host content with the managed block inserted/refreshed.
24
28
  // - If the host already contains markers, replace content between them.
25
29
  // - Otherwise, prepend the block at the top, separated by a blank line.
26
30
  // - If host is null/undefined, return a file containing just the block.
27
- function applyBlock(hostContent) {
28
- if (hostContent == null) return BLOCK_BODY + '\n';
31
+ function applyBlock(hostContent, innerContent) {
32
+ const block = buildBlock(innerContent);
33
+ if (hostContent == null) return block + '\n';
29
34
  if (BLOCK_RE.test(hostContent)) {
30
- return hostContent.replace(BLOCK_RE, BLOCK_BODY);
35
+ return hostContent.replace(BLOCK_RE, block);
31
36
  }
32
- const sep = hostContent.length === 0 || hostContent.startsWith('\n') ? '\n' : '\n\n';
33
- return BLOCK_BODY + sep + hostContent;
37
+ const sep =
38
+ hostContent.length === 0 || hostContent.startsWith('\n') ? '\n' : '\n\n';
39
+ return block + sep + hostContent;
34
40
  }
35
41
 
36
- // Returns the host content with the managed block (and surrounding blank
37
- // lines) removed. Safe to call when no block is present.
38
42
  function removeBlock(hostContent) {
39
43
  if (!hostContent) return '';
40
- const re = new RegExp(`${escapeRegex(BEGIN)}[\\s\\S]*?${escapeRegex(END)}\\n*`, 'g');
44
+ const re = new RegExp(
45
+ `${escapeRegex(BEGIN)}[\\s\\S]*${escapeRegex(END)}\\n*`
46
+ );
41
47
  return hostContent.replace(re, '');
42
48
  }
43
49
 
44
- module.exports = { applyBlock, removeBlock, BEGIN, END, BLOCK_BODY };
50
+ module.exports = { applyBlock, removeBlock, BEGIN, END };
@@ -0,0 +1,124 @@
1
+ // Defines every file ai-commons writes into a consumer project, and how to
2
+ // render its content. Currently covers Claude, Codex (root AGENTS.md), and
3
+ // Cursor (.cursor/rules/ai-commons.mdc).
4
+
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+ const { applyBlock, removeBlock } = require('./managed-block');
8
+
9
+ const PACKAGE_ROOT = path.resolve(__dirname, '..');
10
+
11
+ function readRules() {
12
+ return fs.readFileSync(path.join(PACKAGE_ROOT, 'RULES.md'), 'utf8').trim();
13
+ }
14
+
15
+ // Each target:
16
+ // id — internal name for logs
17
+ // file — path relative to consumer root
18
+ // mode — 'block' (manage section between markers) | 'fullFile' (own whole file)
19
+ // render(r) — render the block body / file body from the rules text
20
+ //
21
+ // Block mode preserves user content outside the markers.
22
+ // fullFile mode means we own the entire file (created/removed as a unit).
23
+
24
+ const TARGETS = [
25
+ {
26
+ id: 'claude',
27
+ file: 'CLAUDE.md',
28
+ mode: 'block',
29
+ // Claude supports @-imports natively; defer to the local AGENTS.md
30
+ // (which carries the embedded rules), avoiding duplication.
31
+ render: () => '@AGENTS.md',
32
+ },
33
+ {
34
+ id: 'codex+standard',
35
+ file: 'AGENTS.md',
36
+ mode: 'block',
37
+ // Codex CLI and the cross-tool AGENTS.md standard read this file
38
+ // directly — embed the full rules text.
39
+ render: (rules) => rules,
40
+ },
41
+ {
42
+ id: 'cursor',
43
+ file: path.join('.cursor', 'rules', 'ai-commons.mdc'),
44
+ mode: 'fullFile',
45
+ // Cursor expects MDC: YAML frontmatter + markdown body.
46
+ render: (rules) =>
47
+ `---\ndescription: ai-commons shared rules\nalwaysApply: true\n---\n\n${rules}\n`,
48
+ },
49
+ ];
50
+
51
+ function applyTarget(consumerRoot, target, rules) {
52
+ const fullPath = path.join(consumerRoot, target.file);
53
+ fs.mkdirSync(path.dirname(fullPath), { recursive: true });
54
+
55
+ if (target.mode === 'fullFile') {
56
+ const next = target.render(rules);
57
+ const existing = fs.existsSync(fullPath)
58
+ ? fs.readFileSync(fullPath, 'utf8')
59
+ : null;
60
+ if (existing === next) return null;
61
+ fs.writeFileSync(fullPath, next);
62
+ return existing == null ? 'created' : 'refreshed';
63
+ }
64
+
65
+ // block mode
66
+ const existing = fs.existsSync(fullPath)
67
+ ? fs.readFileSync(fullPath, 'utf8')
68
+ : null;
69
+ const next = applyBlock(existing, target.render(rules));
70
+ if (existing != null && next === existing) return null;
71
+ fs.writeFileSync(fullPath, next);
72
+ return existing == null ? 'created' : 'refreshed';
73
+ }
74
+
75
+ function removeTarget(consumerRoot, target) {
76
+ const fullPath = path.join(consumerRoot, target.file);
77
+ if (!fs.existsSync(fullPath)) return null;
78
+
79
+ if (target.mode === 'fullFile') {
80
+ fs.rmSync(fullPath);
81
+ return 'removed';
82
+ }
83
+
84
+ const existing = fs.readFileSync(fullPath, 'utf8');
85
+ const next = removeBlock(existing);
86
+ if (next.trim() === '') {
87
+ fs.rmSync(fullPath);
88
+ return 'removed-empty';
89
+ }
90
+ if (next !== existing) {
91
+ fs.writeFileSync(fullPath, next);
92
+ return 'block-removed';
93
+ }
94
+ return null;
95
+ }
96
+
97
+ function applyAllTargets(consumerRoot) {
98
+ const rules = readRules();
99
+ const results = [];
100
+ for (const target of TARGETS) {
101
+ const result = applyTarget(consumerRoot, target, rules);
102
+ if (result) results.push({ target, result });
103
+ }
104
+ return results;
105
+ }
106
+
107
+ function removeAllTargets(consumerRoot) {
108
+ const results = [];
109
+ for (const target of TARGETS) {
110
+ const result = removeTarget(consumerRoot, target);
111
+ if (result) results.push({ target, result });
112
+ }
113
+ return results;
114
+ }
115
+
116
+ module.exports = {
117
+ TARGETS,
118
+ PACKAGE_ROOT,
119
+ readRules,
120
+ applyTarget,
121
+ removeTarget,
122
+ applyAllTargets,
123
+ removeAllTargets,
124
+ };
package/AGENTS.md DELETED
@@ -1,81 +0,0 @@
1
- # ai-commons — общие правила для всех проектов
2
-
3
- Этот файл подгружается в каждую Claude Code сессию проекта-потребителя через
4
- импорт `@node_modules/ai-commons/AGENTS.md` в корневом `CLAUDE.md`. В корневом
5
- `CLAUDE.md` потребителя есть управляемая секция между метками
6
- `<!-- ai-commons:begin -->` и `<!-- ai-commons:end -->` — её содержимое
7
- перезаписывается хуком `ai-commons` на каждом старте сессии. **Не редактируй
8
- блок между метками** — изменения будут потеряны. Всё, что в `CLAUDE.md`
9
- снаружи блока, остаётся нетронутым: пиши там свои проектные правила.
10
-
11
- Чтобы поменять общие правила, правь этот файл в репозитории `ai-commons`.
12
-
13
- Правила сгруппированы по трём уровням приоритета. Игнорировать MUST нельзя
14
- ни при каких обстоятельствах. Желательно — стандартное поведение по
15
- умолчанию, отступление возможно только с явной причиной. Остальное —
16
- стиль и привычки.
17
-
18
- ---
19
-
20
- ## MUST — обязательно, игнорировать нельзя
21
-
22
- - **Никогда не делай `git push --force` в `main`/`master`.** Если нужно
23
- переписать историю, спроси разрешения и работай через feature-ветку.
24
- - **Никогда не коммить секреты** (`.env`, ключи, токены, credentials.json
25
- и т.п.). Если такой файл попал в `git add`, удали его из стейджа и
26
- предупреди пользователя.
27
- - **Не запускай деструктивные операции без подтверждения**: `rm -rf`,
28
- `git reset --hard`, `DROP TABLE`, `git clean -fd`, отключение pre-commit
29
- хуков (`--no-verify`), force push куда угодно.
30
- - **Не правь блок между метками `ai-commons:begin / end`** в корневом
31
- `CLAUDE.md` потребителя — он управляется `ai-commons` и перезаписывается
32
- на старте сессии. Свои правила пиши снаружи этого блока.
33
- - **Для групп связанных проектов используй `git-coherent`**
34
- (`npm i -g git-coherent`, бинари `git-coherent` / `gitc`) — синхронизация
35
- git-операций по сиблинг-репозиториям, которые опт-инятся через
36
- `.git-coherent` маркер. Это «среднее между monorepo и микросервисами»:
37
- каждый подпроект остаётся отдельным git-репо, `git-coherent` запускает
38
- операции над всеми отмеченными сразу. Не предлагай и не создавай
39
- монорепо или независимые multi-repo схемы для таких задач без явного
40
- запроса.
41
- - **Не отключай и не модифицируй хуки `ai-commons`** в `.claude/settings.json`
42
- без явного запроса пользователя.
43
-
44
- ## Желательно — стандарт по умолчанию, отступать только с причиной
45
-
46
- - Отвечай кратко: один-два абзаца, без избыточных вводных и итогов.
47
- - Перед нетривиальной задачей дай короткий план (3–5 пунктов), потом
48
- делай. Не пиши длинные эссе про подход.
49
- - Не добавляй фич, рефакторингов и абстракций сверх задачи. Bug fix не
50
- тянет за собой cleanup.
51
- - Не пиши комментарии, описывающие *что* делает код. Пиши только если
52
- нужно объяснить *почему* — и только если это неочевидно.
53
- - Не валидируй то, что не может случиться. Доверяй внутренним
54
- гарантиям типов и фреймворков; валидируй только на границах системы
55
- (вход пользователя, внешние API).
56
- - Перед удалением «непонятного» файла/ветки/конфигурации — выясни, не
57
- работа ли это пользователя в процессе. Спроси, если есть сомнения.
58
-
59
- ## Остальное — стиль и привычки
60
-
61
- - `curl`-примеры — одной строкой, без переносов `\`.
62
- - При ссылках на код используй формат `path/to/file.ts:42`.
63
- - Для UI-задач — запусти dev-сервер и проверь в браузере перед тем, как
64
- говорить «готово». Тесты и типы проверяют корректность кода, не
65
- фичи.
66
- - Если задача неясная или формулировка двусмысленная — задай один-два
67
- уточняющих вопроса вместо угадывания.
68
-
69
- ---
70
-
71
- ## Как это устроено технически
72
-
73
- - `ai-commons` ставится как обычная npm-зависимость:
74
- `npm i -D ai-commons` (или `file:~/okneigres-repos/ai-commons` для локальной разработки).
75
- - `postinstall` вставляет/обновляет блок между метками `ai-commons:begin/end`
76
- в корневом `CLAUDE.md` потребителя. Если файла нет — создаёт его.
77
- - `SessionStart`-хук `ai-commons` обновляет этот блок на каждом старте
78
- сессии — это гарантирует, что правила всегда актуальны. Остальное
79
- содержимое `CLAUDE.md` не трогается.
80
- - `Stop`-хук сохраняет каждый диалог в
81
- `.ai-dialogs/YYMMDD-HHII-<topic>.md` (см. README модуля).