gsd-pi 2.10.0 → 2.10.2
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/node_modules/@gsd/native/dist/ast/index.d.ts +4 -0
- package/node_modules/@gsd/native/dist/ast/index.js +7 -0
- package/node_modules/@gsd/native/dist/ast/types.d.ts +69 -0
- package/node_modules/@gsd/native/dist/ast/types.js +1 -0
- package/node_modules/@gsd/native/{src/clipboard/index.ts → dist/clipboard/index.d.ts} +3 -15
- package/node_modules/@gsd/native/dist/clipboard/index.js +33 -0
- package/node_modules/@gsd/native/dist/clipboard/types.d.ts +7 -0
- package/node_modules/@gsd/native/dist/clipboard/types.js +1 -0
- package/node_modules/@gsd/native/dist/diff/index.d.ts +33 -0
- package/node_modules/@gsd/native/dist/diff/index.js +38 -0
- package/node_modules/@gsd/native/dist/diff/types.d.ts +23 -0
- package/node_modules/@gsd/native/dist/diff/types.js +1 -0
- package/node_modules/@gsd/native/{src/fd/index.ts → dist/fd/index.d.ts} +2 -12
- package/node_modules/@gsd/native/dist/fd/index.js +26 -0
- package/node_modules/@gsd/native/dist/fd/types.d.ts +29 -0
- package/node_modules/@gsd/native/dist/fd/types.js +1 -0
- package/node_modules/@gsd/native/{src/glob/index.ts → dist/glob/index.d.ts} +3 -19
- package/node_modules/@gsd/native/dist/glob/index.js +31 -0
- package/node_modules/@gsd/native/dist/glob/types.d.ts +50 -0
- package/node_modules/@gsd/native/dist/glob/types.js +1 -0
- package/node_modules/@gsd/native/dist/grep/index.d.ts +20 -0
- package/node_modules/@gsd/native/dist/grep/index.js +23 -0
- package/node_modules/@gsd/native/dist/grep/types.d.ts +99 -0
- package/node_modules/@gsd/native/dist/grep/types.js +1 -0
- package/node_modules/@gsd/native/dist/gsd-parser/index.d.ts +45 -0
- package/node_modules/@gsd/native/dist/gsd-parser/index.js +54 -0
- package/node_modules/@gsd/native/dist/gsd-parser/types.d.ts +55 -0
- package/node_modules/@gsd/native/dist/gsd-parser/types.js +7 -0
- package/node_modules/@gsd/native/{src/highlight/index.ts → dist/highlight/index.d.ts} +3 -19
- package/node_modules/@gsd/native/dist/highlight/index.js +33 -0
- package/node_modules/@gsd/native/dist/highlight/types.d.ts +25 -0
- package/node_modules/@gsd/native/dist/highlight/types.js +1 -0
- package/node_modules/@gsd/native/{src/html/index.ts → dist/html/index.d.ts} +1 -10
- package/node_modules/@gsd/native/dist/html/index.js +16 -0
- package/node_modules/@gsd/native/dist/html/types.d.ts +7 -0
- package/node_modules/@gsd/native/dist/html/types.js +1 -0
- package/node_modules/@gsd/native/{src/image/index.ts → dist/image/index.d.ts} +1 -14
- package/node_modules/@gsd/native/dist/image/index.js +18 -0
- package/node_modules/@gsd/native/dist/image/types.d.ts +35 -0
- package/node_modules/@gsd/native/dist/image/types.js +26 -0
- package/node_modules/@gsd/native/{src/index.ts → dist/index.d.ts} +12 -60
- package/node_modules/@gsd/native/dist/index.js +28 -0
- package/node_modules/@gsd/native/dist/native.d.ts +44 -0
- package/node_modules/@gsd/native/dist/native.js +34 -0
- package/node_modules/@gsd/native/dist/ps/index.d.ts +38 -0
- package/node_modules/@gsd/native/{src/ps/index.ts → dist/ps/index.js} +8 -13
- package/node_modules/@gsd/native/{src/ps/types.ts → dist/ps/types.d.ts} +2 -2
- package/node_modules/@gsd/native/dist/ps/types.js +1 -0
- package/node_modules/@gsd/native/{src/text/index.ts → dist/text/index.d.ts} +6 -76
- package/node_modules/@gsd/native/dist/text/index.js +66 -0
- package/node_modules/@gsd/native/dist/text/types.d.ts +27 -0
- package/node_modules/@gsd/native/dist/text/types.js +10 -0
- package/node_modules/@gsd/native/{src/ttsr/index.ts → dist/ttsr/index.d.ts} +3 -15
- package/node_modules/@gsd/native/dist/ttsr/index.js +32 -0
- package/node_modules/@gsd/native/{src/ttsr/types.ts → dist/ttsr/types.d.ts} +4 -5
- package/node_modules/@gsd/native/dist/ttsr/types.js +1 -0
- package/node_modules/@gsd/native/package.json +24 -23
- package/node_modules/@gsd/pi-coding-agent/dist/core/tools/edit-diff.d.ts +11 -5
- package/node_modules/@gsd/pi-coding-agent/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/node_modules/@gsd/pi-coding-agent/dist/core/tools/edit-diff.js +19 -142
- package/node_modules/@gsd/pi-coding-agent/dist/core/tools/edit-diff.js.map +1 -1
- package/node_modules/@gsd/pi-coding-agent/src/core/tools/edit-diff.ts +23 -157
- package/package.json +4 -2
- package/packages/native/dist/ast/index.d.ts +4 -0
- package/packages/native/dist/ast/index.js +7 -0
- package/packages/native/dist/ast/types.d.ts +69 -0
- package/packages/native/dist/ast/types.js +1 -0
- package/packages/native/dist/clipboard/index.d.ts +28 -0
- package/packages/native/dist/clipboard/index.js +33 -0
- package/packages/native/dist/clipboard/types.d.ts +7 -0
- package/packages/native/dist/clipboard/types.js +1 -0
- package/packages/native/dist/diff/index.d.ts +33 -0
- package/packages/native/dist/diff/index.js +38 -0
- package/packages/native/dist/diff/types.d.ts +23 -0
- package/packages/native/dist/diff/types.js +1 -0
- package/packages/native/dist/fd/index.d.ts +25 -0
- package/packages/native/dist/fd/index.js +26 -0
- package/packages/native/dist/fd/types.d.ts +29 -0
- package/packages/native/dist/fd/types.js +1 -0
- package/packages/native/dist/glob/index.d.ts +28 -0
- package/packages/native/dist/glob/index.js +31 -0
- package/packages/native/dist/glob/types.d.ts +50 -0
- package/packages/native/dist/glob/types.js +1 -0
- package/packages/native/dist/grep/index.d.ts +20 -0
- package/packages/native/dist/grep/index.js +23 -0
- package/packages/native/dist/grep/types.d.ts +99 -0
- package/packages/native/dist/grep/types.js +1 -0
- package/packages/native/dist/gsd-parser/index.d.ts +45 -0
- package/packages/native/dist/gsd-parser/index.js +54 -0
- package/packages/native/dist/gsd-parser/types.d.ts +55 -0
- package/packages/native/dist/gsd-parser/types.js +7 -0
- package/packages/native/dist/highlight/index.d.ts +28 -0
- package/packages/native/dist/highlight/index.js +33 -0
- package/packages/native/dist/highlight/types.d.ts +25 -0
- package/packages/native/dist/highlight/types.js +1 -0
- package/packages/native/dist/html/index.d.ts +15 -0
- package/packages/native/dist/html/index.js +16 -0
- package/packages/native/dist/html/types.d.ts +7 -0
- package/packages/native/dist/html/types.js +1 -0
- package/packages/native/dist/image/index.d.ts +15 -0
- package/packages/native/dist/image/index.js +18 -0
- package/packages/native/dist/image/types.d.ts +35 -0
- package/packages/native/dist/image/types.js +26 -0
- package/packages/native/dist/index.d.ts +40 -0
- package/packages/native/dist/index.js +28 -0
- package/packages/native/dist/native.d.ts +44 -0
- package/packages/native/dist/native.js +34 -0
- package/packages/native/dist/ps/index.d.ts +38 -0
- package/packages/native/dist/ps/index.js +47 -0
- package/packages/native/dist/ps/types.d.ts +5 -0
- package/packages/native/dist/ps/types.js +1 -0
- package/packages/native/dist/text/index.d.ts +55 -0
- package/packages/native/dist/text/index.js +66 -0
- package/packages/native/dist/text/types.d.ts +27 -0
- package/packages/native/dist/text/types.js +10 -0
- package/packages/native/dist/ttsr/index.d.ts +27 -0
- package/packages/native/dist/ttsr/index.js +32 -0
- package/packages/native/dist/ttsr/types.d.ts +9 -0
- package/packages/native/dist/ttsr/types.js +1 -0
- package/packages/native/package.json +24 -23
- package/packages/native/src/__tests__/diff.test.mjs +189 -0
- package/packages/native/src/__tests__/ttsr.test.mjs +135 -0
- package/packages/native/src/diff/index.ts +61 -0
- package/packages/native/src/diff/types.ts +24 -0
- package/packages/native/src/gsd-parser/index.ts +98 -0
- package/packages/native/src/gsd-parser/types.ts +62 -0
- package/packages/native/src/index.ts +23 -0
- package/packages/native/src/native.ts +8 -0
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.d.ts +11 -5
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.js +19 -142
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.js.map +1 -1
- package/packages/pi-coding-agent/src/core/tools/edit-diff.ts +23 -157
- package/src/resources/extensions/gsd/files.ts +9 -0
- package/src/resources/extensions/gsd/native-parser-bridge.ts +135 -0
- package/src/resources/extensions/ttsr/ttsr-manager.ts +86 -0
- package/node_modules/@gsd/native/src/__tests__/clipboard.test.mjs +0 -79
- package/node_modules/@gsd/native/src/__tests__/fd.test.mjs +0 -164
- package/node_modules/@gsd/native/src/__tests__/glob.test.mjs +0 -237
- package/node_modules/@gsd/native/src/__tests__/grep.test.mjs +0 -162
- package/node_modules/@gsd/native/src/__tests__/highlight.test.mjs +0 -156
- package/node_modules/@gsd/native/src/__tests__/html.test.mjs +0 -98
- package/node_modules/@gsd/native/src/__tests__/image.test.mjs +0 -137
- package/node_modules/@gsd/native/src/__tests__/ps.test.mjs +0 -109
- package/node_modules/@gsd/native/src/__tests__/text.test.mjs +0 -262
- package/node_modules/@gsd/native/src/ast/index.ts +0 -12
- package/node_modules/@gsd/native/src/ast/types.ts +0 -75
- package/node_modules/@gsd/native/src/clipboard/types.ts +0 -7
- package/node_modules/@gsd/native/src/fd/types.ts +0 -31
- package/node_modules/@gsd/native/src/glob/types.ts +0 -53
- package/node_modules/@gsd/native/src/grep/index.ts +0 -48
- package/node_modules/@gsd/native/src/grep/types.ts +0 -105
- package/node_modules/@gsd/native/src/highlight/types.ts +0 -25
- package/node_modules/@gsd/native/src/html/types.ts +0 -7
- package/node_modules/@gsd/native/src/image/types.ts +0 -41
- package/node_modules/@gsd/native/src/native.ts +0 -94
- package/node_modules/@gsd/native/src/text/types.ts +0 -29
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
import { test, describe } from "node:test";
|
|
2
|
-
import assert from "node:assert/strict";
|
|
3
|
-
import { createRequire } from "node:module";
|
|
4
|
-
import * as path from "node:path";
|
|
5
|
-
import { fileURLToPath } from "node:url";
|
|
6
|
-
import { deflateSync } from "node:zlib";
|
|
7
|
-
|
|
8
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
-
const require = createRequire(import.meta.url);
|
|
10
|
-
|
|
11
|
-
const addonDir = path.resolve(__dirname, "..", "..", "..", "..", "native", "addon");
|
|
12
|
-
const platformTag = `${process.platform}-${process.arch}`;
|
|
13
|
-
const candidates = [
|
|
14
|
-
path.join(addonDir, `gsd_engine.${platformTag}.node`),
|
|
15
|
-
path.join(addonDir, "gsd_engine.dev.node"),
|
|
16
|
-
];
|
|
17
|
-
|
|
18
|
-
let native;
|
|
19
|
-
for (const candidate of candidates) {
|
|
20
|
-
try {
|
|
21
|
-
native = require(candidate);
|
|
22
|
-
break;
|
|
23
|
-
} catch {
|
|
24
|
-
// try next
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
if (!native) {
|
|
29
|
-
console.error("Native addon not found. Run 'npm run build:native -w @gsd/native' first.");
|
|
30
|
-
process.exit(1);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function crc32(buf) {
|
|
34
|
-
let crc = 0xffffffff;
|
|
35
|
-
const table = [];
|
|
36
|
-
for (let n = 0; n < 256; n++) {
|
|
37
|
-
let c = n;
|
|
38
|
-
for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
|
|
39
|
-
table[n] = c;
|
|
40
|
-
}
|
|
41
|
-
for (let i = 0; i < buf.length; i++) crc = table[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8);
|
|
42
|
-
return (crc ^ 0xffffffff) >>> 0;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function createTestPng() {
|
|
46
|
-
const signature = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);
|
|
47
|
-
const ihdrData = Buffer.alloc(13);
|
|
48
|
-
ihdrData.writeUInt32BE(2, 0);
|
|
49
|
-
ihdrData.writeUInt32BE(2, 4);
|
|
50
|
-
ihdrData[8] = 8;
|
|
51
|
-
ihdrData[9] = 2;
|
|
52
|
-
const ihdrType = Buffer.from("IHDR");
|
|
53
|
-
const ihdrCrc = Buffer.alloc(4);
|
|
54
|
-
ihdrCrc.writeUInt32BE(crc32(Buffer.concat([ihdrType, ihdrData])));
|
|
55
|
-
const ihdr = Buffer.concat([Buffer.from([0, 0, 0, 13]), ihdrType, ihdrData, ihdrCrc]);
|
|
56
|
-
|
|
57
|
-
const raw = Buffer.from([
|
|
58
|
-
0, 255, 0, 0, 255, 0, 0,
|
|
59
|
-
0, 255, 0, 0, 255, 0, 0,
|
|
60
|
-
]);
|
|
61
|
-
const compressed = deflateSync(raw);
|
|
62
|
-
const idatType = Buffer.from("IDAT");
|
|
63
|
-
const idatLen = Buffer.alloc(4);
|
|
64
|
-
idatLen.writeUInt32BE(compressed.length);
|
|
65
|
-
const idatCrc = Buffer.alloc(4);
|
|
66
|
-
idatCrc.writeUInt32BE(crc32(Buffer.concat([idatType, compressed])));
|
|
67
|
-
const idat = Buffer.concat([idatLen, idatType, compressed, idatCrc]);
|
|
68
|
-
|
|
69
|
-
const iendType = Buffer.from("IEND");
|
|
70
|
-
const iendCrc = Buffer.alloc(4);
|
|
71
|
-
iendCrc.writeUInt32BE(crc32(iendType));
|
|
72
|
-
const iend = Buffer.concat([Buffer.from([0, 0, 0, 0]), iendType, iendCrc]);
|
|
73
|
-
|
|
74
|
-
return Buffer.concat([signature, ihdr, idat, iend]);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const NativeImage = native.NativeImage;
|
|
78
|
-
|
|
79
|
-
describe("native image: NativeImage", () => {
|
|
80
|
-
test("NativeImage class exists with parse method", () => {
|
|
81
|
-
assert.ok(NativeImage, "NativeImage should be exported");
|
|
82
|
-
assert.equal(typeof NativeImage.parse, "function");
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
test("parse decodes PNG with correct dimensions", async () => {
|
|
86
|
-
const img = await NativeImage.parse(createTestPng());
|
|
87
|
-
assert.equal(img.width, 2);
|
|
88
|
-
assert.equal(img.height, 2);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
test("encode to PNG produces valid PNG", async () => {
|
|
92
|
-
const img = await NativeImage.parse(createTestPng());
|
|
93
|
-
const encoded = await img.encode(0, 100);
|
|
94
|
-
assert.ok(encoded.length > 0);
|
|
95
|
-
assert.equal(encoded[0], 0x89);
|
|
96
|
-
assert.equal(encoded[1], 0x50);
|
|
97
|
-
assert.equal(encoded[2], 0x4e);
|
|
98
|
-
assert.equal(encoded[3], 0x47);
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
test("encode to JPEG produces valid JPEG", async () => {
|
|
102
|
-
const img = await NativeImage.parse(createTestPng());
|
|
103
|
-
const encoded = await img.encode(1, 80);
|
|
104
|
-
assert.ok(encoded.length > 0);
|
|
105
|
-
assert.equal(encoded[0], 0xff);
|
|
106
|
-
assert.equal(encoded[1], 0xd8);
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
test("resize returns correct dimensions", async () => {
|
|
110
|
-
const img = await NativeImage.parse(createTestPng());
|
|
111
|
-
const resized = await img.resize(10, 20, 5);
|
|
112
|
-
assert.equal(resized.width, 10);
|
|
113
|
-
assert.equal(resized.height, 20);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
test("resize + encode round-trip", async () => {
|
|
117
|
-
const img = await NativeImage.parse(createTestPng());
|
|
118
|
-
const resized = await img.resize(4, 4, 1);
|
|
119
|
-
const encoded = await resized.encode(0, 100);
|
|
120
|
-
assert.ok(encoded.length > 0);
|
|
121
|
-
const reparsed = await NativeImage.parse(new Uint8Array(encoded));
|
|
122
|
-
assert.equal(reparsed.width, 4);
|
|
123
|
-
assert.equal(reparsed.height, 4);
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
test("rejects invalid image data", async () => {
|
|
127
|
-
await assert.rejects(
|
|
128
|
-
() => NativeImage.parse(new Uint8Array([0, 1, 2, 3, 4, 5])),
|
|
129
|
-
/Failed to (detect|decode) image/,
|
|
130
|
-
);
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
test("rejects invalid format number", async () => {
|
|
134
|
-
const img = await NativeImage.parse(createTestPng());
|
|
135
|
-
await assert.rejects(() => img.encode(99, 100), /Invalid image format/);
|
|
136
|
-
});
|
|
137
|
-
});
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import { test, describe } from "node:test";
|
|
2
|
-
import assert from "node:assert/strict";
|
|
3
|
-
import { createRequire } from "node:module";
|
|
4
|
-
import * as path from "node:path";
|
|
5
|
-
import { fileURLToPath } from "node:url";
|
|
6
|
-
import { spawn } from "node:child_process";
|
|
7
|
-
|
|
8
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
-
const require = createRequire(import.meta.url);
|
|
10
|
-
|
|
11
|
-
// Load the native addon directly
|
|
12
|
-
const addonDir = path.resolve(__dirname, "..", "..", "..", "..", "native", "addon");
|
|
13
|
-
const platformTag = `${process.platform}-${process.arch}`;
|
|
14
|
-
const candidates = [
|
|
15
|
-
path.join(addonDir, `gsd_engine.${platformTag}.node`),
|
|
16
|
-
path.join(addonDir, "gsd_engine.dev.node"),
|
|
17
|
-
];
|
|
18
|
-
|
|
19
|
-
let native;
|
|
20
|
-
for (const candidate of candidates) {
|
|
21
|
-
try {
|
|
22
|
-
native = require(candidate);
|
|
23
|
-
break;
|
|
24
|
-
} catch {
|
|
25
|
-
// try next
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (!native) {
|
|
30
|
-
console.error("Native addon not found. Run `npm run build:native -w @gsd/native` first.");
|
|
31
|
-
process.exit(1);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
describe("native ps: listDescendants()", () => {
|
|
35
|
-
test("returns an array for the current process", () => {
|
|
36
|
-
const descendants = native.listDescendants(process.pid);
|
|
37
|
-
assert.ok(Array.isArray(descendants));
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
test("returns empty array for non-existent PID", () => {
|
|
41
|
-
// PID 2147483647 is extremely unlikely to exist
|
|
42
|
-
const descendants = native.listDescendants(2147483647);
|
|
43
|
-
assert.ok(Array.isArray(descendants));
|
|
44
|
-
assert.equal(descendants.length, 0);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
test("finds child processes", { skip: "proc_listchildpids unreliable on macOS — needs sysctl KERN_PROC implementation" }, async () => {
|
|
48
|
-
const child = spawn("sh", ["-c", "sleep 30 & sleep 30 & wait"], {
|
|
49
|
-
stdio: "ignore",
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
53
|
-
|
|
54
|
-
try {
|
|
55
|
-
const descendants = native.listDescendants(child.pid);
|
|
56
|
-
assert.ok(descendants.length > 0, `expected descendants of sh (pid ${child.pid}), got: ${JSON.stringify(descendants)}`);
|
|
57
|
-
} finally {
|
|
58
|
-
native.killTree(child.pid, 9);
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
describe("native ps: killTree()", () => {
|
|
64
|
-
test("kills a process and its children", async () => {
|
|
65
|
-
// Spawn a shell that spawns a sleep subprocess
|
|
66
|
-
const child = spawn("sh", ["-c", "sleep 60"], { stdio: "ignore" });
|
|
67
|
-
|
|
68
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
69
|
-
|
|
70
|
-
const killed = native.killTree(child.pid, 9);
|
|
71
|
-
assert.ok(killed >= 1, `should kill at least 1 process, killed: ${killed}`);
|
|
72
|
-
|
|
73
|
-
// Verify the child is actually dead
|
|
74
|
-
await new Promise((resolve) => {
|
|
75
|
-
child.on("exit", resolve);
|
|
76
|
-
// Timeout safety — if already exited, resolve immediately
|
|
77
|
-
setTimeout(resolve, 500);
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
test("returns 0 for non-existent PID", () => {
|
|
82
|
-
const killed = native.killTree(2147483647, 9);
|
|
83
|
-
assert.equal(killed, 0);
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
describe("native ps: processGroupId()", () => {
|
|
88
|
-
test("returns a number for the current process", () => {
|
|
89
|
-
const pgid = native.processGroupId(process.pid);
|
|
90
|
-
if (process.platform === "win32") {
|
|
91
|
-
assert.equal(pgid, null);
|
|
92
|
-
} else {
|
|
93
|
-
assert.equal(typeof pgid, "number");
|
|
94
|
-
assert.ok(pgid > 0);
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
test("returns null for non-existent PID", () => {
|
|
99
|
-
const pgid = native.processGroupId(2147483647);
|
|
100
|
-
assert.equal(pgid, null);
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
describe("native ps: killProcessGroup()", () => {
|
|
105
|
-
test("returns false for non-existent process group", () => {
|
|
106
|
-
const result = native.killProcessGroup(2147483647, 15);
|
|
107
|
-
assert.equal(result, false);
|
|
108
|
-
});
|
|
109
|
-
});
|
|
@@ -1,262 +0,0 @@
|
|
|
1
|
-
import { test, describe } from "node:test";
|
|
2
|
-
import assert from "node:assert/strict";
|
|
3
|
-
import { createRequire } from "node:module";
|
|
4
|
-
import * as path from "node:path";
|
|
5
|
-
import { fileURLToPath } from "node:url";
|
|
6
|
-
|
|
7
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
-
const require = createRequire(import.meta.url);
|
|
9
|
-
|
|
10
|
-
// Load the native addon directly
|
|
11
|
-
const addonDir = path.resolve(
|
|
12
|
-
__dirname,
|
|
13
|
-
"..",
|
|
14
|
-
"..",
|
|
15
|
-
"..",
|
|
16
|
-
"..",
|
|
17
|
-
"native",
|
|
18
|
-
"addon",
|
|
19
|
-
);
|
|
20
|
-
const platformTag = `${process.platform}-${process.arch}`;
|
|
21
|
-
const candidates = [
|
|
22
|
-
path.join(addonDir, `gsd_engine.${platformTag}.node`),
|
|
23
|
-
path.join(addonDir, "gsd_engine.dev.node"),
|
|
24
|
-
];
|
|
25
|
-
|
|
26
|
-
let native;
|
|
27
|
-
for (const candidate of candidates) {
|
|
28
|
-
try {
|
|
29
|
-
native = require(candidate);
|
|
30
|
-
break;
|
|
31
|
-
} catch {
|
|
32
|
-
// try next
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (!native) {
|
|
37
|
-
console.error(
|
|
38
|
-
"Native addon not found. Run `npm run build:native -w @gsd/native` first.",
|
|
39
|
-
);
|
|
40
|
-
process.exit(1);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// ── visibleWidth ───────────────────────────────────────────────────────
|
|
44
|
-
|
|
45
|
-
describe("visibleWidth", () => {
|
|
46
|
-
test("plain ASCII text", () => {
|
|
47
|
-
assert.equal(native.visibleWidth("hello"), 5);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
test("empty string", () => {
|
|
51
|
-
assert.equal(native.visibleWidth(""), 0);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
test("ignores ANSI SGR codes", () => {
|
|
55
|
-
assert.equal(native.visibleWidth("\x1b[31mhello\x1b[0m"), 5);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
test("ignores 256-color ANSI", () => {
|
|
59
|
-
assert.equal(native.visibleWidth("\x1b[38;5;196mred\x1b[0m"), 3);
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
test("ignores RGB ANSI", () => {
|
|
63
|
-
assert.equal(
|
|
64
|
-
native.visibleWidth("\x1b[38;2;255;128;0morange\x1b[0m"),
|
|
65
|
-
6,
|
|
66
|
-
);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
test("counts tabs with default width", () => {
|
|
70
|
-
// default tab width = 3
|
|
71
|
-
assert.equal(native.visibleWidth("a\tb"), 1 + 3 + 1);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
test("counts tabs with custom width", () => {
|
|
75
|
-
assert.equal(native.visibleWidth("a\tb", 4), 1 + 4 + 1);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
test("CJK double-width characters", () => {
|
|
79
|
-
assert.equal(native.visibleWidth("\u4e16\u754c"), 4); // 世界
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
test("mixed ASCII and CJK", () => {
|
|
83
|
-
assert.equal(native.visibleWidth("a\u4e16b"), 4); // a + 2 + 1
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
// ── wrapTextWithAnsi ───────────────────────────────────────────────────
|
|
88
|
-
|
|
89
|
-
describe("wrapTextWithAnsi", () => {
|
|
90
|
-
test("wraps plain text at word boundary", () => {
|
|
91
|
-
const lines = native.wrapTextWithAnsi("hello world", 5);
|
|
92
|
-
assert.equal(lines.length, 2);
|
|
93
|
-
assert.equal(lines[0], "hello");
|
|
94
|
-
assert.equal(lines[1], "world");
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
test("no wrap needed", () => {
|
|
98
|
-
const lines = native.wrapTextWithAnsi("hi", 10);
|
|
99
|
-
assert.equal(lines.length, 1);
|
|
100
|
-
assert.equal(lines[0], "hi");
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
test("empty string produces one empty line", () => {
|
|
104
|
-
const lines = native.wrapTextWithAnsi("", 10);
|
|
105
|
-
assert.equal(lines.length, 1);
|
|
106
|
-
assert.equal(lines[0], "");
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
test("preserves ANSI color across wrap", () => {
|
|
110
|
-
const lines = native.wrapTextWithAnsi(
|
|
111
|
-
"\x1b[38;2;156;163;176mhello world\x1b[0m",
|
|
112
|
-
5,
|
|
113
|
-
);
|
|
114
|
-
assert.equal(lines.length, 2);
|
|
115
|
-
assert.ok(lines[0].startsWith("\x1b[38;2;156;163;176m"));
|
|
116
|
-
assert.ok(lines[1].startsWith("\x1b[38;2;156;163;176m"));
|
|
117
|
-
assert.ok(lines[1].includes("world"));
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
test("handles multiline input (newlines)", () => {
|
|
121
|
-
const lines = native.wrapTextWithAnsi("line one\nline two", 20);
|
|
122
|
-
assert.equal(lines.length, 2);
|
|
123
|
-
assert.equal(lines[0], "line one");
|
|
124
|
-
assert.equal(lines[1], "line two");
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
test("breaks long words", () => {
|
|
128
|
-
const lines = native.wrapTextWithAnsi("abcdefghij", 5);
|
|
129
|
-
assert.equal(lines.length, 2);
|
|
130
|
-
assert.equal(lines[0], "abcde");
|
|
131
|
-
assert.equal(lines[1], "fghij");
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
// ── truncateToWidth ────────────────────────────────────────────────────
|
|
136
|
-
|
|
137
|
-
describe("truncateToWidth", () => {
|
|
138
|
-
test("returns original when fits", () => {
|
|
139
|
-
const result = native.truncateToWidth("hello", 10, 0, false);
|
|
140
|
-
assert.equal(result, "hello");
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
test("truncates with unicode ellipsis", () => {
|
|
144
|
-
const result = native.truncateToWidth("hello world", 6, 0, false);
|
|
145
|
-
assert.equal(native.visibleWidth(result), 6);
|
|
146
|
-
assert.ok(result.includes("\u2026"));
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
test("truncates with ASCII ellipsis", () => {
|
|
150
|
-
const result = native.truncateToWidth("hello world", 8, 1, false);
|
|
151
|
-
assert.ok(result.includes("..."));
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
test("truncates with no ellipsis", () => {
|
|
155
|
-
const result = native.truncateToWidth("hello world", 5, 2, false);
|
|
156
|
-
assert.equal(native.visibleWidth(result), 5);
|
|
157
|
-
assert.ok(!result.includes("\u2026"));
|
|
158
|
-
assert.ok(!result.includes("..."));
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
test("pads to width", () => {
|
|
162
|
-
const result = native.truncateToWidth("hi", 10, 0, true);
|
|
163
|
-
assert.equal(native.visibleWidth(result), 10);
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
test("preserves ANSI codes and resets on truncation", () => {
|
|
167
|
-
const input = "\x1b[31mhello world\x1b[0m";
|
|
168
|
-
const result = native.truncateToWidth(input, 6, 0, false);
|
|
169
|
-
// Should contain the red code and a reset before ellipsis
|
|
170
|
-
assert.ok(result.includes("\x1b[31m"));
|
|
171
|
-
assert.ok(result.includes("\x1b[0m"));
|
|
172
|
-
});
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
// ── sliceWithWidth ─────────────────────────────────────────────────────
|
|
176
|
-
|
|
177
|
-
describe("sliceWithWidth", () => {
|
|
178
|
-
test("slices from start", () => {
|
|
179
|
-
const result = native.sliceWithWidth("hello world", 0, 5, false);
|
|
180
|
-
assert.equal(result.text, "hello");
|
|
181
|
-
assert.equal(result.width, 5);
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
test("slices from middle", () => {
|
|
185
|
-
const result = native.sliceWithWidth("hello world", 6, 5, false);
|
|
186
|
-
assert.equal(result.text, "world");
|
|
187
|
-
assert.equal(result.width, 5);
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
test("preserves ANSI codes in slice", () => {
|
|
191
|
-
const result = native.sliceWithWidth(
|
|
192
|
-
"\x1b[31mhello\x1b[0m world",
|
|
193
|
-
0,
|
|
194
|
-
5,
|
|
195
|
-
false,
|
|
196
|
-
);
|
|
197
|
-
assert.equal(result.text, "\x1b[31mhello\x1b[0m");
|
|
198
|
-
assert.equal(result.width, 5);
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
test("empty slice", () => {
|
|
202
|
-
const result = native.sliceWithWidth("hello", 0, 0, false);
|
|
203
|
-
assert.equal(result.text, "");
|
|
204
|
-
assert.equal(result.width, 0);
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
test("beyond string length", () => {
|
|
208
|
-
const result = native.sliceWithWidth("hi", 0, 100, false);
|
|
209
|
-
assert.equal(result.text, "hi");
|
|
210
|
-
assert.equal(result.width, 2);
|
|
211
|
-
});
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
// ── extractSegments ────────────────────────────────────────────────────
|
|
215
|
-
|
|
216
|
-
describe("extractSegments", () => {
|
|
217
|
-
test("extracts before and after segments", () => {
|
|
218
|
-
const result = native.extractSegments(
|
|
219
|
-
"hello world test",
|
|
220
|
-
5,
|
|
221
|
-
6,
|
|
222
|
-
5,
|
|
223
|
-
false,
|
|
224
|
-
);
|
|
225
|
-
assert.equal(result.before, "hello");
|
|
226
|
-
assert.equal(result.beforeWidth, 5);
|
|
227
|
-
assert.equal(result.after, "world");
|
|
228
|
-
assert.equal(result.afterWidth, 5);
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
test("handles no after segment", () => {
|
|
232
|
-
const result = native.extractSegments("hello world", 5, 0, 0, false);
|
|
233
|
-
assert.equal(result.before, "hello");
|
|
234
|
-
assert.equal(result.beforeWidth, 5);
|
|
235
|
-
assert.equal(result.after, "");
|
|
236
|
-
assert.equal(result.afterWidth, 0);
|
|
237
|
-
});
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
// ── sanitizeText ───────────────────────────────────────────────────────
|
|
241
|
-
|
|
242
|
-
describe("sanitizeText", () => {
|
|
243
|
-
test("strips ANSI codes", () => {
|
|
244
|
-
assert.equal(native.sanitizeText("\x1b[31mhello\x1b[0m"), "hello");
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
test("returns original when clean", () => {
|
|
248
|
-
assert.equal(native.sanitizeText("hello"), "hello");
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
test("removes control characters", () => {
|
|
252
|
-
assert.equal(native.sanitizeText("he\x01llo"), "hello");
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
test("preserves tabs and newlines", () => {
|
|
256
|
-
assert.equal(native.sanitizeText("a\tb\nc"), "a\tb\nc");
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
test("normalizes CR", () => {
|
|
260
|
-
assert.equal(native.sanitizeText("hello\r\nworld"), "hello\nworld");
|
|
261
|
-
});
|
|
262
|
-
});
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { native } from "../native.js";
|
|
2
|
-
import type { AstFindOptions, AstFindResult, AstReplaceOptions, AstReplaceResult, AstFindMatch, AstReplaceChange, AstReplaceFileChange } from "./types.js";
|
|
3
|
-
|
|
4
|
-
export type { AstFindMatch, AstFindOptions, AstFindResult, AstReplaceChange, AstReplaceFileChange, AstReplaceOptions, AstReplaceResult };
|
|
5
|
-
|
|
6
|
-
export function astGrep(options: AstFindOptions): AstFindResult {
|
|
7
|
-
return (native as Record<string, Function>).astGrep(options) as AstFindResult;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function astEdit(options: AstReplaceOptions): AstReplaceResult {
|
|
11
|
-
return (native as Record<string, Function>).astEdit(options) as AstReplaceResult;
|
|
12
|
-
}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
export interface AstFindOptions {
|
|
2
|
-
patterns: string[];
|
|
3
|
-
lang?: string;
|
|
4
|
-
path?: string;
|
|
5
|
-
glob?: string;
|
|
6
|
-
selector?: string;
|
|
7
|
-
strictness?: string;
|
|
8
|
-
limit?: number;
|
|
9
|
-
offset?: number;
|
|
10
|
-
includeMeta?: boolean;
|
|
11
|
-
context?: number;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface AstFindMatch {
|
|
15
|
-
path: string;
|
|
16
|
-
text: string;
|
|
17
|
-
byteStart: number;
|
|
18
|
-
byteEnd: number;
|
|
19
|
-
startLine: number;
|
|
20
|
-
startColumn: number;
|
|
21
|
-
endLine: number;
|
|
22
|
-
endColumn: number;
|
|
23
|
-
metaVariables?: Record<string, string>;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface AstFindResult {
|
|
27
|
-
matches: AstFindMatch[];
|
|
28
|
-
totalMatches: number;
|
|
29
|
-
filesWithMatches: number;
|
|
30
|
-
filesSearched: number;
|
|
31
|
-
limitReached: boolean;
|
|
32
|
-
parseErrors?: string[];
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface AstReplaceOptions {
|
|
36
|
-
rewrites: Record<string, string>;
|
|
37
|
-
lang?: string;
|
|
38
|
-
path?: string;
|
|
39
|
-
glob?: string;
|
|
40
|
-
selector?: string;
|
|
41
|
-
strictness?: string;
|
|
42
|
-
dryRun?: boolean;
|
|
43
|
-
maxReplacements?: number;
|
|
44
|
-
maxFiles?: number;
|
|
45
|
-
failOnParseError?: boolean;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export interface AstReplaceChange {
|
|
49
|
-
path: string;
|
|
50
|
-
before: string;
|
|
51
|
-
after: string;
|
|
52
|
-
byteStart: number;
|
|
53
|
-
byteEnd: number;
|
|
54
|
-
deletedLength: number;
|
|
55
|
-
startLine: number;
|
|
56
|
-
startColumn: number;
|
|
57
|
-
endLine: number;
|
|
58
|
-
endColumn: number;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export interface AstReplaceFileChange {
|
|
62
|
-
path: string;
|
|
63
|
-
count: number;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export interface AstReplaceResult {
|
|
67
|
-
changes: AstReplaceChange[];
|
|
68
|
-
fileChanges: AstReplaceFileChange[];
|
|
69
|
-
totalReplacements: number;
|
|
70
|
-
filesTouched: number;
|
|
71
|
-
filesSearched: number;
|
|
72
|
-
applied: boolean;
|
|
73
|
-
limitReached: boolean;
|
|
74
|
-
parseErrors?: string[];
|
|
75
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/** Options for fuzzy file path search. */
|
|
2
|
-
export interface FuzzyFindOptions {
|
|
3
|
-
/** Fuzzy query to match against file paths (case-insensitive). */
|
|
4
|
-
query: string;
|
|
5
|
-
/** Directory to search. */
|
|
6
|
-
path: string;
|
|
7
|
-
/** Include hidden files (default: false). */
|
|
8
|
-
hidden?: boolean;
|
|
9
|
-
/** Respect .gitignore (default: true). */
|
|
10
|
-
gitignore?: boolean;
|
|
11
|
-
/** Maximum number of matches to return (default: 100). */
|
|
12
|
-
maxResults?: number;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/** A single match in fuzzy find results. */
|
|
16
|
-
export interface FuzzyFindMatch {
|
|
17
|
-
/** Relative path from the search root (uses `/` separators). Directories have a trailing `/`. */
|
|
18
|
-
path: string;
|
|
19
|
-
/** Whether this entry is a directory. */
|
|
20
|
-
isDirectory: boolean;
|
|
21
|
-
/** Match quality score (higher is better). */
|
|
22
|
-
score: number;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/** Result of fuzzy file path search. */
|
|
26
|
-
export interface FuzzyFindResult {
|
|
27
|
-
/** Matched entries (up to `maxResults`), sorted by score descending. */
|
|
28
|
-
matches: FuzzyFindMatch[];
|
|
29
|
-
/** Total number of matches found (may exceed `matches.length`). */
|
|
30
|
-
totalMatches: number;
|
|
31
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/** File type classification for filesystem entries. */
|
|
2
|
-
export const enum FileType {
|
|
3
|
-
/** Regular file. */
|
|
4
|
-
File = 1,
|
|
5
|
-
/** Directory. */
|
|
6
|
-
Dir = 2,
|
|
7
|
-
/** Symbolic link. */
|
|
8
|
-
Symlink = 3,
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/** A single filesystem entry matched by a glob operation. */
|
|
12
|
-
export interface GlobMatch {
|
|
13
|
-
/** Relative path from the search root, using forward slashes. */
|
|
14
|
-
path: string;
|
|
15
|
-
/** Resolved filesystem type for the match. */
|
|
16
|
-
fileType: FileType;
|
|
17
|
-
/** Modification time in milliseconds since Unix epoch. */
|
|
18
|
-
mtime: number | null;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/** Options for the glob operation. */
|
|
22
|
-
export interface GlobOptions {
|
|
23
|
-
/** Glob pattern to match (e.g., "*.ts"). */
|
|
24
|
-
pattern: string;
|
|
25
|
-
/** Directory to search. */
|
|
26
|
-
path: string;
|
|
27
|
-
/** Filter by file type: File (1), Dir (2), or Symlink (3). */
|
|
28
|
-
fileType?: FileType;
|
|
29
|
-
/** Match simple patterns recursively by default (default: true). */
|
|
30
|
-
recursive?: boolean;
|
|
31
|
-
/** Include hidden files (default: false). */
|
|
32
|
-
hidden?: boolean;
|
|
33
|
-
/** Maximum number of results to return. */
|
|
34
|
-
maxResults?: number;
|
|
35
|
-
/** Respect .gitignore files (default: true). */
|
|
36
|
-
gitignore?: boolean;
|
|
37
|
-
/** Enable shared filesystem scan cache (default: false). */
|
|
38
|
-
cache?: boolean;
|
|
39
|
-
/** Sort results by mtime (most recent first) before applying limit. */
|
|
40
|
-
sortByMtime?: boolean;
|
|
41
|
-
/** Include node_modules entries (default: false, unless pattern mentions it). */
|
|
42
|
-
includeNodeModules?: boolean;
|
|
43
|
-
/** Timeout in milliseconds for the operation. */
|
|
44
|
-
timeoutMs?: number;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** Result payload returned by a glob operation. */
|
|
48
|
-
export interface GlobResult {
|
|
49
|
-
/** Matched filesystem entries. */
|
|
50
|
-
matches: GlobMatch[];
|
|
51
|
-
/** Number of returned matches. */
|
|
52
|
-
totalMatches: number;
|
|
53
|
-
}
|