Skip to content

feat(plugin): dynamic per-model system prompt tuning - #1

Merged
metaphorics merged 4 commits into
mainfrom
feat/dynamic-system-prompt
Aug 7, 2026
Merged

metaphorics merged 4 commits into
mainfrom
feat/dynamic-system-prompt

Conversation

@metaphorics

@metaphorics metaphorics commented Aug 7, 2026 •

Copy link
Copy Markdown
Owner

Summary

omp now ships a single before_agent_start hook that appends a capability-scaled ## Model tuning block after the base prompt instead of replacing it. Small/flagship models on newer generations get a light block (≤700 chars), mid-tier or one-generation-back get medium (≤1600), everything unrecognised gets heavy (≤3000). The block shrinks as the model gets newer/larger, matching the observed prior that over-prescriptive scaffolding degrades output on frontier models.

Design

  • Three-axis resolver (src/model-axis.ts) — reuses @oh-my-pi/pi-catalog/identity parsers for openai/anthropic/gemini/glm and adds version+tier regexes for kimi/deepseek/grok/qwen/minimax; normalises :thinking/:free/effort suffixes before matching. One ModelAxis {family,version,tier,weight,profile} shape; unknown → heavy.
  • Rule table (src/rules.ts) — 9 directives, one per concern (deliberation/ambiguity/scope/context-budget/aesthetics/verification), filtered by minWeight ≤ weight and applies(axis), sorted by priority then id, deduped to first per concern, budget-trimmed from the end. Wording pairs positive routing with negative guard (senpi changes.md lesson) and never names the model to itself.
  • Renderer (src/render.ts) — selectRules/renderTuningBlock returns null when empty (no bare heading) and otherwise ## Model tuning + blank-line-joined directives. CHAR_BUDGET[weight] enforces the size dial.
  • Settings (src/settings.ts) — reads ~/.omp/plugins/omp-plugins.lock.json → OMP_MODEL_TUNING* env → manifest defaults; never throws on missing lockfile (morph shape). Header (src/index.ts:29) is gated on hasUI and lastProfile memo.

Verification

  • bun x tsc --noEmit clean
  • bun test ./test — 63 tests across 6 files (28 worked rows + qwen/minimax, real-id fixture, settings precedence, hook idempotency)
  • Catalog sweep bun -e over 2646 ids: 1284 classified, 0 null-versions among classified, every family spans light+heavy (minimax exception documented)
  • Hook probe: deepseek-v4-pro appends once, claude-opus-5 returns undefined (no light rule), second turn with TUNING_HEADER present returns undefined

Notes

  • TypeScript pinned to ^7 (7.0.2 GA 2026-07-08) per ground-latest (was ^5); skipLibCheck:true retained — false breaks upstream pi-catalog/pi-coding-agent types.
  • .references/ added to .gitignore (research material, not plugin source).

Summary by cubic

Adds dynamic, per-model system prompt tuning that appends a scaled ## Model tuning block after the base prompt. Resolver and rules were tightened to avoid dead rules and false matches; settings accept an injected config root for safe tests without changing runtime behavior.

  • Bug Fixes

    • Removed dead-rule overlap: settled-reading is tier-disjoint from reasoning-aim; no-filler-verification moved to a separate verification concern.
    • More reliable family/tier resolution: test both original and normalized ids; word-boundary tier tokens; extracted Anthropic Haiku fallback; safe minimax gate.
    • Settings seam: plugin factory accepts optional configHome; readTuningSettings(home) reads from that root. Production path unchanged.
    • Pre-commit now fail-fast with set -e.
  • Dependencies

    • Upgraded typescript to ^7 (keeps skipLibCheck: true).

Written for commit 5f9fd7e. Summary will update on new commits.

Review in cubic

- Fix .husky/pre-commit fail-fast (set -e via bunx, chain aborts)
- Fix dead rules: settled-reading now tier-disjoint from reasoning-aim,
  no-filler-verification moved to verification concern (separate slot)
- Fix spine warnings: Maeda comment for axis-only families, Hoare
  word-boundary tier tokens and minimax gate comment, Carmack
  extraction of matchesFamily and haiku fallback
