1- import { existsSync , readFileSync , statSync } from "node:fs" ;
1+ import { existsSync , readFileSync , realpathSync , statSync } from "node:fs" ;
22import * as path from "node:path" ;
3+ import { fileURLToPath } from "node:url" ;
34import {
45 type AgentSession ,
56 DefaultPackageManager ,
67 DefaultResourceLoader ,
78 getAgentDir ,
9+ type LoadExtensionsResult ,
810 type PackageSource ,
911 ProjectTrustStore ,
1012 type ResolvedPaths ,
@@ -165,6 +167,158 @@ function packageSourceValue(source: PackageSource) {
165167 return typeof source === "string" ? source : source . source ;
166168}
167169
170+ const CHILD_DISABLED_OPENPI_EXTENSION =
171+ "-extensions/git-info/index.ts" as const ;
172+ const OPENPI_GIT_INFO_EXTENSION_PATH = realpathSync . native (
173+ fileURLToPath ( new URL ( "../git-info/index.ts" , import . meta. url ) ) ,
174+ ) ;
175+
176+ function canonicalExistingPath ( value : string ) {
177+ try {
178+ return realpathSync . native ( value ) ;
179+ } catch {
180+ return undefined ;
181+ }
182+ }
183+
184+ function excludeOpenPiGitInfoExtension (
185+ resources : LoadExtensionsResult ,
186+ ) : LoadExtensionsResult {
187+ return {
188+ ...resources ,
189+ extensions : resources . extensions . filter (
190+ ( extension ) =>
191+ canonicalExistingPath ( extension . resolvedPath ) !==
192+ OPENPI_GIT_INFO_EXTENSION_PATH ,
193+ ) ,
194+ } ;
195+ }
196+
197+ function installedPathNamesOpenPi ( installedPath : string ) {
198+ try {
199+ const stats = statSync ( installedPath ) ;
200+ if ( stats . isDirectory ( ) ) {
201+ const manifestPath = path . join ( installedPath , "package.json" ) ;
202+ if ( ! existsSync ( manifestPath ) ) return false ;
203+ const manifest = JSON . parse (
204+ readFileSync ( manifestPath , "utf8" ) ,
205+ ) as unknown ;
206+ return (
207+ typeof manifest === "object" &&
208+ manifest !== null &&
209+ ! Array . isArray ( manifest ) &&
210+ ( manifest as Record < string , unknown > ) . name === "@tt-a1i/openpi"
211+ ) ;
212+ }
213+ let current = stats . isFile ( ) ? path . dirname ( installedPath ) : undefined ;
214+ while ( current ) {
215+ const manifestPath = path . join ( current , "package.json" ) ;
216+ if ( existsSync ( manifestPath ) ) {
217+ const manifest = JSON . parse (
218+ readFileSync ( manifestPath , "utf8" ) ,
219+ ) as unknown ;
220+ return (
221+ typeof manifest === "object" &&
222+ manifest !== null &&
223+ ! Array . isArray ( manifest ) &&
224+ ( manifest as Record < string , unknown > ) . name === "@tt-a1i/openpi"
225+ ) ;
226+ }
227+ const parent = path . dirname ( current ) ;
228+ if ( parent === current ) return false ;
229+ current = parent ;
230+ }
231+ return false ;
232+ } catch {
233+ return false ;
234+ }
235+ }
236+
237+ function piMatchesPublishedOpenPiSource ( options : {
238+ source : string ;
239+ cwd : string ;
240+ agentDir : string ;
241+ } ) {
242+ const settingsManager = SettingsManager . inMemory ( {
243+ packages : [ options . source ] ,
244+ } ) ;
245+ const packageManager = new DefaultPackageManager ( {
246+ cwd : options . cwd ,
247+ agentDir : options . agentDir ,
248+ settingsManager,
249+ } ) ;
250+ return (
251+ packageManager . removeSourceFromSettings ( "npm:@tt-a1i/openpi" ) ||
252+ packageManager . removeSourceFromSettings (
253+ "git:https://github.com/tt-a1i/openpi" ,
254+ )
255+ ) ;
256+ }
257+
258+ function createOpenPiPackageMatcher ( options : {
259+ cwd : string ;
260+ agentDir : string ;
261+ } ) {
262+ const sourceMatches = new Map < string , boolean > ( ) ;
263+ const installedPathMatches = new Map < string , boolean > ( ) ;
264+ return ( source : string , installedPath ?: string ) => {
265+ let sourceMatch = sourceMatches . get ( source ) ;
266+ if ( sourceMatch === undefined ) {
267+ sourceMatch = piMatchesPublishedOpenPiSource ( { source, ...options } ) ;
268+ sourceMatches . set ( source , sourceMatch ) ;
269+ }
270+ if ( sourceMatch || installedPath === undefined ) return sourceMatch ;
271+
272+ const resolvedPath = path . resolve ( installedPath ) ;
273+ let installedPathMatch = installedPathMatches . get ( resolvedPath ) ;
274+ if ( installedPathMatch === undefined ) {
275+ installedPathMatch = installedPathNamesOpenPi ( resolvedPath ) ;
276+ installedPathMatches . set ( resolvedPath , installedPathMatch ) ;
277+ }
278+ return installedPathMatch ;
279+ } ;
280+ }
281+
282+ function openPiPackageSources (
283+ packageManager : DefaultPackageManager ,
284+ options : { cwd : string ; agentDir : string } ,
285+ ) {
286+ const isOpenPiPackage = createOpenPiPackageMatcher ( options ) ;
287+ const sources = {
288+ user : new Set < string > ( ) ,
289+ project : new Set < string > ( ) ,
290+ } ;
291+ for ( const configured of packageManager . listConfiguredPackages ( ) ) {
292+ if ( isOpenPiPackage ( configured . source , configured . installedPath ) ) {
293+ sources [ configured . scope ] . add ( configured . source ) ;
294+ }
295+ }
296+ return sources ;
297+ }
298+
299+ function disablesOpenPiGitInfo ( pattern : string ) {
300+ return (
301+ pattern . startsWith ( "-" ) &&
302+ pattern . slice ( 1 ) . replace ( / ^ \. \/ / , "" ) ===
303+ CHILD_DISABLED_OPENPI_EXTENSION . slice ( 1 )
304+ ) ;
305+ }
306+
307+ function disableOpenPiGitInfo ( source : PackageSource ) : PackageSource {
308+ if ( typeof source !== "string" ) {
309+ if ( source . extensions ?. length === 0 ) return source ;
310+ if ( source . autoload === false && source . extensions === undefined ) {
311+ return source ;
312+ }
313+ }
314+ const configured = typeof source === "string" ? { source } : source ;
315+ const extensions = [ ...( configured . extensions ?? [ ] ) ] ;
316+ if ( ! extensions . some ( disablesOpenPiGitInfo ) ) {
317+ extensions . push ( CHILD_DISABLED_OPENPI_EXTENSION ) ;
318+ }
319+ return { ...configured , extensions } ;
320+ }
321+
168322function blockedPackageSources (
169323 packageManager : DefaultPackageManager ,
170324 resolvedPaths : ResolvedPaths ,
@@ -204,6 +358,7 @@ function blockedPackageSources(
204358function createEphemeralChildSettings (
205359 sourceSettings : SettingsManager ,
206360 blockedSources : { user : Set < string > ; project : Set < string > } ,
361+ openPiSources : { user : Set < string > ; project : Set < string > } ,
207362 projectTrusted : boolean ,
208363) {
209364 const globalSettings = sourceSettings . getGlobalSettings ( ) ;
@@ -213,9 +368,15 @@ function createEphemeralChildSettings(
213368 scope : "user" | "project" ,
214369 ) => ( {
215370 ...settings ,
216- packages : settings . packages ?. filter (
217- ( source ) => ! blockedSources [ scope ] . has ( packageSourceValue ( source ) ) ,
218- ) ,
371+ packages : settings . packages
372+ ?. filter (
373+ ( source ) => ! blockedSources [ scope ] . has ( packageSourceValue ( source ) ) ,
374+ )
375+ . map ( ( source ) =>
376+ openPiSources [ scope ] . has ( packageSourceValue ( source ) )
377+ ? disableOpenPiGitInfo ( source )
378+ : source ,
379+ ) ,
219380 } ) ;
220381 const contents = {
221382 global : JSON . stringify ( settingsForScope ( globalSettings , "user" ) ) ,
@@ -248,10 +409,15 @@ async function createChildSettingsManager(options: {
248409 cwd : options . cwd ,
249410 agentDir : options . agentDir ,
250411 } ) ;
412+ const openPiSources = openPiPackageSources ( packageManager , {
413+ cwd : options . cwd ,
414+ agentDir : options . agentDir ,
415+ } ) ;
251416
252417 return createEphemeralChildSettings (
253418 sourceSettings ,
254419 blockedSources ,
420+ openPiSources ,
255421 options . projectTrusted ,
256422 ) ;
257423}
@@ -348,6 +514,7 @@ export async function createChildResources(options: ChildResourceOptions) {
348514 cwd : options . cwd ,
349515 agentDir,
350516 settingsManager,
517+ extensionsOverride : excludeOpenPiGitInfoExtension ,
351518 ...( options . appendSystemPrompt
352519 ? { appendSystemPrompt : options . appendSystemPrompt }
353520 : { } ) ,
0 commit comments