@ai-sdk/harness-pi 1.0.101 → 1.0.103

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/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @ai-sdk/harness-pi
2
2
 
3
+ ## 1.0.103
4
+
5
+ ### Patch Changes
6
+
7
+ - 951c54d: feat(harness): support `askUserQuestions` tool including support for normalization across harness adapters
8
+ - Updated dependencies [951c54d]
9
+ - @ai-sdk/harness@1.0.101
10
+
11
+ ## 1.0.102
12
+
13
+ ### Patch Changes
14
+
15
+ - 7c3211d: fix (harness-pi): transfer the workspace mirror as batched archives instead of one request per file
16
+ - Updated dependencies [0c37bf0]
17
+ - @ai-sdk/harness@1.0.100
18
+
3
19
  ## 1.0.101
4
20
 
5
21
  ### Patch Changes
package/dist/index.js CHANGED
@@ -134,7 +134,7 @@ import {
134
134
  import { access } from "fs/promises";
135
135
 
136
136
  // src/version.ts
137
- var VERSION = true ? "1.0.101" : "0.0.0-test";
137
+ var VERSION = true ? "1.0.103" : "0.0.0-test";
138
138
 
139
139
  // src/pi-auth.ts
140
140
  var DEFAULT_GATEWAY_BASE_URL = "https://ai-gateway.vercel.sh";
@@ -1662,9 +1662,12 @@ import {
1662
1662
  writeFile as writeFile2
1663
1663
  } from "fs/promises";
1664
1664
  import path6 from "path";
1665
+ import { gunzipSync } from "zlib";
1665
1666
  import { shellQuote as shellQuote2 } from "@ai-sdk/harness/utils";
1666
1667
  var PI_CONFIG_DIRS = [".pi", ".agents"];
1667
1668
  var PI_CONTEXT_FILENAMES = ["AGENTS.md", "AGENTS.MD"];
1669
+ var ARCHIVE_BATCH_SIZE = 300;
1670
+ var TAR_BLOCK_SIZE = 512;
1668
1671
  function normalizeRelativePath(inputPath) {
1669
1672
  const normalized = inputPath.split(path6.posix.sep).join(path6.sep);
1670
1673
  const relative = path6.normalize(normalized);
@@ -1802,6 +1805,74 @@ async function listRemoteWorkspaceEntries(sandbox, sandboxWorkDir) {
1802
1805
  }
1803
1806
  return { directories, files };
1804
1807
  }
1808
+ function readTarString(header, offset, length) {
1809
+ const field = header.subarray(offset, offset + length);
1810
+ const end = field.indexOf(0);
1811
+ return field.subarray(0, end === -1 ? field.length : end).toString("utf8");
1812
+ }
1813
+ function parseTarFiles(archive) {
1814
+ const files = /* @__PURE__ */ new Map();
1815
+ let overrideName;
1816
+ let offset = 0;
1817
+ while (offset + TAR_BLOCK_SIZE <= archive.length) {
1818
+ const header = archive.subarray(offset, offset + TAR_BLOCK_SIZE);
1819
+ if (header.every((byte) => byte === 0)) break;
1820
+ const size = Number.parseInt(
1821
+ readTarString(header, 124, 12).trim() || "0",
1822
+ 8
1823
+ );
1824
+ const typeFlag = String.fromCharCode(header[156]);
1825
+ const dataStart = offset + TAR_BLOCK_SIZE;
1826
+ const data = archive.subarray(dataStart, dataStart + size);
1827
+ offset = dataStart + Math.ceil(size / TAR_BLOCK_SIZE) * TAR_BLOCK_SIZE;
1828
+ if (typeFlag === "L") {
1829
+ overrideName = readTarString(data, 0, data.length);
1830
+ continue;
1831
+ }
1832
+ if (typeFlag === "x" || typeFlag === "X") {
1833
+ const pathRecord = data.toString("utf8").split("\n").map((record) => /^\d+ path=(.*)$/.exec(record)?.[1]).find((value) => value != null);
1834
+ if (pathRecord != null) overrideName = pathRecord;
1835
+ continue;
1836
+ }
1837
+ if (typeFlag === "0" || typeFlag === "\0") {
1838
+ const name = readTarString(header, 0, 100);
1839
+ const prefix = readTarString(header, 345, 155);
1840
+ files.set(
1841
+ overrideName ?? (prefix === "" ? name : `${prefix}/${name}`),
1842
+ Buffer.from(data)
1843
+ );
1844
+ }
1845
+ overrideName = void 0;
1846
+ }
1847
+ return files;
1848
+ }
1849
+ async function readSandboxFilesAsArchive(sandbox, sandboxPaths) {
1850
+ const members = sandboxPaths.map(
1851
+ (sandboxPath) => sandboxPath.replace(/^\/+/, "")
1852
+ );
1853
+ const command = `tar -C / -czf - -- ${members.map(shellQuote2).join(" ")} 2>/dev/null | base64`;
1854
+ let encoded;
1855
+ try {
1856
+ encoded = (await readCommandOutput(sandbox, command)).replace(/\s+/g, "");
1857
+ } catch {
1858
+ return /* @__PURE__ */ new Map();
1859
+ }
1860
+ if (encoded === "") return /* @__PURE__ */ new Map();
1861
+ let entries;
1862
+ try {
1863
+ entries = parseTarFiles(gunzipSync(Buffer.from(encoded, "base64")));
1864
+ } catch {
1865
+ return /* @__PURE__ */ new Map();
1866
+ }
1867
+ const contents = /* @__PURE__ */ new Map();
1868
+ for (const [index, member] of members.entries()) {
1869
+ const content = entries.get(member);
1870
+ if (content != null) {
1871
+ contents.set(sandboxPaths[index], content);
1872
+ }
1873
+ }
1874
+ return contents;
1875
+ }
1805
1876
  async function pathKind(target) {
1806
1877
  try {
1807
1878
  const stats = await stat(target);
@@ -1888,25 +1959,38 @@ async function syncHostWorkspaceFromSandbox(args) {
1888
1959
  )) {
1889
1960
  await mkdir2(path6.join(hostWorkDir, relativePath), { recursive: true });
1890
1961
  }
1891
- for (const { relativePath, sandboxPath } of remoteEntries.files) {
1892
- const bytes = await sandbox.readBinaryFile({ path: sandboxPath });
1893
- if (!bytes) {
1894
- throw new Error(
1895
- `Sandbox workspace file disappeared during mirror sync: ${sandboxPath}`
1896
- );
1897
- }
1898
- const content = Buffer.from(bytes);
1899
- const hostPath = path6.join(hostWorkDir, relativePath);
1900
- let shouldWrite = true;
1901
- try {
1902
- const existing = await readFile2(hostPath);
1903
- shouldWrite = !existing.equals(content);
1904
- } catch {
1905
- shouldWrite = true;
1906
- }
1907
- if (shouldWrite) {
1908
- await mkdir2(path6.dirname(hostPath), { recursive: true });
1909
- await writeFile2(hostPath, content);
1962
+ for (let offset = 0; offset < remoteEntries.files.length; offset += ARCHIVE_BATCH_SIZE) {
1963
+ const batch = remoteEntries.files.slice(
1964
+ offset,
1965
+ offset + ARCHIVE_BATCH_SIZE
1966
+ );
1967
+ const archived = await readSandboxFilesAsArchive(
1968
+ sandbox,
1969
+ batch.map((file) => file.sandboxPath)
1970
+ );
1971
+ for (const { relativePath, sandboxPath } of batch) {
1972
+ let content = archived.get(sandboxPath);
1973
+ if (content == null) {
1974
+ const bytes = await sandbox.readBinaryFile({ path: sandboxPath });
1975
+ if (!bytes) {
1976
+ throw new Error(
1977
+ `Sandbox workspace file disappeared during mirror sync: ${sandboxPath}`
1978
+ );
1979
+ }
1980
+ content = Buffer.from(bytes);
1981
+ }
1982
+ const hostPath = path6.join(hostWorkDir, relativePath);
1983
+ let shouldWrite = true;
1984
+ try {
1985
+ const existing = await readFile2(hostPath);
1986
+ shouldWrite = !existing.equals(content);
1987
+ } catch {
1988
+ shouldWrite = true;
1989
+ }
1990
+ if (shouldWrite) {
1991
+ await mkdir2(path6.dirname(hostPath), { recursive: true });
1992
+ await writeFile2(hostPath, content);
1993
+ }
1910
1994
  }
1911
1995
  }
1912
1996
  }