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.
@@ -11,7 +11,7 @@
11
11
  "name": "hypo",
12
12
  "source": "./",
13
13
  "description": "LLM-native personal wiki — session-aware knowledge base for Claude Code",
14
- "version": "1.3.3",
14
+ "version": "1.3.4",
15
15
  "homepage": "https://github.com/sk-lim19f/Hypomnema"
16
16
  }
17
17
  ]
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hypo",
3
- "version": "1.3.3",
3
+ "version": "1.3.4",
4
4
  "description": "LLM-native personal wiki system — session-aware knowledge base for Claude Code",
5
5
  "author": {
6
6
  "name": "sk-lim19f",
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 세부 수정세션 마무리 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 충돌 리포트 포함).
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 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).
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hypomnema",
3
- "version": "1.3.3",
3
+ "version": "1.3.4",
4
4
  "description": "LLM-native personal wiki system for Claude Code",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -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, isIgnored } from './lib/hypo-ignore.mjs';
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 (isIgnored(full, root, ignorePatterns)) continue;
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') {
@@ -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, isIgnored } from './lib/hypo-ignore.mjs';
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 && isIgnored(full, hypoDir, ignorePatterns)) continue;
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, isIgnored } from './lib/hypo-ignore.mjs';
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 (isIgnored(full, root, ignorePatterns)) continue;
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, isIgnored } from './lib/hypo-ignore.mjs';
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 (isIgnored(full, root, ignorePatterns)) continue;
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 exactly
168
- // like collectPages otherwise an ignored root file (e.g. a secret) would
169
- // resolve [[its-slug]] as valid, a false negative.
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
- !isIgnored(full, hypoDir, ignorePatterns) &&
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, isIgnored } from './lib/hypo-ignore.mjs';
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 (isIgnored(full, root, ignorePatterns)) continue;
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) });
@@ -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, isIgnored } from './lib/hypo-ignore.mjs';
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 (isIgnored(full, root, ignorePatterns)) continue;
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 && isIgnored(full, hypoDir, ignorePatterns)) continue;
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);
@@ -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, isIgnored } from './lib/hypo-ignore.mjs';
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 && isIgnored(full, hypoDir, ignorePatterns)) continue;
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);
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  title: Hypomnema Config
3
3
  type: config
4
- version: "1.3.3"
4
+ version: "1.3.4"
5
5
  created: YYYY-MM-DD
6
6
  ---
7
7