jeo-code 0.6.37 → 0.6.38

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/CHANGELOG.md CHANGED
@@ -6,6 +6,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  The README mirrors the latest 5 entries — regenerate with `bun run changelog:sync`.
8
8
 
9
+ ## [0.6.38] - 2026-06-21
10
+ _The OKF concept-bundle memory no longer silently drops what it learns: a legacy single-doc `MEMORY.md` (or a text-only distill fallback) can no longer shadow the concept bundle, break OKF conformance, or lose a turn's learnings — its content is folded into the concept merge and the stale blob is archived. Re-verified leak-free (`mem-probe`, 2000 turns, −570 bytes/turn slope) with a fresh `jeo --tmux` boot battery (6/6)._
11
+
12
+ ### Fixed
13
+ - **A text-only distill fallback no longer loses the turn's learnings.** When the model returns no extractable JSON, `distillSessionMemory` used to write the raw text to a single-doc `MEMORY.md` blob — but `memoryPromptSection` injects that blob ONLY when the concept bundle is empty (concepts always win), so once any concept existed the fallback's learnings were recorded yet never injected. Now, if a concept bundle already exists, the dead blob is suppressed and the prior concepts are kept as the durable memory (`skipped: "distill produced no JSON; kept existing concept bundle (legacy blob suppressed)"`).
14
+ - **A lingering legacy `MEMORY.md` can no longer break OKF conformance.** A frontmatter-less single-doc `MEMORY.md` coexisting with the concept bundle made `validateBundle` non-conformant (`error: concept document missing YAML frontmatter block`) while the loader silently skipped it — an inconsistency that left the bundle permanently invalid (`migrateLegacyMemory` only runs on the explicit `jeo memory-migrate`). Distill now feeds the legacy doc's content into the concept-merge context so its learnings are absorbed, then archives it to `MEMORY.md.bak` on a successful JSON distill — off the active read path, with rollback preserved.
15
+ - **Concept enumeration skips non-concept blobs.** `existingConcepts` now skips any `.md` without YAML frontmatter, so a stray `MEMORY.md` can never be mis-parsed as a concept during the merge.
16
+
17
+ ### Changed
18
+ - **Distill prompt enforces concept granularity.** The merge prompt now forbids a catch-all "Project Memory Bundle" mega-concept and instructs one concept per distinct fact/command/gotcha/preference, so the bundle grows as discrete, cross-linkable concepts.
19
+ - **Per-session injection budget raised** from 3,000 to 5,000 chars (`MEMORY_INJECT_MAX_CHARS`) so a healthy multi-concept bundle is injected in full.
20
+
21
+ ### Verified
22
+ - `bun run typecheck` clean; full suite `1751 pass / 0 fail` (216 files).
23
+ - Memory/OKF suites `57 pass / 0 fail` across `memory`, `memory-okf`, `memory-distill-okf`, `memory-migration-okf`, `memory-search-okf`, `memory-graph-okf`.
24
+ - Live bundle proof: `validateBundle` flips `false (error: MEMORY.md)` → `true (no issues)` after the legacy archive, injection block intact (3,220 chars); bundle now holds discrete facts/commands/gotchas/preferences concepts + a valid `index.md`.
25
+ - `scripts/mem-probe.ts` (2000 turns × 40 tools) reports no long-term leak (−570 bytes/turn, exit-listeners flat at 1); `scripts/tmux-verify.sh battery` passes 6/6 on a fresh `jeo --tmux` boot.
26
+
27
+
9
28
  ## [0.6.37] - 2026-06-20
10
29
  _Two dead-end fixes: the boxed prompt's ↑/↓ now recalls input history on a soft-wrapped one-liner (only a genuine multi-line draft gets in-box caret nav), and every terminating Spec-first stage (deep-interview, ralplan, team) now surfaces a user-visible answer instead of silently stalling — re-verified leak-free (`mem-probe`) with a fresh `jeo --tmux` boot._
11
30
 
package/README.ja.md CHANGED
@@ -200,11 +200,11 @@ CI は `.github/workflows/npm-publish.yml` で公開します — GitHub リリ
200
200
  ## 変更履歴 (Changelog)
201
201
 
202
202
  <!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
