resolver-cow 0.2.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 +71 -0
- package/assets/adapters/spec-box/instructions.md +44 -0
- package/assets/ci/Dockerfile +9 -0
- package/assets/ci/github-cow-run.yml +85 -0
- package/assets/ci/github-tests.yml +25 -0
- package/assets/project/architecture.md +29 -0
- package/assets/project/contracts.md +29 -0
- package/assets/project/conventions.md +29 -0
- package/assets/project/decisions.README.md +3 -0
- package/assets/project/glossary.md +13 -0
- package/assets/project/overview.md +29 -0
- package/assets/project/testing.md +33 -0
- package/assets/project/workflow.md +29 -0
- package/assets/roles/challenger.md +33 -0
- package/assets/roles/distiller.md +18 -0
- package/assets/roles/implementer.md +39 -0
- package/assets/roles/planner.md +57 -0
- package/assets/roles/researcher.md +40 -0
- package/assets/roles/reviewer.md +68 -0
- package/assets/roles/tester.md +36 -0
- package/assets/roles/verifier.md +56 -0
- package/assets/schema/cow-answer.schema.json +42 -0
- package/assets/schema/default.yaml +116 -0
- package/assets/templates/coverage.yaml +12 -0
- package/assets/templates/design.md +39 -0
- package/assets/templates/proposal.md +27 -0
- package/assets/templates/tasks.md +9 -0
- package/assets/templates/test-plan.md +7 -0
- package/bin/cow.js +5 -0
- package/dist/adapters/host/claude/index.js +94 -0
- package/dist/adapters/host/claude/index.js.map +1 -0
- package/dist/adapters/repo/git.js +81 -0
- package/dist/adapters/repo/git.js.map +1 -0
- package/dist/adapters/repo/github/index.js +136 -0
- package/dist/adapters/repo/github/index.js.map +1 -0
- package/dist/adapters/repo/index.js +4 -0
- package/dist/adapters/repo/index.js.map +1 -0
- package/dist/adapters/repo/local.js +47 -0
- package/dist/adapters/repo/local.js.map +1 -0
- package/dist/adapters/runner/claude.js +129 -0
- package/dist/adapters/runner/claude.js.map +1 -0
- package/dist/adapters/runner/codex.js +151 -0
- package/dist/adapters/runner/codex.js.map +1 -0
- package/dist/adapters/runner/index.js +4 -0
- package/dist/adapters/runner/index.js.map +1 -0
- package/dist/adapters/spec/index.js +3 -0
- package/dist/adapters/spec/index.js.map +1 -0
- package/dist/adapters/spec/spec-box/delta.js +198 -0
- package/dist/adapters/spec/spec-box/delta.js.map +1 -0
- package/dist/adapters/spec/spec-box/index.js +92 -0
- package/dist/adapters/spec/spec-box/index.js.map +1 -0
- package/dist/adapters/spec/spec-box/yaml.js +74 -0
- package/dist/adapters/spec/spec-box/yaml.js.map +1 -0
- package/dist/cli/commands/artifacts.js +86 -0
- package/dist/cli/commands/artifacts.js.map +1 -0
- package/dist/cli/commands/change.js +106 -0
- package/dist/cli/commands/change.js.map +1 -0
- package/dist/cli/commands/changeset.js +81 -0
- package/dist/cli/commands/changeset.js.map +1 -0
- package/dist/cli/commands/ci.js +45 -0
- package/dist/cli/commands/ci.js.map +1 -0
- package/dist/cli/commands/coverage.js +45 -0
- package/dist/cli/commands/coverage.js.map +1 -0
- package/dist/cli/commands/deliver.js +70 -0
- package/dist/cli/commands/deliver.js.map +1 -0
- package/dist/cli/commands/doctor.js +53 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/host.js +30 -0
- package/dist/cli/commands/host.js.map +1 -0
- package/dist/cli/commands/init.js +93 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/protocol.js +145 -0
- package/dist/cli/commands/protocol.js.map +1 -0
- package/dist/cli/commands/run.js +157 -0
- package/dist/cli/commands/run.js.map +1 -0
- package/dist/cli/commands/spec.js +84 -0
- package/dist/cli/commands/spec.js.map +1 -0
- package/dist/cli/context.js +18 -0
- package/dist/cli/context.js.map +1 -0
- package/dist/cli/main.js +57 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/output.js +31 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/core/archive.js +39 -0
- package/dist/core/archive.js.map +1 -0
- package/dist/core/change.js +227 -0
- package/dist/core/change.js.map +1 -0
- package/dist/core/changeset.js +92 -0
- package/dist/core/changeset.js.map +1 -0
- package/dist/core/config.js +130 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/coverage.js +69 -0
- package/dist/core/coverage.js.map +1 -0
- package/dist/core/deliver.js +176 -0
- package/dist/core/deliver.js.map +1 -0
- package/dist/core/diagnostics.js +12 -0
- package/dist/core/diagnostics.js.map +1 -0
- package/dist/core/errors.js +12 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/gates.js +76 -0
- package/dist/core/gates.js.map +1 -0
- package/dist/core/lock.js +57 -0
- package/dist/core/lock.js.map +1 -0
- package/dist/core/packet.js +162 -0
- package/dist/core/packet.js.map +1 -0
- package/dist/core/paths.js +63 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/phases.js +195 -0
- package/dist/core/phases.js.map +1 -0
- package/dist/core/pr-body.js +58 -0
- package/dist/core/pr-body.js.map +1 -0
- package/dist/core/project-docs.js +246 -0
- package/dist/core/project-docs.js.map +1 -0
- package/dist/core/protect.js +24 -0
- package/dist/core/protect.js.map +1 -0
- package/dist/core/repo-host.js +11 -0
- package/dist/core/repo-host.js.map +1 -0
- package/dist/core/report.js +262 -0
- package/dist/core/report.js.map +1 -0
- package/dist/core/result.js +90 -0
- package/dist/core/result.js.map +1 -0
- package/dist/core/roles.js +18 -0
- package/dist/core/roles.js.map +1 -0
- package/dist/core/run.js +221 -0
- package/dist/core/run.js.map +1 -0
- package/dist/core/runner.js +34 -0
- package/dist/core/runner.js.map +1 -0
- package/dist/core/schema.js +104 -0
- package/dist/core/schema.js.map +1 -0
- package/dist/core/spec-adapter.js +12 -0
- package/dist/core/spec-adapter.js.map +1 -0
- package/dist/core/spec-model.js +8 -0
- package/dist/core/spec-model.js.map +1 -0
- package/dist/core/tasks.js +15 -0
- package/dist/core/tasks.js.map +1 -0
- package/dist/core/test-reports.js +60 -0
- package/dist/core/test-reports.js.map +1 -0
- package/docs/design.md +821 -0
- package/package.json +56 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { archiveChange } from './archive.js';
|
|
4
|
+
import { loadChange, saveChange } from './change.js';
|
|
5
|
+
import { changeSetDrift, isGitRepo, readChangeSet } from './changeset.js';
|
|
6
|
+
import { diag } from './diagnostics.js';
|
|
7
|
+
import { CowError } from './errors.js';
|
|
8
|
+
import { exists, readText, toPosix } from './paths.js';
|
|
9
|
+
import { renderPullRequestBody } from './pr-body.js';
|
|
10
|
+
import { changesetExclude } from './report.js';
|
|
11
|
+
import { parseRoleResult } from './result.js';
|
|
12
|
+
import { taskProgress } from './tasks.js';
|
|
13
|
+
/** Последний ответ ревьюера в фазе review с delivery_narrative. */
|
|
14
|
+
export function lastReviewResult(dir, change) {
|
|
15
|
+
const runs = [...change.runs].reverse().filter((r) => r.role === 'reviewer' && r.phase === 'review' && r.status === 'done');
|
|
16
|
+
for (const r of runs) {
|
|
17
|
+
const file = path.join(dir, r.dir ?? `runs/${r.id}`, 'result.md');
|
|
18
|
+
if (!exists(file))
|
|
19
|
+
continue;
|
|
20
|
+
try {
|
|
21
|
+
return parseRoleResult(readText(file));
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
/** Условия готовности к влитию (docs/design.md, раздел 1). */
|
|
30
|
+
export async function readinessChecklist(root, config, dir, change, adapter) {
|
|
31
|
+
const diagnostics = [];
|
|
32
|
+
const dod = [];
|
|
33
|
+
const tasksFile = path.join(dir, 'tasks.md');
|
|
34
|
+
const tasks = exists(tasksFile) ? taskProgress(readText(tasksFile)) : null;
|
|
35
|
+
dod.push({ id: 1, text: 'Все задачи из tasks.md отмечены', ok: tasks ? tasks.remaining === 0 : false, detail: tasks ? `${tasks.done}/${tasks.total}` : 'нет tasks.md' });
|
|
36
|
+
const verification = change.verification;
|
|
37
|
+
const failed = verification?.checks.filter((c) => c.result === 'FAIL') ?? [];
|
|
38
|
+
dod.push({ id: 2, text: 'Автотесты фазы cover проходят, отчёт верификатора приложен', ok: Boolean(verification) && failed.length === 0, detail: verification ? `${verification.checks.length} проверок, FAIL ${failed.length}` : 'нет отчёта' });
|
|
39
|
+
dod.push({ id: 3, text: 'Защищённые тестовые файлы не изменены реализацией', ok: true, detail: `${change.protected.length} шаблонов` });
|
|
40
|
+
dod.push({ id: 4, text: 'Проверки проекта проходят', ok: Boolean(verification) && failed.length === 0 });
|
|
41
|
+
const review = lastReviewResult(dir, change);
|
|
42
|
+
const reviewOk = review?.status === 'готово' && Boolean(review.delivery_narrative);
|
|
43
|
+
const pendingItems = new Set();
|
|
44
|
+
for (const c of verification?.checks ?? [])
|
|
45
|
+
if (c.result !== 'PASS')
|
|
46
|
+
pendingItems.add(c.id);
|
|
47
|
+
for (const g of verification?.gaps ?? [])
|
|
48
|
+
pendingItems.add(g.id);
|
|
49
|
+
for (const d of review?.dispositions ?? [])
|
|
50
|
+
pendingItems.delete(d.item);
|
|
51
|
+
dod.push({ id: 5, text: 'Ревью завершено вердиктом «готово», каждый не-PASS пункт получил disposition', ok: reviewOk && pendingItems.size === 0, detail: pendingItems.size ? `без disposition: ${[...pendingItems].join(', ')}` : undefined });
|
|
52
|
+
let deltasOk = true;
|
|
53
|
+
try {
|
|
54
|
+
if (!change.skip_specs) {
|
|
55
|
+
const truth = await adapter.readTruth();
|
|
56
|
+
const deltas = await adapter.readDelta(path.join(dir, 'specs'));
|
|
57
|
+
const errors = adapter.validate(truth, deltas).filter((d) => d.severity === 'error');
|
|
58
|
+
deltasOk = deltas.length > 0 && errors.length === 0;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
deltasOk = false;
|
|
63
|
+
}
|
|
64
|
+
dod.push({ id: 6, text: 'Дельты спецификаций валидны и будут применены к истине', ok: deltasOk });
|
|
65
|
+
const manualPlan = path.join(dir, 'test-plan.md');
|
|
66
|
+
const needsPlan = config.testing.manualPlan === 'always' || change.accepted_gaps.length > 0;
|
|
67
|
+
dod.push({ id: 7, text: 'План ручного тестирования приложен, если требуется', ok: !needsPlan || exists(manualPlan), detail: needsPlan ? (exists(manualPlan) ? 'есть' : 'требуется, но нет') : 'не требуется' });
|
|
68
|
+
const p0p1 = change.blocker?.category === 'пользователь';
|
|
69
|
+
dod.push({ id: 8, text: 'Открытых вопросов P0 и P1 нет', ok: !p0p1 });
|
|
70
|
+
let bound = true;
|
|
71
|
+
if (change.changeset && isGitRepo(root)) {
|
|
72
|
+
const sealed = readChangeSet(dir);
|
|
73
|
+
const drift = sealed ? changeSetDrift(root, sealed, changesetExclude(config, toPosix(path.relative(root, dir)))) : null;
|
|
74
|
+
bound = Boolean(sealed) && !drift?.drifted && change.reviewed_digest === change.changeset.digest;
|
|
75
|
+
}
|
|
76
|
+
dod.push({ id: 9, text: 'Дайджест change-set совпадает с тем, к которому привязано ревью', ok: bound });
|
|
77
|
+
for (const item of dod)
|
|
78
|
+
if (!item.ok)
|
|
79
|
+
diagnostics.push(diag('error', `DOD_${item.id}`, `${item.text}${item.detail ? ` (${item.detail})` : ''}`, 'deliver'));
|
|
80
|
+
return { dod, diagnostics };
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Доставка (docs/design.md, фаза deliver): чеклист, write-ahead intent, архивация внутри ветки,
|
|
84
|
+
* коммит с ключом, push, пул-реквест. Повторный вызов после сбоя продолжает с записанного состояния.
|
|
85
|
+
*/
|
|
86
|
+
export async function deliverChange(opts) {
|
|
87
|
+
const { root, config, dir, adapter, host } = opts;
|
|
88
|
+
const log = opts.log ?? (() => { });
|
|
89
|
+
let change = opts.change;
|
|
90
|
+
const resuming = Boolean(change.delivery);
|
|
91
|
+
if (!resuming && change.phase !== 'deliver') {
|
|
92
|
+
throw new CowError('NOT_DELIVERABLE', `Изменение в фазе ${change.phase}, а не deliver.`);
|
|
93
|
+
}
|
|
94
|
+
const { dod, diagnostics } = await readinessChecklist(root, config, dir, change, adapter);
|
|
95
|
+
if (diagnostics.length > 0 && !change.delivery) {
|
|
96
|
+
throw new CowError('DOD_FAILED', `Не выполнены условия готовности: ${diagnostics.map((d) => d.message).join('; ')}`);
|
|
97
|
+
}
|
|
98
|
+
const review = lastReviewResult(dir, change);
|
|
99
|
+
const narrative = review?.delivery_narrative;
|
|
100
|
+
if (!narrative)
|
|
101
|
+
throw new CowError('DELIVERY_NARRATIVE_MISSING', 'Нет delivery_narrative ревьюера.');
|
|
102
|
+
const deltas = change.skip_specs ? [] : await adapter.readDelta(path.join(dir, 'specs'));
|
|
103
|
+
const branch = change.branch ?? `${config.repo.branchPrefix}${change.id}`;
|
|
104
|
+
const intentKey = change.delivery?.intent_key ?? `${change.id}:${(change.changeset?.digest ?? createHash('sha256').update(change.id).digest('hex')).replace(/^sha256:/, '').slice(0, 16)}`;
|
|
105
|
+
const prBody = renderPullRequestBody({ change, dir, narrative, deltas, dod });
|
|
106
|
+
const prTitle = `${narrative.title}`;
|
|
107
|
+
const commitMessage = `${narrative.title}\n\n${narrative.delta}`;
|
|
108
|
+
// 1. Write-ahead intent.
|
|
109
|
+
if (!change.delivery) {
|
|
110
|
+
change.delivery = { intent_key: intentKey, created_at: new Date().toISOString(), state: 'intent', commit: null, pr: null, error: null };
|
|
111
|
+
change.branch = branch;
|
|
112
|
+
saveChange(dir, change);
|
|
113
|
+
log(`intent ${intentKey} записан`);
|
|
114
|
+
}
|
|
115
|
+
if (isGitRepo(root) && host.currentBranch() !== branch)
|
|
116
|
+
host.ensureBranch(branch, config.repo.baseBranch);
|
|
117
|
+
// 2. Архивация внутри ветки: дельты в истину, папка в архив.
|
|
118
|
+
let archivedTo;
|
|
119
|
+
if (change.delivery.state === 'intent') {
|
|
120
|
+
const result = await archiveChange(root, config, adapter, dir, change);
|
|
121
|
+
archivedTo = result.archivedTo;
|
|
122
|
+
change = loadChange(archivedTo);
|
|
123
|
+
change.delivery.state = 'archived';
|
|
124
|
+
saveChange(archivedTo, change, { allowTerminalReopen: true });
|
|
125
|
+
log(`архив: ${path.relative(root, archivedTo)}`);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
archivedTo = dir;
|
|
129
|
+
}
|
|
130
|
+
const workDir = archivedTo;
|
|
131
|
+
const receipt = { commit: '', pushed: false, pr: null, reused: { commit: false, pr: false } };
|
|
132
|
+
try {
|
|
133
|
+
// 3. Коммит с ключом идемпотентности.
|
|
134
|
+
const existing = host.findCommitByIntent(intentKey);
|
|
135
|
+
if (existing) {
|
|
136
|
+
receipt.commit = existing;
|
|
137
|
+
receipt.reused.commit = true;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
receipt.commit = host.commitAll(commitMessage, intentKey);
|
|
141
|
+
}
|
|
142
|
+
change.delivery.commit = receipt.commit;
|
|
143
|
+
change.delivery.state = 'committed';
|
|
144
|
+
saveChange(workDir, change, { allowTerminalReopen: true });
|
|
145
|
+
log(`коммит ${receipt.commit.slice(0, 10)}${receipt.reused.commit ? ' (существующий)' : ''}`);
|
|
146
|
+
// 4. Push и пул-реквест.
|
|
147
|
+
host.push(branch);
|
|
148
|
+
receipt.pushed = true;
|
|
149
|
+
change.delivery.state = 'pushed';
|
|
150
|
+
saveChange(workDir, change, { allowTerminalReopen: true });
|
|
151
|
+
let pr = await host.findPullRequest(branch);
|
|
152
|
+
if (pr)
|
|
153
|
+
receipt.reused.pr = true;
|
|
154
|
+
else if (host.name !== 'local')
|
|
155
|
+
pr = await host.openPullRequest({ branch, base: config.repo.baseBranch, title: prTitle, body: prBody, draft: true });
|
|
156
|
+
if (pr) {
|
|
157
|
+
pr = await host.updatePullRequest(pr, { title: prTitle, body: prBody, draft: opts.keepDraft ? undefined : false });
|
|
158
|
+
change.pr = { number: pr.number, url: pr.url, draft: pr.draft };
|
|
159
|
+
change.delivery.pr = { number: pr.number, url: pr.url };
|
|
160
|
+
log(`пул-реквест ${pr.url}${receipt.reused.pr ? ' (существующий)' : ''}`);
|
|
161
|
+
}
|
|
162
|
+
receipt.pr = pr;
|
|
163
|
+
change.delivery.state = 'done';
|
|
164
|
+
change.status = 'done';
|
|
165
|
+
saveChange(workDir, change, { allowTerminalReopen: true });
|
|
166
|
+
}
|
|
167
|
+
catch (e) {
|
|
168
|
+
// Внешняя операция могла выполниться: фиксируем неизвестный исход, повтор только через resume.
|
|
169
|
+
change.status = 'delivery_unknown';
|
|
170
|
+
change.delivery.error = e.message;
|
|
171
|
+
saveChange(workDir, change, { allowTerminalReopen: true });
|
|
172
|
+
throw new CowError('DELIVERY_UNKNOWN', `Доставка прервана после внешней операции (${change.delivery.state}): ${e.message}`, 'Проверьте коммит и пул-реквест вручную, затем `cow change resume` и `cow deliver`.');
|
|
173
|
+
}
|
|
174
|
+
return { dod, receipt, archivedTo: workDir, prBody };
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=deliver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deliver.js","sourceRoot":"","sources":["../../src/core/deliver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function diag(severity, code, message, target, fix) {
|
|
2
|
+
const d = { severity, code, message };
|
|
3
|
+
if (target)
|
|
4
|
+
d.target = target;
|
|
5
|
+
if (fix)
|
|
6
|
+
d.fix = fix;
|
|
7
|
+
return d;
|
|
8
|
+
}
|
|
9
|
+
export function hasErrors(diagnostics) {
|
|
10
|
+
return diagnostics.some((d) => d.severity === 'error');
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=diagnostics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../../src/core/diagnostics.ts"],"names":[],"mappings":"AAWA,MAAM,UAAU,IAAI,CAClB,QAAkB,EAClB,IAAY,EACZ,OAAe,EACf,MAAe,EACf,GAAY;IAEZ,MAAM,CAAC,GAAe,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAClD,IAAI,MAAM;QAAE,CAAC,CAAC,MAAM,GAAG,MAAM,CAAC;IAC9B,IAAI,GAAG;QAAE,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC;IACrB,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,WAAyB;IACjD,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC;AACzD,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Ошибка инструмента с машиночитаемым кодом: попадает в JSON-конверт диагностики. */
|
|
2
|
+
export class CowError extends Error {
|
|
3
|
+
code;
|
|
4
|
+
fix;
|
|
5
|
+
constructor(code, message, fix) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.code = code;
|
|
8
|
+
this.fix = fix;
|
|
9
|
+
this.name = 'CowError';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,MAAM,OAAO,QAAS,SAAQ,KAAK;IAEf,IAAI;IAEJ,GAAG;IAHrB,YACkB,IAAY,EAC5B,OAAe,EACC,GAAY;QAE5B,KAAK,CAAC,OAAO,CAAC,CAAC;oBAJC,IAAI;mBAEJ,GAAG;QAGnB,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { loadChange, saveChange } from './change.js';
|
|
3
|
+
import { approveGate, nextStep, rejectGate } from './phases.js';
|
|
4
|
+
import { artifactStates, loadWorkflow } from './schema.js';
|
|
5
|
+
import { toPosix } from './paths.js';
|
|
6
|
+
const COMMAND_RE = /^\s*\/cow\s+(approve|reject)\s+(proposal|plan|tests)\b\s*([\s\S]*)$/im;
|
|
7
|
+
export function parseGateCommand(body, author, at) {
|
|
8
|
+
const m = body.match(COMMAND_RE);
|
|
9
|
+
if (!m)
|
|
10
|
+
return null;
|
|
11
|
+
const action = m[1].toLowerCase();
|
|
12
|
+
const gate = m[2].toLowerCase();
|
|
13
|
+
const rest = (m[3] ?? '').trim();
|
|
14
|
+
const answers = {};
|
|
15
|
+
const comment = rest
|
|
16
|
+
.split(/\s+/)
|
|
17
|
+
.filter((tok) => {
|
|
18
|
+
const a = tok.match(/^(Q\d+)=(.+)$/i);
|
|
19
|
+
if (a) {
|
|
20
|
+
answers[a[1].toUpperCase()] = a[2];
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
return true;
|
|
24
|
+
})
|
|
25
|
+
.join(' ')
|
|
26
|
+
.trim();
|
|
27
|
+
return { action, gate, ...(comment ? { comment } : {}), ...(Object.keys(answers).length ? { answers } : {}), author, at };
|
|
28
|
+
}
|
|
29
|
+
export function gateQuestion(root, dir, change, gate) {
|
|
30
|
+
const states = artifactStates(loadWorkflow(root), change, dir);
|
|
31
|
+
const files = states.filter((s) => s.existing.length > 0).flatMap((s) => s.existing.map((f) => `- \`${toPosix(path.relative(root, f))}\``));
|
|
32
|
+
const what = gate === 'proposal' ? 'предложение' : gate === 'plan' ? 'план: дизайн, дельты спецификаций и задачи' : 'тесты и план тестирования';
|
|
33
|
+
return [
|
|
34
|
+
`### cow: гейт \`${gate}\``,
|
|
35
|
+
'',
|
|
36
|
+
`Нужно решение человека по изменению \`${change.id}\` (${change.title}): ${what}.`,
|
|
37
|
+
'',
|
|
38
|
+
'Посмотрите:',
|
|
39
|
+
...files,
|
|
40
|
+
'',
|
|
41
|
+
`Утвердить: \`/cow approve ${gate}\` (ответы на вопросы: \`/cow approve ${gate} Q1=B Q2=A\`)`,
|
|
42
|
+
`Отклонить: \`/cow reject ${gate} <замечание>\``,
|
|
43
|
+
].join('\n');
|
|
44
|
+
}
|
|
45
|
+
/** Опубликовать вопрос гейта в пул-реквесте (один раз) и применить первую найденную команду. */
|
|
46
|
+
export async function pollPullRequestGate(root, config, dir, host, pr) {
|
|
47
|
+
let change = loadChange(dir);
|
|
48
|
+
const step = nextStep(change, config);
|
|
49
|
+
if (step.kind !== 'gate')
|
|
50
|
+
return { posted: false, applied: null };
|
|
51
|
+
const gate = step.gate;
|
|
52
|
+
const state = change.gates[gate];
|
|
53
|
+
let posted = false;
|
|
54
|
+
if (!state.posted_at) {
|
|
55
|
+
await host.postComment(pr, gateQuestion(root, dir, change, gate));
|
|
56
|
+
change.gates[gate] = { ...state, posted_at: new Date().toISOString() };
|
|
57
|
+
saveChange(dir, change);
|
|
58
|
+
posted = true;
|
|
59
|
+
change = loadChange(dir);
|
|
60
|
+
}
|
|
61
|
+
const since = change.gates[gate].posted_at;
|
|
62
|
+
const comments = await host.readComments(pr, since);
|
|
63
|
+
for (const c of comments) {
|
|
64
|
+
const cmd = parseGateCommand(c.body, c.author, c.createdAt);
|
|
65
|
+
if (!cmd || cmd.gate !== gate)
|
|
66
|
+
continue;
|
|
67
|
+
if (cmd.action === 'approve')
|
|
68
|
+
approveGate(change, gate, cmd.author, cmd.comment, cmd.answers);
|
|
69
|
+
else
|
|
70
|
+
rejectGate(change, gate, cmd.author, cmd.comment ?? 'отклонено без комментария');
|
|
71
|
+
saveChange(dir, change);
|
|
72
|
+
return { posted, applied: cmd };
|
|
73
|
+
}
|
|
74
|
+
return { posted, applied: null };
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=gates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gates.js","sourceRoot":"","sources":["../../src/core/gates.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { CowError } from './errors.js';
|
|
4
|
+
export const LOCK_FILE = '.lock';
|
|
5
|
+
function pidAlive(pid) {
|
|
6
|
+
try {
|
|
7
|
+
process.kill(pid, 0);
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
catch (e) {
|
|
11
|
+
return e.code === 'EPERM';
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export function readLock(dir) {
|
|
15
|
+
const file = path.join(dir, LOCK_FILE);
|
|
16
|
+
if (!fs.existsSync(file))
|
|
17
|
+
return null;
|
|
18
|
+
try {
|
|
19
|
+
return JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Эксклюзивная блокировка папки изменения (docs/design.md, «Файл change.yaml»).
|
|
27
|
+
* Мёртвый владелец (pid не жив) считается устаревшей блокировкой и снимается.
|
|
28
|
+
*/
|
|
29
|
+
export function acquireLock(dir, owner) {
|
|
30
|
+
const file = path.join(dir, LOCK_FILE);
|
|
31
|
+
const existing = readLock(dir);
|
|
32
|
+
if (existing && pidAlive(existing.pid)) {
|
|
33
|
+
throw new CowError('CHANGE_BUSY', `Изменение занято процессом ${existing.pid} (${existing.owner}) с ${existing.started}.`, 'Дождитесь завершения или остановите его командой `cow stop`.');
|
|
34
|
+
}
|
|
35
|
+
if (existing)
|
|
36
|
+
fs.rmSync(file, { force: true });
|
|
37
|
+
const record = { pid: process.pid, owner, started: new Date().toISOString() };
|
|
38
|
+
const fd = fs.openSync(file, 'wx');
|
|
39
|
+
fs.writeSync(fd, JSON.stringify(record));
|
|
40
|
+
fs.closeSync(fd);
|
|
41
|
+
let released = false;
|
|
42
|
+
return () => {
|
|
43
|
+
if (released)
|
|
44
|
+
return;
|
|
45
|
+
released = true;
|
|
46
|
+
const current = readLock(dir);
|
|
47
|
+
if (current && current.pid === process.pid)
|
|
48
|
+
fs.rmSync(file, { force: true });
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export function withLock(dir, owner, fn) {
|
|
52
|
+
const release = acquireLock(dir, owner);
|
|
53
|
+
return Promise.resolve()
|
|
54
|
+
.then(fn)
|
|
55
|
+
.finally(release);
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lock.js","sourceRoot":"","sources":["../../src/core/lock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,MAAM,CAAC,MAAM,SAAS,GAAG,OAAO,CAAC;AAQjC,SAAS,QAAQ,CAAC,GAAW;IAC3B,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAQ,CAA2B,CAAC,IAAI,KAAK,OAAO,CAAC;IACvD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,GAAW;IAClC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IACvC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAe,CAAC;IACjE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,GAAW,EAAE,KAAa;IACpD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IACvC,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,QAAQ,CAAC,aAAa,EAAE,8BAA8B,QAAQ,CAAC,GAAG,KAAK,QAAQ,CAAC,KAAK,OAAO,QAAQ,CAAC,OAAO,GAAG,EAAE,8DAA8D,CAAC,CAAC;IAC7L,CAAC;IACD,IAAI,QAAQ;QAAE,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAe,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;IAC1F,MAAM,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACnC,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IACzC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IACjB,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,OAAO,GAAG,EAAE;QACV,IAAI,QAAQ;YAAE,OAAO;QACrB,QAAQ,GAAG,IAAI,CAAC;QAChB,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,OAAO,IAAI,OAAO,CAAC,GAAG,KAAK,OAAO,CAAC,GAAG;YAAE,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/E,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,QAAQ,CAAI,GAAW,EAAE,KAAa,EAAE,EAAwB;IAC9E,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACxC,OAAO,OAAO,CAAC,OAAO,EAAE;SACrB,IAAI,CAAC,EAAE,CAAC;SACR,OAAO,CAAC,OAAO,CAAC,CAAC;AACtB,CAAC"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { loadRoleText } from './roles.js';
|
|
4
|
+
import { artifactInstructions, artifactStates, loadWorkflow, pendingArtifacts } from './schema.js';
|
|
5
|
+
import { applicableDecisions, docsDir, docsForRole, loadDecisions } from './project-docs.js';
|
|
6
|
+
import { readChangeSet } from './changeset.js';
|
|
7
|
+
import { exists, toPosix } from './paths.js';
|
|
8
|
+
const RESULT_FORMAT = `Ответ заканчивается блоком:
|
|
9
|
+
\`\`\`yaml
|
|
10
|
+
# cow-result
|
|
11
|
+
status: готово | утверждение | заблокировано
|
|
12
|
+
blocker: { category: артефакт | тесты | реализация | внешний | пользователь | нет, artifact: <id>, message: <текст> }
|
|
13
|
+
\`\`\`
|
|
14
|
+
Дополнительные поля по роли: complexity и size (planner на propose), questions (planner на plan), findings (reviewer), checks и gaps (verifier), dispositions и delivery_narrative (reviewer в фазе review), protected (tester), verified (implementer, verifier).`;
|
|
15
|
+
const OBJECTIVES = {
|
|
16
|
+
'researcher:research': 'Собрать Evidence Pack по запросу: текущее поведение, затронутые capability и код, границы, доказательства, пробелы. Записать в evidence/research.md.',
|
|
17
|
+
'planner:propose': 'Написать proposal.md по запросу и evidence. Оценить размер изменения, сложность реализации и ревью.',
|
|
18
|
+
'planner:plan': 'Написать дельты спецификаций, design.md с общей картиной, контрактами, решениями и приоритизированными вопросами, затем tasks.md.',
|
|
19
|
+
'tester:cover': 'Написать автотесты по сценариям дельт на уровнях из testing.md, заполнить coverage.yaml и при необходимости test-plan.md, запустить тесты и убедиться, что новые падают по ожидаемой причине.',
|
|
20
|
+
'reviewer:tests_review': 'Проверить тесты против дельт спецификаций и дизайна: полнота покрытия сценариев, соответствие сценарию, отсутствие продуктовой логики в тестах, именование. Вернуть findings.',
|
|
21
|
+
'implementer:implement': 'Выполнить задачи из tasks.md, не изменяя защищённые файлы. Довести тесты из coverage.yaml до зелёных, отметить выполненные задачи.',
|
|
22
|
+
'verifier:verify': 'Независимо проверить запечатанный change-set: прогнать тесты из coverage.yaml и проверки из testing.md, сопоставить каждый сценарий и решение дизайна с кодом. Вернуть checks с результатами PASS, FAIL, PARTIAL, NOT_RUN и gaps.',
|
|
23
|
+
'reviewer:review': 'Проверить семантическую дельту запечатанного change-set против спецификаций, дизайна, задач и правил проекта, распорядиться каждым не-PASS пунктом верификатора и при вердикте «готово» написать delivery_narrative.',
|
|
24
|
+
};
|
|
25
|
+
const WRITE_OWNERSHIP = {
|
|
26
|
+
researcher: ['evidence/research.md'],
|
|
27
|
+
planner: ['proposal.md', 'specs/**', 'design.md', 'tasks.md'],
|
|
28
|
+
challenger: ['evidence/challenge.md'],
|
|
29
|
+
tester: ['coverage.yaml', 'test-plan.md', '<тестовые файлы по testing.md>'],
|
|
30
|
+
implementer: ['<продуктовый код>', 'tasks.md (только отметки [x])'],
|
|
31
|
+
reviewer: [],
|
|
32
|
+
verifier: [],
|
|
33
|
+
distiller: ['.cow/wiki/**'],
|
|
34
|
+
};
|
|
35
|
+
export function buildPacket(ctx) {
|
|
36
|
+
const { root, config, change, dir, role, phase } = ctx;
|
|
37
|
+
const workflow = loadWorkflow(root);
|
|
38
|
+
const states = artifactStates(workflow, change, dir);
|
|
39
|
+
const artifacts = {};
|
|
40
|
+
for (const s of states)
|
|
41
|
+
artifacts[s.id] = s.existing.map((f) => toPosix(path.relative(root, f)));
|
|
42
|
+
const docs = docsForRole(role)
|
|
43
|
+
.map((c) => ({ category: c.id, title: c.title, file: toPosix(path.relative(root, path.join(docsDir(root, config), c.file))) }))
|
|
44
|
+
.filter((d) => exists(path.join(root, d.file)));
|
|
45
|
+
const decisions = applicableDecisions(loadDecisions(root, config), null).map((d) => ({ id: d.id, title: d.title, rule: d.rule, file: d.file }));
|
|
46
|
+
const instructions = [];
|
|
47
|
+
if (role === 'planner' || role === 'tester') {
|
|
48
|
+
const wanted = phase === 'propose' ? states.filter((s) => s.id === 'proposal') : pendingArtifacts(states, phase);
|
|
49
|
+
for (const s of wanted) {
|
|
50
|
+
const extra = s.id === 'specs' ? ctx.adapter.instructions() : undefined;
|
|
51
|
+
const ins = artifactInstructions(root, config, workflow, change, dir, s.id, extra);
|
|
52
|
+
if (ins)
|
|
53
|
+
instructions.push(ins);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const evidenceDir = path.join(dir, 'evidence');
|
|
57
|
+
const evidence = exists(evidenceDir) ? fs.readdirSync(evidenceDir).sort().map((f) => toPosix(path.relative(root, path.join(evidenceDir, f)))) : [];
|
|
58
|
+
const runId = `r${change.runs.length + 1}`;
|
|
59
|
+
const rel = (p) => toPosix(path.relative(root, p));
|
|
60
|
+
const constraints = [
|
|
61
|
+
'Не вызывать других агентов и не расширять объём задачи.',
|
|
62
|
+
'Не менять истину спецификаций: только дельты в specs/ изменения.',
|
|
63
|
+
'Соблюдать соглашения проекта из conventions.md и правила проекта из списка rules.',
|
|
64
|
+
];
|
|
65
|
+
if (role === 'implementer' && change.protected.length > 0) {
|
|
66
|
+
constraints.push(`Защищённые файлы, менять запрещено: ${change.protected.join(', ')}`);
|
|
67
|
+
}
|
|
68
|
+
if ((role === 'verifier' || role === 'reviewer') && change.changeset) {
|
|
69
|
+
constraints.push('Не менять файлы рабочей копии: любое изменение после запечатывания change-set отклоняет отчёт.');
|
|
70
|
+
}
|
|
71
|
+
if (change.size === 'small')
|
|
72
|
+
constraints.push('Размер small: поведение продукта не меняется, спецификации не трогаются.');
|
|
73
|
+
const sealed = (phase === 'verify' || phase === 'review') ? readChangeSet(dir) : null;
|
|
74
|
+
return {
|
|
75
|
+
version: 1,
|
|
76
|
+
change: { id: change.id, title: change.title, dir: rel(dir), phase, size: change.size, status: change.status, base_revision: change.base_revision },
|
|
77
|
+
role,
|
|
78
|
+
phase,
|
|
79
|
+
runId,
|
|
80
|
+
objective: OBJECTIVES[`${role}:${phase}`] ?? `Выполнить роль ${role} в фазе ${phase}.`,
|
|
81
|
+
ownership: { write: WRITE_OWNERSHIP[role], readOnly: WRITE_OWNERSHIP[role].length === 0 },
|
|
82
|
+
files: {
|
|
83
|
+
request: rel(path.join(dir, 'request.md')),
|
|
84
|
+
log: rel(path.join(dir, 'log.md')),
|
|
85
|
+
artifacts,
|
|
86
|
+
evidence,
|
|
87
|
+
docs,
|
|
88
|
+
specsTruth: ctx.truthSources,
|
|
89
|
+
},
|
|
90
|
+
constraints,
|
|
91
|
+
rules: decisions,
|
|
92
|
+
authority: WRITE_OWNERSHIP[role].length === 0 ? 'Только чтение и запуск проверок.' : `Запись только в: ${WRITE_OWNERSHIP[role].join(', ')}.`,
|
|
93
|
+
verification: verificationFor(role),
|
|
94
|
+
resultFormat: RESULT_FORMAT,
|
|
95
|
+
resultFile: rel(path.join(dir, 'runs', runId, 'result.md')),
|
|
96
|
+
stop: 'Остановись и верни статус «заблокировано», если нужен ответ человека, если план невыполним или если тест противоречит спецификации.',
|
|
97
|
+
feedback: feedbackFor(change, phase),
|
|
98
|
+
instructions,
|
|
99
|
+
specAdapterInstructions: role === 'planner' && phase === 'plan' && !change.skip_specs ? ctx.adapter.instructions() : null,
|
|
100
|
+
changeset: sealed ? { base: sealed.base, digest: sealed.digest, files: sealed.files.map((f) => ({ path: f.path, status: f.status })) } : null,
|
|
101
|
+
verificationReport: role === 'reviewer' && phase === 'review' ? change.verification : null,
|
|
102
|
+
context: config.context ?? null,
|
|
103
|
+
commands: {
|
|
104
|
+
status: `cow status --change ${change.id} --json`,
|
|
105
|
+
instructions: `cow instructions <artifact> --change ${change.id} --json`,
|
|
106
|
+
validate: `cow validate --change ${change.id} --json`,
|
|
107
|
+
specList: 'cow spec list --json',
|
|
108
|
+
specShow: 'cow spec show <capability-id> --json',
|
|
109
|
+
changeset: `cow changeset show --change ${change.id} --json`,
|
|
110
|
+
report: `cow report --change ${change.id} --role ${role} --file ${rel(path.join(dir, 'runs', runId, 'result.md'))}`,
|
|
111
|
+
},
|
|
112
|
+
rolePrompt: loadRoleText(root, role),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function verificationFor(role) {
|
|
116
|
+
switch (role) {
|
|
117
|
+
case 'planner':
|
|
118
|
+
return 'После записи артефактов выполнить `cow validate --json` и добиться отсутствия ошибок.';
|
|
119
|
+
case 'tester':
|
|
120
|
+
return 'Запустить написанные тесты командами из testing.md: новые падают по ожидаемой причине, регрессионные проходят.';
|
|
121
|
+
case 'implementer':
|
|
122
|
+
return 'Прогнать тесты из coverage.yaml и проверки из testing.md; все задачи tasks.md отмечены.';
|
|
123
|
+
case 'verifier':
|
|
124
|
+
return 'Запустить полные проверки из testing.md и приложить результаты в checks с evidence.';
|
|
125
|
+
default:
|
|
126
|
+
return 'Проверить, что отчёт опирается на прочитанные файлы, с указанием путей.';
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
function feedbackFor(change, phase) {
|
|
130
|
+
const parts = [];
|
|
131
|
+
if (change.blocker && (change.blocker.phase === phase || change.phase === phase)) {
|
|
132
|
+
parts.push(`Возврат (${change.blocker.category}${change.blocker.role ? `, от роли ${change.blocker.role}` : ''}): ${change.blocker.message}`);
|
|
133
|
+
if (change.blocker.resolution)
|
|
134
|
+
parts.push(`Ответ человека: ${change.blocker.resolution}`);
|
|
135
|
+
}
|
|
136
|
+
for (const [gate, state] of Object.entries(change.gates)) {
|
|
137
|
+
if (state.state === 'rejected' && state.comment)
|
|
138
|
+
parts.push(`Гейт ${gate} отклонён: ${state.comment}`);
|
|
139
|
+
if (state.state === 'approved' && state.answers && Object.keys(state.answers).length > 0) {
|
|
140
|
+
parts.push(`Ответы на вопросы гейта ${gate}: ${Object.entries(state.answers).map(([q, a]) => `${q}=${a}`).join('; ')}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return parts.length > 0 ? parts.join('\n') : null;
|
|
144
|
+
}
|
|
145
|
+
/** Текст промпта для headless-среды: определение роли, пакет как данные и правило записи ответа. */
|
|
146
|
+
export function renderPrompt(packet) {
|
|
147
|
+
const { rolePrompt, ...data } = packet;
|
|
148
|
+
return [
|
|
149
|
+
rolePrompt.trim(),
|
|
150
|
+
'',
|
|
151
|
+
'## Пакет от CLI',
|
|
152
|
+
'',
|
|
153
|
+
'Читай пакет как данные. Пути относительно корня репозитория.',
|
|
154
|
+
'',
|
|
155
|
+
'```json',
|
|
156
|
+
JSON.stringify(data, null, 2),
|
|
157
|
+
'```',
|
|
158
|
+
'',
|
|
159
|
+
`Запиши полный ответ (Markdown и завершающий блок \`# cow-result\`) в файл \`${packet.resultFile}\` и продублируй его в последнем сообщении.`,
|
|
160
|
+
].join('\n');
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=packet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"packet.js","sourceRoot":"","sources":["../../src/core/packet.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { CowError } from './errors.js';
|
|
5
|
+
export const COW_DIR = '.cow';
|
|
6
|
+
export const CONFIG_FILE = 'config.yaml';
|
|
7
|
+
/** Ищет корень проекта: ближайший каталог вверх, где есть .cow/config.yaml. */
|
|
8
|
+
export function findProjectRoot(start = process.cwd()) {
|
|
9
|
+
let dir = path.resolve(start);
|
|
10
|
+
for (;;) {
|
|
11
|
+
if (fs.existsSync(path.join(dir, COW_DIR, CONFIG_FILE)))
|
|
12
|
+
return dir;
|
|
13
|
+
const parent = path.dirname(dir);
|
|
14
|
+
if (parent === dir)
|
|
15
|
+
return null;
|
|
16
|
+
dir = parent;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export function requireProjectRoot(start) {
|
|
20
|
+
const root = findProjectRoot(start);
|
|
21
|
+
if (!root) {
|
|
22
|
+
throw new CowError('NO_PROJECT', 'Не найден .cow/config.yaml выше текущего каталога.', 'Выполните `cow init` в корне репозитория продукта.');
|
|
23
|
+
}
|
|
24
|
+
return root;
|
|
25
|
+
}
|
|
26
|
+
/** Корень npm-пакета инструмента: нужен, чтобы находить assets/ и в dev-режиме, и после сборки. */
|
|
27
|
+
export function packageRoot() {
|
|
28
|
+
let dir = path.dirname(fileURLToPath(import.meta.url));
|
|
29
|
+
for (;;) {
|
|
30
|
+
if (fs.existsSync(path.join(dir, 'package.json')))
|
|
31
|
+
return dir;
|
|
32
|
+
const parent = path.dirname(dir);
|
|
33
|
+
if (parent === dir)
|
|
34
|
+
throw new Error('Не найден package.json инструмента');
|
|
35
|
+
dir = parent;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export function assetsDir() {
|
|
39
|
+
return path.join(packageRoot(), 'assets');
|
|
40
|
+
}
|
|
41
|
+
export function cowDir(root) {
|
|
42
|
+
return path.join(root, COW_DIR);
|
|
43
|
+
}
|
|
44
|
+
export function readText(file) {
|
|
45
|
+
return fs.readFileSync(file, 'utf8');
|
|
46
|
+
}
|
|
47
|
+
export function writeText(file, content) {
|
|
48
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
49
|
+
fs.writeFileSync(file, content, 'utf8');
|
|
50
|
+
}
|
|
51
|
+
export function exists(file) {
|
|
52
|
+
return fs.existsSync(file);
|
|
53
|
+
}
|
|
54
|
+
export function toPosix(p) {
|
|
55
|
+
return p.split(path.sep).join('/');
|
|
56
|
+
}
|
|
57
|
+
/** Локальная дата YYYY-MM-DD (не UTC), чтобы имена архивов совпадали с календарём разработчика. */
|
|
58
|
+
export function today() {
|
|
59
|
+
const d = new Date();
|
|
60
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
61
|
+
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=paths.js.map
|