@rt-tools/agent-kit 0.2.0 → 0.4.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 +235 -18
- package/assets/agents/business-analyst.md +74 -0
- package/assets/agents/project-manager.md +70 -0
- package/assets/agents/qa-engineer.md +72 -0
- package/assets/agents/skill-curator.md +110 -0
- package/assets/agents/spec-critic.md +44 -0
- package/assets/agents/spec-writer.md +50 -0
- package/assets/checks/board.github.mjs +286 -0
- package/assets/checks/check-board.github.mjs +188 -0
- package/assets/checks/check-doc-paths.mjs +163 -0
- package/assets/checks/check-dupes.mjs +277 -0
- package/assets/checks/check-lib-layers.mjs +573 -0
- package/assets/checks/check-reuse.mjs +208 -0
- package/assets/checks/check-schema-drift.mjs +186 -0
- package/assets/checks/check-specs.mjs +1007 -0
- package/assets/checks/check-styles.mjs +109 -0
- package/assets/checks/rt-kit-checks.config.mjs +134 -0
- package/assets/checks/task-new.github.mjs +198 -0
- package/assets/commands/skill-curator.md +70 -0
- package/assets/defaults/gate-map.sh +100 -0
- package/assets/defaults/project.sh +179 -0
- package/assets/hooks/browser-device-id.sh +20 -0
- package/assets/hooks/browser-guard-device-id.sh +28 -0
- package/assets/hooks/browser-guard-no-asking.sh +27 -0
- package/assets/hooks/browser-guard-no-listing.sh +18 -0
- package/assets/hooks/browser-guard-no-other-drivers.sh +79 -0
- package/assets/hooks/browser-guard-require-select.sh +54 -0
- package/assets/hooks/commit-msg.sh +26 -0
- package/assets/hooks/constitution-index.sh +43 -0
- package/assets/hooks/dev-server-guard.sh +115 -0
- package/assets/hooks/docs-guard.sh +282 -0
- package/assets/hooks/git-guard-delivery.sh +167 -0
- package/assets/hooks/git-guard-main.sh +73 -0
- package/assets/hooks/git-guard-push-tests.sh +94 -0
- package/assets/hooks/glossary-load.sh +23 -0
- package/assets/hooks/lint-after-edit.sh +219 -0
- package/assets/hooks/qa-dataid-guard.sh +121 -0
- package/assets/hooks/reuse-first-guard.sh +154 -0
- package/assets/hooks/skill-gate-rearm.sh +23 -0
- package/assets/hooks/skill-gate.sh +128 -0
- package/assets/hooks/skill-loaded.sh +21 -0
- package/assets/hooks/sql-guard.sh +679 -0
- package/assets/hooks/task-context-load.sh +100 -0
- package/assets/hooks/task-flow-guard.sh +107 -0
- package/assets/laws/{access.md → application/access.md} +1 -4
- package/assets/laws/{locales.md → application/locales.md} +1 -3
- package/assets/laws/application/money.md +41 -0
- package/assets/laws/application/ownership.md +32 -0
- package/assets/laws/{search-visibility.md → application/search-visibility.md} +1 -1
- package/assets/laws/code-structure.md +7 -6
- package/assets/laws/delivery.md +53 -3
- package/assets/laws/entity-editing.md +49 -55
- package/assets/laws/entity-models.md +4 -14
- package/assets/laws/frontend-application.md +5 -5
- package/assets/laws/lib-imports.md +14 -1
- package/assets/laws/lists.md +33 -0
- package/assets/laws/navigation.md +40 -0
- package/assets/laws/project-documentation.md +17 -8
- package/assets/laws/reuse-first.md +26 -21
- package/assets/laws/shared-code.md +13 -1
- package/assets/laws/verifiability.md +17 -1
- package/assets/laws/work-conduct.md +48 -0
- package/assets/patterns/admin-lists-screen.md +131 -0
- package/assets/patterns/admin-nav-item.md +71 -0
- package/assets/patterns/angular-patterns-state.md +101 -0
- package/assets/patterns/api-layer-pair.md +88 -0
- package/assets/patterns/browser-verification-measure.md +86 -0
- package/assets/patterns/browser-verification-stand.md +143 -0
- package/assets/patterns/component-structure-new.md +99 -0
- package/assets/patterns/dependencies-upgrade.md +65 -0
- package/assets/patterns/doc-style-sweep.md +137 -0
- package/assets/patterns/doc-style-write.md +109 -0
- package/assets/patterns/entity-aside.md +136 -0
- package/assets/patterns/entity-models-new.md +124 -0
- package/assets/patterns/entity-store.md +91 -0
- package/assets/patterns/git-workflow-commit.azure.md +259 -0
- package/assets/patterns/git-workflow-commit.github.md +333 -0
- package/assets/patterns/git-workflow-commit.gitlab.md +283 -0
- package/assets/patterns/git-workflow-merge.md +99 -0
- package/assets/patterns/git-workflow-migration.md +88 -0
- package/assets/patterns/git-workflow-restart.md +49 -0
- package/assets/patterns/lib-layers-move.md +95 -0
- package/assets/patterns/lib-layers-new.md +82 -0
- package/assets/patterns/ownership-scope-resolve.md +69 -0
- package/assets/patterns/permissions-procedure.md +71 -0
- package/assets/patterns/platform-access-di.md +84 -0
- package/assets/patterns/pricing-quote.md +71 -0
- package/assets/patterns/reuse-first-extend.md +73 -0
- package/assets/patterns/seo-page.md +104 -0
- package/assets/patterns/seo-verify.md +83 -0
- package/assets/patterns/shared-code-new.md +86 -0
- package/assets/patterns/spec-driven-domain.md +107 -0
- package/assets/patterns/spec-driven-rule.md +127 -0
- package/assets/patterns/styling-bem-component.md +88 -0
- package/assets/patterns/styling-bem-layout.md +73 -0
- package/assets/patterns/task-flow-close.md +90 -0
- package/assets/patterns/task-flow-resume.md +94 -0
- package/assets/patterns/task-flow-start.md +117 -0
- package/assets/patterns/testing-e2e.md +92 -0
- package/assets/patterns/testing-unit.md +117 -0
- package/assets/patterns/translations-key.md +64 -0
- package/assets/patterns/ts-procedure.md +65 -0
- package/assets/rules/angular-patterns.md +71 -0
- package/assets/rules/api-layer.md +71 -0
- package/assets/rules/browser-verification.md +87 -0
- package/assets/rules/component-structure.md +64 -0
- package/assets/rules/dependencies.md +66 -0
- package/assets/rules/doc-style.md +103 -0
- package/assets/rules/entity-conventions.md +78 -0
- package/assets/rules/entity-models.md +70 -0
- package/assets/rules/git-workflow.azure.md +116 -0
- package/assets/rules/git-workflow.github.md +123 -0
- package/assets/rules/git-workflow.gitlab.md +113 -0
- package/assets/rules/lib-layers.md +80 -0
- package/assets/rules/lists.md +73 -0
- package/assets/rules/navigation.md +78 -0
- package/assets/rules/ownership-scope.md +63 -0
- package/assets/rules/permissions.md +70 -0
- package/assets/rules/platform-access.md +77 -0
- package/assets/rules/pricing.md +64 -0
- package/assets/rules/reuse-first.md +83 -0
- package/assets/rules/seo.md +71 -0
- package/assets/rules/shared-code.md +70 -0
- package/assets/rules/spec-driven.md +135 -0
- package/assets/rules/styling-bem.md +74 -0
- package/assets/rules/task-flow.md +110 -0
- package/assets/rules/testing.md +100 -0
- package/assets/rules/translations.md +69 -0
- package/assets/rules/typescript-conventions.md +76 -0
- package/assets/skills/agent-kit.md +81 -0
- package/assets/skills/write-a-skill.md +108 -0
- package/assets/templates/gate-map.sh +45 -0
- package/assets/templates/implementation.md +44 -0
- package/assets/templates/pattern.md +5 -1
- package/assets/templates/project.sh +54 -0
- package/assets/templates/rule.md +12 -23
- package/assets/variants.json +20 -0
- package/assets/workflows/feature.js +134 -0
- package/assets/workflows/plan.js +150 -0
- package/bin/agent-kit.d.ts.map +1 -1
- package/bin/agent-kit.js +78 -5
- package/bin/agent-kit.js.map +1 -1
- package/bin/prompt.d.ts +5 -0
- package/bin/prompt.d.ts.map +1 -1
- package/bin/prompt.js +19 -7
- package/bin/prompt.js.map +1 -1
- package/index.d.ts +1 -0
- package/index.d.ts.map +1 -1
- package/index.js +1 -0
- package/index.js.map +1 -1
- package/lib/assets.d.ts +14 -1
- package/lib/assets.d.ts.map +1 -1
- package/lib/assets.js +23 -2
- package/lib/assets.js.map +1 -1
- package/lib/catalog.d.ts +52 -5
- package/lib/catalog.d.ts.map +1 -1
- package/lib/catalog.js +104 -16
- package/lib/catalog.js.map +1 -1
- package/lib/commands.d.ts +22 -1
- package/lib/commands.d.ts.map +1 -1
- package/lib/commands.js +218 -11
- package/lib/commands.js.map +1 -1
- package/lib/companion.d.ts +57 -0
- package/lib/companion.d.ts.map +1 -0
- package/lib/companion.js +60 -0
- package/lib/companion.js.map +1 -0
- package/lib/config.d.ts +42 -2
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js +60 -2
- package/lib/config.js.map +1 -1
- package/lib/freshness.d.ts +14 -0
- package/lib/freshness.d.ts.map +1 -0
- package/lib/freshness.js +116 -0
- package/lib/freshness.js.map +1 -0
- package/lib/hooks-map.d.ts +24 -0
- package/lib/hooks-map.d.ts.map +1 -0
- package/lib/hooks-map.js +72 -0
- package/lib/hooks-map.js.map +1 -0
- package/lib/integrity.d.ts +36 -0
- package/lib/integrity.d.ts.map +1 -0
- package/lib/integrity.js +44 -0
- package/lib/integrity.js.map +1 -0
- package/lib/picker.d.ts +11 -1
- package/lib/picker.d.ts.map +1 -1
- package/lib/picker.js +44 -6
- package/lib/picker.js.map +1 -1
- package/lib/stamp.d.ts +2 -5
- package/lib/stamp.d.ts.map +1 -1
- package/lib/stamp.js +25 -10
- package/lib/stamp.js.map +1 -1
- package/lib/sync.d.ts +29 -0
- package/lib/sync.d.ts.map +1 -1
- package/lib/sync.js +78 -4
- package/lib/sync.js.map +1 -1
- package/lib/variants.d.ts +44 -0
- package/lib/variants.d.ts.map +1 -0
- package/lib/variants.js +82 -0
- package/lib/variants.js.map +1 -0
- package/package.json +1 -1
- package/rt-tools-agent-kit-0.4.0.tgz +0 -0
- package/assets/laws/admin-lists.md +0 -35
- package/assets/laws/admin-navigation.md +0 -38
- package/rt-tools-agent-kit-0.2.0.tgz +0 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
export const meta = {
|
|
2
|
+
name: 'plan',
|
|
3
|
+
description: 'После разбора с владельцем: нужна ли работа, договорённость о продукте, её состязательный разбор и замысел реализации',
|
|
4
|
+
whenToUse: 'Разбор просьбы владельца закрыт, папка задачи заведена, код ещё не пишется',
|
|
5
|
+
phases: [
|
|
6
|
+
{ title: 'Нужность', detail: 'что даёт работа и что из неё выкидывается' },
|
|
7
|
+
{ title: 'Договорённость', detail: 'спек фичи в proposed/ по разбору' },
|
|
8
|
+
{ title: 'Критика', detail: 'что в договорённости недосказано' },
|
|
9
|
+
{ title: 'Замысел', detail: 'этапы с признаками готовности и разбивка на задачи' },
|
|
10
|
+
],
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// Папка задачи приходит в args; без неё конвейеру нечего читать. Разбор просьбы владельца
|
|
14
|
+
// лежит в ней и остаётся единственным источником: пересказывать его в промпте значит терять
|
|
15
|
+
// слова владельца, ради которых он и записан.
|
|
16
|
+
const dir = typeof args === 'string' ? args : (args?.dir ?? '');
|
|
17
|
+
if (!dir) {
|
|
18
|
+
throw new Error('Нужна папка задачи: передай её строкой в args, например docs/tasks/<ветка>');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const grill = `${dir}/grill.md`;
|
|
22
|
+
|
|
23
|
+
const WORTH = {
|
|
24
|
+
type: 'object',
|
|
25
|
+
additionalProperties: false,
|
|
26
|
+
required: ['verdict', 'gives', 'drop'],
|
|
27
|
+
properties: {
|
|
28
|
+
verdict: { type: 'string', enum: ['делать', 'делать урезанно', 'отложить'] },
|
|
29
|
+
gives: { type: 'string', description: 'что владелец получит' },
|
|
30
|
+
drop: { type: 'array', items: { type: 'string' }, description: 'что выкидывается без потери цели' },
|
|
31
|
+
risks: { type: 'array', items: { type: 'string' } },
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const DRAFT = {
|
|
36
|
+
type: 'object',
|
|
37
|
+
additionalProperties: false,
|
|
38
|
+
required: ['path', 'rules', 'gaps'],
|
|
39
|
+
properties: {
|
|
40
|
+
path: { type: 'string', description: 'заведённая директория в docs/specs/*/proposed/' },
|
|
41
|
+
rules: { type: 'array', items: { type: 'string' }, description: 'правила по одной строке' },
|
|
42
|
+
gaps: { type: 'array', items: { type: 'string' }, description: 'пробелы, которые не закрыть без владельца' },
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const FINDINGS = {
|
|
47
|
+
type: 'object',
|
|
48
|
+
additionalProperties: false,
|
|
49
|
+
required: ['findings'],
|
|
50
|
+
properties: {
|
|
51
|
+
findings: {
|
|
52
|
+
type: 'array',
|
|
53
|
+
items: {
|
|
54
|
+
type: 'object',
|
|
55
|
+
additionalProperties: false,
|
|
56
|
+
required: ['what', 'where', 'cost'],
|
|
57
|
+
properties: {
|
|
58
|
+
what: { type: 'string', description: 'что недосказано' },
|
|
59
|
+
where: { type: 'string', description: 'файл и правило дословно' },
|
|
60
|
+
cost: { type: 'string', description: 'чем обернётся в коде' },
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const PLAN = {
|
|
68
|
+
type: 'object',
|
|
69
|
+
additionalProperties: false,
|
|
70
|
+
required: ['tasks', 'steps', 'acceptance'],
|
|
71
|
+
properties: {
|
|
72
|
+
tasks: {
|
|
73
|
+
type: 'array',
|
|
74
|
+
description: 'на сколько задач делится работа; одна — обычный случай',
|
|
75
|
+
items: {
|
|
76
|
+
type: 'object',
|
|
77
|
+
additionalProperties: false,
|
|
78
|
+
required: ['title', 'slug', 'why'],
|
|
79
|
+
properties: {
|
|
80
|
+
title: { type: 'string' },
|
|
81
|
+
slug: { type: 'string' },
|
|
82
|
+
why: { type: 'string', description: 'почему это откатывается отдельно' },
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
steps: {
|
|
87
|
+
type: 'array',
|
|
88
|
+
maxItems: 8,
|
|
89
|
+
items: {
|
|
90
|
+
type: 'object',
|
|
91
|
+
additionalProperties: false,
|
|
92
|
+
required: ['title', 'scope', 'done'],
|
|
93
|
+
properties: {
|
|
94
|
+
title: { type: 'string' },
|
|
95
|
+
scope: { type: 'string', description: 'что входит и что НЕ входит' },
|
|
96
|
+
done: { type: 'string', description: 'проверяемый признак готовности' },
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
acceptance: { type: 'array', items: { type: 'string' } },
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
phase('Нужность');
|
|
105
|
+
const worth = await agent(
|
|
106
|
+
`Разбор просьбы владельца — \`${grill}\`. Прочитай его целиком.\n\n` +
|
|
107
|
+
`Скажи, что эта работа даёт владельцу, что из неё выкидывается без потери цели и почему её ` +
|
|
108
|
+
`стоит делать сейчас, а не через полгода. Отвергнутое называй с причиной.`,
|
|
109
|
+
{ agentType: 'business-analyst', label: 'нужность', schema: WORTH }
|
|
110
|
+
);
|
|
111
|
+
log(`Нужность: ${worth.verdict}; выкидывается пунктов ${worth.drop.length}`);
|
|
112
|
+
|
|
113
|
+
if (worth.verdict === 'отложить') {
|
|
114
|
+
log('Работа не начинается: решение относится владельцу.');
|
|
115
|
+
return { worth, stopped: 'аналитик предложил отложить — решение за владельцем' };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
phase('Договорённость');
|
|
119
|
+
const draft = await agent(
|
|
120
|
+
`Разбор просьбы владельца — \`${grill}\`. Прочитай его целиком и напиши по нему договорённость ` +
|
|
121
|
+
`о продукте: \`docs/specs/<домен>/proposed/<фича>/\`.\n\n` +
|
|
122
|
+
`Из работы выкинуто: ${worth.drop.join('; ') || '— ничего'}.\n\n` +
|
|
123
|
+
`Пробелы, которые не закрываются разбором, не додумывай — верни их списком.`,
|
|
124
|
+
{ agentType: 'spec-writer', label: 'договорённость', schema: DRAFT }
|
|
125
|
+
);
|
|
126
|
+
log(`Договорённость: ${draft.path}, правил ${draft.rules.length}, пробелов ${draft.gaps.length}`);
|
|
127
|
+
|
|
128
|
+
phase('Критика');
|
|
129
|
+
const critique = await agent(
|
|
130
|
+
`Договорённость — \`${draft.path}\`, разбор просьбы владельца — \`${grill}\`.\n\n` +
|
|
131
|
+
`Состязательно разбери договорённость: что недосказано, где два прочтения, какие случаи ` +
|
|
132
|
+
`не названы. Ничего не правь.`,
|
|
133
|
+
{ agentType: 'spec-critic', label: 'критика', schema: FINDINGS }
|
|
134
|
+
);
|
|
135
|
+
log(`Критика: находок ${critique.findings.length}`);
|
|
136
|
+
|
|
137
|
+
phase('Замысел');
|
|
138
|
+
const plan = await agent(
|
|
139
|
+
`Разбор просьбы владельца — \`${grill}\`, договорённость — \`${draft.path}\`.\n\n` +
|
|
140
|
+
`Находки состязательного разбора:\n${critique.findings.map((f) => `- ${f.what} (${f.where})`).join('\n') || '— нет'}\n\n` +
|
|
141
|
+
`Собери замысел реализации: этапы с границами и проверяемым признаком готовности у каждого. ` +
|
|
142
|
+
`Отдельно скажи, на сколько задач делится работа: делится то, что придётся откатывать порознь, ` +
|
|
143
|
+
`а не то, что просто объёмно. Одна задача — обычный случай.`,
|
|
144
|
+
{ agentType: 'project-manager', label: 'замысел', schema: PLAN }
|
|
145
|
+
);
|
|
146
|
+
log(`Замысел: задач ${plan.tasks.length}, этапов ${plan.steps.length}`);
|
|
147
|
+
|
|
148
|
+
// Ничего не записывается на диск отсюда: замысел и пробелы уходят владельцу, а `plan.md`
|
|
149
|
+
// пишет главный агент — вопросы к владельцу задаёт только он.
|
|
150
|
+
return { worth, draft, critique: critique.findings, plan };
|
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":";AAaA,OAAO,
|
|
1
|
+
{"version":3,"file":"agent-kit.d.ts","sourceRoot":"","sources":["../../../projects/agent-kit/src/bin/agent-kit.ts"],"names":[],"mappings":";AAaA,OAAO,EAAqC,iBAAiB,EAAc,MAAM,oBAAoB,CAAC;AAoKtG,wBAAsB,IAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAqC9E"}
|
package/bin/agent-kit.js
CHANGED
|
@@ -10,9 +10,11 @@ import { dirname, join, resolve } from 'node:path';
|
|
|
10
10
|
import { fileURLToPath } from 'node:url';
|
|
11
11
|
import process from 'node:process';
|
|
12
12
|
import { readCatalog, resolveSelection } from '../lib/catalog.js';
|
|
13
|
-
import { doctor, init, list, sync } from '../lib/commands.js';
|
|
13
|
+
import { adopt, doctor, init, list, sync } from '../lib/commands.js';
|
|
14
|
+
import { staleBuild } from '../lib/freshness.js';
|
|
14
15
|
import { packageRootFrom } from '../lib/package-root.js';
|
|
15
|
-
import {
|
|
16
|
+
import { readAxes } from '../lib/variants.js';
|
|
17
|
+
import { ask, askOne, canAsk } from './prompt.js';
|
|
16
18
|
const USAGE = [
|
|
17
19
|
'agent-kit <команда>',
|
|
18
20
|
'',
|
|
@@ -21,6 +23,7 @@ const USAGE = [
|
|
|
21
23
|
' sync разложить ресурсы пакета в дерево проекта',
|
|
22
24
|
' sync --check ничего не писать, отказать при расхождении — для гейта пуша',
|
|
23
25
|
' doctor рассказать о состоянии раскладки, ничего не меняя',
|
|
26
|
+
' adopt [файлы] отдать пакету файлы, лежащие на его путях не от него',
|
|
24
27
|
'',
|
|
25
28
|
' --root <путь> корень проекта; по умолчанию текущий каталог',
|
|
26
29
|
'',
|
|
@@ -29,6 +32,11 @@ const USAGE = [
|
|
|
29
32
|
' --all взять все законы, ни о чём не спрашивая',
|
|
30
33
|
' --laws a,b,c взять только названные; имена — из `agent-kit list`',
|
|
31
34
|
' без обоих спросить галочками; без терминала — отказ',
|
|
35
|
+
'',
|
|
36
|
+
'Вид ресурсов при `init` — там, где один закон исполняется разными командами:',
|
|
37
|
+
'',
|
|
38
|
+
' --<ось> <вид> например `--host gitlab`; оси и виды — из `agent-kit list`',
|
|
39
|
+
' без флага спросить; без терминала — отказ, кроме `--all`',
|
|
32
40
|
];
|
|
33
41
|
/**
|
|
34
42
|
* Единственное место, где пакет узнаёт собственное расположение. `import.meta` живёт только
|
|
@@ -37,8 +45,15 @@ const USAGE = [
|
|
|
37
45
|
*/
|
|
38
46
|
function environmentOf(root) {
|
|
39
47
|
const pkg = packageRootFrom(dirname(fileURLToPath(import.meta.url)));
|
|
40
|
-
const
|
|
41
|
-
return {
|
|
48
|
+
const manifest = JSON.parse(readFileSync(join(pkg, 'package.json'), 'utf8'));
|
|
49
|
+
return {
|
|
50
|
+
root,
|
|
51
|
+
version: manifest.version,
|
|
52
|
+
assetsDir: join(pkg, 'assets'),
|
|
53
|
+
// Сверка со своими исходниками возможна только отсюда: здесь пакет знает, где лежит сам.
|
|
54
|
+
// У потребителя исходников рядом нет, и сверка молчит.
|
|
55
|
+
stale: staleBuild(pkg, manifest.name),
|
|
56
|
+
};
|
|
42
57
|
}
|
|
43
58
|
function optionOf(argv, name, fallback) {
|
|
44
59
|
const index = argv.indexOf(name);
|
|
@@ -82,6 +97,53 @@ async function selectionFor(argv, assetsDir) {
|
|
|
82
97
|
.map((entry) => ({ id: entry.id, name: entry.name, title: entry.title }));
|
|
83
98
|
return ask(choices, 'Какие законы разложить в этом проекте?');
|
|
84
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Виды для `init` по осям, объявленным пакетом: что взято из флага, что спрошено.
|
|
102
|
+
*
|
|
103
|
+
* `--all` берёт первый объявленный вид оси и **говорит об этом**: в CI спрашивать некого, а
|
|
104
|
+
* отказ там означал бы, что пакет нельзя разложить без человека. Первый вид — умолчание, а не
|
|
105
|
+
* догадка: порядок в объявлении оси и есть порядок предпочтения.
|
|
106
|
+
*/
|
|
107
|
+
async function variantsFor(argv, assetsDir) {
|
|
108
|
+
const axes = readAxes(assetsDir);
|
|
109
|
+
const chosen = {};
|
|
110
|
+
for (const axis of axes) {
|
|
111
|
+
const spoken = optionOf(argv, `--${axis.name}`, '');
|
|
112
|
+
const known = (value) => axis.options.some((option) => option.value === value);
|
|
113
|
+
if (spoken) {
|
|
114
|
+
if (!known(spoken)) {
|
|
115
|
+
return {
|
|
116
|
+
code: 1,
|
|
117
|
+
lines: [
|
|
118
|
+
`такого вида по оси «${axis.name}» пакет не везёт: ${spoken}`,
|
|
119
|
+
`есть: ${axis.options.map((option) => option.value).join(', ')}`,
|
|
120
|
+
],
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
chosen[axis.name] = spoken;
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (argv.includes('--all')) {
|
|
127
|
+
chosen[axis.name] = axis.options[0]?.value ?? '';
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
if (!canAsk()) {
|
|
131
|
+
return {
|
|
132
|
+
code: 1,
|
|
133
|
+
lines: [
|
|
134
|
+
'спросить некого: запуск без терминала',
|
|
135
|
+
`назови вид флагом \`--${axis.name} <вид>\`: ${axis.options.map((option) => option.value).join(', ')}`,
|
|
136
|
+
],
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
const answer = await askOne(axis.options.map((option) => ({ id: option.value, name: option.value, title: option.title })), axis.question);
|
|
140
|
+
if (answer === null) {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
chosen[axis.name] = answer;
|
|
144
|
+
}
|
|
145
|
+
return chosen;
|
|
146
|
+
}
|
|
85
147
|
export async function main(argv) {
|
|
86
148
|
const command = argv[0] ?? '';
|
|
87
149
|
const env = environmentOf(resolve(optionOf(argv, '--root', process.cwd())));
|
|
@@ -91,7 +153,16 @@ export async function main(argv) {
|
|
|
91
153
|
if (isOutcome(selection)) {
|
|
92
154
|
return selection;
|
|
93
155
|
}
|
|
94
|
-
|
|
156
|
+
if (selection === null) {
|
|
157
|
+
return { code: 1, lines: ['выбор брошен — ничего не заведено'] };
|
|
158
|
+
}
|
|
159
|
+
const variants = await variantsFor(argv, env.assetsDir);
|
|
160
|
+
if (isOutcome(variants)) {
|
|
161
|
+
return variants;
|
|
162
|
+
}
|
|
163
|
+
return variants === null
|
|
164
|
+
? { code: 1, lines: ['выбор брошен — ничего не заведено'] }
|
|
165
|
+
: init(env.root, selection, variants, env.assetsDir);
|
|
95
166
|
}
|
|
96
167
|
case 'list':
|
|
97
168
|
return list(env);
|
|
@@ -99,6 +170,8 @@ export async function main(argv) {
|
|
|
99
170
|
return sync(env, argv.includes('--check'));
|
|
100
171
|
case 'doctor':
|
|
101
172
|
return doctor(env);
|
|
173
|
+
case 'adopt':
|
|
174
|
+
return adopt(env, argv.slice(1).filter((value) => !value.startsWith('--') && value !== optionOf(argv, '--root', '')));
|
|
102
175
|
default:
|
|
103
176
|
return { code: command ? 1 : 0, lines: command ? [`неизвестная команда «${command}»`, '', ...USAGE] : USAGE };
|
|
104
177
|
}
|
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 { readFileSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport process from 'node:process';\n\nimport { IEntryOfCatalog, readCatalog, resolveSelection } from '../lib/catalog.js';\nimport { doctor, IEnvironment, init, IOutcomeOfCommand, list, sync } from '../lib/commands.js';\nimport { packageRootFrom } from '../lib/package-root.js';\nimport { IChoice } from '../lib/picker.js';\nimport { ask, 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 '',\n ' --root <путь> корень проекта; по умолчанию текущий каталог',\n '',\n 'Выбор законов при `init`:',\n '',\n ' --all взять все законы, ни о чём не спрашивая',\n ' --laws a,b,c взять только названные; имена — из `agent-kit list`',\n ' без обоих спросить галочками; без терминала — отказ',\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 version: string = (JSON.parse(readFileSync(join(pkg, 'package.json'), 'utf8')) as { version: string }).version;\n\n return { root, version, assetsDir: join(pkg, 'assets') };\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\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\n switch (command) {\n case 'init': {\n const selection: readonly string[] | null | IOutcomeOfCommand = await selectionFor(argv, env.assetsDir);\n if (isOutcome(selection)) {\n return selection;\n }\n\n return selection === null ? { code: 1, lines: ['выбор брошен — ничего не заведено'] } : init(env.root, selection);\n }\n case 'list':\n return list(env);\n case 'sync':\n return sync(env, argv.includes('--check'));\n case 'doctor':\n return doctor(env);\n default:\n return { code: command ? 1 : 0, lines: command ? [`неизвестная команда «${command}»`, '', ...USAGE] : USAGE };\n }\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 { readFileSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport process from 'node:process';\n\nimport { IEntryOfCatalog, readCatalog, resolveSelection } from '../lib/catalog.js';\nimport { adopt, doctor, IEnvironment, init, IOutcomeOfCommand, list, sync } from '../lib/commands.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 ' adopt [файлы] отдать пакету файлы, лежащие на его путях не от него',\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 * Единственное место, где пакет узнаёт собственное расположение. `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\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 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 spoken: string = optionOf(argv, `--${axis.name}`, '');\n const known: (value: string) => boolean = (value: string): boolean =>\n axis.options.some((option: IOptionOfAxis): boolean => option.value === value);\n\n if (spoken) {\n if (!known(spoken)) {\n return {\n code: 1,\n lines: [\n `такого вида по оси «${axis.name}» пакет не везёт: ${spoken}`,\n `есть: ${axis.options.map((option: IOptionOfAxis): string => option.value).join(', ')}`,\n ],\n };\n }\n chosen[axis.name] = spoken;\n continue;\n }\n\n if (argv.includes('--all')) {\n chosen[axis.name] = axis.options[0]?.value ?? '';\n continue;\n }\n\n if (!canAsk()) {\n return {\n code: 1,\n lines: [\n 'спросить некого: запуск без терминала',\n `назови вид флагом \\`--${axis.name} <вид>\\`: ${axis.options.map((option: IOptionOfAxis): string => option.value).join(', ')}`,\n ],\n };\n }\n\n const answer: string | null = await askOne(\n axis.options.map((option: IOptionOfAxis): IChoice => ({ id: option.value, name: option.value, title: option.title })),\n axis.question\n );\n if (answer === null) {\n return null;\n }\n chosen[axis.name] = answer;\n }\n\n return chosen;\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\n switch (command) {\n case 'init': {\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 case 'list':\n return list(env);\n case 'sync':\n return sync(env, argv.includes('--check'));\n case 'doctor':\n return doctor(env);\n case 'adopt':\n return adopt(\n env,\n argv.slice(1).filter((value: string): boolean => !value.startsWith('--') && value !== optionOf(argv, '--root', ''))\n );\n default:\n return { code: command ? 1 : 0, lines: command ? [`неизвестная команда «${command}»`, '', ...USAGE] : USAGE };\n }\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/bin/prompt.d.ts
CHANGED
|
@@ -6,4 +6,9 @@ export declare const canAsk: () => boolean;
|
|
|
6
6
|
* подставлять вместо ответа умолчание нельзя, потому что «взять всё» — тоже решение.
|
|
7
7
|
*/
|
|
8
8
|
export declare function ask(choices: readonly IChoice[], question: string): Promise<readonly string[] | null>;
|
|
9
|
+
/**
|
|
10
|
+
* Выбор одного из. Тем же путём и с тем же брошенным выбором: вид, выбранный за проект молча,
|
|
11
|
+
* разложил бы ему чужой git-flow — и заметил бы это тот, кто пошёл открывать заявку на слияние.
|
|
12
|
+
*/
|
|
13
|
+
export declare function askOne(choices: readonly IChoice[], question: string): Promise<string | null>;
|
|
9
14
|
//# sourceMappingURL=prompt.d.ts.map
|
package/bin/prompt.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../../projects/agent-kit/src/bin/prompt.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../../projects/agent-kit/src/bin/prompt.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,OAAO,EAAoE,MAAM,kBAAkB,CAAC;AAM7G,wFAAwF;AACxF,eAAO,MAAM,MAAM,EAAE,MAAM,OAA6E,CAAC;AAoDzG;;;GAGG;AACH,wBAAgB,GAAG,CAAC,OAAO,EAAE,SAAS,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC,CAEpG;AAED;;;GAGG;AACH,wBAAsB,MAAM,CAAC,OAAO,EAAE,SAAS,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAIlG"}
|
package/bin/prompt.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* неё: ввод перестаёт отзываться, и виноватым выглядит терминал.
|
|
8
8
|
*/
|
|
9
9
|
import process from 'node:process';
|
|
10
|
-
import { pickerOf, pressChunk, renderPicker } from '../lib/picker.js';
|
|
10
|
+
import { pickerOf, pressChunk, renderPicker, singlePickerOf } from '../lib/picker.js';
|
|
11
11
|
const HIDE_CURSOR = `${String.fromCharCode(27)}[?25l`;
|
|
12
12
|
const SHOW_CURSOR = `${String.fromCharCode(27)}[?25h`;
|
|
13
13
|
const UP_AND_CLEAR = `${String.fromCharCode(27)}[1A${String.fromCharCode(27)}[2K`;
|
|
@@ -18,16 +18,13 @@ function draw(state, question, previous) {
|
|
|
18
18
|
process.stdout.write(UP_AND_CLEAR.repeat(previous) + lines.join('\n') + '\n');
|
|
19
19
|
return lines.length;
|
|
20
20
|
}
|
|
21
|
-
/**
|
|
22
|
-
|
|
23
|
-
* подставлять вместо ответа умолчание нельзя, потому что «взять всё» — тоже решение.
|
|
24
|
-
*/
|
|
25
|
-
export function ask(choices, question) {
|
|
21
|
+
/** Спрашивание как таковое: сырой режим, перерисовка и возврат терминала на любом выходе. */
|
|
22
|
+
function askWith(start, choices, question) {
|
|
26
23
|
if (!choices.length) {
|
|
27
24
|
return Promise.resolve([]);
|
|
28
25
|
}
|
|
29
26
|
return new Promise((resolve) => {
|
|
30
|
-
let state =
|
|
27
|
+
let state = start(choices);
|
|
31
28
|
let drawn = 0;
|
|
32
29
|
/** Обработчик приходит доводом, чтобы отпустить терминал ровно тот, что его занял. */
|
|
33
30
|
const stop = (handler) => {
|
|
@@ -54,4 +51,19 @@ export function ask(choices, question) {
|
|
|
54
51
|
process.stdin.on('data', onData);
|
|
55
52
|
});
|
|
56
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Выбор галочками. Возвращает выбранные идентификаторы, а на брошенном выборе — `null`:
|
|
56
|
+
* подставлять вместо ответа умолчание нельзя, потому что «взять всё» — тоже решение.
|
|
57
|
+
*/
|
|
58
|
+
export function ask(choices, question) {
|
|
59
|
+
return askWith(pickerOf, choices, question);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Выбор одного из. Тем же путём и с тем же брошенным выбором: вид, выбранный за проект молча,
|
|
63
|
+
* разложил бы ему чужой git-flow — и заметил бы это тот, кто пошёл открывать заявку на слияние.
|
|
64
|
+
*/
|
|
65
|
+
export async function askOne(choices, question) {
|
|
66
|
+
const chosen = await askWith(singlePickerOf, choices, question);
|
|
67
|
+
return chosen?.length ? chosen[0] : null;
|
|
68
|
+
}
|
|
57
69
|
//# sourceMappingURL=prompt.js.map
|
package/bin/prompt.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../../projects/agent-kit/src/bin/prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,OAAO,MAAM,cAAc,CAAC;AAEnC,OAAO,EAAyB,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../../projects/agent-kit/src/bin/prompt.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Терминал: сырой режим, перерисовка и восстановление курсора. Решений здесь нет — переход\n * состояния по нажатой клавише живёт в `lib/picker.ts` и проверяется спекой.\n *\n * Всё, что этот модуль обязан сделать помимо перерисовки, — вернуть терминал в прежнее\n * состояние на любом выходе. Оставленный сырой режим ломает не программу, а оболочку после\n * неё: ввод перестаёт отзываться, и виноватым выглядит терминал.\n */\nimport process from 'node:process';\n\nimport { IChoice, IPickerState, pickerOf, pressChunk, renderPicker, singlePickerOf } from '../lib/picker.js';\n\nconst HIDE_CURSOR: string = `${String.fromCharCode(27)}[?25l`;\nconst SHOW_CURSOR: string = `${String.fromCharCode(27)}[?25h`;\nconst UP_AND_CLEAR: string = `${String.fromCharCode(27)}[1A${String.fromCharCode(27)}[2K`;\n\n/** Спросить можно только там, где есть кого спрашивать: в конвейере и в CI — некого. */\nexport const canAsk: () => boolean = (): boolean => Boolean(process.stdin.isTTY && process.stdout.isTTY);\n\nfunction draw(state: IPickerState, question: string, previous: number): number {\n const lines: readonly string[] = renderPicker(state, question);\n process.stdout.write(UP_AND_CLEAR.repeat(previous) + lines.join('\\n') + '\\n');\n\n return lines.length;\n}\n\n/** Спрашивание как таковое: сырой режим, перерисовка и возврат терминала на любом выходе. */\nfunction askWith(\n start: (choices: readonly IChoice[]) => IPickerState,\n choices: readonly IChoice[],\n question: string\n): Promise<readonly string[] | null> {\n if (!choices.length) {\n return Promise.resolve([]);\n }\n\n return new Promise((resolve: (value: readonly string[] | null) => void): void => {\n let state: IPickerState = start(choices);\n let drawn: number = 0;\n\n /** Обработчик приходит доводом, чтобы отпустить терминал ровно тот, что его занял. */\n const stop: (handler: (chunk: Buffer) => void) => void = (handler: (chunk: Buffer) => void): void => {\n process.stdin.off('data', handler);\n process.stdin.setRawMode(false);\n process.stdin.pause();\n process.stdout.write(SHOW_CURSOR);\n };\n\n const onData: (chunk: Buffer) => void = (chunk: Buffer): void => {\n state = pressChunk(state, chunk.toString('utf8'));\n if (state.done || state.cancelled) {\n stop(onData);\n resolve(state.cancelled ? null : [...state.chosen]);\n\n return;\n }\n drawn = draw(state, question, drawn);\n };\n\n process.stdout.write(HIDE_CURSOR);\n drawn = draw(state, question, 0);\n // Сырой режим: клавиша доходит нажатием, а не строкой по enter, и Ctrl-C приходит\n // знаком в потоке вместо сигнала — потому он и разбирается наравне с остальными.\n process.stdin.setRawMode(true);\n process.stdin.resume();\n process.stdin.on('data', onData);\n });\n}\n\n/**\n * Выбор галочками. Возвращает выбранные идентификаторы, а на брошенном выборе — `null`:\n * подставлять вместо ответа умолчание нельзя, потому что «взять всё» — тоже решение.\n */\nexport function ask(choices: readonly IChoice[], question: string): Promise<readonly string[] | null> {\n return askWith(pickerOf, choices, question);\n}\n\n/**\n * Выбор одного из. Тем же путём и с тем же брошенным выбором: вид, выбранный за проект молча,\n * разложил бы ему чужой git-flow — и заметил бы это тот, кто пошёл открывать заявку на слияние.\n */\nexport async function askOne(choices: readonly IChoice[], question: string): Promise<string | null> {\n const chosen: readonly string[] | null = await askWith(singlePickerOf, choices, question);\n\n return chosen?.length ? chosen[0] : null;\n}\n"]}
|
package/index.d.ts
CHANGED
package/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../projects/agent-kit/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../projects/agent-kit/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC"}
|
package/index.js
CHANGED
package/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../projects/agent-kit/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC","sourcesContent":["export * from './lib/assets.js';\nexport * from './lib/catalog.js';\nexport * from './lib/commands.js';\nexport * from './lib/config.js';\nexport * from './lib/picker.js';\nexport * from './lib/plan.js';\nexport * from './lib/sections.js';\nexport * from './lib/stamp.js';\nexport * from './lib/sync.js';\nexport * from './lib/vars.js';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../projects/agent-kit/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC","sourcesContent":["export * from './lib/assets.js';\nexport * from './lib/catalog.js';\nexport * from './lib/commands.js';\nexport * from './lib/config.js';\nexport * from './lib/picker.js';\nexport * from './lib/plan.js';\nexport * from './lib/sections.js';\nexport * from './lib/stamp.js';\nexport * from './lib/sync.js';\nexport * from './lib/vars.js';\nexport * from './lib/freshness.js';\n"]}
|
package/lib/assets.d.ts
CHANGED
|
@@ -1,11 +1,24 @@
|
|
|
1
|
+
import { IEntryOfCatalog } from './catalog.js';
|
|
1
2
|
import { IConfig, TKind } from './config.js';
|
|
2
3
|
export interface IAsset {
|
|
3
|
-
/** Идентификатор: `laws/
|
|
4
|
+
/** Идентификатор: `laws/application/money.md`. Он же путь надстройки и ключ в `only` и `skip`. */
|
|
4
5
|
readonly id: string;
|
|
5
6
|
readonly kind: TKind;
|
|
7
|
+
/** Имя без рода, вида и расширения: `delivery`. У скила — имя каталога, которым его зовут. */
|
|
8
|
+
readonly name: string;
|
|
6
9
|
readonly text: string;
|
|
7
10
|
/** Путь в дереве проекта, куда ресурс ложится. */
|
|
8
11
|
readonly target: string;
|
|
12
|
+
/** Запускается ли файл сам по себе: гарда без права на запуск не существует. */
|
|
13
|
+
readonly executable: boolean;
|
|
9
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Куда ложится ресурс. Скил читается агентом как `<имя>/SKILL.md`, и другого имени у него быть
|
|
17
|
+
* не может: файл, названный по ресурсу, агент не найдёт вовсе. Остальные роды ложатся файлом —
|
|
18
|
+
* по имени, а не по идентификатору: слой законов из идентификатора в путь переезжает, а вид
|
|
19
|
+
* ресурса нет. У разложенного `git-workflow` хостинга в имени не остаётся: второго вида в этом
|
|
20
|
+
* дереве нет, а агенту, который правило читает, различать их незачем.
|
|
21
|
+
*/
|
|
22
|
+
export declare function targetOf(entry: IEntryOfCatalog, layout: Readonly<Record<TKind, string>>): string;
|
|
10
23
|
export declare function collectAssets(config: IConfig, assetsDir: string): readonly IAsset[];
|
|
11
24
|
//# sourceMappingURL=assets.d.ts.map
|
package/lib/assets.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assets.d.ts","sourceRoot":"","sources":["../../../projects/agent-kit/src/lib/assets.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"assets.d.ts","sourceRoot":"","sources":["../../../projects/agent-kit/src/lib/assets.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,eAAe,EAAyB,MAAM,cAAc,CAAC;AACtE,OAAO,EAAE,OAAO,EAA2B,KAAK,EAAE,MAAM,aAAa,CAAC;AAEtE,MAAM,WAAW,MAAM;IACnB,kGAAkG;IAClG,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB,8FAA8F;IAC9F,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,kDAAkD;IAClD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,gFAAgF;IAChF,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;CAChC;AAUD;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,GAAG,MAAM,CAIhG;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAWnF"}
|
package/lib/assets.js
CHANGED
|
@@ -7,14 +7,35 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { join } from 'node:path';
|
|
9
9
|
import { isChosen, readCatalog } from './catalog.js';
|
|
10
|
+
import { SKILL_FILE, SKILL_KINDS } from './config.js';
|
|
11
|
+
/** Расширение ресурса вместе с точкой; у файла без расширения — пустая строка. */
|
|
12
|
+
const extensionOf = (id) => {
|
|
13
|
+
const dot = id.lastIndexOf('.');
|
|
14
|
+
const slash = id.lastIndexOf('/');
|
|
15
|
+
return dot > slash ? id.slice(dot) : '';
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Куда ложится ресурс. Скил читается агентом как `<имя>/SKILL.md`, и другого имени у него быть
|
|
19
|
+
* не может: файл, названный по ресурсу, агент не найдёт вовсе. Остальные роды ложатся файлом —
|
|
20
|
+
* по имени, а не по идентификатору: слой законов из идентификатора в путь переезжает, а вид
|
|
21
|
+
* ресурса нет. У разложенного `git-workflow` хостинга в имени не остаётся: второго вида в этом
|
|
22
|
+
* дереве нет, а агенту, который правило читает, различать их незачем.
|
|
23
|
+
*/
|
|
24
|
+
export function targetOf(entry, layout) {
|
|
25
|
+
return SKILL_KINDS.includes(entry.kind)
|
|
26
|
+
? join(layout[entry.kind], entry.name, SKILL_FILE)
|
|
27
|
+
: join(layout[entry.kind], `${entry.name}${extensionOf(entry.id)}`);
|
|
28
|
+
}
|
|
10
29
|
export function collectAssets(config, assetsDir) {
|
|
11
30
|
return readCatalog(assetsDir)
|
|
12
|
-
.filter((entry) => isChosen(entry, config
|
|
31
|
+
.filter((entry) => isChosen(entry, config))
|
|
13
32
|
.map((entry) => ({
|
|
14
33
|
id: entry.id,
|
|
15
34
|
kind: entry.kind,
|
|
35
|
+
name: entry.name,
|
|
16
36
|
text: entry.text,
|
|
17
|
-
target:
|
|
37
|
+
target: targetOf(entry, config.layout),
|
|
38
|
+
executable: entry.executable,
|
|
18
39
|
}));
|
|
19
40
|
}
|
|
20
41
|
//# sourceMappingURL=assets.js.map
|
package/lib/assets.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assets.js","sourceRoot":"","sources":["../../../projects/agent-kit/src/lib/assets.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAmB,QAAQ,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"assets.js","sourceRoot":"","sources":["../../../projects/agent-kit/src/lib/assets.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAmB,QAAQ,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,EAAW,UAAU,EAAE,WAAW,EAAS,MAAM,aAAa,CAAC;AAetE,kFAAkF;AAClF,MAAM,WAAW,GAA2B,CAAC,EAAU,EAAU,EAAE;IAC/D,MAAM,GAAG,GAAW,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACxC,MAAM,KAAK,GAAW,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAE1C,OAAO,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC5C,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAC,KAAsB,EAAE,MAAuC;IACpF,OAAO,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC;QACnC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC;QAClD,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,KAAK,CAAC,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAe,EAAE,SAAiB;IAC5D,OAAO,WAAW,CAAC,SAAS,CAAC;SACxB,MAAM,CAAC,CAAC,KAAsB,EAAW,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;SACpE,GAAG,CAAC,CAAC,KAAsB,EAAU,EAAE,CAAC,CAAC;QACtC,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,MAAM,EAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC;QACtC,UAAU,EAAE,KAAK,CAAC,UAAU;KAC/B,CAAC,CAAC,CAAC;AACZ,CAAC","sourcesContent":["/**\n * Что из везомого пакетом взял этот проект и куда оно ложится.\n *\n * Полный набор читает `catalog.ts`, здесь из него остаётся выбранное. Разделено потому, что\n * выбирать приходится раньше, чем раскладывать: `init` спрашивает, какие законы взять, а `list`\n * показывает и то, от чего проект отказался, — обоим нужен набор до отбора.\n */\nimport { join } from 'node:path';\n\nimport { IEntryOfCatalog, isChosen, readCatalog } from './catalog.js';\nimport { IConfig, SKILL_FILE, SKILL_KINDS, TKind } from './config.js';\n\nexport interface IAsset {\n /** Идентификатор: `laws/application/money.md`. Он же путь надстройки и ключ в `only` и `skip`. */\n readonly id: string;\n readonly kind: TKind;\n /** Имя без рода, вида и расширения: `delivery`. У скила — имя каталога, которым его зовут. */\n readonly name: string;\n readonly text: string;\n /** Путь в дереве проекта, куда ресурс ложится. */\n readonly target: string;\n /** Запускается ли файл сам по себе: гарда без права на запуск не существует. */\n readonly executable: boolean;\n}\n\n/** Расширение ресурса вместе с точкой; у файла без расширения — пустая строка. */\nconst extensionOf: (id: string) => string = (id: string): string => {\n const dot: number = id.lastIndexOf('.');\n const slash: number = id.lastIndexOf('/');\n\n return dot > slash ? id.slice(dot) : '';\n};\n\n/**\n * Куда ложится ресурс. Скил читается агентом как `<имя>/SKILL.md`, и другого имени у него быть\n * не может: файл, названный по ресурсу, агент не найдёт вовсе. Остальные роды ложатся файлом —\n * по имени, а не по идентификатору: слой законов из идентификатора в путь переезжает, а вид\n * ресурса нет. У разложенного `git-workflow` хостинга в имени не остаётся: второго вида в этом\n * дереве нет, а агенту, который правило читает, различать их незачем.\n */\nexport function targetOf(entry: IEntryOfCatalog, layout: Readonly<Record<TKind, string>>): string {\n return SKILL_KINDS.includes(entry.kind)\n ? join(layout[entry.kind], entry.name, SKILL_FILE)\n : join(layout[entry.kind], `${entry.name}${extensionOf(entry.id)}`);\n}\n\nexport function collectAssets(config: IConfig, assetsDir: string): readonly IAsset[] {\n return readCatalog(assetsDir)\n .filter((entry: IEntryOfCatalog): boolean => isChosen(entry, config))\n .map((entry: IEntryOfCatalog): IAsset => ({\n id: entry.id,\n kind: entry.kind,\n name: entry.name,\n text: entry.text,\n target: targetOf(entry, config.layout),\n executable: entry.executable,\n }));\n}\n"]}
|