- Ground latest: bump typescript ^5 -> ^7 (7.0.2, GA 2026-07-08)
- Tests: add qwen/minimax worked rows, real-id fixture, settings
  precedence and before_agent_start hook coverage (63 tests)
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added support for specifying a custom configuration directory when loading tuning settings.
    • Improved model family, version, tier, and weight detection across Qwen, MiniMax, Kimi, DeepSeek, Grok, and Anthropic Haiku models.
    • Added verification-focused tuning rules and refined model-specific rule selection.
  • Bug Fixes

    • Improved fallback handling for incomplete or unrecognized model identifiers.
    • Reduced incorrect rule matches and ensured more consistent prompt tuning behavior.

Walkthrough

The plugin now supports injectable configuration roots. Model-family resolution uses shared matching and axis construction. Rule concerns and selection tests were expanded. Hook and settings behavior gained isolated coverage. The pre-commit hook now stops on failures, and TypeScript targets version 7.

Changes

Model and prompt behavior

Layer / File(s) Summary
Model axis resolution
src/model-axis.ts, test/model-axis.test.ts, test/render.test.ts
Shared family matching, version parsing, tier detection, axis construction, and Anthropic Haiku fallback resolution were added or updated. Tests cover Qwen, MiniMax, Kimi, DeepSeek, Grok, and boolean-family models.
Rule concerns and selection
src/rules.ts, test/rules.test.ts, test/render.test.ts
The verification concern and shared open-weight matching were added. Rule applicability changed for flagship models. Tests enforce disjoint same-concern rules and verify that every rule wins for at least one model.
Hook configuration and prompt integration
src/index.ts, src/settings.ts, test/hook.test.ts
The plugin accepts an optional configuration root and forwards it to readTuningSettings. Hook tests cover registration, prompt augmentation, weight overrides, unsupported models, duplicate prevention, and UI headers.
Settings precedence and fallback validation
test/settings.test.ts
Tests cover defaults, environment values, lockfile precedence, partial settings, invalid weights, and malformed or incomplete lockfiles.

Repository tooling

Layer / File(s) Summary
Tooling updates
.husky/pre-commit, package.json
The pre-commit hook exits after a failed command. The TypeScript development dependency now targets version ^7.

Estimated code review effort: 3 (Moderate) | ~30 minutes

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title follows Conventional Commits style and clearly describes the dynamic per-model system prompt tuning change.
Description check ✅ Passed The description directly explains the hook, model tuning behavior, resolver, rules, settings, tests, and related changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/dynamic-system-prompt

Comment @coderabbitai help to get the list of available commands.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Simplifying code... This may take up to 20 minutes.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Note

Quiet mode is enabled, so only the most important comments were posted inline. Other review comments are grouped below.

🟡 Other comments (2)
test/hook.test.ts-159-160 (1)

159-160: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Fail when the hook is not registered.

These tests return successfully when loadPlugin() returns no handler. A registration regression then makes the behavior assertions meaningless.

Assert that handler exists before each guard.

