@retaw106/mmc-oc 2.6.0 → 2.7.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/dist/{context-cfbjrr0n.js → context-9q17e52a.js} +140 -53
- package/dist/features/magic-context/auto-search-diagnostics.d.ts +27 -0
- package/dist/features/magic-context/auto-search-diagnostics.d.ts.map +1 -0
- package/dist/features/magic-context/search.d.ts +4 -0
- package/dist/features/magic-context/search.d.ts.map +1 -1
- package/dist/hooks/magic-context/auto-search-observation.d.ts +13 -0
- package/dist/hooks/magic-context/auto-search-observation.d.ts.map +1 -0
- package/dist/hooks/magic-context/auto-search-runner.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/{index-1np16gxq.js → index-cgjyhwdk.js} +1 -1
- package/dist/{index-xk1dz6q9.js → index-xrxpbe74.js} +34 -1
- package/dist/index.js +14 -4
- package/dist/{recomp-orchestrator-51xyaexp.js → recomp-orchestrator-gzd1at06.js} +2 -2
- package/dist/shared/search-text.d.ts +2 -0
- package/dist/shared/search-text.d.ts.map +1 -1
- package/dist/tools/ctx-expand/render.d.ts +5 -3
- package/dist/tools/ctx-expand/render.d.ts.map +1 -1
- package/dist/tools/ctx-expand/tools.d.ts +2 -0
- package/dist/tools/ctx-expand/tools.d.ts.map +1 -1
- package/dist/tools/parameter-descriptions.d.ts +6 -6
- package/dist/tools/parameter-descriptions.d.ts.map +1 -1
- package/dist/tui.js +2144 -0
- package/dist/v2/server.js +194 -54
- package/dist/v2/tui/client.d.ts +57 -0
- package/dist/v2/tui/client.d.ts.map +1 -0
- package/dist/v2/tui/context-rpc.d.ts +63 -0
- package/dist/v2/tui/context-rpc.d.ts.map +1 -0
- package/dist/v2/tui/entry.d.ts +8 -0
- package/dist/v2/tui/entry.d.ts.map +1 -0
- package/dist/v2/tui/notification-socket.d.ts +26 -0
- package/dist/v2/tui/notification-socket.d.ts.map +1 -0
- package/dist/v2/tui/session-directory.d.ts +22 -0
- package/dist/v2/tui/session-directory.d.ts.map +1 -0
- package/dist/v2/tui/types.d.ts +110 -0
- package/dist/v2/tui/types.d.ts.map +1 -0
- package/dist/{wrapup-orchestrator-g0mww1h4.js → wrapup-orchestrator-ghq4y406.js} +2 -2
- package/package.json +13 -3
- package/src/shared/prompt-surface-a1-golden.md +5 -5
- package/src/shared/search-text.test.ts +36 -1
- package/src/shared/search-text.ts +48 -0
- package/tui.js +4 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entry.d.ts","sourceRoot":"","sources":["../../../src/v2/tui/entry.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,iBAAe,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,CAG/D;;;;;AAGD,wBAA2C"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface SocketNotification {
|
|
2
|
+
id: number;
|
|
3
|
+
type: string;
|
|
4
|
+
payload: Record<string, unknown>;
|
|
5
|
+
sessionId?: string;
|
|
6
|
+
}
|
|
7
|
+
interface NotificationSocketOptions {
|
|
8
|
+
/** Current active session id (re-read cheaply to follow session switches). */
|
|
9
|
+
getSessionId: () => string | null;
|
|
10
|
+
/**
|
|
11
|
+
* Directory of the active session, when the host reports it. The socket
|
|
12
|
+
* subscribes to that directory's server, because that is the server whose
|
|
13
|
+
* commands push this session's notifications; null means the startup one.
|
|
14
|
+
*/
|
|
15
|
+
getSessionDirectory?: () => string | null;
|
|
16
|
+
/** Handle one delivered notification. Returns true only after it is fully
|
|
17
|
+
* consumed and can be acknowledged. Async because dialog handlers await. */
|
|
18
|
+
onNotification: (notification: SocketNotification) => boolean | Promise<boolean>;
|
|
19
|
+
}
|
|
20
|
+
/** Open the persistent notification socket. Reconnects on its own after a drop. */
|
|
21
|
+
export declare function startNotificationSocket(options: NotificationSocketOptions): void;
|
|
22
|
+
/** Close the socket and release all state owned by this TUI initialization. */
|
|
23
|
+
export declare function stopNotificationSocket(): void;
|
|
24
|
+
export declare function _resetNotificationSocketStateForTesting(): void;
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=notification-socket.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification-socket.d.ts","sourceRoot":"","sources":["../../../src/v2/tui/notification-socket.ts"],"names":[],"mappings":"AAiDA,MAAM,WAAW,kBAAkB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,UAAU,yBAAyB;IAC/B,8EAA8E;IAC9E,YAAY,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IAClC;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IAC1C;iFAC6E;IAC7E,cAAc,EAAE,CAAC,YAAY,EAAE,kBAAkB,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACpF;AAoDD,mFAAmF;AACnF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,yBAAyB,GAAG,IAAI,CAOhF;AAED,+EAA+E;AAC/E,wBAAgB,sBAAsB,IAAI,IAAI,CAiC7C;AA2UD,wBAAgB,uCAAuC,IAAI,IAAI,CAE9D"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { V2TuiContext } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* The directory whose Magic Context server owns a session.
|
|
4
|
+
*
|
|
5
|
+
* OpenCode starts one Magic Context server instance per directory. The TUI
|
|
6
|
+
* starts in one directory but can show a session from another one (non-git
|
|
7
|
+
* directories share OpenCode's global project, so a TUI started in the home
|
|
8
|
+
* directory lists sessions from any of them). The status dialog must ask the
|
|
9
|
+
* server for the session's directory, not the startup one.
|
|
10
|
+
*
|
|
11
|
+
* `sessionDirectory` is what the host reports for the session
|
|
12
|
+
* (`context.data.session.get(id).location.directory` on OpenCode 2). The
|
|
13
|
+
* startup directory is the fallback while the host has not loaded the session.
|
|
14
|
+
*/
|
|
15
|
+
export declare function directoryForSession(sessionDirectory: unknown, startupDirectory: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* The directory of the Magic Context server that owns `sessionID` on this host,
|
|
18
|
+
* or undefined while the host has not loaded the session (the caller then uses
|
|
19
|
+
* its startup directory). See `directoryForSession`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function sessionDirectory(context: V2TuiContext, sessionID: string): string | undefined;
|
|
22
|
+
//# sourceMappingURL=session-directory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-directory.d.ts","sourceRoot":"","sources":["../../../src/v2/tui/session-directory.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,gBAAgB,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAI/F;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAM7F"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
export interface V2TuiLocation {
|
|
2
|
+
readonly directory: string;
|
|
3
|
+
}
|
|
4
|
+
export interface V2TuiRoute {
|
|
5
|
+
readonly type: string;
|
|
6
|
+
readonly sessionID?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface V2TuiContext {
|
|
9
|
+
readonly location?: V2TuiLocation;
|
|
10
|
+
readonly data: {
|
|
11
|
+
readonly location: {
|
|
12
|
+
default(): V2TuiLocation;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* `Context.data.session` on GA 2.0.x. `location.directory` is the
|
|
16
|
+
* directory whose Magic Context server owns the session. Optional so a
|
|
17
|
+
* host without it falls back to the startup directory.
|
|
18
|
+
*/
|
|
19
|
+
readonly session?: {
|
|
20
|
+
get(sessionID: string): {
|
|
21
|
+
readonly location?: {
|
|
22
|
+
readonly directory?: string;
|
|
23
|
+
};
|
|
24
|
+
} | undefined;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
readonly renderer: {
|
|
28
|
+
requestRender(): void;
|
|
29
|
+
};
|
|
30
|
+
readonly keymap: {
|
|
31
|
+
/** `Context.keymap.layer` on GA 2.0.22. See `V2KeymapLayer`. */
|
|
32
|
+
readonly layer: (input: () => V2KeymapLayer) => void;
|
|
33
|
+
};
|
|
34
|
+
readonly ui: {
|
|
35
|
+
readonly router: {
|
|
36
|
+
current(): V2TuiRoute;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* `Context.ui.slot` on GA 2.0.22: claims a place in the host's slot
|
|
40
|
+
* tree and returns the unregister function. See `V2SlotClaim`.
|
|
41
|
+
*/
|
|
42
|
+
readonly slot: (claim: V2SlotClaim) => () => void;
|
|
43
|
+
readonly toast: {
|
|
44
|
+
show(options: {
|
|
45
|
+
readonly title?: string;
|
|
46
|
+
readonly message: string;
|
|
47
|
+
readonly variant?: "info" | "success" | "warning" | "error";
|
|
48
|
+
readonly duration?: number;
|
|
49
|
+
}): void;
|
|
50
|
+
};
|
|
51
|
+
readonly dialog: {
|
|
52
|
+
alert(options: {
|
|
53
|
+
readonly title: string;
|
|
54
|
+
readonly message: string;
|
|
55
|
+
}): Promise<void>;
|
|
56
|
+
confirm(options: {
|
|
57
|
+
readonly title: string;
|
|
58
|
+
readonly message: string;
|
|
59
|
+
readonly label?: {
|
|
60
|
+
readonly confirm?: string;
|
|
61
|
+
readonly cancel?: string;
|
|
62
|
+
};
|
|
63
|
+
}): Promise<boolean | undefined>;
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* One keymap command, aligned with `@opencode/plugin` 2.0.22's
|
|
69
|
+
* `dist/tui/context.d.ts` `KeymapCommand` (the fields this layer writes).
|
|
70
|
+
* Differences from that declaration, kept as a structural subset so the
|
|
71
|
+
* plugin depends on no @opentui/* types: 2.0.22 makes `id`/`title`/`group`
|
|
72
|
+
* optional (inline commands omit them) and adds `description`/`enabled`/
|
|
73
|
+
* `bind`/`suggested`; its `run` also receives the dispatching `KeyEvent` as a
|
|
74
|
+
* second argument and may return `false` to continue dispatch. This layer
|
|
75
|
+
* always names its commands and reads only the slash input, so the narrower
|
|
76
|
+
* `run` shape stays assignable to the host's.
|
|
77
|
+
*/
|
|
78
|
+
export interface V2KeymapCommand {
|
|
79
|
+
readonly id: string;
|
|
80
|
+
readonly title: string;
|
|
81
|
+
readonly group: string;
|
|
82
|
+
readonly palette: true;
|
|
83
|
+
readonly slash: {
|
|
84
|
+
readonly name: string;
|
|
85
|
+
readonly arguments?: true;
|
|
86
|
+
};
|
|
87
|
+
readonly run: (input?: string) => void | Promise<void>;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* The layer object `context.keymap.layer()` accepts, aligned with 2.0.22's
|
|
91
|
+
* `KeymapLayer` (whose `mode`/`commands` are optional and which also carries
|
|
92
|
+
* `enabled`/`target`/`priority`/`bindings`). This layer always pins
|
|
93
|
+
* `mode: "global"` and lists its commands.
|
|
94
|
+
*/
|
|
95
|
+
export interface V2KeymapLayer {
|
|
96
|
+
readonly mode: string;
|
|
97
|
+
readonly commands: readonly V2KeymapCommand[];
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* The one slot claim this face uses, a subset of 2.0.22's `SlotClaim`
|
|
101
|
+
* (`SlotMap["app"]` input is `Readonly<Record<string, never>>`; 2.0.22's claim
|
|
102
|
+
* type is a mutually-exclusive placement union whose `render` returns a
|
|
103
|
+
* Solid `JSX.Element` — this layer's app-slot render returns `null`, which
|
|
104
|
+
* the host accepts at runtime).
|
|
105
|
+
*/
|
|
106
|
+
export interface V2SlotClaim {
|
|
107
|
+
readonly append: "app";
|
|
108
|
+
readonly render: (input: Readonly<Record<string, never>>) => unknown;
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/v2/tui/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
getActiveCompartmentRun,
|
|
22
22
|
markActiveCompartmentRunPublished,
|
|
23
23
|
registerActiveCompartmentRun
|
|
24
|
-
} from "./index-
|
|
24
|
+
} from "./index-xrxpbe74.js";
|
|
25
25
|
import"./index-pte3cfs9.js";
|
|
26
26
|
import"./index-x37vg474.js";
|
|
27
27
|
import"./index-t0zx3tgz.js";
|
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
import {
|
|
38
38
|
setRecompStarting2,
|
|
39
39
|
setRecompTerminal2
|
|
40
|
-
} from "./index-
|
|
40
|
+
} from "./index-cgjyhwdk.js";
|
|
41
41
|
import"./index-yjv8dpht.js";
|
|
42
42
|
|
|
43
43
|
// src/hooks/magic-context/wrapup-orchestrator.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@retaw106/mmc-oc",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "OpenCode plugin for Magic Context — cross-session memory and context management",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -31,14 +31,16 @@
|
|
|
31
31
|
"files": [
|
|
32
32
|
"dist",
|
|
33
33
|
"index.js",
|
|
34
|
+
"tui.js",
|
|
34
35
|
"src/shared",
|
|
35
36
|
"src/config",
|
|
36
37
|
"src/agents",
|
|
37
38
|
"README.md"
|
|
38
39
|
],
|
|
39
40
|
"scripts": {
|
|
40
|
-
"build": "bun ../../scripts/check-bun.mjs && bun ../../scripts/clean-dist-chunks.mjs dist index.js config-init.js cli.js && rm -rf dist/web && bun build src/index.ts --outdir dist --target node --format esm --splitting --external @opencode-ai/plugin --external bun:sqlite --external node:sqlite && bun run build:v2 && bun run build:web && bun run build:config-init && bun run build:cli && tsc --emitDeclarationOnly",
|
|
41
|
+
"build": "bun ../../scripts/check-bun.mjs && bun ../../scripts/clean-dist-chunks.mjs dist index.js config-init.js cli.js && rm -rf dist/web && bun build src/index.ts --outdir dist --target node --format esm --splitting --external @opencode-ai/plugin --external bun:sqlite --external node:sqlite && bun run build:v2 && bun run build:tui && bun run build:web && bun run build:config-init && bun run build:cli && tsc --emitDeclarationOnly",
|
|
41
42
|
"build:v2": "bun build src/v2/server.ts --outfile dist/v2/server.js --target node --format esm --external @opencode/plugin && bun test src/v2/server.test.ts",
|
|
43
|
+
"build:tui": "bun build src/v2/tui/entry.ts --outfile dist/tui.js --target node --format esm",
|
|
42
44
|
"build:web": "bun build src/web/main.ts --outfile dist/web/main.js --target node --format esm --external bun:sqlite --external node:sqlite && mkdir -p dist/web/ui && cp src/web/ui/* dist/web/ui/",
|
|
43
45
|
"build:config-init": "bun build scripts/config-init-entry.ts --outfile dist/config-init.js --target node --format esm",
|
|
44
46
|
"build:cli": "bun build scripts/cli.ts --outfile dist/cli.js --target node --format esm",
|
|
@@ -80,10 +82,18 @@
|
|
|
80
82
|
".": {
|
|
81
83
|
"types": "./dist/index.d.ts",
|
|
82
84
|
"import": "./dist/index.js"
|
|
85
|
+
},
|
|
86
|
+
"./tui": {
|
|
87
|
+
"import": "./tui.js"
|
|
83
88
|
}
|
|
84
89
|
},
|
|
85
90
|
"oc-plugin": [
|
|
86
|
-
"server"
|
|
91
|
+
"server",
|
|
92
|
+
"tui"
|
|
93
|
+
],
|
|
94
|
+
"opencode": [
|
|
95
|
+
"server",
|
|
96
|
+
"tui"
|
|
87
97
|
],
|
|
88
98
|
"peerDependencies": {
|
|
89
99
|
"@opencode-ai/plugin": ">=1.15.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Magic Context agent-facing surface (exported from source)
|
|
2
2
|
|
|
3
|
-
Generated by `packages/plugin/scripts/export-agent-surface.ts` at 2026-11-
|
|
3
|
+
Generated by `packages/plugin/scripts/export-agent-surface.ts` at 2026-11-10.
|
|
4
4
|
Token counts are Claude BPE estimates on the raw text.
|
|
5
5
|
|
|
6
6
|
## 1. System-prompt guidance section
|
|
@@ -271,7 +271,7 @@ First line is the title (under 80 chars), followed by detail. Operations:
|
|
|
271
271
|
}
|
|
272
272
|
```
|
|
273
273
|
|
|
274
|
-
### mmc_memory — description ~279 tokens, params ~
|
|
274
|
+
### mmc_memory — description ~279 tokens, params ~198 tokens (total ~477)
|
|
275
275
|
|
|
276
276
|
**Description:**
|
|
277
277
|
|
|
@@ -305,11 +305,11 @@ Examples: category="CONFIG_VALUES", content="OpenCode source is at ~/Work/OSS/op
|
|
|
305
305
|
]
|
|
306
306
|
},
|
|
307
307
|
"content": {
|
|
308
|
-
"description": "The memory text — one standalone fact (write, update, merge).",
|
|
308
|
+
"description": "The memory text — one standalone fact (write, update, merge). Archive and get take an empty string.",
|
|
309
309
|
"type": "string"
|
|
310
310
|
},
|
|
311
311
|
"category": {
|
|
312
|
-
"description": "Kind of fact
|
|
312
|
+
"description": "Kind of fact: the new fact's kind for write; on update/merge, the memory's current category to keep it. Archive and get ignore it.",
|
|
313
313
|
"type": "string",
|
|
314
314
|
"enum": [
|
|
315
315
|
"PROJECT_RULES",
|
|
@@ -320,7 +320,7 @@ Examples: category="CONFIG_VALUES", content="OpenCode source is at ~/Work/OSS/op
|
|
|
320
320
|
]
|
|
321
321
|
},
|
|
322
322
|
"ids": {
|
|
323
|
-
"description": "Memory ids from <project-memory>: one for update, one or more for archive, two or more for merge, 1–20 for get.",
|
|
323
|
+
"description": "Memory ids from <project-memory>: one for update, one or more for archive, two or more for merge, 1–20 for get. Write takes an empty list.",
|
|
324
324
|
"type": "array",
|
|
325
325
|
"items": {
|
|
326
326
|
"type": "number"
|
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
import { expect, test } from "bun:test";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
cleanSearchText,
|
|
4
|
+
hintKeywordRelevance,
|
|
5
|
+
keywordRelevance,
|
|
6
|
+
matchedSearchSnippet,
|
|
7
|
+
} from "./search-text";
|
|
8
|
+
|
|
9
|
+
test("hint scoring preserves exact English and other space-separated keyword scores", () => {
|
|
10
|
+
const cases: Array<[string, string, number]> = [
|
|
11
|
+
["explain historian cache wiring", "cache icons", 0.2],
|
|
12
|
+
["historian cache wiring", "historian cache wiring details", 0.8000000000000002],
|
|
13
|
+
["please explain cache wiring to me", "cache wiring", 0.5333333333333333],
|
|
14
|
+
["CACHE cache cache_timeout", "cache_timeout", 0.4],
|
|
15
|
+
["how are you", "how are you", 0],
|
|
16
|
+
["historian cache", "<task>historian cache</task>", 0],
|
|
17
|
+
["résumé über prüfen", "über prüfen", 0.5333333333333333],
|
|
18
|
+
["память кеш", "кеш", 0.4],
|
|
19
|
+
["ذاكرة تخزين", "تخزين", 0.4],
|
|
20
|
+
];
|
|
21
|
+
for (const [query, content, expected] of cases) {
|
|
22
|
+
expect(keywordRelevance(query, content)).toBe(expected);
|
|
23
|
+
expect(hintKeywordRelevance(query, content)).toBe(expected);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test("only hint scoring splits unspaced CJK runs into overlapping character bigrams", () => {
|
|
28
|
+
expect(keywordRelevance("MC_Maze 残差怎样汇总?", "MC_Maze 残差按种子汇总。")).toBe(0.4);
|
|
29
|
+
expect(hintKeywordRelevance("残差", "残留")).toBe(0);
|
|
30
|
+
expect(hintKeywordRelevance("差", "残差")).toBe(0.8);
|
|
31
|
+
expect(hintKeywordRelevance("𠮷野家", "𠮷野川")).toBe(0.8);
|
|
32
|
+
expect(hintKeywordRelevance("かながき", "かながきです")).toBe(0.8);
|
|
33
|
+
expect(hintKeywordRelevance("カタカナ", "カタカナです")).toBe(0.8);
|
|
34
|
+
expect(hintKeywordRelevance("프로젝트캐시", "프로젝트의캐시")).toBe(0.8);
|
|
35
|
+
expect(hintKeywordRelevance("cache残差", "cache残差按种子汇总")).toBe(0.8);
|
|
36
|
+
expect(hintKeywordRelevance("差", "<task>残差</task> unrelated")).toBe(0);
|
|
37
|
+
});
|
|
3
38
|
|
|
4
39
|
test("notification trees never contribute relevance or display text", () => {
|
|
5
40
|
expect(
|
|
@@ -35,6 +35,54 @@ export function keywordRelevance(query: string, content: string): number {
|
|
|
35
35
|
return (0.8 * needles.filter((term) => words.has(term)).length) / needles.length;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
const CJK_RUN = /^[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]+$/u;
|
|
39
|
+
const CJK_RUN_SPLIT = /([\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]+)/u;
|
|
40
|
+
|
|
41
|
+
function hintTerms(text: string): string[] {
|
|
42
|
+
return [
|
|
43
|
+
...new Set(
|
|
44
|
+
terms(text)
|
|
45
|
+
.flatMap((term) => term.split(CJK_RUN_SPLIT))
|
|
46
|
+
.filter((term) => term.length > 0 && !QUERY_STOP_WORDS.has(term)),
|
|
47
|
+
),
|
|
48
|
+
];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function characterBigrams(run: string): string[] {
|
|
52
|
+
const characters = [...run];
|
|
53
|
+
return characters.length === 1
|
|
54
|
+
? characters
|
|
55
|
+
: characters.slice(1).map((character, index) => characters[index] + character);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Match unspaced clauses for hints without changing retrieval or snippet scoring. */
|
|
59
|
+
export function hintKeywordRelevance(query: string, content: string): number {
|
|
60
|
+
const needles = hintTerms(query);
|
|
61
|
+
if (needles.length === 0) return 0;
|
|
62
|
+
const words = new Set(hintTerms(cleanSearchText(content)));
|
|
63
|
+
const runs = [...words].filter((word) => CJK_RUN.test(word));
|
|
64
|
+
const bigrams = new Set(runs.flatMap(characterBigrams));
|
|
65
|
+
let matched = 0;
|
|
66
|
+
for (const needle of needles) {
|
|
67
|
+
if (!CJK_RUN.test(needle)) {
|
|
68
|
+
matched += Number(words.has(needle));
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
const grams = characterBigrams(needle);
|
|
72
|
+
if ([...needle].length === 1) {
|
|
73
|
+
matched += Number(runs.some((run) => run.includes(needle)));
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
// Count each clause as one term so filler bigrams across word boundaries
|
|
77
|
+
// do not dilute it; require half coverage so shared function words alone do not pass.
|
|
78
|
+
matched += Math.min(
|
|
79
|
+
1,
|
|
80
|
+
grams.filter((gram) => bigrams.has(gram)).length / Math.ceil(grams.length / 2),
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
return (0.8 * matched) / needles.length;
|
|
84
|
+
}
|
|
85
|
+
|
|
38
86
|
/** Pick the densest matching passage before compression discards matched words. */
|
|
39
87
|
export function matchedSearchSnippet(content: string, query: string, cap = 220): string {
|
|
40
88
|
const text = cleanSearchText(content);
|
package/tui.js
ADDED