pi-ultracode 0.3.2 → 0.5.0

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.
@@ -0,0 +1,76 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import * as fs from "node:fs";
3
+ import * as path from "node:path";
4
+ import { hermeticGitEnvironment, stripOneLineEnding } from "./hermetic-git.ts";
5
+
6
+ const MAX_GIT_PATH_BYTES = 1024 * 1024;
7
+
8
+ export interface RepositoryContext {
9
+ identity: string;
10
+ cwd: string;
11
+ repoRoot?: string;
12
+ relativeCwd?: string;
13
+ gitDir?: string;
14
+ gitCommonDir?: string;
15
+ }
16
+
17
+ /** Resolve the immutable working-tree target used by resume and delivery. */
18
+ export function resolveRepositoryContext(cwd: string): RepositoryContext {
19
+ const realCwd = fs.realpathSync(cwd);
20
+ if (gitLine(realCwd, ["rev-parse", "--is-inside-work-tree"], true) !== "true") {
21
+ const identity = JSON.stringify({
22
+ kind: "directory",
23
+ cwd: realCwd,
24
+ cwdFile: fileIdentity(realCwd),
25
+ });
26
+ return { identity, cwd: realCwd };
27
+ }
28
+
29
+ const repoRoot = fs.realpathSync(gitLine(realCwd, ["rev-parse", "--show-toplevel"]));
30
+ const gitDir = fs.realpathSync(gitLine(realCwd, ["rev-parse", "--path-format=absolute", "--git-dir"]));
31
+ const gitCommonDir = fs.realpathSync(
32
+ gitLine(realCwd, ["rev-parse", "--path-format=absolute", "--git-common-dir"]),
33
+ );
34
+ const relativeCwd = path.relative(repoRoot, realCwd);
35
+ if (relativeCwd.startsWith("..") || path.isAbsolute(relativeCwd)) {
36
+ throw new Error("workflow cwd must remain inside its Git working tree");
37
+ }
38
+ const repositoryRootCommit = gitLine(realCwd, ["rev-list", "--max-parents=0", "HEAD"], true);
39
+ const identity = JSON.stringify({
40
+ kind: "git-worktree",
41
+ repoRoot,
42
+ repoRootFile: fileIdentity(repoRoot),
43
+ cwdFile: fileIdentity(realCwd),
44
+ gitDir,
45
+ gitDirFile: fileIdentity(gitDir),
46
+ gitCommonDir,
47
+ gitCommonDirFile: fileIdentity(gitCommonDir),
48
+ repositoryRootCommit,
49
+ relativeCwd,
50
+ });
51
+ return { identity, cwd: realCwd, repoRoot, relativeCwd, gitDir, gitCommonDir };
52
+ }
53
+
54
+ /** Read one Git plumbing line without stripping valid path whitespace. */
55
+ function gitLine(cwd: string, args: string[], optional = false): string {
56
+ try {
57
+ const output = execFileSync("git", args, {
58
+ cwd,
59
+ encoding: "utf8",
60
+ stdio: ["ignore", "pipe", "pipe"],
61
+ env: hermeticGitEnvironment(),
62
+ maxBuffer: MAX_GIT_PATH_BYTES,
63
+ timeout: 25_000,
64
+ killSignal: "SIGKILL",
65
+ });
66
+ return stripOneLineEnding(output);
67
+ } catch (error) {
68
+ if (optional) return "";
69
+ throw error;
70
+ }
71
+ }
72
+
73
+ function fileIdentity(filePath: string): { dev: number; ino: number; birthtimeMs: number } {
74
+ const stat = fs.statSync(filePath);
75
+ return { dev: stat.dev, ino: stat.ino, birthtimeMs: stat.birthtimeMs };
76
+ }
@@ -16,21 +16,30 @@ export function ensurePrivateArtifactDirectory(dir: string, trustedRoot?: string
16
16
  ensureContainedDirectory(trustedRoot, dir);
17
17
  return;
18
18
  }
