fix(agents): recognize Pi bundled npm entrypoint

Carry the focused patch from boris-papevis/orca PR #25040 onto current main, with independent npm runtime and regression verification.
This commit is contained in:
Borys Papevis
2026-10-04 14:46:24 -07:00
committed by Neil
parent b1e12d7bb4
commit ca774091d7
3 changed files with 89 additions and 59 deletions
@@ -33,60 +33,64 @@ describe('Pi Windows foreground recognition', () => {
}
})
it('recognizes the npm entrypoint within the active ConPTY', async () => {
const rows = [
{
pid: 100,
ppid: 99,
name: 'bash.exe',
commandLine: '"C:\\Program Files\\Git\\usr\\bin\\bash.exe"'
},
{
pid: 101,
ppid: 100,
name: 'node.exe',
commandLine:
'node.exe C:\\Users\\dev\\AppData\\Roaming\\npm\\node_modules\\@earendil-works\\pi-coding-agent\\dist\\cli.js'
}
]
getAllProcessesMock.mockImplementation((cb: (snapshot: unknown) => void) => {
cb(withSelf(rows))
})
const readWindowsConsoleAttachedProcessIds = vi.fn(async () => new Set([100, 101]))
await expect(
resolveAgentForegroundProcessWithAvailability(100, 'node.exe', {
fresh: true,
readWindowsConsoleAttachedProcessIds
it.each(['cli.js', String.raw`bundle\cli.js`])(
'recognizes the npm entrypoint dist/%s within the active ConPTY',
async (entrypoint) => {
const rows = [
{
pid: 100,
ppid: 99,
name: 'bash.exe',
commandLine: '"C:\\Program Files\\Git\\usr\\bin\\bash.exe"'
},
{
pid: 101,
ppid: 100,
name: 'node.exe',
commandLine: `node.exe C:\\Users\\dev\\AppData\\Roaming\\npm\\node_modules\\@earendil-works\\pi-coding-agent\\dist\\${entrypoint}`
}
]
getAllProcessesMock.mockImplementation((cb: (snapshot: unknown) => void) => {
cb(withSelf(rows))
})
).resolves.toEqual({ available: true, processName: 'pi', processId: 101 })
expect(readWindowsConsoleAttachedProcessIds).toHaveBeenCalledTimes(1)
})
const readWindowsConsoleAttachedProcessIds = vi.fn(async () => new Set([100, 101]))
it('anchors a collapsed omp name to the omp pid, not the embedded pi leaf', async () => {
// Pi restarts under a live OMP; an anchor on pi's pid would read that as
// OMP's exit and fire a false "agent done" when the next snapshot degrades.
const rows = [
{ pid: 100, ppid: 99, name: 'powershell.exe', commandLine: 'powershell.exe' },
{ pid: 101, ppid: 100, name: 'omp.exe', commandLine: 'omp' },
{
pid: 102,
ppid: 101,
name: 'node.exe',
commandLine:
'node.exe C:\\npm\\node_modules\\@earendil-works\\pi-coding-agent\\dist\\cli.js'
}
]
getAllProcessesMock.mockImplementation((cb: (snapshot: unknown) => void) => {
cb(withSelf(rows))
})
const readWindowsConsoleAttachedProcessIds = vi.fn(async () => new Set([100, 101, 102]))
await expect(
resolveAgentForegroundProcessWithAvailability(100, 'node.exe', {
fresh: true,
readWindowsConsoleAttachedProcessIds
})
).resolves.toEqual({ available: true, processName: 'pi', processId: 101 })
expect(readWindowsConsoleAttachedProcessIds).toHaveBeenCalledTimes(1)
}
)
await expect(
resolveAgentForegroundProcessWithAvailability(100, 'powershell.exe', {
fresh: true,
readWindowsConsoleAttachedProcessIds
it.each(['cli.js', String.raw`bundle\cli.js`])(
'anchors a collapsed omp name to the omp pid, not the embedded pi leaf at dist/%s',
async (entrypoint) => {
// Pi restarts under a live OMP; an anchor on pi's pid would read that as
// OMP's exit and fire a false "agent done" when the next snapshot degrades.
const rows = [
{ pid: 100, ppid: 99, name: 'powershell.exe', commandLine: 'powershell.exe' },
{ pid: 101, ppid: 100, name: 'omp.exe', commandLine: 'omp' },
{
pid: 102,
ppid: 101,
name: 'node.exe',
commandLine: `node.exe C:\\npm\\node_modules\\@earendil-works\\pi-coding-agent\\dist\\${entrypoint}`
}
]
getAllProcessesMock.mockImplementation((cb: (snapshot: unknown) => void) => {
cb(withSelf(rows))
})
).resolves.toEqual({ available: true, processName: 'omp', processId: 101 })
})
const readWindowsConsoleAttachedProcessIds = vi.fn(async () => new Set([100, 101, 102]))
await expect(
resolveAgentForegroundProcessWithAvailability(100, 'powershell.exe', {
fresh: true,
readWindowsConsoleAttachedProcessIds
})
).resolves.toEqual({ available: true, processName: 'omp', processId: 101 })
}
)
})
@@ -17,7 +17,7 @@ export const EXACT_NODE_ENTRYPOINT_IDENTITIES: readonly {
// Why: Pi's npm shim launches a generic cli.js; only the exact package path is authoritative.
{
pattern:
/(?:^|\/)node_modules\/@(?:earendil-works|mariozechner)\/pi-coding-agent\/dist\/cli\.js$/,
/(?:^|\/)node_modules\/@(?:earendil-works|mariozechner)\/pi-coding-agent\/dist\/(?:bundle\/)?cli\.js$/,
agent: 'pi',
processName: 'pi'
},
+32 -6
View File
@@ -405,12 +405,38 @@ describe('agent process recognition', () => {
).toEqual({ agent: 'gemini', processName: 'gemini' })
})
it.each(['earendil-works', 'mariozechner'])('recognizes the @%s Pi npm entrypoint', (scope) => {
expect(
recognizeAgentProcessFromCommandLine(
String.raw`node.exe C:\Users\dev\AppData\Roaming\npm\node_modules\@${scope}\pi-coding-agent\dist\cli.js`
)
).toEqual({ agent: 'pi', processName: 'pi' })
it.each([
['earendil-works', 'cli.js'],
['earendil-works', 'bundle/cli.js'],
['mariozechner', 'cli.js'],
['mariozechner', 'bundle/cli.js']
])('recognizes the @%s Pi npm entrypoint at dist/%s', (scope, entrypoint) => {
const windowsEntrypoint = entrypoint.replace('/', '\\')
const windowsPath = `C:\\Users\\Dev User\\AppData\\Roaming\\npm\\node_modules\\@${scope}\\pi-coding-agent\\dist\\${windowsEntrypoint}`
for (const command of [
`node /usr/local/lib/node_modules/@${scope}/pi-coding-agent/dist/${entrypoint}`,
`node.exe ${windowsPath.replace('Dev User', 'dev')}`,
String.raw`"C:\Program Files\nodejs\node.exe" "${windowsPath}"`
]) {
expect(recognizeAgentProcessFromCommandLine(command)).toEqual({
agent: 'pi',
processName: 'pi'
})
}
})
it.each([
'node /tmp/dist/bundle/cli.js',
'node /tmp/node_modules/@other/pi-coding-agent/dist/bundle/cli.js',
'node /tmp/node_modules/@earendil-works/not-pi-coding-agent/dist/bundle/cli.js',
'node /tmp/notnode_modules/@earendil-works/pi-coding-agent/dist/bundle/cli.js',
'node /tmp/node_modules/@earendil-works/pi-coding-agent/dist/bundle/cli.js.extra',
'node /tmp/node_modules/@earendil-works/pi-coding-agent/dist/bundle/nested/cli.js',
'node /tmp/server.js /tmp/node_modules/@earendil-works/pi-coding-agent/dist/bundle/cli.js',
'node --require /tmp/node_modules/@earendil-works/pi-coding-agent/dist/bundle/cli.js /tmp/server.js',
'node --eval "console.log(1)" /tmp/node_modules/@earendil-works/pi-coding-agent/dist/bundle/cli.js'
])('does not recognize a Pi entrypoint lookalike or argument: %s', (command) => {
expect(recognizeAgentProcessFromCommandLine(command)).toBeNull()
})
it('recognizes Prime Agent by its binary and npm entrypoint', () => {