203
+ - **[0.6.38]** (2026-06-21) — The OKF concept-bundle memory no longer silently drops what it learns: a legacy single-doc `MEMORY.md` (or a text-only distill fallback) can no longer shadow the concept bundle, break OKF conformance, or lose a turn's learnings — its content is folded into the concept merge and the stale blob is archived. Re-verified leak-free (`mem-probe`, 2000 turns, −570 bytes/turn slope) with a fresh `jeo --tmux` boot battery (6/6).
203
204
  - **[0.6.37]** (2026-06-20) — Two dead-end fixes: the boxed prompt's ↑/↓ now recalls input history on a soft-wrapped one-liner (only a genuine multi-line draft gets in-box caret nav), and every terminating Spec-first stage (deep-interview, ralplan, team) now surfaces a user-visible answer instead of silently stalling — re-verified leak-free (`mem-probe`) with a fresh `jeo --tmux` boot.
204
205
  - **[0.6.36]** (2026-06-20) — When `jeo --tmux` flips the mouse on so you can drag-select, the drag now actually lands on the system clipboard — the in-session tmux profile sets `set-clipboard on` + a local `copy-command` on the CURRENT session only — plus `/help` documents the drag-to-copy and the Shift/Option-drag escape hatch, re-verified leak-free (`mem-probe`) with a fresh `jeo --tmux` boot.
205
206
  - **[0.6.35]** (2026-06-20) — The prompt's Ctrl+C now clears a non-empty input box on the first press and only exits on the next press of an empty box; plus app-driven system-clipboard copy (OSC 52 + local tool, tmux-aware), drag-and-drop image attachment, a Ctrl-L prompt re-anchor, and a SIGCONT resume repaint — verified leak-free (`mem-probe`) with a fresh `jeo --tmux` boot check.
206
207
  - **[0.6.34]** (2026-06-20) — Per-session model memory — each saved session now remembers the model it was last using and restores it on `/resume` — plus clearer `jeo --tmux` attach diagnostics, a tmux session-name double-dash fix, and a more robust no-leak probe gate.
207
- - **[0.6.33]** (2026-06-19) — A redesigned `jeo` forge mark — a hollow line-board crayfish/eyeglass emblem drawn as thick rounded-corner tubes (no letters, no DNA helix) — that now renders inside compact-scaled forge cards, plus a unified verification directive that adds gjc's test-quality contract, and a fresh `jeo --tmux` no-leak re-verification.
208
208
 
209
209
  See [CHANGELOG.md](CHANGELOG.md) for the full history.
210
210
  <!-- CHANGELOG:END -->
package/README.ko.md CHANGED
@@ -200,11 +200,11 @@ CI는 `.github/workflows/npm-publish.yml`로 배포합니다 — GitHub 릴리
200
200
  ## 변경 이력 (Changelog)
201
201
 
202
202
  <!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
203
+ - **[0.6.38]** (2026-06-21) — The OKF concept-bundle memory no longer silently drops what it learns: a legacy single-doc `MEMORY.md` (or a text-only distill fallback) can no longer shadow the concept bundle, break OKF conformance, or lose a turn's learnings — its content is folded into the concept merge and the stale blob is archived. Re-verified leak-free (`mem-probe`, 2000 turns, −570 bytes/turn slope) with a fresh `jeo --tmux` boot battery (6/6).
203
204
  - **[0.6.37]** (2026-06-20) — Two dead-end fixes: the boxed prompt's ↑/↓ now recalls input history on a soft-wrapped one-liner (only a genuine multi-line draft gets in-box caret nav), and every terminating Spec-first stage (deep-interview, ralplan, team) now surfaces a user-visible answer instead of silently stalling — re-verified leak-free (`mem-probe`) with a fresh `jeo --tmux` boot.
204
205
  - **[0.6.36]** (2026-06-20) — When `jeo --tmux` flips the mouse on so you can drag-select, the drag now actually lands on the system clipboard — the in-session tmux profile sets `set-clipboard on` + a local `copy-command` on the CURRENT session only — plus `/help` documents the drag-to-copy and the Shift/Option-drag escape hatch, re-verified leak-free (`mem-probe`) with a fresh `jeo --tmux` boot.
205
206
  - **[0.6.35]** (2026-06-20) — The prompt's Ctrl+C now clears a non-empty input box on the first press and only exits on the next press of an empty box; plus app-driven system-clipboard copy (OSC 52 + local tool, tmux-aware), drag-and-drop image attachment, a Ctrl-L prompt re-anchor, and a SIGCONT resume repaint — verified leak-free (`mem-probe`) with a fresh `jeo --tmux` boot check.