Also applies to: 174-175

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/hook.test.ts` around lines 159 - 160, Update the tests around loadPlugin
in test/hook.test.ts so they assert that the returned handler exists instead of
silently returning when it is absent. Apply this to both guarded cases near
lines 159-160 and 174-175, preserving the subsequent behavior assertions.
test/hook.test.ts-201-205 (1)

201-205: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Remove the first temporary home before creating the second.

The second freshHome() call overwrites tmpHome. afterEach removes only the second directory. The first mt-hook-* directory remains on disk.

Clean the existing tmpHome in freshHome() before assigning a new path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/hook.test.ts` around lines 201 - 205, Update freshHome() to remove the
currently assigned tmpHome directory before generating and assigning a new
temporary home path, ensuring repeated calls clean up the prior mt-hook-*
directory while preserving the existing setup behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/hook.test.ts`:
- Around line 17-20: Remove the top-level partial node:os mock from
test/hook.test.ts (lines 17-20) and test/settings.test.ts (lines 14-17). Update
the affected tests to inject the home-directory dependency directly instead,
preserving their existing homedir behavior without replacing the shared node:os
module.

---

Other comments:
In `@test/hook.test.ts`:
- Around line 159-160: Update the tests around loadPlugin in test/hook.test.ts
so they assert that the returned handler exists instead of silently returning
when it is absent. Apply this to both guarded cases near lines 159-160 and
174-175, preserving the subsequent behavior assertions.
- Around line 201-205: Update freshHome() to remove the currently assigned
tmpHome directory before generating and assigning a new temporary home path,
ensuring repeated calls clean up the prior mt-hook-* directory while preserving
the existing setup behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: QUIET

Plan: Pro Plus

Run ID: 03733ac5-4fa8-4a70-91fb-14516cc37bcd

📥 Commits

Reviewing files that changed from the base of the PR and between 9540624 and 0158fd0.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (10)
  • .husky/pre-commit
  • package.json
  • src/index.ts
  • src/model-axis.ts
  • src/rules.ts
  • test/hook.test.ts
  • test/model-axis.test.ts
  • test/render.test.ts
  • test/rules.test.ts
  • test/settings.test.ts
📜 Review details
🧰 Additional context used
🪛 ast-grep (0.45.0)
test/hook.test.ts

[error] 77-80: Recursive/iterative merge copies attacker-controllable keys from a source object into a target via a computed property assignment without rejecting dangerous keys, allowing prototype pollution. Skip or block "proto", "constructor", and "prototype" keys (e.g. if (key === "__proto__" || key === "constructor" || key === "prototype") continue;), use a null-prototype object (Object.create(null)), or use a safe merge utility instead.
Context: for (const k of ENV_KEYS) {
savedEnv[k] = process.env[k];
delete process.env[k];
}
Note: [CWE-1321] Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution').

(prototype-pollution-recursive-merge-typescript)


[error] 84-87: Recursive/iterative merge copies attacker-controllable keys from a source object into a target via a computed property assignment without rejecting dangerous keys, allowing prototype pollution. Skip or block "proto", "constructor", and "prototype" keys (e.g. if (key === "__proto__" || key === "constructor" || key === "prototype") continue;), use a null-prototype object (Object.create(null)), or use a safe merge utility instead.
Context: for (const k of ENV_KEYS) {
if (savedEnv[k] === undefined) delete process.env[k];
else process.env[k] = savedEnv[k];
}
Note: [CWE-1321] Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution').

(prototype-pollution-recursive-merge-typescript)

test/settings.test.ts

[error] 47-50: Recursive/iterative merge copies attacker-controllable keys from a source object into a target via a computed property assignment without rejecting dangerous keys, allowing prototype pollution. Skip or block "proto", "constructor", and "prototype" keys (e.g. if (key === "__proto__" || key === "constructor" || key === "prototype") continue;), use a null-prototype object (Object.create(null)), or use a safe merge utility instead.
Context: for (const k of ENV_KEYS) {
savedEnv[k] = process.env[k];
delete process.env[k];
}
Note: [CWE-1321] Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution').

(prototype-pollution-recursive-merge-typescript)


[error] 54-57: Recursive/iterative merge copies attacker-controllable keys from a source object into a target via a computed property assignment without rejecting dangerous keys, allowing prototype pollution. Skip or block "proto", "constructor", and "prototype" keys (e.g. if (key === "__proto__" || key === "constructor" || key === "prototype") continue;), use a null-prototype object (Object.create(null)), or use a safe merge utility instead.
Context: for (const k of ENV_KEYS) {
if (savedEnv[k] === undefined) delete process.env[k];
else process.env[k] = savedEnv[k];
}
Note: [CWE-1321] Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution').

(prototype-pollution-recursive-merge-typescript)

src/model-axis.ts

[warning] 124-124: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp((^|[-._/])${t}($|[-._/]))
Note: [CWE-1333] Inefficient Regular Expression Complexity

(regexp-from-variable)


[warning] 127-127: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp((^|[-._/])${t}($|[-._/]))
Note: [CWE-1333] Inefficient Regular Expression Complexity

(regexp-from-variable)

🪛 OpenGrep (1.26.0)
src/model-axis.ts

[ERROR] 216-216: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.

(coderabbit.command-injection.exec-js)

🔍 Remote MCP Context7, Grep, Valyu

Additional review context

  • TypeScript 7.0 is stable and published via the typescript npm package. However, it does not ship the programmatic compiler API; the official guidance recommends @typescript/typescript6 for tools such as typescript-eslint that import TypeScript directly. Verify the lint/test toolchain does not depend on that API.
  • TypeScript 7 introduces configuration changes and hard errors, including defaults for strict, module, rootDir, and types, plus removal of legacy options such as baseUrl and moduleResolution: node. Confirm the repository’s tsconfig explicitly remains compatible.
  • TypeScript 6’s package still exposes the JavaScript compiler API, providing a concrete compatibility distinction between the old and new major versions.
  • Repository searches did not locate this exact project or its model-tuning implementation, so model-regex and hook-behavior claims could not be independently validated.
🔇 Additional comments (9)
src/model-axis.ts (1)

9-12: LGTM!

Also applies to: 78-80, 118-136, 192-229, 249-249, 271-278, 293-293, 310-318, 328-328, 348-348, 359-360

test/model-axis.test.ts (1)

174-201: LGTM!

test/render.test.ts (2)

2-2: LGTM!

Also applies to: 19-27


120-120: 🎯 Functional Correctness

Keep the single fixtures declaration.

test/render.test.ts contains only one declaration in this scope, so this compile-error claim is incorrect.

			> Likely an incorrect or invalid review comment.
src/rules.ts (1)

3-9: LGTM!

Also applies to: 20-41, 88-88

src/index.ts (1)

28-28: LGTM!

test/rules.test.ts (1)

3-3: LGTM!

Also applies to: 49-80

.husky/pre-commit (1)

1-1: LGTM!

package.json (1)

52-52: 🩺 Stability & Availability

Do not block TypeScript 7 on compiler API compatibility.

The project invokes TypeScript only through tsc. lint-staged and bun test do not consume the TypeScript compiler API. The lockfile resolves typescript@7.0.2.

			> Likely an incorrect or invalid review comment.

Comment thread test/hook.test.ts
@metaphorics

Copy link
Copy Markdown
Owner Author

@coderabbitai ultrareview

@coderabbitai

coderabbitai Bot commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

@metaphorics Starting a comprehensive review of all changes in PR #1.

⚠️ Action not completed

Review rate limited.


Your included review limit is currently reached under our Fair Usage Limits Policy. Your recent PR review activity is in the 95th percentile or higher among CodeRabbit users, so adaptive limits apply. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 2 minutes.

The two new test files replaced node:os in the shared module registry with a
partial mock (homedir + tmpdir only) and never restored it. `bun test` runs one
registry for the whole suite, so any later file reaching for os.platform(),
os.EOL, or os.cpus() would have received undefined -- a landmine whose blast
radius depended on file ordering.

readTuningSettings and the plugin entry now take the config root as a
parameter, so tests point at a temp directory instead of mutating a global.
omp's loader still calls the factory with `pi` alone.

Two vacuous tests fixed while here: `if (!handler) return;` let a registration
regression pass silently, so loadHandler throws instead. freshHome now removes
its predecessor -- the second call in the weight-override test orphaned the
first mt-hook-* directory past afterEach.
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

✅ Created PR with simplified code: #2

📝 CodeRabbit Chat: Simplify code structure
@metaphorics
metaphorics merged commit f3777b0 into main Aug 7, 2026
1 of 2 checks passed
@metaphorics
metaphorics deleted the feat/dynamic-system-prompt branch August 7, 2026 16:08

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

Quiet mode is enabled, so only the most important comments were posted inline. Other review comments are grouped below.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/model-axis.ts (1)

84-107: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Preserve semantic minor versions.

versionFromDigits("2", "10") returns 2.1. It then compares below 2.9 and renders as 2.1, although version 2.10 is newer than 2.9.

Use a structured major/minor representation, or a comparison-safe encoding. Update FRONTIER_VERSION, GENERATION_STEP, deriveWeight, and profile rendering with the same representation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/model-axis.ts` around lines 84 - 107, Replace the decimal encoding in
versionFromDigits with a comparison-safe major/minor representation that
preserves values such as 2.10 as newer than 2.9. Update FRONTIER_VERSION,
GENERATION_STEP, deriveWeight, and profile rendering to consume and display that
same representation consistently, preserving correct ordering and semantic
minor-version output.
🟡 Other comments (1)
test/hook.test.ts-67-70 (1)

