hypomnema 1.8.1 → 1.8.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/CHANGELOG.md +133 -49
- package/README.ko.md +7 -7
- package/README.md +7 -7
- package/commands/crystallize.md +45 -8
- package/commands/graph.md +7 -4
- package/commands/lint.md +8 -1
- package/commands/query.md +6 -4
- package/commands/verify.md +12 -1
- package/docs/ARCHITECTURE.md +20 -12
- package/docs/CONTRIBUTING.md +23 -7
- package/hooks/close-journal.mjs +128 -0
- package/hooks/hooks.json +1 -9
- package/hooks/hypo-compact-guard.mjs +126 -23
- package/hooks/hypo-cwd-change.mjs +20 -19
- package/hooks/hypo-first-prompt.mjs +31 -16
- package/hooks/hypo-lookup.mjs +10 -5
- package/hooks/hypo-session-start.mjs +199 -13
- package/hooks/hypo-shared.mjs +521 -116
- package/hooks/hypo-web-fetch-ingest.mjs +9 -13
- package/hooks/proposal-store.mjs +35 -1
- package/hooks/shared.json +9 -0
- package/package.json +3 -1
- package/scripts/doctor.mjs +75 -94
- package/scripts/graph.mjs +22 -2
- package/scripts/init.mjs +54 -106
- package/scripts/lib/core-hooks.mjs +48 -22
- package/scripts/lib/crystallize-args.mjs +38 -2
- package/scripts/lib/crystallize-close-apply.mjs +634 -83
- package/scripts/lib/git-hooks-dir.mjs +427 -52
- package/scripts/lib/hook-inventory.mjs +150 -0
- package/scripts/lib/pkg-provenance.mjs +11 -0
- package/scripts/lib/plugin-detect.mjs +43 -9
- package/scripts/lib/template-schema-version.mjs +47 -0
- package/scripts/lint.mjs +166 -11
- package/scripts/query.mjs +22 -2
- package/scripts/uninstall.mjs +130 -66
- package/scripts/upgrade.mjs +245 -147
- package/scripts/verify.mjs +22 -2
- package/templates/SCHEMA.md +23 -1
- package/templates/hypo-automation.md +4 -2
- package/templates/hypo-config.md +1 -1
- package/templates/hypo-guide.md +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,19 +5,103 @@ All notable changes to Hypomnema are 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
|
|
|
8
|
+
## [1.8.4] - 2026-09-14
|
|
9
|
+
|
|
10
|
+
### Bug Fixes
|
|
11
|
+
|
|
12
|
+
#### English
|
|
13
|
+
|
|
14
|
+
- A session close no longer blocks on another project's uncommitted files. It judges the scope the close actually owns, and a dirty file belonging to a different project comes back as a notice naming its path instead of a blocker. ([#296](https://github.com/sk-lim19f/Hypomnema/pull/296))
|
|
15
|
+
- A close that could not write its marker no longer spends the close signal, so the session stays closable. ([#296](https://github.com/sk-lim19f/Hypomnema/pull/296))
|
|
16
|
+
- A close whose commit fails used to deadlock: the retry skipped every field as already-current, dropped those paths from the commit scope, and the gate then blocked on them forever. A close journal records what this session wrote, and a later run reclaims a path only when those exact bytes are still on disk. ([#296](https://github.com/sk-lim19f/Hypomnema/pull/296))
|
|
17
|
+
- The hook file list moved out of `hooks/hooks.json` into its own `hooks/shared.json`, ending the harness warning that fired on every session. ([#297](https://github.com/sk-lim19f/Hypomnema/pull/297))
|
|
18
|
+
- Install, upgrade, doctor and uninstall read that list through one parser instead of five private ones, so a command target outside `hooks/`, a command carrying arguments, and an empty hook map now mean the same thing to all of them. Install refuses to write anything when a listed file is missing from the package, and uninstall falls back to its provenance record when the package list is unreadable rather than exiting with every hook still in place. ([#297](https://github.com/sk-lim19f/Hypomnema/pull/297))
|
|
19
|
+
|
|
20
|
+
#### 한국어
|
|
21
|
+
|
|
22
|
+
- 세션 close 가 다른 프로젝트의 미커밋 파일에 더는 막히지 않습니다. close 가 실제로 책임지는 범위로 판정하고, 다른 프로젝트의 dirty 파일은 blocker 가 아니라 경로가 적힌 notice 로 돌아옵니다. ([#296](https://github.com/sk-lim19f/Hypomnema/pull/296))
|
|
23
|
+
- 마커를 못 쓴 close 가 close 신호를 소진하지 않아, 세션을 계속 닫을 수 있습니다. ([#296](https://github.com/sk-lim19f/Hypomnema/pull/296))
|
|
24
|
+
- 커밋에 실패한 close 가 교착에 빠지던 것을 고쳤습니다. 재시도가 모든 필드를 already-current 로 건너뛰면서 그 경로를 커밋 범위에서 빠뜨렸고, 게이트가 영원히 막았습니다. close 저널이 이 세션이 쓴 것을 기록하고, 나중 실행은 그 bytes 가 디스크에 그대로 있을 때만 경로를 되찾습니다. ([#296](https://github.com/sk-lim19f/Hypomnema/pull/296))
|
|
25
|
+
- 훅 파일 목록이 `hooks/hooks.json` 밖으로 나와 `hooks/shared.json` 이 됐습니다. 세션마다 뜨던 하네스 경고가 사라집니다. ([#297](https://github.com/sk-lim19f/Hypomnema/pull/297))
|
|
26
|
+
- 설치와 업그레이드와 진단과 제거가 그 목록을 각자의 reader 다섯 대신 공용 parser 하나로 읽습니다. `hooks/` 밖을 가리키는 command, 인자가 붙은 command, 빈 훅 맵이 이제 넷 모두에게 같은 뜻입니다. 설치는 목록의 파일이 패키지에 없으면 아무것도 쓰지 않고, 제거는 패키지 목록을 못 읽으면 provenance 기록으로 되돌아갑니다. 훅을 전부 남긴 채 종료하지 않습니다. ([#297](https://github.com/sk-lim19f/Hypomnema/pull/297))
|
|
27
|
+
|
|
28
|
+
### Changelog
|
|
29
|
+
|
|
30
|
+
- [#296](https://github.com/sk-lim19f/Hypomnema/pull/296) fix(close): scope the dirty gate and let a retry reclaim its own writes
|
|
31
|
+
- [#297](https://github.com/sk-lim19f/Hypomnema/pull/297) fix(hooks): move the shared file list out of hooks.json
|
|
32
|
+
- [#295](https://github.com/sk-lim19f/Hypomnema/pull/295) chore(release): v1.8.3
|
|
33
|
+
|
|
34
|
+
Contributors: @sk-lim19f
|
|
35
|
+
|
|
36
|
+
## [1.8.3] - 2026-09-11
|
|
37
|
+
|
|
38
|
+
### Bug Fixes
|
|
39
|
+
|
|
40
|
+
#### English
|
|
41
|
+
|
|
42
|
+
- The vault pre-commit hook finds the active install when it runs, instead of baking a path in at install time. It now survives a move, a reinstall, or a version bump. When it cannot find one it blocks the commit and prints how to fix it, rather than passing silently. ([#294](https://github.com/sk-lim19f/Hypomnema/pull/294))
|
|
43
|
+
- SessionStart repairs a drifted `hypo-pkg.json` pointer itself instead of only warning about it. It refuses a downgrade, refuses a value that is not semver, and serialises against other sessions with a file lock. ([#294](https://github.com/sk-lim19f/Hypomnema/pull/294))
|
|
44
|
+
- `upgrade` names what each SCHEMA version added, so a template-update notice says what changed rather than only that something did. ([#294](https://github.com/sk-lim19f/Hypomnema/pull/294))
|
|
45
|
+
|
|
46
|
+
#### 한국어
|
|
47
|
+
|
|
48
|
+
- 볼트 pre-commit 훅이 설치 경로를 설치 시점에 박아 두는 대신 실행할 때 찾습니다. 설치를 옮기거나 다시 깔거나 버전을 올려도 살아남습니다. 못 찾으면 조용히 통과시키지 않고 커밋을 막으면서 고치는 법을 알려 줍니다. ([#294](https://github.com/sk-lim19f/Hypomnema/pull/294))
|
|
49
|
+
- SessionStart 가 어긋난 `hypo-pkg.json` 포인터를 경고만 하지 않고 직접 고칩니다. 다운그레이드와 semver 가 아닌 값은 거부하고, 파일 잠금으로 다른 세션과 직렬화합니다. ([#294](https://github.com/sk-lim19f/Hypomnema/pull/294))
|
|
50
|
+
- `upgrade` 가 SCHEMA 버전마다 무엇이 더해졌는지 말해 줍니다. 템플릿 갱신 안내가 무언가 바뀌었다고만 하지 않고 무엇이 바뀌었는지 알려 줍니다. ([#294](https://github.com/sk-lim19f/Hypomnema/pull/294))
|
|
51
|
+
|
|
52
|
+
### Chores
|
|
53
|
+
|
|
54
|
+
#### English
|
|
55
|
+
|
|
56
|
+
- Wiki decision pointers are gone from every public surface, this changelog included. The repo ships no directory for them, so they resolved to nothing for any reader outside the maintainer's private notes. ([#294](https://github.com/sk-lim19f/Hypomnema/pull/294))
|
|
57
|
+
|
|
58
|
+
#### 한국어
|
|
59
|
+
|
|
60
|
+
- 위키 결정 문서 포인터를 이 changelog 를 포함한 모든 공개 표면에서 없앴습니다. 레포가 그 문서를 담은 디렉터리를 출하하지 않아서, 관리자의 개인 기록 밖에 있는 독자에게는 아무것도 가리키지 않는 포인터였습니다. ([#294](https://github.com/sk-lim19f/Hypomnema/pull/294))
|
|
61
|
+
|
|
62
|
+
## [1.8.2] - 2026-09-10
|
|
63
|
+
|
|
64
|
+
### Bug Fixes
|
|
65
|
+
|
|
66
|
+
#### English
|
|
67
|
+
|
|
68
|
+
- Hook notices reach the model again. They were emitted with a top-level `additionalContext`, which Claude Code silently ignores, so the close gate, the resume contract, and lookup results never arrived. Measured after the fix: a canary planted in a project's `hot.md` came back verbatim from a session with every file tool blocked, and the same canary read as absent on the previous build. ([#287](https://github.com/sk-lim19f/Hypomnema/pull/287))
|
|
69
|
+
- The session-close gate reads a background-task notification the same way on every delivery path, so a task finishing after you asked to close no longer cancels the close. A refusal also reports `gateReason`, naming which check refused. ([#289](https://github.com/sk-lim19f/Hypomnema/pull/289))
|
|
70
|
+
- `lint`, `verify`, `graph`, `query` and `crystallize` exit 2 on an unrecognised flag or an empty `--hypo-dir=`, instead of silently dropping it and falling back to the default vault. Their command docs no longer print placeholder syntax as runnable arguments. ([#286](https://github.com/sk-lim19f/Hypomnema/pull/286))
|
|
71
|
+
- The `/compact` and `/clear` notice no longer orders a session close, no longer fires on another project's uncommitted files, and no longer goes silent when the vault is broken enough to be worth reporting. ([#285](https://github.com/sk-lim19f/Hypomnema/pull/285))
|
|
72
|
+
- `/hypo:doctor` no longer accepts a session-closed marker as proof for a project the close gate never evaluated. The marker records the set the gate actually checked, and the audit requires an artifact's project to be in that set as well as in the marker's attribution. ([#284](https://github.com/sk-lim19f/Hypomnema/pull/284))
|
|
73
|
+
|
|
74
|
+
#### 한국어
|
|
75
|
+
|
|
76
|
+
- 훅 알림이 다시 모델에 닿습니다. 최상단 `additionalContext`로 나가고 있었는데 Claude Code가 그것을 조용히 무시해서 close 게이트, 세션 재개 계약, lookup 결과가 도착한 적이 없었습니다. 고친 뒤 실측했습니다. 프로젝트 `hot.md`에 심은 난수를 파일 도구를 전부 막은 세션이 그대로 답했고, 같은 난수를 이전 빌드는 못 읽었습니다. ([#287](https://github.com/sk-lim19f/Hypomnema/pull/287))
|
|
77
|
+
- 세션 마무리 게이트가 background task 알림을 어느 전달 경로로 오든 같게 읽습니다. 마무리를 요청한 뒤 작업이 끝나도 그 마무리가 취소되지 않습니다. 거절할 때는 `gateReason`으로 어느 검사가 거절했는지도 함께 알립니다. ([#289](https://github.com/sk-lim19f/Hypomnema/pull/289))
|
|
78
|
+
- `lint`·`verify`·`graph`·`query`·`crystallize`가 못 알아보는 플래그와 빈 `--hypo-dir=`를 조용히 버리고 기본 볼트로 가는 대신 exit 2를 냅니다. 명령 문서도 placeholder 문법을 실행 가능한 인자처럼 찍지 않습니다. ([#286](https://github.com/sk-lim19f/Hypomnema/pull/286))
|
|
79
|
+
- `/compact`·`/clear` 알림이 세션 마무리를 지시하지 않고, 다른 프로젝트의 미커밋 파일로 뜨지 않으며, 보고할 값어치가 있을 만큼 볼트가 망가졌을 때 조용해지지 않습니다. ([#285](https://github.com/sk-lim19f/Hypomnema/pull/285))
|
|
80
|
+
- `/hypo:doctor`가 close 게이트가 한 번도 평가하지 않은 프로젝트에 대해 session-closed 마커를 증거로 받지 않습니다. 마커가 게이트의 실제 검사 집합을 기록하고, 감사가 산출물의 프로젝트를 귀속뿐 아니라 그 집합에서도 요구합니다. ([#284](https://github.com/sk-lim19f/Hypomnema/pull/284))
|
|
81
|
+
|
|
82
|
+
### Chores
|
|
83
|
+
|
|
84
|
+
#### English
|
|
85
|
+
|
|
86
|
+
- The shipped `SCHEMA.md` template defines `updated` as the day content changed, not the day the file was written, and states plainly that nothing enforces it. ([#288](https://github.com/sk-lim19f/Hypomnema/pull/288))
|
|
87
|
+
|
|
88
|
+
#### 한국어
|
|
89
|
+
|
|
90
|
+
- 출하되는 `SCHEMA.md` 템플릿이 `updated`를 파일을 쓴 날이 아니라 내용이 바뀐 날로 정의하고, 그것을 집행하는 장치가 없다는 사실도 함께 적습니다. ([#288](https://github.com/sk-lim19f/Hypomnema/pull/288))
|
|
91
|
+
|
|
8
92
|
## [1.8.1] - 2026-09-07
|
|
9
93
|
|
|
10
94
|
### Bug Fixes
|
|
11
95
|
|
|
12
96
|
#### English
|
|
13
97
|
|
|
14
|
-
- Six slash names (`crystallize`, `graph`, `ingest`, `lint`, `query`, `verify`) shipped as both a `commands/*.md` file and a `skills/*/SKILL.md` directory, so each registered twice as a component and the command palette repeated them. Only the `commands/` half ever loaded, so the duplicates are removed with no behavior change, and `smoke:plugin` now fails on a name present in both directories
|
|
98
|
+
- Six slash names (`crystallize`, `graph`, `ingest`, `lint`, `query`, `verify`) shipped as both a `commands/*.md` file and a `skills/*/SKILL.md` directory, so each registered twice as a component and the command palette repeated them. Only the `commands/` half ever loaded, so the duplicates are removed with no behavior change, and `smoke:plugin` now fails on a name present in both directories. ([#282](https://github.com/sk-lim19f/Hypomnema/pull/282))
|
|
15
99
|
- A session close now checks that the root files it writes still carry a usable frontmatter block, and refuses a close that would leave invalid YAML in one of them. ([#281](https://github.com/sk-lim19f/Hypomnema/pull/281))
|
|
16
100
|
- `/hypo:resume` and SessionStart now surface uncommitted vault work that belongs to another project, so a session does not silently adopt it. ([#280](https://github.com/sk-lim19f/Hypomnema/pull/280))
|
|
17
101
|
|
|
18
102
|
#### 한국어
|
|
19
103
|
|
|
20
|
-
- 여섯 슬래시 이름(`crystallize`, `graph`, `ingest`, `lint`, `query`, `verify`)이 `commands/*.md` 파일과 `skills/*/SKILL.md` 디렉터리로 둘 다 출하되어 component 가 두 번씩 등록되고 명령 팔레트가 그만큼 반복됐습니다. 실제로 로드된 것은 `commands/` 쪽뿐이라 중복을 동작 변화 없이 지웠고, 이제 한 이름이 두 디렉터리에 다 있으면 `smoke:plugin` 이
|
|
104
|
+
- 여섯 슬래시 이름(`crystallize`, `graph`, `ingest`, `lint`, `query`, `verify`)이 `commands/*.md` 파일과 `skills/*/SKILL.md` 디렉터리로 둘 다 출하되어 component 가 두 번씩 등록되고 명령 팔레트가 그만큼 반복됐습니다. 실제로 로드된 것은 `commands/` 쪽뿐이라 중복을 동작 변화 없이 지웠고, 이제 한 이름이 두 디렉터리에 다 있으면 `smoke:plugin` 이 실패합니다. ([#282](https://github.com/sk-lim19f/Hypomnema/pull/282))
|
|
21
105
|
- 세션 마무리가 자기가 쓰는 루트 파일에 쓸 만한 프론트매터 블록이 남는지 검사하고, 그중 하나에 깨진 YAML 을 남길 마무리를 거절합니다. ([#281](https://github.com/sk-lim19f/Hypomnema/pull/281))
|
|
22
106
|
- `/hypo:resume` 과 SessionStart 가 다른 프로젝트 소관의 미커밋 변경을 한 줄로 알려, 세션이 그것을 조용히 자기 일로 삼지 않게 합니다. ([#280](https://github.com/sk-lim19f/Hypomnema/pull/280))
|
|
23
107
|
|
|
@@ -44,32 +128,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
44
128
|
- A session close no longer writes over a page that changed since it read it, in any case: every drifted whole-file overwrite parks for review. `CHANGELOG.md` ships in the npm package, so the README links to it resolve. ([#262](https://github.com/sk-lim19f/Hypomnema/pull/262))
|
|
45
129
|
- Five skills told Claude to pass `--wiki-dir` to scripts that only ever parsed `--hypo-dir`, and none of those scripts rejects an unknown flag, so the value was dropped and the command silently used the default vault instead of the one you named. `crystallize` was among them, so a session close could land in the wrong vault and still report success. ([#266](https://github.com/sk-lim19f/Hypomnema/pull/266))
|
|
46
130
|
- `hypomnema upgrade --apply` repoints the git pre-commit hook in your wiki repo at the install you are actually running, and `/hypo:doctor` reports when that hook names an older one. The hook holds an absolute path baked in at init time, so until now a vault could keep checking every commit against a release from months earlier while the version string read correctly. Installing a release does not repoint it: run the apply step once after updating. ([#267](https://github.com/sk-lim19f/Hypomnema/pull/267))
|
|
47
|
-
- `/compact` is no longer blocked by an unfinished session close. The PreCompact hook reports what it finds and lets the compact through, and a close gate scoped to the project this session is actually closing stops charging one session for another session's unfinished close
|
|
131
|
+
- `/compact` is no longer blocked by an unfinished session close. The PreCompact hook reports what it finds and lets the compact through, and a close gate scoped to the project this session is actually closing stops charging one session for another session's unfinished close. ([#273](https://github.com/sk-lim19f/Hypomnema/pull/273))
|
|
48
132
|
- The session-close gate no longer demotes a file the session itself edited when the transcript is only partially readable, and each pending-work notice names its own type instead of being reported as a lint issue. ([#275](https://github.com/sk-lim19f/Hypomnema/pull/275))
|
|
49
133
|
- A session that spans several days can close again: targets a later session start re-read are no longer parked as stale, while anything it was not shown in full still parks. ([#276](https://github.com/sk-lim19f/Hypomnema/pull/276))
|
|
50
|
-
- When the plugin registry cannot be read, init and upgrade leave the package pointer and the vault's pre-commit hook alone instead of recording the npm copy the dual-install notice asks you to delete, and the drift banner and doctor point at repairing the registry
|
|
134
|
+
- When the plugin registry cannot be read, init and upgrade leave the package pointer and the vault's pre-commit hook alone instead of recording the npm copy the dual-install notice asks you to delete, and the drift banner and doctor point at repairing the registry. ([#277](https://github.com/sk-lim19f/Hypomnema/pull/277))
|
|
51
135
|
|
|
52
136
|
#### 한국어
|
|
53
137
|
|
|
54
138
|
- 세션 마무리가 자기가 읽은 뒤 바뀐 페이지를 덮어쓰는 경우가 이제 없습니다. 드리프트된 전체 덮어쓰기는 전부 보류되고 검토를 기다립니다. `CHANGELOG.md` 가 npm 패키지에 실려 README 의 링크가 살아납니다. ([#262](https://github.com/sk-lim19f/Hypomnema/pull/262))
|
|
55
139
|
- 다섯 스킬이 `--hypo-dir` 만 파싱하는 스크립트에 `--wiki-dir` 를 넘기라고 지시했고, 그 스크립트들이 미지정 플래그를 거부하지 않아 값이 버려진 채 지정한 볼트가 아니라 기본 볼트가 쓰였습니다. `crystallize` 가 그중 하나라 세션 마무리가 엉뚱한 볼트에 쓰이고도 성공을 보고할 수 있었습니다. ([#266](https://github.com/sk-lim19f/Hypomnema/pull/266))
|
|
56
140
|
- `hypomnema upgrade --apply` 가 위키 레포의 git pre-commit 훅을 실제로 돌고 있는 설치로 다시 겨눕니다. 그리고 `/hypo:doctor` 가 그 훅이 더 오래된 설치를 가리키면 보고합니다. 이 훅은 init 시점의 절대경로를 들고 있어서, 지금까지는 버전 문자열이 맞게 읽히는 동안에도 볼트가 몇 달 전 릴리스로 모든 커밋을 계속 검사할 수 있었습니다. 릴리스를 설치하는 것만으로는 다시 겨눠지지 않으니 업데이트 후 apply 단계를 한 번 돌리세요. ([#267](https://github.com/sk-lim19f/Hypomnema/pull/267))
|
|
57
|
-
- 세션 마무리가 미완결이어도 `/compact` 가 막히지 않습니다. PreCompact 훅은 찾은 것을 보고만 하고 compact 를 통과시키며, 이 세션이 실제로 닫는 프로젝트로 좁혀진 close 게이트가 남의 세션이 남긴 미완결 close 를 이 세션에 물리지
|
|
141
|
+
- 세션 마무리가 미완결이어도 `/compact` 가 막히지 않습니다. PreCompact 훅은 찾은 것을 보고만 하고 compact 를 통과시키며, 이 세션이 실제로 닫는 프로젝트로 좁혀진 close 게이트가 남의 세션이 남긴 미완결 close 를 이 세션에 물리지 않습니다. ([#273](https://github.com/sk-lim19f/Hypomnema/pull/273))
|
|
58
142
|
- transcript 가 일부만 읽히는 상황에서 세션이 직접 편집한 파일이 강등되지 않고, 남은 작업 notice 가 lint 로 뭉뚱그려지지 않고 각자 유형으로 표시됩니다. ([#275](https://github.com/sk-lim19f/Hypomnema/pull/275))
|
|
59
143
|
- 여러 날 이어진 세션도 close 가 됩니다. 나중 세션 시작이 다시 읽어 보여준 대상은 묵었다고 파킹되지 않고, 전부를 보여주지 못한 것은 그대로 파킹됩니다. ([#276](https://github.com/sk-lim19f/Hypomnema/pull/276))
|
|
60
|
-
- 플러그인 registry 를 못 읽을 때 init 과 upgrade 가 dual install 안내가 지우라고 하는 npm 사본을 기록하지 않고 포인터와 볼트 pre-commit 훅을 그대로 둡니다. drift 배너와 doctor 도 registry 수리를
|
|
144
|
+
- 플러그인 registry 를 못 읽을 때 init 과 upgrade 가 dual install 안내가 지우라고 하는 npm 사본을 기록하지 않고 포인터와 볼트 pre-commit 훅을 그대로 둡니다. drift 배너와 doctor 도 registry 수리를 지목합니다. ([#277](https://github.com/sk-lim19f/Hypomnema/pull/277))
|
|
61
145
|
|
|
62
146
|
### Chores
|
|
63
147
|
|
|
64
148
|
#### English
|
|
65
149
|
|
|
66
150
|
- The automation reference installed into a vault no longer claims that no hook makes a network request, lists all 15 registered hooks under their correct events, and corrects five further claims about auto-stage, the Stop chain, FileChanged, and `.hypoignore`. Existing vaults keep their old copy: the file has no update channel yet. ([#263](https://github.com/sk-lim19f/Hypomnema/pull/263))
|
|
67
|
-
- `/hypo:doctor` tells an unreadable plugin registry apart from no plugin at all, so an install it cannot verify is reported instead of being treated as absent
|
|
151
|
+
- `/hypo:doctor` tells an unreadable plugin registry apart from no plugin at all, so an install it cannot verify is reported instead of being treated as absent. ([#272](https://github.com/sk-lim19f/Hypomnema/pull/272))
|
|
68
152
|
|
|
69
153
|
#### 한국어
|
|
70
154
|
|
|
71
155
|
- 볼트에 설치되는 자동화 참조가 더 이상 "어떤 훅도 네트워크 요청을 하지 않는다" 고 말하지 않고, 등록된 훅 15 개를 각자의 올바른 이벤트 아래 나열하며, auto-stage·Stop 체인·FileChanged·`.hypoignore` 에 대한 다섯 가지 서술을 함께 고칩니다. 기존 볼트는 낡은 사본을 유지합니다. 이 파일에는 아직 갱신 채널이 없습니다. ([#263](https://github.com/sk-lim19f/Hypomnema/pull/263))
|
|
72
|
-
- `/hypo:doctor` 가 읽을 수 없는 플러그인 registry 와 플러그인이 아예 없는 경우를 구별하여, 확인할 수 없는 설치를 부재로 취급하지 않고
|
|
156
|
+
- `/hypo:doctor` 가 읽을 수 없는 플러그인 registry 와 플러그인이 아예 없는 경우를 구별하여, 확인할 수 없는 설치를 부재로 취급하지 않고 보고합니다. ([#272](https://github.com/sk-lim19f/Hypomnema/pull/272))
|
|
73
157
|
|
|
74
158
|
## [1.7.4] - 2026-08-29
|
|
75
159
|
|
|
@@ -246,7 +330,7 @@ Contributors: @sk-lim19f
|
|
|
246
330
|
#### English
|
|
247
331
|
|
|
248
332
|
- A session close now verifies the user asked for it before writing anything, rather than after the files were already written and committed. ([#199](https://github.com/sk-lim19f/Hypomnema/pull/199))
|
|
249
|
-
- The close gate tracks the latest user decision as a lease instead of scanning the whole transcript for any close signal, so a stale close, a queued change of mind, a `/clear`, or a model self-close no longer counts as a user close
|
|
333
|
+
- The close gate tracks the latest user decision as a lease instead of scanning the whole transcript for any close signal, so a stale close, a queued change of mind, a `/clear`, or a model self-close no longer counts as a user close. ([#213](https://github.com/sk-lim19f/Hypomnema/pull/213))
|
|
250
334
|
- The session-close marker is attributed to the project the session actually closed rather than the vault's most recent one, and close debt is charged to the session that made it: an incomplete close in a project this session never touched is now a non-blocking notice instead of blocking `/compact`. ([#193](https://github.com/sk-lim19f/Hypomnema/pull/193), [#212](https://github.com/sk-lim19f/Hypomnema/pull/212))
|
|
251
335
|
- A session close can no longer apply one session's payload under another's marker: the payload temp path is session-scoped, and apply refuses a payload whose `sessionId` does not match. ([#204](https://github.com/sk-lim19f/Hypomnema/pull/204))
|
|
252
336
|
- Two sessions withholding an overwrite for the same page no longer keep only the last one's bytes, and `proposal apply` reports any proposal still pending against the file it just wrote. ([#191](https://github.com/sk-lim19f/Hypomnema/pull/191))
|
|
@@ -264,7 +348,7 @@ Contributors: @sk-lim19f
|
|
|
264
348
|
#### 한국어
|
|
265
349
|
|
|
266
350
|
- 세션 close가 파일을 다 쓰고 커밋한 뒤가 아니라, 아무것도 쓰기 전에 사용자가 요청했는지 확인합니다. ([#199](https://github.com/sk-lim19f/Hypomnema/pull/199))
|
|
267
|
-
- close 게이트가 트랜스크립트 전체에서 close 신호를 찾는 대신 가장 최근 사용자 결정을 lease로 추적해, 오래된 close나 큐에 넣은 마음 바꿈, `/clear`, 모델의 자기 종료가 더 이상 사용자 종료로 세어지지
|
|
351
|
+
- close 게이트가 트랜스크립트 전체에서 close 신호를 찾는 대신 가장 최근 사용자 결정을 lease로 추적해, 오래된 close나 큐에 넣은 마음 바꿈, `/clear`, 모델의 자기 종료가 더 이상 사용자 종료로 세어지지 않습니다. ([#213](https://github.com/sk-lim19f/Hypomnema/pull/213))
|
|
268
352
|
- session-close 마커가 볼트에서 가장 최근이었던 프로젝트가 아니라 이 세션이 실제로 닫은 프로젝트에 귀속되고, 이 세션이 건드린 적 없는 프로젝트의 미완 close는 `/compact`를 막는 대신 비차단 notice가 됩니다. ([#193](https://github.com/sk-lim19f/Hypomnema/pull/193), [#212](https://github.com/sk-lim19f/Hypomnema/pull/212))
|
|
269
353
|
- 세션 close가 한 세션의 payload를 다른 세션 마커로 적용할 수 없게 됐습니다: payload 임시 경로가 세션 범위로 바뀌었고, `sessionId`가 맞지 않는 payload는 apply가 거부합니다. ([#204](https://github.com/sk-lim19f/Hypomnema/pull/204))
|
|
270
354
|
- 같은 페이지에 대해 두 세션이 overwrite를 보류할 때 마지막 세션의 바이트만 남던 문제를 고쳤고, `proposal apply`가 방금 쓴 파일에 남아 있는 proposal을 알려줍니다. ([#191](https://github.com/sk-lim19f/Hypomnema/pull/191))
|
|
@@ -662,13 +746,13 @@ Contributors: @sk-lim19f
|
|
|
662
746
|
|
|
663
747
|
#### English
|
|
664
748
|
|
|
665
|
-
- Template injection keeps your hand-authored page instead of dropping a duplicate orphan. `init` checked only the exact destination filename, so a stock `hypo-automation.md` landed next to a user's `wiki-automation.md` (the `hypo-`/`wiki-` namespace split), leaving a 0-reference duplicate orphan. `init` now carries an explicit equivalents map (the same idiom the hook-rename migration uses): when a legacy `wiki-*` page exists it keeps that page, skips the stock one, and reports the skip loudly so you can merge by hand. `hypo-guide.md` is exempt, because the runtime loads it by name and a mid-migration vault must still receive it. The check also fires in `--dry-run`. ([#133](https://github.com/sk-lim19f/Hypomnema/pull/133)
|
|
666
|
-
- Generated root artifacts no longer pollute the knowledge catalog. The upgrade report (`MIGRATION-v*.md`) sits at the vault root, and the catalog scans (lint link targets, rename, doctor) treated it as a knowledge page. (`GRAPH_REPORT.md` has no writer today; its name is reserved preventively so a future dump cannot pollute the catalog either.) They cannot go in `.hypoignore`, because that list also drives the pre-commit secret gate, so listing them there would block their own commit and freeze every auto-commit while the report sits at root. A root-anchored, catalog-only exclusion now hides them from the scans while the pre-commit gate and `ingest --check` keep treating them normally, so the report still commits and enters git history but stops cluttering the catalog. Same-named files nested under `pages/` or `projects/` are untouched. ([#133](https://github.com/sk-lim19f/Hypomnema/pull/133)
|
|
749
|
+
- Template injection keeps your hand-authored page instead of dropping a duplicate orphan. `init` checked only the exact destination filename, so a stock `hypo-automation.md` landed next to a user's `wiki-automation.md` (the `hypo-`/`wiki-` namespace split), leaving a 0-reference duplicate orphan. `init` now carries an explicit equivalents map (the same idiom the hook-rename migration uses): when a legacy `wiki-*` page exists it keeps that page, skips the stock one, and reports the skip loudly so you can merge by hand. `hypo-guide.md` is exempt, because the runtime loads it by name and a mid-migration vault must still receive it. The check also fires in `--dry-run`. ([#133](https://github.com/sk-lim19f/Hypomnema/pull/133))
|
|
750
|
+
- Generated root artifacts no longer pollute the knowledge catalog. The upgrade report (`MIGRATION-v*.md`) sits at the vault root, and the catalog scans (lint link targets, rename, doctor) treated it as a knowledge page. (`GRAPH_REPORT.md` has no writer today; its name is reserved preventively so a future dump cannot pollute the catalog either.) They cannot go in `.hypoignore`, because that list also drives the pre-commit secret gate, so listing them there would block their own commit and freeze every auto-commit while the report sits at root. A root-anchored, catalog-only exclusion now hides them from the scans while the pre-commit gate and `ingest --check` keep treating them normally, so the report still commits and enters git history but stops cluttering the catalog. Same-named files nested under `pages/` or `projects/` are untouched. ([#133](https://github.com/sk-lim19f/Hypomnema/pull/133))
|
|
667
751
|
|
|
668
752
|
#### 한국어
|
|
669
753
|
|
|
670
|
-
- 템플릿 주입이 중복 고아를 떨구지 않고 손수 쓴 페이지를 유지합니다. `init`이 정확한 대상 파일명만 검사해서 stock `hypo-automation.md`가 사용자의 `wiki-automation.md`(hypo-/wiki- 네임스페이스 split) 옆에 떨어지며 참조 0곳 중복 고아를 남겼습니다. 이제 `init`은 명시적 등가본 맵(hook-rename 마이그레이션과 같은 관용구)을 갖춰, 레거시 `wiki-*` 페이지가 있으면 그 페이지를 유지하고 stock 페이지는 건너뛰며 그 사실을 눈에 띄게 보고해 사용자가 수동으로 머지하게 합니다. `hypo-guide.md`는 런타임이 이름으로 읽고 마이그레이션 중간 볼트도 받아야 하므로 예외입니다. `--dry-run`에서도 이 안내를 출력합니다. ([#133](https://github.com/sk-lim19f/Hypomnema/pull/133)
|
|
671
|
-
- 생성된 루트 산출물이 지식 카탈로그를 오염하지 않습니다. 업그레이드 리포트(`MIGRATION-v*.md`)가 볼트 루트에 있어 카탈로그 스캔(lint 링크 타깃·rename·doctor)이 지식 페이지로 취급했습니다. (`GRAPH_REPORT.md`는 현재 writer가 없고, 향후 덤프가 카탈로그를 오염하지 못하도록 이름만 예방적으로 예약했습니다.) 이들은 `.hypoignore`에 넣을 수 없는데, 그 목록이 pre-commit 시크릿 게이트도 구동하므로 거기 넣으면 자기 커밋이 차단되고 리포트가 루트에 있는 동안 모든 auto-commit이 동결되기 때문입니다. 이제 root-anchored 카탈로그 전용 제외 규칙이 스캔에서는 숨기되 pre-commit 게이트와 `ingest --check`은 정상 취급하므로, 리포트는 여전히 커밋되어 git 히스토리에 들어가면서 카탈로그를 어지럽히지 않습니다. `pages/`·`projects/` 아래 중첩 동명 파일은 영향받지 않습니다. ([#133](https://github.com/sk-lim19f/Hypomnema/pull/133)
|
|
754
|
+
- 템플릿 주입이 중복 고아를 떨구지 않고 손수 쓴 페이지를 유지합니다. `init`이 정확한 대상 파일명만 검사해서 stock `hypo-automation.md`가 사용자의 `wiki-automation.md`(hypo-/wiki- 네임스페이스 split) 옆에 떨어지며 참조 0곳 중복 고아를 남겼습니다. 이제 `init`은 명시적 등가본 맵(hook-rename 마이그레이션과 같은 관용구)을 갖춰, 레거시 `wiki-*` 페이지가 있으면 그 페이지를 유지하고 stock 페이지는 건너뛰며 그 사실을 눈에 띄게 보고해 사용자가 수동으로 머지하게 합니다. `hypo-guide.md`는 런타임이 이름으로 읽고 마이그레이션 중간 볼트도 받아야 하므로 예외입니다. `--dry-run`에서도 이 안내를 출력합니다. ([#133](https://github.com/sk-lim19f/Hypomnema/pull/133))
|
|
755
|
+
- 생성된 루트 산출물이 지식 카탈로그를 오염하지 않습니다. 업그레이드 리포트(`MIGRATION-v*.md`)가 볼트 루트에 있어 카탈로그 스캔(lint 링크 타깃·rename·doctor)이 지식 페이지로 취급했습니다. (`GRAPH_REPORT.md`는 현재 writer가 없고, 향후 덤프가 카탈로그를 오염하지 못하도록 이름만 예방적으로 예약했습니다.) 이들은 `.hypoignore`에 넣을 수 없는데, 그 목록이 pre-commit 시크릿 게이트도 구동하므로 거기 넣으면 자기 커밋이 차단되고 리포트가 루트에 있는 동안 모든 auto-commit이 동결되기 때문입니다. 이제 root-anchored 카탈로그 전용 제외 규칙이 스캔에서는 숨기되 pre-commit 게이트와 `ingest --check`은 정상 취급하므로, 리포트는 여전히 커밋되어 git 히스토리에 들어가면서 카탈로그를 어지럽히지 않습니다. `pages/`·`projects/` 아래 중첩 동명 파일은 영향받지 않습니다. ([#133](https://github.com/sk-lim19f/Hypomnema/pull/133))
|
|
672
756
|
|
|
673
757
|
### Changelog
|
|
674
758
|
|
|
@@ -698,29 +782,29 @@ Contributors: @sk-lim19f
|
|
|
698
782
|
|
|
699
783
|
#### English
|
|
700
784
|
|
|
701
|
-
- `rename` handles a directory subtree, not just a single page. The rename helper shipped for pages in 1.3.2; renaming a folder still meant moving each page by hand. `scripts/rename.mjs` (and a `/hypo:rename` slash command) now relocates an entire subtree, rewrites the eligible inbound wikilinks across the vault the same way the page mode does, and when a destination path already exists it emits a merge/renumber collision report and refuses `--apply` (leaving the merge for manual handling) rather than clobbering. It stays a dry-run by default; pass `--apply` to write the move. ([#125](https://github.com/sk-lim19f/Hypomnema/pull/125)
|
|
785
|
+
- `rename` handles a directory subtree, not just a single page. The rename helper shipped for pages in 1.3.2; renaming a folder still meant moving each page by hand. `scripts/rename.mjs` (and a `/hypo:rename` slash command) now relocates an entire subtree, rewrites the eligible inbound wikilinks across the vault the same way the page mode does, and when a destination path already exists it emits a merge/renumber collision report and refuses `--apply` (leaving the merge for manual handling) rather than clobbering. It stays a dry-run by default; pass `--apply` to write the move. ([#125](https://github.com/sk-lim19f/Hypomnema/pull/125))
|
|
702
786
|
|
|
703
787
|
#### 한국어
|
|
704
788
|
|
|
705
|
-
- `rename`이 단일 페이지뿐 아니라 디렉터리 서브트리를 처리합니다. rename 헬퍼는 1.3.2에서 페이지용으로 출시됐는데, 폴더 이름 변경은 여전히 페이지를 하나씩 손으로 옮겨야 했습니다. `scripts/rename.mjs`(및 `/hypo:rename` 슬래시 커맨드)가 이제 서브트리 전체를 옮기고, 페이지 모드와 동일하게 볼트 전체의 해당하는 인바운드 위키링크를 갱신하며, 대상 경로가 이미 있으면 clobber 대신 merge/renumber 충돌 리포트를 내고 `--apply`를 거부합니다(merge는 수동 처리에 맡깁니다). 기본은 dry-run이며 `--apply`로 이동을 기록합니다. ([#125](https://github.com/sk-lim19f/Hypomnema/pull/125)
|
|
789
|
+
- `rename`이 단일 페이지뿐 아니라 디렉터리 서브트리를 처리합니다. rename 헬퍼는 1.3.2에서 페이지용으로 출시됐는데, 폴더 이름 변경은 여전히 페이지를 하나씩 손으로 옮겨야 했습니다. `scripts/rename.mjs`(및 `/hypo:rename` 슬래시 커맨드)가 이제 서브트리 전체를 옮기고, 페이지 모드와 동일하게 볼트 전체의 해당하는 인바운드 위키링크를 갱신하며, 대상 경로가 이미 있으면 clobber 대신 merge/renumber 충돌 리포트를 내고 `--apply`를 거부합니다(merge는 수동 처리에 맡깁니다). 기본은 dry-run이며 `--apply`로 이동을 기록합니다. ([#125](https://github.com/sk-lim19f/Hypomnema/pull/125))
|
|
706
790
|
|
|
707
791
|
### Bug Fixes
|
|
708
792
|
|
|
709
793
|
#### English
|
|
710
794
|
|
|
711
|
-
- A session is no longer marked closed without a real user close signal. Both session-closed marker writers gated only on "is the wiki compact-ready", never on whether you actually asked to close, so the model could self-close (write the marker and declare done) on its own judgment. A hard gate now requires a genuine user close signal in the session (a natural-language close phrase, `/compact`, or an AskUserQuestion close answer), resolved strictly from the session id, separate from the compact-readiness check. This blocks inadvertent over-close; it is not a claim of unforgeability (the model owns its own subprocess), and a direct marker write stays inert because the Stop hook only consults the marker once a close signal is already present. ([#129](https://github.com/sk-lim19f/Hypomnema/pull/129)
|
|
712
|
-
- Reading close-related text no longer false-blocks the turn. The Stop-gate close-intent check stringified `role:user` tool results and injected skill or command bodies, so a session that merely read close vocabulary (a prior transcript, the close docs, a skill body full of "wrap up" / "session close" examples) tripped the gate every turn. Close-intent now ignores tool results and injected meta/system content, and the Korean close pattern moved from a verb-suffix blacklist to a complete-terminal whitelist, so it matches the common real phrasings and rejects noun-modifier and negation forms. (Tool-result exclusion is [#126](https://github.com/sk-lim19f/Hypomnema/pull/126)
|
|
795
|
+
- A session is no longer marked closed without a real user close signal. Both session-closed marker writers gated only on "is the wiki compact-ready", never on whether you actually asked to close, so the model could self-close (write the marker and declare done) on its own judgment. A hard gate now requires a genuine user close signal in the session (a natural-language close phrase, `/compact`, or an AskUserQuestion close answer), resolved strictly from the session id, separate from the compact-readiness check. This blocks inadvertent over-close; it is not a claim of unforgeability (the model owns its own subprocess), and a direct marker write stays inert because the Stop hook only consults the marker once a close signal is already present. ([#129](https://github.com/sk-lim19f/Hypomnema/pull/129))
|
|
796
|
+
- Reading close-related text no longer false-blocks the turn. The Stop-gate close-intent check stringified `role:user` tool results and injected skill or command bodies, so a session that merely read close vocabulary (a prior transcript, the close docs, a skill body full of "wrap up" / "session close" examples) tripped the gate every turn. Close-intent now ignores tool results and injected meta/system content, and the Korean close pattern moved from a verb-suffix blacklist to a complete-terminal whitelist, so it matches the common real phrasings and rejects noun-modifier and negation forms. (Tool-result exclusion is [#126](https://github.com/sk-lim19f/Hypomnema/pull/126); the injected meta/system exclusion and the whitelist are [#129](https://github.com/sk-lim19f/Hypomnema/pull/129).)
|
|
713
797
|
- The proactive close offer can no longer close the session by itself. The "looks like you're wrapping up" path could proceed all the way to a self-close; it is now scoped to offering only, and the actual close still requires you to choose it. ([#128](https://github.com/sk-lim19f/Hypomnema/pull/128))
|
|
714
|
-
- `--apply-session-close` writes the session-closed marker instead of silently skipping it. apply wrote its payload files (leaving the tree dirty) and then checked a gate whose git-clean blocker its own writes had just tripped, so the marker was skipped and you were nudged to run `--mark-session-closed` by hand, after the close had already reported success. apply now commits its own payload first, via the same `.hypoignore`-aware helper the auto-commit Stop hook uses, then writes and verifies the marker. Unpushed commits ("ahead") are demoted from a blocker to a notice across the shared gate (push is automatic and its failures are already non-fatal), so a committed-but-unpushed close still marks and still compacts. ([#130](https://github.com/sk-lim19f/Hypomnema/pull/130)
|
|
715
|
-
- Tracker bookkeeping no longer cross-blocks an unrelated project's `/compact`. The global close invariant treated a freshly-dated `session-state.md` as close activity, but routine tracker bookkeeping (mirroring a new item into "next tasks") bumps that date with no real session, so an unrelated project's `/compact` was held hostage demanding the bookkept project's full close. Close activity is now recognized only from the artifacts a real close writes (a today session-log heading or a `## [today] session | P` log entry); the soft state files (`session-state.md`, project `hot.md`, the root `hot.md` row) no longer count, which also stops `project-create` and hot-cache rebuilds from looking like sessions. ([#131](https://github.com/sk-lim19f/Hypomnema/pull/131)
|
|
798
|
+
- `--apply-session-close` writes the session-closed marker instead of silently skipping it. apply wrote its payload files (leaving the tree dirty) and then checked a gate whose git-clean blocker its own writes had just tripped, so the marker was skipped and you were nudged to run `--mark-session-closed` by hand, after the close had already reported success. apply now commits its own payload first, via the same `.hypoignore`-aware helper the auto-commit Stop hook uses, then writes and verifies the marker. Unpushed commits ("ahead") are demoted from a blocker to a notice across the shared gate (push is automatic and its failures are already non-fatal), so a committed-but-unpushed close still marks and still compacts. ([#130](https://github.com/sk-lim19f/Hypomnema/pull/130))
|
|
799
|
+
- Tracker bookkeeping no longer cross-blocks an unrelated project's `/compact`. The global close invariant treated a freshly-dated `session-state.md` as close activity, but routine tracker bookkeeping (mirroring a new item into "next tasks") bumps that date with no real session, so an unrelated project's `/compact` was held hostage demanding the bookkept project's full close. Close activity is now recognized only from the artifacts a real close writes (a today session-log heading or a `## [today] session | P` log entry); the soft state files (`session-state.md`, project `hot.md`, the root `hot.md` row) no longer count, which also stops `project-create` and hot-cache rebuilds from looking like sessions. ([#131](https://github.com/sk-lim19f/Hypomnema/pull/131))
|
|
716
800
|
|
|
717
801
|
#### 한국어
|
|
718
802
|
|
|
719
|
-
- 실제 사용자 종료 신호 없이 세션이 닫히지 않습니다. 두 session-closed 마커 writer는 "위키가 compact-ready인가"만 검사하고 사용자가 실제로 종료를 요청했는지는 보지 않아, 모델이 자의로 self-close(마커를 쓰고 완료 선언)할 수 있었습니다. 이제 hard gate가 세션 안의 진짜 사용자 종료 신호(자연어 종료 표현·`/compact`·AskUserQuestion 종료 답변)를 요구하며, session id에서만 해석하고 compact-readiness 검사와는 별개입니다. 무심코 일어나는 over-close를 막는 장치이지 위조 불가를 주장하는 것은 아니며(모델은 자기 subprocess를 소유합니다), 직접 마커를 써도 Stop 훅은 종료 신호가 이미 있을 때만 마커를 참조하므로 무력합니다. ([#129](https://github.com/sk-lim19f/Hypomnema/pull/129)
|
|
720
|
-
- 종료 관련 텍스트를 읽는 것이 턴을 false-block하지 않습니다. Stop 게이트의 close-intent 검사가 `role:user` tool result와 주입된 스킬·커맨드 본문을 통째로 문자열화해서, 종료 어휘를 단지 읽은 세션(이전 transcript·종료 문서·"wrap up"·"session close" 예시가 가득한 스킬 본문)이 매 턴 게이트에 걸렸습니다. 이제 close-intent는 tool result와 주입된 meta/system 콘텐츠를 무시하고, 한국어 종료 패턴은 동사어미 blacklist에서 종결형 완전체 whitelist로 바뀌어 흔한 실제 표현은 잡고 명사수식·부정형은 거부합니다. (tool result 제외는 [#126](https://github.com/sk-lim19f/Hypomnema/pull/126)
|
|
803
|
+
- 실제 사용자 종료 신호 없이 세션이 닫히지 않습니다. 두 session-closed 마커 writer는 "위키가 compact-ready인가"만 검사하고 사용자가 실제로 종료를 요청했는지는 보지 않아, 모델이 자의로 self-close(마커를 쓰고 완료 선언)할 수 있었습니다. 이제 hard gate가 세션 안의 진짜 사용자 종료 신호(자연어 종료 표현·`/compact`·AskUserQuestion 종료 답변)를 요구하며, session id에서만 해석하고 compact-readiness 검사와는 별개입니다. 무심코 일어나는 over-close를 막는 장치이지 위조 불가를 주장하는 것은 아니며(모델은 자기 subprocess를 소유합니다), 직접 마커를 써도 Stop 훅은 종료 신호가 이미 있을 때만 마커를 참조하므로 무력합니다. ([#129](https://github.com/sk-lim19f/Hypomnema/pull/129))
|
|
804
|
+
- 종료 관련 텍스트를 읽는 것이 턴을 false-block하지 않습니다. Stop 게이트의 close-intent 검사가 `role:user` tool result와 주입된 스킬·커맨드 본문을 통째로 문자열화해서, 종료 어휘를 단지 읽은 세션(이전 transcript·종료 문서·"wrap up"·"session close" 예시가 가득한 스킬 본문)이 매 턴 게이트에 걸렸습니다. 이제 close-intent는 tool result와 주입된 meta/system 콘텐츠를 무시하고, 한국어 종료 패턴은 동사어미 blacklist에서 종결형 완전체 whitelist로 바뀌어 흔한 실제 표현은 잡고 명사수식·부정형은 거부합니다. (tool result 제외는 [#126](https://github.com/sk-lim19f/Hypomnema/pull/126), 주입된 meta/system 제외와 whitelist는 [#129](https://github.com/sk-lim19f/Hypomnema/pull/129)입니다.)
|
|
721
805
|
- 선제적 종료 제안이 스스로 세션을 닫을 수 없습니다. "마무리하는 것 같다" 경로가 self-close까지 진행될 수 있었는데, 이제 제안만 하도록 스코프되고 실제 종료는 사용자가 선택해야 합니다. ([#128](https://github.com/sk-lim19f/Hypomnema/pull/128))
|
|
722
|
-
- `--apply-session-close`가 session-closed 마커를 조용히 건너뛰지 않고 기록합니다. apply는 payload 파일을 쓰고(트리가 dirty해짐) 나서 자기 write가 방금 건드린 git-clean 차단을 검사해서, 마커가 생략되고 종료가 이미 성공으로 보고된 뒤에 사용자가 `--mark-session-closed`를 손수 돌리도록 내몰렸습니다. 이제 apply는 auto-commit Stop 훅과 동일한 `.hypoignore` 인지 헬퍼로 자기 payload를 먼저 커밋한 뒤 마커를 쓰고 검증합니다. unpushed 커밋("ahead")은 공유 게이트 전반에서 차단이 아니라 notice로 강등되어(push는 자동이고 그 실패는 이미 비치명적입니다), committed-but-unpushed 종료도 마커가 써지고 `/compact`도 통과합니다. ([#130](https://github.com/sk-lim19f/Hypomnema/pull/130)
|
|
723
|
-
- 트래커 bookkeeping이 무관한 프로젝트의 `/compact`를 cross-block하지 않습니다. 전역 close 불변식이 갓 갱신된 `session-state.md`를 close 활동으로 봤는데, 일상적 트래커 bookkeeping("다음 작업"에 새 항목 미러)은 실제 세션 없이 그 날짜를 bump하므로 무관한 프로젝트의 `/compact`가 bookkeeping된 프로젝트의 완전 close를 요구하며 인질이 됐습니다. 이제 close 활동은 실제 종료가 쓰는 아티팩트(오늘 session-log 헤딩 또는 `## [today] session | P` log 항목)에서만 인식하고, soft state 파일(`session-state.md`·프로젝트 `hot.md`·루트 `hot.md` row)은 치지 않으므로 `project-create`나 hot-cache 재빌드도 세션처럼 보이지 않습니다. ([#131](https://github.com/sk-lim19f/Hypomnema/pull/131)
|
|
806
|
+
- `--apply-session-close`가 session-closed 마커를 조용히 건너뛰지 않고 기록합니다. apply는 payload 파일을 쓰고(트리가 dirty해짐) 나서 자기 write가 방금 건드린 git-clean 차단을 검사해서, 마커가 생략되고 종료가 이미 성공으로 보고된 뒤에 사용자가 `--mark-session-closed`를 손수 돌리도록 내몰렸습니다. 이제 apply는 auto-commit Stop 훅과 동일한 `.hypoignore` 인지 헬퍼로 자기 payload를 먼저 커밋한 뒤 마커를 쓰고 검증합니다. unpushed 커밋("ahead")은 공유 게이트 전반에서 차단이 아니라 notice로 강등되어(push는 자동이고 그 실패는 이미 비치명적입니다), committed-but-unpushed 종료도 마커가 써지고 `/compact`도 통과합니다. ([#130](https://github.com/sk-lim19f/Hypomnema/pull/130))
|
|
807
|
+
- 트래커 bookkeeping이 무관한 프로젝트의 `/compact`를 cross-block하지 않습니다. 전역 close 불변식이 갓 갱신된 `session-state.md`를 close 활동으로 봤는데, 일상적 트래커 bookkeeping("다음 작업"에 새 항목 미러)은 실제 세션 없이 그 날짜를 bump하므로 무관한 프로젝트의 `/compact`가 bookkeeping된 프로젝트의 완전 close를 요구하며 인질이 됐습니다. 이제 close 활동은 실제 종료가 쓰는 아티팩트(오늘 session-log 헤딩 또는 `## [today] session | P` log 항목)에서만 인식하고, soft state 파일(`session-state.md`·프로젝트 `hot.md`·루트 `hot.md` row)은 치지 않으므로 `project-create`나 hot-cache 재빌드도 세션처럼 보이지 않습니다. ([#131](https://github.com/sk-lim19f/Hypomnema/pull/131))
|
|
724
808
|
|
|
725
809
|
### Chores
|
|
726
810
|
|
|
@@ -856,7 +940,7 @@ Contributors: @sk-lim19f
|
|
|
856
940
|
|
|
857
941
|
#### English
|
|
858
942
|
|
|
859
|
-
- Update-notifier banners now actually reach the user. The SessionStart hook computed an "Update available" banner
|
|
943
|
+
- Update-notifier banners now actually reach the user. The SessionStart hook computed an "Update available" banner and a stale-sibling banner but emitted them only to **stderr** (invisible in the normal TUI on a hook that exits 0) and to `additionalContext`, which is model-only. Per the Claude Code hooks contract the user-visible channel is the top-level **`systemMessage`** field, which the hook never set, so both notices were no-ops on screen (the version cache would even mark a version "notified" against a banner nobody saw). Both banners now route to `systemMessage` (and stay in `additionalContext`, so the model and the user see the same state). This applies equally to the **npm** and **Claude marketplace (plugin)** channels: the notifier fetches the latest version for both and shows the channel-appropriate upgrade command. Scope: only the update + stale-sibling notices; the sync/growth/clear/suggest lines remain intentionally transcript-only.
|
|
860
944
|
- Plugin installs no longer double-register core hooks on `/hypo:upgrade --apply`. When Hypomnema is installed as a Claude Code **plugin**, the 15 core hooks and 14 slash commands are provided by the plugin loader (`hooks.json` + `commands/`), not copied into `~/.claude/`. `upgrade.mjs` assumed the manual/npm install model, reported ~47 items "missing", and recommended `--apply`, which copied the hooks into `~/.claude/hooks/` and registered 14 `settings.json` events, so Claude Code then ran **both** the plugin hooks and the user hooks and every hook fired **twice**. A plugin-mode guard (keyed on the running `upgrade.mjs` living under `~/.claude/plugins/`) now reports the core surface as "provided by the plugin loader", excludes it from drift, and skips copying/registering it on `--apply`. Vault extensions, the codex target (`--codex`), and `hypo-pkg.json` metadata stay managed: the metadata write is required so the runtime can resolve the package root for the PreCompact lint/feedback gates.
|
|
861
945
|
- `/hypo:resume` respects the working directory on a same-date tie. With no `--project`, `resolveActiveProject` sorted the root `hot.md` "Active Projects" rows by date only; when two projects shared the latest date, the table's top row always won regardless of where you were working. A **tie-breaker-only** cwd match (cwd ↔ each project's `session-state.md` `working_dir`, longest-prefix) now breaks same-date ties without overriding a genuinely newer non-matching project. `resume.mjs` and the mirrored `hooks/hypo-shared.mjs` are kept in sync.
|
|
862
946
|
- `resume.mjs` `--hypo-dir` header comment corrected. The comment described root resolution as a sequential `A / B / C` fallback chain, but `$HYPO_DIR` actually takes precedence and short-circuits the other steps. Pure comment fix, no runtime change.
|
|
@@ -865,7 +949,7 @@ Contributors: @sk-lim19f
|
|
|
865
949
|
|
|
866
950
|
#### 한국어
|
|
867
951
|
|
|
868
|
-
- 업데이트 notifier 배너가 이제 실제로 사용자에게 도달. SessionStart 훅이 "Update available"
|
|
952
|
+
- 업데이트 notifier 배너가 이제 실제로 사용자에게 도달. SessionStart 훅이 "Update available" 배너와 stale-sibling 배너를 계산하지만 **stderr**(exit 0 훅에선 일반 TUI에 비가시)와 모델 전용 `additionalContext`로만 출력했다. Claude Code 훅 계약상 사용자 가시 채널은 top-level **`systemMessage`**인데 훅이 이를 설정하지 않아 두 배너 모두 화면에선 무효였다(버전 캐시는 아무도 못 본 배너를 "notified"로 마킹까지 함). 두 배너를 이제 `systemMessage`로 라우팅한다(`additionalContext`에도 유지 → 모델·사용자 동기). **npm**·**Claude marketplace(plugin)** 두 채널 모두 동일 적용. notifier가 양 채널의 latest를 fetch해 채널별 업그레이드 명령을 보여준다. 범위: update + stale-sibling만, sync/growth/clear/suggest는 의도적으로 transcript 전용 유지.
|
|
869
953
|
- 플러그인 설치에서 `/hypo:upgrade --apply`가 더는 core 훅을 중복 등록하지 않음. Hypomnema를 Claude Code **플러그인**으로 설치하면 core 훅 15개·슬래시 커맨드 14개를 플러그인 로더(`hooks.json` + `commands/`)가 제공하며 `~/.claude/`로 복사되지 않는다. `upgrade.mjs`가 수동/npm 설치 모델을 가정해 ~47개를 "missing"으로 보고하고 `--apply`를 권했고 → `--apply`가 훅을 `~/.claude/hooks/`로 복사 + `settings.json` 이벤트 14개 등록 → Claude Code가 플러그인 훅과 사용자 훅을 **둘 다** 실행해 모든 훅이 **2회씩** 발화했다. 플러그인 모드 가드(실행 중 `upgrade.mjs`가 `~/.claude/plugins/` 하위인지로 판정)가 이제 core 표면을 "provided by the plugin loader"로 보고하고 drift에서 제외하며 `--apply` 시 복사·등록을 skip한다. vault extensions·codex 타깃(`--codex`)·`hypo-pkg.json` 메타데이터는 계속 관리. 메타데이터 write는 런타임이 PreCompact lint/feedback 게이트용 패키지 루트를 해석하는 데 필요.
|
|
870
954
|
- `/hypo:resume`가 동률 날짜에서 작업 디렉터리를 존중. `--project` 미지정 시 `resolveActiveProject`가 루트 `hot.md`의 "Active Projects" 행을 날짜로만 정렬해, 같은 날짜 프로젝트가 둘이면 작업 위치와 무관하게 테이블 최상단 행이 항상 선택됐다. **tie-breaker 전용** cwd 매칭(cwd ↔ 각 프로젝트 `session-state.md`의 `working_dir`, longest-prefix)이 더 최신인 비매칭 프로젝트를 덮어쓰지 않으면서 동률만 깬다. `resume.mjs`와 미러 `hooks/hypo-shared.mjs`를 동기화.
|
|
871
955
|
- `resume.mjs` `--hypo-dir` 헤더 주석 정정. 주석이 root resolution을 순차 `A / B / C` 폴백 체인처럼 기술했으나, 실제로는 `$HYPO_DIR`이 최우선이며 나머지 단계를 단락(short-circuit)한다. 순수 주석 수정, 런타임 변경 없음.
|
|
@@ -905,37 +989,37 @@ Contributors: @sk-lim19f
|
|
|
905
989
|
|
|
906
990
|
#### English
|
|
907
991
|
|
|
908
|
-
- Stale-sibling install detection: downgrade guard + PATH-CLI notice + doctor scan
|
|
992
|
+
- Stale-sibling install detection: downgrade guard + PATH-CLI notice + doctor scan. When a second, older Hypomnema sits on `$PATH` (e.g. a leftover `npm i -g hypomnema`) while a newer copy owns the active hooks, running `hypomnema init` / `upgrade --apply` through the stale bin used to **silently downgrade** the newer registered hooks (dropping features like the update-notifier). Three coordinated defenses now exist: **(P, preventive)** `init` and `upgrade --apply` refuse to overwrite a newer active install. They compare the running package version against `~/.claude/hypo-pkg.json`'s `pkgVersion` using full semver and abort with **exit 2** unless `--allow-downgrade` is passed; a dev workspace re-running its own install is exempt via realpath-equal `pkgRoot` (so the post-commit sync hook and `npm link` setups are never mis-flagged). **(D3, detective, reaches the live victim)** the SessionStart notifier resolves the `hypomnema` bin on `$PATH` (fs-only; no `npm`/`which` spawn) and warns once per `(cliPath@version → activeVersion)` tuple when it is strictly older than the active install. This is the only surface that reaches a user already stuck on the old CLI, since `hypomnema doctor` invoked via the stale bin would run the *old* doctor. **(D, detective backstop)** `hypomnema doctor` adds a `PATH CLI vs active install` check (warn + `npm uninstall -g hypomnema` remediation). Note: the in-product notifier **cannot** retroactively warn installs older than v1.2.0 (the notifier did not exist yet): that bootstrap gap is unfixable in code; the guard protects forward, and the doctor/notifier surfaces flag the stale copy on any current install.
|
|
909
993
|
- `hypomnema lint --strict` promotes selected warnings to errors. A new opt-in `--strict` flag promotes a frozen set of warning classes to errors so they exit 1: a general gate for release-checklists and opt-in pre-commit hooks. Stable warning IDs were introduced (`W1` no-frontmatter, `W2` unknown-type, `W3` missing-`updated`, `W4` broken-wikilink) alongside the pre-existing `W8` (design-history stale). `--strict` promotes `STRICT_PROMOTE_IDS = {W1, W2, W4}` (confirmed content defects) while leaving `W3` (auto-repaired by `--fix`) and `W8` (handled separately by the pre-compact hook) as warnings. Default `hypomnema lint` is **byte-identical**: only `W8` exposes an `id` in `--json` output, so existing consumers (`hooks/hypo-personal-check.mjs`) are unaffected. `npm run lint` and `prepublishOnly` keep using the default mode, and `--strict` is never auto-wired into CI.
|
|
910
|
-
- Session-close now surfaces four advisory reflections
|
|
994
|
+
- Session-close now surfaces four advisory reflections. The `/hypo:crystallize` session-close flow (exposed both as the `crystallize.md` slash command and the `crystallize` skill) now prompts you, *advisory-only*, on four points before composing the session payload: flag a trivial session and recommend skipping close (without bypassing the mandatory checklist or marking the session closed); when a non-trivial decision lacks an ADR, record `ADR 없음: <reason>` in the session-log payload (it never auto-writes an ADR file); recommend refreshing a stale `design-history.md` (silently skips when none exists, never creates one); recommend `/hypo:ingest` for trustworthy external knowledge acquired in the session (user-confirmed). Every reflection is advisory: none performs an automatic action, none bypasses a gate, none writes a file on its own. A surface-drift guard test pins both surfaces to keep the four advisories and the identity-guard contract present.
|
|
911
995
|
|
|
912
996
|
#### 한국어
|
|
913
997
|
|
|
914
|
-
- Stale-sibling 설치 감지: downgrade 가드 + PATH-CLI 노티 + doctor
|
|
998
|
+
- Stale-sibling 설치 감지: downgrade 가드 + PATH-CLI 노티 + doctor 스캔. 더 오래된 Hypomnema가 `$PATH`를 점유(예: 남아있는 `npm i -g hypomnema`)하고 더 새 사본이 active 훅을 소유한 상황에서, stale 바이너리로 `hypomnema init` / `upgrade --apply`를 돌리면 더 새 등록 훅이 **조용히 다운그레이드**(update-notifier 등 기능 제거)되던 footgun을 막는다. 세 방어를 함께 도입: **(P, 예방)** `init`·`upgrade --apply`가 실행 중 패키지 버전과 `~/.claude/hypo-pkg.json`의 `pkgVersion`을 full semver로 비교해, active가 더 새로우면 `--allow-downgrade` 없이는 **exit 2**로 거부한다. dev workspace가 자기 자신을 재실행하는 경우는 `pkgRoot` realpath 동일성으로 면제(post-commit sync 훅·`npm link` 오탐 없음). **(D3, 탐지, 현재 피해자에게 도달)** SessionStart notifier가 `$PATH`의 `hypomnema` 바이너리를 해석(fs-only, `npm`/`which` spawn 없음)해 active보다 엄격히 오래되면 `(cliPath@version → activeVersion)` 튜플당 1회 경고한다. stale 바이너리로 부른 `hypomnema doctor`는 *구버전* doctor를 돌리므로, 이미 옛 CLI에 갇힌 사용자에게 도달하는 유일한 경로다. **(D, 탐지 백스톱)** `hypomnema doctor`에 `PATH CLI vs active install` 체크 추가(warn + `npm uninstall -g hypomnema` 안내). 참고: in-product notifier는 v1.2.0 이전 설치(당시 notifier 미존재)에는 소급 경고할 수 **없다**. 이 bootstrap 갭은 코드로 수정 불가다. 가드는 앞으로를 보호하고, doctor/notifier 표면이 현재 설치에서 stale 사본을 적발한다.
|
|
915
999
|
- `hypomnema lint --strict`가 선택 warning을 error로 승격한다. opt-in `--strict` 플래그가 동결된 warning 클래스 집합을 error로 승격해 exit 1로 만든다: release-checklist / opt-in pre-commit용 범용 게이트. 안정 warning ID(`W1` no-frontmatter, `W2` unknown-type, `W3` missing-`updated`, `W4` broken-wikilink)를 기존 `W8`(design-history stale)에 더해 부여했다. `--strict`는 `STRICT_PROMOTE_IDS = {W1, W2, W4}`(확정적 콘텐츠 결함)만 승격하고, `W3`(`--fix`로 자동복구)·`W8`(pre-compact 훅이 별도 처리)은 warning으로 유지한다. 기본 `hypomnema lint`는 **byte-identical**. `--json`에서 `W8`만 `id`를 노출하므로 기존 소비자(`hooks/hypo-personal-check.mjs`)는 무영향. `npm run lint`·`prepublishOnly`는 기본 모드를 그대로 사용하며 `--strict`는 CI에 자동 배선되지 않는다.
|
|
916
|
-
- 세션-close가 네 가지 advisory 성찰을
|
|
1000
|
+
- 세션-close가 네 가지 advisory 성찰을 띄운다. `/hypo:crystallize` 세션-close 흐름(`crystallize.md` 슬래시 커맨드 + `crystallize` 스킬 양쪽)이 세션 payload 작성 전에 네 가지를 *advisory로만* 권고한다: trivial 세션이면 close 스킵 권고(필수 체크리스트 우회·세션 closed 표기는 하지 않음); 비자명 결정에 ADR이 없으면 session-log payload에 `ADR 없음: <이유>` 기록(ADR 파일을 auto-write 하지 않음); stale `design-history.md` 갱신 권고(없으면 silent skip, 생성하지 않음); 세션 중 습득한 신뢰할 만한 외부 지식에 `/hypo:ingest` 권고(user-confirm). 모든 성찰은 advisory다. 자동 동작·게이트 우회·파일 자동 작성을 하는 것은 하나도 없다. surface-drift 가드 테스트가 두 표면에 네 advisory와 identity-guard 계약 문구가 그대로 있는지 검증한다.
|
|
917
1001
|
|
|
918
1002
|
### Bug Fixes
|
|
919
1003
|
|
|
920
1004
|
#### English
|
|
921
1005
|
|
|
922
|
-
- Session-close gate no longer blocks `/compact` on lint debt this session did not create
|
|
1006
|
+
- Session-close gate no longer blocks `/compact` on lint debt this session did not create. The PreCompact gate and the crystallize apply gate both linted the *entire* vault, so unfinished session-close could be blocked by lint errors in other projects or shared pages you never touched. Each gate is now **scoped to the files this session actually touched** (the PreCompact gate to transcript-touched files ∪ the mandatory close-file targets, the apply gate to its payload files), and errors outside that scope downgrade to a non-blocking notice. A companion marker-coherence fix prevents a session from being marked closed without lint running on its own files: `--mark-session-closed --transcript-path` refuses the marker on scoped-lint failure (without `--transcript-path` it keeps the legacy freshness + clean-git recovery path), and the Stop hook surfaces the transcript path. Broken-wikilink stays `W4` warn-only (forward-references are legitimate; gating on them re-introduced friction).
|
|
923
1007
|
- `/hypo:feedback` scope validator accepts cwd-derived project ids. The shared `scope:` validator rejected the project-id shape `deriveProjectId` emits (leading dash + mixed case, e.g. `project:-Users-you-Workspace-Project`), so writing a cwd-scoped feedback page failed lint and forced a manual `--project-id=<slug>` override. A single source-of-truth `FEEDBACK_SCOPE_RE` (`scripts/lib/feedback-scope.mjs`, imported by both `lint.mjs` and `feedback.mjs`) now accepts that form while still rejecting dot-only ids (`project:.` / `project:..`); the deriver, on-disk project dirs, and string-equality projection are unchanged.
|
|
924
1008
|
|
|
925
1009
|
#### 한국어
|
|
926
1010
|
|
|
927
|
-
- 세션-close 게이트가 이 세션이 만들지 않은 lint debt로 `/compact`를 더는 막지
|
|
1011
|
+
- 세션-close 게이트가 이 세션이 만들지 않은 lint debt로 `/compact`를 더는 막지 않는다. PreCompact 게이트와 crystallize apply 게이트가 볼트 *전체*를 lint해서, 손대지도 않은 타 프로젝트·공유 페이지의 lint error로 세션-close가 막히던 버그를 수정. 이제 각 게이트는 **이 세션이 실제로 touch한 파일로 스코프**된다(PreCompact는 transcript-touched ∪ 필수 close-파일 타깃, apply는 자신의 payload 파일로). 그리고 스코프 밖 error는 non-blocking notice로 강등된다. marker-coherence 보강으로 자기 파일에 lint가 돌지 않은 채 세션이 closed로 표기되는 것을 방지: `--mark-session-closed --transcript-path`가 스코프-lint 실패 시 marker를 거부하고(`--transcript-path` 없으면 legacy freshness + clean-git 복구 경로 유지), Stop 훅이 transcript path를 노출한다. broken-wikilink는 `W4` warn-only 유지(forward-reference는 정상이며, 게이트 시 마찰 재발).
|
|
928
1012
|
- `/hypo:feedback` scope 검증기가 cwd 유래 project id를 수용한다. 공유 `scope:` 검증기가 `deriveProjectId`가 내보내는 project-id 형태(leading dash + 대소문자 혼합, 예 `project:-Users-you-Workspace-Project`)를 거부해, cwd-스코프 feedback 페이지 작성이 lint를 통과 못 하고 수동 `--project-id=<slug>` override를 강요당했다. 단일 SoT `FEEDBACK_SCOPE_RE`(`scripts/lib/feedback-scope.mjs`, `lint.mjs`·`feedback.mjs` 양쪽 import)가 이제 그 형태를 수용하되 dot-only id(`project:.` / `project:..`)는 여전히 거부한다. deriver·on-disk project 디렉터리·string-equality projection은 변경 없음.
|
|
929
1013
|
|
|
930
1014
|
### Chores
|
|
931
1015
|
|
|
932
1016
|
#### English
|
|
933
1017
|
|
|
934
|
-
- Maintainer tooling and repo hygiene (no user-facing surface change). `fix:verify` test-linkage CLI plus its `STUB_SPEC` vacuous-gate rejection and the fix-manifest evidence-only SoT + ADR-line grep gate
|
|
1018
|
+
- Maintainer tooling and repo hygiene (no user-facing surface change). `fix:verify` test-linkage CLI plus its `STUB_SPEC` vacuous-gate rejection and the fix-manifest evidence-only SoT + ADR-line grep gate; a pre-commit auto-format hook for staged files; publish-time bilingual CHANGELOG + annotated-tag enforcement (`check-bilingual.mjs`); a `feedback-sync` per-mode source-loader refactor (byte-identical golden tests); inline-comment hygiene cleanup; `actions/checkout` + `actions/setup-node` bumped to v5; and untracking of personal dev-workflow commands (`.claude/` is now fully gitignored: the repo ships only the published plugin surface). These touch dev/CI/maintainer workflows only; the installed product surface is unchanged.
|
|
935
1019
|
|
|
936
1020
|
#### 한국어
|
|
937
1021
|
|
|
938
|
-
- 메인테이너 도구·repo 위생 (사용자 대상 표면 변경 없음). `fix:verify` test-linkage CLI와 그 `STUB_SPEC` vacuous-gate 거부, fix-manifest evidence-only SoT + ADR-line grep
|
|
1022
|
+
- 메인테이너 도구·repo 위생 (사용자 대상 표면 변경 없음). `fix:verify` test-linkage CLI와 그 `STUB_SPEC` vacuous-gate 거부, fix-manifest evidence-only SoT + ADR-line grep 게이트, staged 파일용 pre-commit auto-format 훅, publish 시점 bilingual CHANGELOG + annotated-tag 강제(`check-bilingual.mjs`), `feedback-sync`의 per-mode source-loader 리팩터(byte-identical golden 테스트), inline-comment 위생 정리, `actions/checkout`·`actions/setup-node` v5 bump, 개인 dev-workflow 커맨드 untrack(`.claude/`를 완전히 gitignore: repo는 published plugin 표면만 ship). 모두 dev/CI/maintainer 워크플로만 건드리며 설치되는 제품 표면은 동일하다.
|
|
939
1023
|
|
|
940
1024
|
### Changelog
|
|
941
1025
|
|
|
@@ -952,7 +1036,7 @@ Contributors: @sk-lim19f
|
|
|
952
1036
|
- [#80](https://github.com/sk-lim19f/Hypomnema/pull/80) scope session-close lint to touched files + coherent marker gate
|
|
953
1037
|
- [#81](https://github.com/sk-lim19f/Hypomnema/pull/81) stale-sibling install detection (downgrade guard + PATH-CLI notice + doctor scan)
|
|
954
1038
|
- [#82](https://github.com/sk-lim19f/Hypomnema/pull/82) fix-manifest SoT + ADR-line grep + bare-anchor gate
|
|
955
|
-
- [#83](https://github.com/sk-lim19f/Hypomnema/pull/83) session-close advisory reflections
|
|
1039
|
+
- [#83](https://github.com/sk-lim19f/Hypomnema/pull/83) session-close advisory reflections
|
|
956
1040
|
- [#84](https://github.com/sk-lim19f/Hypomnema/pull/84) document claude-worker HOME-isolation limits
|
|
957
1041
|
- [#85](https://github.com/sk-lim19f/Hypomnema/pull/85) untrack personal dev-workflow commands; fully gitignore .claude/
|
|
958
1042
|
- [#86](https://github.com/sk-lim19f/Hypomnema/pull/86) prepare v1.3.0 (bump version + reconcile CHANGELOG)
|
|
@@ -992,7 +1076,7 @@ Contributors: @sk-lim19f
|
|
|
992
1076
|
## [1.2.0] - 2026-05-24
|
|
993
1077
|
|
|
994
1078
|
> [!IMPORTANT]
|
|
995
|
-
> **`SCHEMA.md` version 2.0: `feedback` page type now requires 9 hard fields (
|
|
1079
|
+
> **`SCHEMA.md` version 2.0: `feedback` page type now requires 9 hard fields (PR [#60](https://github.com/sk-lim19f/Hypomnema/pull/60)).** Pages of `type: feedback` must declare `status`, `scope`, `tier`, `targets`, `sensitivity`, `priority`, `memory_summary`, `reason`, `source`. When `targets` includes `claude-learned`, the page must additionally be `scope: global` + `tier: L1` and declare `global_summary` + `promote_to_global: true`. `hypomnema upgrade --apply` now writes `MIGRATION-v2.0.md` into the wiki root with a manual-backfill checklist; the upgrade deliberately does NOT auto-stub the fields because wrong defaults for `scope` / `tier` / `targets` / `sensitivity` / `reason` / `source` would silently project wrong behavior. `SCHEMA.md` itself remains user-owned and byte-equal across upgrade (Option C, preserved by PR [#57](https://github.com/sk-lim19f/Hypomnema/pull/57)'s invariants). The migration report also carries the `project-id` ↔ slug regex caveat from PR [#59](https://github.com/sk-lim19f/Hypomnema/pull/59): to use `scope: project:*` in v1.2.0 you must `--project-id=<slug>` override.
|
|
996
1080
|
|
|
997
1081
|
> [!IMPORTANT]
|
|
998
1082
|
> **SCHEMA 2.0: `feedback` page 9 hard 필드 + claude-learned conditional 2 필드 강제.** `hypomnema upgrade --apply` 시 `MIGRATION-v2.0.md`가 자동 작성되어 backfill checklist 제공. `SCHEMA.md`는 사용자 소유 (Option C 보존, byte-equal). 자동 stub은 거부. `scope` / `tier` / `targets` / `sensitivity` / `reason` / `source`는 의미 결정이라 wrong default가 wrong behavior로 이어짐.
|
|
@@ -1003,14 +1087,14 @@ Contributors: @sk-lim19f
|
|
|
1003
1087
|
|
|
1004
1088
|
- `lint` emits `W8` design-history-stale warning. The PreCompact hook (`hypo-personal-check.mjs`) has filtered `lint --json` warns for `id === 'W8'` since the initial OSS hook drop, but `scripts/lint.mjs` never emitted that id: so `design-history.md` aging next to a fresher `session-log.md` (or `session-log/YYYY-MM.md` directory layout) was silently invisible to the gate. Lint now runs `findDesignHistoryStale()` once per project (outside the page loop), and emits a `W8`-tagged warn per stale project with a POSIX-separated `file` literal (`projects/<name>/design-history.md`) so the consumer's `file.split('/')` contract stays portable. The JSON `warn` shape gains an optional `id` field, omitted for legacy id-less warns.
|
|
1005
1089
|
- Update notifier. The SessionStart hook now shows an "Update available!" banner when a newer Hypomnema version has been published, detecting both distribution channels (npm package and Claude Code plugin) and printing the channel-appropriate update command (`npm install -g hypomnema`, or `/plugin marketplace update hypomnema` + `/reload-plugins`). The check never blocks session start: the hook reads a 24-hour cache only, and a detached worker refreshes it out-of-band, so a newer version surfaces from the next session. Per-channel notification state prevents the same banner from repeating, and `current >= latest` (local dev) is silently skipped. Opt out with `HYPO_NO_UPDATE_CHECK`, `NO_UPDATE_NOTIFIER`, or `CI`.
|
|
1006
|
-
- `feedback`-as-source-of-truth + one-way projections to MEMORY / `<learned_behaviors>` (
|
|
1007
|
-
- Extensions companion sync (
|
|
1090
|
+
- `feedback`-as-source-of-truth + one-way projections to MEMORY / `<learned_behaviors>` (PR [#36](https://github.com/sk-lim19f/Hypomnema/pull/36)). A new `pages/feedback/<slug>.md` page type replaces ad-hoc human-side sync of behavior corrections across three storage surfaces. `hypomnema feedback-sync` derives `~/.claude/projects/<project-id>/memory/MEMORY.md` (200-line cap) and `~/.claude/CLAUDE.md` `<learned_behaviors>` (max 10 entries, strict gate: `scope:global` + `tier:L1` + `targets:claude-learned` + `promote_to_global:true` + `sensitivity ∈ {public, sanitized}`) from the wiki. Managed blocks are marker- and hash-fenced; hand-edits are flagged as `CONFLICT_MANUAL_EDIT`. PreCompact integration runs inside `hypo-personal-check` (single-blocking-gate invariant). `sensitivity: private` is forbidden: the wiki is git-pushed; private data must stay outside the wiki entirely. `/hypo:feedback` slash command writes pages directly; `hypomnema feedback-sync --bootstrap` scaffolds drafts from existing MEMORY/CLAUDE state under `pages/feedback/_drafts/` for human review.
|
|
1091
|
+
- Extensions companion sync (PRs [#42](https://github.com/sk-lim19f/Hypomnema/pull/42)~[#47](https://github.com/sk-lim19f/Hypomnema/pull/47)). A new `extensions/` taxonomy in the wiki (`agents/`, `commands/`, `hooks/`, `skills/`) lets users ship Claude Code / Codex companion files alongside their wiki. `hypomnema init` scaffolds the directory; `hypomnema upgrade` mirrors the inventory into `~/.claude/` and (with `--codex`) **only the `hooks` and `commands` subset** into `~/.codex/` (agents/skills are Claude-only and skipped on the Codex target by design, see `scripts/lib/extensions.mjs` `CODEX_TYPES`). Conflict detection (`--force-extensions` to overwrite), and `hypomnema doctor extensions` audits integrity (orphan duplicates, matcher drift, non-registrable orphans). `hypomnema uninstall` cleans up the companion files. PR [#49](https://github.com/sk-lim19f/Hypomnema/pull/49) added settings.json mixed-group surgical write so settings.json edits stay minimal and merge-friendly.
|
|
1008
1092
|
- `hypomnema upgrade --codex` mirrors core hooks (PR [#50](https://github.com/sk-lim19f/Hypomnema/pull/50)). `init --codex` has always installed Hypomnema's core hooks into `~/.codex/hooks/` and registered them in `~/.codex/settings.json`, but `upgrade` only mirrored user extensions: so a v1.1.x → v1.2.0 codex user's core hooks stayed stale until a fresh install. The flag now drives drift detection, hook-file apply, settings.json registration, and the `wiki-*.mjs → hypo-*.mjs` rename migration on both targets in one pass. The human-readable report labels the two blocks ("Hook files (codex)", "settings.json (codex)") and JSON output gains `hooksCodex` / `settingsCodex` / `oldHookRefsCodex` plus matching `applied.*Codex` keys. Without `--codex` nothing under `~/.codex/` is inspected (parity with the existing extensions behaviour).
|
|
1009
|
-
- `hypomnema upgrade` v1→v2 migration report (
|
|
1093
|
+
- `hypomnema upgrade` v1→v2 migration report (PR [#60](https://github.com/sk-lim19f/Hypomnema/pull/60)). Major SCHEMA bump now writes `MIGRATION-v2.0.md` into the wiki root with v1→v2-specific guidance: all 9 unconditional `feedback` fields, the conditional `claude-learned` set, the explicit no-auto-stub policy, the "fix existing pages before `/hypo:feedback` append" warning, the PR [#59](https://github.com/sk-lim19f/Hypomnema/pull/59) `project-id` ↔ slug regex caveat, and a closing re-run-lint checklist. Other major jumps keep the original generic body. PR [#57](https://github.com/sk-lim19f/Hypomnema/pull/57) invariants preserved: `SCHEMA.md` is byte-equal after `--apply` (Option C), report tag stays `[schema]` (the only token historically valid across all shipped Meta vocabularies).
|
|
1010
1094
|
- PostToolUse WebFetch / WebSearch auto-ingest signal (PR [#48](https://github.com/sk-lim19f/Hypomnema/pull/48)). When Claude resolves a URL via WebFetch or runs WebSearch, the PostToolUse hook injects a nudge in `hookSpecificOutput.additionalContext` so Claude considers running `/hypo:ingest`. URL query/hash tokens and userinfo (`user:pass@host`) are stripped before injection. Non-HTTP schemes (`file://`, `ftp://`, `data:`) and missing URLs are silent skips. Opt out with `HYPO_SKIP_GATE=1`. Fail-open on invalid JSON stdin; stderr carries the unified `[hypo-web-fetch-ingest] error:` tag.
|
|
1011
|
-
- Stop-chain auto-minimal-crystallize (
|
|
1095
|
+
- Stop-chain auto-minimal-crystallize (PR [#34](https://github.com/sk-lim19f/Hypomnema/pull/34)). A session that crossed a "non-trivial" threshold now offers (and on `Y` runs) `/hypo:crystallize --apply-session-close --minimal` automatically from the Stop hook chain. Combined with PR [#31](https://github.com/sk-lim19f/Hypomnema/pull/31)~[#33](https://github.com/sk-lim19f/Hypomnema/pull/33) `/clear` detection and SessionEnd marker / SessionStart `source=clear` recovery, the personal-check gate now catches forgotten session closes and reopens cleanly when the user runs `/clear`.
|
|
1012
1096
|
- `crystallize --apply-session-close` programmatic entrypoint (PRs [#21](https://github.com/sk-lim19f/Hypomnema/pull/21), [#23](https://github.com/sk-lim19f/Hypomnema/pull/23)~[#26](https://github.com/sk-lim19f/Hypomnema/pull/26)). Strict 11-step session-close validation (PreCompact hard gate + crystallize). `--payload <json>` and `--apply-session-close` make the path machine-callable from the Stop hook chain; `--probe` early-exit (option D) keeps no-op closes fast. Lint preflight + post-apply gate ensures the wiki ends up clean.
|
|
1013
|
-
- Auto-project creation on cwd match (
|
|
1097
|
+
- Auto-project creation on cwd match (PR [#41](https://github.com/sk-lim19f/Hypomnema/pull/41)). When you start a session (or change directory) inside a git repository that carries a project marker (`package.json`, `Cargo.toml`, `go.mod`, `pyproject.toml`, `pom.xml`, `build.gradle`, `composer.json`, `Gemfile`) but matches no existing wiki project's `working_dir`, the SessionStart/CwdChanged hook now offers to create one. The offer is a nudge only; on "Y" Claude runs the new internal scaffold helper (`scripts/lib/project-create.mjs`) which materializes the project from `templates/projects/_template/` with token substitution, adds the root `hot.md` pointer row, and logs the creation. On "N" the cwd is recorded under `skips[]` in `.cache/project-suggestions.json` and never offered again (a 5-minute per-cwd cooldown also suppresses repeats within a session). Temp and marker-less directories never trigger the offer. `hypomnema doctor` validates the skip-persistence file's schema. The deprecated `hypomnema project new` subcommand is not introduced. PR [#41](https://github.com/sk-lim19f/Hypomnema/pull/41) also strengthens the templated Session Start guidance: the first response must lead with a resume summary.
|
|
1014
1098
|
- First-prompt resume summary + cwd-change re-trigger (PR [#39](https://github.com/sk-lim19f/Hypomnema/pull/39)). SessionStart's resume nudge now forces the resume summary on the first response, and a cwd change inside the session re-triggers the project match check (so opening a new repo without restarting Claude still picks up the right project).
|
|
1015
1099
|
- `weekly-report` migrates output to `journal/weekly/<YYYY-Www>.md` (PR [#29](https://github.com/sk-lim19f/Hypomnema/pull/29)). Single source of truth per spec §6.4. Old report locations are no longer written.
|
|
1016
1100
|
- Lint type-conditional fields + tag vocabulary lock (PRs [#28](https://github.com/sk-lim19f/Hypomnema/pull/28), [#38](https://github.com/sk-lim19f/Hypomnema/pull/38)). Lint now enforces per-type required fields and rejects unknown tags (vocabulary outside SCHEMA `Tag Vocabulary`). PR [#38](https://github.com/sk-lim19f/Hypomnema/pull/38) adds `B6` warn for `pages/` subdirs absent from SCHEMA taxonomy.
|
|
@@ -1019,10 +1103,10 @@ Contributors: @sk-lim19f
|
|
|
1019
1103
|
|
|
1020
1104
|
#### 한국어
|
|
1021
1105
|
|
|
1022
|
-
- `feedback`-as-SoT + 단방향 projection
|
|
1023
|
-
- Extensions companion sync
|
|
1024
|
-
- Auto-project creation on cwd match
|
|
1025
|
-
- Stop-chain auto-minimal-crystallize + `/clear` 감지 + SessionEnd marker
|
|
1106
|
+
- `feedback`-as-SoT + 단방향 projection: `pages/feedback/<slug>.md`가 행동 교정의 단일 source-of-truth. `hypomnema feedback-sync`로 MEMORY.md (cwd-scoped, 200줄 cap) + CLAUDE.md `<learned_behaviors>` (max 10, 엄격 게이트) 자동 동기.
|
|
1107
|
+
- Extensions companion sync: wiki에 `extensions/{agents,commands,hooks,skills}` 동봉. init/upgrade가 `~/.claude/` (+`--codex`로 `~/.codex/`) 미러링, conflict 감지, doctor 무결성 검사.
|
|
1108
|
+
- Auto-project creation on cwd match: git project marker 있는 cwd에 wiki project 없으면 SessionStart에서 생성 권유.
|
|
1109
|
+
- Stop-chain auto-minimal-crystallize + `/clear` 감지 + SessionEnd marker 복구: session 종료 누락 시 자동 minimal crystallize 권유, `/clear` 후 재시작 시 깔끔 복구.
|
|
1026
1110
|
- Update notifier: SessionStart에서 신규 버전 알림 (npm 패키지 / Claude Code plugin 두 채널), opt out: `HYPO_NO_UPDATE_CHECK` / `NO_UPDATE_NOTIFIER` / `CI`.
|
|
1027
1111
|
- PostToolUse WebFetch / WebSearch auto-ingest 신호: URL fetch 시 `/hypo:ingest` 권유 nudge 자동 주입 (privacy redaction 포함).
|
|
1028
1112
|
|
|
@@ -1031,9 +1115,9 @@ Contributors: @sk-lim19f
|
|
|
1031
1115
|
#### English
|
|
1032
1116
|
|
|
1033
1117
|
- `doctor` orphan duplicate scan + matcher drift surfacing (PRs [#53](https://github.com/sk-lim19f/Hypomnema/pull/53)~[#56](https://github.com/sk-lim19f/Hypomnema/pull/56), PR [#54](https://github.com/sk-lim19f/Hypomnema/pull/54) follow-ups). `doctor extensions` now surfaces non-registrable orphans, gated `matcher:""` specific message on `hookExact`, and reports orphan duplicate counts. `parseManifest` handles empty matcher; the canonical-pick mirror keeps the doctor view aligned with the actual registered hook.
|
|
1034
|
-
- `extensions` settings.json mixed-group surgical write (PR [#49](https://github.com/sk-lim19f/Hypomnema/pull/49)
|
|
1118
|
+
- `extensions` settings.json mixed-group surgical write (PR [#49](https://github.com/sk-lim19f/Hypomnema/pull/49)). Edits to `settings.json` for extensions registration are now surgical inside mixed groups, leaving siblings + matcher in the source group exactly as found.
|
|
1035
1119
|
- `crystallize --apply-session-close` lint preflight + post-apply gate (PR [#25](https://github.com/sk-lim19f/Hypomnema/pull/25)). Lint runs before AND after the apply to fail loudly on dirty input or post-write drift.
|
|
1036
|
-
- PreCompact `/clear` detection + SessionEnd marker recovery (PRs [#31](https://github.com/sk-lim19f/Hypomnema/pull/31)~[#33](https://github.com/sk-lim19f/Hypomnema/pull/33) + amendments
|
|
1120
|
+
- PreCompact `/clear` detection + SessionEnd marker recovery (PRs [#31](https://github.com/sk-lim19f/Hypomnema/pull/31)~[#33](https://github.com/sk-lim19f/Hypomnema/pull/33) + amendments). `compact-guard` detects `/clear` so it does not block; `personal-check` capacity bypass removed ([#32](https://github.com/sk-lim19f/Hypomnema/pull/32)); SessionEnd marker + SessionStart `source=clear` recovery makes /clear-then-restart cleanup work end-to-end.
|
|
1037
1121
|
- Test hermeticity: child HOME isolation in `tests/runner.mjs` (PR [#30](https://github.com/sk-lim19f/Hypomnema/pull/30)). Tests no longer rely on the dev's real `$HOME`; child processes get an isolated home so external writes can't pollute or break the suite.
|
|
1038
1122
|
- `withWiki()` fixture date local-time alignment (PR [#52](https://github.com/sk-lim19f/Hypomnema/pull/52)). UTC vs local boundary flake removed.
|
|
1039
1123
|
|
|
@@ -1048,7 +1132,7 @@ Contributors: @sk-lim19f
|
|
|
1048
1132
|
|
|
1049
1133
|
#### English
|
|
1050
1134
|
|
|
1051
|
-
- `feedback-sync` MEMORY projection is now strictly cwd-scoped (
|
|
1135
|
+
- `feedback-sync` MEMORY projection is now strictly cwd-scoped (PR [#59](https://github.com/sk-lim19f/Hypomnema/pull/59)). `memoryTarget.filter` previously accepted any `scope: project:*` page regardless of the resolved project-id, so a `scope: project:other` page was silently projected into `~/.claude/projects/<this-project>/memory/`. The filter is now `scope === 'global' || scope === \`project:${projectId}\`` (exact match). `templates/SCHEMA.md` §3.1 and `commands/feedback.md` `--scope` flag clarify that `<project-id>` must exact-match the resolved project-id (default: `cwd → '/'.'.' → '-'`; or `--project-id=<id>` override). Mismatch = silent MEMORY skip (not a lint error). The lint regex `^project:[a-z0-9][a-z0-9-]*$` and the default cwd-derived id are incompatible: to use a `project:*` scope you must `--project-id=<slug>` override. Full resolved-id ↔ wiki-slug reconciliation is deferred to v1.3.0.
|
|
1052
1136
|
- `hypomnema upgrade` migration report tag historical regression fix (PR [#57](https://github.com/sk-lim19f/Hypomnema/pull/57)). `writeMigrationReport()` previously emitted `tags: [hypomnema, migration, schema]`, but the v1.0 / v1.1 historical Meta vocab is `wiki, index, operations, guide, schema`: neither `hypomnema` nor `migration` are present. Because Option C deliberately does NOT touch the user's `SCHEMA.md`, a v1.0 / v1.1 user upgrading would have a lint-failing page created at the wiki root. Tag tightened to `[schema]` (the only token historically valid). Added two regression tests: `--apply leaves user SCHEMA.md byte-equal` (Option C contract) and `--apply migration report tags are all in installed SCHEMA vocab` (vocab-level assertion, with the installed Meta vocab back-dated to the oldest shipped set). Also clarified `upgrade.mjs` dry-run wording and removed the self-referential "Run /hypo:upgrade --apply" action item from the report body.
|
|
1053
1137
|
- Unified `[hypo-<name>] error:` stderr log tag across all lifecycle hooks (PR [#40](https://github.com/sk-lim19f/Hypomnema/pull/40)). Every hook (`hypo-cwd-change`, `hypo-first-prompt`, `hypo-compact-guard`, `hypo-file-watch`, `hypo-lookup`, `hypo-personal-check`, `hypo-auto-minimal-crystallize`, `hypo-auto-stage`, `hypo-web-fetch-ingest`) emits its forced-catch path with the same `[hypo-<name>] error: ...` prefix so dogfood log triage is grep-friendly.
|
|
1054
1138
|
- Prettier setup + format pass (chore commits `dbc228f`, `4dac33c`, `4696abf`). Repository-wide Prettier config + `npm run format` / `format:check` scripts. `.git-blame-ignore-revs` for the reformat commit so `git blame` stays clean.
|
|
@@ -1056,7 +1140,7 @@ Contributors: @sk-lim19f
|
|
|
1056
1140
|
|
|
1057
1141
|
#### 한국어
|
|
1058
1142
|
|
|
1059
|
-
- `feedback-sync` MEMORY cross-project pollution fix (PR [#59](https://github.com/sk-lim19f/Hypomnema/pull/59)
|
|
1143
|
+
- `feedback-sync` MEMORY cross-project pollution fix (PR [#59](https://github.com/sk-lim19f/Hypomnema/pull/59)): `scope: project:*` exact-match 강제.
|
|
1060
1144
|
- `hypomnema upgrade` migration report tag historical regression fix (PR [#57](https://github.com/sk-lim19f/Hypomnema/pull/57)): tag `[schema]`로 좁힘. v1.0/v1.1 historical vocab에 있는 유일 안전 토큰.
|
|
1061
1145
|
- Code comment rot cleanup Phase 1. 13 files comment-only diff. `fix #NN` / `PR #NN follow-up` 등 시간에 따라 stale 되는 참조 제거, ADR / contract / spec anchor 보존.
|
|
1062
1146
|
|