-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathJoyRideContext.ts
More file actions
100 lines (89 loc) · 2.63 KB
/
Copy pathJoyRideContext.ts
File metadata and controls
100 lines (89 loc) · 2.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/**
* [LAYER: CORE]
* Workspace and task fingerprint helpers for JoyRide cache invalidation.
*/
import { createHash } from "node:crypto"
import * as fs from "node:fs"
import * as path from "node:path"
import { getLatestGitCommitHash } from "@/utils/git"
import { createJoyRideFingerprint } from "./keys"
const LOCKFILE_CANDIDATES = [
"package-lock.json",
"pnpm-lock.yaml",
"yarn.lock",
"bun.lockb",
"Cargo.lock",
"go.sum",
"poetry.lock",
]
const DEPENDENCY_MANIFEST_CANDIDATES = ["package.json", "pyproject.toml", "Cargo.toml", "go.mod", "Gemfile", "tsconfig.json"]
export interface JoyRideWorkspaceSnapshot {
workspaceFingerprint: string
gitHead: string
dependencyFingerprint: string
lockfileFingerprint: string
environmentFingerprint: string
changedFileGeneration: number
}
export interface JoyRideTaskScope {
taskId: string
generation: number
approvalBoundaryId: string
cwd: string
terminalMode: string
}
function hashFileStat(fullPath: string): string | undefined {
try {
const stat = fs.statSync(fullPath)
return createHash("sha256").update(`${stat.size}:${stat.mtimeMs}`).digest("hex").slice(0, 16)
} catch {
return undefined
}
}
function fingerprintLockfiles(cwd: string): string {
const parts: Record<string, string> = {}
for (const name of LOCKFILE_CANDIDATES) {
const hash = hashFileStat(path.join(cwd, name))
if (hash) {
parts[name] = hash
}
}
return createJoyRideFingerprint(parts)
}
function fingerprintDependencies(cwd: string): string {
const parts: Record<string, string> = {}
for (const name of DEPENDENCY_MANIFEST_CANDIDATES) {
const hash = hashFileStat(path.join(cwd, name))
if (hash) {
parts[name] = hash
}
}
return createJoyRideFingerprint(parts)
}
export function createEnvironmentFingerprint(cwd: string, terminalMode: string): string {
return createJoyRideFingerprint({
cwd,
terminalMode,
runtimeVersion: process.version,
platform: process.platform,
arch: process.arch,
})
}
export async function buildJoyRideWorkspaceSnapshot(
cwd: string,
terminalMode: string,
changedFileGeneration = 0,
): Promise<JoyRideWorkspaceSnapshot> {
const gitHead = (await getLatestGitCommitHash(cwd)) ?? "no-git"
return {
workspaceFingerprint: createJoyRideFingerprint({ cwd, gitHead, changedFileGeneration }),
gitHead,
dependencyFingerprint: fingerprintDependencies(cwd),
lockfileFingerprint: fingerprintLockfiles(cwd),
environmentFingerprint: createEnvironmentFingerprint(cwd, terminalMode),
changedFileGeneration,
}
}
export function buildApprovalBoundaryId(taskId: string, apiRequestCount: number, suffix = "command"): string {
return `task:${taskId}:${suffix}:${apiRequestCount}`
}