@selesai/code 0.14.0 → 0.14.3
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/config.d.ts +10 -1
- package/dist/config.js +39 -1
- package/dist/core/resource-loader.js +2 -0
- package/dist/extensions/codemode/execute.js +18 -6
- package/dist/extensions/jev/classifier.test.ts +85 -20
- package/dist/extensions/jev/classifier.ts +147 -61
- package/dist/extensions/jev/decisions.test.ts +21 -0
- package/dist/extensions/jev/decisions.ts +36 -5
- package/dist/extensions/jev-ask-tool.ts +1 -1
- package/dist/extensions/jev-tool-ranker.test.ts +185 -0
- package/dist/extensions/jev-tool-ranker.ts +169 -0
- package/dist/extensions/package.json +1 -0
- package/dist/extensions/pi-graft/index.ts +4 -19
- package/dist/extensions/pi-graft/lifecycle.test.ts +32 -25
- package/dist/extensions/pi-graft/tools.ts +2 -2
- package/dist/extensions/pi-hermes-memory/src/tools/skill-tool.ts +1 -1
- package/dist/extensions/question/index.ts +1 -1
- package/dist/extensions/tokenin-onboarding.ts +3 -3
- package/dist/extensions/tool-search/tool.d.ts +23 -4
- package/dist/extensions/tool-search/tool.js +35 -9
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/docs/codemode.md +1 -1
- package/package.json +3 -3
|
@@ -85,17 +85,17 @@ afterEach(() => {
|
|
|
85
85
|
});
|
|
86
86
|
|
|
87
87
|
describe("session start", () => {
|
|
88
|
-
it("resolves the Git working tree, probes the executable, and
|
|
88
|
+
it("resolves the Git working tree, probes the executable, and writes no status line", async () => {
|
|
89
89
|
const session = await bootSession();
|
|
90
90
|
expect(session.commandsRun()).toEqual(["git rev-parse --show-toplevel", "graft --version"]);
|
|
91
|
-
expect(session.ctx.
|
|
91
|
+
expect(session.ctx.ui.setStatus).not.toHaveBeenCalled();
|
|
92
92
|
await session.reset();
|
|
93
93
|
});
|
|
94
94
|
|
|
95
95
|
it("does nothing at all when the extension is disabled by settings", async () => {
|
|
96
96
|
const session = await bootSession({ settings: { enabled: false } });
|
|
97
97
|
expect(session.exec).not.toHaveBeenCalled();
|
|
98
|
-
expect(session.ctx.
|
|
98
|
+
expect(session.ctx.ui.setStatus).not.toHaveBeenCalled();
|
|
99
99
|
await session.reset();
|
|
100
100
|
});
|
|
101
101
|
|
|
@@ -133,7 +133,9 @@ describe("session start", () => {
|
|
|
133
133
|
const session = await bootSession({
|
|
134
134
|
branch: [{ type: "custom", customType: MODE_ENTRY_TYPE, data: { mode: "hybrid" } }],
|
|
135
135
|
});
|
|
136
|
-
|
|
136
|
+
const status = session.commands.get("graft")!.handler as (args: string, ctx: unknown) => Promise<void>;
|
|
137
|
+
await status("status", session.ctx);
|
|
138
|
+
expect(notified(session.ctx)).toContain("hybrid —");
|
|
137
139
|
await session.reset();
|
|
138
140
|
});
|
|
139
141
|
|
|
@@ -171,8 +173,8 @@ describe("session start", () => {
|
|
|
171
173
|
const ctx = makeCtx({ cwd: repo });
|
|
172
174
|
const start = handlerFor(harness, "session_start") as (e: unknown, c: unknown) => Promise<void>;
|
|
173
175
|
await start({ type: "session_start", reason: "startup" }, ctx);
|
|
174
|
-
await vi.waitFor(() => expect(
|
|
175
|
-
expect(harness.commandsRun()
|
|
176
|
+
await vi.waitFor(() => expect(harness.commandsRun()).toContain("npm install -g @nanonets/graft@^0.21"));
|
|
177
|
+
await vi.waitFor(() => expect(harness.commandsRun().filter((c) => c.includes("--version"))).toHaveLength(2));
|
|
176
178
|
|
|
177
179
|
await start({ type: "session_start", reason: "reload" }, ctx);
|
|
178
180
|
expect(harness.commandsRun().filter((command) => command.startsWith("npm install"))).toHaveLength(1);
|
|
@@ -194,7 +196,7 @@ describe("session start", () => {
|
|
|
194
196
|
ctx,
|
|
195
197
|
);
|
|
196
198
|
await vi.waitFor(() => expect(notified(ctx)).toContain("npm access denied"));
|
|
197
|
-
expect(ctx.
|
|
199
|
+
expect(ctx.ui.setStatus).not.toHaveBeenCalled();
|
|
198
200
|
});
|
|
199
201
|
|
|
200
202
|
it("reports that Graft needs a Git working tree without probing anything else", async () => {
|
|
@@ -210,7 +212,7 @@ describe("session start", () => {
|
|
|
210
212
|
{ type: "session_start", reason: "startup" },
|
|
211
213
|
ctx,
|
|
212
214
|
);
|
|
213
|
-
expect(ctx.
|
|
215
|
+
expect(ctx.ui.setStatus).not.toHaveBeenCalled();
|
|
214
216
|
expect(ctx.ui.notify).not.toHaveBeenCalled();
|
|
215
217
|
});
|
|
216
218
|
});
|
|
@@ -224,6 +226,12 @@ describe("mutation awareness", () => {
|
|
|
224
226
|
content: [],
|
|
225
227
|
isError,
|
|
226
228
|
});
|
|
229
|
+
/** Whether the graph counts as changed shows up as a rebuild when the turn ends. */
|
|
230
|
+
const expectRefreshOnAgentEnd = async (session: Booted, expected: boolean) => {
|
|
231
|
+
await (handlerFor(session, "agent_end") as (e: unknown, c: unknown) => Promise<void>)({}, session.ctx);
|
|
232
|
+
if (expected) await vi.waitFor(() => expect(session.commandsRun()).toContain("graft build"));
|
|
233
|
+
else expect(session.commandsRun()).not.toContain("graft build");
|
|
234
|
+
};
|
|
227
235
|
const onToolResult = (session: Booted, toolName: string, input: Record<string, unknown>, isError = false) =>
|
|
228
236
|
(handlerFor(session, "tool_result") as (e: unknown, c: unknown) => Promise<void>)(
|
|
229
237
|
toolResultEvent(toolName, input, isError),
|
|
@@ -233,14 +241,14 @@ describe("mutation awareness", () => {
|
|
|
233
241
|
it("marks the graph changed after a successful edit", async () => {
|
|
234
242
|
const session = await bootSession();
|
|
235
243
|
await onToolResult(session, "edit", { path: "src/a.ts" });
|
|
236
|
-
|
|
244
|
+
await expectRefreshOnAgentEnd(session, true);
|
|
237
245
|
await session.reset();
|
|
238
246
|
});
|
|
239
247
|
|
|
240
248
|
it("marks the graph changed after a clearly mutating bash command", async () => {
|
|
241
249
|
const session = await bootSession();
|
|
242
250
|
await onToolResult(session, "bash", { command: "rm -rf dist" });
|
|
243
|
-
|
|
251
|
+
await expectRefreshOnAgentEnd(session, true);
|
|
244
252
|
await session.reset();
|
|
245
253
|
});
|
|
246
254
|
|
|
@@ -249,7 +257,7 @@ describe("mutation awareness", () => {
|
|
|
249
257
|
await onToolResult(session, "read", { path: "src/a.ts" });
|
|
250
258
|
await onToolResult(session, "bash", { command: "git status" });
|
|
251
259
|
await onToolResult(session, "edit", { path: "src/a.ts" }, true);
|
|
252
|
-
|
|
260
|
+
await expectRefreshOnAgentEnd(session, false);
|
|
253
261
|
await session.reset();
|
|
254
262
|
});
|
|
255
263
|
});
|
|
@@ -283,8 +291,7 @@ describe("proactive refresh", () => {
|
|
|
283
291
|
{ type: "session_start", reason: "startup" },
|
|
284
292
|
ctx,
|
|
285
293
|
);
|
|
286
|
-
await vi.waitFor(() => expect(
|
|
287
|
-
expect(harness.commandsRun()).toContain("graft build");
|
|
294
|
+
await vi.waitFor(() => expect(harness.commandsRun()).toContain("graft build"));
|
|
288
295
|
});
|
|
289
296
|
|
|
290
297
|
it("uses the active TokenIn model for the default deep build", async () => {
|
|
@@ -314,7 +321,7 @@ describe("proactive refresh", () => {
|
|
|
314
321
|
{ type: "session_start", reason: "startup" },
|
|
315
322
|
ctx,
|
|
316
323
|
);
|
|
317
|
-
await vi.waitFor(() => expect(
|
|
324
|
+
await vi.waitFor(() => expect(harness.commandsRun().some((c) => c.startsWith("graft build"))).toBe(true));
|
|
318
325
|
const build = harness.exec.mock.calls.find((call) => (call[1] as string[]).includes("build"))!;
|
|
319
326
|
expect(build[1]).toEqual(["build", "--deep"]);
|
|
320
327
|
expect(build[2]).toMatchObject({
|
|
@@ -359,7 +366,8 @@ describe("proactive refresh", () => {
|
|
|
359
366
|
{ type: "session_start", reason: "startup" },
|
|
360
367
|
ctx,
|
|
361
368
|
);
|
|
362
|
-
await vi.waitFor(() => expect(ctx
|
|
369
|
+
await vi.waitFor(() => expect(notified(ctx)).toContain("retrying the deep pass"));
|
|
370
|
+
await vi.waitFor(() => expect(models).toEqual(["deepseek-v4.1-flash", "glm-5.3-flash"]));
|
|
363
371
|
expect(models).toEqual(["deepseek-v4.1-flash", "glm-5.3-flash"]);
|
|
364
372
|
expect(notified(ctx)).toContain("retrying the deep pass");
|
|
365
373
|
});
|
|
@@ -388,12 +396,12 @@ describe("proactive refresh", () => {
|
|
|
388
396
|
{ type: "session_start", reason: "startup" },
|
|
389
397
|
ctx,
|
|
390
398
|
);
|
|
391
|
-
await vi.waitFor(() => expect(
|
|
399
|
+
await vi.waitFor(() => expect(harness.commandsRun().some((c) => c.startsWith("graft build"))).toBe(true));
|
|
392
400
|
const build = harness.exec.mock.calls.find((call) => (call[1] as string[]).includes("build"))!;
|
|
393
401
|
expect(build[1]).toEqual(["build"]);
|
|
394
402
|
});
|
|
395
403
|
|
|
396
|
-
it("re-indexes after edits
|
|
404
|
+
it("re-indexes after edits without touching the status line", async () => {
|
|
397
405
|
const session = await bootSession({ settings: { refreshDebounceSeconds: 0 } });
|
|
398
406
|
await (handlerFor(session, "tool_result") as (e: unknown, c: unknown) => Promise<void>)(
|
|
399
407
|
{ type: "tool_result", toolName: "read", toolCallId: "c", input: {}, content: [], isError: false },
|
|
@@ -403,12 +411,10 @@ describe("proactive refresh", () => {
|
|
|
403
411
|
{ type: "tool_result", toolName: "write", toolCallId: "c1", input: {}, content: [], isError: false },
|
|
404
412
|
session.ctx,
|
|
405
413
|
);
|
|
406
|
-
expect(session.ctx.statuses.get("graft")).toBe("graft: ◐ changed v0.21.1");
|
|
407
414
|
|
|
408
415
|
await (handlerFor(session, "agent_end") as (e: unknown, c: unknown) => Promise<void>)({}, session.ctx);
|
|
409
|
-
expect(session.
|
|
410
|
-
|
|
411
|
-
expect(session.commandsRun()).toContain("graft build");
|
|
416
|
+
await vi.waitFor(() => expect(session.commandsRun()).toContain("graft build"));
|
|
417
|
+
expect(session.ctx.ui.setStatus).not.toHaveBeenCalled();
|
|
412
418
|
await session.reset();
|
|
413
419
|
});
|
|
414
420
|
|
|
@@ -449,7 +455,8 @@ describe("proactive refresh", () => {
|
|
|
449
455
|
ctx,
|
|
450
456
|
);
|
|
451
457
|
await (handlerFor(harness, "agent_end") as (e: unknown, c: unknown) => Promise<void>)({}, ctx);
|
|
452
|
-
await vi.waitFor(() => expect(
|
|
458
|
+
await vi.waitFor(() => expect(harness.commandsRun()).toContain("graft build"));
|
|
459
|
+
expect(ctx.ui.setStatus).not.toHaveBeenCalled();
|
|
453
460
|
});
|
|
454
461
|
});
|
|
455
462
|
|
|
@@ -592,8 +599,7 @@ describe("session shutdown", () => {
|
|
|
592
599
|
const session = await bootSession({ settings: { mode: "push" } });
|
|
593
600
|
await session.reset();
|
|
594
601
|
|
|
595
|
-
expect(session.ctx.
|
|
596
|
-
expect(session.ctx.statuses.get("graft-mode")).toBeUndefined();
|
|
602
|
+
expect(session.ctx.ui.setStatus).not.toHaveBeenCalled();
|
|
597
603
|
expect(process.env[TELEMETRY_ENV]).toBeUndefined();
|
|
598
604
|
|
|
599
605
|
const before = session.exec.mock.calls.length;
|
|
@@ -714,7 +720,8 @@ describe("mode selection through commands", () => {
|
|
|
714
720
|
const handler = session.commands.get("graft")!.handler as (args: string, ctx: unknown) => Promise<void>;
|
|
715
721
|
await handler("mode hybrid", session.ctx);
|
|
716
722
|
expect(session.entries).toContainEqual({ customType: MODE_ENTRY_TYPE, data: { mode: "hybrid" as RetrievalMode } });
|
|
717
|
-
|
|
723
|
+
await handler("status", session.ctx);
|
|
724
|
+
expect(notified(session.ctx)).toContain("hybrid —");
|
|
718
725
|
|
|
719
726
|
const result = await (handlerFor(session, "before_agent_start") as (e: unknown, c: unknown) => Promise<unknown>)(
|
|
720
727
|
{ type: "before_agent_start", prompt: "Refactor src/auth.ts" },
|
|
@@ -282,7 +282,7 @@ export function registerGraftTools(pi: ExtensionAPI, runtime: GraftToolRuntime):
|
|
|
282
282
|
});
|
|
283
283
|
|
|
284
284
|
pi.registerTool({
|
|
285
|
-
exposure: "
|
|
285
|
+
exposure: "deferred",
|
|
286
286
|
name: "graft_repo_map",
|
|
287
287
|
label: "Graft: repo map",
|
|
288
288
|
description:
|
|
@@ -308,7 +308,7 @@ export function registerGraftTools(pi: ExtensionAPI, runtime: GraftToolRuntime):
|
|
|
308
308
|
});
|
|
309
309
|
|
|
310
310
|
pi.registerTool({
|
|
311
|
-
exposure: "
|
|
311
|
+
exposure: "deferred",
|
|
312
312
|
name: "graft_check_freshness",
|
|
313
313
|
label: "Graft: check freshness",
|
|
314
314
|
description:
|
|
@@ -95,7 +95,7 @@ export function registerSkillTool(pi: ExtensionAPI, store: SkillStore): void {
|
|
|
95
95
|
label: "Skill Manager",
|
|
96
96
|
description: SKILL_TOOL_DESCRIPTION,
|
|
97
97
|
promptSnippet: "Create, inspect, and update reusable procedures and patterns",
|
|
98
|
-
exposure: "
|
|
98
|
+
exposure: "deferred",
|
|
99
99
|
promptGuidelines: [
|
|
100
100
|
"Use the skill_manage tool after completing complex tasks that required trial and error or multiple tool calls.",
|
|
101
101
|
"Use 'create' to save a new reusable procedure, 'patch' to update a section of an existing skill by skill_id, and 'update' for a full rewrite.",
|
|
@@ -616,7 +616,7 @@ export default function questionExtension(pi: ExtensionAPI) {
|
|
|
616
616
|
description:
|
|
617
617
|
"Ask one or more typed questions in a terminal wizard. Supports select, multiselect, text, stable option values, Other answers, and partial atomic submission.",
|
|
618
618
|
promptSnippet: "Ask the user one or more typed questions when a decision is required.",
|
|
619
|
-
exposure: "
|
|
619
|
+
exposure: "model-only",
|
|
620
620
|
promptGuidelines: [
|
|
621
621
|
"Use question only for decisions the user must make; inspect facts yourself.",
|
|
622
622
|
"Send one questions array containing independent decisions that can be answered together.",
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
} from "@earendil-works/pi-ai";
|
|
25
25
|
import { getApiProvider } from "@earendil-works/pi-ai/compat";
|
|
26
26
|
import { normalizeContext } from "@earendil-works/pi-ai/utils/transcript";
|
|
27
|
-
import { classifyTokenIn,
|
|
27
|
+
import { classifyTokenIn, TOKENIN_CLASSIFIERS } from "./jev/classifier.ts";
|
|
28
28
|
|
|
29
29
|
type TokenInCredentialStore = ExtensionContext["modelRegistry"]["authStorage"];
|
|
30
30
|
|
|
@@ -1000,8 +1000,8 @@ export default function tokenInOnboardingExtension(pi: ExtensionAPI): void {
|
|
|
1000
1000
|
...ctx.modelRegistry.getModelsOfType("image", "tokenin"),
|
|
1001
1001
|
...ctx.modelRegistry.getModelsOfType("classifier", "tokenin"),
|
|
1002
1002
|
];
|
|
1003
|
-
|
|
1004
|
-
models.push(
|
|
1003
|
+
for (const classifier of TOKENIN_CLASSIFIERS) {
|
|
1004
|
+
if (!models.some((model) => model.type === "classifier" && model.id === classifier.id)) models.push(classifier);
|
|
1005
1005
|
}
|
|
1006
1006
|
pi.registerProvider("tokenin", { ...provider, models });
|
|
1007
1007
|
if (event.reason !== "startup") return;
|
|
@@ -8,21 +8,33 @@
|
|
|
8
8
|
* like any other tool change and survives `/tree`, resume, and fork on that branch.
|
|
9
9
|
*/
|
|
10
10
|
import { type Static, Type } from "typebox";
|
|
11
|
-
import type { ExtensionAPI, ToolDefinition, ToolInfo, ToolNamespace } from "../../core/extensions/types.ts";
|
|
11
|
+
import type { ExtensionAPI, ExtensionContext, ToolDefinition, ToolInfo, ToolNamespace } from "../../core/extensions/types.ts";
|
|
12
12
|
export declare const TOOL_SEARCH_TOOL_NAME = "tool_search";
|
|
13
13
|
export declare const DEFAULT_TOOL_SEARCH_LIMIT = 8;
|
|
14
14
|
/** A tool as the ranker sees it: its name and the text built by {@link createToolSearchDocument}. */
|
|
15
15
|
export interface ToolSearchDocument {
|
|
16
16
|
name: string;
|
|
17
17
|
text: string;
|
|
18
|
+
/** Short human-readable form for rankers that read tools as text (name, first paragraph of the description). */
|
|
19
|
+
summary?: string;
|
|
18
20
|
}
|
|
19
21
|
export interface ToolSearchMatch {
|
|
20
22
|
name: string;
|
|
21
23
|
score: number;
|
|
22
24
|
}
|
|
23
|
-
/**
|
|
25
|
+
/** What a ranker may use besides the query: the caller's cancellation and session (model access). */
|
|
26
|
+
export interface ToolRankOptions {
|
|
27
|
+
signal?: AbortSignal;
|
|
28
|
+
/** Absent when the caller has no session. A ranker that needs one falls back to its own default. */
|
|
29
|
+
ctx?: ExtensionContext;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Ranks tools for a query. BM25 is the built-in; an extension can replace it with
|
|
33
|
+
* {@link registerToolRanker}, for example a model-backed ranker. Rankers may be asynchronous and
|
|
34
|
+
* should degrade to a local ranking rather than throw.
|
|
35
|
+
*/
|
|
24
36
|
export interface ToolRanker {
|
|
25
|
-
rank(query: string, documents: readonly ToolSearchDocument[], limit: number): ToolSearchMatch[]
|
|
37
|
+
rank(query: string, documents: readonly ToolSearchDocument[], limit: number, options?: ToolRankOptions): ToolSearchMatch[] | Promise<ToolSearchMatch[]>;
|
|
26
38
|
}
|
|
27
39
|
/** Lowercase terms, split at camelCase boundaries and non-alphanumerics, without stop words. */
|
|
28
40
|
export declare function tokenize(text: string): string[];
|
|
@@ -42,6 +54,13 @@ export declare class Bm25Ranker implements ToolRanker {
|
|
|
42
54
|
});
|
|
43
55
|
rank(query: string, documents: readonly ToolSearchDocument[], limit: number): ToolSearchMatch[];
|
|
44
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Make `ranker` the one `tool_search` and codemode's `searchTools()` use, until the returned function
|
|
59
|
+
* is called. Kept on `globalThis` so every copy of this module sees the same ranker.
|
|
60
|
+
*/
|
|
61
|
+
export declare function registerToolRanker(ranker: ToolRanker): () => void;
|
|
62
|
+
/** The registered ranker, or BM25. */
|
|
63
|
+
export declare function getToolRanker(): ToolRanker;
|
|
45
64
|
export declare const toolSearchSchema: Type.TObject<{
|
|
46
65
|
query: Type.TString;
|
|
47
66
|
limit: Type.TOptional<Type.TNumber>;
|
|
@@ -68,5 +87,5 @@ export interface ToolSearchToolOptions {
|
|
|
68
87
|
* The `tool_search` description. It does not list the searchable tools or their namespaces, so it
|
|
69
88
|
* stays the same while tools are registered, for example when MCP servers connect.
|
|
70
89
|
*/
|
|
71
|
-
export declare const TOOL_SEARCH_DESCRIPTION = "# Tool discovery\n\nSearches over deferred tool metadata
|
|
90
|
+
export declare const TOOL_SEARCH_DESCRIPTION = "# Tool discovery\n\nSearches over deferred tool metadata and exposes matching tools for the next model call.\n\nSome of the tools, such as tools of MCP servers, may not have been provided to you upfront, and you should use this tool (`tool_search`) to search for the required tools. For MCP tool discovery, always use `tool_search`.";
|
|
72
91
|
export declare function createToolSearchToolDefinition(options?: ToolSearchToolOptions): ToolDefinition<typeof toolSearchSchema, ToolSearchToolDetails>;
|
|
@@ -86,7 +86,9 @@ export function createToolSearchDocument(tool, namespace) {
|
|
|
86
86
|
schemaText(tool.parameters, parts);
|
|
87
87
|
if (namespace)
|
|
88
88
|
parts.push(namespace.name, namespace.description ?? "", namespace.instructions ?? "");
|
|
89
|
-
|
|
89
|
+
const lead = tool.description.trim().split(/\n\s*\n/)[0] ?? "";
|
|
90
|
+
const summary = [`${tool.name}: ${lead}`, namespace?.description].filter((part) => part?.trim()).join(" - ");
|
|
91
|
+
return { name: tool.name, text: parts.filter((part) => part.trim()).join(" "), summary };
|
|
90
92
|
}
|
|
91
93
|
/** Okapi BM25 with the usual parameters. Ties keep document order. */
|
|
92
94
|
export class Bm25Ranker {
|
|
@@ -128,6 +130,24 @@ export class Bm25Ranker {
|
|
|
128
130
|
return matches.sort((a, b) => b.score - a.score).slice(0, limit);
|
|
129
131
|
}
|
|
130
132
|
}
|
|
133
|
+
const TOOL_RANKER_SLOT = Symbol.for("selesai.toolRanker");
|
|
134
|
+
const bm25Ranker = new Bm25Ranker();
|
|
135
|
+
/**
|
|
136
|
+
* Make `ranker` the one `tool_search` and codemode's `searchTools()` use, until the returned function
|
|
137
|
+
* is called. Kept on `globalThis` so every copy of this module sees the same ranker.
|
|
138
|
+
*/
|
|
139
|
+
export function registerToolRanker(ranker) {
|
|
140
|
+
globalThis[TOOL_RANKER_SLOT] = ranker;
|
|
141
|
+
return () => {
|
|
142
|
+
if (globalThis[TOOL_RANKER_SLOT] === ranker) {
|
|
143
|
+
delete globalThis[TOOL_RANKER_SLOT];
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
/** The registered ranker, or BM25. */
|
|
148
|
+
export function getToolRanker() {
|
|
149
|
+
return globalThis[TOOL_RANKER_SLOT] ?? bm25Ranker;
|
|
150
|
+
}
|
|
131
151
|
export const toolSearchSchema = Type.Object({
|
|
132
152
|
query: Type.String({ description: "Search query for deferred tools." }),
|
|
133
153
|
limit: Type.Optional(Type.Number({ description: `Maximum number of tools to return. Defaults to ${DEFAULT_TOOL_SEARCH_LIMIT}.` })),
|
|
@@ -144,13 +164,19 @@ function isSearchable(exposure) {
|
|
|
144
164
|
* Rank the searchable tools that are not active yet and activate the matches, so the next model
|
|
145
165
|
* call declares them. Activation is recorded in the transcript like any tool change.
|
|
146
166
|
*/
|
|
147
|
-
function searchAndLoad(tools, query, limit) {
|
|
148
|
-
const
|
|
149
|
-
|
|
167
|
+
async function searchAndLoad(tools, query, limit, rankOptions) {
|
|
168
|
+
const candidates = tools
|
|
169
|
+
.getAllTools()
|
|
170
|
+
.filter((tool) => isSearchable(tool.exposure) && !tools.getActiveTools().includes(tool.name));
|
|
150
171
|
const documents = candidates.map((tool) => createToolSearchDocument(tool, tool.namespace));
|
|
151
|
-
const
|
|
172
|
+
const ranked = await getToolRanker().rank(query, documents, limit, rankOptions);
|
|
173
|
+
// A registered ranker is third-party code: keep only known, distinct candidates, within the limit.
|
|
174
|
+
const known = new Set(candidates.map((tool) => tool.name));
|
|
175
|
+
const matches = [...new Map(ranked.filter((match) => known.has(match.name)).map((match) => [match.name, match])).values()].slice(0, limit);
|
|
176
|
+
// Read the active set after the await: it may have changed while the ranker ran.
|
|
177
|
+
const active = tools.getActiveTools();
|
|
152
178
|
if (matches.length > 0)
|
|
153
|
-
tools.setActiveTools([...active, ...matches.map((match) => match.name)]);
|
|
179
|
+
tools.setActiveTools([...new Set([...active, ...matches.map((match) => match.name)])]);
|
|
154
180
|
return matches.map((match) => ({
|
|
155
181
|
name: match.name,
|
|
156
182
|
description: candidates.find((tool) => tool.name === match.name)?.description ?? "",
|
|
@@ -160,7 +186,7 @@ function searchAndLoad(tools, query, limit) {
|
|
|
160
186
|
* The `tool_search` description. It does not list the searchable tools or their namespaces, so it
|
|
161
187
|
* stays the same while tools are registered, for example when MCP servers connect.
|
|
162
188
|
*/
|
|
163
|
-
export const TOOL_SEARCH_DESCRIPTION = `# Tool discovery\n\nSearches over deferred tool metadata
|
|
189
|
+
export const TOOL_SEARCH_DESCRIPTION = `# Tool discovery\n\nSearches over deferred tool metadata and exposes matching tools for the next model call.\n\nSome of the tools, such as tools of MCP servers, may not have been provided to you upfront, and you should use this tool (\`${TOOL_SEARCH_TOOL_NAME}\`) to search for the required tools. For MCP tool discovery, always use \`${TOOL_SEARCH_TOOL_NAME}\`.`;
|
|
164
190
|
export function createToolSearchToolDefinition(options = {}) {
|
|
165
191
|
return {
|
|
166
192
|
name: TOOL_SEARCH_TOOL_NAME,
|
|
@@ -170,13 +196,13 @@ export function createToolSearchToolDefinition(options = {}) {
|
|
|
170
196
|
parameters: toolSearchSchema,
|
|
171
197
|
// Searching is not something scripts need; it changes what the model sees.
|
|
172
198
|
exposure: "model-only",
|
|
173
|
-
async execute(_toolCallId, { query, limit }) {
|
|
199
|
+
async execute(_toolCallId, { query, limit }, signal, _onUpdate, ctx) {
|
|
174
200
|
if (query.trim() === "")
|
|
175
201
|
throw new Error("query must not be empty");
|
|
176
202
|
const max = limit ?? DEFAULT_TOOL_SEARCH_LIMIT;
|
|
177
203
|
if (!Number.isInteger(max) || max <= 0)
|
|
178
204
|
throw new Error("limit must be a positive integer");
|
|
179
|
-
const tools = options.tools ? searchAndLoad(options.tools, query, max) : [];
|
|
205
|
+
const tools = options.tools ? await searchAndLoad(options.tools, query, max, { signal, ctx }) : [];
|
|
180
206
|
const text = tools.length === 0
|
|
181
207
|
? "No matching tools found."
|
|
182
208
|
: `Loaded ${tools.length} tool${tools.length === 1 ? "" : "s"}. They are available from your next call:\n${tools
|
package/dist/index.d.ts
CHANGED
|
@@ -32,6 +32,7 @@ export type { CodemodeStoreEntryData, CodemodeToolDetails } from "./extensions/c
|
|
|
32
32
|
export type { LoadedMcpConfig, McpExposure, McpServerConfig, McpServerEntry } from "./extensions/mcp/config.ts";
|
|
33
33
|
export { createMcpExtension, type McpExtensionOptions, type McpTransportFactory } from "./extensions/mcp/index.ts";
|
|
34
34
|
export { createToolSearchExtension } from "./extensions/tool-search/index.ts";
|
|
35
|
+
export { Bm25Ranker, getToolRanker, registerToolRanker, type ToolRankOptions, type ToolRanker, type ToolSearchDocument, type ToolSearchMatch, } from "./extensions/tool-search/tool.ts";
|
|
35
36
|
export { type MainOptions, main } from "./main.ts";
|
|
36
37
|
export { InteractiveMode, type InteractiveModeOptions, type JsonAgentSessionEvent, type ModelInfo, type PrintModeOptions, RpcClient, type RpcClientOptions, type RpcCommand, type RpcEvent, type SubagentRpcCommand, type SubagentRpcEvent, type SubagentRpcResponse, type SubagentRpcSnapshot, type SubagentRpcNode, type SubagentRpcFleet, type SubagentRpcTokens, type SubagentRpcLifecycle, type RpcObservationScope, type ReleaseCommand, type ReleaseResponse, type ReleaseResult, type ReleaseReadinessCommand, type ReleaseReadinessResponse, type ReleaseReadiness, type StopAllBackgroundCommand, type StopAllBackgroundResponse, type StopAllBackgroundResult, type StopAllBackgroundItem, type IntercomRpcCommand, type IntercomRpcResponse, type IntercomRpcEvent, type IntercomRpcStatus, type IntercomRpcDelivery, type IntercomRpcMessageOptions, type IntercomRpcDataMap, type RpcEventListener, type RpcExtensionUIRequest, type RpcExtensionUIResponse, type RpcResponse, type RpcSessionState, runPrintMode, runRpcMode, } from "./modes/index.ts";
|
|
37
38
|
export { ArminComponent, AssistantMessageComponent, BashExecutionComponent, BorderedLoader, BranchSummaryMessageComponent, CompactionSummaryMessageComponent, CustomEditor, type CustomEditorOptions, CustomMessageComponent, DynamicBorder, ExtensionEditorComponent, ExtensionInputComponent, ExtensionSelectorComponent, FooterComponent, keyHint, keyText, LoginDialogComponent, ModelSelectorComponent, OAuthSelectorComponent, type RenderDiffOptions, rawKeyHint, renderDiff, SessionSelectorComponent, type SettingsCallbacks, type SettingsConfig, SettingsSelectorComponent, ShowImagesSelectorComponent, SkillInvocationMessageComponent, ThemeSelectorComponent, ThinkingSelectorComponent, ToolExecutionComponent, type ToolExecutionOptions, TreeSelectorComponent, truncateToVisualLines, UserMessageComponent, UserMessageSelectorComponent, type VisualTruncateResult, } from "./modes/interactive/components/index.ts";
|
package/dist/index.js
CHANGED
|
@@ -35,6 +35,7 @@ export { VIRTUAL_MODEL_STATE_ENTRY, } from "./core/virtual-models.js";
|
|
|
35
35
|
export { createCodemodeExtension } from "./extensions/codemode/index.js";
|
|
36
36
|
export { createMcpExtension } from "./extensions/mcp/index.js";
|
|
37
37
|
export { createToolSearchExtension } from "./extensions/tool-search/index.js";
|
|
38
|
+
export { Bm25Ranker, getToolRanker, registerToolRanker, } from "./extensions/tool-search/tool.js";
|
|
38
39
|
// Main entry point
|
|
39
40
|
export { main } from "./main.js";
|
|
40
41
|
// Run modes for programmatic SDK usage
|
package/docs/codemode.md
CHANGED
|
@@ -29,7 +29,7 @@ The result starts with `Script completed` or `Script failed`, the wall time, and
|
|
|
29
29
|
| `exit()` | End the script successfully. |
|
|
30
30
|
| `store(key, value)` / `load(key)` | Keep small JSON values across `codemode` calls. See [Store values](#store-values). |
|
|
31
31
|
| `ALL_TOOLS` | Every callable tool as `{ name, description }`, including tools the description does not list. |
|
|
32
|
-
| `searchTools(query, { limit?, namespace? })` | Rank callable tools by relevance (
|
|
32
|
+
| `searchTools(query, { limit?, namespace? })` | Rank callable tools by relevance (default limit 8). Asks Jev (`jevAdvisory.routes.toolSearch`) when a Token-In account is available, for the first 8 searches of a script; otherwise BM25. Resolves to `{ name, description }[]`. |
|
|
33
33
|
| `describeTool(name)` | Resolves to a tool's description and TypeScript declaration, or `undefined`. |
|
|
34
34
|
| `describeNamespace(name)` | Resolves to `{ name, description?, instructions?, tools }` for a namespace such as an MCP server, or `undefined`. |
|
|
35
35
|
| `models` | List and run non-LLM models. See [Models](#models). |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@selesai/code",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.3",
|
|
4
4
|
"description": "Maintained, extension-first Pi coding agent with built-in workflows, subagents, web research, questions, skills, and an enhanced terminal UI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
"clean": "shx rm -rf dist",
|
|
56
56
|
"dev": "tsx src/cli.ts",
|
|
57
57
|
"dev:print": "tsx src/cli.ts --print",
|
|
58
|
-
"test": "vitest run src/__tests__/model-registry-completion.test.ts src/extensions/jev/decisions.test.ts test/auto-handoff-retirement.test.ts src/core/remote-catalog-provider.test.ts src/extensions/jev-advisory-memory.test.ts src/extensions/jev-advisory-recommendations.test.ts src/extensions/jev-ask-tool.test.ts src/extensions/jev-advisory-lifecycle.test.ts src/extensions/undo.test.ts src/extensions/tps.test.ts src/extensions/pi-graft src/extensions/agent-browser.test.ts src/extensions/auto-session-name.test.ts src/extensions/context-compaction-reminder.test.ts src/extensions/copy-turn.test.ts src/extensions/grep-app/index.test.ts src/extensions/inline-skills.test.ts src/extensions/rtk.test.ts src/extensions/handoff-new.test.ts src/extensions/question/tests src/extensions/ponytail/test src/__tests__/tokenin-search.test.ts src/__tests__/tokenin-onboarding.test.ts src/__tests__/model-registry-defaults.test.ts src/core/system-prompt.test.ts src/core/session-format.test.ts test/settings-manager-compaction.test.ts test/suite/agent-session-runtime.test.ts test/suite/agent-session-tool-orchestration.test.ts test/suite/agent-session-prompt.test.ts test/suite/agent-session-queue.test.ts test/suite/agent-session-retry-events.test.ts test/suite/agent-session-compaction.test.ts test/suite/agent-session-compaction-model-overrides.test.ts test/suite/agent-session-bash-persistence.test.ts test/suite/agent-session-model-extension.test.ts test/clipboard.test.ts test/clipboard-command.test.ts test/clipboard-image.test.ts test/clipboard-image-bmp-conversion.test.ts test/clipboard-image-native-errors.test.ts src/cli/args.test.ts test/mermaid.test.ts test/settings-manager-mermaid.test.ts test/syntax-highlight.test.ts test/rpc-prompt-response-semantics.test.ts test/rpc-client-clear-queue.test.ts test/rpc-client-process-exit.test.ts test/rpc-client-prompt-disposition.test.ts test/keybindings.test.ts test/user-message.test.ts src/extensions/jev-find-source.test.ts src/extensions/skills-index/index.test.ts test/gateway-retirement.test.ts test/config-selector-builtins.test.ts test/mcp-fork-safety.test.ts test/mcp-cli-real.test.ts test/mcp-prompt-contract.test.ts test/shell-structured-output.test.ts test/rpc-real-bridge.test.ts test/rpc-caption-handoff.test.ts test/native-runtime-packages.test.ts test/rtk-scope-lifecycle.test.ts src/extensions/jev/classifier.test.ts test/tokenin-classifier-registration.test.ts test/program-status-reporter.test.ts test/output-pad.test.ts test/mcp-manager-view.test.ts test/suite/regressions/7187-malformed-package-manifest.test.ts test/suite/regressions/7193-event-bus-lifecycle.test.ts test/suite/regressions/7209-model-selector-filter-resets-selection.test.ts test/suite/regressions/7253-manual-compact-during-response.test.ts test/suite/regressions/7269-cli-end-of-options.test.ts test/suite/regressions/7290-json-stream-linear.test.ts test/suite/regressions/7497-session-discovery-symlink.test.ts test/suite/regressions/7731-tui-method-wrapping.test.ts test/suite/regressions/7829-invalid-settings-warning.test.ts test/suite/regressions/7911-json-stream-usage.test.ts test/suite/regressions/7925-toolcall-start-metadata.test.ts test/suite/regressions/8328-zero-usage-auto-compaction.test.ts test/suite/regressions/8337-utf8-bom-parsing.test.ts test/suite/regressions/8423-extension-factory-failure.test.ts test/suite/regressions/8964-extension-provider-streaming.test.ts test/suite/regressions/8989-fork-compaction-label-boundary.test.ts test/git-update.test.ts test/skills.test.ts test/settings-diagnostics.test.ts test/auth-check.test.ts test/credential-print.test.ts src/core/agent-session-custom-tools.test.ts src/core/agent-session-length-continuation.test.ts src/core/package-manager.test.ts",
|
|
59
|
-
"test:coverage": "vitest run --coverage src/__tests__/model-registry-completion.test.ts src/extensions/jev/decisions.test.ts test/auto-handoff-retirement.test.ts src/core/remote-catalog-provider.test.ts src/extensions/jev-advisory-memory.test.ts src/extensions/jev-advisory-recommendations.test.ts src/extensions/jev-ask-tool.test.ts src/extensions/jev-advisory-lifecycle.test.ts src/extensions/undo.test.ts src/extensions/tps.test.ts src/extensions/pi-graft src/extensions/agent-browser.test.ts src/extensions/auto-session-name.test.ts src/extensions/context-compaction-reminder.test.ts src/extensions/copy-turn.test.ts src/extensions/grep-app/index.test.ts src/extensions/inline-skills.test.ts src/extensions/rtk.test.ts src/extensions/handoff-new.test.ts src/extensions/question/tests src/extensions/ponytail/test src/__tests__/tokenin-search.test.ts src/__tests__/tokenin-onboarding.test.ts src/__tests__/model-registry-defaults.test.ts src/core/system-prompt.test.ts src/core/session-format.test.ts test/settings-manager-compaction.test.ts test/suite/agent-session-runtime.test.ts test/suite/agent-session-tool-orchestration.test.ts test/suite/agent-session-prompt.test.ts test/suite/agent-session-queue.test.ts test/suite/agent-session-retry-events.test.ts test/suite/agent-session-compaction.test.ts test/suite/agent-session-compaction-model-overrides.test.ts test/suite/agent-session-bash-persistence.test.ts test/suite/agent-session-model-extension.test.ts test/clipboard.test.ts test/clipboard-command.test.ts test/clipboard-image.test.ts test/clipboard-image-bmp-conversion.test.ts test/clipboard-image-native-errors.test.ts src/cli/args.test.ts test/mermaid.test.ts test/settings-manager-mermaid.test.ts test/syntax-highlight.test.ts test/rpc-prompt-response-semantics.test.ts test/rpc-client-clear-queue.test.ts test/rpc-client-process-exit.test.ts test/rpc-client-prompt-disposition.test.ts test/keybindings.test.ts test/user-message.test.ts src/extensions/jev-find-source.test.ts src/extensions/skills-index/index.test.ts test/gateway-retirement.test.ts test/config-selector-builtins.test.ts test/mcp-fork-safety.test.ts test/mcp-cli-real.test.ts test/mcp-prompt-contract.test.ts test/shell-structured-output.test.ts test/rpc-real-bridge.test.ts test/rpc-caption-handoff.test.ts test/native-runtime-packages.test.ts test/rtk-scope-lifecycle.test.ts src/extensions/jev/classifier.test.ts test/tokenin-classifier-registration.test.ts test/program-status-reporter.test.ts test/output-pad.test.ts test/mcp-manager-view.test.ts test/suite/regressions/7187-malformed-package-manifest.test.ts test/suite/regressions/7193-event-bus-lifecycle.test.ts test/suite/regressions/7209-model-selector-filter-resets-selection.test.ts test/suite/regressions/7253-manual-compact-during-response.test.ts test/suite/regressions/7269-cli-end-of-options.test.ts test/suite/regressions/7290-json-stream-linear.test.ts test/suite/regressions/7497-session-discovery-symlink.test.ts test/suite/regressions/7731-tui-method-wrapping.test.ts test/suite/regressions/7829-invalid-settings-warning.test.ts test/suite/regressions/7911-json-stream-usage.test.ts test/suite/regressions/7925-toolcall-start-metadata.test.ts test/suite/regressions/8328-zero-usage-auto-compaction.test.ts test/suite/regressions/8337-utf8-bom-parsing.test.ts test/suite/regressions/8423-extension-factory-failure.test.ts test/suite/regressions/8964-extension-provider-streaming.test.ts test/suite/regressions/8989-fork-compaction-label-boundary.test.ts test/git-update.test.ts test/skills.test.ts test/settings-diagnostics.test.ts test/auth-check.test.ts test/credential-print.test.ts src/core/agent-session-custom-tools.test.ts src/core/agent-session-length-continuation.test.ts src/core/package-manager.test.ts",
|
|
58
|
+
"test": "vitest run src/__tests__/model-registry-completion.test.ts src/extensions/jev/decisions.test.ts test/auto-handoff-retirement.test.ts src/core/remote-catalog-provider.test.ts src/extensions/jev-advisory-memory.test.ts src/extensions/jev-advisory-recommendations.test.ts src/extensions/jev-ask-tool.test.ts src/extensions/jev-tool-ranker.test.ts src/extensions/tool-search/tool.test.ts src/extensions/jev-advisory-lifecycle.test.ts src/extensions/undo.test.ts src/extensions/tps.test.ts src/extensions/pi-graft src/extensions/agent-browser.test.ts src/extensions/auto-session-name.test.ts src/extensions/context-compaction-reminder.test.ts src/extensions/copy-turn.test.ts src/extensions/grep-app/index.test.ts src/extensions/inline-skills.test.ts src/extensions/rtk.test.ts src/extensions/handoff-new.test.ts src/extensions/question/tests src/extensions/ponytail/test src/__tests__/tokenin-search.test.ts src/__tests__/tokenin-onboarding.test.ts src/__tests__/model-registry-defaults.test.ts src/core/system-prompt.test.ts src/core/session-format.test.ts test/settings-manager-compaction.test.ts test/suite/agent-session-runtime.test.ts test/suite/agent-session-tool-orchestration.test.ts test/suite/agent-session-prompt.test.ts test/suite/agent-session-queue.test.ts test/suite/agent-session-retry-events.test.ts test/suite/agent-session-compaction.test.ts test/suite/agent-session-compaction-model-overrides.test.ts test/suite/agent-session-bash-persistence.test.ts test/suite/agent-session-model-extension.test.ts test/clipboard.test.ts test/clipboard-command.test.ts test/clipboard-image.test.ts test/clipboard-image-bmp-conversion.test.ts test/clipboard-image-native-errors.test.ts src/cli/args.test.ts test/mermaid.test.ts test/settings-manager-mermaid.test.ts test/syntax-highlight.test.ts test/rpc-prompt-response-semantics.test.ts test/rpc-client-clear-queue.test.ts test/rpc-client-process-exit.test.ts test/rpc-client-prompt-disposition.test.ts test/keybindings.test.ts test/user-message.test.ts src/extensions/jev-find-source.test.ts src/extensions/skills-index/index.test.ts test/gateway-retirement.test.ts test/config-selector-builtins.test.ts test/mcp-fork-safety.test.ts test/mcp-cli-real.test.ts test/mcp-prompt-contract.test.ts test/shell-structured-output.test.ts test/rpc-real-bridge.test.ts test/rpc-caption-handoff.test.ts test/native-runtime-packages.test.ts test/rtk-scope-lifecycle.test.ts src/extensions/jev/classifier.test.ts test/tokenin-classifier-registration.test.ts test/program-status-reporter.test.ts test/output-pad.test.ts test/mcp-manager-view.test.ts test/suite/regressions/7187-malformed-package-manifest.test.ts test/suite/regressions/7193-event-bus-lifecycle.test.ts test/suite/regressions/7209-model-selector-filter-resets-selection.test.ts test/suite/regressions/7253-manual-compact-during-response.test.ts test/suite/regressions/7269-cli-end-of-options.test.ts test/suite/regressions/7290-json-stream-linear.test.ts test/suite/regressions/7497-session-discovery-symlink.test.ts test/suite/regressions/7731-tui-method-wrapping.test.ts test/suite/regressions/7829-invalid-settings-warning.test.ts test/suite/regressions/7911-json-stream-usage.test.ts test/suite/regressions/7925-toolcall-start-metadata.test.ts test/suite/regressions/8328-zero-usage-auto-compaction.test.ts test/suite/regressions/8337-utf8-bom-parsing.test.ts test/suite/regressions/8423-extension-factory-failure.test.ts test/suite/regressions/8964-extension-provider-streaming.test.ts test/suite/regressions/8989-fork-compaction-label-boundary.test.ts test/git-update.test.ts test/skills.test.ts test/settings-diagnostics.test.ts test/auth-check.test.ts test/credential-print.test.ts src/core/agent-session-custom-tools.test.ts src/core/agent-session-length-continuation.test.ts src/core/package-manager.test.ts",
|
|
59
|
+
"test:coverage": "vitest run --coverage src/__tests__/model-registry-completion.test.ts src/extensions/jev/decisions.test.ts test/auto-handoff-retirement.test.ts src/core/remote-catalog-provider.test.ts src/extensions/jev-advisory-memory.test.ts src/extensions/jev-advisory-recommendations.test.ts src/extensions/jev-ask-tool.test.ts src/extensions/jev-tool-ranker.test.ts src/extensions/tool-search/tool.test.ts src/extensions/jev-advisory-lifecycle.test.ts src/extensions/undo.test.ts src/extensions/tps.test.ts src/extensions/pi-graft src/extensions/agent-browser.test.ts src/extensions/auto-session-name.test.ts src/extensions/context-compaction-reminder.test.ts src/extensions/copy-turn.test.ts src/extensions/grep-app/index.test.ts src/extensions/inline-skills.test.ts src/extensions/rtk.test.ts src/extensions/handoff-new.test.ts src/extensions/question/tests src/extensions/ponytail/test src/__tests__/tokenin-search.test.ts src/__tests__/tokenin-onboarding.test.ts src/__tests__/model-registry-defaults.test.ts src/core/system-prompt.test.ts src/core/session-format.test.ts test/settings-manager-compaction.test.ts test/suite/agent-session-runtime.test.ts test/suite/agent-session-tool-orchestration.test.ts test/suite/agent-session-prompt.test.ts test/suite/agent-session-queue.test.ts test/suite/agent-session-retry-events.test.ts test/suite/agent-session-compaction.test.ts test/suite/agent-session-compaction-model-overrides.test.ts test/suite/agent-session-bash-persistence.test.ts test/suite/agent-session-model-extension.test.ts test/clipboard.test.ts test/clipboard-command.test.ts test/clipboard-image.test.ts test/clipboard-image-bmp-conversion.test.ts test/clipboard-image-native-errors.test.ts src/cli/args.test.ts test/mermaid.test.ts test/settings-manager-mermaid.test.ts test/syntax-highlight.test.ts test/rpc-prompt-response-semantics.test.ts test/rpc-client-clear-queue.test.ts test/rpc-client-process-exit.test.ts test/rpc-client-prompt-disposition.test.ts test/keybindings.test.ts test/user-message.test.ts src/extensions/jev-find-source.test.ts src/extensions/skills-index/index.test.ts test/gateway-retirement.test.ts test/config-selector-builtins.test.ts test/mcp-fork-safety.test.ts test/mcp-cli-real.test.ts test/mcp-prompt-contract.test.ts test/shell-structured-output.test.ts test/rpc-real-bridge.test.ts test/rpc-caption-handoff.test.ts test/native-runtime-packages.test.ts test/rtk-scope-lifecycle.test.ts src/extensions/jev/classifier.test.ts test/tokenin-classifier-registration.test.ts test/program-status-reporter.test.ts test/output-pad.test.ts test/mcp-manager-view.test.ts test/suite/regressions/7187-malformed-package-manifest.test.ts test/suite/regressions/7193-event-bus-lifecycle.test.ts test/suite/regressions/7209-model-selector-filter-resets-selection.test.ts test/suite/regressions/7253-manual-compact-during-response.test.ts test/suite/regressions/7269-cli-end-of-options.test.ts test/suite/regressions/7290-json-stream-linear.test.ts test/suite/regressions/7497-session-discovery-symlink.test.ts test/suite/regressions/7731-tui-method-wrapping.test.ts test/suite/regressions/7829-invalid-settings-warning.test.ts test/suite/regressions/7911-json-stream-usage.test.ts test/suite/regressions/7925-toolcall-start-metadata.test.ts test/suite/regressions/8328-zero-usage-auto-compaction.test.ts test/suite/regressions/8337-utf8-bom-parsing.test.ts test/suite/regressions/8423-extension-factory-failure.test.ts test/suite/regressions/8964-extension-provider-streaming.test.ts test/suite/regressions/8989-fork-compaction-label-boundary.test.ts test/git-update.test.ts test/skills.test.ts test/settings-diagnostics.test.ts test/auth-check.test.ts test/credential-print.test.ts src/core/agent-session-custom-tools.test.ts src/core/agent-session-length-continuation.test.ts src/core/package-manager.test.ts",
|
|
60
60
|
"prepare": "npm run build",
|
|
61
61
|
"build:native": "bun scripts/build-native.ts",
|
|
62
62
|
"build": "npm run clean && tsgo -p tsconfig.build.json && shx chmod +x dist/cli.js dist/rpc-entry.js && npm run copy-assets",
|