@dzhechkov/keysarium 1.7.3 → 1.7.5
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/.dz-manifest.json +9 -5
- package/README.md +9 -1
- package/package.json +4 -4
- package/sbom.json +14 -4
- package/templates/.claude/skills/feature-adr/scripts/check-plan-completeness.mjs +17 -16
- package/templates/.claude/skills/feature-adr/scripts/markdown-masker.mjs +109 -0
- package/templates/.claude/skills/reverse-engineering-unicorn/modules/025-cjm-prototype.md +21 -1
package/.dz-manifest.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"files": [
|
|
6
6
|
{
|
|
7
7
|
"path": "README.md",
|
|
8
|
-
"sha256": "
|
|
8
|
+
"sha256": "e2f661392b2862870ae3ab05892493e5a7ddcdb86360690d126525f08b6d87a1"
|
|
9
9
|
},
|
|
10
10
|
{
|
|
11
11
|
"path": "README.ru.md",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"path": "package.json",
|
|
20
|
-
"sha256": "
|
|
20
|
+
"sha256": "56048c9ebf810b35645674fe4a413112af02be6a53836583d3c80b0ad4047dde"
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
23
|
"path": "src/cli.js",
|
|
@@ -481,7 +481,11 @@
|
|
|
481
481
|
},
|
|
482
482
|
{
|
|
483
483
|
"path": "templates/.claude/skills/feature-adr/scripts/check-plan-completeness.mjs",
|
|
484
|
-
"sha256": "
|
|
484
|
+
"sha256": "cbe70a524f6ce7987b5e3961ee412b92c24c00d84066d438c759659d656efaa2"
|
|
485
|
+
},
|
|
486
|
+
{
|
|
487
|
+
"path": "templates/.claude/skills/feature-adr/scripts/markdown-masker.mjs",
|
|
488
|
+
"sha256": "82c3c48c25f400f3a64d1caba3d47357f3db87460f0746f88706f901eb6ff689"
|
|
485
489
|
},
|
|
486
490
|
{
|
|
487
491
|
"path": "templates/.claude/skills/frontend-design/LICENSE.txt",
|
|
@@ -669,7 +673,7 @@
|
|
|
669
673
|
},
|
|
670
674
|
{
|
|
671
675
|
"path": "templates/.claude/skills/reverse-engineering-unicorn/modules/025-cjm-prototype.md",
|
|
672
|
-
"sha256": "
|
|
676
|
+
"sha256": "d9dd399cbb60d6b5fa9734ad44128a49790ef15bbde25c809d69d5c918601eb3"
|
|
673
677
|
},
|
|
674
678
|
{
|
|
675
679
|
"path": "templates/.claude/skills/reverse-engineering-unicorn/modules/03-market-competition.md",
|
|
@@ -985,5 +989,5 @@
|
|
|
985
989
|
}
|
|
986
990
|
]
|
|
987
991
|
},
|
|
988
|
-
"signature": "
|
|
992
|
+
"signature": "Ni8QtKUfWoED6GoaSA9ARScSXZdJxtM6FSWTILwzYsRLvgJ6fyCmHV9Vz0IriuT0E/NXt8YYp1Oo8Np1iBpVDg=="
|
|
989
993
|
}
|
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ Full 7-phase pipeline for AI case studies, hackathons, and casariums. Provides s
|
|
|
18
18
|
> the teach protocol. See `skills/goap-research-ed25519/SKILL.md`.
|
|
19
19
|
|
|
20
20
|
## Growth engine (reverse-engineering-unicorn M5)
|
|
21
|
-
### What M5 produces, since 0.2.0 / 1.7.
|
|
21
|
+
### What M5 produces, since 0.2.0 / 1.7.5 / 1.6.0
|
|
22
22
|
|
|
23
23
|
M5 no longer ends as analysis. Three changes, in the order they matter:
|
|
24
24
|
|
|
@@ -458,3 +458,11 @@ carried that file and the last four in a row did not.
|
|
|
458
458
|
|
|
459
459
|
`1.5.40` — the bundled `feature-adr` Step-8 module now describes the amendment gate as the command
|
|
460
460
|
`dz amendment-check` instead of a judgement the reviewer is asked to make. Text only; no pipeline change.
|
|
461
|
+
|
|
462
|
+
### Shared Markdown masking in feature-adr gates
|
|
463
|
+
|
|
464
|
+
The standalone plan-completeness gate ships with `markdown-masker.mjs`, copied byte-for-byte from
|
|
465
|
+
harness-core's `src/markdown-masker.ts`. It runs without a core build. Amendment checks, swarm briefs
|
|
466
|
+
and K2 share the parser while retaining their existing unclosed-block and indentation policies.
|
|
467
|
+
The four-space indented-code gap remains open for amendment checks and K2; swarm briefs retain their
|
|
468
|
+
existing masking of indented code. Versions are unchanged in this staged change.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dzhechkov/keysarium",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.5",
|
|
4
4
|
"description": "AI Case Research Toolkit for Claude Code — full 7-phase pipeline with feature-adr, dream cycles, background workers, multi-platform support, reward learning, and Cloud.ru AI Factory mapping (--ai-factory flag)",
|
|
5
5
|
"main": "src/cli.js",
|
|
6
6
|
"bin": {
|
|
@@ -34,12 +34,12 @@
|
|
|
34
34
|
},
|
|
35
35
|
"repository": {
|
|
36
36
|
"type": "git",
|
|
37
|
-
"url": "https://github.com/djd1m/dz-harness
|
|
37
|
+
"url": "git+https://github.com/djd1m/dz-harness.git",
|
|
38
38
|
"directory": "packages/@dzhechkov/keysarium"
|
|
39
39
|
},
|
|
40
|
-
"homepage": "https://github.com/djd1m/dz-harness
|
|
40
|
+
"homepage": "https://github.com/djd1m/dz-harness/tree/main/packages/@dzhechkov/keysarium#readme",
|
|
41
41
|
"bugs": {
|
|
42
|
-
"url": "https://github.com/djd1m/dz-harness
|
|
42
|
+
"url": "https://github.com/djd1m/dz-harness/issues"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
45
|
"@dzhechkov/keysarium-core": "^1.1.0"
|
package/sbom.json
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"hashes": [
|
|
16
16
|
{
|
|
17
17
|
"alg": "SHA-256",
|
|
18
|
-
"content": "
|
|
18
|
+
"content": "e2f661392b2862870ae3ab05892493e5a7ddcdb86360690d126525f08b6d87a1"
|
|
19
19
|
}
|
|
20
20
|
]
|
|
21
21
|
},
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
},
|
|
50
50
|
{
|
|
51
51
|
"name": "dz:canonical-json-sha256-v2",
|
|
52
|
-
"value": "
|
|
52
|
+
"value": "56048c9ebf810b35645674fe4a413112af02be6a53836583d3c80b0ad4047dde"
|
|
53
53
|
}
|
|
54
54
|
]
|
|
55
55
|
},
|
|
@@ -1209,7 +1209,17 @@
|
|
|
1209
1209
|
"hashes": [
|
|
1210
1210
|
{
|
|
1211
1211
|
"alg": "SHA-256",
|
|
1212
|
-
"content": "
|
|
1212
|
+
"content": "cbe70a524f6ce7987b5e3961ee412b92c24c00d84066d438c759659d656efaa2"
|
|
1213
|
+
}
|
|
1214
|
+
]
|
|
1215
|
+
},
|
|
1216
|
+
{
|
|
1217
|
+
"type": "file",
|
|
1218
|
+
"name": "templates/.claude/skills/feature-adr/scripts/markdown-masker.mjs",
|
|
1219
|
+
"hashes": [
|
|
1220
|
+
{
|
|
1221
|
+
"alg": "SHA-256",
|
|
1222
|
+
"content": "82c3c48c25f400f3a64d1caba3d47357f3db87460f0746f88706f901eb6ff689"
|
|
1213
1223
|
}
|
|
1214
1224
|
]
|
|
1215
1225
|
},
|
|
@@ -1679,7 +1689,7 @@
|
|
|
1679
1689
|
"hashes": [
|
|
1680
1690
|
{
|
|
1681
1691
|
"alg": "SHA-256",
|
|
1682
|
-
"content": "
|
|
1692
|
+
"content": "d9dd399cbb60d6b5fa9734ad44128a49790ef15bbde25c809d69d5c918601eb3"
|
|
1683
1693
|
}
|
|
1684
1694
|
]
|
|
1685
1695
|
},
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
// the feature's own `00_complexity_assessment.md` acid-case table (rows shaped `| A<N> | … |`), or
|
|
52
52
|
// supplied explicitly with `--acid=T1,T2,…`. If neither establishes a corpus, C4 is SKIPPED-with-note
|
|
53
53
|
// (a feature that declared no acid cases cannot be failed for not naming them).
|
|
54
|
+
import { maskMarkdown } from './markdown-masker.mjs';
|
|
54
55
|
import { readFileSync, readdirSync, existsSync } from 'node:fs';
|
|
55
56
|
import { isAbsolute, join, resolve } from 'node:path';
|
|
56
57
|
|
|
@@ -180,7 +181,21 @@ if (adrFiles.length === 0 && TIER_REQUIRES_ADR) {
|
|
|
180
181
|
const adr = readFileSync(join(adrDir, f), 'utf-8');
|
|
181
182
|
const confIdx = adr.search(/^##+\s*Confirmation/mi);
|
|
182
183
|
if (confIdx < 0) { failures.push(`C2: ${safe(f)} has no Confirmation section`); continue; }
|
|
183
|
-
|
|
184
|
+
// The section ENDS at the next heading of the same or higher level — it does not run to EOF.
|
|
185
|
+
// Slicing to EOF swallowed every later section, so a `Links` entry citing an existing test as
|
|
186
|
+
// PRECEDENT was read as this ADR's own Confirmation and demanded of the plan (measured
|
|
187
|
+
// 2026-08-31 on features/finding-identity-closure: reqe.test.ts, cited under
|
|
188
|
+
// "Implementation precedent", failed C2 while the real Confirmation test was named correctly).
|
|
189
|
+
// Deeper subsections stay inside: a Confirmation with ### children is one section.
|
|
190
|
+
const rest = adr.slice(confIdx);
|
|
191
|
+
const confLevel = (rest.match(/^(#+)/) || ['', '##'])[1].length;
|
|
192
|
+
// Search AFTER the Confirmation heading's own line — searching from the heading itself matches
|
|
193
|
+
// it and collapses the section to nothing, which turns a scoping fix into a gate that reports
|
|
194
|
+
// "Confirmation names no test file paths" for every ADR (caught by running it).
|
|
195
|
+
const bodyStart = rest.indexOf('\n') + 1;
|
|
196
|
+
const afterHeading = rest.slice(bodyStart);
|
|
197
|
+
const nextHeading = afterHeading.search(new RegExp('^#{1,' + confLevel + '}[^#]', 'm'));
|
|
198
|
+
const conf = nextHeading < 0 ? rest : rest.slice(0, bodyStart + nextHeading);
|
|
184
199
|
const paths = extractCandidatePaths(conf).filter(isTestPath);
|
|
185
200
|
// UNKNOWN ECOSYSTEM STAYS A FAILURE, never a WARN: a gate that downgrades itself on the one
|
|
186
201
|
// repo it cannot read is a gate that is off exactly where it is needed. The remedy is named
|
|
@@ -305,21 +320,7 @@ else for (const t of acidTokens) if (!new RegExp(`\\b${t.replace(/[.*+?^${}()|[\
|
|
|
305
320
|
// `## Amendments` could become the section heading, and a fenced example row could either open a
|
|
306
321
|
// phantom amendment or hand a real testless one someone else's marker. Third fence-blindness
|
|
307
322
|
// found in a checker today, so it is closed here by construction rather than by care.
|
|
308
|
-
const
|
|
309
|
-
const planLines = [];
|
|
310
|
-
{
|
|
311
|
-
let fence = null;
|
|
312
|
-
for (const line of rawLines) {
|
|
313
|
-
const open = /^ {0,3}(```+|~~~+)/.exec(line);
|
|
314
|
-
if (fence === null && open) { fence = open[1][0]; planLines.push(''); continue; }
|
|
315
|
-
if (fence !== null) {
|
|
316
|
-
planLines.push('');
|
|
317
|
-
if (new RegExp('^ {0,3}' + fence + '{3,}\\s*$').test(line)) fence = null;
|
|
318
|
-
continue;
|
|
319
|
-
}
|
|
320
|
-
planLines.push(line);
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
+
const planLines = maskMarkdown(plan, { unclosed: 'mask' }).split('\n');
|
|
323
324
|
let sectionStart = -1, sectionEnd = -1, cursor = 0;
|
|
324
325
|
for (const pl of planLines) {
|
|
325
326
|
// The SAME heading shape amendment-trace.ts accepts: up to three leading spaces, two to four
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical Markdown block masker; copied byte-for-byte as markdown-masker.mjs beside K2.
|
|
3
|
+
* Keep this file valid JavaScript (inferred TS types, no build needed by the copy).
|
|
4
|
+
*
|
|
5
|
+
* CommonMark fences and type-2 HTML comments; same UTF-16 length and newline positions.
|
|
6
|
+
* Inline code cannot open an HTML block. HTML delimiters within a block are consumed left to
|
|
7
|
+
* right, including close/reopen on one line. This is not a complete CommonMark parser.
|
|
8
|
+
*
|
|
9
|
+
* Reader policies are deliberate: amendment-trace restores unclosed blocks; brief/K2 hide them.
|
|
10
|
+
* Four-space code is still unsupported by default. ONLY brief keeps its pre-existing policy.
|
|
11
|
+
* Containers, tab indentation and HTML block types other than comments remain unsupported.
|
|
12
|
+
* Callbacks expose line facts; callers own semantic diagnostics and list-barrier representation.
|
|
13
|
+
*/
|
|
14
|
+
export function maskMarkdown(md = '', {
|
|
15
|
+
unclosed = 'restore',
|
|
16
|
+
indentedCode = false,
|
|
17
|
+
inlineComments = false,
|
|
18
|
+
onMasked = (_line = 0) => {},
|
|
19
|
+
onDisputed = (_line = 0) => {},
|
|
20
|
+
} = {}) {
|
|
21
|
+
const lines = md.split('\n');
|
|
22
|
+
const out = lines.slice();
|
|
23
|
+
const masked = lines.map(() => false);
|
|
24
|
+
let state = 'text';
|
|
25
|
+
let marker = '';
|
|
26
|
+
let markerLength = 0;
|
|
27
|
+
let openedAt = -1;
|
|
28
|
+
let nestedOpener = false;
|
|
29
|
+
let disputed = false;
|
|
30
|
+
for (let i = 0; i < lines.length; i++) {
|
|
31
|
+
const line = lines[i] ?? '';
|
|
32
|
+
const blank = () => { out[i] = ' '.repeat(line.length); masked[i] = true; };
|
|
33
|
+
if (state === 'fence') {
|
|
34
|
+
blank();
|
|
35
|
+
const close = /^ {0,3}(`{3,}|~{3,})\s*$/.exec(line);
|
|
36
|
+
if (close) {
|
|
37
|
+
const run = close[1] ?? '';
|
|
38
|
+
if (run[0] === marker && run.length >= markerLength) {
|
|
39
|
+
state = 'text';
|
|
40
|
+
openedAt = -1;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (state === 'text') {
|
|
46
|
+
const fence = /^ {0,3}(`{3,}|~{3,})([^\n]*)$/.exec(line);
|
|
47
|
+
if (fence && !(fence[1]?.[0] === '`' && fence[2]?.includes('`'))) {
|
|
48
|
+
const run = fence[1] ?? '';
|
|
49
|
+
state = 'fence';
|
|
50
|
+
marker = run[0] ?? '';
|
|
51
|
+
markerLength = run.length;
|
|
52
|
+
openedAt = i;
|
|
53
|
+
blank();
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (indentedCode && /^ {4,}/.test(line)) {
|
|
57
|
+
blank();
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Outside HTML only a block opener counts: code-spanned delimiters in prose are inert.
|
|
62
|
+
// Inside HTML, backticks are literal and do not protect a delimiter.
|
|
63
|
+
const htmlStart = /^ {0,3}<!--/.test(line);
|
|
64
|
+
const wasDisputed = disputed;
|
|
65
|
+
// Ambiguity is diagnostic state, never permission to scan otherwise-visible prose.
|
|
66
|
+
// Brief deliberately keeps that diagnostic across blocks until the author's outer close;
|
|
67
|
+
// block-only readers must not hide an unrelated arrow or opener because it is pending.
|
|
68
|
+
if (state === 'html' || htmlStart || inlineComments) {
|
|
69
|
+
let maskLine = state === 'html' || htmlStart;
|
|
70
|
+
const tokens = [...line.matchAll(/`+|<!--|-->/g)];
|
|
71
|
+
for (let t = 0; t < tokens.length; t++) {
|
|
72
|
+
const token = tokens[t];
|
|
73
|
+
if (!token) continue;
|
|
74
|
+
if (token[0][0] === '`') {
|
|
75
|
+
// Code spans require an EXACT matching run; a shorter embedded run is literal.
|
|
76
|
+
// HTML blocks treat backticks literally. Inline-comment support is brief's existing
|
|
77
|
+
// policy; other readers only enter this scan at a block opener or while disputed.
|
|
78
|
+
if (state !== 'html') {
|
|
79
|
+
const end = tokens.findIndex((next, j) => j > t && next[0] === token[0]);
|
|
80
|
+
if (end >= 0) t = end;
|
|
81
|
+
}
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (token[0] === '<!--') {
|
|
85
|
+
if (state === 'html') nestedOpener = true;
|
|
86
|
+
else { state = 'html'; openedAt = i; }
|
|
87
|
+
maskLine = true;
|
|
88
|
+
} else if (state === 'html') {
|
|
89
|
+
state = 'text';
|
|
90
|
+
openedAt = -1;
|
|
91
|
+
if (nestedOpener) { disputed = true; nestedOpener = false; }
|
|
92
|
+
} else if (disputed) {
|
|
93
|
+
disputed = false;
|
|
94
|
+
maskLine = true;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (maskLine) blank();
|
|
98
|
+
}
|
|
99
|
+
if (wasDisputed || disputed) onDisputed(i);
|
|
100
|
+
}
|
|
101
|
+
if (openedAt >= 0 && unclosed === 'restore') {
|
|
102
|
+
for (let i = openedAt; i < lines.length; i++) {
|
|
103
|
+
out[i] = lines[i] ?? '';
|
|
104
|
+
masked[i] = false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
for (let i = 0; i < masked.length; i++) if (masked[i]) onMasked(i);
|
|
108
|
+
return out.join('\n');
|
|
109
|
+
}
|
|
@@ -144,7 +144,27 @@ const CJM_META = {
|
|
|
144
144
|
// Lock result (✅)
|
|
145
145
|
```
|
|
146
146
|
|
|
147
|
-
**Design
|
|
147
|
+
**Design: откуда берётся облик. Порядок приоритета, и он не симметричен.**
|
|
148
|
+
|
|
149
|
+
Прежде чем открывать таблицу ниже, ответьте на один вопрос: **воспроизводит ли проект НАЗВАННЫЙ
|
|
150
|
+
существующий продукт, и снят ли его облик?**
|
|
151
|
+
|
|
152
|
+
| Состояние источника | Откуда берётся палитра/типографика/тон |
|
|
153
|
+
|---|---|
|
|
154
|
+
| источник назван, облик **СНЯТ** | **из снятого облика источника** — таблица ниже НЕ применяется |
|
|
155
|
+
| источник назван, облик **НЕ ИЗМЕРЕН** (не удалось снять) | таблица ниже — как **ФОЛБЭК**, и он подписывается словом «фолбэк» вместе с причиной, по которой облик не сняли |
|
|
156
|
+
| **источника нет** (продукт не воспроизводится) | таблица ниже — как **ФОЛБЭК** по отрасли, и он тоже подписывается |
|
|
157
|
+
|
|
158
|
+
Почему это не две равноправные ветви. Отраслевая палитра — это догадка о том, как продукт мог бы
|
|
159
|
+
выглядеть. Когда есть живой источник, догадка не «одна из двух опций»: она хуже измерения ровно
|
|
160
|
+
настолько, насколько выдуманное отличается от наблюдённого. Прототип, который тихо подставил
|
|
161
|
+
Emerald, потому что проект про здоровье, читается точно так же, как прототип, у которого Emerald
|
|
162
|
+
измерен у источника — и именно эта неразличимость и есть дефект.
|
|
163
|
+
|
|
164
|
+
Подпись обязательна во всех состояниях, включая «источника нет»: неподписанная палитра и
|
|
165
|
+
подписанная выглядят одинаково для следующего читателя, а значат разное.
|
|
166
|
+
|
|
167
|
+
**Design адаптация под {INDUSTRY} — ФОЛБЭК, применяется только в двух нижних состояниях:**
|
|
148
168
|
|
|
149
169
|
| Industry | Палитра | Иконки | Тон |
|
|
150
170
|
|----------|---------|--------|-----|
|