@rt-tools/agent-kit 0.10.0 → 0.12.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 (139) hide show
  1. package/assets/checks/check-file-size.mjs +19 -4
  2. package/assets/checks/check-state-next.mjs +202 -0
  3. package/assets/checks/check-states.mjs +142 -0
  4. package/assets/checks/check-turn-map.mjs +146 -0
  5. package/assets/checks/rt-kit-checks.config.mjs +16 -2
  6. package/assets/defaults/project.sh +67 -7
  7. package/assets/defaults/turn-map.md +48 -0
  8. package/assets/hooks/browser-device-id.sh +2 -0
  9. package/assets/hooks/browser-guard-device-id.sh +5 -1
  10. package/assets/hooks/browser-guard-no-asking.sh +5 -1
  11. package/assets/hooks/browser-guard-no-listing.sh +2 -0
  12. package/assets/hooks/browser-guard-no-other-drivers.sh +7 -3
  13. package/assets/hooks/browser-guard-require-select.sh +6 -2
  14. package/assets/hooks/claim-guard.sh +5 -1
  15. package/assets/hooks/commit-msg.sh +2 -0
  16. package/assets/hooks/conscience-guard.sh +5 -1
  17. package/assets/hooks/constitution-index.sh +2 -0
  18. package/assets/hooks/dev-server-guard.sh +7 -3
  19. package/assets/hooks/dispatch.sh +69 -0
  20. package/assets/hooks/docs-guard.sh +8 -4
  21. package/assets/hooks/exam-guard.sh +7 -3
  22. package/assets/hooks/git-guard-delivery-signature.sh +2 -0
  23. package/assets/hooks/git-guard-delivery.sh +39 -5
  24. package/assets/hooks/git-guard-main.sh +8 -4
  25. package/assets/hooks/git-guard-push-tests.sh +8 -4
  26. package/assets/hooks/glossary-load.sh +2 -0
  27. package/assets/hooks/grill-gate.sh +6 -2
  28. package/assets/hooks/handoff-entry-guard.sh +6 -2
  29. package/assets/hooks/handoff-write.sh +124 -0
  30. package/assets/hooks/hook-input.sh +54 -0
  31. package/assets/hooks/lint-after-edit.sh +7 -3
  32. package/assets/hooks/observe.sh +2 -0
  33. package/assets/hooks/postmortem-guard.sh +5 -1
  34. package/assets/hooks/proposal-guard.sh +5 -1
  35. package/assets/hooks/prose-style-guard.sh +7 -3
  36. package/assets/hooks/qa-dataid-guard.sh +6 -2
  37. package/assets/hooks/rerun-guard.sh +7 -3
  38. package/assets/hooks/reuse-first-guard.sh +7 -3
  39. package/assets/hooks/roles.sh +2 -0
  40. package/assets/hooks/rule-article.sh +99 -0
  41. package/assets/hooks/skill-gate-layers.sh +2 -0
  42. package/assets/hooks/skill-gate-rearm.sh +5 -1
  43. package/assets/hooks/skill-gate.sh +25 -2
  44. package/assets/hooks/skill-loaded.sh +5 -1
  45. package/assets/hooks/sql-guard-parse.sh +2 -0
  46. package/assets/hooks/sql-guard-request.sh +4 -1
  47. package/assets/hooks/sql-guard-target.sh +2 -0
  48. package/assets/hooks/sql-guard-write.sh +2 -0
  49. package/assets/hooks/sql-guard.sh +6 -2
  50. package/assets/hooks/task-context-load.sh +2 -0
  51. package/assets/hooks/task-flow-guard.sh +8 -4
  52. package/assets/hooks/turn-entry-load.sh +62 -0
  53. package/assets/hooks/turn-exit-guard.sh +44 -17
  54. package/assets/hooks/utf8.sh +35 -0
  55. package/assets/hooks/waiting-turn-guard.sh +5 -1
  56. package/assets/hooks/window-fill-guard.sh +37 -5
  57. package/assets/laws/work-conduct.md +34 -9
  58. package/assets/patterns/dependencies-upgrade.md +1 -1
  59. package/assets/patterns/doc-style-write.md +3 -3
  60. package/assets/patterns/git-workflow-commit.azure.md +2 -202
  61. package/assets/patterns/git-workflow-commit.github.md +2 -258
  62. package/assets/patterns/git-workflow-commit.gitlab.md +1 -217
  63. package/assets/patterns/git-workflow-docker.md +3 -3
  64. package/assets/patterns/git-workflow-merge.md +3 -2
  65. package/assets/patterns/git-workflow-migration.md +3 -3
  66. package/assets/patterns/git-workflow-pr.azure.md +224 -0
  67. package/assets/patterns/git-workflow-pr.github.md +280 -0
  68. package/assets/patterns/git-workflow-pr.gitlab.md +240 -0
  69. package/assets/patterns/git-workflow-restart.md +3 -3
  70. package/assets/patterns/git-workflow-secrets.md +3 -3
  71. package/assets/patterns/task-flow-archive.md +193 -0
  72. package/assets/patterns/task-flow-close.md +11 -160
  73. package/assets/patterns/task-flow-handoff.md +22 -4
  74. package/assets/patterns/task-flow-resume.md +6 -0
  75. package/assets/patterns/task-flow-start.md +41 -0
  76. package/assets/patterns/turn-entry-map.md +81 -0
  77. package/assets/pitfalls/doc-style.md +80 -0
  78. package/assets/pitfalls/git-workflow.azure.md +50 -0
  79. package/assets/pitfalls/git-workflow.github.md +78 -0
  80. package/assets/pitfalls/git-workflow.gitlab.md +49 -0
  81. package/assets/pitfalls/spec-driven.md +36 -0
  82. package/assets/pitfalls/styling-bem.md +45 -0
  83. package/assets/pitfalls/task-flow.md +62 -0
  84. package/assets/pitfalls/testing.md +70 -0
  85. package/assets/rules/deploy-flow.azure.md +106 -0
  86. package/assets/rules/deploy-flow.github.md +113 -0
  87. package/assets/rules/deploy-flow.gitlab.md +108 -0
  88. package/assets/rules/doc-style.md +25 -76
  89. package/assets/rules/git-workflow.azure.md +6 -92
  90. package/assets/rules/git-workflow.github.md +14 -127
  91. package/assets/rules/git-workflow.gitlab.md +6 -93
  92. package/assets/rules/spec-driven.md +39 -30
  93. package/assets/rules/styling-bem.md +20 -39
  94. package/assets/rules/task-flow.md +17 -186
  95. package/assets/rules/testing.md +3 -64
  96. package/assets/rules/turn-conduct.md +206 -0
  97. package/assets/rules/turn-entry.md +93 -0
  98. package/assets/rules/typescript-conventions.md +15 -0
  99. package/assets/skills/agent-kit.md +35 -12
  100. package/assets/templates/pitfalls.md +10 -0
  101. package/assets/templates/rule.md +5 -3
  102. package/lib/assets.d.ts.map +1 -1
  103. package/lib/assets.js +6 -1
  104. package/lib/assets.js.map +1 -1
  105. package/lib/cargo.d.ts +42 -0
  106. package/lib/cargo.d.ts.map +1 -1
  107. package/lib/cargo.js +2 -0
  108. package/lib/cargo.js.map +1 -1
  109. package/lib/cascade.d.ts.map +1 -1
  110. package/lib/cascade.js +19 -1
  111. package/lib/cascade.js.map +1 -1
  112. package/lib/commands.d.ts.map +1 -1
  113. package/lib/commands.js +65 -4
  114. package/lib/commands.js.map +1 -1
  115. package/lib/config.d.ts +16 -1
  116. package/lib/config.d.ts.map +1 -1
  117. package/lib/config.js +8 -0
  118. package/lib/config.js.map +1 -1
  119. package/lib/hooks-map.d.ts +13 -0
  120. package/lib/hooks-map.d.ts.map +1 -1
  121. package/lib/hooks-map.js +33 -1
  122. package/lib/hooks-map.js.map +1 -1
  123. package/lib/observations.d.ts +35 -1
  124. package/lib/observations.d.ts.map +1 -1
  125. package/lib/observations.js +14 -2
  126. package/lib/observations.js.map +1 -1
  127. package/lib/ship.d.ts +2 -0
  128. package/lib/ship.d.ts.map +1 -1
  129. package/lib/ship.js +2 -0
  130. package/lib/ship.js.map +1 -1
  131. package/lib/thresholds.d.ts +49 -0
  132. package/lib/thresholds.d.ts.map +1 -0
  133. package/lib/thresholds.js +151 -0
  134. package/lib/thresholds.js.map +1 -0
  135. package/package.json +1 -1
  136. package/rt-tools-agent-kit-0.12.0.tgz +0 -0
  137. package/assets/commands/agent-kit-digest.md +0 -88
  138. package/assets/commands/rules-review.md +0 -98
  139. package/rt-tools-agent-kit-0.10.0.tgz +0 -0
