pi-goosedump 0.12.53 → 0.12.55

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.
Files changed (3) hide show
  1. package/README.md +27 -3
  2. package/dist/index.ts +44 -25
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -11,9 +11,12 @@ pi install npm:pi-goosedump
11
11
 
12
12
  Bundled native binaries: Linux x64 and arm64, macOS arm64, and Windows x64.
13
13
 
14
- Unsupported platforms are rejected when the extension loads. A missing packaged
15
- binary is treated as a broken installation instead of falling back to a
16
- `goosedump` executable on `PATH`. Local models download on first use.
14
+ Unsupported platforms are rejected when the extension loads. The extension uses
15
+ that packaged binary by default and does not fall back to a `goosedump`
16
+ executable on `PATH`. Set the shared `GOOSEDUMP_BINARY` environment variable to
17
+ an absolute executable path to override it. An invalid override or missing
18
+ packaged binary is treated as a broken installation. Local models download on
19
+ first use.
17
20
 
18
21
  ## Tools
19
22
 
@@ -99,6 +102,27 @@ The footer shows the remaining turn count in hexadecimal.
99
102
  compacts at that turn boundary, and resumes automatically.
100
103
  - Goosedump failures fall back to Pi's compactor.
101
104
 
105
+ ## Development
106
+
107
+ Install dependencies and run the test suite:
108
+
109
+ ```sh
110
+ npm install
111
+ npm test
112
+ npm run check
113
+ ```
114
+
115
+ To exercise the extension against the binary built in this repository:
116
+
117
+ ```sh
118
+ cargo build
119
+ GOOSEDUMP_BINARY="$(cd ../.. && pwd)/target/debug/goosedump" \
120
+ pi --no-extensions -e ./index.ts
121
+ ```
122
+
123
+ The explicit override takes precedence over the packaged platform binary. It must
124
+ be an absolute path to an executable regular file.
125
+
102
126
  ## License
103
127
 
104
128
  Apache-2.0. See [LICENSE](LICENSE).
package/dist/index.ts CHANGED
@@ -5,9 +5,9 @@
5
5
  import { Type as Type2 } from "@sinclair/typebox";
6
6
  import { Value as Value2 } from "@sinclair/typebox/value";
7
7
  import { execFile } from "node:child_process";
8
- import { existsSync, readFileSync } from "node:fs";
8
+ import { accessSync, constants as fsConstants, existsSync, readFileSync as readFileSync2, statSync } from "node:fs";
9
9
  import { createRequire } from "node:module";
10
- import { dirname, join } from "node:path";
10
+ import { dirname, isAbsolute, join } from "node:path";
11
11
  import { fileURLToPath } from "node:url";
12
12
 
13
13
  // src/format.ts
