hypomnema 1.4.2 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.ko.md +1 -1
- package/README.md +1 -1
- package/commands/audit.md +1 -1
- package/commands/crystallize.md +8 -8
- 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 +2 -2
- 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-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 +34 -40
- package/hooks/hypo-shared.mjs +271 -71
- package/hooks/version-check.mjs +1 -1
- package/package.json +5 -1
- package/scripts/check-tracker-ids.mjs +69 -31
- package/scripts/crystallize.mjs +82 -38
- 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/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 +17 -18
- package/skills/crystallize/SKILL.md +7 -7
- package/skills/graph/SKILL.md +2 -2
- package/skills/ingest/SKILL.md +4 -4
- package/skills/lint/SKILL.md +2 -2
- package/skills/query/SKILL.md +2 -2
- package/skills/verify/SKILL.md +2 -2
- package/templates/SCHEMA.md +1 -1
- package/templates/hypo-config.md +1 -1
- package/templates/hypo-guide.md +20 -14
- 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
package/scripts/resume.mjs
CHANGED
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
* --json Output as JSON
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
-
import { existsSync, readFileSync, readdirSync, statSync } from 'fs';
|
|
29
|
+
import { existsSync, readFileSync, readdirSync, statSync, realpathSync } from 'fs';
|
|
30
30
|
import { join } from 'path';
|
|
31
|
-
import { homedir } from 'os';
|
|
32
31
|
import { resolveHypoRoot, expandHome } from './lib/hypo-root.mjs';
|
|
32
|
+
import { pickProjectByCwd, collectProjectWorkingDirs } from './lib/wd-match.mjs';
|
|
33
33
|
|
|
34
34
|
// ── arg parsing ──────────────────────────────────────────────────────────────
|
|
35
35
|
|
|
@@ -60,27 +60,25 @@ function parseFrontmatterField(content, key) {
|
|
|
60
60
|
.replace(/^['"]|['"]$/g, '');
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
//
|
|
63
|
+
// Return the project (among `slugs`) that owns cwd: a longest-prefix
|
|
64
|
+
// working_dir match, or — when no absolute path matches because the vault was
|
|
65
|
+
// synced from another machine — a cwd ancestor whose directory name is a
|
|
66
|
+
// globally-unique project basename. Uniqueness is judged over EVERY project on
|
|
67
|
+
// disk (not just `slugs`), so a shared dirname declines and falls back to
|
|
68
|
+
// recency. resume gives this authority over recency: a cwd↔project match wins
|
|
69
|
+
// regardless of which hot.md row is newest.
|
|
67
70
|
function pickByCwd(hypoDir, slugs, cwd) {
|
|
68
71
|
if (!cwd) return null;
|
|
69
|
-
let
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const wd = parseFrontmatterField(readFileSync(indexPath, 'utf-8'), 'working_dir');
|
|
75
|
-
if (!wd) continue;
|
|
76
|
-
let resolved = wd.startsWith('~/') ? join(homedir(), wd.slice(2)) : wd;
|
|
77
|
-
resolved = resolved.replace(/\/+$/, ''); // trailing-slash normalize
|
|
78
|
-
if ((cwd === resolved || cwd.startsWith(resolved + '/')) && resolved.length > bestLen) {
|
|
79
|
-
bestLen = resolved.length;
|
|
80
|
-
best = slug;
|
|
81
|
-
}
|
|
72
|
+
let realpathCwd = null;
|
|
73
|
+
try {
|
|
74
|
+
realpathCwd = realpathSync(cwd);
|
|
75
|
+
} catch {
|
|
76
|
+
realpathCwd = null;
|
|
82
77
|
}
|
|
83
|
-
return
|
|
78
|
+
return pickProjectByCwd(collectProjectWorkingDirs(hypoDir), cwd, {
|
|
79
|
+
eligible: slugs,
|
|
80
|
+
realpathCwd,
|
|
81
|
+
});
|
|
84
82
|
}
|
|
85
83
|
|
|
86
84
|
// When cwd is set but no project's working_dir matches it, resume falls back to
|
|
@@ -125,11 +123,11 @@ function resolveActiveProject(hypoDir, cwd = null) {
|
|
|
125
123
|
),
|
|
126
124
|
].map((m) => ({ name: m[1].trim(), date: m[2] || '', slug: m[3] }));
|
|
127
125
|
if (wikiRows.length > 0) {
|
|
128
|
-
// cwd-first
|
|
126
|
+
// cwd-first: a cwd↔working_dir match wins over recency, across
|
|
129
127
|
// ALL rows (not just a same-date tie). The user is physically in that
|
|
130
128
|
// project, so cwd is a stronger intent signal than "some other project was
|
|
131
129
|
// touched more recently". This reverses the earlier tie-breaker-only
|
|
132
|
-
// semantics now that resume=cwd-positive
|
|
130
|
+
// semantics now that resume=cwd-positive. Tradeoff: a stale cwd
|
|
133
131
|
// match can mask a genuinely newer project; `--project` overrides. close
|
|
134
132
|
// callers pass null → recency path below (resume=cwd-positive / close=no-pick).
|
|
135
133
|
if (cwd) {
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* (search count, ingest count, URLs mentioned, feedback count) so the
|
|
7
7
|
* weekly observability report (Lane E) can compute autonomy scores.
|
|
8
8
|
*
|
|
9
|
-
* Transcript dual-source
|
|
9
|
+
* Transcript dual-source:
|
|
10
10
|
* 1) Primary: <hypo-dir>/.cache/sessions/index.jsonl
|
|
11
11
|
* Written by hooks/hypo-session-record.mjs (Stop hook).
|
|
12
12
|
* 2) Fallback: ~/.claude/projects/<encoded>/*.jsonl
|
package/scripts/stats.mjs
CHANGED
|
@@ -48,8 +48,8 @@ function collectMdFiles(dir, acc = [], hypoDir = '', ignorePatterns = []) {
|
|
|
48
48
|
// Local top-level-only extractor, behavior-aligned with lib/frontmatter.mjs:
|
|
49
49
|
// skip indented / list lines, first-wins, strip a trailing `# comment`. Without
|
|
50
50
|
// the comment strip a `failure_type: overreach # note` would aggregate under the
|
|
51
|
-
// literal "overreach # note" key
|
|
52
|
-
// hold stats' dependency surface flat per the
|
|
51
|
+
// literal "overreach # note" key. Kept local (not the shared import) to
|
|
52
|
+
// hold stats' dependency surface flat per the scope split.
|
|
53
53
|
function parseFrontmatter(content) {
|
|
54
54
|
const m = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
55
55
|
if (!m) return null;
|
|
@@ -101,7 +101,7 @@ const sources = existsSync(join(args.hypoDir, 'sources'))
|
|
|
101
101
|
: [];
|
|
102
102
|
|
|
103
103
|
const typeCounts = {};
|
|
104
|
-
const failureTypeCounts = {}; //
|
|
104
|
+
const failureTypeCounts = {}; // feedback pages carrying a failure_type
|
|
105
105
|
let missingFrontmatter = 0;
|
|
106
106
|
|
|
107
107
|
for (const f of pageFiles) {
|
package/scripts/uninstall.mjs
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* --force-extensions Remove user-modified extension files (hypo-ext-*) instead of preserving them
|
|
16
16
|
* --hooks-dir=<path> Override Claude hooks directory (default: ~/.claude/hooks)
|
|
17
17
|
*
|
|
18
|
-
* Extensions
|
|
18
|
+
* Extensions: hypo-ext-* hard-copies under
|
|
19
19
|
* ~/.claude/{hooks,commands,skills,agents}/ and ~/.codex/{hooks,commands}/ (with
|
|
20
20
|
* --codex) are removed when their on-disk SHA matches the recorded one in
|
|
21
21
|
* ~/.claude/hypo-pkg.json#extensions.<target>. User-modified copies are preserved
|
|
@@ -94,7 +94,7 @@ function removeCommands(apply, force) {
|
|
|
94
94
|
return { removed, skippedUserModified, skippedNonRegular };
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
// ── extensions removal
|
|
97
|
+
// ── extensions removal ───────────────────────────────────
|
|
98
98
|
|
|
99
99
|
// Strip per-target extension SHA records from ~/.claude/hypo-pkg.json. Surgical:
|
|
100
100
|
// we only touch the entries for keys we actually removed, so a `--force-extensions`
|
|
@@ -424,7 +424,7 @@ const hookResult = removeHookFiles(claudeHooksDir, hookFiles, args.apply);
|
|
|
424
424
|
const settingsResult = stripSettingsJson(claudeSettings, claudeHooksDir, hookMap, args.apply);
|
|
425
425
|
const commandResult = removeCommands(args.apply, args.forceCommands);
|
|
426
426
|
|
|
427
|
-
// Extensions
|
|
427
|
+
// Extensions. Order matters: remove files first, then strip
|
|
428
428
|
// settings, then surgically clear the per-target SHA map. The SHA strip uses
|
|
429
429
|
// removedKeys so a user-modified file we left in place keeps its recorded SHA
|
|
430
430
|
// (doctor still has a baseline next run). Settings are path-based and run even
|
package/scripts/upgrade.mjs
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* the user-extensions companion sync (E4).
|
|
21
21
|
* --json Output results as JSON
|
|
22
22
|
* --allow-downgrade Override the guard that refuses to overwrite a NEWER
|
|
23
|
-
* active install with an older package
|
|
23
|
+
* active install with an older package
|
|
24
24
|
* --allow-dual-install Override the dual-install guard: register the Claude core
|
|
25
25
|
* surface even though the Hypomnema plugin is also enabled
|
|
26
26
|
* (knowingly accept the double-registration risk)
|
|
@@ -235,7 +235,7 @@ function checkSchemaVersion(hypoDir) {
|
|
|
235
235
|
|
|
236
236
|
// Target-aware: the same core-hook integrity check runs against ~/.claude/hooks/
|
|
237
237
|
// for the default claude target, and against ~/.codex/hooks/ when --codex is set
|
|
238
|
-
//
|
|
238
|
+
// The function reads only (apply happens in applyHookFiles).
|
|
239
239
|
function checkHookFiles(hooksDir) {
|
|
240
240
|
const results = [];
|
|
241
241
|
|
|
@@ -473,15 +473,15 @@ function writeMigrationReport(hypoDir, fromVersion, toVersion, { pluginMode = fa
|
|
|
473
473
|
// Don't overwrite an existing report
|
|
474
474
|
if (existsSync(dest)) return dest;
|
|
475
475
|
|
|
476
|
-
// v1 → v2 specific guidance for the
|
|
477
|
-
//
|
|
478
|
-
//
|
|
479
|
-
//
|
|
480
|
-
//
|
|
481
|
-
// Fire for any 1.x → 2.x major crossing, not just 1.0 → 2.0 exactly: the
|
|
482
|
-
//
|
|
476
|
+
// v1 → v2 specific guidance for the feedback classification bump. Other major
|
|
477
|
+
// jumps fall back to the generic body. The schema deliberately keeps SCHEMA.md
|
|
478
|
+
// user-owned (Option C); auto-stub of the 9 new fields is rejected because
|
|
479
|
+
// scope/tier/targets/sensitivity/reason/source are semantic decisions whose
|
|
480
|
+
// wrong defaults would project wrong behavior.
|
|
481
|
+
// Fire for any 1.x → 2.x major crossing, not just 1.0 → 2.0 exactly: the
|
|
482
|
+
// feedback-field backfill that this body explains was introduced at 2.0
|
|
483
483
|
// and still applies to a user landing on any later 2.x (e.g. 2.1's additive
|
|
484
|
-
// failure_type
|
|
484
|
+
// failure_type). Keying on the exact target string would silently
|
|
485
485
|
// drop this guidance the moment the template minor moves.
|
|
486
486
|
const fromV = parseVersion(fromVersion);
|
|
487
487
|
const toV = parseVersion(toVersion);
|
|
@@ -489,8 +489,7 @@ function writeMigrationReport(hypoDir, fromVersion, toVersion, { pluginMode = fa
|
|
|
489
489
|
const specificBody = isV1ToV2
|
|
490
490
|
? `## What changed in SCHEMA 2.0
|
|
491
491
|
|
|
492
|
-
|
|
493
|
-
made \`feedback\` pages the single source of truth for behavior corrections and added
|
|
492
|
+
This release made \`feedback\` pages the single source of truth for behavior corrections and added
|
|
494
493
|
**9 hard-required frontmatter fields** for every \`feedback\` page:
|
|
495
494
|
|
|
496
495
|
- \`status\` (active | superseded | archived)
|
|
@@ -510,8 +509,8 @@ that does not satisfy all four is rejected by both \`hypomnema lint\` and
|
|
|
510
509
|
\`hypomnema feedback\` (see \`scripts/lint.mjs\` and \`scripts/feedback.mjs\`
|
|
511
510
|
enforcement).
|
|
512
511
|
|
|
513
|
-
|
|
514
|
-
|
|
512
|
+
This schema bump is semver-major because existing feedback pages without these
|
|
513
|
+
fields now fail \`hypomnema lint\`.
|
|
515
514
|
|
|
516
515
|
## Action items — existing wiki
|
|
517
516
|
|
|
@@ -799,7 +798,7 @@ function writePluginModeMetadata() {
|
|
|
799
798
|
const args = parseArgs(process.argv);
|
|
800
799
|
|
|
801
800
|
// Target paths. Claude is always checked; codex is checked only when --codex is set
|
|
802
|
-
//
|
|
801
|
+
// so users without codex installed see no false drift.
|
|
803
802
|
const claudeHooksDir = join(HOME, '.claude', 'hooks');
|
|
804
803
|
const claudeSettingsPath = join(HOME, '.claude', 'settings.json');
|
|
805
804
|
const codexHooksDir = join(HOME, '.codex', 'hooks');
|
|
@@ -858,7 +857,7 @@ const hooksCodex = args.codex ? checkHookFiles(codexHooksDir) : null;
|
|
|
858
857
|
const settingsCodex = args.codex ? checkSettingsJson(codexSettingsPath, codexHooksDir) : null;
|
|
859
858
|
const oldHookRefsCodex = args.codex ? checkOldHookNames(codexSettingsPath) : null;
|
|
860
859
|
|
|
861
|
-
// Extensions companion
|
|
860
|
+
// Extensions companion. Read-only check; the apply
|
|
862
861
|
// happens below, AFTER applyCommands, so the per-target SHA map merges into the
|
|
863
862
|
// hypo-pkg.json that applyCommands writes (rather than being clobbered by it).
|
|
864
863
|
const extSettingsPath = claudeSettingsPath;
|
|
@@ -935,7 +934,7 @@ let appliedExtensions = null;
|
|
|
935
934
|
let appliedExtensionsCodex = null;
|
|
936
935
|
|
|
937
936
|
if (args.apply) {
|
|
938
|
-
// Downgrade guard
|
|
937
|
+
// Downgrade guard: an `--apply` from an OLDER package than the
|
|
939
938
|
// active install would overwrite newer hooks (upgrade.mjs:287 copyFileSync) and
|
|
940
939
|
// rewrite hypo-pkg.json to the older version. Refuse before the first mutation.
|
|
941
940
|
// A dev workspace re-running its own --apply (incl. the post-commit sync hook)
|
|
@@ -1370,7 +1369,7 @@ if (hypoignore.status === 'no-file') {
|
|
|
1370
1369
|
for (const e of hypoignore.missing) lines.push(` + ${e.pattern}`);
|
|
1371
1370
|
}
|
|
1372
1371
|
|
|
1373
|
-
// Extensions companion (
|
|
1372
|
+
// Extensions companion (conflict/drift gating E3, #31). Shared by the
|
|
1374
1373
|
// claude target and, under --codex, the codex target (E4, #32) — the label keeps
|
|
1375
1374
|
// the two blocks distinguishable in the report.
|
|
1376
1375
|
function pushExtSummary(check, label) {
|
|
@@ -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`
|
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>]
|
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.
|
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:
|
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>] \
|
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]
|
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.
|
|
@@ -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
|
|