@@ -0,0 +1,49 @@
1
+ /** Пороги, объявленные деревом. Размер окна не объявлен — стража нет, и судить нечего. */
2
+ export interface IThresholds {
3
+ /** Размер окна захода в токенах: `RT_WINDOW_TOKENS`. */
4
+ readonly window: number;
5
+ /** Доля окна, на которой страж напоминает: `RT_WINDOW_WARN_PCT`. */
6
+ readonly warnPct: number;
7
+ /** Доля окна, на которой страж отбивает работу: `RT_WINDOW_STOP_PCT`. */
8
+ readonly stopPct: number;
9
+ /** Запас между порогом сжатия и порогом остановки: `RT_WINDOW_MARGIN_PCT`. */
10
+ readonly marginPct: number;
11
+ /** Размер окна автосжатия: настройка `autoCompactWindow`. Не объявлен — `null`. */
12
+ readonly compactWindow: number | null;
13
+ /** Доля, на которой приходит сжатие: `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE`. Не объявлена — `null`. */
14
+ readonly compactPct: number | null;
15
+ }
16
+ /** Расхождение пары: что с чем разъехалось, какими числами и чем это кончится для захода. */
17
+ export interface IThresholdDrift {
18
+ /** Что разошлось, словами читателя. */
19
+ readonly what: string;
20
+ /** Что объявлено стражу. */
21
+ readonly guard: string;
22
+ /** Что объявлено сжатию. */
23
+ readonly compact: string;
24
+ /** Чем это кончится для захода. Пусто у расхождения, которое говорит само за себя. */
25
+ readonly why: string;
26
+ }
27
+ /**
28
+ * Что дерево объявило о порогах.
29
+ *
30
+ * Настройку читаем разбором и только им: пороги лежат полями объекта, и вынуть их из текста
31
+ * поиском значило бы гадать. Не разобралась — молчим целиком, как молчит карта хуков: назвать
32
+ * расхождением непрочитанное хуже, чем не назвать ничего.
33
+ */
34
+ export declare function readThresholds(root: string): IThresholds | null;
35
+ /**
36
+ * Чем пара стража разошлась с парой сжатия.
37
+ *
38
+ * Незаданное расхождением не считается: дерево вправе не задавать порога сжатия вовсе — тогда
39
+ * его назначает инструмент, и сказать об этом надо один раз, а не двумя строками о разнице.
40
+ *
41
+ * Долю судит расстояние, а не равенство. Три случая дают расхождение, и у каждого свой исход
42
+ * для захода: сжатие выше остановки — страж отбивает раньше, чем клиент успевает начать;
43
+ * сжатие вровень с остановкой — гонка, которую страж выигрывает; сжатие ниже, но ближе
44
+ * объявленного запаса — клиент начать успевает, а докончить нет.
45
+ */
46
+ export declare function thresholdDrift(thresholds: IThresholds): readonly IThresholdDrift[];
47
+ /** Раздел разбора состояния: числа порогов и то, что о них известно. */
48
+ export declare function thresholdLines(root: string): string[];
49
+ //# sourceMappingURL=thresholds.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thresholds.d.ts","sourceRoot":"","sources":["../../../projects/agent-kit/src/lib/thresholds.ts"],"names":[],"mappings":"AA0CA,0FAA0F;AAC1F,MAAM,WAAW,WAAW;IACxB,wDAAwD;IACxD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,oEAAoE;IACpE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,yEAAyE;IACzE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,8EAA8E;IAC9E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,mFAAmF;IACnF,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,kGAAkG;IAClG,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC;AAED,6FAA6F;AAC7F,MAAM,WAAW,eAAe;IAC5B,uCAAuC;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4BAA4B;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,4BAA4B;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,sFAAsF;IACtF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACxB;AAYD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CA2B/D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,WAAW,GAAG,SAAS,eAAe,EAAE,CA0ClF;AAED,wEAAwE;AACxE,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAkCrD"}
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Пороги окна захода: где заход останавливается и где инструмент сжимает контекст сам.
3
+ *
4
+ * Чисел два, и живут они в разных местах чужой настройки. Размер окна и доля, на которой страж
5
+ * останавливает заход, приходят переменными окружения — их читает профиль дерева. Порог, на
6
+ * котором инструмент сжимает контекст, задаётся своей парой: размером окна автосжатия и долей в
7
+ * процентах. Пакет ни тем ни другим не владеет — окно принадлежит дереву.
8
+ *
9
+ * Разъехавшись, пары дают заход, который либо сжимается раньше, чем передача написана, либо
10
+ * доживает до предела окна и роняет работу. Заметить это нечем: обе стороны по отдельности
11
+ * выглядят настроенными, а расхождение видно только тому, кто положит их рядом. Здесь их и
12
+ * кладут рядом — разбор состояния раскладки печатает числа и называет разошедшееся.
13
+ *
14
+ * Сведёнными считаются РАЗВЕДЁННЫЕ доли, а не совпавшие. Порог сжатия обязан стоять ниже порога
15
+ * остановки: первым обязано срабатывать то, что заход продолжает, а не то, что его
16
+ * останавливает. Совпавшая пара — гонка, и выигрывает её страж: он стоит на вызове инструмента,
17
+ * а сжатие приходит между ходами. Ровно так заход и вставал на пороге вместо того, чтобы
18
+ * продолжиться сжатым, — при том что прежняя сверка обе стороны считала настроенными и молчала.
19
+ *
20
+ * Насколько ниже — своё число дерева, `RT_WINDOW_MARGIN_PCT`. Запас объявляется, а не выводится
21
+ * разницей: сжатие идёт не мгновенно, и разница в один процент требование «ниже» удовлетворяет,
22
+ * а работу не спасает.
23
+ *
24
+ * Размер окна при этом сверяется по-прежнему на равенство: это одно и то же окно, названное в
25
+ * двух местах, и разные числа там означают, что одна из сторон считает долю не от того.
26
+ *
27
+ * Дерево, не объявившее размера окна, стража не получает вовсе, и судить у него нечего: раздел
28
+ * молчит целиком, а не краснеет отсутствием.
29
+ */
30
+ import { existsSync, readFileSync } from 'node:fs';
31
+ import { join } from 'node:path';
32
+ import { SETTINGS_PATH } from './hooks-map.js';
33
+ /** Доля окна, на которой страж напоминает выбрать точку остановки. Умолчание профиля. */
34
+ const WARN_PCT_DEFAULT = 40;
35
+ /** Доля окна, на которой страж отбивает всё, кроме закрытия захода. Умолчание профиля. */
36
+ const STOP_PCT_DEFAULT = 50;
37
+ /** На сколько долей окна порог сжатия обязан стоять ниже порога остановки. Умолчание профиля. */
38
+ const MARGIN_PCT_DEFAULT = 5;
39
+ /**
40
+ * Число из строки настройки. Пусто, не число, ноль и меньше — ничего: значение, которого нельзя
41
+ * посчитать, объявленным не считается, иначе расхождением станет опечатка, а не расхождение.
42
+ */
43
+ function numberOf(value) {
44
+ const parsed = typeof value === 'number' ? value : Number.parseInt(String(value ?? ''), 10);
45
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
46
+ }
47
+ /**
48
+ * Что дерево объявило о порогах.
49
+ *
50
+ * Настройку читаем разбором и только им: пороги лежат полями объекта, и вынуть их из текста
51
+ * поиском значило бы гадать. Не разобралась — молчим целиком, как молчит карта хуков: назвать
52
+ * расхождением непрочитанное хуже, чем не назвать ничего.
53
+ */
54
+ export function readThresholds(root) {
55
+ const path = join(root, SETTINGS_PATH);
56
+ if (!existsSync(path)) {
57
+ return null;
58
+ }
59
+ let settings;
60
+ try {
61
+ settings = JSON.parse(readFileSync(path, 'utf8'));
62
+ }
63
+ catch {
64
+ return null;
65
+ }
66
+ const env = settings['env'] ?? {};
67
+ const windowTokens = numberOf(env['RT_WINDOW_TOKENS']);
68
+ if (windowTokens === null) {
69
+ return null;
70
+ }
71
+ return {
72
+ window: windowTokens,
73
+ warnPct: numberOf(env['RT_WINDOW_WARN_PCT']) ?? WARN_PCT_DEFAULT,
74
+ stopPct: numberOf(env['RT_WINDOW_STOP_PCT']) ?? STOP_PCT_DEFAULT,
75
+ marginPct: numberOf(env['RT_WINDOW_MARGIN_PCT']) ?? MARGIN_PCT_DEFAULT,
76
+ compactWindow: numberOf(settings['autoCompactWindow']),
77
+ compactPct: numberOf(env['CLAUDE_AUTOCOMPACT_PCT_OVERRIDE']),
78
+ };
79
+ }
80
+ /**
81
+ * Чем пара стража разошлась с парой сжатия.
82
+ *
83
+ * Незаданное расхождением не считается: дерево вправе не задавать порога сжатия вовсе — тогда
84
+ * его назначает инструмент, и сказать об этом надо один раз, а не двумя строками о разнице.
85
+ *
86
+ * Долю судит расстояние, а не равенство. Три случая дают расхождение, и у каждого свой исход
87
+ * для захода: сжатие выше остановки — страж отбивает раньше, чем клиент успевает начать;
88
+ * сжатие вровень с остановкой — гонка, которую страж выигрывает; сжатие ниже, но ближе
89
+ * объявленного запаса — клиент начать успевает, а докончить нет.
90
+ */
91
+ export function thresholdDrift(thresholds) {
92
+ const drift = [];
93
+ if (thresholds.compactWindow !== null && thresholds.compactWindow !== thresholds.window) {
94
+ drift.push({
95
+ what: 'размер окна',
96
+ guard: String(thresholds.window),
97
+ compact: String(thresholds.compactWindow),
98
+ why: 'доля считается не от того же окна',
99
+ });
100
+ }
101
+ const compactPct = thresholds.compactPct;
102
+ if (compactPct === null) {
103
+ return drift;
104
+ }
105
+ const gap = thresholds.stopPct - compactPct;
106
+ const tooHigh = 'сжатие стоит выше остановки: страж отбивает заход раньше, чем приходит сжатие';
107
+ const tied = 'пороги совпали: кто сработает первым, не назначено, и выигрывает страж';
108
+ if (gap <= 0) {
109
+ drift.push({
110
+ what: 'доля окна',
111
+ guard: `${thresholds.stopPct}%`,
112
+ compact: `${compactPct}%`,
113
+ why: gap < 0 ? tooHigh : tied,
114
+ });
115
+ return drift;
116
+ }
117
+ if (gap < thresholds.marginPct) {
118
+ drift.push({
119
+ what: 'запас между порогами',
120
+ guard: `${thresholds.marginPct}% объявлено`,
121
+ compact: `${gap}% на деле`,
122
+ why: 'сжатие идёт не мгновенно и может не успеть до порога остановки',
123
+ });
124
+ }
125
+ return drift;
126
+ }
127
+ /** Раздел разбора состояния: числа порогов и то, что о них известно. */
128
+ export function thresholdLines(root) {
129
+ const thresholds = readThresholds(root);
130
+ if (!thresholds) {
131
+ return [];
132
+ }
133
+ const lines = [
134
+ `окно захода: ${thresholds.window} токенов, напоминание ${thresholds.warnPct}%, остановка ${thresholds.stopPct}%`,
135
+ ];
136
+ if (thresholds.compactWindow === null && thresholds.compactPct === null) {
137
+ lines.push(' порог сжатия деревом не задан — его назначает инструмент, и передача пишется когда придётся', ` объяви в \`${SETTINGS_PATH}\`: \`autoCompactWindow\` числом ${thresholds.window}, а \`CLAUDE_AUTOCOMPACT_PCT_OVERRIDE\` — числом ${thresholds.stopPct - thresholds.marginPct}`);
138
+ return lines;
139
+ }
140
+ const drift = thresholdDrift(thresholds);
141
+ if (!drift.length) {
142
+ lines.push(` порог сжатия ниже порога остановки на ${thresholds.marginPct}% и более: сжатие приходит первым, страж остаётся страховкой`);
143
+ return lines;
144
+ }
145
+ lines.push(' порог сжатия разошёлся с порогом остановки:');
146
+ for (const one of drift) {
147
+ lines.push(` ${one.what}: у стража ${one.guard}, у сжатия ${one.compact}`, ` ${one.why}`);
148
+ }
149
+ return lines;
150
+ }
151
+ //# sourceMappingURL=thresholds.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thresholds.js","sourceRoot":"","sources":["../../../projects/agent-kit/src/lib/thresholds.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Пороги окна захода: где заход останавливается и где инструмент сжимает контекст сам.\n *\n * Чисел два, и живут они в разных местах чужой настройки. Размер окна и доля, на которой страж\n * останавливает заход, приходят переменными окружения — их читает профиль дерева. Порог, на\n * котором инструмент сжимает контекст, задаётся своей парой: размером окна автосжатия и долей в\n * процентах. Пакет ни тем ни другим не владеет — окно принадлежит дереву.\n *\n * Разъехавшись, пары дают заход, который либо сжимается раньше, чем передача написана, либо\n * доживает до предела окна и роняет работу. Заметить это нечем: обе стороны по отдельности\n * выглядят настроенными, а расхождение видно только тому, кто положит их рядом. Здесь их и\n * кладут рядом — разбор состояния раскладки печатает числа и называет разошедшееся.\n *\n * Сведёнными считаются РАЗВЕДЁННЫЕ доли, а не совпавшие. Порог сжатия обязан стоять ниже порога\n * остановки: первым обязано срабатывать то, что заход продолжает, а не то, что его\n * останавливает. Совпавшая пара — гонка, и выигрывает её страж: он стоит на вызове инструмента,\n * а сжатие приходит между ходами. Ровно так заход и вставал на пороге вместо того, чтобы\n * продолжиться сжатым, — при том что прежняя сверка обе стороны считала настроенными и молчала.\n *\n * Насколько ниже — своё число дерева, `RT_WINDOW_MARGIN_PCT`. Запас объявляется, а не выводится\n * разницей: сжатие идёт не мгновенно, и разница в один процент требование «ниже» удовлетворяет,\n * а работу не спасает.\n *\n * Размер окна при этом сверяется по-прежнему на равенство: это одно и то же окно, названное в\n * двух местах, и разные числа там означают, что одна из сторон считает долю не от того.\n *\n * Дерево, не объявившее размера окна, стража не получает вовсе, и судить у него нечего: раздел\n * молчит целиком, а не краснеет отсутствием.\n */\nimport { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { SETTINGS_PATH } from './hooks-map.js';\n\n/** Доля окна, на которой страж напоминает выбрать точку остановки. Умолчание профиля. */\nconst WARN_PCT_DEFAULT: number = 40;\n\n/** Доля окна, на которой страж отбивает всё, кроме закрытия захода. Умолчание профиля. */\nconst STOP_PCT_DEFAULT: number = 50;\n\n/** На сколько долей окна порог сжатия обязан стоять ниже порога остановки. Умолчание профиля. */\nconst MARGIN_PCT_DEFAULT: number = 5;\n\n/** Пороги, объявленные деревом. Размер окна не объявлен — стража нет, и судить нечего. */\nexport interface IThresholds {\n /** Размер окна захода в токенах: `RT_WINDOW_TOKENS`. */\n readonly window: number;\n /** Доля окна, на которой страж напоминает: `RT_WINDOW_WARN_PCT`. */\n readonly warnPct: number;\n /** Доля окна, на которой страж отбивает работу: `RT_WINDOW_STOP_PCT`. */\n readonly stopPct: number;\n /** Запас между порогом сжатия и порогом остановки: `RT_WINDOW_MARGIN_PCT`. */\n readonly marginPct: number;\n /** Размер окна автосжатия: настройка `autoCompactWindow`. Не объявлен — `null`. */\n readonly compactWindow: number | null;\n /** Доля, на которой приходит сжатие: `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE`. Не объявлена — `null`. */\n readonly compactPct: number | null;\n}\n\n/** Расхождение пары: что с чем разъехалось, какими числами и чем это кончится для захода. */\nexport interface IThresholdDrift {\n /** Что разошлось, словами читателя. */\n readonly what: string;\n /** Что объявлено стражу. */\n readonly guard: string;\n /** Что объявлено сжатию. */\n readonly compact: string;\n /** Чем это кончится для захода. Пусто у расхождения, которое говорит само за себя. */\n readonly why: string;\n}\n\n/**\n * Число из строки настройки. Пусто, не число, ноль и меньше — ничего: значение, которого нельзя\n * посчитать, объявленным не считается, иначе расхождением станет опечатка, а не расхождение.\n */\nfunction numberOf(value: unknown): number | null {\n const parsed: number = typeof value === 'number' ? value : Number.parseInt(String(value ?? ''), 10);\n\n return Number.isFinite(parsed) && parsed > 0 ? parsed : null;\n}\n\n/**\n * Что дерево объявило о порогах.\n *\n * Настройку читаем разбором и только им: пороги лежат полями объекта, и вынуть их из текста\n * поиском значило бы гадать. Не разобралась — молчим целиком, как молчит карта хуков: назвать\n * расхождением непрочитанное хуже, чем не назвать ничего.\n */\nexport function readThresholds(root: string): IThresholds | null {\n const path: string = join(root, SETTINGS_PATH);\n if (!existsSync(path)) {\n return null;\n }\n\n let settings: Record<string, unknown>;\n try {\n settings = JSON.parse(readFileSync(path, 'utf8')) as Record<string, unknown>;\n } catch {\n return null;\n }\n\n const env: Record<string, unknown> = (settings['env'] as Record<string, unknown>) ?? {};\n const windowTokens: number | null = numberOf(env['RT_WINDOW_TOKENS']);\n if (windowTokens === null) {\n return null;\n }\n\n return {\n window: windowTokens,\n warnPct: numberOf(env['RT_WINDOW_WARN_PCT']) ?? WARN_PCT_DEFAULT,\n stopPct: numberOf(env['RT_WINDOW_STOP_PCT']) ?? STOP_PCT_DEFAULT,\n marginPct: numberOf(env['RT_WINDOW_MARGIN_PCT']) ?? MARGIN_PCT_DEFAULT,\n compactWindow: numberOf(settings['autoCompactWindow']),\n compactPct: numberOf(env['CLAUDE_AUTOCOMPACT_PCT_OVERRIDE']),\n };\n}\n\n/**\n * Чем пара стража разошлась с парой сжатия.\n *\n * Незаданное расхождением не считается: дерево вправе не задавать порога сжатия вовсе — тогда\n * его назначает инструмент, и сказать об этом надо один раз, а не двумя строками о разнице.\n *\n * Долю судит расстояние, а не равенство. Три случая дают расхождение, и у каждого свой исход\n * для захода: сжатие выше остановки — страж отбивает раньше, чем клиент успевает начать;\n * сжатие вровень с остановкой — гонка, которую страж выигрывает; сжатие ниже, но ближе\n * объявленного запаса — клиент начать успевает, а докончить нет.\n */\nexport function thresholdDrift(thresholds: IThresholds): readonly IThresholdDrift[] {\n const drift: IThresholdDrift[] = [];\n\n if (thresholds.compactWindow !== null && thresholds.compactWindow !== thresholds.window) {\n drift.push({\n what: 'размер окна',\n guard: String(thresholds.window),\n compact: String(thresholds.compactWindow),\n why: 'доля считается не от того же окна',\n });\n }\n\n const compactPct: number | null = thresholds.compactPct;\n if (compactPct === null) {\n return drift;\n }\n\n const gap: number = thresholds.stopPct - compactPct;\n const tooHigh: string = 'сжатие стоит выше остановки: страж отбивает заход раньше, чем приходит сжатие';\n const tied: string = 'пороги совпали: кто сработает первым, не назначено, и выигрывает страж';\n\n if (gap <= 0) {\n drift.push({\n what: 'доля окна',\n guard: `${thresholds.stopPct}%`,\n compact: `${compactPct}%`,\n why: gap < 0 ? tooHigh : tied,\n });\n\n return drift;\n }\n\n if (gap < thresholds.marginPct) {\n drift.push({\n what: 'запас между порогами',\n guard: `${thresholds.marginPct}% объявлено`,\n compact: `${gap}% на деле`,\n why: 'сжатие идёт не мгновенно и может не успеть до порога остановки',\n });\n }\n\n return drift;\n}\n\n/** Раздел разбора состояния: числа порогов и то, что о них известно. */\nexport function thresholdLines(root: string): string[] {\n const thresholds: IThresholds | null = readThresholds(root);\n if (!thresholds) {\n return [];\n }\n\n const lines: string[] = [\n `окно захода: ${thresholds.window} токенов, напоминание ${thresholds.warnPct}%, остановка ${thresholds.stopPct}%`,\n ];\n\n if (thresholds.compactWindow === null && thresholds.compactPct === null) {\n lines.push(\n ' порог сжатия деревом не задан — его назначает инструмент, и передача пишется когда придётся',\n ` объяви в \\`${SETTINGS_PATH}\\`: \\`autoCompactWindow\\` числом ${thresholds.window}, а \\`CLAUDE_AUTOCOMPACT_PCT_OVERRIDE\\` — числом ${thresholds.stopPct - thresholds.marginPct}`\n );\n\n return lines;\n }\n\n const drift: readonly IThresholdDrift[] = thresholdDrift(thresholds);\n if (!drift.length) {\n lines.push(\n ` порог сжатия ниже порога остановки на ${thresholds.marginPct}% и более: сжатие приходит первым, страж остаётся страховкой`\n );\n\n return lines;\n }\n\n lines.push(' порог сжатия разошёлся с порогом остановки:');\n for (const one of drift) {\n lines.push(` ${one.what}: у стража ${one.guard}, у сжатия ${one.compact}`, ` ${one.why}`);\n }\n\n return lines;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rt-tools/agent-kit",
3
- "version": "0.10.0",
3
+ "version": "0.12.0",
4
4
  "description": "Переносимый слой правил для агента: законы, хуки, проверки и агенты, раскладываемые в репозиторий одной командой",
