hypomnema 1.4.2 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.ko.md +35 -18
- package/README.md +25 -8
- package/commands/audit.md +2 -2
- package/commands/crystallize.md +22 -14
- package/commands/doctor.md +1 -1
- package/commands/feedback.md +2 -2
- package/commands/graph.md +1 -1
- package/commands/ingest.md +1 -1
- package/commands/init.md +2 -2
- package/commands/lint.md +1 -1
- package/commands/query.md +1 -1
- package/commands/rename.md +1 -1
- package/commands/resume.md +1 -1
- package/commands/stats.md +1 -1
- package/commands/uninstall.md +4 -2
- package/commands/upgrade.md +1 -1
- package/commands/verify.md +1 -1
- package/docs/ARCHITECTURE.md +4 -4
- package/docs/CONTRIBUTING.md +8 -7
- package/hooks/hypo-auto-commit.mjs +2 -2
- package/hooks/hypo-auto-minimal-crystallize.mjs +7 -7
- package/hooks/hypo-compact-guard.mjs +2 -2
- package/hooks/hypo-cwd-change.mjs +27 -37
- package/hooks/hypo-lookup.mjs +37 -2
- package/hooks/hypo-personal-check.mjs +37 -22
- package/hooks/hypo-session-end.mjs +1 -1
- package/hooks/hypo-session-record.mjs +2 -2
- package/hooks/hypo-session-start.mjs +62 -42
- package/hooks/hypo-shared.mjs +430 -85
- package/hooks/version-check.mjs +1 -1
- package/package.json +5 -1
- package/scripts/check-tracker-ids.mjs +69 -31
- package/scripts/crystallize.mjs +151 -53
- package/scripts/doctor.mjs +7 -7
- package/scripts/feedback-sync.mjs +5 -5
- package/scripts/feedback.mjs +9 -10
- package/scripts/init.mjs +7 -7
- package/scripts/lib/check-tracker-ids.mjs +90 -32
- package/scripts/lib/design-history-stale.mjs +1 -1
- package/scripts/lib/extensions.mjs +7 -7
- package/scripts/lib/failure-type.mjs +1 -1
- package/scripts/lib/feedback-scope.mjs +1 -1
- package/scripts/lib/page-usage.mjs +141 -0
- package/scripts/lib/project-create.mjs +2 -2
- package/scripts/lib/template-schema-version.mjs +1 -1
- package/scripts/lib/wd-match.mjs +181 -0
- package/scripts/lib/wikilink.mjs +1 -1
- package/scripts/lint.mjs +5 -5
- package/scripts/rename.mjs +1 -1
- package/scripts/resume.mjs +20 -22
- package/scripts/session-audit.mjs +1 -1
- package/scripts/stats.mjs +3 -3
- package/scripts/uninstall.mjs +3 -3
- package/scripts/upgrade.mjs +85 -18
- package/skills/crystallize/SKILL.md +17 -11
- package/skills/graph/SKILL.md +3 -3
- package/skills/ingest/SKILL.md +5 -5
- package/skills/lint/SKILL.md +3 -3
- package/skills/query/SKILL.md +3 -3
- package/skills/verify/SKILL.md +3 -3
- package/templates/SCHEMA.md +1 -1
- package/templates/hypo-config.md +1 -1
- package/templates/hypo-guide.md +21 -15
- package/templates/projects/_template/hot.md +1 -1
- package/scripts/fix-status-verify.mjs +0 -256
- package/scripts/lib/adr-corpus.mjs +0 -79
- package/scripts/lib/fix-manifest.mjs +0 -109
- package/scripts/lib/fix-status-verify.mjs +0 -439
|
@@ -11,14 +11,14 @@ When invoked to close a session — via an explicit close signal ("세션 종료
|
|
|
11
11
|
|
|
12
12
|
## What this does
|
|
13
13
|
|
|
14
|
-
- **Close mode**: walks the checklist (session-state, project hot.md, root hot.md, session-log, open-questions(변경 시), log.md) plus a lint step, then writes via `
|
|
14
|
+
- **Close mode**: walks the checklist (session-state, project hot.md, root hot.md, session-log, open-questions(변경 시), log.md) plus a lint step, then writes via `/hypo:crystallize` in `--apply-session-close --payload=<path>` mode — which runs the lint gate automatically, **scoped to the files it writes** (debt elsewhere is a non-blocking notice). `--check-session-close` is a read-only dry-run of the **full** PreCompact gate: close files + scoped lint + design-history + feedback projection, sharing one function (`precompactGateStatus`) with the gate. A green check means no gate blocker needs a human fix, so it is the signal to declare the session closed (pass `--transcript-path` to widen the lint scope to this session's edited files exactly as the interactive hook does). It is not a hard guarantee: the live `/compact` can still differ on a context-≥70% prompt, `HYPO_SKIP_GATE`, or a transcript-scoped lint error the check did not see.
|
|
15
15
|
- **Synthesis mode**: finds tag clusters (≥ N pages), orphan pages (no outbound `[[wikilinks]]`), and draft / stub pages, then guides consolidation into `pages/syntheses/<topic>.md` with back-links and `index.md` updates.
|
|
16
16
|
|
|
17
17
|
---
|
|
18
18
|
|
|
19
19
|
## Step 1 — Locate package root
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
Bundled scripts here run via `${CLAUDE_PLUGIN_ROOT}/scripts/`. To resolve that package root: if `${CLAUDE_PLUGIN_ROOT}` is already an absolute path, use it; otherwise read `pkgRoot` from `~/.claude/hypo-pkg.json` (only when non-empty and the target script exists under it); otherwise use the `hypo@hypomnema` (or legacy `hypomnema@hypomnema`) installPath in `~/.claude/plugins/installed_plugins.json`; if none resolve, stop and tell the user to run `hypomnema upgrade --apply` or reinstall instead of guessing the cache layout.
|
|
22
22
|
|
|
23
23
|
If the user specified a wiki directory, pass it as `--wiki-dir="<path>"`. Otherwise omit the flag and the script resolves the wiki root automatically via `HYPO_DIR` → `hypo-config.md` scan → `~/hypomnema`.
|
|
24
24
|
|
|
@@ -27,7 +27,7 @@ If the user specified a wiki directory, pass it as `--wiki-dir="<path>"`. Otherw
|
|
|
27
27
|
## Step 2 — Run crystallize scan
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
|
-
node
|
|
30
|
+
node ${CLAUDE_PLUGIN_ROOT}/scripts/crystallize.mjs \
|
|
31
31
|
[--wiki-dir="<path>"] \
|
|
32
32
|
[--min-group=<n>] \
|
|
33
33
|
[--json]
|
|
@@ -47,7 +47,7 @@ If `/hypo:crystallize` was invoked as a session-close action, run through this c
|
|
|
47
47
|
|
|
48
48
|
### Advisory reflections (run before the checklist below — advisory only)
|
|
49
49
|
|
|
50
|
-
Surface each of these four to the user first. Every one is **advisory** (
|
|
50
|
+
Surface each of these four to the user first. Every one is **advisory** (identity guard): the user confirms or declines, and none performs an automatic action, writes a file on its own, or bypasses the mandatory gate.
|
|
51
51
|
|
|
52
52
|
- **Trivial-session check (#44)** — Was this session trivial (a single bug fix, a single-file edit, or Q&A with no durable artifact)? If so, recommend skipping session-close: *"이 세션은 trivial해 보입니다 — session-close를 건너뛸까요?"* A trivial skip is a recommendation, **not** a bypass: it must not mark the session closed, must not run `--mark-session-closed`, and must not claim `/compact` can pass. Any real close still requires all 5 mandatory files.
|
|
53
53
|
- **ADR-candidate check (#41)** — Did this session make an architectural or design decision (a new pattern, a tradeoff, a convention)? If yes, ask whether it warrants an ADR and capture that intent in the session-log entry. If nothing rose to ADR level, you may record the literal marker `ADR 없음 — <one-line reason>` in that same session-log entry — but gate it on #42's bar, not this one: the marker is machine-read and W8 treats a session-log entry carrying `ADR 없음` (and no ADR reference) as a *no-design* session, excluding it from the design-history staleness check. So write `ADR 없음` only when the session had no design change at all. If it had a sub-ADR design shift (background / tradeoff / differentiation), append to design-history (#42a) instead — writing the marker there would suppress the W8 nudge that shift needs. **Never auto-write an ADR file** — the session-log note is the only action here.
|
|
@@ -67,11 +67,11 @@ When uncertain, surface the question rather than skip it. None of the four block
|
|
|
67
67
|
After completing the checklist, verify it before reporting:
|
|
68
68
|
|
|
69
69
|
```bash
|
|
70
|
-
node
|
|
70
|
+
node ${CLAUDE_PLUGIN_ROOT}/scripts/crystallize.mjs --check-session-close [--hypo-dir="<path>"]
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
-
This runs the **full** PreCompact gate via the shared `precompactGateStatus
|
|
74
|
-
|
|
73
|
+
This runs the **full** PreCompact gate via the shared `precompactGateStatus`:
|
|
74
|
+
close files (`missing` / `stale`) plus lint blockers, stale
|
|
75
75
|
design-history, and feedback projection over-cap/conflict. Fix every `✗` it
|
|
76
76
|
reports and re-run until it prints **"Compact-ready"** — that is the signal the
|
|
77
77
|
session is closed. A close-files-only pass is not enough; the real `/compact`
|
|
@@ -92,7 +92,9 @@ main conversation id. Passing the wrong id causes `markerWritten: false` with
|
|
|
92
92
|
`markerSkipReason: "transcript-unresolved"` or `"no-user-close-signal"`: the
|
|
93
93
|
5 mandatory files are written (ok: true) but the Stop-chain marker is withheld,
|
|
94
94
|
so the session is not actually closed and the Stop hook re-prompts. The correct
|
|
95
|
-
id comes from the `[WIKI_AUTOCLOSE]` block reason or
|
|
95
|
+
id comes from the `[WIKI_AUTOCLOSE]` block reason or the injected
|
|
96
|
+
`$CLAUDE_CODE_SESSION_ID` (accept the legacy spelling via
|
|
97
|
+
`${CLAUDE_CODE_SESSION_ID:-$CLAUDE_SESSION_ID}`).
|
|
96
98
|
|
|
97
99
|
Once it passes, report each item with ✓:
|
|
98
100
|
- ✓ session-state.md
|
|
@@ -100,11 +102,15 @@ Once it passes, report each item with ✓:
|
|
|
100
102
|
- ✓ session-log entry
|
|
101
103
|
- ✓ open-questions (or skipped if unchanged)
|
|
102
104
|
- ✓ log.md entry
|
|
103
|
-
- **marker written?** (required, if `--apply-session-close --session-id` was used): check `markerWritten` in the JSON output. If `true`, report "session-close marker written." If `false`, do NOT declare the session closed or complete
|
|
105
|
+
- **marker written?** (required, if `--apply-session-close --session-id` was used): check `markerWritten` in the JSON output. If `true`, report "session-close marker written." If `false`, do NOT declare the session closed or complete; recover per the `markerSkipReason` branch below.
|
|
104
106
|
|
|
105
107
|
If `markerWritten: true` (or `--session-id` was not passed), ask: "Session closed. Would you like to also run knowledge synthesis now, or stop here?"
|
|
106
108
|
|
|
107
|
-
If `markerWritten: false`, do NOT say "session closed."
|
|
109
|
+
If `markerWritten: false`, do NOT say "session closed." Branch on `markerSkipReason`:
|
|
110
|
+
|
|
111
|
+
- `no-user-close-signal`: files applied cleanly and the transcript resolved, but it carries no close phrase the gate recognizes (the user's close wording fell outside the close-signal set, e.g. "세션 마무리까지 진행해줘" / "세션 마무리 진행"). Re-running the same id will not help. Confirm intent once with `AskUserQuestion` (header "세션", one option **세션 마무리**); if the user picks it, that answer is a recognized close signal, so re-run the same `--apply-session-close … --session-id` command (idempotent no-op writes; the marker lands). If the user declines, leave the session unmarked. Do NOT change the close-signal matcher.
|
|
112
|
+
- `transcript-unresolved` (wrong / background id): report "Files applied and verified (ok: true), but the marker was not written (reason: `<markerSkipReason>`). The Stop-chain is still active. Re-run with the correct main-conversation `--session-id`."
|
|
113
|
+
- any other reason (`compact-gate-not-ok`, `commit-failed: …`, `marker-did-not-land`): surface it verbatim and resolve the underlying blocker before re-running.
|
|
108
114
|
|
|
109
115
|
---
|
|
110
116
|
|
|
@@ -141,4 +147,4 @@ evidence_strength: inferred
|
|
|
141
147
|
|
|
142
148
|
---
|
|
143
149
|
|
|
144
|
-
> **Citation convention.** When you reference a wiki page in your response, link it as `[[page-slug]]
|
|
150
|
+
> **Citation convention.** When you reference a wiki page in your response, link it as `[[page-slug]]` so it stays connected in the graph. The observability audit scores sessions on search / ingest / feedback activity (recorded by `hypo-session-record`), not on these inline citations; run `/hypo:audit` to inspect and see [[pages/observability/_index]].
|
package/skills/graph/SKILL.md
CHANGED
|
@@ -14,7 +14,7 @@ You are running `/hypo:graph`. Build a wikilink dependency graph from all pages
|
|
|
14
14
|
|
|
15
15
|
## Step 1 — Locate package root
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
Bundled scripts here run via `${CLAUDE_PLUGIN_ROOT}/scripts/`. To resolve that package root: if `${CLAUDE_PLUGIN_ROOT}` is already an absolute path, use it; otherwise read `pkgRoot` from `~/.claude/hypo-pkg.json` (only when non-empty and the target script exists under it); otherwise use the `hypo@hypomnema` (or legacy `hypomnema@hypomnema`) installPath in `~/.claude/plugins/installed_plugins.json`; if none resolve, stop and tell the user to run `hypomnema upgrade --apply` or reinstall instead of guessing the cache layout.
|
|
18
18
|
|
|
19
19
|
If the user specified a wiki directory, pass it as `--wiki-dir="<path>"`. Otherwise omit the flag and the script resolves the wiki root automatically via `HYPO_DIR` → `hypo-config.md` scan → `~/hypomnema`.
|
|
20
20
|
|
|
@@ -37,7 +37,7 @@ Optionally ask:
|
|
|
37
37
|
## Step 3 — Run graph
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
|
-
node
|
|
40
|
+
node ${CLAUDE_PLUGIN_ROOT}/scripts/graph.mjs \
|
|
41
41
|
[--wiki-dir="<path>"] \
|
|
42
42
|
[--format=json|mermaid|dot] \
|
|
43
43
|
[--min-edges=<n>]
|
|
@@ -55,4 +55,4 @@ If the graph has 0 edges, note that no `[[wikilinks]]` were found between pages.
|
|
|
55
55
|
|
|
56
56
|
---
|
|
57
57
|
|
|
58
|
-
> **Citation convention.** When you reference a wiki page in your response, link it as `[[page-slug]]
|
|
58
|
+
> **Citation convention.** When you reference a wiki page in your response, link it as `[[page-slug]]` so it stays connected in the graph. The observability audit scores sessions on search / ingest / feedback activity (recorded by `hypo-session-record`), not on these inline citations; run `/hypo:audit` to inspect and see [[pages/observability/_index]].
|
package/skills/ingest/SKILL.md
CHANGED
|
@@ -14,7 +14,7 @@ You are running `/hypo:ingest`. Add a new source document to `sources/` and crea
|
|
|
14
14
|
|
|
15
15
|
## Step 1 — Locate package root
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
Bundled scripts here run via `${CLAUDE_PLUGIN_ROOT}/scripts/`. To resolve that package root: if `${CLAUDE_PLUGIN_ROOT}` is already an absolute path, use it; otherwise read `pkgRoot` from `~/.claude/hypo-pkg.json` (only when non-empty and the target script exists under it); otherwise use the `hypo@hypomnema` (or legacy `hypomnema@hypomnema`) installPath in `~/.claude/plugins/installed_plugins.json`; if none resolve, stop and tell the user to run `hypomnema upgrade --apply` or reinstall instead of guessing the cache layout.
|
|
18
18
|
|
|
19
19
|
If the user specified a wiki directory, pass it as `--hypo-dir="<path>"`. Otherwise omit the flag and the script resolves the wiki root automatically via `HYPO_DIR` → `hypo-config.md` scan → `~/hypomnema`.
|
|
20
20
|
|
|
@@ -23,7 +23,7 @@ If the user specified a wiki directory, pass it as `--hypo-dir="<path>"`. Otherw
|
|
|
23
23
|
## Step 2 — Run ingest status check
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
node
|
|
26
|
+
node ${CLAUDE_PLUGIN_ROOT}/scripts/ingest.mjs [--hypo-dir="<path>"] [--json]
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
Options:
|
|
@@ -40,13 +40,13 @@ Before touching any source content, refuse to ingest secrets (`.env`, SSH keys,
|
|
|
40
40
|
1. **If the user provided a file path**, check it (use an absolute path):
|
|
41
41
|
|
|
42
42
|
```bash
|
|
43
|
-
node
|
|
43
|
+
node ${CLAUDE_PLUGIN_ROOT}/scripts/ingest.mjs [--hypo-dir="<path>"] --check="<absolute-input-path>"
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
2. **Always** check the destination `sources/<slug>.<ext>`:
|
|
47
47
|
|
|
48
48
|
```bash
|
|
49
|
-
node
|
|
49
|
+
node ${CLAUDE_PLUGIN_ROOT}/scripts/ingest.mjs [--hypo-dir="<path>"] --check="sources/<slug>.<ext>"
|
|
50
50
|
```
|
|
51
51
|
|
|
52
52
|
If either command exits non-zero, **stop**: surface the `Refused: ...` message to the user and do not download, read, or save the source. The slug check matters because a user could rename a `.env` to an innocuous slug — the destination must still be blocked.
|
|
@@ -104,4 +104,4 @@ Append an ingest entry to `<wiki-root>/log.md`:
|
|
|
104
104
|
|
|
105
105
|
---
|
|
106
106
|
|
|
107
|
-
> **Citation convention.** When you reference a wiki page in your response, link it as `[[page-slug]]
|
|
107
|
+
> **Citation convention.** When you reference a wiki page in your response, link it as `[[page-slug]]` so it stays connected in the graph. The observability audit scores sessions on search / ingest / feedback activity (recorded by `hypo-session-record`), not on these inline citations; run `/hypo:audit` to inspect and see [[pages/observability/_index]].
|
package/skills/lint/SKILL.md
CHANGED
|
@@ -16,7 +16,7 @@ You are running `/hypo:lint`. Validate all wiki pages for frontmatter correctnes
|
|
|
16
16
|
|
|
17
17
|
## Step 1 — Locate package root
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
Bundled scripts here run via `${CLAUDE_PLUGIN_ROOT}/scripts/`. To resolve that package root: if `${CLAUDE_PLUGIN_ROOT}` is already an absolute path, use it; otherwise read `pkgRoot` from `~/.claude/hypo-pkg.json` (only when non-empty and the target script exists under it); otherwise use the `hypo@hypomnema` (or legacy `hypomnema@hypomnema`) installPath in `~/.claude/plugins/installed_plugins.json`; if none resolve, stop and tell the user to run `hypomnema upgrade --apply` or reinstall instead of guessing the cache layout.
|
|
20
20
|
|
|
21
21
|
If the user specified a wiki directory, pass it as `--wiki-dir="<path>"`. Otherwise omit the flag and the script resolves the wiki root automatically via `HYPO_DIR` → `hypo-config.md` scan → `~/hypomnema`.
|
|
22
22
|
|
|
@@ -25,7 +25,7 @@ If the user specified a wiki directory, pass it as `--wiki-dir="<path>"`. Otherw
|
|
|
25
25
|
## Step 2 — Run lint
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
node
|
|
28
|
+
node ${CLAUDE_PLUGIN_ROOT}/scripts/lint.mjs [--wiki-dir="<path>"] [--json] [--fix]
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
Options:
|
|
@@ -56,4 +56,4 @@ For **missing required fields** (`title`, `type`): open the affected files and h
|
|
|
56
56
|
|
|
57
57
|
---
|
|
58
58
|
|
|
59
|
-
> **Citation convention.** When you reference a wiki page in your response, link it as `[[page-slug]]
|
|
59
|
+
> **Citation convention.** When you reference a wiki page in your response, link it as `[[page-slug]]` so it stays connected in the graph. The observability audit scores sessions on search / ingest / feedback activity (recorded by `hypo-session-record`), not on these inline citations; run `/hypo:audit` to inspect and see [[pages/observability/_index]].
|
package/skills/query/SKILL.md
CHANGED
|
@@ -14,7 +14,7 @@ You are running `/hypo:query`. Full-text search across all wiki pages and projec
|
|
|
14
14
|
|
|
15
15
|
## Step 1 — Locate package root
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
Bundled scripts here run via `${CLAUDE_PLUGIN_ROOT}/scripts/`. To resolve that package root: if `${CLAUDE_PLUGIN_ROOT}` is already an absolute path, use it; otherwise read `pkgRoot` from `~/.claude/hypo-pkg.json` (only when non-empty and the target script exists under it); otherwise use the `hypo@hypomnema` (or legacy `hypomnema@hypomnema`) installPath in `~/.claude/plugins/installed_plugins.json`; if none resolve, stop and tell the user to run `hypomnema upgrade --apply` or reinstall instead of guessing the cache layout.
|
|
18
18
|
|
|
19
19
|
If the user specified a wiki directory, pass it as `--wiki-dir="<path>"`. Otherwise omit the flag and the script resolves the wiki root automatically via `HYPO_DIR` → `hypo-config.md` scan → `~/hypomnema`.
|
|
20
20
|
|
|
@@ -31,7 +31,7 @@ Use the search terms from the user's message. If no query was provided, ask:
|
|
|
31
31
|
## Step 3 — Run query
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
|
-
node
|
|
34
|
+
node ${CLAUDE_PLUGIN_ROOT}/scripts/query.mjs \
|
|
35
35
|
--q="<search terms>" \
|
|
36
36
|
[--wiki-dir="<path>"] \
|
|
37
37
|
[--limit=<n>] \
|
|
@@ -59,4 +59,4 @@ If zero results are returned, say so and offer to broaden the search or suggest
|
|
|
59
59
|
|
|
60
60
|
---
|
|
61
61
|
|
|
62
|
-
> **Citation convention.** When you reference a wiki page in your response, link it as `[[page-slug]]
|
|
62
|
+
> **Citation convention.** When you reference a wiki page in your response, link it as `[[page-slug]]` so it stays connected in the graph. The observability audit scores sessions on search / ingest / feedback activity (recorded by `hypo-session-record`), not on these inline citations; run `/hypo:audit` to inspect and see [[pages/observability/_index]].
|
package/skills/verify/SKILL.md
CHANGED
|
@@ -14,7 +14,7 @@ You are running `/hypo:verify`. Check all wiki pages for `verify_by` and `verify
|
|
|
14
14
|
|
|
15
15
|
## Step 1 — Locate package root
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
Bundled scripts here run via `${CLAUDE_PLUGIN_ROOT}/scripts/`. To resolve that package root: if `${CLAUDE_PLUGIN_ROOT}` is already an absolute path, use it; otherwise read `pkgRoot` from `~/.claude/hypo-pkg.json` (only when non-empty and the target script exists under it); otherwise use the `hypo@hypomnema` (or legacy `hypomnema@hypomnema`) installPath in `~/.claude/plugins/installed_plugins.json`; if none resolve, stop and tell the user to run `hypomnema upgrade --apply` or reinstall instead of guessing the cache layout.
|
|
18
18
|
|
|
19
19
|
If the user specified a wiki directory, pass it as `--wiki-dir="<path>"`. Otherwise omit the flag and the script resolves the wiki root automatically via `HYPO_DIR` → `hypo-config.md` scan → `~/hypomnema`.
|
|
20
20
|
|
|
@@ -23,7 +23,7 @@ If the user specified a wiki directory, pass it as `--wiki-dir="<path>"`. Otherw
|
|
|
23
23
|
## Step 2 — Run verify
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
node
|
|
26
|
+
node ${CLAUDE_PLUGIN_ROOT}/scripts/verify.mjs \
|
|
27
27
|
[--wiki-dir="<path>"] \
|
|
28
28
|
[--file="<path>"] \
|
|
29
29
|
[--json]
|
|
@@ -93,4 +93,4 @@ updated: <today YYYY-MM-DD>
|
|
|
93
93
|
|
|
94
94
|
---
|
|
95
95
|
|
|
96
|
-
> **Citation convention.** When you reference a wiki page in your response, link it as `[[page-slug]]
|
|
96
|
+
> **Citation convention.** When you reference a wiki page in your response, link it as `[[page-slug]]` so it stays connected in the graph. The observability audit scores sessions on search / ingest / feedback activity (recorded by `hypo-session-record`), not on these inline citations; run `/hypo:audit` to inspect and see [[pages/observability/_index]].
|
package/templates/SCHEMA.md
CHANGED
|
@@ -96,7 +96,7 @@ verify_by: <question to re-check at next review>
|
|
|
96
96
|
verify_by_date: YYYY-MM-DD
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
-
### 3.1. `feedback` type — projection fields
|
|
99
|
+
### 3.1. `feedback` type — projection fields
|
|
100
100
|
|
|
101
101
|
Feedback pages are the single source of truth for behavior corrections;
|
|
102
102
|
`hypomnema feedback-sync` projects them one-way into Claude Code's `MEMORY.md`
|
package/templates/hypo-config.md
CHANGED
package/templates/hypo-guide.md
CHANGED
|
@@ -67,7 +67,7 @@ Trigger: explicit close mention, `/compact` request, or context limit approachin
|
|
|
67
67
|
|
|
68
68
|
**Auto-trigger rule**: when the user sends a natural-language close signal — "세션 마무리하자", "오늘 여기까지", "이만 종료", "wrap up", "signing off", or equivalent — run the session close checklist immediately without waiting for an explicit `/compact` or `/hypo:crystallize`. If the intent is ambiguous, confirm with a single question before proceeding.
|
|
69
69
|
|
|
70
|
-
**Proactive close offer** (
|
|
70
|
+
**Proactive close offer** (Layer 1): even when the user gives no close signal, offer to wrap up once a task is truly done — don't make them remember to. Fire `AskUserQuestion` **at the end of the assistant turn in which you report a task complete or verified**, when both hold:
|
|
71
71
|
|
|
72
72
|
1. The session did substantial work — file mutations or multi-step changes, not Q&A only.
|
|
73
73
|
2. The current user request did not already include a next task or tell you not to close.
|
|
@@ -82,13 +82,13 @@ Ask: *"이 작업이 마무리되었나요? 세션을 정리(crystallize)할까
|
|
|
82
82
|
2. Update `projects/<name>/hot.md` (what was done, ≤500 words, overwrite)
|
|
83
83
|
3. Append to `projects/<name>/session-log/YYYY-MM-DD.md` (daily shard, narrative entry, append-only)
|
|
84
84
|
4. Update root `hot.md` pointer table + date
|
|
85
|
-
5. Run
|
|
85
|
+
5. Run `/hypo:lint` and fix errors in files **you** touched — debt in other
|
|
86
86
|
projects / shared pages you did not author is reported as a non-blocking
|
|
87
|
-
notice, not a gate. (The documented `
|
|
88
|
-
|
|
89
|
-
6. Verify with `
|
|
87
|
+
notice, not a gate. (The documented `/hypo:crystallize` session-close path
|
|
88
|
+
runs this lint automatically, scoped to the files it writes.)
|
|
89
|
+
6. Verify with `/hypo:crystallize` in its `--check-session-close` mode: a dry-run of the
|
|
90
90
|
**full** PreCompact gate (close files + lint + design-history + feedback
|
|
91
|
-
projection
|
|
91
|
+
projection), sharing one function with the gate. Only declare the
|
|
92
92
|
session closed once it prints **"Compact-ready"**. A "close files updated"
|
|
93
93
|
check alone is not enough — the real `/compact` gate also blocks on a lint
|
|
94
94
|
error in a close file or a feedback projection over-cap. (Not a hard
|
|
@@ -99,13 +99,13 @@ Ask: *"이 작업이 마무리되었나요? 세션을 정리(crystallize)할까
|
|
|
99
99
|
diagnostic, JSON `scope: "project"`): green there means only that slug is
|
|
100
100
|
close-complete, **not** that `/compact` is globally unblocked. Use the plain
|
|
101
101
|
check for the go/no-go signal.
|
|
102
|
-
7. Record the session-closed marker
|
|
102
|
+
7. Record the session-closed marker. The Stop hook blocks until this
|
|
103
103
|
session's per-session marker exists, and a hand-edit close (writing the files
|
|
104
104
|
directly + committing) never writes it; the marker is written only by the
|
|
105
|
-
crystallize writer, never by the hook (
|
|
106
|
-
close via `
|
|
105
|
+
crystallize writer, never by the hook (bypass guard). Normal path:
|
|
106
|
+
close via `/hypo:crystallize` (`--apply-session-close --session-id=<id> --transcript-path=<path>`),
|
|
107
107
|
which writes the marker once the gate is green. Hand-edit recovery: after
|
|
108
|
-
committing the files, run `
|
|
108
|
+
committing the files, run `/hypo:crystallize` (`--mark-session-closed --session-id=<id> --transcript-path=<path>`).
|
|
109
109
|
Both writers gate the marker on the SAME `precompactGateStatus` as `/compact`,
|
|
110
110
|
so the marker only lands when step 6 would print **"Compact-ready"**.
|
|
111
111
|
|
|
@@ -153,7 +153,7 @@ projects/<name>/
|
|
|
153
153
|
|
|
154
154
|
Add to root `hot.md` active projects table.
|
|
155
155
|
|
|
156
|
-
#### Auto-project offer
|
|
156
|
+
#### Auto-project offer
|
|
157
157
|
|
|
158
158
|
When SessionStart / CwdChanged injects a line like
|
|
159
159
|
`[WIKI: cwd '<name>'에 매칭되는 프로젝트가 없습니다. 자동 생성할까요? (Y/n)]`,
|
|
@@ -166,8 +166,14 @@ ignore it:**
|
|
|
166
166
|
2. **On Yes** — run the scaffold helper once (it substitutes tokens, creates
|
|
167
167
|
the project files, adds the root `hot.md` row, and logs the entry):
|
|
168
168
|
```
|
|
169
|
-
node
|
|
169
|
+
node ${CLAUDE_PLUGIN_ROOT}/scripts/lib/project-create.mjs --name <slug> --working-dir "$(pwd)"
|
|
170
170
|
```
|
|
171
|
+
To resolve that package root from this guide: if `${CLAUDE_PLUGIN_ROOT}` is
|
|
172
|
+
already an absolute path, use it; otherwise read `pkgRoot` from
|
|
173
|
+
`~/.claude/hypo-pkg.json` (only when non-empty and the script exists under it);
|
|
174
|
+
otherwise use the `hypo@hypomnema` (or legacy `hypomnema@hypomnema`) installPath
|
|
175
|
+
in `~/.claude/plugins/installed_plugins.json`; if none resolve, stop and tell the
|
|
176
|
+
user to run `hypomnema upgrade --apply` or reinstall instead of guessing.
|
|
171
177
|
Then tell the user: "Created project `<name>` at
|
|
172
178
|
`~/hypomnema/projects/<name>/`. Edit `index.md` to refine." Do **not** hand-write
|
|
173
179
|
the five files — the helper keeps substitution and registration consistent.
|
|
@@ -219,7 +225,7 @@ ADRs are immutable once accepted. Mark deprecated/superseded but never edit cont
|
|
|
219
225
|
|
|
220
226
|
Hypomnema v1.1.0 ships an **autonomy score** so you can see whether the wiki is actually being used per session, rather than just trusting that it is.
|
|
221
227
|
|
|
222
|
-
- **Citation:** when a response uses a wiki page, link it inline as `[[page-slug]]
|
|
228
|
+
- **Citation:** when a response uses a wiki page, link it inline as `[[page-slug]]` to keep it connected in the graph. (The audit score is based on the tool and command usage below, not on these inline citations.)
|
|
223
229
|
- **Tools that count:** `Grep`, `WebSearch`, `WebFetch`, and any `/hypo:query` / `/hypo:ingest` / `/hypo:feedback` invocation in the transcript.
|
|
224
230
|
- **Classification (heuristic v0):**
|
|
225
231
|
- `normal` — at least one search, no missed URL ingests
|
|
@@ -229,8 +235,8 @@ Hypomnema v1.1.0 ships an **autonomy score** so you can see whether the wiki is
|
|
|
229
235
|
- `staleness-skip` — session older than the audit window (default 30d)
|
|
230
236
|
- **Where it lives:**
|
|
231
237
|
- Per-session transcript index: `<hypo-root>/.cache/sessions/index.jsonl` (written by the Stop hook `hypo-session-record.mjs`).
|
|
232
|
-
- Fallback source: `~/.claude/projects/<encoded>/*.jsonl` (used when the index is empty
|
|
233
|
-
- Reports: `journal/weekly/<YYYY-Www>.md` (spec §6.4 SoT), generated by `
|
|
238
|
+
- Fallback source: `~/.claude/projects/<encoded>/*.jsonl` (used when the index is empty).
|
|
239
|
+
- Reports: `journal/weekly/<YYYY-Www>.md` (spec §6.4 SoT), generated by the `/hypo:audit` weekly report flow.
|
|
234
240
|
- **Definitions:** the 0% / 100% endpoints, the formal score sketch, and open questions live in `pages/observability/_index.md`.
|
|
235
241
|
|
|
236
242
|
Use `/hypo:audit` for a quick read of recent sessions; pass `--write` to commit the weekly report into the wiki.
|
|
@@ -21,7 +21,7 @@ tags: [hot-cache, project]
|
|
|
21
21
|
## Key Decisions
|
|
22
22
|
|
|
23
23
|
<!-- Brief pointers to important ADRs or design choices -->
|
|
24
|
-
<!-- [[decisions/
|
|
24
|
+
<!-- [[decisions/NNNN-topic]] — decision summary -->
|
|
25
25
|
|
|
26
26
|
## Blockers / Open Questions
|
|
27
27
|
|
|
@@ -1,256 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* fix-status-verify (CLI) — verify fix→test linkage + ADR-line evidence
|
|
4
|
-
* against wiki spec claims.
|
|
5
|
-
*
|
|
6
|
-
* Phase 1: test-green half (anchors × spec status × runner results).
|
|
7
|
-
* Phase 2 (A-sot): manifest validation + manifest↔anchor drift + ADR core
|
|
8
|
-
* decision grep against the production corpus. See scripts/lib/fix-manifest.mjs
|
|
9
|
-
* and scripts/lib/fix-status-verify.mjs headers.
|
|
10
|
-
*
|
|
11
|
-
* Usage:
|
|
12
|
-
* node scripts/fix-status-verify.mjs [--hypo-dir <path>]
|
|
13
|
-
* [--spec <path>]
|
|
14
|
-
* [--runner <path>]
|
|
15
|
-
* [--test-command "<cmd>"]
|
|
16
|
-
* [--json]
|
|
17
|
-
*
|
|
18
|
-
* Exit 0 if no error-level findings, 1 otherwise.
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
import { readFileSync, existsSync } from 'node:fs';
|
|
22
|
-
import { join, dirname, resolve } from 'node:path';
|
|
23
|
-
import { homedir } from 'node:os';
|
|
24
|
-
import { spawnSync } from 'node:child_process';
|
|
25
|
-
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
26
|
-
import {
|
|
27
|
-
parseAnchors,
|
|
28
|
-
parseStatus,
|
|
29
|
-
parseRunnerOutput,
|
|
30
|
-
verifyMatrix,
|
|
31
|
-
isReferenceStub,
|
|
32
|
-
validateManifest,
|
|
33
|
-
checkManifestCoverage,
|
|
34
|
-
checkAdrLines,
|
|
35
|
-
FIX_MANIFEST,
|
|
36
|
-
NO_ADR,
|
|
37
|
-
} from './lib/fix-status-verify.mjs';
|
|
38
|
-
import { buildCorpusSearch } from './lib/adr-corpus.mjs';
|
|
39
|
-
|
|
40
|
-
const REPO = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
41
|
-
|
|
42
|
-
// Production-code corpus for the ADR-line grep (spec §A amendment 2026-06-07:
|
|
43
|
-
// templates/ ships via npm `files`, so prompt-driven fixes are verifiable).
|
|
44
|
-
const CORPUS_DIRS = ['scripts', 'hooks', 'commands', 'skills', 'templates'];
|
|
45
|
-
// MUST exclude the manifest itself — it holds every adrKeyLine as a literal and
|
|
46
|
-
// would self-match, making ADR_LINE_MISSING impossible to ever fire.
|
|
47
|
-
const CORPUS_EXCLUDE = ['scripts/lib/fix-manifest.mjs'];
|
|
48
|
-
|
|
49
|
-
function parseArgs(argv) {
|
|
50
|
-
const out = {
|
|
51
|
-
hypoDir: process.env.HYPO_DIR || join(homedir(), 'hypomnema'),
|
|
52
|
-
spec: null,
|
|
53
|
-
runner: join(REPO, 'tests/runner.mjs'),
|
|
54
|
-
testCommand: 'npm test',
|
|
55
|
-
json: false,
|
|
56
|
-
manifest: null,
|
|
57
|
-
};
|
|
58
|
-
for (let i = 0; i < argv.length; i++) {
|
|
59
|
-
const a = argv[i];
|
|
60
|
-
if (a === '--hypo-dir') out.hypoDir = argv[++i];
|
|
61
|
-
else if (a === '--spec') out.spec = argv[++i];
|
|
62
|
-
else if (a === '--runner') out.runner = argv[++i];
|
|
63
|
-
else if (a === '--test-command') out.testCommand = argv[++i];
|
|
64
|
-
else if (a === '--manifest') out.manifest = argv[++i];
|
|
65
|
-
else if (a === '--json') out.json = true;
|
|
66
|
-
else if (a === '--help' || a === '-h') {
|
|
67
|
-
printHelp();
|
|
68
|
-
process.exit(0);
|
|
69
|
-
} else {
|
|
70
|
-
console.error(`unknown arg: ${a}`);
|
|
71
|
-
process.exit(2);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
if (!out.spec) {
|
|
75
|
-
out.spec = join(out.hypoDir, 'projects/hypomnema/spec-v1.2.md');
|
|
76
|
-
}
|
|
77
|
-
return out;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function printHelp() {
|
|
81
|
-
console.log(
|
|
82
|
-
[
|
|
83
|
-
'fix-status-verify — Phase 1 (test-green half) of learned_behavior #6',
|
|
84
|
-
'',
|
|
85
|
-
'Options:',
|
|
86
|
-
' --hypo-dir <path> Wiki root (default: $HYPO_DIR or ~/hypomnema)',
|
|
87
|
-
' --spec <path> Override spec-v1.2.md path',
|
|
88
|
-
' --runner <path> Override tests/runner.mjs path',
|
|
89
|
-
' --test-command "<cmd>" Test invocation (default: "npm test")',
|
|
90
|
-
' --json Emit machine-readable JSON report',
|
|
91
|
-
'',
|
|
92
|
-
'Exit 0 if no error findings, 1 otherwise.',
|
|
93
|
-
'',
|
|
94
|
-
'NOTE: The default --spec is a `type: reference` redirect stub (the real',
|
|
95
|
-
'spec moved to archive/). Running without --spec fails with STUB_SPEC by',
|
|
96
|
-
'design — pass --spec <real spec> to verify against actual claims.',
|
|
97
|
-
'',
|
|
98
|
-
'Phase 2 (A-sot): also greps each manifest adrKeyLine against the',
|
|
99
|
-
'production corpus (scripts/ hooks/ commands/ skills/ templates/) and',
|
|
100
|
-
'checks manifest↔anchor drift. NO_ADR rows skip the grep (test-green only).',
|
|
101
|
-
].join('\n'),
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function runTests(testCommand) {
|
|
106
|
-
// Parse simple command (no shell metacharacters supported in args; this is
|
|
107
|
-
// a maintainer tool, not a security boundary).
|
|
108
|
-
const parts = testCommand.split(/\s+/).filter(Boolean);
|
|
109
|
-
const [cmd, ...args] = parts;
|
|
110
|
-
const result = spawnSync(cmd, args, {
|
|
111
|
-
cwd: REPO,
|
|
112
|
-
encoding: 'utf-8',
|
|
113
|
-
env: { ...process.env, FORCE_COLOR: '0' },
|
|
114
|
-
maxBuffer: 64 * 1024 * 1024,
|
|
115
|
-
});
|
|
116
|
-
return {
|
|
117
|
-
stdout: result.stdout || '',
|
|
118
|
-
stderr: result.stderr || '',
|
|
119
|
-
exitCode: result.status,
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function formatFinding(f) {
|
|
124
|
-
const icon = f.level === 'error' ? '✗' : '⚠';
|
|
125
|
-
// Some findings are not tied to a specific fix # (STUB_SPEC,
|
|
126
|
-
// TEST_RUN_NONZERO_EXIT). Only render the `fix #N` segment when present so
|
|
127
|
-
// they don't print `fix #undefined`.
|
|
128
|
-
const ref = f.fixNum != null ? ` fix #${f.fixNum}` : '';
|
|
129
|
-
return ` ${icon} [${f.class}]${ref}` + (f.testName ? ` (${f.testName})` : '') + `: ${f.detail}`;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
async function main() {
|
|
133
|
-
const opts = parseArgs(process.argv.slice(2));
|
|
134
|
-
|
|
135
|
-
// Manifest source: built-in code constant by default (ADR 0036). --manifest
|
|
136
|
-
// <path.mjs> overrides for tests, which inject a fixture manifest matching
|
|
137
|
-
// their synthetic fixes so the real manifest does not couple to fixtures.
|
|
138
|
-
let manifest = FIX_MANIFEST;
|
|
139
|
-
if (opts.manifest) {
|
|
140
|
-
if (!existsSync(opts.manifest)) {
|
|
141
|
-
console.error(`manifest not found: ${opts.manifest}`);
|
|
142
|
-
process.exit(2);
|
|
143
|
-
}
|
|
144
|
-
const mod = await import(pathToFileURL(resolve(opts.manifest)).href);
|
|
145
|
-
manifest = mod.FIX_MANIFEST;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (!existsSync(opts.spec)) {
|
|
149
|
-
console.error(`spec not found: ${opts.spec}`);
|
|
150
|
-
console.error('hint: pass --hypo-dir <path> or set $HYPO_DIR');
|
|
151
|
-
process.exit(2);
|
|
152
|
-
}
|
|
153
|
-
if (!existsSync(opts.runner)) {
|
|
154
|
-
console.error(`runner not found: ${opts.runner}`);
|
|
155
|
-
process.exit(2);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const specText = readFileSync(opts.spec, 'utf-8');
|
|
159
|
-
const runnerText = readFileSync(opts.runner, 'utf-8');
|
|
160
|
-
|
|
161
|
-
const anchors = parseAnchors(runnerText);
|
|
162
|
-
const status = parseStatus(specText);
|
|
163
|
-
const specIsStub = isReferenceStub(specText);
|
|
164
|
-
|
|
165
|
-
if (!opts.json) {
|
|
166
|
-
console.log(`fix-status-verify (Phase 1)`);
|
|
167
|
-
console.log(` spec: ${opts.spec}`);
|
|
168
|
-
console.log(` runner: ${opts.runner}`);
|
|
169
|
-
console.log(` ${status.size} positive status claim(s), ${anchors.size} anchor(s)`);
|
|
170
|
-
console.log(` running: ${opts.testCommand}`);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const testRun = runTests(opts.testCommand);
|
|
174
|
-
const testResults = parseRunnerOutput(testRun.stdout + '\n' + testRun.stderr);
|
|
175
|
-
|
|
176
|
-
if (!opts.json) {
|
|
177
|
-
const passes = [...testResults.values()].filter((v) => v === 'pass').length;
|
|
178
|
-
const fails = [...testResults.values()].filter((v) => v === 'fail').length;
|
|
179
|
-
console.log(` test run: ${passes} pass, ${fails} fail (exit ${testRun.exitCode})`);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const matrixResult = verifyMatrix({ anchors, status, testResults, specIsStub });
|
|
183
|
-
const findings = [...matrixResult.findings];
|
|
184
|
-
|
|
185
|
-
// Phase 2 (A-sot): manifest validation + ADR-line grep. validateManifest and
|
|
186
|
-
// checkAdrLines are spec-independent (manifest/code health) and run always;
|
|
187
|
-
// checkManifestCoverage keys off the spec status (a no-op under STUB_SPEC,
|
|
188
|
-
// where status is empty).
|
|
189
|
-
const needsCorpus = manifest.some((r) => r.adrKeyLine !== NO_ADR);
|
|
190
|
-
const adrSearch = needsCorpus
|
|
191
|
-
? buildCorpusSearch({ repoRoot: REPO, includeDirs: CORPUS_DIRS, excludePaths: CORPUS_EXCLUDE })
|
|
192
|
-
: () => false;
|
|
193
|
-
const adrExists = (adrPath) => existsSync(join(opts.hypoDir, 'projects/hypomnema', adrPath));
|
|
194
|
-
findings.push(...validateManifest(manifest));
|
|
195
|
-
findings.push(...checkManifestCoverage({ manifest, anchors, status }));
|
|
196
|
-
findings.push(...checkAdrLines({ manifest, searchFn: adrSearch, adrExistsFn: adrExists }));
|
|
197
|
-
|
|
198
|
-
// CLI-level error: if the test command itself exited nonzero, the test run
|
|
199
|
-
// is not green even if the anchored tests happen to all pass in the parsed
|
|
200
|
-
// output. Surface as a synthetic error finding so `ok` flips false.
|
|
201
|
-
if (testRun.exitCode !== 0) {
|
|
202
|
-
findings.push({
|
|
203
|
-
level: 'error',
|
|
204
|
-
class: 'TEST_RUN_NONZERO_EXIT',
|
|
205
|
-
detail: `test command "${opts.testCommand}" exited ${testRun.exitCode}`,
|
|
206
|
-
exitCode: testRun.exitCode,
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
const ok = !findings.some((f) => f.level === 'error') && testRun.exitCode === 0;
|
|
210
|
-
|
|
211
|
-
const MANDATORY_NOTE =
|
|
212
|
-
'test-linkage + green + ADR-line grep (Phase 2): manifest evidence checked against production corpus';
|
|
213
|
-
|
|
214
|
-
if (opts.json) {
|
|
215
|
-
console.log(
|
|
216
|
-
JSON.stringify(
|
|
217
|
-
{
|
|
218
|
-
ok,
|
|
219
|
-
spec: opts.spec,
|
|
220
|
-
runner: opts.runner,
|
|
221
|
-
statusClaims: status.size,
|
|
222
|
-
anchorCount: anchors.size,
|
|
223
|
-
testsRan: testResults.size,
|
|
224
|
-
testExitCode: testRun.exitCode,
|
|
225
|
-
findings,
|
|
226
|
-
note: MANDATORY_NOTE,
|
|
227
|
-
},
|
|
228
|
-
null,
|
|
229
|
-
2,
|
|
230
|
-
),
|
|
231
|
-
);
|
|
232
|
-
} else {
|
|
233
|
-
const errors = findings.filter((f) => f.level === 'error');
|
|
234
|
-
const warns = findings.filter((f) => f.level === 'warn');
|
|
235
|
-
if (errors.length === 0 && warns.length === 0) {
|
|
236
|
-
console.log(` ✓ all ${status.size} claimed-merged fix(es) verified`);
|
|
237
|
-
} else {
|
|
238
|
-
if (errors.length) {
|
|
239
|
-
console.log(`\nerrors (${errors.length}):`);
|
|
240
|
-
for (const f of errors) console.log(formatFinding(f));
|
|
241
|
-
}
|
|
242
|
-
if (warns.length) {
|
|
243
|
-
console.log(`\nwarnings (${warns.length}):`);
|
|
244
|
-
for (const f of warns) console.log(formatFinding(f));
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
console.log(`\n(${MANDATORY_NOTE})`);
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
process.exit(ok ? 0 : 1);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
main().catch((e) => {
|
|
254
|
-
console.error(e);
|
|
255
|
-
process.exit(2);
|
|
256
|
-
});
|