CodeNomad/packages/server/scripts/native-plugin-build.test.mjs
Pascal André 7a206a9297
feat(history): rank past-session search and expose it to agents as session_search (#1161)
## Summary

Agents can now find past discussions themselves. The bundled
session-pruning plugin registers a Code Mode tool,
`codenomad.session_search`, ranked by relevance over the calling
session's own project history. This is PR 1 of 2: server/plugin only;
the search window keeps its current behaviour until PR 2 wires the same
engine.

- **Tool scope:** the caller's directory tree, native workspace and
project (plus `global`) history, never other projects. The caller's
location is checked before and after the read, and excerpts are flagged
as untrusted transcript data. The tool follows backend presence like the
plugin's RPCs.
- **Ranking:** up to six Unicode terms; a precise SQL prefilter over
rowid chunks (superset of the JS judge: ASCII folding, Unicode case
classes, literal `\u` escape fallback) yields per-term IDF weights. The
best candidates are judged one bounded body at a time on word
boundaries, with an exact-phrase bonus, prose before tool payloads,
recency as tie-break and one hit per session before repeats. Optional
inclusive UTC `since`/`until`. Candidate, session, judge and time caps
are reported.
- **Shared limits:** scope SQL, readable-part extraction, the 16 MiB
message bound and 40 ms slices move to `history-content.ts` and are
shared with the literal search.
- **For PR 2:** a versioned `historyRanked` RPC returns the same hit
fields plus per-session provenance, so the broker can validate ownership
as for `history`. Existing RPC methods, HTTP routes and UI are
unchanged; the generic RPC proxy stays closed.

Inspired by `@rizal72/oc-session-search`.

## Validation

- Session-pruning tests 98/98, including the package regression; native
plugin bundle 1/1; server typecheck.
- Regressions: Unicode terms and accented case variants, weights, phrase
bonus, diversity, dates, prefilter precision (multi-line and accented
messages lacking a term are not candidates), a rare old match outranking
600+ newer frequent ones, scope isolation, cancellation, caps, skipped
rows, tool registration and presence disposal.
- Isolated native history fixture on OpenCode 2.2.0: 23 checks,
including a ranked query (3 hits across 2 sessions). No shared daemon or
user database was used.
2026-10-27 19:41:50 +01:00

21 lines
1.2 KiB
JavaScript

import assert from "node:assert/strict"
import { test } from "node:test"
import { fileURLToPath } from "node:url"
import { build } from "esbuild"
import { nativePluginBuild } from "./native-plugin-build.mjs"
test("native plugin builds never embed a second Effect runtime or OpenCode adapter", async () => {
for (const entry of ["session-pruning/desktop-plugin", "automation/desktop-plugin", "missions/managed-owner-plugin"]) {
const result = await build({ ...nativePluginBuild,
entryPoints: [fileURLToPath(new URL(`../src/opencode/${entry}.ts`, import.meta.url))],
write: false, metafile: true })
const inputs = Object.keys(result.metafile.inputs).map(value => value.replaceAll("\\", "/"))
assert.equal(inputs.some(value => /node_modules\/(?:effect|@opencode\/plugin)\//.test(value)), false, entry)
assert(result.outputFiles[0].text.includes("desktopPlugin"), entry)
if (entry === "session-pruning/desktop-plugin") {
assert(result.outputFiles[0].text.includes('name: "session_search"'))
assert(result.outputFiles[0].text.includes("codemode: true"))
assert.equal(inputs.some(value => value.endsWith("workspaces/git-process.ts")), false, "Ranked ownership stays filesystem-only")
}
}
})