206
207
  - **[0.6.34]** (2026-06-20) — Per-session model memory — each saved session now remembers the model it was last using and restores it on `/resume` — plus clearer `jeo --tmux` attach diagnostics, a tmux session-name double-dash fix, and a more robust no-leak probe gate.
207
- - **[0.6.33]** (2026-06-19) — A redesigned `jeo` forge mark — a hollow line-board crayfish/eyeglass emblem drawn as thick rounded-corner tubes (no letters, no DNA helix) — that now renders inside compact-scaled forge cards, plus a unified verification directive that adds gjc's test-quality contract, and a fresh `jeo --tmux` no-leak re-verification.
208
208
 
209
209
  See [CHANGELOG.md](CHANGELOG.md) for the full history.
210
210
  <!-- CHANGELOG:END -->
package/README.md CHANGED
@@ -200,11 +200,11 @@ Required npm token permissions (repository secret `NPM_TOKEN`):
200
200
  ## Changelog
201
201
 
202
202
  <!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
203
+ - **[0.6.38]** (2026-06-21) — The OKF concept-bundle memory no longer silently drops what it learns: a legacy single-doc `MEMORY.md` (or a text-only distill fallback) can no longer shadow the concept bundle, break OKF conformance, or lose a turn's learnings — its content is folded into the concept merge and the stale blob is archived. Re-verified leak-free (`mem-probe`, 2000 turns, −570 bytes/turn slope) with a fresh `jeo --tmux` boot battery (6/6).
203
204
  - **[0.6.37]** (2026-06-20) — Two dead-end fixes: the boxed prompt's ↑/↓ now recalls input history on a soft-wrapped one-liner (only a genuine multi-line draft gets in-box caret nav), and every terminating Spec-first stage (deep-interview, ralplan, team) now surfaces a user-visible answer instead of silently stalling — re-verified leak-free (`mem-probe`) with a fresh `jeo --tmux` boot.
204
205
  - **[0.6.36]** (2026-06-20) — When `jeo --tmux` flips the mouse on so you can drag-select, the drag now actually lands on the system clipboard — the in-session tmux profile sets `set-clipboard on` + a local `copy-command` on the CURRENT session only — plus `/help` documents the drag-to-copy and the Shift/Option-drag escape hatch, re-verified leak-free (`mem-probe`) with a fresh `jeo --tmux` boot.
205
206
  - **[0.6.35]** (2026-06-20) — The prompt's Ctrl+C now clears a non-empty input box on the first press and only exits on the next press of an empty box; plus app-driven system-clipboard copy (OSC 52 + local tool, tmux-aware), drag-and-drop image attachment, a Ctrl-L prompt re-anchor, and a SIGCONT resume repaint — verified leak-free (`mem-probe`) with a fresh `jeo --tmux` boot check.
206
207
  - **[0.6.34]** (2026-06-20) — Per-session model memory — each saved session now remembers the model it was last using and restores it on `/resume` — plus clearer `jeo --tmux` attach diagnostics, a tmux session-name double-dash fix, and a more robust no-leak probe gate.
207
- - **[0.6.33]** (2026-06-19) — A redesigned `jeo` forge mark — a hollow line-board crayfish/eyeglass emblem drawn as thick rounded-corner tubes (no letters, no DNA helix) — that now renders inside compact-scaled forge cards, plus a unified verification directive that adds gjc's test-quality contract, and a fresh `jeo --tmux` no-leak re-verification.
208
208
 
209
209
  See [CHANGELOG.md](CHANGELOG.md) for the full history.
210
210
  <!-- CHANGELOG:END -->
package/README.zh.md CHANGED
@@ -200,11 +200,11 @@ CI 通过 `.github/workflows/npm-publish.yml` 发布 — GitHub 发布 release
200
200
  ## 更新日志 (Changelog)
201
201
 
202
202
  <!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