19
- let created = false;
20
- try {
21
- fs.lstatSync(dir);
22
- } catch (error: any) {
23
- if (error?.code !== "ENOENT") throw error;
24
- fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
25
- created = true;
19
+ const target = path.resolve(dir);
20
+ const missing: string[] = [];
21
+ let current = target;
22
+ while (true) {
23
+ try {
24
+ assertRealDirectory(current);
25
+ break;
26
+ } catch (error: any) {
27
+ if (error?.code !== "ENOENT") throw error;
28
+ missing.push(current);
29
+ const parent = path.dirname(current);
30
+ if (parent === current) throw error;
31
+ current = parent;
32
+ }
26
33
  }
27
- assertRealDirectory(dir);
28
- if (process.platform !== "win32") fs.chmodSync(dir, 0o700);
29
- if (created) {
30
- fsyncArtifactDirectory(dir);
31
- const parent = path.dirname(dir);
32
- if (parent !== dir) fsyncArtifactDirectory(parent);
34
+ for (const directory of missing.reverse()) {
35
+ fs.mkdirSync(directory, { mode: 0o700 });
36
+ assertRealDirectory(directory);
37
+ if (process.platform !== "win32") fs.chmodSync(directory, 0o700);
38
+ fsyncArtifactDirectory(directory);
39
+ fsyncArtifactDirectory(path.dirname(directory));
33
40
  }
41
+ assertRealDirectory(target);
42
+ if (process.platform !== "win32") fs.chmodSync(target, 0o700);
34
43
  }
35
44
 
36
45
  function ensureContainedDirectory(trustedRoot: string, dir: string): void {
@@ -112,6 +121,10 @@ export function readContainedArtifactFile(
112
121
  maxBytes = 16 * 1024 * 1024,
113
122
  ): string {
114
123
  const root = path.resolve(trustedRoot);
124
+ const rootStat = fs.lstatSync(root);
125
+ if (rootStat.isSymbolicLink() || !rootStat.isDirectory()) {
126
+ throw new Error(`${label} trusted root must be a real directory: ${root}`);
127
+ }
115
128
  const target = path.resolve(filePath);
116
129
  const relative = path.relative(root, target);
117
130
  if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) {
@@ -130,7 +143,40 @@ export function readContainedArtifactFile(
130
143
  return readArtifactFile(target, label, maxBytes);
131
144
  }
132
145
 
146
+ export function readContainedArtifactBytes(
147
+ trustedRoot: string,
148
+ filePath: string,
149
+ label: string,
150
+ maxBytes = 16 * 1024 * 1024,
151
+ ): Buffer {
152
+ const root = path.resolve(trustedRoot);
153
+ const rootStat = fs.lstatSync(root);
154
+ if (rootStat.isSymbolicLink() || !rootStat.isDirectory()) {
155
+ throw new Error(`${label} trusted root must be a real directory: ${root}`);
156
+ }
157
+ const target = path.resolve(filePath);
158
+ const relative = path.relative(root, target);
159
+ if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) {
160
+ throw new Error(`${label} must stay inside ${root}`);
161
+ }
162
+ let current = root;
163
+ const parts = relative.split(path.sep);
164
+ for (const [index, part] of parts.entries()) {
165
+ current = path.join(current, part);
166
+ const stat = fs.lstatSync(current);
167
+ if (stat.isSymbolicLink()) throw new Error(`${label} path may not contain symlinks: ${current}`);
168
+ if (index < parts.length - 1 && !stat.isDirectory()) {
169
+ throw new Error(`${label} parent must be a directory: ${current}`);
170
+ }
171
+ }
172
+ return readArtifactBytes(target, label, maxBytes);
173
+ }
174
+
133
175
  export function readArtifactFile(filePath: string, label: string, maxBytes = 16 * 1024 * 1024): string {
176
+ return readArtifactBytes(filePath, label, maxBytes).toString("utf8");
177
+ }
178
+
179
+ export function readArtifactBytes(filePath: string, label: string, maxBytes = 16 * 1024 * 1024): Buffer {
134
180
  assertRegularArtifactFile(filePath, label);
135
181
  const fd = fs.openSync(filePath, fs.constants.O_RDONLY | NO_FOLLOW);
136
182
  try {
@@ -147,7 +193,7 @@ export function readArtifactFile(filePath: string, label: string, maxBytes = 16
147
193
  total += bytesRead;
148
194
  }
149
195
  if (total > maxBytes) throw new Error(`${label} exceeds ${maxBytes} bytes: ${filePath}`);
150
- return Buffer.concat(chunks, total).toString("utf8");
196
+ return Buffer.concat(chunks, total);
151
197
  } finally {
152
198
  fs.closeSync(fd);
153
199
  }