67-70: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Test the injected configuration-root path.

loadPlugin always calls dynamicSystemPromptPlugin(pi). The hook suite cannot verify that configHome reaches readTuningSettings.

Accept an optional configHome parameter in loadPlugin. Pass it to dynamicSystemPromptPlugin. Add a hook test that writes a lockfile under the temporary root and calls loadPlugin(home).

Based on learnings, keep configuration-root injection explicit and test it without mocking node:os.

Proposed fix
-async function loadPlugin(): Promise<CapturedHandler | undefined> {
+async function loadPlugin(
+  configHome?: string,
+): Promise<CapturedHandler | undefined> {
   const { pi, getHandler } = createStubPi();
-  await dynamicSystemPromptPlugin(pi);
+  await dynamicSystemPromptPlugin(pi, configHome);
   return getHandler();
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/hook.test.ts` around lines 67 - 70, Update loadPlugin to accept an
optional configHome argument and forward it to dynamicSystemPromptPlugin,
keeping configuration-root injection explicit. Add a hook test that creates a
lockfile beneath a temporary root and invokes loadPlugin with that root to
verify the path reaches readTuningSettings; do not mock node:os.

Source: Learnings

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/model-axis.ts`:
- Around line 84-107: Replace the decimal encoding in versionFromDigits with a
comparison-safe major/minor representation that preserves values such as 2.10 as
newer than 2.9. Update FRONTIER_VERSION, GENERATION_STEP, deriveWeight, and
profile rendering to consume and display that same representation consistently,
preserving correct ordering and semantic minor-version output.

---

Other comments:
In `@test/hook.test.ts`:
- Around line 67-70: Update loadPlugin to accept an optional configHome argument
and forward it to dynamicSystemPromptPlugin, keeping configuration-root
injection explicit. Add a hook test that creates a lockfile beneath a temporary
root and invokes loadPlugin with that root to verify the path reaches
readTuningSettings; do not mock node:os.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: QUIET

Plan: Pro Plus

Run ID: ea609394-e006-4347-83a3-077e0b653dd7

📥 Commits

Reviewing files that changed from the base of the PR and between 0158fd0 and 5f9fd7e.

📒 Files selected for processing (6)
  • src/index.ts
  • src/model-axis.ts
  • src/rules.ts
  • src/settings.ts
  • test/hook.test.ts
  • test/settings.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Run typechecking with bun x tsc --noEmit -p tsconfig.json; this is especially important for pi-catalog import paths.
Verify the three-axis resolver against the live catalog with a bun -e sweep covering 2646 IDs, with no null version among classified models.
Do not add runtime dependencies; every import must be a Node builtin or an omp package resolved from the host.
Preserve append-only behavior: never replace omp's system prompt; only append ## Model tuning via before_agent_start.
Before appending, check event.systemPrompt.some(entry => entry.includes(TUNING_HEADER)) so tuning content does not accumulate across turns.
Resolve model identity through @oh-my-pi/pi-catalog/identity using bareModelId, the provider parsers, and family predicates; never re-implement parsers.
Normalize model IDs by lowercasing bareModelId(id) and stripping :thinking, :free, -cheaper, @default, [1m], -high, and equivalent suffixes before classification.
Derive weight from FRONTIER_VERSION and GENERATION_STEP, apply the small tier penalty, and ensure unknown models are assigned heavy.
Keep one rule per concern; sort rules by priority and then id, and trim from the end to CHAR_BUDGET[weight].
Never include the model name, version, or profile string in the rendered ## Model tuning block.
Read settings from ~/.omp/plugins/omp-plugins.lock.json under omp-plugin-dynamic-system-prompt, falling back to OMP_MODEL_TUNING* environment variables and manifest defaults; never throw when the lockfile is missing.

Files:

  • src/settings.ts
  • src/index.ts
  • test/hook.test.ts
  • src/model-axis.ts
  • test/settings.test.ts
  • src/rules.ts
**/test/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Run unit tests with bun test ./test and ensure all four test files pass.

Files:

  • test/hook.test.ts
  • test/settings.test.ts
🧠 Learnings (1)
📚 Learning: 2026-08-07T15:53:07.838Z
Learnt from: metaphorics
Repo: metaphorics/omp-plugin-dynamic-system-prompt PR: 1
File: test/hook.test.ts:0-0
Timestamp: 2026-08-07T15:53:07.838Z
Learning: In this Bun TypeScript plugin, keep configuration-root injection explicit: `readTuningSettings(home = homedir())` should accept an injectable config-root path, and `dynamicSystemPromptPlugin(pi, configHome?)` should pass it through while production continues calling `dynamicSystemPromptPlugin(pi)` via the unchanged `ExtensionFactory` interface. In `test/hook.test.ts` and `test/settings.test.ts`, avoid partial `mock.module("node:os", ...)` replacements because Bun test files may share a module registry; use injected paths instead.

Applied to files:

  • test/hook.test.ts
  • test/settings.test.ts
🪛 ast-grep (0.45.0)
src/model-axis.ts

[warning] 133-133: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp((^|[-._/])${t}($|[-._/]))
Note: [CWE-1333] Inefficient Regular Expression Complexity

(regexp-from-variable)

🔍 Remote MCP Grep, Sequential Thinking, Valyu

Additional review context

  • TypeScript 7 is available as the standard typescript npm package and uses the usual tsc command. However, it does not provide the prior programmatic compiler API; tools such as typescript-eslint may need the TypeScript 6 compatibility package until the TypeScript 7.1 API is available. Verify all lint, test, bundler, and code-generation dependencies before accepting the upgrade.

  • TypeScript 7 adopts stricter defaults, including strict: true, module: "esnext", rootDir: "./", and types: []. It also turns several options into hard errors, including baseUrl, moduleResolution: "node"/"node10"/"classic", and target: "es5". The repository’s tsconfig and inherited configs should be checked explicitly.

  • TypeScript 7’s parallel checker defaults can increase memory usage; CI behavior should be validated rather than relying only on the reported test count.

  • A GitHub search found unrelated projects already declaring "typescript": "^7", confirming the version range is in active use, but it did not identify this repository or validate this PR’s toolchain compatibility.

  • Sequential review prioritization identified the TypeScript upgrade and its surrounding configuration/toolchain as the highest-risk area.

🔇 Additional comments (6)
src/model-axis.ts (2)

3-12: 🎯 Functional Correctness

Validate the TypeScript 7 and catalog contract.

Run bun x tsc --noEmit -p tsconfig.json. Run bun test ./test and ensure the required test files pass. Run the required bun -e sweep across all 2,646 catalog IDs, and ensure every recognized family resolves with a non-null version.

This change imports catalog predicates and changes resolver paths used by the prompt hook. TypeScript 7 and catalog export compatibility must be confirmed before merge. As per coding guidelines, “Run typechecking with bun x tsc --noEmit -p tsconfig.json” and verify the three-axis resolver against the live catalog.

Also applies to: 245-360

Sources: Coding guidelines, MCP tools


133-141: LGTM!

src/rules.ts (1)

1-1: LGTM!

Also applies to: 26-50, 59-59, 68-68, 85-85

src/settings.ts (1)

53-60: LGTM!

test/settings.test.ts (1)

1-10: LGTM!

Also applies to: 21-26, 61-146

src/index.ts (1)

10-14: 📐 Maintainability & Code Quality

Run the required Bun validation suite. Run typechecking, bun test ./test, and the bun -e sweep across all 2,646 live catalog IDs. The current environment lacks Bun and node_modules; global tsc stops because bun-types is missing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant