mister-wolf 2.19.0 → 2.20.1

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 (92) hide show
  1. package/README.md +12 -1
  2. package/README.ru.md +19 -2
  3. package/dist/adapters/cli/commands/memory-doctor.d.ts.map +1 -1
  4. package/dist/adapters/cli/commands/memory-doctor.js.map +1 -1
  5. package/dist/adapters/cli/commands/memory-uninstall.d.ts.map +1 -1
  6. package/dist/adapters/cli/commands/memory-uninstall.js.map +1 -1
  7. package/dist/adapters/cli/commands/memory-upgrade.d.ts +143 -2
  8. package/dist/adapters/cli/commands/memory-upgrade.d.ts.map +1 -1
  9. package/dist/adapters/cli/commands/memory-upgrade.js +887 -41
  10. package/dist/adapters/cli/commands/memory-upgrade.js.map +1 -1
  11. package/dist/adapters/cli/commands/upgrade-projects.d.ts +4 -2
  12. package/dist/adapters/cli/commands/upgrade-projects.d.ts.map +1 -1
  13. package/dist/adapters/cli/commands/upgrade-projects.js +17 -7
  14. package/dist/adapters/cli/commands/upgrade-projects.js.map +1 -1
  15. package/dist/adapters/platforms/index.d.ts.map +1 -1
  16. package/dist/adapters/platforms/index.js +2 -1
  17. package/dist/adapters/platforms/index.js.map +1 -1
  18. package/dist/adapters/platforms/opencode-adapter.d.ts +13 -4
  19. package/dist/adapters/platforms/opencode-adapter.d.ts.map +1 -1
  20. package/dist/adapters/platforms/opencode-adapter.js +278 -55
  21. package/dist/adapters/platforms/opencode-adapter.js.map +1 -1
  22. package/dist/adapters/platforms/opencode-config-keys.d.ts +78 -0
  23. package/dist/adapters/platforms/opencode-config-keys.d.ts.map +1 -0
  24. package/dist/adapters/platforms/opencode-config-keys.js +169 -0
  25. package/dist/adapters/platforms/opencode-config-keys.js.map +1 -0
  26. package/dist/adapters/render/opencode/opencode-renderer.d.ts +35 -7
  27. package/dist/adapters/render/opencode/opencode-renderer.d.ts.map +1 -1
  28. package/dist/adapters/render/opencode/opencode-renderer.js +395 -115
  29. package/dist/adapters/render/opencode/opencode-renderer.js.map +1 -1
  30. package/dist/adapters/render/stamp.d.ts +2 -0
  31. package/dist/adapters/render/stamp.d.ts.map +1 -1
  32. package/dist/adapters/render/stamp.js +9 -1
  33. package/dist/adapters/render/stamp.js.map +1 -1
  34. package/dist/adapters/render/sync-state.d.ts +15 -3
  35. package/dist/adapters/render/sync-state.d.ts.map +1 -1
  36. package/dist/adapters/render/sync-state.js +52 -8
  37. package/dist/adapters/render/sync-state.js.map +1 -1
  38. package/dist/app/use-cases/decisions.d.ts +247 -0
  39. package/dist/app/use-cases/decisions.d.ts.map +1 -0
  40. package/dist/app/use-cases/decisions.js +528 -0
  41. package/dist/app/use-cases/decisions.js.map +1 -0
  42. package/dist/app/use-cases/doctor.d.ts.map +1 -1
  43. package/dist/app/use-cases/doctor.js +6 -0
  44. package/dist/app/use-cases/doctor.js.map +1 -1
  45. package/dist/app/use-cases/init-project.d.ts.map +1 -1
  46. package/dist/app/use-cases/init-project.js +39 -3
  47. package/dist/app/use-cases/init-project.js.map +1 -1
  48. package/dist/app/use-cases/platform-mismatch.d.ts +2 -1
  49. package/dist/app/use-cases/platform-mismatch.d.ts.map +1 -1
  50. package/dist/app/use-cases/platform-mismatch.js.map +1 -1
  51. package/dist/app/use-cases/project-step.d.ts +20 -1
  52. package/dist/app/use-cases/project-step.d.ts.map +1 -1
  53. package/dist/app/use-cases/project-step.js +101 -15
  54. package/dist/app/use-cases/project-step.js.map +1 -1
  55. package/dist/app/use-cases/repair-platform.d.ts +2 -1
  56. package/dist/app/use-cases/repair-platform.d.ts.map +1 -1
  57. package/dist/app/use-cases/repair-platform.js +4 -1
  58. package/dist/app/use-cases/repair-platform.js.map +1 -1
  59. package/dist/app/use-cases/sync-base-set.d.ts +4 -2
  60. package/dist/app/use-cases/sync-base-set.d.ts.map +1 -1
  61. package/dist/app/use-cases/sync-base-set.js +4 -2
  62. package/dist/app/use-cases/sync-base-set.js.map +1 -1
  63. package/dist/app/use-cases/tool-librarian.d.ts.map +1 -1
  64. package/dist/app/use-cases/tool-librarian.js +3 -1
  65. package/dist/app/use-cases/tool-librarian.js.map +1 -1
  66. package/dist/app/use-cases/uninstall.d.ts +2 -1
  67. package/dist/app/use-cases/uninstall.d.ts.map +1 -1
  68. package/dist/app/use-cases/uninstall.js.map +1 -1
  69. package/dist/app/use-cases/upgrade-projects.d.ts +30 -0
  70. package/dist/app/use-cases/upgrade-projects.d.ts.map +1 -1
  71. package/dist/app/use-cases/upgrade-projects.js +119 -4
  72. package/dist/app/use-cases/upgrade-projects.js.map +1 -1
  73. package/dist/app/use-cases/verify-against-map.d.ts +5 -1
  74. package/dist/app/use-cases/verify-against-map.d.ts.map +1 -1
  75. package/dist/app/use-cases/verify-against-map.js +34 -6
  76. package/dist/app/use-cases/verify-against-map.js.map +1 -1
  77. package/dist/domain/line-diff.d.ts +36 -0
  78. package/dist/domain/line-diff.d.ts.map +1 -0
  79. package/dist/domain/line-diff.js +175 -0
  80. package/dist/domain/line-diff.js.map +1 -0
  81. package/dist/domain/protect-key.d.ts +21 -0
  82. package/dist/domain/protect-key.d.ts.map +1 -0
  83. package/dist/domain/protect-key.js +112 -0
  84. package/dist/domain/protect-key.js.map +1 -0
  85. package/dist/ports/base-set-renderer.port.d.ts +51 -3
  86. package/dist/ports/base-set-renderer.port.d.ts.map +1 -1
  87. package/dist/ports/platform-adapter.port.d.ts +8 -2
  88. package/dist/ports/platform-adapter.port.d.ts.map +1 -1
  89. package/package.json +1 -1
  90. package/templates/.wolf/router.log +1 -1
  91. package/templates/base/AGENTS.md +6 -3
  92. package/update-map.json +2 -2
@@ -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":"AAAA,0BAA0B;AAC1B,8EAA8E;AAC9E,6EAA6E;AAC7E,uEAAuE;AACvE,0EAA0E;AAC1E,gFAAgF;AAkChF,MAAM,iBAAiB,GAAG,IAAI,CAAC;AAC/B,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAC/B,MAAM,eAAe,GAAG,CAAC,CAAC;AAC1B,gFAAgF;AAChF,MAAM,aAAa,GAAG,SAAS,CAAC;AAEhC,MAAM,OAAO,GAAG,CAAC,MAAc,EAAY,EAAE;IAC3C,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACrC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE;QAAE,KAAK,CAAC,GAAG,EAAE,CAAC;IACpE,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAOF,SAAS,SAAS,CAAC,CAAW,EAAE,CAAW;IACzC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;IACnB,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;IACnB,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAc,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACtE,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAc,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACtE,IAAI,CAAC,GAAG,CAAC,GAAG,aAAa,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAc,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAc,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACtH,CAAC;IACD,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC;IACpB,MAAM,EAAE,GAAG,IAAI,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC;IAC5C,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAChC,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAChC,EAAE,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;gBACf,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,CAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,CAAE,EAAE,EAAE,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,CAAE,CAAC,CAAC;QAClH,CAAC;IACH,CAAC;IACD,MAAM,GAAG,GAAS,EAAE,CAAC;IACrB,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAClB,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAE,EAAE,CAAC,CAAC;YACzC,CAAC,EAAE,CAAC;YACJ,CAAC,EAAE,CAAC;QACN,CAAC;aAAM,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,CAAE,IAAI,EAAE,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,CAAE,EAAE,CAAC;YAC9D,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAE,EAAE,CAAC,CAAC;YACvC,CAAC,EAAE,CAAC;QACN,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAE,EAAE,CAAC,CAAC;YACvC,CAAC,EAAE,CAAC;QACN,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,CAAC;QAAE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAE,EAAE,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC;QAAE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAE,EAAE,CAAC,CAAC;IACvD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,oEAAoE;AACpE,SAAS,OAAO,CAAC,CAAW,EAAE,CAAW;IACvC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,OAAO,KAAK,GAAG,CAAC,CAAC,MAAM,IAAI,KAAK,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC;QAAE,KAAK,EAAE,CAAC;IAC9E,IAAI,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC;IACpB,IAAI,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC;IACpB,OAAO,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,EAAE,CAAC;QACnE,IAAI,EAAE,CAAC;QACP,IAAI,EAAE,CAAC;IACT,CAAC;IACD,MAAM,GAAG,GAAS,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,OAAgB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACtF,GAAG,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IACnE,KAAK,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAE,EAAE,CAAC,CAAC;IAC/E,OAAO,GAAG,CAAC;AACb,CAAC;AAED,mFAAmF;AACnF,SAAS,OAAO,CAAC,GAAS,EAAE,OAAe;IACzC,oEAAoE;IACpE,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAChD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAChE,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,MAAM,MAAM,GAA4B,EAAE,CAAC;IAC3C,IAAI,UAAU,GAAG,CAAC,CAAC,CAAC;IACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,IAAI,GAAG,CAAC,CAAC,CAAE,CAAC,IAAI,KAAK,OAAO;YAAE,SAAS;QACvC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC;QAClD,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACvC,oEAAoE;QACpE,IAAI,IAAI,IAAI,UAAU,IAAI,CAAC,IAAI,CAAC,GAAG,UAAU,GAAG,CAAC,IAAI,CAAC,GAAG,OAAO;YAAE,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;;YAC9F,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QAClD,UAAU,GAAG,CAAC,CAAC;IACjB,CAAC;IAED,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,EAAE;QACjC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAa,CAAC,CAAC;QACpG,OAAO;YACL,MAAM,EAAE,OAAO,CAAC,KAAK,CAAE,GAAG,CAAC;YAC3B,MAAM,EAAE,OAAO,CAAC,GAAG,GAAG,CAAC,CAAE,GAAG,OAAO,CAAC,KAAK,CAAE;YAC3C,MAAM,EAAE,OAAO,CAAC,KAAK,CAAE,GAAG,CAAC;YAC3B,MAAM,EAAE,OAAO,CAAC,GAAG,GAAG,CAAC,CAAE,GAAG,OAAO,CAAC,KAAK,CAAE;YAC3C,KAAK;SACN,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,KAAa,EAAE,KAAa,EAAE,SAAyB,EAAE;IAChF,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,iBAAiB,CAAC;IACtD,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,kBAAkB,CAAC;IACzD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,eAAe,CAAC;IAElD,IAAI,KAAK,KAAK,KAAK,EAAE,CAAC;QACpB,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC;IAClF,CAAC;IACD,IAAI,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IACvB,IAAI,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IACvB,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,GAAG,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,QAAQ,CAAC;IAClE,IAAI,CAAC,CAAC,MAAM,GAAG,QAAQ;QAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAClD,IAAI,CAAC,CAAC,MAAM,GAAG,QAAQ;QAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAElD,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1B,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,MAAM,CAAC;IAC3D,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,MAAM,CAAC;IAC7D,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAElC,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,IAAI,MAAM,GAAG,SAAS,CAAC;IACvB,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,IAAI,IAAI,GAAG,EAAE,CAAC;QACvB,IAAI,MAAM,IAAI,CAAC,EAAE,CAAC;YAChB,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;YAC5B,SAAS;QACX,CAAC;QACD,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,MAAM,EAAE,CAAC;YAChC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjB,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;YAC5B,SAAS;QACX,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;QAClF,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;QACrC,MAAM,GAAG,CAAC,CAAC;IACb,CAAC;IACD,wEAAwE;IACxE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,MAAM,CAAC;YAChE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,MAAM,CAAC;QAClE,CAAC;IACH,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;AACtE,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,UAAU,CAAC,MAAsB;IAC/C,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QAChC,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC;QAChF,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9B,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACzF,CAAC;IACH,CAAC;IACD,IAAI,MAAM,CAAC,SAAS,GAAG,CAAC;QAAE,GAAG,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,SAAS,aAAa,CAAC,CAAC;IACvE,IAAI,MAAM,CAAC,cAAc;QAAE,GAAG,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC;IAC3E,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -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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"}
@@ -7,6 +7,14 @@ export interface RenderOutcome {
7
7
  * verifyAgainstMap различает skipped-identical / skipped-mutated полем,
8
8
  * не парсингом reason-строки. */
9
9
  mutated?: boolean;
10
+ /** Правило 2 §4.3: файл держится ключом protect, не тронут (вне needs-decision). */
11
+ protected?: true;
12
+ /** Значение ключа для дайджеста (`true` | `X.Y.Z` | raw вне грамматики). */
13
+ protect?: string | true;
14
+ /** Правило 6.5 §4.3: принятый локальный контент (origin:'keep'), файл не менялся. */
15
+ kept?: true;
16
+ /** Путь бэкапа, если файл был перезаписан по режиму take-on-mutated (§4.12). */
17
+ backup?: string;
10
18
  }
11
19
  /** Контекст подстановки моделей (onboarding v2, §4.5): {{model.primary}} / {{model.worker}}. */
12
20
  export interface ModelContext {
@@ -15,12 +23,30 @@ export interface ModelContext {
15
23
  }
16
24
  /** Действие read-only инспекции цели (T10, REQ-08, design §«--check»): цель
17
25
  * сверяется с текущим рендером без единой записи на диск. foreign — unstamped
18
- * файл на месте цели (wx-политика: чужое, вне покрытия). */
19
- export type InspectAction = 'identical' | 'differs' | 'missing' | 'mutated' | 'foreign' | 'unknown';
26
+ * файл на месте цели (wx-политика: чужое, вне покрытия). protected/kept —
27
+ * защищённая вариация и принятый локальный контент: не решения (§4.6). */
28
+ export type InspectAction = 'identical' | 'differs' | 'missing' | 'mutated' | 'foreign' | 'unknown' | 'protected' | 'kept';
20
29
  export interface InspectOutcome {
21
30
  /** rel-путь от baseDir — тот же ключ, что RenderOutcome.file. */
22
31
  file: string;
23
32
  action: InspectAction;
33
+ protected?: true;
34
+ protect?: string | true;
35
+ kept?: true;
36
+ /** База, на которой владелец принял локальный контент (правило 6.5 §4.3). */
37
+ keepBase?: string;
38
+ /** Причина наблюдения для человека (`onboarding markers broken`, …); в classify
39
+ * и `--check` передаётся полем, а не разбором reason-строки (§4.15). */
40
+ detail?: string;
41
+ }
42
+ /** Хук бэкапа: приложение решает, куда и как копировать; рендерер только
43
+ * требует «сначала бэкап, потом запись» (NFR-05). Возвращает путь бэкапа. */
44
+ export type BackupHook = (rel: string, content: string) => Promise<string>;
45
+ export interface SyncBaseSetOptions {
46
+ /** --yes (§4.12): mutated → бэкап + эталон. Без хука режим запрещён. */
47
+ takeMutated?: {
48
+ backup: BackupHook;
49
+ };
24
50
  }
25
51
  export interface BakeResolver {
26
52
  /** Вернуть тело playbook'а для вживления (bake-in) или null. Источник — память целевого проекта (§4). */
@@ -34,6 +60,22 @@ export interface RenderBaseSetOptions {
34
60
  * 'full' (дефолт) — весь базовый набор. */
35
61
  scope?: 'full' | 'agents-md';
36
62
  }
63
+ /** Реестр защит (`--check`, REQ-09; design §4.11): включая файлы вне карты. */
64
+ export interface ProtectEntry {
65
+ /** Корень проекта (abs). */
66
+ project: string;
67
+ /** rel-путь от корня проекта. */
68
+ file: string;
69
+ /** `true` | `X.Y.Z` либо raw вне грамматики. */
70
+ value: 'true' | string;
71
+ /** false — значение вне грамматики (вывод с предупреждением). */
72
+ recognized: boolean;
73
+ stamp: string | null;
74
+ /** Версия базы (map.version). */
75
+ base: string;
76
+ /** Нормализованный контент != fresh; null — эталона нет (файл вне карты). */
77
+ behind: boolean | null;
78
+ }
37
79
  export interface BaseSetRenderer {
38
80
  id: string;
39
81
  /** Init-рендер: create + diff-ветка (§4.5: stamped + diff контента → updated; unstamped → skipped). */
@@ -43,9 +85,15 @@ export interface BaseSetRenderer {
43
85
  * models — контекст из routing-объекта; 'omit' (и undefined — легаси без routing-объекта) —
44
86
  * построчное удаление model:-строки из fresh-контента (§4.5).
45
87
  */
46
- syncBaseSet(baseDir: string, models?: ModelContext | 'omit'): Promise<{
88
+ syncBaseSet(baseDir: string, models?: ModelContext | 'omit', opts?: SyncBaseSetOptions): Promise<{
47
89
  outcomes: RenderOutcome[];
48
90
  orphaned: string[];
49
91
  }>;
92
+ /** Read-only инспекция целей base-set и AGENTS.md (`--check`, §4.6). */
93
+ inspectBaseSet?(baseDir: string, opts?: RenderBaseSetOptions): Promise<InspectOutcome[]>;
94
+ /** Read-only реестр защит по каталогам base-set, включая файлы вне карты (§4.11). */
95
+ listProtections?(baseDir: string, base: string): Promise<ProtectEntry[]>;
96
+ /** Свежий рендер одного rel-файла (эталон для `--show`/`behind`); null — файла нет в карте. */
97
+ renderFreshFile?(baseDir: string, rel: string, opts?: RenderBaseSetOptions): string | null;
50
98
  }
51
99
  //# sourceMappingURL=base-set-renderer.port.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"base-set-renderer.port.d.ts","sourceRoot":"","sources":["../../src/ports/base-set-renderer.port.ts"],"names":[],"mappings":"AACA,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC;AAEvF,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;sCAEkC;IAClC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,gGAAgG;AAChG,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;6DAE6D;AAC7D,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAEpG,MAAM,WAAW,cAAc;IAC7B,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,aAAa,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,yGAAyG;IACzG,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CACnC;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,0GAA0G;IAC1G,MAAM,CAAC,EAAE,YAAY,GAAG,MAAM,CAAC;IAC/B;+CAC2C;IAC3C,KAAK,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,uGAAuG;IACvG,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;IACtF;;;;OAIG;IACH,WAAW,CACT,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,YAAY,GAAG,MAAM,GAC7B,OAAO,CAAC;QAAE,QAAQ,EAAE,aAAa,EAAE,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;CAC/D"}
1
+ {"version":3,"file":"base-set-renderer.port.d.ts","sourceRoot":"","sources":["../../src/ports/base-set-renderer.port.ts"],"names":[],"mappings":"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"}
@@ -40,18 +40,24 @@ export interface PlatformAdapter {
40
40
  * Идемпотентная запись wolf-сервера (ключ идемпотентности — имя MCP-сервера 'wolf'):
41
41
  * 'written' — создан, 'replaced' — существующая запись wolf перезаписана (в т.ч. ручная
42
42
  * dev-запись), 'unchanged' — уже канонический. Чужие серверы и секции не трогаются.
43
- * opencode мерджит ещё и default_agent/subagent_depth (§6.1): конфликт — unchanged + reason.
43
+ * opencode мерджит ещё и default_agent/subagent_depth (§6.1) — глубина живёт в
44
+ * `experimental.subagent_depth` (opencode v2; верхнеуровневый ключ deprecated): конфликт — unchanged + reason.
44
45
  */
45
46
  writeConfig(projectRoot: string, cmd: McpCommand): Promise<PlatformWriteResult>;
46
47
  /** Удалить wolf-запись (для --platform replace-семантики); true если удалил. */
47
48
  removeWolf(projectRoot: string): Promise<boolean>;
48
49
  /**
49
50
  * 2.16.2 (uninstall): удалить ТОЛЬКО wolf-ключи с ТОЧНЫМ нашим значением
50
- * (mcp.wolf / mcpServers.wolf; default_agent === mr-wolf; subagent_depth === 2 —
51
+ * (mcp.wolf / mcpServers.wolf; default_agent === mr-wolf; experimental.subagent_depth === 2 —
51
52
  * пользовательскую повышенную настройку не трогаем). Отсутствующий конфиг —
52
53
  * { action: 'skipped', reason }.
53
54
  */
54
55
  removeWolfKeys?(projectRoot: string): Promise<PlatformWriteResult>;
56
+ /**
57
+ * Строки проблем конфига, которые знает только адаптер (6.2/6.3: обе формы MCP-записи).
58
+ * Нет метода — doctor делает generic-проверку wolf-записи.
59
+ */
60
+ configIssues?(projectRoot: string): Promise<string[]>;
55
61
  /** Детект версии платформы (опционально; init не ломается, если адаптер не умеет). */
56
62
  detectVersion?(projectRoot: string): Promise<PlatformVersionInfo>;
57
63
  }
@@ -1 +1 @@
1
- {"version":3,"file":"platform-adapter.port.d.ts","sourceRoot":"","sources":["../../src/ports/platform-adapter.port.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,8EAA8E;AAC9E,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAErD,2HAA2H;AAC3H,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,WAAW,GAAG,SAAS,GAAG,SAAS,CAAC;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mGAAmG;IACnG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gHAAgH;IAChH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG,IAAI,GAAG,IAAI,GAAG,aAAa,GAAG,QAAQ,GAAG,aAAa,CAAC;AAE3F,0EAA0E;AAC1E,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,qBAAqB,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,2DAA2D;IAC3D,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;IACrC,yDAAyD;IACzD,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IAChE;;;;;OAKG;IACH,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAChF,gFAAgF;IAChF,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClD;;;;;OAKG;IACH,cAAc,CAAC,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACnE,sFAAsF;IACtF,aAAa,CAAC,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;CACnE"}
1
+ {"version":3,"file":"platform-adapter.port.d.ts","sourceRoot":"","sources":["../../src/ports/platform-adapter.port.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,8EAA8E;AAC9E,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAErD,2HAA2H;AAC3H,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,WAAW,GAAG,SAAS,GAAG,SAAS,CAAC;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mGAAmG;IACnG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gHAAgH;IAChH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG,IAAI,GAAG,IAAI,GAAG,aAAa,GAAG,QAAQ,GAAG,aAAa,CAAC;AAE3F,0EAA0E;AAC1E,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,qBAAqB,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,2DAA2D;IAC3D,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;IACrC,yDAAyD;IACzD,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IAChE;;;;;;OAMG;IACH,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAChF,gFAAgF;IAChF,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClD;;;;;OAKG;IACH,cAAc,CAAC,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACnE;;;OAGG;IACH,YAAY,CAAC,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACtD,sFAAsF;IACtF,aAAa,CAAC,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;CACnE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mister-wolf",
3
- "version": "2.19.0",
3
+ "version": "2.20.1",
4
4
  "description": "Local-first project memory for AI coding agents: decisions, lessons, tools and processes that outlive the session",
5
5
  "keywords": [
6
6
  "ai-agents",
@@ -1 +1 @@
1
- 2026-10-24T17:36:23.551Z agent-id=v2-router-probe-xyz playbook=hit name=fallback variant=fallback source=default resolution=error face_id=- version=- hash=- session=opc-277ab5c4-acf5-40ed-bfb9-6037555e3f73 injected=yes ms=1 bytes=1274
1
+ 2026-10-25T20:17:27.443Z agent-id=v2-router-probe-xyz playbook=hit name=fallback variant=fallback source=default resolution=error face_id=- version=- hash=- session=opc-4200d069-b038-4694-a9a6-3509841abc3c injected=yes ms=1 bytes=1274
@@ -1,4 +1,4 @@
1
- <!-- wolf:onboarding v2 -->
1
+ <!-- wolf:onboarding v3 -->
2
2
 
3
3
  # Mr. Wolf — память проекта
4
4
 
@@ -26,7 +26,10 @@
26
26
  ## Указатели
27
27
 
28
28
  - Документация: `docs/README.md`
29
+ - Защита файла от обновления: `protect: true` (или `protect: X.Y.Z`) в YAML-frontmatter
30
+ agent/skill/command-файла; конфликты разбираются `wolf upgrade --review`,
31
+ снятие защиты — `wolf upgrade --resolve <файл>=take|keep`.
29
32
  - Номер версии всегда полный X.Y.Z — в планах, тредах, волнах, тегах и разговоре.
30
- Голый минор («2.16») запрещён как имя релиза/волны/треда/плана: релизов «2.16» не
31
- существует, есть «2.16.0», «2.16.1» (пример корректного полного номера: 2.16.2).
33
+ Голый минор («2.16») запрещён как имя релиза/волны/треда/плана: релизов «2.16» не
34
+ существует, есть «2.16.0», «2.16.1» (пример корректного полного номера: 2.16.2).
32
35
  <!-- /wolf:onboarding -->
package/update-map.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "2.19.0",
3
- "prev": "2.18.5",
2
+ "version": "2.20.1",
3
+ "prev": "2.20.0",
4
4
  "files": [
5
5
  {
6
6
  "path": "base/agents/executor-lead.md",