@xynogen/pix-models 0.1.17 → 0.1.18
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/package.json +1 -1
- package/src/patch-builtin.test.ts +50 -22
- package/src/patch-builtin.ts +27 -7
package/package.json
CHANGED
|
@@ -2,19 +2,7 @@ import { describe, expect, it } from "bun:test";
|
|
|
2
2
|
import { mkdtempSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
|
-
|
|
6
|
-
// Pure replacement tested in isolation (the exported fn resolves the host
|
|
7
|
-
// package, which isn't present in the test sandbox).
|
|
8
|
-
const MODEL_COMMAND_LINE = '{ name: "model", description: "Select model (opens selector UI)" },';
|
|
9
|
-
|
|
10
|
-
function escapeRegExp(text: string): string {
|
|
11
|
-
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function patchSource(source: string): string {
|
|
15
|
-
if (!source.includes(MODEL_COMMAND_LINE)) return source;
|
|
16
|
-
return source.replace(new RegExp(`[ \\t]*${escapeRegExp(MODEL_COMMAND_LINE)}\\n?`), "");
|
|
17
|
-
}
|
|
5
|
+
import { stripBuiltinModelCommand } from "./patch-builtin.ts";
|
|
18
6
|
|
|
19
7
|
const UNPATCHED = `export const BUILTIN_SLASH_COMMANDS = [
|
|
20
8
|
{ name: "settings", description: "Open settings menu" },
|
|
@@ -23,40 +11,80 @@ const UNPATCHED = `export const BUILTIN_SLASH_COMMANDS = [
|
|
|
23
11
|
];
|
|
24
12
|
`;
|
|
25
13
|
|
|
14
|
+
const CURRENT_PI = `export const BUILTIN_SLASH_COMMANDS = [
|
|
15
|
+
{ name: "settings", description: "Open settings menu" },
|
|
16
|
+
{ name: "model", description: "Select model (opens selector UI)", argumentHint: "<provider/model>" },
|
|
17
|
+
{ name: "scoped-models", description: "Enable/disable models for Ctrl+P cycling" },
|
|
18
|
+
];
|
|
19
|
+
`;
|
|
20
|
+
|
|
26
21
|
describe("patch-builtin /model removal", () => {
|
|
27
22
|
it("removes the built-in /model line and keeps neighbors", () => {
|
|
28
|
-
const out =
|
|
23
|
+
const out = stripBuiltinModelCommand(UNPATCHED);
|
|
29
24
|
expect(out).not.toContain('name: "model"');
|
|
30
25
|
expect(out).toContain('name: "settings"');
|
|
31
26
|
expect(out).toContain('name: "login"');
|
|
32
27
|
});
|
|
33
28
|
|
|
34
29
|
it("is idempotent — second pass is a no-op", () => {
|
|
35
|
-
const once =
|
|
36
|
-
const twice =
|
|
30
|
+
const once = stripBuiltinModelCommand(UNPATCHED);
|
|
31
|
+
const twice = stripBuiltinModelCommand(once);
|
|
37
32
|
expect(twice).toBe(once);
|
|
38
33
|
});
|
|
39
34
|
|
|
40
35
|
it("leaves an already-clean file untouched", () => {
|
|
41
36
|
const clean = `export const X = [\n { name: "login" },\n];\n`;
|
|
42
|
-
expect(
|
|
37
|
+
expect(stripBuiltinModelCommand(clean)).toBe(clean);
|
|
43
38
|
});
|
|
44
39
|
|
|
45
40
|
it("does not strip the plural /models entry", () => {
|
|
46
|
-
const withPlural = `[
|
|
41
|
+
const withPlural = `export const BUILTIN_SLASH_COMMANDS = [
|
|
47
42
|
{ name: "models", description: "Enhanced picker" },
|
|
48
43
|
{ name: "model", description: "Select model (opens selector UI)" },
|
|
49
|
-
]
|
|
50
|
-
const out =
|
|
44
|
+
];`;
|
|
45
|
+
const out = stripBuiltinModelCommand(withPlural);
|
|
51
46
|
expect(out).toContain('name: "models"');
|
|
52
47
|
expect(out).not.toContain('{ name: "model", description');
|
|
53
48
|
});
|
|
54
49
|
|
|
50
|
+
it("removes Pi's current /model form with an argument hint", () => {
|
|
51
|
+
const out = stripBuiltinModelCommand(CURRENT_PI);
|
|
52
|
+
expect(out).not.toContain('name: "model"');
|
|
53
|
+
expect(out).toContain('name: "settings"');
|
|
54
|
+
expect(out).toContain('name: "scoped-models"');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("does not alter /model text outside the built-in command array", () => {
|
|
58
|
+
const source = `const source = '{ name: "model" }';
|
|
59
|
+
export const BUILTIN_SLASH_COMMANDS = [
|
|
60
|
+
{ name: "settings", description: "Open settings menu" },
|
|
61
|
+
];
|
|
62
|
+
`;
|
|
63
|
+
expect(stripBuiltinModelCommand(source)).toBe(source);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("removes a multi-line /model command without touching adjacent entries", () => {
|
|
67
|
+
const multiline = `export const BUILTIN_SLASH_COMMANDS = [
|
|
68
|
+
{ name: "settings", description: "Open settings menu" },
|
|
69
|
+
{
|
|
70
|
+
name: "model",
|
|
71
|
+
description: "Select model (opens selector UI)",
|
|
72
|
+
argumentHint: "<provider/model>",
|
|
73
|
+
},
|
|
74
|
+
{ name: "login", description: "Configure provider authentication" },
|
|
75
|
+
];
|
|
76
|
+
`;
|
|
77
|
+
const out = stripBuiltinModelCommand(multiline);
|
|
78
|
+
expect(out).not.toContain('name: "model"');
|
|
79
|
+
expect(out).toContain('name: "settings"');
|
|
80
|
+
expect(out).toContain('name: "login"');
|
|
81
|
+
});
|
|
82
|
+
|
|
55
83
|
it("round-trips through disk", () => {
|
|
56
84
|
const dir = mkdtempSync(join(tmpdir(), "pix-patch-"));
|
|
57
85
|
const file = join(dir, "slash-commands.js");
|
|
58
|
-
writeFileSync(file,
|
|
59
|
-
writeFileSync(file,
|
|
86
|
+
writeFileSync(file, CURRENT_PI, "utf8");
|
|
87
|
+
writeFileSync(file, stripBuiltinModelCommand(readFileSync(file, "utf8")), "utf8");
|
|
60
88
|
expect(readFileSync(file, "utf8")).not.toContain('name: "model"');
|
|
61
89
|
});
|
|
62
90
|
});
|
package/src/patch-builtin.ts
CHANGED
|
@@ -19,7 +19,12 @@ import { createRequire } from "node:module";
|
|
|
19
19
|
import { homedir } from "node:os";
|
|
20
20
|
import { dirname, join, resolve } from "node:path";
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
// Pi has added fields to this object over time (for example, `argumentHint` in
|
|
23
|
+
// v0.80). Match the command entry by its stable `name`, rather than an exact
|
|
24
|
+
// serialized line, while limiting the match to a single non-nested object.
|
|
25
|
+
const BUILTIN_COMMANDS_ARRAY = /export\s+const\s+BUILTIN_SLASH_COMMANDS[^=]*=\s*\[/;
|
|
26
|
+
const BUILTIN_MODEL_COMMAND =
|
|
27
|
+
/^[ \t]*\{(?=[^{}]*\bname\s*:\s*["']model["'])[^{}]*\},?[ \t]*(?:\r?\n|$)/gm;
|
|
23
28
|
|
|
24
29
|
/** Candidate slash-commands.js paths, most-specific first. */
|
|
25
30
|
function candidatePaths(): string[] {
|
|
@@ -89,10 +94,8 @@ export function patchOutBuiltinModelCommand(): void {
|
|
|
89
94
|
return;
|
|
90
95
|
}
|
|
91
96
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const patched = source.replace(new RegExp(`[ \\t]*${escapeRegExp(MODEL_COMMAND_LINE)}\\n?`), "");
|
|
95
|
-
if (patched === source) return;
|
|
97
|
+
const patched = stripBuiltinModelCommand(source);
|
|
98
|
+
if (patched === source) return; // already patched, or host format is unknown
|
|
96
99
|
|
|
97
100
|
try {
|
|
98
101
|
writeFileSync(file, patched, "utf8");
|
|
@@ -101,8 +104,25 @@ export function patchOutBuiltinModelCommand(): void {
|
|
|
101
104
|
}
|
|
102
105
|
}
|
|
103
106
|
|
|
104
|
-
|
|
105
|
-
|
|
107
|
+
/**
|
|
108
|
+
* Remove Pi's built-in `/model` entry from compiled slash-command source.
|
|
109
|
+
*
|
|
110
|
+
* The command objects are static, flat literals. Matching the entry's `name`
|
|
111
|
+
* tolerates added properties and line wrapping without touching `/models`.
|
|
112
|
+
*/
|
|
113
|
+
export function stripBuiltinModelCommand(source: string): string {
|
|
114
|
+
const array = BUILTIN_COMMANDS_ARRAY.exec(source);
|
|
115
|
+
if (!array || array.index === undefined) return source;
|
|
116
|
+
|
|
117
|
+
const open = array.index + array[0].lastIndexOf("[");
|
|
118
|
+
const close = source.indexOf("];", open);
|
|
119
|
+
if (close < 0) return source;
|
|
120
|
+
|
|
121
|
+
const entries = source.slice(open + 1, close);
|
|
122
|
+
const patchedEntries = entries.replace(BUILTIN_MODEL_COMMAND, "");
|
|
123
|
+
if (patchedEntries === entries) return source;
|
|
124
|
+
|
|
125
|
+
return `${source.slice(0, open + 1)}${patchedEntries}${source.slice(close)}`;
|
|
106
126
|
}
|
|
107
127
|
|
|
108
128
|
// Export for tests
|