203
+ - **[0.6.38]** (2026-06-21) — The OKF concept-bundle memory no longer silently drops what it learns: a legacy single-doc `MEMORY.md` (or a text-only distill fallback) can no longer shadow the concept bundle, break OKF conformance, or lose a turn's learnings — its content is folded into the concept merge and the stale blob is archived. Re-verified leak-free (`mem-probe`, 2000 turns, −570 bytes/turn slope) with a fresh `jeo --tmux` boot battery (6/6).
203
204
  - **[0.6.37]** (2026-06-20) — Two dead-end fixes: the boxed prompt's ↑/↓ now recalls input history on a soft-wrapped one-liner (only a genuine multi-line draft gets in-box caret nav), and every terminating Spec-first stage (deep-interview, ralplan, team) now surfaces a user-visible answer instead of silently stalling — re-verified leak-free (`mem-probe`) with a fresh `jeo --tmux` boot.
204
205
  - **[0.6.36]** (2026-06-20) — When `jeo --tmux` flips the mouse on so you can drag-select, the drag now actually lands on the system clipboard — the in-session tmux profile sets `set-clipboard on` + a local `copy-command` on the CURRENT session only — plus `/help` documents the drag-to-copy and the Shift/Option-drag escape hatch, re-verified leak-free (`mem-probe`) with a fresh `jeo --tmux` boot.
205
206
  - **[0.6.35]** (2026-06-20) — The prompt's Ctrl+C now clears a non-empty input box on the first press and only exits on the next press of an empty box; plus app-driven system-clipboard copy (OSC 52 + local tool, tmux-aware), drag-and-drop image attachment, a Ctrl-L prompt re-anchor, and a SIGCONT resume repaint — verified leak-free (`mem-probe`) with a fresh `jeo --tmux` boot check.
206
207
  - **[0.6.34]** (2026-06-20) — Per-session model memory — each saved session now remembers the model it was last using and restores it on `/resume` — plus clearer `jeo --tmux` attach diagnostics, a tmux session-name double-dash fix, and a more robust no-leak probe gate.
207
- - **[0.6.33]** (2026-06-19) — A redesigned `jeo` forge mark — a hollow line-board crayfish/eyeglass emblem drawn as thick rounded-corner tubes (no letters, no DNA helix) — that now renders inside compact-scaled forge cards, plus a unified verification directive that adds gjc's test-quality contract, and a fresh `jeo --tmux` no-leak re-verification.
208
208
 
209
209
  See [CHANGELOG.md](CHANGELOG.md) for the full history.
210
210
  <!-- CHANGELOG:END -->
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jeo-code",
3
- "version": "0.6.37",
3
+ "version": "0.6.38",
4
4
  "description": "Clean, highly optimized AI coding agent using spec-first loop",
5
5
  "type": "module",
6
6
  "main": "src/cli.ts",
