mister-wolf 2.18.5 → 2.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/README.md +12 -1
  2. package/README.ru.md +33 -14
  3. package/dist/adapters/cli/cli-entry.d.ts.map +1 -1
  4. package/dist/adapters/cli/cli-entry.js +10 -1
  5. package/dist/adapters/cli/cli-entry.js.map +1 -1
  6. package/dist/adapters/cli/commands/memory-doctor.d.ts.map +1 -1
  7. package/dist/adapters/cli/commands/memory-doctor.js.map +1 -1
  8. package/dist/adapters/cli/commands/memory-sync.d.ts.map +1 -1
  9. package/dist/adapters/cli/commands/memory-sync.js +3 -0
  10. package/dist/adapters/cli/commands/memory-sync.js.map +1 -1
  11. package/dist/adapters/cli/commands/memory-uninstall.d.ts.map +1 -1
  12. package/dist/adapters/cli/commands/memory-uninstall.js.map +1 -1
  13. package/dist/adapters/cli/commands/memory-upgrade.d.ts +274 -0
  14. package/dist/adapters/cli/commands/memory-upgrade.d.ts.map +1 -1
  15. package/dist/adapters/cli/commands/memory-upgrade.js +1354 -6
  16. package/dist/adapters/cli/commands/memory-upgrade.js.map +1 -1
  17. package/dist/adapters/cli/commands/upgrade-projects.d.ts +19 -0
  18. package/dist/adapters/cli/commands/upgrade-projects.d.ts.map +1 -0
  19. package/dist/adapters/cli/commands/upgrade-projects.js +85 -0
  20. package/dist/adapters/cli/commands/upgrade-projects.js.map +1 -0
  21. package/dist/adapters/cli/report-renderer.d.ts +43 -0
  22. package/dist/adapters/cli/report-renderer.d.ts.map +1 -0
  23. package/dist/adapters/cli/report-renderer.js +184 -0
  24. package/dist/adapters/cli/report-renderer.js.map +1 -0
  25. package/dist/adapters/fs/projects-registry.d.ts +21 -0
  26. package/dist/adapters/fs/projects-registry.d.ts.map +1 -1
  27. package/dist/adapters/fs/projects-registry.js +54 -1
  28. package/dist/adapters/fs/projects-registry.js.map +1 -1
  29. package/dist/adapters/fs/update-map.d.ts +102 -0
  30. package/dist/adapters/fs/update-map.d.ts.map +1 -0
  31. package/dist/adapters/fs/update-map.js +95 -0
  32. package/dist/adapters/fs/update-map.js.map +1 -0
  33. package/dist/adapters/fs/upgrade-lock.d.ts +23 -0
  34. package/dist/adapters/fs/upgrade-lock.d.ts.map +1 -0
  35. package/dist/adapters/fs/upgrade-lock.js +59 -0
  36. package/dist/adapters/fs/upgrade-lock.js.map +1 -0
  37. package/dist/adapters/render/opencode/opencode-renderer.d.ts +45 -5
  38. package/dist/adapters/render/opencode/opencode-renderer.d.ts.map +1 -1
  39. package/dist/adapters/render/opencode/opencode-renderer.js +434 -86
  40. package/dist/adapters/render/opencode/opencode-renderer.js.map +1 -1
  41. package/dist/adapters/render/stamp.d.ts +2 -0
  42. package/dist/adapters/render/stamp.d.ts.map +1 -1
  43. package/dist/adapters/render/stamp.js +9 -1
  44. package/dist/adapters/render/stamp.js.map +1 -1
  45. package/dist/adapters/render/sync-state.d.ts +15 -3
  46. package/dist/adapters/render/sync-state.d.ts.map +1 -1
  47. package/dist/adapters/render/sync-state.js +52 -8
  48. package/dist/adapters/render/sync-state.js.map +1 -1
  49. package/dist/app/use-cases/decisions.d.ts +247 -0
  50. package/dist/app/use-cases/decisions.d.ts.map +1 -0
  51. package/dist/app/use-cases/decisions.js +528 -0
  52. package/dist/app/use-cases/decisions.js.map +1 -0
  53. package/dist/app/use-cases/init-project.d.ts.map +1 -1
  54. package/dist/app/use-cases/init-project.js +34 -1
  55. package/dist/app/use-cases/init-project.js.map +1 -1
  56. package/dist/app/use-cases/platform-mismatch.d.ts +2 -1
  57. package/dist/app/use-cases/platform-mismatch.d.ts.map +1 -1
  58. package/dist/app/use-cases/platform-mismatch.js.map +1 -1
  59. package/dist/app/use-cases/project-step.d.ts +71 -0
  60. package/dist/app/use-cases/project-step.d.ts.map +1 -0
  61. package/dist/app/use-cases/project-step.js +163 -0
  62. package/dist/app/use-cases/project-step.js.map +1 -0
  63. package/dist/app/use-cases/repair-platform.d.ts +2 -1
  64. package/dist/app/use-cases/repair-platform.d.ts.map +1 -1
  65. package/dist/app/use-cases/repair-platform.js.map +1 -1
  66. package/dist/app/use-cases/scan-unregistered.d.ts +25 -0
  67. package/dist/app/use-cases/scan-unregistered.d.ts.map +1 -0
  68. package/dist/app/use-cases/scan-unregistered.js +74 -0
  69. package/dist/app/use-cases/scan-unregistered.js.map +1 -0
  70. package/dist/app/use-cases/seed-base-playbooks.d.ts +10 -0
  71. package/dist/app/use-cases/seed-base-playbooks.d.ts.map +1 -1
  72. package/dist/app/use-cases/seed-base-playbooks.js +54 -13
  73. package/dist/app/use-cases/seed-base-playbooks.js.map +1 -1
  74. package/dist/app/use-cases/sync-base-set.d.ts +4 -2
  75. package/dist/app/use-cases/sync-base-set.d.ts.map +1 -1
  76. package/dist/app/use-cases/sync-base-set.js +4 -2
  77. package/dist/app/use-cases/sync-base-set.js.map +1 -1
  78. package/dist/app/use-cases/uninstall.d.ts +2 -1
  79. package/dist/app/use-cases/uninstall.d.ts.map +1 -1
  80. package/dist/app/use-cases/uninstall.js.map +1 -1
  81. package/dist/app/use-cases/upgrade-projects.d.ts +91 -0
  82. package/dist/app/use-cases/upgrade-projects.d.ts.map +1 -0
  83. package/dist/app/use-cases/upgrade-projects.js +494 -0
  84. package/dist/app/use-cases/upgrade-projects.js.map +1 -0
  85. package/dist/app/use-cases/verify-against-map.d.ts +52 -0
  86. package/dist/app/use-cases/verify-against-map.d.ts.map +1 -0
  87. package/dist/app/use-cases/verify-against-map.js +189 -0
  88. package/dist/app/use-cases/verify-against-map.js.map +1 -0
  89. package/dist/domain/line-diff.d.ts +36 -0
  90. package/dist/domain/line-diff.d.ts.map +1 -0
  91. package/dist/domain/line-diff.js +175 -0
  92. package/dist/domain/line-diff.js.map +1 -0
  93. package/dist/domain/protect-key.d.ts +21 -0
  94. package/dist/domain/protect-key.d.ts.map +1 -0
  95. package/dist/domain/protect-key.js +112 -0
  96. package/dist/domain/protect-key.js.map +1 -0
  97. package/dist/ports/base-set-renderer.port.d.ts +62 -1
  98. package/dist/ports/base-set-renderer.port.d.ts.map +1 -1
  99. package/package.json +3 -2
  100. package/templates/.wolf/router.log +1 -1
  101. package/templates/base/AGENTS.md +6 -3
  102. package/update-map.json +204 -0
