hypomnema 1.3.3 → 1.3.4
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.ko.md +1 -1
- package/README.md +1 -1
- package/package.json +1 -1
- package/scripts/crystallize.mjs +2 -2
- package/scripts/doctor.mjs +2 -2
- package/scripts/graph.mjs +2 -2
- package/scripts/init.mjs +31 -2
- package/scripts/lib/hypo-ignore.mjs +24 -0
- package/scripts/lint.mjs +7 -6
- package/scripts/query.mjs +2 -2
- package/scripts/rename.mjs +2 -2
- package/scripts/stats.mjs +2 -2
- package/scripts/verify.mjs +2 -2
- package/templates/hypo-config.md +1 -1
package/README.ko.md
CHANGED
|
@@ -250,7 +250,7 @@ v1.0에서는 `personal / shared / public` 3-mode를 만들었습니다. 현실
|
|
|
250
250
|
|
|
251
251
|
이와 별도로 `SessionStart` 훅은 npm 레지스트리와 Claude Code 플러그인 마켓플레이스를 백그라운드에서 확인합니다(세션 시작을 막지 않습니다). 새 버전이 게시되어 있으면 다음 세션 시작 시 "Update available!" 안내가 한 줄 표시됩니다. `HYPO_NO_UPDATE_CHECK=1`, `NO_UPDATE_NOTIFIER=1`을 지정하거나 `CI=true` 환경에서 실행하면 점검을 건너뜁니다.
|
|
252
252
|
|
|
253
|
-
위 네 가지 레인 외의 v1.3 세부 수정
|
|
253
|
+
위 네 가지 레인 외의 v1.3 세부 수정(세션 마무리 lint를 건드린 파일로 스코프해 무관한 debt로 `/compact`가 막히지 않게 한 변경, `feedback` scope 검증기가 cwd 유래 project id를 수용하게 한 수정, `--strict`가 에러로 승격하는 안정적 lint 경고 ID `W1`/`W2`/`W4`이며 `--fix`로 자동복구되는 `W3`는 경고로 유지)은 [`CHANGELOG.md`](CHANGELOG.md)를 참고하세요. **v1.3.1**은 수정 전용 패치입니다: 업데이트 notifier 배너가 이제 보이지 않던 stderr 출력 대신 top-level `systemMessage` 채널로 실제 사용자에게 도달하고, `/hypo:upgrade`가 플러그인·dual(수동+플러그인) 설치에서 core 훅을 중복 등록하지 않으며, 세션 마무리가 두 프로젝트가 같은 최신 날짜를 가질 때 완료된 close를 false-block 하지 않습니다. **v1.3.2**는 비-프로젝트(툴링·위키 전용) 세션을 무관한 프로젝트에 엮지 않고 닫는 1급 log-only close 경로와, 페이지 이름을 바꿀 때 해당하는 인바운드 위키링크를 갱신하는 `rename` 헬퍼를 추가합니다(모호하거나 append-only인 참조는 갱신하지 않고 보고합니다). 또한 세션 마무리 게이트(오늘 활동한 모든 프로젝트를 게이트, 세션별 마커와 `/compact`가 하나의 게이트를 공유, 도출 가능한 루트 `log.md` 항목 자동 도출)와 linter(`--json`이 파이프에서 잘리지 않음, 볼트 관습 위키링크를 오탐 대신 정상 해석)를 수정합니다. **v1.3.3**은 세션 마무리 게이트를 실수 발동에 대해 단단히 합니다: 모델이 실제 사용자 종료 신호 없이 세션을 닫을 수 없고, 종료 관련 텍스트를 읽는 것이 턴을 false-block하지 않으며, `--apply-session-close`가 사용자 종료 신호가 있는 close에서 payload 커밋과 마커 기록을 한 번에 끝내고, 일상적 트래커 bookkeeping이 무관한 프로젝트의 `/compact`를 cross-block하지 않습니다. 또한 `rename`을 디렉터리 서브트리 전체 이동으로 확장합니다(`/hypo:rename` 커맨드와 대상 경로가 이미 있을 때의 merge/renumber 충돌 리포트 포함). **v1.3.4**는 위키 위생 수정 전용 패치입니다: `init`이 손수 쓴 알려진 등가본 옆에 중복 stock 페이지를 떨구지 않고(`wiki-automation.md`나 `wiki-help.md`가 보이면 그 페이지를 유지하고 stock `hypo-*`를 건너뛰며 머지 경고를 크게 냅니다), 볼트 루트의 재생성 가능한 리포트 산출물(업그레이드 `MIGRATION-v*.md` 리포트, 예약된 `GRAPH_REPORT.md` 이름 포함)을 정상 커밋되게 두면서 카탈로그 스캔에서 제외합니다.
|
|
254
254
|
|
|
255
255
|
### 셋업 & 유지보수
|
|
256
256
|
|
package/README.md
CHANGED
|
@@ -250,7 +250,7 @@ All hooks resolve the wiki root via `HYPO_DIR` env → `hypo-config.md` scan →
|
|
|
250
250
|
|
|
251
251
|
Additionally, the `SessionStart` hook performs a non-blocking background check against npm and the Claude Code plugin marketplace and prints an "Update available!" banner the next time a newer Hypomnema version has been published. Opt out with `HYPO_NO_UPDATE_CHECK=1`, `NO_UPDATE_NOTIFIER=1`, or by running under `CI=true`.
|
|
252
252
|
|
|
253
|
-
For fix-level v1.3 detail beyond the lanes above
|
|
253
|
+
For fix-level v1.3 detail beyond the lanes above (session-close lint scoped to touched files so `/compact` is no longer blocked by unrelated debt, the `feedback` scope validator accepting cwd-derived project ids, and the stable lint warning IDs `W1`/`W2`/`W4` that `--strict` promotes to errors while `W3`, auto-repaired by `--fix`, stays a warning), see [`CHANGELOG.md`](CHANGELOG.md). **v1.3.1** is a fixes-only patch: update-notifier banners now actually reach the user via the top-level `systemMessage` channel instead of an invisible stderr write, `/hypo:upgrade` no longer double-registers core hooks for plugin or dual (manual + plugin) installs, and session-close no longer false-blocks a completed close when two projects share the latest date. **v1.3.2** adds a first-class log-only session-close path, so a non-project (tooling or wiki-only) session closes cleanly without being forced onto an unrelated project, plus a `rename` helper that rewrites the eligible inbound wikilinks when you rename a page (ambiguous or append-only references are reported, not rewritten). It also tightens the session-close gate (every project with activity today is gated, the per-session marker and `/compact` share one gate, and the derivable root `log.md` entry auto-derives) and the linter (`--json` no longer truncates on a pipe, and vault-convention wikilinks resolve instead of being false-flagged). **v1.3.3** hardens the session-close gate against accidental triggers: the model can no longer mark a session closed without a real user close signal, reading close-related text no longer false-blocks the turn, `--apply-session-close` commits its payload and writes the marker in one step on a close that carries a user close signal, and routine tracker bookkeeping no longer cross-blocks an unrelated project's `/compact`. It also extends `rename` to move a whole directory subtree (with a `/hypo:rename` command and a merge/renumber collision report when a destination already exists). **v1.3.4** is a fixes-only patch for wiki hygiene: `init` no longer drops a duplicate stock page next to a known hand-authored equivalent (when it sees `wiki-automation.md` or `wiki-help.md` it keeps that page and skips the stock `hypo-*` one, with a loud merge notice), and regenerable report output at the vault root (the upgrade `MIGRATION-v*.md` report, plus the reserved `GRAPH_REPORT.md` name) is excluded from the catalog scans while staying fully committable.
|
|
254
254
|
|
|
255
255
|
### Setup & maintenance
|
|
256
256
|
|
package/package.json
CHANGED
package/scripts/crystallize.mjs
CHANGED
|
@@ -73,7 +73,7 @@ import { join, relative, extname, dirname } from 'path';
|
|
|
73
73
|
import { spawnSync } from 'child_process';
|
|
74
74
|
import { fileURLToPath } from 'url';
|
|
75
75
|
import { resolveHypoRoot, expandHome } from './lib/hypo-root.mjs';
|
|
76
|
-
import { loadHypoIgnore,
|
|
76
|
+
import { loadHypoIgnore, isScanIgnored } from './lib/hypo-ignore.mjs';
|
|
77
77
|
import {
|
|
78
78
|
sessionCloseFileStatus,
|
|
79
79
|
sessionCloseGlobalStatus,
|
|
@@ -949,7 +949,7 @@ function collectPages(dir, root, acc = [], ignorePatterns = []) {
|
|
|
949
949
|
for (const entry of readdirSync(dir)) {
|
|
950
950
|
if (entry.startsWith('.')) continue;
|
|
951
951
|
const full = join(dir, entry);
|
|
952
|
-
if (
|
|
952
|
+
if (isScanIgnored(full, root, ignorePatterns)) continue;
|
|
953
953
|
const st = statSync(full);
|
|
954
954
|
if (st.isDirectory()) collectPages(full, root, acc, ignorePatterns);
|
|
955
955
|
else if (extname(entry) === '.md') {
|
package/scripts/doctor.mjs
CHANGED
|
@@ -18,7 +18,7 @@ import { homedir } from 'os';
|
|
|
18
18
|
import { spawnSync } from 'child_process';
|
|
19
19
|
import { fileURLToPath } from 'url';
|
|
20
20
|
import { resolveHypoRoot, expandHome } from './lib/hypo-root.mjs';
|
|
21
|
-
import { loadHypoIgnore,
|
|
21
|
+
import { loadHypoIgnore, isScanIgnored } from './lib/hypo-ignore.mjs';
|
|
22
22
|
import { parseFrontmatter } from './lib/frontmatter.mjs';
|
|
23
23
|
import { readSyncState, projectSuggestionsPath } from '../hooks/hypo-shared.mjs';
|
|
24
24
|
import {
|
|
@@ -443,7 +443,7 @@ function collectMdFiles(dir, acc = [], hypoDir = '', ignorePatterns = []) {
|
|
|
443
443
|
for (const entry of readdirSync(dir)) {
|
|
444
444
|
if (entry.startsWith('.')) continue;
|
|
445
445
|
const full = join(dir, entry);
|
|
446
|
-
if (hypoDir &&
|
|
446
|
+
if (hypoDir && isScanIgnored(full, hypoDir, ignorePatterns)) continue;
|
|
447
447
|
const st = statSync(full);
|
|
448
448
|
if (st.isDirectory()) collectMdFiles(full, acc, hypoDir, ignorePatterns);
|
|
449
449
|
else if (extname(entry) === '.md') acc.push(full);
|
package/scripts/graph.mjs
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
import { existsSync, readFileSync, readdirSync, statSync } from 'fs';
|
|
18
18
|
import { join, relative, extname, basename } from 'path';
|
|
19
19
|
import { resolveHypoRoot, expandHome } from './lib/hypo-root.mjs';
|
|
20
|
-
import { loadHypoIgnore,
|
|
20
|
+
import { loadHypoIgnore, isScanIgnored } from './lib/hypo-ignore.mjs';
|
|
21
21
|
|
|
22
22
|
// ── arg parsing ───────────────────────────────────────────────────────────────
|
|
23
23
|
|
|
@@ -38,7 +38,7 @@ function collectPages(dir, root, pages = [], ignorePatterns = []) {
|
|
|
38
38
|
if (!existsSync(dir)) return pages;
|
|
39
39
|
for (const entry of readdirSync(dir)) {
|
|
40
40
|
const full = join(dir, entry);
|
|
41
|
-
if (
|
|
41
|
+
if (isScanIgnored(full, root, ignorePatterns)) continue;
|
|
42
42
|
const st = statSync(full);
|
|
43
43
|
if (st.isDirectory()) {
|
|
44
44
|
collectPages(full, root, pages, ignorePatterns);
|
package/scripts/init.mjs
CHANGED
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
renameSync,
|
|
33
33
|
unlinkSync,
|
|
34
34
|
} from 'fs';
|
|
35
|
-
import { join, basename } from 'path';
|
|
35
|
+
import { join, basename, dirname } from 'path';
|
|
36
36
|
import { homedir } from 'os';
|
|
37
37
|
import { execSync, spawnSync } from 'child_process';
|
|
38
38
|
import { fileURLToPath } from 'url';
|
|
@@ -171,7 +171,19 @@ docstring at the top of scripts/<command>.mjs.`);
|
|
|
171
171
|
|
|
172
172
|
// ── result tracking ──────────────────────────────────────────────────────────
|
|
173
173
|
|
|
174
|
-
const results = { created: [], skipped: [], merged: [], errors: [] };
|
|
174
|
+
const results = { created: [], skipped: [], merged: [], deduped: [], errors: [] };
|
|
175
|
+
|
|
176
|
+
// Stock template basename → legacy hand-authored equivalents to honor instead of
|
|
177
|
+
// injecting a duplicate. The hypo-/wiki- namespace split (the rename that
|
|
178
|
+
// produced hypo-guide from wiki-guide, etc.) means an exact-filename check misses
|
|
179
|
+
// a user's existing page and drops a 0-reference duplicate orphan beside it.
|
|
180
|
+
// Mirrors the explicit HOOK_RENAMES idiom in upgrade.mjs. hypo-guide.md is
|
|
181
|
+
// intentionally absent: the runtime reads it by name, so a mid-migration vault
|
|
182
|
+
// must still receive it even when wiki-guide.md is present.
|
|
183
|
+
const PAGE_EQUIVALENTS = {
|
|
184
|
+
'hypo-automation.md': ['wiki-automation.md'],
|
|
185
|
+
'hypo-help.md': ['wiki-help.md'],
|
|
186
|
+
};
|
|
175
187
|
|
|
176
188
|
function log(action, path) {
|
|
177
189
|
results[action].push(path);
|
|
@@ -213,6 +225,19 @@ function copyTemplate(srcName, destPath, dryRun, transform) {
|
|
|
213
225
|
log('skipped', destPath);
|
|
214
226
|
return;
|
|
215
227
|
}
|
|
228
|
+
// If a legacy hand-authored equivalent already exists, do NOT inject the stock
|
|
229
|
+
// page — that is exactly what produced a duplicate orphan. Skip LOUDLY (own
|
|
230
|
+
// bucket, ⚠ in the summary) so the user can merge manually. Fires in --dry-run
|
|
231
|
+
// too, so a dry run previews the suppression.
|
|
232
|
+
const equivalents = PAGE_EQUIVALENTS[basename(srcName)] || [];
|
|
233
|
+
const existingEquivalent = equivalents.find((name) => existsSync(join(dirname(destPath), name)));
|
|
234
|
+
if (existingEquivalent) {
|
|
235
|
+
log(
|
|
236
|
+
'deduped',
|
|
237
|
+
`${destPath} — kept existing ${existingEquivalent}; stock ${basename(srcName)} not installed (merge manually if you want the template content)`,
|
|
238
|
+
);
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
216
241
|
if (!dryRun) {
|
|
217
242
|
let content = readFileSync(src, 'utf-8');
|
|
218
243
|
content = content.replace(/YYYY-MM-DD/g, new Date().toISOString().slice(0, 10));
|
|
@@ -1017,6 +1042,10 @@ if (results.skipped.length)
|
|
|
1017
1042
|
);
|
|
1018
1043
|
if (results.merged.length)
|
|
1019
1044
|
lines.push(`↪ Merged into settings.json:\n${results.merged.map((p) => ` ${p}`).join('\n')}`);
|
|
1045
|
+
if (results.deduped.length)
|
|
1046
|
+
lines.push(
|
|
1047
|
+
`⚠ Skipped to avoid a duplicate — an equivalent page already exists (${results.deduped.length}):\n${results.deduped.map((p) => ` ${p}`).join('\n')}`,
|
|
1048
|
+
);
|
|
1020
1049
|
if (results.errors.length)
|
|
1021
1050
|
lines.push(`✗ Errors:\n${results.errors.map((p) => ` ${p}`).join('\n')}`);
|
|
1022
1051
|
|
|
@@ -23,6 +23,30 @@ function globToRegex(glob) {
|
|
|
23
23
|
);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
// Generated, regenerable tool artifacts that live at the WIKI ROOT and must not
|
|
27
|
+
// pollute the knowledge catalog. These are intentionally NOT added to
|
|
28
|
+
// .hypoignore: that list also drives the pre-commit secret gate
|
|
29
|
+
// (hooks/hypo-pre-commit.mjs), so listing them there would block the report's
|
|
30
|
+
// commit and freeze every auto-commit while it sits at root. Instead they are
|
|
31
|
+
// excluded from catalog/scan only, via isScanIgnored(). The patterns are
|
|
32
|
+
// anchored to the root-relative path (no '/'), so an equivalent name nested
|
|
33
|
+
// under pages/, projects/, or sources/ is left untouched.
|
|
34
|
+
const GENERATED_ARTIFACT_RES = [/^MIGRATION-v[^/]*\.md$/, /^GRAPH_REPORT\.md$/];
|
|
35
|
+
|
|
36
|
+
export function isGeneratedArtifact(filePath, hypoDir) {
|
|
37
|
+
const rel = relative(hypoDir, filePath).replace(/\\/g, '/');
|
|
38
|
+
return GENERATED_ARTIFACT_RES.some((re) => re.test(rel));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Catalog/scan exclusion = privacy/.hypoignore patterns PLUS generated root
|
|
42
|
+
// artifacts. Use this in tools that build the knowledge catalog (lint, graph,
|
|
43
|
+
// stats, query, verify, crystallize, rename, doctor broken-links). Do NOT use it
|
|
44
|
+
// in the pre-commit gate or ingest --check, which are privacy boundaries that
|
|
45
|
+
// must stay on isIgnored()/.hypoignore alone.
|
|
46
|
+
export function isScanIgnored(filePath, hypoDir, patterns) {
|
|
47
|
+
return isIgnored(filePath, hypoDir, patterns) || isGeneratedArtifact(filePath, hypoDir);
|
|
48
|
+
}
|
|
49
|
+
|
|
26
50
|
export function isIgnored(filePath, hypoDir, patterns) {
|
|
27
51
|
const rel = relative(hypoDir, filePath).replace(/\\/g, '/');
|
|
28
52
|
const base = basename(filePath);
|
package/scripts/lint.mjs
CHANGED
|
@@ -20,7 +20,7 @@ import { existsSync, readFileSync, writeFileSync, readdirSync, statSync } from '
|
|
|
20
20
|
import { join, relative, extname, basename } from 'path';
|
|
21
21
|
import { resolveHypoRoot, expandHome } from './lib/hypo-root.mjs';
|
|
22
22
|
import { SESSION_STATE_NEXT_HEADINGS } from '../hooks/hypo-shared.mjs';
|
|
23
|
-
import { loadHypoIgnore,
|
|
23
|
+
import { loadHypoIgnore, isScanIgnored } from './lib/hypo-ignore.mjs';
|
|
24
24
|
import { parseSchemaVocab, checkForbidden, parseSchemaPageDirs } from './lib/schema-vocab.mjs';
|
|
25
25
|
import { findDesignHistoryStale } from './lib/design-history-stale.mjs';
|
|
26
26
|
import { FEEDBACK_SCOPE_RE } from './lib/feedback-scope.mjs';
|
|
@@ -117,7 +117,7 @@ function collectPages(dir, root, pages = [], ignorePatterns = []) {
|
|
|
117
117
|
if (!existsSync(dir)) return pages;
|
|
118
118
|
for (const entry of readdirSync(dir)) {
|
|
119
119
|
const full = join(dir, entry);
|
|
120
|
-
if (
|
|
120
|
+
if (isScanIgnored(full, root, ignorePatterns)) continue;
|
|
121
121
|
const st = statSync(full);
|
|
122
122
|
if (st.isDirectory()) {
|
|
123
123
|
// `_`-prefixed dirs (e.g. pages/feedback/_drafts) hold scaffolds / scratch
|
|
@@ -164,13 +164,14 @@ function collectLinkTargets(hypoDir, ignorePatterns = []) {
|
|
|
164
164
|
if (existsSync(hypoDir)) {
|
|
165
165
|
for (const entry of readdirSync(hypoDir)) {
|
|
166
166
|
const full = join(hypoDir, entry);
|
|
167
|
-
// root-level *.md FILES only (no recursion), honoring .hypoignore
|
|
168
|
-
//
|
|
169
|
-
//
|
|
167
|
+
// root-level *.md FILES only (no recursion), honoring .hypoignore plus the
|
|
168
|
+
// scan-only generated-artifact exclusions (isScanIgnored) like collectPages
|
|
169
|
+
// — otherwise an ignored root file (e.g. a secret) or a regenerable report
|
|
170
|
+
// would resolve [[its-slug]] as valid, a false negative.
|
|
170
171
|
if (
|
|
171
172
|
extname(entry) === '.md' &&
|
|
172
173
|
!entry.startsWith('.') &&
|
|
173
|
-
!
|
|
174
|
+
!isScanIgnored(full, hypoDir, ignorePatterns) &&
|
|
174
175
|
statSync(full).isFile()
|
|
175
176
|
) {
|
|
176
177
|
targets.push(entry.replace(/\.md$/, ''));
|
package/scripts/query.mjs
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
import { existsSync, readFileSync, readdirSync, statSync } from 'fs';
|
|
20
20
|
import { join, relative, extname } from 'path';
|
|
21
21
|
import { resolveHypoRoot, expandHome } from './lib/hypo-root.mjs';
|
|
22
|
-
import { loadHypoIgnore,
|
|
22
|
+
import { loadHypoIgnore, isScanIgnored } from './lib/hypo-ignore.mjs';
|
|
23
23
|
|
|
24
24
|
// ── arg parsing ──────────────────────────────────────────────────────────────
|
|
25
25
|
|
|
@@ -42,7 +42,7 @@ function collectMdFiles(dir, root, acc = [], ignorePatterns = []) {
|
|
|
42
42
|
for (const entry of readdirSync(dir)) {
|
|
43
43
|
if (entry.startsWith('.')) continue;
|
|
44
44
|
const full = join(dir, entry);
|
|
45
|
-
if (
|
|
45
|
+
if (isScanIgnored(full, root, ignorePatterns)) continue;
|
|
46
46
|
const st = statSync(full);
|
|
47
47
|
if (st.isDirectory()) collectMdFiles(full, root, acc, ignorePatterns);
|
|
48
48
|
else if (extname(entry) === '.md') acc.push({ path: full, rel: relative(root, full) });
|
package/scripts/rename.mjs
CHANGED
|
@@ -49,7 +49,7 @@ import {
|
|
|
49
49
|
} from 'fs';
|
|
50
50
|
import { join, relative, extname, basename, dirname, normalize, isAbsolute, sep } from 'path';
|
|
51
51
|
import { resolveHypoRoot, expandHome } from './lib/hypo-root.mjs';
|
|
52
|
-
import { loadHypoIgnore,
|
|
52
|
+
import { loadHypoIgnore, isScanIgnored } from './lib/hypo-ignore.mjs';
|
|
53
53
|
|
|
54
54
|
// ── arg parsing ───────────────────────────────────────────────────────────────
|
|
55
55
|
|
|
@@ -72,7 +72,7 @@ function collectPages(dir, root, pages = [], ignorePatterns = []) {
|
|
|
72
72
|
if (!existsSync(dir)) return pages;
|
|
73
73
|
for (const entry of readdirSync(dir)) {
|
|
74
74
|
const full = join(dir, entry);
|
|
75
|
-
if (
|
|
75
|
+
if (isScanIgnored(full, root, ignorePatterns)) continue;
|
|
76
76
|
// lstat (never follow): a symlinked dir or file is skipped entirely so the
|
|
77
77
|
// whole-vault scan can never traverse out of the vault via a symlink.
|
|
78
78
|
const st = lstatSync(full);
|
package/scripts/stats.mjs
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
import { existsSync, readFileSync, readdirSync, statSync } from 'fs';
|
|
17
17
|
import { join, extname } from 'path';
|
|
18
18
|
import { resolveHypoRoot, expandHome } from './lib/hypo-root.mjs';
|
|
19
|
-
import { loadHypoIgnore, isIgnored } from './lib/hypo-ignore.mjs';
|
|
19
|
+
import { loadHypoIgnore, isIgnored, isScanIgnored } from './lib/hypo-ignore.mjs';
|
|
20
20
|
|
|
21
21
|
// ── arg parsing ──────────────────────────────────────────────────────────────
|
|
22
22
|
|
|
@@ -37,7 +37,7 @@ function collectMdFiles(dir, acc = [], hypoDir = '', ignorePatterns = []) {
|
|
|
37
37
|
for (const entry of readdirSync(dir)) {
|
|
38
38
|
if (entry.startsWith('.')) continue;
|
|
39
39
|
const full = join(dir, entry);
|
|
40
|
-
if (hypoDir &&
|
|
40
|
+
if (hypoDir && isScanIgnored(full, hypoDir, ignorePatterns)) continue;
|
|
41
41
|
const st = statSync(full);
|
|
42
42
|
if (st.isDirectory()) collectMdFiles(full, acc, hypoDir, ignorePatterns);
|
|
43
43
|
else if (extname(entry) === '.md') acc.push(full);
|
package/scripts/verify.mjs
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
import { existsSync, readFileSync, readdirSync, statSync } from 'fs';
|
|
19
19
|
import { join, relative, extname } from 'path';
|
|
20
20
|
import { resolveHypoRoot, expandHome } from './lib/hypo-root.mjs';
|
|
21
|
-
import { loadHypoIgnore,
|
|
21
|
+
import { loadHypoIgnore, isScanIgnored } from './lib/hypo-ignore.mjs';
|
|
22
22
|
|
|
23
23
|
// ── arg parsing ──────────────────────────────────────────────────────────────
|
|
24
24
|
|
|
@@ -40,7 +40,7 @@ function collectMdFiles(dir, acc = [], hypoDir = '', ignorePatterns = []) {
|
|
|
40
40
|
for (const entry of readdirSync(dir)) {
|
|
41
41
|
if (entry.startsWith('.')) continue;
|
|
42
42
|
const full = join(dir, entry);
|
|
43
|
-
if (hypoDir &&
|
|
43
|
+
if (hypoDir && isScanIgnored(full, hypoDir, ignorePatterns)) continue;
|
|
44
44
|
const st = statSync(full);
|
|
45
45
|
if (st.isDirectory()) collectMdFiles(full, acc, hypoDir, ignorePatterns);
|
|
46
46
|
else if (extname(entry) === '.md') acc.push(full);
|