@@ -22,7 +22,7 @@ import { buildConceptGraph, expandByGraph, lintConceptGraph, type GraphLintRepor
22
22
  /** On-disk document cap — the distill prompt instructs the model to stay under it. */
23
23
  export const MEMORY_MAX_CHARS = 6_000;
24
24
  /** Per-session prompt injection budget. */
25
- export const MEMORY_INJECT_MAX_CHARS = 3_000;
25
+ export const MEMORY_INJECT_MAX_CHARS = 5_000;
26
26
  /** Transcript slice fed to the distill call. */
27
27
  const TRANSCRIPT_MAX_CHARS = 12_000;
28
28
  /** A session shorter than this has nothing durable to learn. */
@@ -560,6 +560,7 @@ export async function distillSessionMemory(
560
560
  try {
561
561
  const content = await fs.readFile(file, "utf-8");
562
562
  const parsed = parseConcept(content);
563
+ if (!parsed.hasFrontmatter) continue; // skip MEMORY.md and other legacy blobs
563
564
  existingConcepts.push({
564
565
  type: parsed.frontmatter.type,
565
566
  title: parsed.frontmatter.title || "",
@@ -573,6 +574,11 @@ export async function distillSessionMemory(
573
574
  } catch {}
574
575
  }
575
576
  } catch {}
577
+ // A lingering single-doc MEMORY.md (legacy, or a prior text-only bootstrap
578
+ // fallback) is NOT a concept document — loadConcepts ignores it and it breaks
579
+ // OKF conformance. Feed its content into the merge context so its learnings
580
+ // are absorbed into concepts, then archive it on a successful JSON distill.
581
+ const legacyDoc = await loadMemory(cwd);
576
582
 
577
583
  const prompt: Message[] = [
578
584
  {
@@ -583,12 +589,21 @@ export async function distillSessionMemory(
583
589
  "Keep ONLY what helps future sessions in THIS repository: repo facts (structure, conventions, key files), " +
584
590
  "commands that work (build/test/run), gotchas (failures and their fixes), and user preferences. " +
585
591
  "Drop session-specific noise (one-off tasks, transient errors, conversational detail). " +
592
+ "CRITICAL RULES for concept granularity:\n" +
593
+ " 1. Create ONE concept per distinct fact/command/gotcha/preference — never combine multiple learnings into a single concept.\n" +
594
+ " 2. NEVER create a catch-all 'Project Memory Bundle' or similar mega-concept that lists many things. Split it.\n" +
595
+ " 3. Each Command concept covers exactly one command or workflow (e.g., 'bun test', NOT 'All bun commands').\n" +
596
+ " 4. Each Gotcha covers exactly one failure mode and its fix.\n" +
597
+ " 5. Each UserPreference covers exactly one observable preference.\n" +
598
+ " 6. RepoFact concepts describe structure/conventions — split by area (e.g., 'CLI entrypoint', 'Test setup').\n" +
599
+ " 7. If an existing concept is a mega-concept (lists many things), REPLACE it with properly split granular concepts.\n" +
600
+ " 8. Keep each concept body under 400 chars.\n\n" +
586
601
  "You must output a JSON object with a single key \"concepts\", which is an array of concept objects. " +
587
602
  "Each concept object must have the following fields:\n" +
588
603
  " - \"type\": one of \"RepoFact\", \"Command\", \"Gotcha\", \"UserPreference\"\n" +
589
604
  " - \"title\": a short, descriptive title (e.g., \"Bun test runner\")\n" +
590
605
  " - \"description\": a brief one-line summary of the concept\n" +
591
- " - \"body\": the detailed markdown content/body of the concept\n" +
606
+ " - \"body\": the detailed markdown content/body of the concept (≤400 chars)\n" +
592
607
  " - \"tags\": an array of string tags (optional)\n" +
593
608
  " - \"confidence\": one of \"high\", \"medium\", \"low\" (optional)\n" +
594
609
  " - \"links\": an array of other concept paths/IDs this concept links to (optional)\n\n" +
@@ -598,6 +613,7 @@ export async function distillSessionMemory(
598
613
  role: "user",
599
614
  content:
600
615
  `Existing concepts:\n${JSON.stringify(existingConcepts, null, 2)}\n\n` +
616
+ (legacyDoc ? `Legacy single-doc memory to fold into concepts:\n${legacyDoc}\n\n` : "") +
601
617
  `Session transcript (tail):\n${transcriptTail(history)}`
602
618
  }
603
619
  ];
@@ -695,9 +711,25 @@ export async function distillSessionMemory(
695
711
  if (updatedConcepts.length > 0) {
696
712
  await updateLog(bundleDir, updatedConcepts);
697
713
  }
714
+ // Concepts now own the durable memory and the legacy blob (if any) was
715
+ // folded into the merge above. Archive a lingering MEMORY.md off the active
716
+ // read path so it can never break OKF conformance or shadow the bundle.
717
+ if (legacyDoc) {
718
+ await fs.rename(memoryFilePath(cwd), `${memoryFilePath(cwd)}.bak`).catch(() => {});
719
+ }
698
720
  await cleanupStalePendingFiles(bundleDir);
699
721
  return { updated: true };
700
722
  } else {
723
+ // JSON extraction failed (text-only models often wrap or drop the JSON).
724
+ // The single-doc MEMORY.md is a BOOTSTRAP fallback only: it is injected by
725
+ // memoryPromptSection ONLY when the OKF concept bundle is empty. Writing it
726
+ // while concepts already exist would (a) be silently ignored at injection
727
+ // (concepts win) — losing the learning — and (b) break OKF conformance
728
+ // (MEMORY.md has no frontmatter). So when a bundle exists, do NOT clobber
729
+ // it with a dead blob; keep the prior concepts as the durable memory.
730
+ if (existingConcepts.length > 0) {
731
+ return { updated: false, skipped: "distill produced no JSON; kept existing concept bundle (legacy blob suppressed)" };
732
+ }
701
733
  const doc = distilled.trim().slice(0, MEMORY_MAX_CHARS);
702
734
  if (!doc) return { updated: false, skipped: "model returned an empty document" };
703
735
  const file = memoryFilePath(cwd);