@rt-tools/agent-kit 0.13.0 → 0.15.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/README.md +17 -0
- package/assets/checks/board-runs.github.mjs +45 -0
- package/assets/checks/board.github.mjs +43 -1
- package/assets/checks/check-board.github.mjs +51 -1
- package/assets/checks/check-descriptions.mjs +123 -0
- package/assets/checks/check-dupes.mjs +31 -3
- package/assets/checks/check-file-size.mjs +47 -2
- package/assets/checks/check-turn-map.mjs +20 -3
- package/assets/checks/lib-common.mjs +12 -1
- package/assets/checks/lib-domains.mjs +1 -1
- package/assets/checks/rt-kit-checks.config.mjs +17 -1
- package/assets/checks/spec-anchors.mjs +18 -3
- package/assets/checks/spec-common.mjs +5 -1
- package/assets/checks/task-new.github.mjs +15 -3
- package/assets/defaults/project.sh +21 -16
- package/assets/defaults/turn-map.md +15 -19
- package/assets/docs/GLOSSARY.md +52 -58
- package/assets/hooks/claim-guard.sh +34 -0
- package/assets/hooks/dispatch.sh +48 -15
- package/assets/hooks/hook-input.sh +39 -0
- package/assets/hooks/rule-article.sh +12 -0
- package/assets/hooks/skill-gate.sh +5 -4
- package/assets/hooks/task-flow-guard.sh +20 -0
- package/assets/hooks/turn-exit-guard.sh +248 -8
- package/assets/hooks/waiting-turn-guard.sh +39 -3
- package/assets/laws/delivery.md +92 -104
- package/assets/laws/frontend-application.md +4 -0
- package/assets/laws/project-documentation.md +64 -68
- package/assets/laws/verifiability.md +32 -33
- package/assets/laws/work-conduct.md +167 -157
- package/assets/patterns/doc-style-sweep.md +1 -1
- package/assets/patterns/doc-style-trace.md +1 -1
- package/assets/patterns/git-workflow-commit.azure.md +1 -1
- package/assets/patterns/git-workflow-commit.github.md +7 -1
- package/assets/patterns/git-workflow-commit.gitlab.md +1 -1
- package/assets/patterns/git-workflow-docker.md +1 -1
- package/assets/patterns/git-workflow-merge.md +14 -3
- package/assets/patterns/git-workflow-pr.azure.md +1 -1
- package/assets/patterns/git-workflow-pr.github.md +1 -1
- package/assets/patterns/git-workflow-pr.gitlab.md +1 -1
- package/assets/patterns/git-workflow-restart.md +1 -1
- package/assets/patterns/git-workflow-secrets.md +1 -1
- package/assets/patterns/git-workflow-stack.md +93 -0
- package/assets/patterns/seo-page.md +1 -1
- package/assets/patterns/spec-driven-rule.md +55 -0
- package/assets/patterns/status-report-table.github.md +88 -0
- package/assets/patterns/task-flow-archive.md +3 -4
- package/assets/patterns/task-flow-close.md +6 -1
- package/assets/patterns/task-flow-start.md +17 -5
- package/assets/patterns/ts-procedure.md +1 -1
- package/assets/pitfalls/doc-style.md +5 -0
- package/assets/pitfalls/git-workflow.github.md +55 -0
- package/assets/pitfalls/task-flow.md +28 -0
- package/assets/pitfalls/testing.md +14 -0
- package/assets/pitfalls/turn-conduct.md +33 -0
- package/assets/rules/angular-patterns.md +1 -1
- package/assets/rules/api-layer.md +3 -3
- package/assets/rules/browser-verification.md +15 -1
- package/assets/rules/dependencies.md +1 -1
- package/assets/rules/deploy-flow.azure.md +1 -1
- package/assets/rules/deploy-flow.github.md +1 -1
- package/assets/rules/deploy-flow.gitlab.md +1 -1
- package/assets/rules/doc-style.md +7 -0
- package/assets/rules/entity-conventions.needs-admin.md +1 -1
- package/assets/rules/entity-models.md +1 -1
- package/assets/rules/git-workflow.azure.md +1 -1
- package/assets/rules/git-workflow.github.md +154 -181
- package/assets/rules/git-workflow.gitlab.md +1 -1
- package/assets/rules/lib-layers.md +1 -1
- package/assets/rules/observability.needs-app.md +1 -1
- package/assets/rules/platform-access.md +1 -1
- package/assets/rules/reuse-first.md +1 -1
- package/assets/rules/seo.md +4 -3
- package/assets/rules/shared-code.md +1 -1
- package/assets/rules/spec-driven.md +68 -1
- package/assets/rules/status-report.md +97 -0
- package/assets/rules/styling-bem.md +12 -0
- package/assets/rules/task-flow.md +102 -98
- package/assets/rules/testing.md +67 -66
- package/assets/rules/turn-conduct.md +155 -85
- package/assets/rules/turn-entry.md +7 -1
- package/assets/rules/typescript-conventions.md +1 -1
- package/assets/skills/agent-kit-extend.md +1 -1
- package/assets/skills/agent-kit.md +18 -1
- package/bin/agent-kit.d.ts.map +1 -1
- package/bin/agent-kit.js +25 -0
- package/bin/agent-kit.js.map +1 -1
- package/lib/cost.d.ts +44 -0
- package/lib/cost.d.ts.map +1 -0
- package/lib/cost.js +181 -0
- package/lib/cost.js.map +1 -0
- package/package.json +1 -1
- package/rt-tools-agent-kit-0.15.0.tgz +0 -0
- package/rt-tools-agent-kit-0.13.0.tgz +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: agent-kit-extend
|
|
3
|
-
description: Готовые примеры того, как дерево дописывает своё поверх пакета
|
|
3
|
+
description: Готовые примеры того, как дерево дописывает своё поверх пакета правил. Брать, когда пакетный текст говорит не то, что верно здесь, гейт требует не то правило или гард судит не по тем путям. Раскладка и настройки — скил agent-kit; форма нового скила — write-a-skill.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Как дописать своё поверх пакета
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: agent-kit
|
|
3
|
-
description: Переносимый слой правил агента — законы, правила, хуки и проверки, которые везёт пакет, а дерево настраивает надстройками. Брать, когда правится файл с шапкой rt-kit, обновляется
|
|
3
|
+
description: Переносимый слой правил агента — законы, правила, хуки и проверки, которые везёт пакет, а дерево настраивает надстройками. Брать, когда правится файл с шапкой rt-kit, обновляется пакет или отказывает сверка раскладки. Форма нового скила — write-a-skill.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Переносимый слой правил
|
|
@@ -115,6 +115,12 @@ npx agent-kit propose # отправить груз в приём: сво
|
|
|
115
115
|
**Сводка** — `agent-kit stats`. Самая ценная её строка не «чем пользовались», а **что разложено
|
|
116
116
|
и не загружено ни разу**: правило, которого никто не открыл, ничем себя не выдаёт.
|
|
117
117
|
|
|
118
|
+
**Цена** — `agent-kit cost`. Сводка говорит, чем пользовались; цена — сколько это стоило: вес
|
|
119
|
+
входа в работу, вес одного правила и вес всего слоя. Считается не файл, а то, что заход
|
|
120
|
+
получает: описание приходит ему полем, словарь и карта хода — выводом хуков. Меряется в
|
|
121
|
+
символах и байтах, на месте и без сети; чем считано, стоит в первой строке вывода, и число
|
|
122
|
+
сравнимо только со снятым той же командой.
|
|
123
|
+
|
|
118
124
|
**Предложения** приходят двумя путями. Разбор закрытой задачи — командой `/skill-curator` —
|
|
119
125
|
приносит их пачкой, задним числом. Слово, сказанное посреди работы, кладёт командой `/feedback`
|
|
120
126
|
сам агент: до неё такое слово адреса не получало вовсе и умирало вместе с сессией. Оба пути
|
|
@@ -233,3 +239,14 @@ npx agent-kit propose # отправить груз в приём: сво
|
|
|
233
239
|
- **Выключение живёт в настройке дерева, а не в настройке агента.** Строка, вырезанная из
|
|
234
240
|
настроек агента руками, теряется на первой же правке того файла, и вернуть роль будет нечем.
|
|
235
241
|
Здесь оно объявлено в одном месте и видно всякому, кто читает настройку дерева.
|
|
242
|
+
|
|
243
|
+
## Ловушки раскладки
|
|
244
|
+
|
|
245
|
+
- **Своё, стоящее рядом с разложенным, повторяет его механику молча.** Проверка, гард и утилита
|
|
246
|
+
дерева лежат в тех же каталогах, что и пакетные, а общий разбор списка известного, корни
|
|
247
|
+
исходников, список пропускаемых каталогов и снимок долга приезжают модулем настройки проверок.
|
|
248
|
+
Второе такое же заводится в своей проверке без единого сигнала: имена разные, форма разная, и
|
|
249
|
+
повтора не видит ни сверка раскладки — файл не разложен, — ни проверка повторов, которая ищет
|
|
250
|
+
совпадение текста. Признак один, и он читается, а не ищется: до того как в своей проверке
|
|
251
|
+
заводится разбор списка, чтение настройки или сравнение с накопленным, смотрят, что
|
|
252
|
+
экспортирует модуль настройки проверок и чем живут соседние проверки.
|
package/bin/agent-kit.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-kit.d.ts","sourceRoot":"","sources":["../../../projects/agent-kit/src/bin/agent-kit.ts"],"names":[],"mappings":";AAeA,OAAO,EAAqC,iBAAiB,EAAqB,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"agent-kit.d.ts","sourceRoot":"","sources":["../../../projects/agent-kit/src/bin/agent-kit.ts"],"names":[],"mappings":";AAeA,OAAO,EAAqC,iBAAiB,EAAqB,MAAM,oBAAoB,CAAC;AAwU7G,wBAAsB,IAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAU9E"}
|
package/bin/agent-kit.js
CHANGED
|
@@ -14,6 +14,7 @@ import { unknownFlagsIn } from '../lib/argv.js';
|
|
|
14
14
|
import { readCatalog, resolveSelection } from '../lib/catalog.js';
|
|
15
15
|
import { adopt, doctor, init, list, stats, sync } from '../lib/commands.js';
|
|
16
16
|
import { CONFIG_PATH, readConfig } from '../lib/config.js';
|
|
17
|
+
import { costLines, costOf, CostUnavailableError } from '../lib/cost.js';
|
|
17
18
|
import { enroll, httpEnroll } from '../lib/enroll.js';
|
|
18
19
|
import { httpShip } from '../lib/ship.js';
|
|
19
20
|
import { propose, treeSlugOf } from '../lib/shipment.js';
|
|
@@ -30,6 +31,9 @@ const USAGE = [
|
|
|
30
31
|
' sync разложить ресурсы пакета в дерево проекта',
|
|
31
32
|
' sync --check ничего не писать, отказать при расхождении — для гейта пуша',
|
|
32
33
|
' doctor рассказать о состоянии раскладки, ничего не меняя',
|
|
34
|
+
' cost посчитать цену контекста: вход в работу, одно правило, весь слой',
|
|
35
|
+
' cost --rule <имя> какое правило взвесить; без довода берётся самое тяжёлое',
|
|
36
|
+
' cost --json то же машиночитаемо — этим числа кладут в замысел',
|
|
33
37
|
' stats свести наблюдения: чем пользовались, чем ни разу, обо что спотыкались',
|
|
34
38
|
' stats --days N за сколько дней; без довода — за три',
|
|
35
39
|
' stats --json то же машиночитаемо — этим сводку прикладывают к предложению',
|
|
@@ -197,6 +201,26 @@ async function runInit(env, argv) {
|
|
|
197
201
|
? { code: 1, lines: ['выбор брошен — ничего не заведено'] }
|
|
198
202
|
: init(env.root, selection, variants, env.assetsDir);
|
|
199
203
|
}
|
|
204
|
+
/**
|
|
205
|
+
* Цена контекста: три веса и то, чем они сняты.
|
|
206
|
+
*
|
|
207
|
+
* Отказ печатается тем же выводом, а не броском: команду зовут глазами, и трассировка стека
|
|
208
|
+
* говорит ей читателю меньше, чем строка о том, чего в дереве нет.
|
|
209
|
+
*/
|
|
210
|
+
function runCost(env, argv) {
|
|
211
|
+
const named = optionOf(argv, '--rule', '');
|
|
212
|
+
let cost;
|
|
213
|
+
try {
|
|
214
|
+
cost = costOf(env.root, named === '' ? null : named);
|
|
215
|
+
}
|
|
216
|
+
catch (failure) {
|
|
217
|
+
if (failure instanceof CostUnavailableError) {
|
|
218
|
+
return { code: 1, lines: [failure.message] };
|
|
219
|
+
}
|
|
220
|
+
throw failure;
|
|
221
|
+
}
|
|
222
|
+
return { code: 0, lines: [...costLines(cost, argv.includes('--json'))] };
|
|
223
|
+
}
|
|
200
224
|
/** Сводка наблюдений: отрезок из флага, сегодняшний день — с края. */
|
|
201
225
|
function runStats(env, argv) {
|
|
202
226
|
const spoken = Number(optionOf(argv, '--days', ''));
|
|
@@ -255,6 +279,7 @@ const COMMANDS = {
|
|
|
255
279
|
init: runInit,
|
|
256
280
|
list: (env) => list(env),
|
|
257
281
|
sync: (env, argv) => sync(env, argv.includes('--check')),
|
|
282
|
+
cost: runCost,
|
|
258
283
|
stats: runStats,
|
|
259
284
|
propose: runPropose,
|
|
260
285
|
enroll: runEnroll,
|
package/bin/agent-kit.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-kit.js","sourceRoot":"","sources":["../../../projects/agent-kit/src/bin/agent-kit.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n/**\n * Точка входа. Разбирает аргументы, добывает выбор проекта, зовёт команду и печатает то, что\n * она вернула. Своей работы у неё нет: всё, что решает, живёт в `commands.ts` и проверяется\n * спеками — кроме одного, чего команде знать не по чину: откуда взялся выбор законов. У строки\n * запуска это флаг, у терминала — вопрос, у прогона без терминала нет ни того ни другого.\n */\nimport { execFileSync } from 'node:child_process';\nimport { readFileSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport process from 'node:process';\n\nimport { unknownFlagsIn } from '../lib/argv.js';\nimport { IEntryOfCatalog, readCatalog, resolveSelection } from '../lib/catalog.js';\nimport { adopt, doctor, IEnvironment, init, IOutcomeOfCommand, list, stats, sync } from '../lib/commands.js';\nimport { CONFIG_PATH, IConfig, readConfig } from '../lib/config.js';\nimport { enroll, httpEnroll } from '../lib/enroll.js';\nimport { httpShip } from '../lib/ship.js';\nimport { propose, treeSlugOf } from '../lib/shipment.js';\nimport { DEFAULT_DAYS } from '../lib/observations.js';\nimport { staleBuild } from '../lib/freshness.js';\nimport { packageRootFrom } from '../lib/package-root.js';\nimport { IChoice } from '../lib/picker.js';\nimport { IAxis, IOptionOfAxis, readAxes } from '../lib/variants.js';\nimport { ask, askOne, canAsk } from './prompt.js';\n\nconst USAGE: readonly string[] = [\n 'agent-kit <команда>',\n '',\n ' init завести .claude/rt-kit.json и каталог надстроек',\n ' list что везёт пакет и что из этого взято здесь',\n ' sync разложить ресурсы пакета в дерево проекта',\n ' sync --check ничего не писать, отказать при расхождении — для гейта пуша',\n ' doctor рассказать о состоянии раскладки, ничего не меняя',\n ' stats свести наблюдения: чем пользовались, чем ни разу, обо что спотыкались',\n ' stats --days N за сколько дней; без довода — за три',\n ' stats --json то же машиночитаемо — этим сводку прикладывают к предложению',\n ' propose отправить груз в приём: сводку со снимком надстроек, предложения и разборы',\n ' propose --dry-run показать, что уехало бы, и ничего не отправлять',\n ' adopt [файлы] отдать пакету файлы, лежащие на его путях не от него',\n ' enroll --code <код> завести дерево по приглашению владельца: обмен кода на токен',\n ' enroll --token <токен> завести дерево токеном, выданным в админке приёма; в сеть не идёт',\n ' enroll --force перезаписать уже лежащий токен намеренно',\n '',\n ' --root <путь> корень проекта; по умолчанию текущий каталог',\n '',\n 'Выбор законов при `init`:',\n '',\n ' --all взять все законы, ни о чём не спрашивая',\n ' --laws a,b,c взять только названные; имена — из `agent-kit list`',\n ' без обоих спросить галочками; без терминала — отказ',\n '',\n 'Вид ресурсов при `init` — там, где один закон исполняется разными командами:',\n '',\n ' --<ось> <вид> например `--host gitlab`; оси и виды — из `agent-kit list`',\n ' без флага спросить; без терминала — отказ, кроме `--all`',\n];\n\n/**\n * Доводы отправки. Довод со значением помечен `<>`: за ним идёт отдельным словом путь, и без\n * пометки этот путь читался бы как ещё один незнакомый довод.\n */\nconst PROPOSE_FLAGS: readonly string[] = ['--dry-run', '--root <>'];\n\n/** Что печатает отказ на незнакомом доводе: режимы команды, а не весь свод. */\nconst PROPOSE_USAGE: readonly string[] = [\n ' propose отправить груз в приём',\n ' propose --dry-run показать, что уехало бы, и ничего не отправлять',\n ' --root <путь> корень проекта; по умолчанию текущий каталог',\n];\n\n/**\n * Единственное место, где пакет узнаёт собственное расположение. `import.meta` живёт только\n * здесь: библиотечные модули получают каталог ресурсов входным значением, и трансформ тестов,\n * разбирающий модули как CommonJS, на них уже не спотыкается.\n */\nfunction environmentOf(root: string): IEnvironment {\n const pkg: string = packageRootFrom(dirname(fileURLToPath(import.meta.url)));\n const manifest: { name: string; version: string } = JSON.parse(readFileSync(join(pkg, 'package.json'), 'utf8')) as {\n name: string;\n version: string;\n };\n\n return {\n root,\n version: manifest.version,\n assetsDir: join(pkg, 'assets'),\n // Сверка со своими исходниками возможна только отсюда: здесь пакет знает, где лежит сам.\n // У потребителя исходников рядом нет, и сверка молчит.\n stale: staleBuild(pkg, manifest.name),\n };\n}\n\n/** Чем это дерево себя выдаёт снаружи. Нет удалённого репозитория — нечем, и это не отказ. */\nfunction remoteOf(root: string): string {\n try {\n // eslint-disable-next-line sonarjs/no-os-command-from-path -- путь к git у каждой машины свой, и прибитый здесь сделал бы пакет непереносимым\n return execFileSync('git', ['-C', root, 'remote', 'get-url', 'origin'], {\n encoding: 'utf8',\n stdio: ['ignore', 'pipe', 'ignore'],\n }).trim();\n } catch {\n return '';\n }\n}\n\nfunction optionOf(argv: readonly string[], name: string, fallback: string): string {\n const index: number = argv.indexOf(name);\n\n return index >= 0 && argv[index + 1] ? argv[index + 1] : fallback;\n}\n\nconst isOutcome: (value: unknown) => value is IOutcomeOfCommand = (value: unknown): value is IOutcomeOfCommand =>\n typeof value === 'object' && value !== null && 'code' in value;\n\n/**\n * Выбор законов для `init`: список идентификаторов, `null` на брошенном выборе или готовый\n * отказ. Пустой список означает «взять всё», поэтому брошенный выбор отличается от него не\n * значением, а `null`: подставить «всё» вместо неотвеченного вопроса значило бы разложить\n * пятнадцать законов тому, кто как раз просил спросить.\n */\nasync function selectionFor(argv: readonly string[], assetsDir: string): Promise<readonly string[] | null | IOutcomeOfCommand> {\n if (argv.includes('--all')) {\n return [];\n }\n\n const catalog: readonly IEntryOfCatalog[] = readCatalog(assetsDir);\n const spoken: string = optionOf(argv, '--laws', '');\n\n if (spoken) {\n const named: string[] = spoken\n .split(',')\n .map((name: string): string => name.trim())\n .filter(Boolean);\n const { ids, unknown } = resolveSelection(named, 'laws', catalog);\n\n return unknown.length\n ? { code: 1, lines: [`таких законов пакет не везёт: ${unknown.join(', ')}`, 'что везёт — `agent-kit list`'] }\n : ids;\n }\n\n if (!canAsk()) {\n return {\n code: 1,\n lines: [\n 'спросить некого: запуск без терминала',\n 'назови законы флагом `--laws a,b,c` или возьми все флагом `--all`',\n 'что везёт пакет — `agent-kit list`',\n ],\n };\n }\n\n const choices: readonly IChoice[] = catalog\n .filter((entry: IEntryOfCatalog): boolean => entry.kind === 'laws')\n .map((entry: IEntryOfCatalog): IChoice => ({ id: entry.id, name: entry.name, title: entry.title }));\n\n return ask(choices, 'Какие законы разложить в этом проекте?');\n}\n\n/**\n * Виды для `init` по осям, объявленным пакетом: что взято из флага, что спрошено.\n *\n * `--all` берёт первый объявленный вид оси и **говорит об этом**: в CI спрашивать некого, а\n * отказ там означал бы, что пакет нельзя разложить без человека. Первый вид — умолчание, а не\n * догадка: порядок в объявлении оси и есть порядок предпочтения.\n */\nasync function variantOfAxis(axis: IAxis, argv: readonly string[]): Promise<string | null | IOutcomeOfCommand> {\n const spoken: string = optionOf(argv, `--${axis.name}`, '');\n const values: readonly string[] = axis.options.map((option: IOptionOfAxis): string => option.value);\n\n if (spoken) {\n return values.includes(spoken)\n ? spoken\n : {\n code: 1,\n lines: [`такого вида по оси «${axis.name}» пакет не везёт: ${spoken}`, `есть: ${values.join(', ')}`],\n };\n }\n\n if (argv.includes('--all')) {\n return axis.options[0]?.value ?? '';\n }\n\n if (!canAsk()) {\n return {\n code: 1,\n lines: ['спросить некого: запуск без терминала', `назови вид флагом \\`--${axis.name} <вид>\\`: ${values.join(', ')}`],\n };\n }\n\n return askOne(\n axis.options.map((option: IOptionOfAxis): IChoice => ({ id: option.value, name: option.value, title: option.title })),\n axis.question\n );\n}\n\nasync function variantsFor(argv: readonly string[], assetsDir: string): Promise<Record<string, string> | null | IOutcomeOfCommand> {\n const axes: readonly IAxis[] = readAxes(assetsDir);\n const chosen: Record<string, string> = {};\n\n for (const axis of axes) {\n const answer: string | null | IOutcomeOfCommand = await variantOfAxis(axis, argv);\n\n if (isOutcome(answer)) {\n return answer;\n }\n\n if (answer === null) {\n return null;\n }\n\n chosen[axis.name] = answer;\n }\n\n return chosen;\n}\n\n/** Заведение настройки: выбор ресурсов и видов, брошенный выбор ничего не пишет. */\nasync function runInit(env: IEnvironment, argv: readonly string[]): Promise<IOutcomeOfCommand> {\n const selection: readonly string[] | null | IOutcomeOfCommand = await selectionFor(argv, env.assetsDir);\n if (isOutcome(selection)) {\n return selection;\n }\n if (selection === null) {\n return { code: 1, lines: ['выбор брошен — ничего не заведено'] };\n }\n\n const variants: Record<string, string> | null | IOutcomeOfCommand = await variantsFor(argv, env.assetsDir);\n if (isOutcome(variants)) {\n return variants;\n }\n\n return variants === null\n ? { code: 1, lines: ['выбор брошен — ничего не заведено'] }\n : init(env.root, selection, variants, env.assetsDir);\n}\n\n/** Сводка наблюдений: отрезок из флага, сегодняшний день — с края. */\nfunction runStats(env: IEnvironment, argv: readonly string[]): IOutcomeOfCommand {\n const spoken: number = Number(optionOf(argv, '--days', ''));\n\n return stats(env, {\n days: Number.isFinite(spoken) && spoken > 0 ? Math.floor(spoken) : DEFAULT_DAYS,\n // Сегодняшний день берётся здесь: у команды своих часов нет, иначе сводку за\n // отрезок не проверить спекой — вчерашняя фикстура завтра станет позавчерашней.\n today: new Date().toISOString().slice(0, 10),\n json: argv.includes('--json'),\n });\n}\n\n/**\n * Отправка накопленного.\n *\n * Единственное действие этой команды необратимо и уходит наружу, поэтому незнакомый довод её\n * кончает, а не пропускается молча: вызов ради списка режимов отправил в приём всё накопленное, и\n * по выводу это не отличалось от «команда ничего не сделала». Прочие команды такого разбора не\n * знают — их действие обратимо.\n */\nasync function runPropose(env: IEnvironment, argv: readonly string[]): Promise<IOutcomeOfCommand> {\n const unknown: readonly string[] = unknownFlagsIn(argv.slice(1), PROPOSE_FLAGS);\n if (unknown.length) {\n return {\n code: 1,\n lines: [`таких доводов у \\`propose\\` нет: ${unknown.join(', ')}`, '', ...PROPOSE_USAGE],\n };\n }\n\n return propose(env, {\n dryRun: argv.includes('--dry-run'),\n ship: httpShip,\n remote: remoteOf(env.root),\n // Отрезок тот же, что у сводки по умолчанию: отправку зовут по свежей задаче.\n days: DEFAULT_DAYS,\n today: new Date().toISOString().slice(0, 10),\n });\n}\n\n/** Приписка дерева к приёмнику по коду приглашения. */\nasync function runEnroll(env: IEnvironment, argv: readonly string[]): Promise<IOutcomeOfCommand> {\n const config: IConfig | null = readConfig(env.root);\n\n if (!config) {\n return { code: 1, lines: [`настройки дерева нет: ${CONFIG_PATH}. Заведите её командой \\`init\\``] };\n }\n\n return enroll({\n root: env.root,\n intake: config.intake,\n code: optionOf(argv, '--code', ''),\n issued: optionOf(argv, '--token', ''),\n tree: treeSlugOf(remoteOf(env.root), config.tree),\n token: config.token,\n force: argv.includes('--force'),\n call: httpEnroll,\n });\n}\n\n/** Ветка команды: окружение и доводы строки запуска на входе, вывод и код возврата на выходе. */\ntype TCommandRun = (env: IEnvironment, argv: readonly string[]) => IOutcomeOfCommand | Promise<IOutcomeOfCommand>;\n\n/** Что делает каждая команда строки запуска. Ключ — слово, которым её зовут. */\nconst COMMANDS: Readonly<Record<string, TCommandRun>> = {\n init: runInit,\n list: (env: IEnvironment): IOutcomeOfCommand => list(env),\n sync: (env: IEnvironment, argv: readonly string[]): IOutcomeOfCommand => sync(env, argv.includes('--check')),\n stats: runStats,\n propose: runPropose,\n enroll: runEnroll,\n doctor: (env: IEnvironment): IOutcomeOfCommand => doctor(env),\n adopt: (env: IEnvironment, argv: readonly string[]): IOutcomeOfCommand =>\n adopt(\n env,\n argv.slice(1).filter((value: string): boolean => !value.startsWith('--') && value !== optionOf(argv, '--root', ''))\n ),\n};\n\nexport async function main(argv: readonly string[]): Promise<IOutcomeOfCommand> {\n const command: string = argv[0] ?? '';\n const env: IEnvironment = environmentOf(resolve(optionOf(argv, '--root', process.cwd())));\n const run: TCommandRun | undefined = Object.hasOwn(COMMANDS, command) ? COMMANDS[command] : undefined;\n\n if (!run) {\n return { code: command ? 1 : 0, lines: command ? [`неизвестная команда «${command}»`, '', ...USAGE] : USAGE };\n }\n\n return run(env, argv);\n}\n\nconst outcome: IOutcomeOfCommand = await main(process.argv.slice(2));\nfor (const line of outcome.lines) {\n // eslint-disable-next-line no-console\n console.log(line);\n}\nprocess.exit(outcome.code);\n"]}
|
|
1
|
+
{"version":3,"file":"agent-kit.js","sourceRoot":"","sources":["../../../projects/agent-kit/src/bin/agent-kit.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n/**\n * Точка входа. Разбирает аргументы, добывает выбор проекта, зовёт команду и печатает то, что\n * она вернула. Своей работы у неё нет: всё, что решает, живёт в `commands.ts` и проверяется\n * спеками — кроме одного, чего команде знать не по чину: откуда взялся выбор законов. У строки\n * запуска это флаг, у терминала — вопрос, у прогона без терминала нет ни того ни другого.\n */\nimport { execFileSync } from 'node:child_process';\nimport { readFileSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport process from 'node:process';\n\nimport { unknownFlagsIn } from '../lib/argv.js';\nimport { IEntryOfCatalog, readCatalog, resolveSelection } from '../lib/catalog.js';\nimport { adopt, doctor, IEnvironment, init, IOutcomeOfCommand, list, stats, sync } from '../lib/commands.js';\nimport { CONFIG_PATH, IConfig, readConfig } from '../lib/config.js';\nimport { costLines, costOf, CostUnavailableError, ICost } from '../lib/cost.js';\nimport { enroll, httpEnroll } from '../lib/enroll.js';\nimport { httpShip } from '../lib/ship.js';\nimport { propose, treeSlugOf } from '../lib/shipment.js';\nimport { DEFAULT_DAYS } from '../lib/observations.js';\nimport { staleBuild } from '../lib/freshness.js';\nimport { packageRootFrom } from '../lib/package-root.js';\nimport { IChoice } from '../lib/picker.js';\nimport { IAxis, IOptionOfAxis, readAxes } from '../lib/variants.js';\nimport { ask, askOne, canAsk } from './prompt.js';\n\nconst USAGE: readonly string[] = [\n 'agent-kit <команда>',\n '',\n ' init завести .claude/rt-kit.json и каталог надстроек',\n ' list что везёт пакет и что из этого взято здесь',\n ' sync разложить ресурсы пакета в дерево проекта',\n ' sync --check ничего не писать, отказать при расхождении — для гейта пуша',\n ' doctor рассказать о состоянии раскладки, ничего не меняя',\n ' cost посчитать цену контекста: вход в работу, одно правило, весь слой',\n ' cost --rule <имя> какое правило взвесить; без довода берётся самое тяжёлое',\n ' cost --json то же машиночитаемо — этим числа кладут в замысел',\n ' stats свести наблюдения: чем пользовались, чем ни разу, обо что спотыкались',\n ' stats --days N за сколько дней; без довода — за три',\n ' stats --json то же машиночитаемо — этим сводку прикладывают к предложению',\n ' propose отправить груз в приём: сводку со снимком надстроек, предложения и разборы',\n ' propose --dry-run показать, что уехало бы, и ничего не отправлять',\n ' adopt [файлы] отдать пакету файлы, лежащие на его путях не от него',\n ' enroll --code <код> завести дерево по приглашению владельца: обмен кода на токен',\n ' enroll --token <токен> завести дерево токеном, выданным в админке приёма; в сеть не идёт',\n ' enroll --force перезаписать уже лежащий токен намеренно',\n '',\n ' --root <путь> корень проекта; по умолчанию текущий каталог',\n '',\n 'Выбор законов при `init`:',\n '',\n ' --all взять все законы, ни о чём не спрашивая',\n ' --laws a,b,c взять только названные; имена — из `agent-kit list`',\n ' без обоих спросить галочками; без терминала — отказ',\n '',\n 'Вид ресурсов при `init` — там, где один закон исполняется разными командами:',\n '',\n ' --<ось> <вид> например `--host gitlab`; оси и виды — из `agent-kit list`',\n ' без флага спросить; без терминала — отказ, кроме `--all`',\n];\n\n/**\n * Доводы отправки. Довод со значением помечен `<>`: за ним идёт отдельным словом путь, и без\n * пометки этот путь читался бы как ещё один незнакомый довод.\n */\nconst PROPOSE_FLAGS: readonly string[] = ['--dry-run', '--root <>'];\n\n/** Что печатает отказ на незнакомом доводе: режимы команды, а не весь свод. */\nconst PROPOSE_USAGE: readonly string[] = [\n ' propose отправить груз в приём',\n ' propose --dry-run показать, что уехало бы, и ничего не отправлять',\n ' --root <путь> корень проекта; по умолчанию текущий каталог',\n];\n\n/**\n * Единственное место, где пакет узнаёт собственное расположение. `import.meta` живёт только\n * здесь: библиотечные модули получают каталог ресурсов входным значением, и трансформ тестов,\n * разбирающий модули как CommonJS, на них уже не спотыкается.\n */\nfunction environmentOf(root: string): IEnvironment {\n const pkg: string = packageRootFrom(dirname(fileURLToPath(import.meta.url)));\n const manifest: { name: string; version: string } = JSON.parse(readFileSync(join(pkg, 'package.json'), 'utf8')) as {\n name: string;\n version: string;\n };\n\n return {\n root,\n version: manifest.version,\n assetsDir: join(pkg, 'assets'),\n // Сверка со своими исходниками возможна только отсюда: здесь пакет знает, где лежит сам.\n // У потребителя исходников рядом нет, и сверка молчит.\n stale: staleBuild(pkg, manifest.name),\n };\n}\n\n/** Чем это дерево себя выдаёт снаружи. Нет удалённого репозитория — нечем, и это не отказ. */\nfunction remoteOf(root: string): string {\n try {\n // eslint-disable-next-line sonarjs/no-os-command-from-path -- путь к git у каждой машины свой, и прибитый здесь сделал бы пакет непереносимым\n return execFileSync('git', ['-C', root, 'remote', 'get-url', 'origin'], {\n encoding: 'utf8',\n stdio: ['ignore', 'pipe', 'ignore'],\n }).trim();\n } catch {\n return '';\n }\n}\n\nfunction optionOf(argv: readonly string[], name: string, fallback: string): string {\n const index: number = argv.indexOf(name);\n\n return index >= 0 && argv[index + 1] ? argv[index + 1] : fallback;\n}\n\nconst isOutcome: (value: unknown) => value is IOutcomeOfCommand = (value: unknown): value is IOutcomeOfCommand =>\n typeof value === 'object' && value !== null && 'code' in value;\n\n/**\n * Выбор законов для `init`: список идентификаторов, `null` на брошенном выборе или готовый\n * отказ. Пустой список означает «взять всё», поэтому брошенный выбор отличается от него не\n * значением, а `null`: подставить «всё» вместо неотвеченного вопроса значило бы разложить\n * пятнадцать законов тому, кто как раз просил спросить.\n */\nasync function selectionFor(argv: readonly string[], assetsDir: string): Promise<readonly string[] | null | IOutcomeOfCommand> {\n if (argv.includes('--all')) {\n return [];\n }\n\n const catalog: readonly IEntryOfCatalog[] = readCatalog(assetsDir);\n const spoken: string = optionOf(argv, '--laws', '');\n\n if (spoken) {\n const named: string[] = spoken\n .split(',')\n .map((name: string): string => name.trim())\n .filter(Boolean);\n const { ids, unknown } = resolveSelection(named, 'laws', catalog);\n\n return unknown.length\n ? { code: 1, lines: [`таких законов пакет не везёт: ${unknown.join(', ')}`, 'что везёт — `agent-kit list`'] }\n : ids;\n }\n\n if (!canAsk()) {\n return {\n code: 1,\n lines: [\n 'спросить некого: запуск без терминала',\n 'назови законы флагом `--laws a,b,c` или возьми все флагом `--all`',\n 'что везёт пакет — `agent-kit list`',\n ],\n };\n }\n\n const choices: readonly IChoice[] = catalog\n .filter((entry: IEntryOfCatalog): boolean => entry.kind === 'laws')\n .map((entry: IEntryOfCatalog): IChoice => ({ id: entry.id, name: entry.name, title: entry.title }));\n\n return ask(choices, 'Какие законы разложить в этом проекте?');\n}\n\n/**\n * Виды для `init` по осям, объявленным пакетом: что взято из флага, что спрошено.\n *\n * `--all` берёт первый объявленный вид оси и **говорит об этом**: в CI спрашивать некого, а\n * отказ там означал бы, что пакет нельзя разложить без человека. Первый вид — умолчание, а не\n * догадка: порядок в объявлении оси и есть порядок предпочтения.\n */\nasync function variantOfAxis(axis: IAxis, argv: readonly string[]): Promise<string | null | IOutcomeOfCommand> {\n const spoken: string = optionOf(argv, `--${axis.name}`, '');\n const values: readonly string[] = axis.options.map((option: IOptionOfAxis): string => option.value);\n\n if (spoken) {\n return values.includes(spoken)\n ? spoken\n : {\n code: 1,\n lines: [`такого вида по оси «${axis.name}» пакет не везёт: ${spoken}`, `есть: ${values.join(', ')}`],\n };\n }\n\n if (argv.includes('--all')) {\n return axis.options[0]?.value ?? '';\n }\n\n if (!canAsk()) {\n return {\n code: 1,\n lines: ['спросить некого: запуск без терминала', `назови вид флагом \\`--${axis.name} <вид>\\`: ${values.join(', ')}`],\n };\n }\n\n return askOne(\n axis.options.map((option: IOptionOfAxis): IChoice => ({ id: option.value, name: option.value, title: option.title })),\n axis.question\n );\n}\n\nasync function variantsFor(argv: readonly string[], assetsDir: string): Promise<Record<string, string> | null | IOutcomeOfCommand> {\n const axes: readonly IAxis[] = readAxes(assetsDir);\n const chosen: Record<string, string> = {};\n\n for (const axis of axes) {\n const answer: string | null | IOutcomeOfCommand = await variantOfAxis(axis, argv);\n\n if (isOutcome(answer)) {\n return answer;\n }\n\n if (answer === null) {\n return null;\n }\n\n chosen[axis.name] = answer;\n }\n\n return chosen;\n}\n\n/** Заведение настройки: выбор ресурсов и видов, брошенный выбор ничего не пишет. */\nasync function runInit(env: IEnvironment, argv: readonly string[]): Promise<IOutcomeOfCommand> {\n const selection: readonly string[] | null | IOutcomeOfCommand = await selectionFor(argv, env.assetsDir);\n if (isOutcome(selection)) {\n return selection;\n }\n if (selection === null) {\n return { code: 1, lines: ['выбор брошен — ничего не заведено'] };\n }\n\n const variants: Record<string, string> | null | IOutcomeOfCommand = await variantsFor(argv, env.assetsDir);\n if (isOutcome(variants)) {\n return variants;\n }\n\n return variants === null\n ? { code: 1, lines: ['выбор брошен — ничего не заведено'] }\n : init(env.root, selection, variants, env.assetsDir);\n}\n\n/**\n * Цена контекста: три веса и то, чем они сняты.\n *\n * Отказ печатается тем же выводом, а не броском: команду зовут глазами, и трассировка стека\n * говорит ей читателю меньше, чем строка о том, чего в дереве нет.\n */\nfunction runCost(env: IEnvironment, argv: readonly string[]): IOutcomeOfCommand {\n const named: string = optionOf(argv, '--rule', '');\n let cost: ICost;\n try {\n cost = costOf(env.root, named === '' ? null : named);\n } catch (failure: unknown) {\n if (failure instanceof CostUnavailableError) {\n return { code: 1, lines: [failure.message] };\n }\n throw failure;\n }\n\n return { code: 0, lines: [...costLines(cost, argv.includes('--json'))] };\n}\n\n/** Сводка наблюдений: отрезок из флага, сегодняшний день — с края. */\nfunction runStats(env: IEnvironment, argv: readonly string[]): IOutcomeOfCommand {\n const spoken: number = Number(optionOf(argv, '--days', ''));\n\n return stats(env, {\n days: Number.isFinite(spoken) && spoken > 0 ? Math.floor(spoken) : DEFAULT_DAYS,\n // Сегодняшний день берётся здесь: у команды своих часов нет, иначе сводку за\n // отрезок не проверить спекой — вчерашняя фикстура завтра станет позавчерашней.\n today: new Date().toISOString().slice(0, 10),\n json: argv.includes('--json'),\n });\n}\n\n/**\n * Отправка накопленного.\n *\n * Единственное действие этой команды необратимо и уходит наружу, поэтому незнакомый довод её\n * кончает, а не пропускается молча: вызов ради списка режимов отправил в приём всё накопленное, и\n * по выводу это не отличалось от «команда ничего не сделала». Прочие команды такого разбора не\n * знают — их действие обратимо.\n */\nasync function runPropose(env: IEnvironment, argv: readonly string[]): Promise<IOutcomeOfCommand> {\n const unknown: readonly string[] = unknownFlagsIn(argv.slice(1), PROPOSE_FLAGS);\n if (unknown.length) {\n return {\n code: 1,\n lines: [`таких доводов у \\`propose\\` нет: ${unknown.join(', ')}`, '', ...PROPOSE_USAGE],\n };\n }\n\n return propose(env, {\n dryRun: argv.includes('--dry-run'),\n ship: httpShip,\n remote: remoteOf(env.root),\n // Отрезок тот же, что у сводки по умолчанию: отправку зовут по свежей задаче.\n days: DEFAULT_DAYS,\n today: new Date().toISOString().slice(0, 10),\n });\n}\n\n/** Приписка дерева к приёмнику по коду приглашения. */\nasync function runEnroll(env: IEnvironment, argv: readonly string[]): Promise<IOutcomeOfCommand> {\n const config: IConfig | null = readConfig(env.root);\n\n if (!config) {\n return { code: 1, lines: [`настройки дерева нет: ${CONFIG_PATH}. Заведите её командой \\`init\\``] };\n }\n\n return enroll({\n root: env.root,\n intake: config.intake,\n code: optionOf(argv, '--code', ''),\n issued: optionOf(argv, '--token', ''),\n tree: treeSlugOf(remoteOf(env.root), config.tree),\n token: config.token,\n force: argv.includes('--force'),\n call: httpEnroll,\n });\n}\n\n/** Ветка команды: окружение и доводы строки запуска на входе, вывод и код возврата на выходе. */\ntype TCommandRun = (env: IEnvironment, argv: readonly string[]) => IOutcomeOfCommand | Promise<IOutcomeOfCommand>;\n\n/** Что делает каждая команда строки запуска. Ключ — слово, которым её зовут. */\nconst COMMANDS: Readonly<Record<string, TCommandRun>> = {\n init: runInit,\n list: (env: IEnvironment): IOutcomeOfCommand => list(env),\n sync: (env: IEnvironment, argv: readonly string[]): IOutcomeOfCommand => sync(env, argv.includes('--check')),\n cost: runCost,\n stats: runStats,\n propose: runPropose,\n enroll: runEnroll,\n doctor: (env: IEnvironment): IOutcomeOfCommand => doctor(env),\n adopt: (env: IEnvironment, argv: readonly string[]): IOutcomeOfCommand =>\n adopt(\n env,\n argv.slice(1).filter((value: string): boolean => !value.startsWith('--') && value !== optionOf(argv, '--root', ''))\n ),\n};\n\nexport async function main(argv: readonly string[]): Promise<IOutcomeOfCommand> {\n const command: string = argv[0] ?? '';\n const env: IEnvironment = environmentOf(resolve(optionOf(argv, '--root', process.cwd())));\n const run: TCommandRun | undefined = Object.hasOwn(COMMANDS, command) ? COMMANDS[command] : undefined;\n\n if (!run) {\n return { code: command ? 1 : 0, lines: command ? [`неизвестная команда «${command}»`, '', ...USAGE] : USAGE };\n }\n\n return run(env, argv);\n}\n\nconst outcome: IOutcomeOfCommand = await main(process.argv.slice(2));\nfor (const line of outcome.lines) {\n // eslint-disable-next-line no-console\n console.log(line);\n}\nprocess.exit(outcome.code);\n"]}
|
package/lib/cost.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/** Чем считано. Стоит рядом с числами: снятое иначе с этим несравнимо. */
|
|
2
|
+
export declare const COUNTED_BY: string;
|
|
3
|
+
export interface IWeighed {
|
|
4
|
+
/** Что взвешено — строкой для человека. */
|
|
5
|
+
readonly what: string;
|
|
6
|
+
/** Сколько в этом символов. */
|
|
7
|
+
readonly chars: number;
|
|
8
|
+
/** Сколько в этом байтов: у кириллицы их вдвое больше, чем символов. */
|
|
9
|
+
readonly bytes: number;
|
|
10
|
+
}
|
|
11
|
+
export interface ICost {
|
|
12
|
+
/** Чем считано: без этого имени число несравнимо со снятым вчера. */
|
|
13
|
+
readonly countedBy: string;
|
|
14
|
+
/** Что заход получает до первой своей правки. */
|
|
15
|
+
readonly entry: IWeighed;
|
|
16
|
+
/** Одно правило вместе со спутником — столько стоит решение, которое его задело. */
|
|
17
|
+
readonly rule: IWeighed;
|
|
18
|
+
/** Все законы, правила и паттерны разом. Ни один заход столько не грузит; число про рост. */
|
|
19
|
+
readonly layer: IWeighed;
|
|
20
|
+
}
|
|
21
|
+
/** Отказ, который команда печатает вместо чисел: сказано, чего нет. */
|
|
22
|
+
export declare class CostUnavailableError extends Error {
|
|
23
|
+
constructor(reason: string);
|
|
24
|
+
}
|
|
25
|
+
/** Что заход получает до первой правки: описания всех правил и вывод хуков старта. */
|
|
26
|
+
export declare function entryTexts(root: string): readonly string[];
|
|
27
|
+
/** Правило вместе со спутником — столько стоит одна его загрузка. */
|
|
28
|
+
export declare function ruleTexts(root: string, rule: string): readonly string[];
|
|
29
|
+
/** Весь слой разом: законы, правила и паттерны. Ни один заход столько не грузит. */
|
|
30
|
+
export declare function layerTexts(root: string): readonly string[];
|
|
31
|
+
/** Правило с самым тяжёлым файлом — то, что берётся, когда имя не названо. */
|
|
32
|
+
export declare function heaviestRule(root: string): string;
|
|
33
|
+
/** Вес набора текстов: символы и байты. Байты считаются кодировкой, в которой файлы и лежат. */
|
|
34
|
+
export declare function weigh(what: string, texts: readonly string[]): IWeighed;
|
|
35
|
+
/**
|
|
36
|
+
* Печать цены: таблица человеку либо разбор машине.
|
|
37
|
+
*
|
|
38
|
+
* Обе живут здесь, а не в строке запуска: числа кладут в замысел эпика и в разбор закрытой
|
|
39
|
+
* работы, и та половина, что никем не покрыта, расходится с другой молча.
|
|
40
|
+
*/
|
|
41
|
+
export declare function costLines(cost: ICost, json: boolean): readonly string[];
|
|
42
|
+
/** Три числа цены: вход в работу, одно правило и весь слой. */
|
|
43
|
+
export declare function costOf(root: string, rule: string | null): ICost;
|
|
44
|
+
//# sourceMappingURL=cost.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost.d.ts","sourceRoot":"","sources":["../../../projects/agent-kit/src/lib/cost.ts"],"names":[],"mappings":"AAmBA,0EAA0E;AAC1E,eAAO,MAAM,UAAU,EAAE,MAAyC,CAAC;AAKnE,MAAM,WAAW,QAAQ;IACrB,2CAA2C;IAC3C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+BAA+B;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,wEAAwE;IACxE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,KAAK;IAClB,qEAAqE;IACrE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,iDAAiD;IACjD,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,oFAAoF;IACpF,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,6FAA6F;IAC7F,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;CAC5B;AAED,uEAAuE;AACvE,qBAAa,oBAAqB,SAAQ,KAAK;gBAC/B,MAAM,EAAE,MAAM;CAI7B;AAwED,sFAAsF;AACtF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAY1D;AAED,qEAAqE;AACrE,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CASvE;AAED,oFAAoF;AACpF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAE1D;AAED,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAkBjD;AAED,gGAAgG;AAChG,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,QAAQ,CAQtE;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,GAAG,SAAS,MAAM,EAAE,CAOvE;AAED,+DAA+D;AAC/D,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,KAAK,CAQ/D"}
|
package/lib/cost.js
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Цена контекста: чем заход платит за слой правил.
|
|
3
|
+
*
|
|
4
|
+
* Проверка длины считает строки одного файла, сводка наблюдений — загрузки и отбития. Сколько
|
|
5
|
+
* весит то, что заход получает целиком, не считает ничто, а окно кончается именно на этом.
|
|
6
|
+
*
|
|
7
|
+
* Считается не файл, а то, что заход получает: описание правила приходит ему полем, а не файлом
|
|
8
|
+
* целиком, и словарь с картой хода — выводом хуков, а не своими исходниками. Вес файла назвал
|
|
9
|
+
* бы не ту цену.
|
|
10
|
+
*
|
|
11
|
+
* Меряется в символах и байтах — тем, что считается на месте, без сети и без платы. Точный счёт
|
|
12
|
+
* токенов живёт у модели и стоит денег; работа его не требует. Цена этого решения названа
|
|
13
|
+
* прямо: число сравнимо только само с собой, и вопрос «дешевле ли та же мысль на другой
|
|
14
|
+
* письменности» этим счётом не решается — в символах письменности равны.
|
|
15
|
+
*/
|
|
16
|
+
import { execFileSync } from 'node:child_process';
|
|
17
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
18
|
+
import { join } from 'node:path';
|
|
19
|
+
/** Чем считано. Стоит рядом с числами: снятое иначе с этим несравнимо. */
|
|
20
|
+
export const COUNTED_BY = 'символы и байты, счёт на месте';
|
|
21
|
+
/** Хуки старта захода, чей вывод заход получает целиком. */
|
|
22
|
+
const ENTRY_HOOKS = ['glossary-load', 'turn-entry-load', 'constitution-index'];
|
|
23
|
+
/** Отказ, который команда печатает вместо чисел: сказано, чего нет. */
|
|
24
|
+
export class CostUnavailableError extends Error {
|
|
25
|
+
constructor(reason) {
|
|
26
|
+
super(`цену посчитать не на чем: ${reason}`);
|
|
27
|
+
this.name = 'CostUnavailableError';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** Описание правила — единственное, что агент видит, решая, грузить его или нет. */
|
|
31
|
+
function descriptionOf(file) {
|
|
32
|
+
const text = readFileSync(file, 'utf8');
|
|
33
|
+
const pattern = /^description:[^\n]*(?:\n[ \t]+[^\n]*)*/m;
|
|
34
|
+
const match = pattern.exec(text);
|
|
35
|
+
return match === null ? '' : match[0];
|
|
36
|
+
}
|
|
37
|
+
/** Каталог разложенных правил этого дерева. */
|
|
38
|
+
function skillsDir(root) {
|
|
39
|
+
return join(root, '.claude', 'skills');
|
|
40
|
+
}
|
|
41
|
+
/** Каталог законов этого дерева. */
|
|
42
|
+
function lawsDir(root) {
|
|
43
|
+
return join(root, 'docs', 'constitution');
|
|
44
|
+
}
|
|
45
|
+
/** Все файлы разметки под каталогом. Каталога нет — считать нечего, и это не отказ. */
|
|
46
|
+
function markdownUnder(dir) {
|
|
47
|
+
const found = [];
|
|
48
|
+
const walk = (current) => {
|
|
49
|
+
let entries;
|
|
50
|
+
try {
|
|
51
|
+
entries = readdirSync(current, { withFileTypes: true });
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
for (const entry of entries) {
|
|
57
|
+
const path = join(current, entry.name);
|
|
58
|
+
if (entry.isDirectory()) {
|
|
59
|
+
walk(path);
|
|
60
|
+
}
|
|
61
|
+
else if (entry.name.endsWith('.md')) {
|
|
62
|
+
found.push(path);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
walk(dir);
|
|
70
|
+
return found;
|
|
71
|
+
}
|
|
72
|
+
/** Имена разложенных правил. Каталога нет — слой не разложен, и считать нечего. */
|
|
73
|
+
function ruleNames(root) {
|
|
74
|
+
try {
|
|
75
|
+
return readdirSync(skillsDir(root));
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
throw new CostUnavailableError('слой правил в дереве не разложен');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/** Вывод хука старта — ровно то, что он кладёт заходу. Молчащий хук стоит ноль. */
|
|
82
|
+
function hookOutput(root, hook) {
|
|
83
|
+
const path = join(root, '.claude', 'hooks', `${hook}.sh`);
|
|
84
|
+
if (!existsSync(path)) {
|
|
85
|
+
return '';
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
return execFileSync(path, [], {
|
|
89
|
+
cwd: root,
|
|
90
|
+
input: JSON.stringify({ session_id: 'cost', cwd: root }),
|
|
91
|
+
encoding: 'utf8',
|
|
92
|
+
timeout: 30_000,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return '';
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/** Что заход получает до первой правки: описания всех правил и вывод хуков старта. */
|
|
100
|
+
export function entryTexts(root) {
|
|
101
|
+
const texts = [];
|
|
102
|
+
for (const name of ruleNames(root)) {
|
|
103
|
+
const file = join(skillsDir(root), name, 'SKILL.md');
|
|
104
|
+
if (existsSync(file)) {
|
|
105
|
+
texts.push(descriptionOf(file));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
for (const hook of ENTRY_HOOKS) {
|
|
109
|
+
texts.push(hookOutput(root, hook));
|
|
110
|
+
}
|
|
111
|
+
return texts.filter((text) => text.length > 0);
|
|
112
|
+
}
|
|
113
|
+
/** Правило вместе со спутником — столько стоит одна его загрузка. */
|
|
114
|
+
export function ruleTexts(root, rule) {
|
|
115
|
+
const dir = join(skillsDir(root), rule);
|
|
116
|
+
if (!existsSync(join(dir, 'SKILL.md'))) {
|
|
117
|
+
throw new CostUnavailableError(`правила «${rule}» в дереве нет`);
|
|
118
|
+
}
|
|
119
|
+
return ['SKILL.md', 'implementation.md']
|
|
120
|
+
.map((name) => join(dir, name))
|
|
121
|
+
.filter((file) => existsSync(file))
|
|
122
|
+
.map((file) => readFileSync(file, 'utf8'));
|
|
123
|
+
}
|
|
124
|
+
/** Весь слой разом: законы, правила и паттерны. Ни один заход столько не грузит. */
|
|
125
|
+
export function layerTexts(root) {
|
|
126
|
+
return [...markdownUnder(lawsDir(root)), ...markdownUnder(skillsDir(root))].map((file) => readFileSync(file, 'utf8'));
|
|
127
|
+
}
|
|
128
|
+
/** Правило с самым тяжёлым файлом — то, что берётся, когда имя не названо. */
|
|
129
|
+
export function heaviestRule(root) {
|
|
130
|
+
let heaviest = '';
|
|
131
|
+
let weight = -1;
|
|
132
|
+
for (const name of ruleNames(root)) {
|
|
133
|
+
const file = join(skillsDir(root), name, 'SKILL.md');
|
|
134
|
+
if (!existsSync(file)) {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const size = readFileSync(file, 'utf8').length;
|
|
138
|
+
if (size > weight) {
|
|
139
|
+
weight = size;
|
|
140
|
+
heaviest = name;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (heaviest === '') {
|
|
144
|
+
throw new CostUnavailableError('слой правил в дереве не разложен');
|
|
145
|
+
}
|
|
146
|
+
return heaviest;
|
|
147
|
+
}
|
|
148
|
+
/** Вес набора текстов: символы и байты. Байты считаются кодировкой, в которой файлы и лежат. */
|
|
149
|
+
export function weigh(what, texts) {
|
|
150
|
+
let chars = 0;
|
|
151
|
+
let bytes = 0;
|
|
152
|
+
for (const text of texts) {
|
|
153
|
+
chars += text.length;
|
|
154
|
+
bytes += Buffer.byteLength(text, 'utf8');
|
|
155
|
+
}
|
|
156
|
+
return { what, chars, bytes };
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Печать цены: таблица человеку либо разбор машине.
|
|
160
|
+
*
|
|
161
|
+
* Обе живут здесь, а не в строке запуска: числа кладут в замысел эпика и в разбор закрытой
|
|
162
|
+
* работы, и та половина, что никем не покрыта, расходится с другой молча.
|
|
163
|
+
*/
|
|
164
|
+
export function costLines(cost, json) {
|
|
165
|
+
if (json) {
|
|
166
|
+
return [JSON.stringify(cost, null, 2)];
|
|
167
|
+
}
|
|
168
|
+
const row = (weighed) => ` ${weighed.what.padEnd(34)} ${String(weighed.chars).padStart(9)} симв. ${String(weighed.bytes).padStart(10)} байт`;
|
|
169
|
+
return [`цена контекста — считано: ${cost.countedBy}`, '', row(cost.entry), row(cost.rule), row(cost.layer)];
|
|
170
|
+
}
|
|
171
|
+
/** Три числа цены: вход в работу, одно правило и весь слой. */
|
|
172
|
+
export function costOf(root, rule) {
|
|
173
|
+
const named = rule ?? heaviestRule(root);
|
|
174
|
+
return {
|
|
175
|
+
countedBy: COUNTED_BY,
|
|
176
|
+
entry: weigh('вход в работу', entryTexts(root)),
|
|
177
|
+
rule: weigh(`правило «${named}»`, ruleTexts(root, named)),
|
|
178
|
+
layer: weigh('весь слой', layerTexts(root)),
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=cost.js.map
|
package/lib/cost.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost.js","sourceRoot":"","sources":["../../../projects/agent-kit/src/lib/cost.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Цена контекста: чем заход платит за слой правил.\n *\n * Проверка длины считает строки одного файла, сводка наблюдений — загрузки и отбития. Сколько\n * весит то, что заход получает целиком, не считает ничто, а окно кончается именно на этом.\n *\n * Считается не файл, а то, что заход получает: описание правила приходит ему полем, а не файлом\n * целиком, и словарь с картой хода — выводом хуков, а не своими исходниками. Вес файла назвал\n * бы не ту цену.\n *\n * Меряется в символах и байтах — тем, что считается на месте, без сети и без платы. Точный счёт\n * токенов живёт у модели и стоит денег; работа его не требует. Цена этого решения названа\n * прямо: число сравнимо только само с собой, и вопрос «дешевле ли та же мысль на другой\n * письменности» этим счётом не решается — в символах письменности равны.\n */\nimport { execFileSync } from 'node:child_process';\nimport { Dirent, existsSync, readdirSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\n/** Чем считано. Стоит рядом с числами: снятое иначе с этим несравнимо. */\nexport const COUNTED_BY: string = 'символы и байты, счёт на месте';\n\n/** Хуки старта захода, чей вывод заход получает целиком. */\nconst ENTRY_HOOKS: readonly string[] = ['glossary-load', 'turn-entry-load', 'constitution-index'];\n\nexport interface IWeighed {\n /** Что взвешено — строкой для человека. */\n readonly what: string;\n /** Сколько в этом символов. */\n readonly chars: number;\n /** Сколько в этом байтов: у кириллицы их вдвое больше, чем символов. */\n readonly bytes: number;\n}\n\nexport interface ICost {\n /** Чем считано: без этого имени число несравнимо со снятым вчера. */\n readonly countedBy: string;\n /** Что заход получает до первой своей правки. */\n readonly entry: IWeighed;\n /** Одно правило вместе со спутником — столько стоит решение, которое его задело. */\n readonly rule: IWeighed;\n /** Все законы, правила и паттерны разом. Ни один заход столько не грузит; число про рост. */\n readonly layer: IWeighed;\n}\n\n/** Отказ, который команда печатает вместо чисел: сказано, чего нет. */\nexport class CostUnavailableError extends Error {\n constructor(reason: string) {\n super(`цену посчитать не на чем: ${reason}`);\n this.name = 'CostUnavailableError';\n }\n}\n\n/** Описание правила — единственное, что агент видит, решая, грузить его или нет. */\nfunction descriptionOf(file: string): string {\n const text: string = readFileSync(file, 'utf8');\n const pattern: RegExp = /^description:[^\\n]*(?:\\n[ \\t]+[^\\n]*)*/m;\n const match: RegExpExecArray | null = pattern.exec(text);\n return match === null ? '' : match[0];\n}\n\n/** Каталог разложенных правил этого дерева. */\nfunction skillsDir(root: string): string {\n return join(root, '.claude', 'skills');\n}\n\n/** Каталог законов этого дерева. */\nfunction lawsDir(root: string): string {\n return join(root, 'docs', 'constitution');\n}\n\n/** Все файлы разметки под каталогом. Каталога нет — считать нечего, и это не отказ. */\nfunction markdownUnder(dir: string): readonly string[] {\n const found: string[] = [];\n const walk: (current: string) => void = (current: string): void => {\n let entries: readonly Dirent[];\n try {\n entries = readdirSync(current, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n const path: string = join(current, entry.name);\n if (entry.isDirectory()) {\n walk(path);\n } else if (entry.name.endsWith('.md')) {\n found.push(path);\n } else {\n continue;\n }\n }\n };\n walk(dir);\n return found;\n}\n\n/** Имена разложенных правил. Каталога нет — слой не разложен, и считать нечего. */\nfunction ruleNames(root: string): readonly string[] {\n try {\n return readdirSync(skillsDir(root));\n } catch {\n throw new CostUnavailableError('слой правил в дереве не разложен');\n }\n}\n\n/** Вывод хука старта — ровно то, что он кладёт заходу. Молчащий хук стоит ноль. */\nfunction hookOutput(root: string, hook: string): string {\n const path: string = join(root, '.claude', 'hooks', `${hook}.sh`);\n if (!existsSync(path)) {\n return '';\n }\n try {\n return execFileSync(path, [], {\n cwd: root,\n input: JSON.stringify({ session_id: 'cost', cwd: root }),\n encoding: 'utf8',\n timeout: 30_000,\n });\n } catch {\n return '';\n }\n}\n\n/** Что заход получает до первой правки: описания всех правил и вывод хуков старта. */\nexport function entryTexts(root: string): readonly string[] {\n const texts: string[] = [];\n for (const name of ruleNames(root)) {\n const file: string = join(skillsDir(root), name, 'SKILL.md');\n if (existsSync(file)) {\n texts.push(descriptionOf(file));\n }\n }\n for (const hook of ENTRY_HOOKS) {\n texts.push(hookOutput(root, hook));\n }\n return texts.filter((text: string): boolean => text.length > 0);\n}\n\n/** Правило вместе со спутником — столько стоит одна его загрузка. */\nexport function ruleTexts(root: string, rule: string): readonly string[] {\n const dir: string = join(skillsDir(root), rule);\n if (!existsSync(join(dir, 'SKILL.md'))) {\n throw new CostUnavailableError(`правила «${rule}» в дереве нет`);\n }\n return ['SKILL.md', 'implementation.md']\n .map((name: string): string => join(dir, name))\n .filter((file: string): boolean => existsSync(file))\n .map((file: string): string => readFileSync(file, 'utf8'));\n}\n\n/** Весь слой разом: законы, правила и паттерны. Ни один заход столько не грузит. */\nexport function layerTexts(root: string): readonly string[] {\n return [...markdownUnder(lawsDir(root)), ...markdownUnder(skillsDir(root))].map((file: string): string => readFileSync(file, 'utf8'));\n}\n\n/** Правило с самым тяжёлым файлом — то, что берётся, когда имя не названо. */\nexport function heaviestRule(root: string): string {\n let heaviest: string = '';\n let weight: number = -1;\n for (const name of ruleNames(root)) {\n const file: string = join(skillsDir(root), name, 'SKILL.md');\n if (!existsSync(file)) {\n continue;\n }\n const size: number = readFileSync(file, 'utf8').length;\n if (size > weight) {\n weight = size;\n heaviest = name;\n }\n }\n if (heaviest === '') {\n throw new CostUnavailableError('слой правил в дереве не разложен');\n }\n return heaviest;\n}\n\n/** Вес набора текстов: символы и байты. Байты считаются кодировкой, в которой файлы и лежат. */\nexport function weigh(what: string, texts: readonly string[]): IWeighed {\n let chars: number = 0;\n let bytes: number = 0;\n for (const text of texts) {\n chars += text.length;\n bytes += Buffer.byteLength(text, 'utf8');\n }\n return { what, chars, bytes };\n}\n\n/**\n * Печать цены: таблица человеку либо разбор машине.\n *\n * Обе живут здесь, а не в строке запуска: числа кладут в замысел эпика и в разбор закрытой\n * работы, и та половина, что никем не покрыта, расходится с другой молча.\n */\nexport function costLines(cost: ICost, json: boolean): readonly string[] {\n if (json) {\n return [JSON.stringify(cost, null, 2)];\n }\n const row: (weighed: IWeighed) => string = (weighed: IWeighed): string =>\n ` ${weighed.what.padEnd(34)} ${String(weighed.chars).padStart(9)} симв. ${String(weighed.bytes).padStart(10)} байт`;\n return [`цена контекста — считано: ${cost.countedBy}`, '', row(cost.entry), row(cost.rule), row(cost.layer)];\n}\n\n/** Три числа цены: вход в работу, одно правило и весь слой. */\nexport function costOf(root: string, rule: string | null): ICost {\n const named: string = rule ?? heaviestRule(root);\n return {\n countedBy: COUNTED_BY,\n entry: weigh('вход в работу', entryTexts(root)),\n rule: weigh(`правило «${named}»`, ruleTexts(root, named)),\n layer: weigh('весь слой', layerTexts(root)),\n };\n}\n"]}
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|