@@ -0,0 +1,189 @@
1
+ // src/app/use-cases/verify-against-map.ts
2
+ // T5 (волна 2.19.0, REQ-11, design §«Сверка»): движок сверки проекта против
3
+ // карты обновления. Чистая функция без I/O: ожидание из карты × факт из
4
+ // исходов прохода (sync → seed → removals, design §«Проектный шаг» шаг 5).
5
+ // Исходы — структурные коды, НЕ reason-строки.
6
+ import { basename } from 'path';
7
+ /** Коды, всегда отображаемые как «требует решения» (view-код needs-decision). */
8
+ export const NEEDS_DECISION_CODES = new Set(['skipped-mutated', 'diverged', 'conflict']);
9
+ /** Корень карты (по kind, генератор T1) → корень проекта (LAYOUT opencode-renderer.ts). */
10
+ const TARGET_ROOT = {
11
+ agent: '.opencode/agents/',
12
+ skill: '.opencode/skills/',
13
+ command: '.opencode/command/',
14
+ plugin: '.opencode/plugins/',
15
+ };
16
+ const SOURCE_ROOT = {
17
+ agent: 'base/agents/',
18
+ skill: 'base/skills/',
19
+ command: 'base/commands/',
20
+ plugin: 'opencode/plugins/',
21
+ };
22
+ /** Путь цели карты → проектный путь (LAYOUT opencode-renderer.ts). Экспорт —
23
+ * точечный (T6): проектный шаг использует тот же перевод путей в удалениях. */
24
+ export function projectPath(entry) {
25
+ const src = SOURCE_ROOT[entry.kind];
26
+ return entry.path.startsWith(src) ? TARGET_ROOT[entry.kind] + entry.path.slice(src.length) : entry.path;
27
+ }
28
+ /** Факт sync → код сверки. appended (AGENTS-блок init) ≈ updated. */
29
+ function syncFact(o) {
30
+ // Порядок §4.6: protect/kept перекрывают ожидание категории и не являются решениями.
31
+ if (o.protected)
32
+ return 'protected';
33
+ if (o.kept)
34
+ return 'kept';
35
+ if (o.action === 'conflict')
36
+ return 'conflict';
37
+ if (o.action === 'skipped')
38
+ return o.mutated ? 'skipped-mutated' : 'skipped-identical';
39
+ if (o.action === 'appended')
40
+ return 'updated';
41
+ return o.action;
42
+ }
43
+ /**
44
+ * Категория карты × факт → код. Мутант и unstamped-conflict перекрывают
45
+ * любое ожидание → «требует решения». created/updated/skipped-identical —
46
+ * конечное состояние равно текущему рендеру (повтор прогона NFR-02 — exit 0).
47
+ */
48
+ /**
49
+ * Категория карты × факт → код. Мутант и unstamped-conflict перекрывают
50
+ * любое ожидание → «требует решения», кроме deprecated: цель этой категории
51
+ * остаётся в поставке, но только репортится (`deprecated-noted`, design §4.6) —
52
+ * решение владельца по ней не требуется, иначе `--check` и реестр расходятся.
53
+ */
54
+ function fileVerdict(category, fact) {
55
+ // Защищённая вариация и принятый локальный контент перекрывают ожидание категории (§4.6).
56
+ if (fact === 'protected' || fact === 'kept')
57
+ return fact;
58
+ if (category === 'deprecated') {
59
+ // «файл на месте»: identical/updated/mutated → пометка; created → файла не было
60
+ // (удалён вручную до прохода) — факт ≠ ожиданию → «требует решения».
61
+ return fact === 'created' ? 'conflict' : 'deprecated-noted';
62
+ }
63
+ if (fact === 'skipped-mutated' || fact === 'conflict')
64
+ return fact;
65
+ switch (category) {
66
+ case 'new':
67
+ case 'changed':
68
+ return fact;
69
+ case 'unchanged':
70
+ return fact === 'skipped-identical' ? 'unchanged' : fact;
71
+ case 'removed':
72
+ return fact;
73
+ }
74
+ }
75
+ function item(kind, target, code, detail) {
76
+ return { kind, target, code, needsDecision: NEEDS_DECISION_CODES.has(code), detail };
77
+ }
78
+ function errorItem(kind, target, detail) {
79
+ return { kind, target, code: 'error', needsDecision: false, detail };
80
+ }
81
+ /** Сверка проекта против карты: каждый пункт карты получает статус,
82
+ * факты без ожидания → conflict, отсутствие статуса → error. */
83
+ export function verifyAgainstMap(map, outcomes) {
84
+ if (!map || !Array.isArray(map.files) || !Array.isArray(map.faces) || !map.agents_md) {
85
+ throw new Error('verifyAgainstMap: invalid update map (files/faces/agents_md are required)');
86
+ }
87
+ const items = [];
88
+ const syncByFile = new Map(outcomes.syncOutcomes.map((o) => [o.file, o]));
89
+ const seedByTemplate = new Map(outcomes.seedOutcomes.map((o) => [o.file, o]));
90
+ const removals = new Set(outcomes.removals);
91
+ const seenSync = new Set();
92
+ const seenSeed = new Set();
93
+ const seenRemovals = new Set();
94
+ for (const entry of map.files) {
95
+ const path = projectPath(entry);
96
+ if (entry.category === 'removed') {
97
+ if (removals.has(path)) {
98
+ seenRemovals.add(path);
99
+ items.push(item('file', entry.path, 'removed'));
100
+ }
101
+ else {
102
+ // protect сильнее удаления (REQ-05, §4.3): защищённая removed-цель — факт
103
+ // `protected`/`kept`, а не error; без факта — прежний error (fail-safe).
104
+ const fact = syncByFile.get(path);
105
+ if (fact?.protected || fact?.kept) {
106
+ seenSync.add(path);
107
+ items.push(item('file', entry.path, syncFact(fact)));
108
+ }
109
+ else {
110
+ items.push(errorItem('file', entry.path, 'removed target got no removal status'));
111
+ }
112
+ }
113
+ continue;
114
+ }
115
+ const fact = syncByFile.get(path);
116
+ if (!fact) {
117
+ items.push(errorItem('file', entry.path, `${entry.category} target got no sync outcome`));
118
+ continue;
119
+ }
120
+ seenSync.add(path);
121
+ items.push(item('file', entry.path, fileVerdict(entry.category, syncFact(fact))));
122
+ }
123
+ // AGENTS.md (append-block): цель в корне проекта, категория — из карты.
124
+ const agentsFact = syncByFile.get('AGENTS.md');
125
+ if (agentsFact) {
126
+ seenSync.add('AGENTS.md');
127
+ items.push(item('agents-md', 'AGENTS.md', fileVerdict(map.agents_md.category, syncFact(agentsFact))));
128
+ }
129
+ else {
130
+ items.push(errorItem('agents-md', 'AGENTS.md', 'agents_md target got no sync outcome'));
131
+ }
132
+ for (const face of map.faces) {
133
+ items.push(faceEntry(face, seedByTemplate, seenSeed));
134
+ }
135
+ // Факт без ожидания → conflict → «требует решения» (дрейф без объявления).
136
+ // Защищённый orphan и принятый локальный контент остаются своими кодами (§4.6):
137
+ // иначе санкционированная вариация снова стала бы needs-decision.
138
+ for (const o of outcomes.syncOutcomes) {
139
+ if (!seenSync.has(o.file)) {
140
+ const fact = syncFact(o);
141
+ const code = fact === 'protected' || fact === 'kept' ? fact : 'conflict';
142
+ items.push(item('file', o.file, code, code === 'conflict' ? 'sync outcome for a file outside the map' : undefined));
143
+ }
144
+ }
145
+ for (const o of outcomes.seedOutcomes) {
146
+ if (!seenSeed.has(o.file)) {
147
+ items.push(item('face', o.file, 'conflict', 'seed outcome for a face outside the map'));
148
+ }
149
+ }
150
+ for (const p of outcomes.removals) {
151
+ if (!seenRemovals.has(p)) {
152
+ items.push(item('file', p, 'conflict', 'removal of a file not declared removed in the map'));
153
+ }
154
+ }
155
+ return { items, summary: summarize(items) };
156
+ }
157
+ function faceEntry(face, seedByTemplate, seenSeed) {
158
+ // SeedOutcome.file — базовое имя шаблона (прецедент memory-init.ts); playbooks — плоский каталог.
159
+ const fact = seedByTemplate.get(basename(face.template));
160
+ if (!face.seed) {
161
+ // deprecated-шаблон лица: репортится, не мутируется (R10.4)
162
+ if (!fact)
163
+ return item('face', face.template, 'deprecated-noted');
164
+ seenSeed.add(fact.file);
165
+ return item('face', face.template, 'conflict', 'deprecated face template must not be seeded or updated');
166
+ }
167
+ if (!fact)
168
+ return errorItem('face', face.template, 'seed target got no seed outcome');
169
+ seenSeed.add(fact.file);
170
+ if (!fact.kind) {
171
+ return errorItem('face', face.template, 'seed outcome carries no structural kind (legacy seed mode?)');
172
+ }
173
+ return item('face', face.template, fact.kind);
174
+ }
175
+ function summarize(items) {
176
+ const byCode = {};
177
+ let needsDecision = 0;
178
+ let errors = 0;
179
+ for (const it of items) {
180
+ if (it.code === 'error')
181
+ errors++;
182
+ else
183
+ byCode[it.code] = (byCode[it.code] ?? 0) + 1;
184
+ if (it.needsDecision)
185
+ needsDecision++;
186
+ }
187
+ return { byCode, needsDecision, errors };
188
+ }
189
+ //# sourceMappingURL=verify-against-map.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify-against-map.js","sourceRoot":"","sources":["../../../src/app/use-cases/verify-against-map.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ export interface DiffLine {
2
+ kind: 'context' | 'del' | 'add';
3
+ text: string;
4
+ }
5
+ export interface DiffHunk {
6
+ /** 1-based стартовые номера и длины сторон (как в unified diff). */
7
+ aStart: number;
8
+ aLines: number;
9
+ bStart: number;
10
+ bLines: number;
11
+ lines: DiffLine[];
12
+ }
13
+ export interface LineDiffResult {
14
+ hunks: DiffHunk[];
15
+ /** Число добавленных/удалённых строк (для заголовков `−N +M`). */
16
+ added: number;
17
+ removed: number;
18
+ /** Сколько строк содержимого скрыто лимитом вывода. */
19
+ truncated: number;
20
+ /** Вход был длиннее maxInput и обрезан (лимит §4.10). */
21
+ inputTruncated: boolean;
22
+ }
23
+ export interface LineDiffLimits {
24
+ maxInput?: number;
25
+ maxOutput?: number;
26
+ /** Строк контекста вокруг изменения (по умолчанию 2). */
27
+ context?: number;
28
+ }
29
+ /**
30
+ * Diff двух текстов (a — «было», b — «стало»): хунки с контекстом, счётчики
31
+ * изменений, обрезка вывода по maxOutput (скрытые строки → `truncated`).
32
+ */
33
+ export declare function lineDiff(aText: string, bText: string, limits?: LineDiffLimits): LineDiffResult;
34
+ /** Текстовое представление diff (unified-подобное): заголовки хунков и строки. */
35
+ export declare function formatDiff(result: LineDiffResult): string[];
36
+ //# sourceMappingURL=line-diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"line-diff.d.ts","sourceRoot":"","sources":["../../src/domain/line-diff.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,SAAS,GAAG,KAAK,GAAG,KAAK,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,QAAQ;IACvB,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,SAAS,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AA2GD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,GAAE,cAAmB,GAAG,cAAc,CA4ClG;AAED,kFAAkF;AAClF,wBAAgB,UAAU,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,EAAE,CAW3D"}
@@ -0,0 +1,175 @@
1
+ // src/domain/line-diff.ts
2
+ // T8 (волна 2.20.0, REQ-08, design §4.10): построчный LCS-diff для `--show` и
3
+ // `--review`. Без внешних зависимостей, детерминирован: при равной длине LCS
4
+ // удаление идёт раньше вставки, хунки — от начала файла. Лимиты — вход
5
+ // (maxInput строк на сторону) и вывод (maxOutput строк содержимого, далее
6
+ // «… ещё N строк»). EOL нормализуется: `\r` не делает каждую строку изменённой.
7
+ const DEFAULT_MAX_INPUT = 4000;
8
+ const DEFAULT_MAX_OUTPUT = 200;
9
+ const DEFAULT_CONTEXT = 2;
10
+ /** Порог DP LCS: при n×m больше — блок считается заменой (детерминированно). */
11
+ const DP_CELL_LIMIT = 4_000_000;
12
+ const toLines = (source) => {
13
+ const normalized = source.replace(/\r\n/g, '\n');
14
+ const lines = normalized.split('\n');
15
+ if (lines.length > 0 && lines[lines.length - 1] === '')
16
+ lines.pop();
17
+ return lines;
18
+ };
19
+ function middleOps(a, b) {
20
+ const n = a.length;
21
+ const m = b.length;
22
+ if (n === 0)
23
+ return b.map((text) => ({ kind: 'add', text }));
24
+ if (m === 0)
25
+ return a.map((text) => ({ kind: 'del', text }));
26
+ if (n * m > DP_CELL_LIMIT) {
27
+ return [...a.map((text) => ({ kind: 'del', text })), ...b.map((text) => ({ kind: 'add', text }))];
28
+ }
29
+ const width = m + 1;
30
+ const dp = new Uint32Array((n + 1) * width);
31
+ for (let i = n - 1; i >= 0; i--) {
32
+ for (let j = m - 1; j >= 0; j--) {
33
+ dp[i * width + j] =
34
+ a[i] === b[j] ? dp[(i + 1) * width + j + 1] + 1 : Math.max(dp[(i + 1) * width + j], dp[i * width + j + 1]);
35
+ }
36
+ }
37
+ const ops = [];
38
+ let i = 0;
39
+ let j = 0;
40
+ while (i < n && j < m) {
41
+ if (a[i] === b[j]) {
42
+ ops.push({ kind: 'equal', text: a[i] });
43
+ i++;
44
+ j++;
45
+ }
46
+ else if (dp[(i + 1) * width + j] >= dp[i * width + j + 1]) {
47
+ ops.push({ kind: 'del', text: a[i] });
48
+ i++;
49
+ }
50
+ else {
51
+ ops.push({ kind: 'add', text: b[j] });
52
+ j++;
53
+ }
54
+ }
55
+ while (i < n)
56
+ ops.push({ kind: 'del', text: a[i++] });
57
+ while (j < m)
58
+ ops.push({ kind: 'add', text: b[j++] });
59
+ return ops;
60
+ }
61
+ /** Полный список операций: общий префикс/суффикс не входят в DP. */
62
+ function diffOps(a, b) {
63
+ let start = 0;
64
+ while (start < a.length && start < b.length && a[start] === b[start])
65
+ start++;
66
+ let endA = a.length;
67
+ let endB = b.length;
68
+ while (endA > start && endB > start && a[endA - 1] === b[endB - 1]) {
69
+ endA--;
70
+ endB--;
71
+ }
72
+ const ops = a.slice(0, start).map((text) => ({ kind: 'equal', text }));
73
+ ops.push(...middleOps(a.slice(start, endA), b.slice(start, endB)));
74
+ for (let i = endA; i < a.length; i++)
75
+ ops.push({ kind: 'equal', text: a[i] });
76
+ return ops;
77
+ }
78
+ /** Группировка в хунки: изменения ближе 2×context сливаются, иначе — отдельные. */
79
+ function toHunks(ops, context) {
80
+ // префиксные счётчики сторон: сколько строк a/b прошло до индекса k
81
+ const aBefore = new Uint32Array(ops.length + 1);
82
+ const bBefore = new Uint32Array(ops.length + 1);
83
+ for (let k = 0; k < ops.length; k++) {
84
+ aBefore[k + 1] = aBefore[k] + (ops[k].kind === 'add' ? 0 : 1);
85
+ bBefore[k + 1] = bBefore[k] + (ops[k].kind === 'del' ? 0 : 1);
86
+ }
87
+ const ranges = [];
88
+ let lastChange = -1;
89
+ for (let i = 0; i < ops.length; i++) {
90
+ if (ops[i].kind === 'equal')
91
+ continue;
92
+ const end = Math.min(ops.length - 1, i + context);
93
+ const last = ranges[ranges.length - 1];
94
+ // равный промежуток ≤ 2×context → тот же хунк (стандартное слияние)
95
+ if (last && lastChange >= 0 && i - lastChange - 1 <= 2 * context)
96
+ last[1] = Math.max(last[1], end);
97
+ else
98
+ ranges.push([Math.max(0, i - context), end]);
99
+ lastChange = i;
100
+ }
101
+ return ranges.map(([start, end]) => {
102
+ const lines = ops.slice(start, end + 1).map((op) => ({ kind: op.kind, text: op.text }));
103
+ return {
104
+ aStart: aBefore[start] + 1,
105
+ aLines: aBefore[end + 1] - aBefore[start],
106
+ bStart: bBefore[start] + 1,
107
+ bLines: bBefore[end + 1] - bBefore[start],
108
+ lines,
109
+ };
110
+ });
111
+ }
112
+ /**
113
+ * Diff двух текстов (a — «было», b — «стало»): хунки с контекстом, счётчики
114
+ * изменений, обрезка вывода по maxOutput (скрытые строки → `truncated`).
115
+ */
116
+ export function lineDiff(aText, bText, limits = {}) {
117
+ const maxInput = limits.maxInput ?? DEFAULT_MAX_INPUT;
118
+ const maxOutput = limits.maxOutput ?? DEFAULT_MAX_OUTPUT;
119
+ const context = limits.context ?? DEFAULT_CONTEXT;
120
+ if (aText === bText) {
121
+ return { hunks: [], added: 0, removed: 0, truncated: 0, inputTruncated: false };
122
+ }
123
+ let a = toLines(aText);
124
+ let b = toLines(bText);
125
+ const inputTruncated = a.length > maxInput || b.length > maxInput;
126
+ if (a.length > maxInput)
127
+ a = a.slice(0, maxInput);
128
+ if (b.length > maxInput)
129
+ b = b.slice(0, maxInput);
130
+ const ops = diffOps(a, b);
131
+ const added = ops.filter((op) => op.kind === 'add').length;
132
+ const removed = ops.filter((op) => op.kind === 'del').length;
133
+ const all = toHunks(ops, context);
134
+ const hunks = [];
135
+ let budget = maxOutput;
136
+ let hidden = 0;
137
+ for (const hunk of all) {
138
+ if (budget <= 0) {
139
+ hidden += hunk.lines.length;
140
+ continue;
141
+ }
142
+ if (hunk.lines.length <= budget) {
143
+ hunks.push(hunk);
144
+ budget -= hunk.lines.length;
145
+ continue;
146
+ }
147
+ hunks.push({ ...hunk, lines: hunk.lines.slice(0, budget), aLines: 0, bLines: 0 });
148
+ hidden += hunk.lines.length - budget;
149
+ budget = 0;
150
+ }
151
+ // длины сторон обрезанного хунка пересчитываются по фактическим строкам
152
+ for (const hunk of hunks) {
153
+ if (hunk.aLines === 0 && hunk.bLines === 0 && hunk.lines.length > 0) {
154
+ hunk.aLines = hunk.lines.filter((l) => l.kind !== 'add').length;
155
+ hunk.bLines = hunk.lines.filter((l) => l.kind !== 'del').length;
156
+ }
157
+ }
158
+ return { hunks, added, removed, truncated: hidden, inputTruncated };
159
+ }
160
+ /** Текстовое представление diff (unified-подобное): заголовки хунков и строки. */
161
+ export function formatDiff(result) {
162
+ const out = [];
163
+ for (const hunk of result.hunks) {
164
+ out.push(`@@ -${hunk.aStart},${hunk.aLines} +${hunk.bStart},${hunk.bLines} @@`);
165
+ for (const line of hunk.lines) {
166
+ out.push(`${line.kind === 'del' ? '-' : line.kind === 'add' ? '+' : ' '}${line.text}`);
167
+ }
168
+ }
169
+ if (result.truncated > 0)
170
+ out.push(`… ${result.truncated} more lines`);
171
+ if (result.inputTruncated)
172
+ out.push('… input truncated to the line limit');
173
+ return out;
174
+ }
175
+ //# sourceMappingURL=line-diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"line-diff.js","sourceRoot":"","sources":["../../src/domain/line-diff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /** Разобранное значение ключа: `true` / `X.Y.Z` / null (false, пусто, вне грамматики). */
2
+ export interface ProtectValue {
3
+ /** Держать локальный контент (в т.ч. fail-safe для недописанного/битого значения). */
4
+ held: boolean;
5
+ value: 'true' | string | null;
6
+ raw: string | null;
7
+ /** Значение вне грамматики (`yes`, `2.19`, кавычки, пусто) — держим, но предупреждаем (ADR-5). */
8
+ unrecognized?: true;
9
+ }
10
+ export interface InsertProtectResult {
11
+ content: string;
12
+ changed: boolean;
13
+ error?: 'no-yaml-frontmatter' | 'frontmatter-unparsable';
14
+ }
15
+ export declare function parseProtect(content: string): ProtectValue;
16
+ /** Контент без строк ключа (все они, внутри frontmatter): единая база сравнения и свидетеля. */
17
+ export declare function normalizeManaged(content: string): string;
18
+ export declare function insertProtect(content: string, value: 'true' | string): InsertProtectResult;
19
+ /** Снятие: удаляет все строки ключа, остальное байт-в-байт. */
20
+ export declare function removeProtect(content: string): string;
21
+ //# sourceMappingURL=protect-key.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protect-key.d.ts","sourceRoot":"","sources":["../../src/domain/protect-key.ts"],"names":[],"mappings":"AAMA,0FAA0F;AAC1F,MAAM,WAAW,YAAY;IAC3B,sFAAsF;IACtF,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC9B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,kGAAkG;IAClG,YAAY,CAAC,EAAE,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,qBAAqB,GAAG,wBAAwB,CAAC;CAC1D;AAwCD,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,CAe1D;AAED,gGAAgG;AAChG,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAMxD;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,mBAAmB,CA6B1F;AAWD,+DAA+D;AAC/D,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAErD"}
@@ -0,0 +1,112 @@
1
+ // src/domain/protect-key.ts
2
+ // REQ-05 (design §4.1): единственная точка правды о ключе `protect` в
3
+ // YAML-frontmatter. Чистая логика без I/O: грамматика (parseProtect),
4
+ // нормализация (normalizeManaged), вставка/снятие ключа построчной правкой.
5
+ // Регекса штампа `wolf:rendered` здесь нет — он живёт только в stamp.ts (§4.4).
6
+ const FENCE = '---';
7
+ const KEY_LINE = /^protect\s*:\s*(.*?)\s*$/;
8
+ /** Строка ключа в блоке — для нормализации (шире грамматики: снимаем и `false`). */
9
+ const KEY_ANY = /^protect\s*:/;
10
+ const FULL_VERSION = /^\d+\.\d+\.\d+$/;
11
+ function splitLines(content) {
12
+ const out = [];
13
+ let i = 0;
14
+ while (i < content.length) {
15
+ const nl = content.indexOf('\n', i);
16
+ if (nl === -1) {
17
+ out.push({ text: content.slice(i), eol: '' });
18
+ break;
19
+ }
20
+ const crlf = nl > i && content[nl - 1] === '\r';
21
+ out.push({ text: content.slice(i, crlf ? nl - 1 : nl), eol: crlf ? '\r\n' : '\n' });
22
+ i = nl + 1;
23
+ }
24
+ return out;
25
+ }
26
+ const joinLines = (lines) => lines.map((l) => l.text + l.eol).join('');
27
+ /** Границы frontmatter в строках: первая строка файла — `---`, закрывающая — следующая `---`. */
28
+ function frontmatter(lines) {
29
+ if (lines.length === 0 || lines[0].text !== FENCE)
30
+ return null;
31
+ for (let i = 1; i < lines.length; i++) {
32
+ if (lines[i].text === FENCE)
33
+ return { open: 0, close: i };
34
+ }
35
+ return null;
36
+ }
37
+ export function parseProtect(content) {
38
+ const lines = splitLines(content);
39
+ const fm = frontmatter(lines);
40
+ if (!fm)
41
+ return { held: false, value: null, raw: null };
42
+ for (let i = fm.open + 1; i < fm.close; i++) {
43
+ const m = lines[i].text.match(KEY_LINE);
44
+ if (!m)
45
+ continue;
46
+ const raw = m[1];
47
+ if (raw === '' || raw === '~' || raw === 'null')
48
+ return { held: true, value: null, raw, unrecognized: true };
49
+ if (raw === 'true')
50
+ return { held: true, value: 'true', raw };
51
+ if (raw === 'false')
52
+ return { held: false, value: null, raw };
53
+ if (FULL_VERSION.test(raw))
54
+ return { held: true, value: raw, raw };
55
+ return { held: true, value: null, raw, unrecognized: true };
56
+ }
57
+ return { held: false, value: null, raw: null };
58
+ }
59
+ /** Контент без строк ключа (все они, внутри frontmatter): единая база сравнения и свидетеля. */
60
+ export function normalizeManaged(content) {
61
+ const lines = splitLines(content);
62
+ const fm = frontmatter(lines);
63
+ if (!fm)
64
+ return content;
65
+ const kept = lines.filter((l, i) => !(i > fm.open && i < fm.close && KEY_ANY.test(l.text)));
66
+ return joinLines(kept);
67
+ }
68
+ export function insertProtect(content, value) {
69
+ const lines = splitLines(content);
70
+ const fm0 = frontmatter(lines);
71
+ if (!fm0)
72
+ return { content, changed: false, error: 'no-yaml-frontmatter' };
73
+ const normalized = lines.filter((l, i) => !(i > fm0.open && i < fm0.close && KEY_ANY.test(l.text)));
74
+ const fm = frontmatter(normalized);
75
+ if (!fm)
76
+ return { content, changed: false, error: 'frontmatter-unparsable' };
77
+ const closeEol = normalized[fm.close].eol === '\r\n' ? '\r\n' : '\n';
78
+ const result = joinLines([
79
+ ...normalized.slice(0, fm.close),
80
+ { text: `protect: ${value}`, eol: closeEol },
81
+ ...normalized.slice(fm.close),
82
+ ]);
83
+ // Структурная проверка ДО возврата (§4.1 п.3): границы блока, распознавание значения,
84
+ // взаимная обратимость с нормализацией. Файл пишет вызывающий — но только валидный контент.
85
+ const check = splitLines(result);
86
+ const fm1 = frontmatter(check);
87
+ if (!fm1 || fm1.close !== fm.close + 1 || check[fm1.close].text !== FENCE) {
88
+ return { content, changed: false, error: 'frontmatter-unparsable' };
89
+ }
90
+ const parsed = parseProtect(result);
91
+ const expected = value === 'true' ? parsed.held && parsed.value === 'true' : parsed.held && parsed.value === value;
92
+ if (!expected)
93
+ return { content, changed: false, error: 'frontmatter-unparsable' };
94
+ if (reinstateProtectLine(result, value) !== result) {
95
+ return { content, changed: false, error: 'frontmatter-unparsable' };
96
+ }
97
+ return { content: result, changed: result !== content };
98
+ }
99
+ /** Обратимость (в): нормализованный контент + строка ключа перед закрывающим `---`. */
100
+ function reinstateProtectLine(content, value) {
101
+ const lines = splitLines(normalizeManaged(content));
102
+ const fm = frontmatter(lines);
103
+ if (!fm)
104
+ return content;
105
+ const eol = lines[fm.close].eol === '\r\n' ? '\r\n' : '\n';
106
+ return joinLines([...lines.slice(0, fm.close), { text: `protect: ${value}`, eol }, ...lines.slice(fm.close)]);
107
+ }
108
+ /** Снятие: удаляет все строки ключа, остальное байт-в-байт. */
109
+ export function removeProtect(content) {
110
+ return normalizeManaged(content);
111
+ }
112
+ //# sourceMappingURL=protect-key.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protect-key.js","sourceRoot":"","sources":["../../src/domain/protect-key.ts"],"names":[],"mappings":"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"}