@holmes-lab/holmes-kit 0.20.1 → 0.20.2
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/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,43 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
<!-- @implements A-SPEC-209 -->
|
|
8
|
+
## [0.20.2] - 2026-09-16
|
|
9
|
+
|
|
10
|
+
Two findings the Windows cycle recorded and could not close, closed — without giving autonomy or the
|
|
11
|
+
drift check one inch of slack.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
- **A sealed spec can now admit a root-level file** (A-SPEC-654). `Files to Touch` tokens had to contain
|
|
15
|
+
a slash, so a spec listing `- jest.config.js` produced no token at all and its own anchored write was
|
|
16
|
+
refused as "outside its Files to Touch scope" — measured 2026-09-15 on Windows, where A-SPEC-652.4 had
|
|
17
|
+
to be redesigned around it. A list item whose first word is a filename with an extension is now a token;
|
|
18
|
+
a filename mentioned inside prose, a version-like item (`- 0.20.1`) and a bare word still yield nothing,
|
|
19
|
+
and the enforcer still admits exactly that one path.
|
|
20
|
+
- **A CRLF checkout is no longer reported as skill drift.** Under `core.autocrlf=true`, git rewrote the
|
|
21
|
+
skill files the installer writes with LF, so `doctor` reported three untouched skills as `drifted` and
|
|
22
|
+
advised a refresh that produced LF for the next checkout to convert straight back (measured 2026-09-16,
|
|
23
|
+
Windows). `init`'s `.gitattributes` block now declares `.claude/skills/**/SKILL.md` and
|
|
24
|
+
`.agents/skills/**/SKILL.md` as `text eol=lf`, so checkout stops re-creating the difference. One
|
|
25
|
+
`holmes-kit skills refresh` converges an existing CRLF working tree.
|
|
26
|
+
|
|
27
|
+
### Unchanged on purpose
|
|
28
|
+
- **Autonomy did not widen with the new tokens.** Measured before the change: 36 A-SPECs in this
|
|
29
|
+
repository have prose-only Files to Touch and 8 of them would have gained tokens — one mentioning
|
|
30
|
+
`handlers.ts` in a sentence would have flipped from human approval to self-approval. The grader now
|
|
31
|
+
requires at least one directory-scoped token, so a spec whose tokens are all root-level files still asks
|
|
32
|
+
a human: a root-level file is project-wide configuration. A test walks every A-SPEC in the store and
|
|
33
|
+
asserts each verdict equals the pre-change verdict.
|
|
34
|
+
- **The drift comparison is still byte-exact.** Folding CRLF into it was implemented, measured against
|
|
35
|
+
A-SPEC-190 §9a — whitespace-touched files are `drifted` *and a refresh reclaims them* — and reverted:
|
|
36
|
+
it would have made the first of those three mutations invisible rather than recoverable. That refusal
|
|
37
|
+
is pinned in the new suite.
|
|
38
|
+
|
|
39
|
+
### Measured
|
|
40
|
+
- macOS: 503 suites / 6,461 passed / 11 skipped; official `test_run` green, last-green recorded.
|
|
41
|
+
- Still open: the Windows residual single-assertion reds. They need the failure text from the Windows box
|
|
42
|
+
(`npx jest --json`); nothing in this repository names why they fail, and guessing from a macOS run would
|
|
43
|
+
be inventing evidence.
|
|
44
|
+
|
|
8
45
|
## [0.20.1] - 2026-09-16
|
|
9
46
|
|
|
10
47
|
The Windows release. 0.20.0's external matrix was run natively on Windows 11 (Node 24, npm 12, pytest 9)
|
package/dist/.build-id
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
5796f530-mu3b082d
|
|
@@ -61,6 +61,16 @@ exports.ATTRIBUTE_LINES = [
|
|
|
61
61
|
'# 남는 체인 이음새는 `holmes-kit ledger rechain`의 일이다.',
|
|
62
62
|
'.ax/ledger/*.jsonl merge=union',
|
|
63
63
|
'.ax/approvals/queue.jsonl merge=union',
|
|
64
|
+
// @implements A-SPEC-654
|
|
65
|
+
// The installer writes these with LF and doctor compares them byte for byte (A-SPEC-190 §9a: a
|
|
66
|
+
// whitespace-touched file is `drifted` so a refresh can reclaim it). Under `core.autocrlf=true`
|
|
67
|
+
// checkout rewrote them to CRLF, so three untouched skills read `drifted` and the advised refresh
|
|
68
|
+
// produced LF for the next checkout to convert straight back — measured 2026-09-16 on Windows.
|
|
69
|
+
// Declaring the files settles it where the disagreement is, instead of teaching the drift check to
|
|
70
|
+
// ignore a difference it exists to catch.
|
|
71
|
+
'# @implements A-SPEC-654 — 설치기가 LF 로 쓰는 파일은 체크아웃에서 CRLF 로 바뀌지 않는다.',
|
|
72
|
+
'.claude/skills/**/SKILL.md text eol=lf',
|
|
73
|
+
'.agents/skills/**/SKILL.md text eol=lf',
|
|
64
74
|
];
|
|
65
75
|
/** As `mergeGitignore`, over `.gitattributes` — the same marker block machinery, so idempotence
|
|
66
76
|
* and user-content preservation are inherited rather than re-implemented. */
|
|
@@ -178,6 +178,12 @@ function specApprovalAutonomy(spec, resolveParent, descendants) {
|
|
|
178
178
|
return 'hitl';
|
|
179
179
|
if (paths.some(isHighRiskPath))
|
|
180
180
|
return 'hitl'; // gate/governance/taint file
|
|
181
|
+
// @implements A-SPEC-654 — a ROOT-level file is project-wide configuration (the test runner, the
|
|
182
|
+
// manifest, the ignore policy): admitting it at the gate was the point of that slice, but grading
|
|
183
|
+
// it auto would be a widening nobody asked for. A spec earns self-approval only when it also names
|
|
184
|
+
// a directory-scoped surface — the same doubt `paths.length === 0` already encodes.
|
|
185
|
+
if (!paths.some((p) => p.includes('/')))
|
|
186
|
+
return 'hitl';
|
|
181
187
|
return 'auto';
|
|
182
188
|
}
|
|
183
189
|
default:
|
|
@@ -29,7 +29,18 @@ export declare function isTestPath(relPath: string): boolean;
|
|
|
29
29
|
* one bounded fragment, so no ReDoS surface.
|
|
30
30
|
*/
|
|
31
31
|
export declare function matchesFtt(token: string, relPath: string): boolean;
|
|
32
|
-
|
|
32
|
+
export declare function isRootFileToken(token: string): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Concrete path-like tokens of a Files-to-Touch section (globs included) — prose yields none.
|
|
35
|
+
*
|
|
36
|
+
* @implements A-SPEC-654
|
|
37
|
+
* The slashed match alone could not see a ROOT-level file, so a sealed spec listing `- jest.config.js`
|
|
38
|
+
* admitted nothing at all and its own anchored write was refused as out of scope (measured 2026-09-15 on
|
|
39
|
+
* Windows; A-SPEC-652.4 was redesigned around it). A bare filename counts only as a LIST ITEM's first
|
|
40
|
+
* word: `- \`tsconfig.test.json\` (신규)` is a token, while `\`cfg.ts\`, \`ddg.ts\` 를 고친다` — prose, and a
|
|
41
|
+
* word carrying a comma — stays what it always was, nothing. The enforcer is unchanged: a root token
|
|
42
|
+
* admits that exact path (`matchesFtt`), and the grader requires a directory-scoped token of its own.
|
|
43
|
+
*/
|
|
33
44
|
export declare function fttPathTokens(fttText: string): string[];
|
|
34
45
|
export interface ScopeInput {
|
|
35
46
|
relPath: string;
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.isTestPath = isTestPath;
|
|
27
27
|
exports.matchesFtt = matchesFtt;
|
|
28
|
+
exports.isRootFileToken = isRootFileToken;
|
|
28
29
|
exports.fttPathTokens = fttPathTokens;
|
|
29
30
|
exports.judgeScope = judgeScope;
|
|
30
31
|
/** Repo test conventions — the single census every dispensation consumer shares. */
|
|
@@ -63,9 +64,37 @@ function matchesFtt(token, relPath) {
|
|
|
63
64
|
return relPath === tok; // file literal: that file only
|
|
64
65
|
return relPath === tok || relPath.startsWith(tok + '/'); // dir literal: its subtree
|
|
65
66
|
}
|
|
66
|
-
/**
|
|
67
|
+
/**
|
|
68
|
+
* @implements A-SPEC-654
|
|
69
|
+
* A repository-ROOT file named as a Files-to-Touch item: a bare filename with an extension that starts
|
|
70
|
+
* with a letter, so a version (`0.20.1`) is not a file and a bare word (`README`) is not either.
|
|
71
|
+
*/
|
|
72
|
+
const ROOT_FILE = /^[\w@.-]+\.[A-Za-z][A-Za-z0-9]*$/;
|
|
73
|
+
function isRootFileToken(token) {
|
|
74
|
+
return !token.includes('/') && ROOT_FILE.test(token);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Concrete path-like tokens of a Files-to-Touch section (globs included) — prose yields none.
|
|
78
|
+
*
|
|
79
|
+
* @implements A-SPEC-654
|
|
80
|
+
* The slashed match alone could not see a ROOT-level file, so a sealed spec listing `- jest.config.js`
|
|
81
|
+
* admitted nothing at all and its own anchored write was refused as out of scope (measured 2026-09-15 on
|
|
82
|
+
* Windows; A-SPEC-652.4 was redesigned around it). A bare filename counts only as a LIST ITEM's first
|
|
83
|
+
* word: `- \`tsconfig.test.json\` (신규)` is a token, while `\`cfg.ts\`, \`ddg.ts\` 를 고친다` — prose, and a
|
|
84
|
+
* word carrying a comma — stays what it always was, nothing. The enforcer is unchanged: a root token
|
|
85
|
+
* admits that exact path (`matchesFtt`), and the grader requires a directory-scoped token of its own.
|
|
86
|
+
*/
|
|
67
87
|
function fttPathTokens(fttText) {
|
|
68
|
-
|
|
88
|
+
const tokens = [...(fttText.match(/[\w@.*-]+(?:\/[\w@.*-]+)+/g) ?? [])];
|
|
89
|
+
for (const line of fttText.split('\n')) {
|
|
90
|
+
const item = /^\s*[-*]\s+(.*)$/.exec(line);
|
|
91
|
+
if (!item)
|
|
92
|
+
continue;
|
|
93
|
+
const word = (item[1].trim().split(/\s+/)[0] ?? '').replace(/^[`'"]+|[`'"]+$/g, '');
|
|
94
|
+
if (isRootFileToken(word) && !tokens.includes(word))
|
|
95
|
+
tokens.push(word);
|
|
96
|
+
}
|
|
97
|
+
return tokens;
|
|
69
98
|
}
|
|
70
99
|
// @implements A-SPEC-508.1
|
|
71
100
|
function judgeScope(input) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"//": "@implements A-SPEC-209",
|
|
3
3
|
"name": "@holmes-lab/holmes-kit",
|
|
4
|
-
"version": "0.20.
|
|
4
|
+
"version": "0.20.2",
|
|
5
5
|
"description": "Holmes-Kit — deterministic Agentic Software Engineering (ASE) harness with causal traceability (spec chain + D-CPG + RTM + phase guardrail)",
|
|
6
6
|
"main": "dist/holmes/mcp/server.js",
|
|
7
7
|
"types": "dist/holmes/mcp/server.d.ts",
|