@@ -160,7 +160,7 @@ var GOOSE_PROVIDERS = [
160
160
  var SUMMARIZABLE_ENTRY_TYPES = new Set(["message", "custom_message", "branch_summary"]);
161
161
 
162
162
  // src/util.ts
163
- import { closeSync, openSync, readSync } from "node:fs";
163
+ import { readFileSync } from "node:fs";
164
164
  function isRecord(value) {
165
165
  return typeof value === "object" && value !== null && !Array.isArray(value);
166
166
  }
@@ -181,21 +181,13 @@ function compactStartedMessage(keep, queued = false) {
181
181
  return keep !== null ? `${action}; keeping the last ${keep} user turn${keep === 1 ? "" : "s"}.` : `${action} up to Pi's token-based cut.`;
182
182
  }
183
183
  function readFirstLine(path) {
184
- let fd;
185
184
  try {
186
- fd = openSync(path, "r");
187
- const buf = Buffer.alloc(8192);
188
- const bytesRead = readSync(fd, buf, 0, buf.length, 0);
189
- if (bytesRead < 0)
190
- return null;
191
- const slice = buf.subarray(0, bytesRead);
192
- const newline = slice.indexOf(10);
193
- return (newline < 0 ? slice : slice.subarray(0, newline)).toString("utf8");
185
+ const content = readFileSync(path, "utf8");
186
+ const newline = content.indexOf(`
187
+ `);
188
+ return newline < 0 ? content : content.slice(0, newline);
194
189
  } catch {
195
190
  return null;
196
- } finally {
197
- if (fd !== undefined)
198
- closeSync(fd);
199
191
  }
200
192
  }
201
193
  function formatTarget(provider, id) {
@@ -206,16 +198,17 @@ function appendScope(args, scope) {
206
198
  args.push("--all");
207
199
  }
208
200
  function utf8Prefix(text, maxBytes) {
209
- const prefix = [];
210
201
  let bytes = 0;
202
+ let index = 0;
211
203
  for (const char of text) {
212
- const charBytes = Buffer.byteLength(char);
204
+ const cp = char.codePointAt(0);
205
+ const charBytes = cp <= 127 ? 1 : cp <= 2047 ? 2 : cp <= 65535 ? 3 : 4;
213
206
  if (bytes + charBytes > maxBytes)
214
207
  break;
215
- prefix.push(char);
216
208
  bytes += charBytes;
209
+ index += char.length;
217
210
  }
218
- return prefix.join("");
211
+ return text.slice(0, index);
219
212
  }
220
213
  function isControlChar(char) {
221
214
  const code = char.charCodeAt(0);
@@ -417,7 +410,7 @@ function resolveNativePackageTable() {
417
410
  throw new Error("broken pi-goosedump installation: cannot resolve the native package table from @jarkkojs/goosedump");
418
411
  }
419
412
  function loadNativeGoosedumpPackages() {
420
- const table = JSON.parse(readFileSync(resolveNativePackageTable(), "utf8"));
413
+ const table = JSON.parse(readFileSync2(resolveNativePackageTable(), "utf8"));
421
414
  if (!Value2.Check(NATIVE_GOOSEDUMP_PACKAGES_SCHEMA, table)) {
422
415
  throw new Error("broken pi-goosedump installation: native package table is invalid");
423
416
  }
@@ -442,7 +435,29 @@ function resolveGoosedumpBinary() {
442
435
  throw new Error("broken pi-goosedump installation: cannot resolve the @jarkkojs/goosedump dependency", { cause });
443
436
  }
444
437
  }
445
- function resolveNativeGoosedumpBinary() {
438
+ var GOOSEDUMP_BINARY_ENV = "GOOSEDUMP_BINARY";
439
+ function resolveGoosedumpBinaryOverride(environment = process.env) {
440
+ const binaryPath = environment[GOOSEDUMP_BINARY_ENV];
441
+ if (binaryPath === undefined)
442
+ return null;
443
+ if (!isAbsolute(binaryPath)) {
444
+ throw new Error(`${GOOSEDUMP_BINARY_ENV} must be an absolute path to the goosedump executable`);
445
+ }
446
+ try {
447
+ if (!statSync(binaryPath).isFile())
448
+ throw new Error("not a regular file");
449
+ accessSync(binaryPath, fsConstants.X_OK);
450
+ } catch (cause) {
451
+ throw new Error(`${GOOSEDUMP_BINARY_ENV} does not point to an executable file: ${binaryPath}`, {
452
+ cause
453
+ });
454
+ }
455
+ return binaryPath;
456
+ }
457
+ function resolveNativeGoosedumpBinary(environment = process.env) {
458
+ const override = resolveGoosedumpBinaryOverride(environment);
459
+ if (override)
460
+ return override;
446
461
  const target = `${process.platform}-${process.arch}`;
447
462
  const { packageName, binaryName } = nativeGoosedumpPackage(target);
448
463
  try {
@@ -610,7 +625,7 @@ import { randomUUID } from "node:crypto";
610
625
  import {
611
626
  existsSync as existsSync2,
612
627
  mkdirSync,
613
- readFileSync as readFileSync2,
628
+ readFileSync as readFileSync3,
614
629
  renameSync,
615
630
  unlinkSync,
616
631
  writeFileSync
@@ -663,7 +678,7 @@ function readJsonObject(path) {
663
678
  if (!existsSync2(path))
664
679
  return {};
665
680
  try {
666
- const parsed = JSON.parse(readFileSync2(path, "utf8"));
681
+ const parsed = JSON.parse(readFileSync3(path, "utf8"));
667
682
  return isRecord(parsed) ? parsed : {};
668
683
  } catch {
669
684
  return {};
@@ -674,7 +689,7 @@ function readJsonObjectStrict(path) {
674
689
  return {};
675
690
  let parsed;
676
691
  try {
677
- parsed = JSON.parse(readFileSync2(path, "utf8"));
692
+ parsed = JSON.parse(readFileSync3(path, "utf8"));
678
693
  } catch (error) {
679
694
  const message = error instanceof Error ? error.message : String(error);
680
695
  throw new Error(`${path}: ${message}`);
@@ -2827,7 +2842,11 @@ function pi_goosedump_default(pi) {
2827
2842
  createGoosedumpIntegration().register(pi);
2828
2843
  }
2829
2844
  export {
2845
+ resolveNativeGoosedumpBinary,
2846
+ resolveGoosedumpBinaryOverride,
2847
+ resolveGoosedumpBinary,
2830
2848
  parsePiMessages,
2831
2849
  pi_goosedump_default as default,
2832
- createGoosedumpIntegration
2850
+ createGoosedumpIntegration,
2851
+ GOOSEDUMP_BINARY_ENV
2833
2852
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-goosedump",
3
- "version": "0.12.53",
3
+ "version": "0.12.55",
4
4
  "description": "Pi extension for goosedump session search, durable memory, session management, and compaction",
5
5
  "keywords": [
6
6
  "compaction",
@@ -38,7 +38,7 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "@earendil-works/pi-tui": "^0.82.1",
41
- "@jarkkojs/goosedump": "^0.12.53",
41
+ "@jarkkojs/goosedump": "^0.12.55",
42
42
  "@sinclair/typebox": "^0.34.49"
43
43
  },
44
44
  "devDependencies": {