5
5
  "author": "RT Team",
6
6
  "license": "Apache-2.0",
Binary file
@@ -1,88 +0,0 @@
1
- ---
2
- description: Свести накопленные предложения и наблюдения в правки ресурсов пакета правил
3
- argument-hint: '[пусто | --days N]'
4
- ---
5
-
6
- Собери предложения, пришедшие из деревьев, и скажи, что из них становится правкой пакета.
7
- Отрезок от пользователя: `$ARGUMENTS` (без довода — три дня).
8
-
9
- Зовётся **в репозитории самого пакета**, а не в дереве, где он стоит: здесь лежат ресурсы,
10
- которые предстоит править, и видно всех потребителей сразу. В чужом дереве команда бессмысленна
11
- — там есть только своя половина картины.
12
-
13
- ## 1. Собери, что пришло
14
-
15
- Груз уезжает в приём, а не в очередь работ: сводка говорит о рабочих привычках команды, и в
16
- открытой очереди это выложено всему свету. Записи приёма читает его админка; пока её нет,
17
- собранное читается запросом к его хранилищу — как именно, сказано в компаньоне этой команды.
18
-
19
- Записи, заведённые прежним порядком, лежат в очереди работ и никуда не делись:
20
-
21
- ```bash
22
- gh issue list --label agent-kit-feedback --state all --limit 100 \
23
- --json number,title,body,createdAt
24
- ```
25
-
26
- Помощник хостинга и учётная запись машинной работы у каждого дерева свои — как их звать здесь,
27
- сказано в компаньоне правила `git-workflow`.
28
-
29
- В каждой записи — ресурс, место, повод и готовый текст. Признак дерева, приехавший с грузом,
30
- адреса дерева не выдаёт: он считается хешем и по нему различают деревья, а не находят их.
31
-
32
- Своё дерево тоже потребитель — его наблюдения читаются прямо:
33
-
34
- ```bash
35
- npx agent-kit stats --days <отрезок> --json
36
- ```
37
-
38
- ## 2. Раздели повторившееся и разовое
39
-
40
- Это и есть работа сведения; всё остальное — оформление.
41
-
42
- - **Пришло об одном ресурсе из двух и более записей** — правка пакета. Разные деревья
43
- споткнулись об одно и то же место, и чинить его надо там, откуда оно к ним приехало.
44
- - **Пришло однажды и называет то, чего у других нет** — надстройка того дерева, а не пакет.
45
- Скажи это прямо и назови, куда именно: `overrides/<ресурс>` для текстов, карта гейта и
46
- профиль — для родов файлов и команд.
47
- - **Пришло однажды, но верно любому дереву** — правка пакета. Числа записей мало: правило,
48
- которое молчит о важном, молчит у всех, а споткнулся о него пока один.
49
-
50
- Ресурс, о котором пришли **противоречащие** предложения, в правку не идёт вовсе: неси оба
51
- владельцу. Слой правил, который говорит два разных, хуже слоя, который молчит.
52
-
53
- ## 3. Посмотри, что говорят наблюдения
54
-
55
- Сводка отвечает на то, чего в предложениях нет:
56
-
57
- - **правило, разложенное и не загруженное ни разу** — кандидат на сокращение или на запись в
58
- карте гейта: правило, которого гейт не требует, никто и не откроет;
59
- - **правило, которое гейт отбивает чаще прочих** — его либо забывают, либо оно требуется не
60
- там; посмотри род правки в той же сводке;
61
- - **гард, отказывающий чаще прочих** — либо место поставки раз за разом делают не так, либо
62
- отказ не называет, чем он снимается.
63
-
64
- ## 4. Принеси правки
65
-
66
- По каждой — ресурс, место, готовый текст и число записей, из которых она вышла. Не правь ничего
67
- сам: решение принимает владелец, а работа идёт обычным ходом — задача, ветка, папка задачи.
68
-
69
- Заведи задачу на то, что владелец принял:
70
-
71
- ```bash
72
- npm run task:new -- --title '<что не так>' --slug <короткое-имя> --label enhancement < тело.md
73
- ```
74
-
75
- Записи, вошедшие в задачу, закрой ссылкой на неё:
76
-
77
- ```bash
78
- gh issue close <номер> --comment 'Вошло в #<номер задачи>.'
79
- ```
80
-
81
- ## 5. Черновик записи в журнал изменений
82
-
83
- Собери его сразу, пока видно, из чего правка выросла: заголовок коммита по формату дерева и
84
- одна фраза о том, что менялось и почему. Журнал изменений при выпуске собирается из заголовков,
85
- и переписывать их задним числом — работа заново.
86
-
87
- **Выпуск отсюда не запускается.** Это отдельное решение владельца: слияние PR пакета не
88
- публикует. Скажи, что накопилось на выпуск, и остановись.
@@ -1,98 +0,0 @@
1
- ---
2
- description: Смысловое ревью семьи текстов слоя правил — закон, его правила и паттерны при них
3
- argument-hint: '<имя закона>'
4
- ---
5
-
6
- Прогони смысловое ревью одной семьи текстов пакета правил. Семья: `$ARGUMENTS`
7
-
8
- Зовётся **в репозитории самого пакета**, а не в дереве, где он стоит: судятся исходные тексты
9
- ресурсов, и лежат они только здесь. В чужом дереве лежит разложенная копия выбранных ресурсов, а
10
- не семья целиком, и путей, по которым команда ходит, в нём нет вовсе: обход по ним вернёт
11
- пустоту, неотличимую от «такого закона не бывает». Каталог ресурсов ниже назван так, как он
12
- зовётся в репозитории пакета.
13
-
14
- Считаемое ловит проверка полноты текстов — недостающий раздел, правило без паттерна, имя соседа,
15
- которому в наборе ничего не отвечает. Здесь ищется то, чего она не считает: два текста,
16
- говорящих об одном разное, и случай, которого не назвал ни один. Ответ роли не повторяется от
17
- запуска к запуску, поэтому в гейт он не идёт и ветку не отбивает.
18
-
19
- ## 1. Пойми, какая семья
20
-
21
- Семья зовётся именем закона — без пути и без расширения: `work-conduct`, `delivery`,
22
- `project-documentation`.
23
-
24
- ```bash
25
- ls projects/agent-kit/assets/laws/*.md projects/agent-kit/assets/laws/*/*.md
26
- ```
27
-
28
- **Имени нет** — назови человеку перечень имён и остановись. Догадываться по похожести нельзя:
29
- ревью уйдёт на чужую семью, и его находки человек примет за находки о своей.
30
-
31
- **Названо несколько** — гони по одной, по очереди, и ответы не смешивай: находка семьи читается
32
- вместе с её законом, а сваленные в кучу они теряют адрес.
33
-
34
- **Довода нет вовсе** — потребуй имя и напечатай перечень. Умолчания здесь нет: «первый
35
- попавшийся закон» даёт прогон, неотличимый от осмысленного.
36
-
37
- **Закон лежит в слое приложения** — это законный случай, а не промах: у денег, локалей и доступа
38
- семья такая же. Читается он оттуда же, где лежит.
39
-
40
- ## 2. Собери семью
41
-
42
- Правило принадлежит закону полем `law:`, паттерн правилу — полем `rule:`. Приставка имени
43
- ненадёжна: её несут не все паттерны.
44
-
45
- ```bash
46
- LAW=<имя закона>
47
- grep -l "^law: $LAW\$" projects/agent-kit/assets/rules/*.md
48
- ```
49
-
50
- Дальше по каждому найденному правилу — его паттерны. Имя правила для поиска берётся голым: без
51
- вида и без требования — оба стоят суффиксами в имени файла, а поле `rule:` у паттерна несёт
52
- только само имя.
53
-
54
- ```bash
55
- RULE=<имя правила: первое слово имени файла, до первой точки>
56
- grep -l "^rule: $RULE\$" projects/agent-kit/assets/patterns/*.md
57
- ```
58
-
59
- **Виды берутся все.** `git-workflow.github`, `git-workflow.gitlab`, `git-workflow.azure` — три
60
- редакции одного правила: дерево раскладывает одну, а расходятся они молча.
61
-
62
- **Суффикс требования — не вид.** `entity-conventions.needs-admin`, `observability.needs-app` —
63
- это правила, которые дерево берёт, только когда объявило нужную черту. Имя с этим суффиксом в
64
- поле `rule:` не стоит ни у одного паттерна: поиск по нему возвращает пустоту, и семья уезжает в
65
- ревью без паттернов вовсе — молча, потому что пустой ответ выглядит как «паттернов нет».
66
-
67
- **У закона нет ни одного правила** — скажи это человеку и остановись. Читать один закон нечем:
68
- расхождение живёт между двумя текстами, а пробел уровня статьи без правил под ней — не находка
69
- ревью, а отсутствие целого слоя. Сам по себе такой закон стоит разговора: его находит и проверка
70
- полноты текстов, и она же скажет, сколько их.
71
-
72
- ## 3. Запусти роль
73
-
74
- Инструментом `Agent`, `subagent_type: 'rules-reviewer'`. В промпт — имя закона и полный список
75
- путей: закон, все его правила со всеми видами, все паттерны при них. Список собираешь ты: роль
76
- git-команд не зовёт и историю не читает.
77
-
78
- Одна роль на семью. Веер из нескольких ролей со сведением ответов здесь не заводится: взгляд на
79
- предмет один — два текста об одном говорят разное, — а сведение превращает дословные цитаты в
80
- пересказ.
81
-
82
- ## 4. Покажи находки человеку
83
-
84
- **Как есть.** Роль возвращает цитаты дословно, и пересказ их портит: по пересказу человек не
85
- отличит настоящее расхождение от прочтения роли.
86
-
87
- Порядок сохрани: сперва расхождения — у каждого два места и две цитаты, — потом пробелы, у
88
- которых второго места нет.
89
-
90
- По каждой находке скажи своё: согласен или нет и почему. Правку не вноси — тексты правил
91
- действуют на все будущие сессии всех деревьев, и решает по ним человек.
92
-
93
- Находка, с которой человек согласился, идёт дальше двумя путями, и выбирает он:
94
-
95
- - **правится тут же** — если это правка текста пакета и она укладывается в текущую работу;
96
- - **уходит задачей** в очередь работ — если тянет за собой код, раскладку или другой закон.
97
-
98
- Пустой ответ роли — тоже результат: скажи, что находок нет, и не выдумывай их из вежливости.
Binary file