@everydaydevopsio/pilot 0.6.1 → 0.6.3
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/AGENTS.md +6 -0
- package/CHANGELOG.md +45 -0
- package/README.md +86 -9
- package/dist/browser/browser-manager.d.ts +7 -1
- package/dist/browser/browser-manager.d.ts.map +1 -1
- package/dist/browser/browser-manager.js +196 -40
- package/dist/browser/browser-manager.js.map +1 -1
- package/dist/browser/chrome-launcher.d.ts +13 -2
- package/dist/browser/chrome-launcher.d.ts.map +1 -1
- package/dist/browser/chrome-launcher.js +33 -4
- package/dist/browser/chrome-launcher.js.map +1 -1
- package/dist/browser/sessions.d.ts +49 -0
- package/dist/browser/sessions.d.ts.map +1 -0
- package/dist/browser/sessions.js +249 -0
- package/dist/browser/sessions.js.map +1 -0
- package/dist/browser/types.d.ts +10 -0
- package/dist/browser/types.d.ts.map +1 -1
- package/dist/cli/skill-template.d.ts +1 -1
- package/dist/cli/skill-template.d.ts.map +1 -1
- package/dist/cli/skill-template.js +1 -1
- package/dist/cli/skill-template.js.map +1 -1
- package/dist/mcp/tools/browser.d.ts.map +1 -1
- package/dist/mcp/tools/browser.js +52 -3
- package/dist/mcp/tools/browser.js.map +1 -1
- package/dist/mcp/tools/names.d.ts +1 -1
- package/dist/mcp/tools/names.d.ts.map +1 -1
- package/dist/mcp/tools/names.js +2 -0
- package/dist/mcp/tools/names.js.map +1 -1
- package/package.json +1 -1
- package/skills/pilot/SKILL.md +9 -0
- package/src/browser/browser-manager.ts +248 -41
- package/src/browser/chrome-launcher.ts +40 -4
- package/src/browser/sessions.ts +299 -0
- package/src/browser/types.ts +11 -0
- package/src/cli/skill-template.ts +1 -1
- package/src/mcp/tools/browser.ts +72 -3
- package/src/mcp/tools/names.ts +2 -0
|
@@ -166,9 +166,17 @@ export function formatPortBindError(error) {
|
|
|
166
166
|
}
|
|
167
167
|
return error;
|
|
168
168
|
}
|
|
169
|
-
|
|
169
|
+
// Cold starts on Linux servers (first-run profile setup, software rendering
|
|
170
|
+
// under Xvfb/VNC) can take well over 30s. A healthy start returns as soon as
|
|
171
|
+
// DevTools answers, and a Chrome that exits is detected immediately, so the
|
|
172
|
+
// longer ceiling only matters when Chrome is genuinely slow.
|
|
173
|
+
export const DEFAULT_STARTUP_TIMEOUT_MS = 90000;
|
|
174
|
+
export async function waitForChromeReady(port, timeoutMs = DEFAULT_STARTUP_TIMEOUT_MS, earlyFailure) {
|
|
170
175
|
const deadline = Date.now() + timeoutMs;
|
|
171
176
|
while (Date.now() < deadline) {
|
|
177
|
+
const failure = earlyFailure?.();
|
|
178
|
+
if (failure)
|
|
179
|
+
throw failure;
|
|
172
180
|
try {
|
|
173
181
|
await CDP.List({ host: '127.0.0.1', port });
|
|
174
182
|
return;
|
|
@@ -177,6 +185,9 @@ export async function waitForChromeReady(port, timeoutMs = 30000) {
|
|
|
177
185
|
await new Promise((r) => setTimeout(r, 200));
|
|
178
186
|
}
|
|
179
187
|
}
|
|
188
|
+
const failure = earlyFailure?.();
|
|
189
|
+
if (failure)
|
|
190
|
+
throw failure;
|
|
180
191
|
throw new Error(`Chrome did not become ready on port ${port} within ${timeoutMs}ms`);
|
|
181
192
|
}
|
|
182
193
|
export function launchChrome(opts) {
|
|
@@ -212,14 +223,32 @@ export function launchChrome(opts) {
|
|
|
212
223
|
detached: false
|
|
213
224
|
});
|
|
214
225
|
}
|
|
215
|
-
export function
|
|
226
|
+
export function profileLockOwner(userDataDir) {
|
|
227
|
+
return extractLockPid(join(userDataDir, 'SingletonLock'));
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Remove the profile lock files left by a Chrome process Pilot launched.
|
|
231
|
+
* A SingletonLock that names a different process is left alone: if Chrome
|
|
232
|
+
* handed off to another instance already using the profile, that lock
|
|
233
|
+
* belongs to the live browser. Returns false when a lock was left in place.
|
|
234
|
+
*/
|
|
235
|
+
export function cleanupLockFiles(userDataDir, ownerPid) {
|
|
236
|
+
const owner = profileLockOwner(userDataDir);
|
|
237
|
+
if (fileOrSymlinkExists(join(userDataDir, 'SingletonLock')) &&
|
|
238
|
+
(!owner || owner.pid !== ownerPid || owner.lockHost !== hostname())) {
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
let removed = true;
|
|
216
242
|
for (const lockName of ['SingletonLock', 'lockfile']) {
|
|
217
243
|
try {
|
|
218
244
|
unlinkSync(join(userDataDir, lockName));
|
|
219
245
|
}
|
|
220
|
-
catch {
|
|
221
|
-
// lock file
|
|
246
|
+
catch (err) {
|
|
247
|
+
// A lock file that does not exist is already gone.
|
|
248
|
+
if (err.code !== 'ENOENT')
|
|
249
|
+
removed = false;
|
|
222
250
|
}
|
|
223
251
|
}
|
|
252
|
+
return removed;
|
|
224
253
|
}
|
|
225
254
|
//# sourceMappingURL=chrome-launcher.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chrome-launcher.js","sourceRoot":"","sources":["../../src/browser/chrome-launcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAqB,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AACrE,OAAO,KAAK,GAAG,MAAM,KAAK,CAAC;AAC3B,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,GAAG,MAAM,yBAAyB,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAG9C,MAAM,CAAC,MAAM,eAAe,GAAG,6BAA6B,CAAC;AAE7D,MAAM,UAAU,eAAe;IAC7B,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC;IACxD,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,WAAW,KAAK,MAAM,IAAI,WAAW,KAAK,GAAG,CAAC;QAC7D,OAAO,MAAM;YACX,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE;YAC3C,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IACzB,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC5B,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,EAAE,EAAE,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;IAChD,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,oBAAoB;IAClC,OAAO,eAAe,EAAE,CAAC,OAAO,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,WAAmB;IACpD,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CACb,yBAAyB,WAAW,wDAAwD,CAC7F,CAAC;IACJ,CAAC;IACD,MAAM,OAAO,GACX,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IAClE,OAAO,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,mBAAmB,CAAC,QAAgB;IAC3C,IAAI,CAAC;QACH,SAAS,CAAC,QAAQ,CAAC,CAAC;QACpB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,IAAI,GAAI,GAA6B,EAAE,IAAI,CAAC;QAClD,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YAC5C,OAAO,KAAK,CAAC;QACf,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,QAAgB;IAEhB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;QACjC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE;YAAE,OAAO,IAAI,CAAC;QACxC,MAAM,MAAM,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;QACtC,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACzC,IAAI,QAAQ,KAAK,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QACjC,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;QAC3C,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACrD,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QACxC,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,IAAI,GAAG,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAC3B,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,IAAI,GAAI,GAA6B,EAAE,IAAI,CAAC;QAClD,OAAO,IAAI,KAAK,OAAO,CAAC;IAC1B,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,WAAmB;IAC3C,KAAK,MAAM,QAAQ,IAAI,CAAC,eAAe,EAAE,UAAU,CAAC,EAAE,CAAC;QACrD,IAAI,CAAC;YACH,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,IAAI,GAAI,GAA6B,EAAE,IAAI,CAAC;YAClD,IAAI,IAAI,KAAK,QAAQ;gBAAE,MAAM,GAAG,CAAC;QACnC,CAAC;IACH,CAAC;IACD,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,CAAC,IAAI,CACT,EAAE,WAAW,EAAE,EACf,0DAA0D,CAC3D,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,WAAmB;IACjD,MAAM,aAAa,GAAG,IAAI,CAAC,WAAW,EAAE,eAAe,CAAC,CAAC;IACzD,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IAEnD,MAAM,YAAY,GAAG,mBAAmB,CAAC,aAAa,CAAC,CAAC;IACxD,MAAM,WAAW,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC;IAE7C,IAAI,CAAC,YAAY,IAAI,CAAC,WAAW;QAAE,OAAO,KAAK,CAAC;IAEhD,MAAM,QAAQ,GAAG,YAAY,CAAC,CAAC,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAErE,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,WAAW,GAAG,QAAQ,EAAE,CAAC;IAC/B,IAAI,QAAQ,CAAC,QAAQ,KAAK,WAAW,EAAE,CAAC;QACtC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,cAAc,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,gBAAgB,CAAC,WAAW,CAAC,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,QAAiB;IACpD,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IAC1C,IAAI,GAAG;QAAE,OAAO,GAAG,CAAC;IAEpB,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAClC,MAAM,UAAU,GACd,QAAQ,KAAK,QAAQ;QACnB,CAAC,CAAC;YACE,8DAA8D;YAC9D,oDAAoD;SACrD;QACH,CAAC,CAAC,QAAQ,KAAK,OAAO;YACpB,CAAC,CAAC;gBACE,+BAA+B;gBAC/B,wBAAwB;gBACxB,2BAA2B;gBAC3B,mBAAmB;gBACnB,oBAAoB;aACrB;YACH,CAAC,CAAC,QAAQ,KAAK,OAAO;gBACpB,CAAC,CAAC;oBACE,4DAA4D;oBAC5D,kEAAkE;iBACnE;gBACH,CAAC,CAAC,EAAE,CAAC;IAEb,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,IAAI,UAAU,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC;IAC9B,CAAC;IACD,MAAM,IAAI,KAAK,CACb,uBAAuB,QAAQ,mDAAmD,CACnF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE;YACjC,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC,OAAO,EAAqB,CAAC;YACrD,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAA4B,EAAE,EAAE;YAClD,MAAM,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,KAA4B;IAC9D,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC3D,OAAO,IAAI,KAAK,CACd,8IAA8I,CAC/I,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,IAAY,EACZ,SAAS,GAAG,
|
|
1
|
+
{"version":3,"file":"chrome-launcher.js","sourceRoot":"","sources":["../../src/browser/chrome-launcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export type ProfileLockState =
|
|
2
|
+
/** No lock files: the profile is free. */
|
|
3
|
+
'unlocked'
|
|
4
|
+
/** Locked by a live process on this host. */
|
|
5
|
+
| 'locked'
|
|
6
|
+
/** Locked by a process on this host that is no longer running. */
|
|
7
|
+
| 'stale'
|
|
8
|
+
/** Locked from another host; liveness cannot be checked here. */
|
|
9
|
+
| 'locked_other_host'
|
|
10
|
+
/** Lock files exist but name no owner Pilot can read. */
|
|
11
|
+
| 'locked_unknown';
|
|
12
|
+
export interface ProfileStatus {
|
|
13
|
+
profile: string;
|
|
14
|
+
userDataDir: string;
|
|
15
|
+
state: ProfileLockState;
|
|
16
|
+
pid?: number;
|
|
17
|
+
host?: string;
|
|
18
|
+
/** True when the lock owner's command line shows Chrome using this Pilot profile. */
|
|
19
|
+
pilotChrome?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export declare function pilotDataDir(): string;
|
|
22
|
+
/**
|
|
23
|
+
* Report the lock state of every Pilot profile. Read-only: unlike
|
|
24
|
+
* isProfileLocked, it never removes stale locks.
|
|
25
|
+
*/
|
|
26
|
+
export declare function listProfiles(): ProfileStatus[];
|
|
27
|
+
/** The full command line of a process, or null when it cannot be read. */
|
|
28
|
+
export declare function readProcessCommand(pid: number): string | null;
|
|
29
|
+
/**
|
|
30
|
+
* Whether pid is a Chrome or Chromium browser started with exactly this Pilot
|
|
31
|
+
* profile directory. A pid read from a lock can be reused by an unrelated
|
|
32
|
+
* process, so stop-all only signals processes that pass this check.
|
|
33
|
+
*/
|
|
34
|
+
export declare function isPilotChrome(pid: number, userDataDir: string): boolean;
|
|
35
|
+
export interface StopResult {
|
|
36
|
+
profile: string;
|
|
37
|
+
pid?: number;
|
|
38
|
+
outcome: 'stopped' | 'cleaned' | 'failed' | 'skipped';
|
|
39
|
+
detail: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Stop every Chrome on this host that holds a Pilot profile lock. Processes
|
|
43
|
+
* are only signalled after their command line confirms they use that
|
|
44
|
+
* profile's directory; nothing else is touched.
|
|
45
|
+
*/
|
|
46
|
+
export declare function stopPilotBrowsers(): Promise<StopResult[]>;
|
|
47
|
+
/** Stop the Chrome holding a profile lock, if it is verifiably Pilot's. */
|
|
48
|
+
export declare function stopLockedProfile(status: ProfileStatus): Promise<StopResult>;
|
|
49
|
+
//# sourceMappingURL=sessions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../src/browser/sessions.ts"],"names":[],"mappings":"AAYA,MAAM,MAAM,gBAAgB;AAC1B,0CAA0C;AACxC,UAAU;AACZ,6CAA6C;GAC3C,QAAQ;AACV,kEAAkE;GAChE,OAAO;AACT,iEAAiE;GAC/D,mBAAmB;AACrB,yDAAyD;GACvD,gBAAgB,CAAC;AAErB,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,gBAAgB,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qFAAqF;IACrF,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,wBAAgB,YAAY,IAAI,MAAM,CAGrC;AAED;;;GAGG;AACH,wBAAgB,YAAY,IAAI,aAAa,EAAE,CAoB9C;AAsDD,0EAA0E;AAC1E,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE7D;AAMD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAevE;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;IACtD,MAAM,EAAE,MAAM,CAAC;CAChB;AAiED;;;;GAIG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC,CA8C/D;AAED,2EAA2E;AAC3E,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,UAAU,CAAC,CAwBrB"}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { execFileSync } from 'child_process';
|
|
2
|
+
import { existsSync, lstatSync, readdirSync, statSync } from 'fs';
|
|
3
|
+
import { hostname } from 'os';
|
|
4
|
+
import { basename, dirname, join } from 'path';
|
|
5
|
+
import { PROFILE_NAME_RE, cleanupLockFiles, isProcessAlive, profileLockOwner, resolveUserDataDir } from './chrome-launcher.js';
|
|
6
|
+
export function pilotDataDir() {
|
|
7
|
+
// resolveUserDataDir validates the name; any valid name gives the parent.
|
|
8
|
+
return dirname(resolveUserDataDir('profile1'));
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Report the lock state of every Pilot profile. Read-only: unlike
|
|
12
|
+
* isProfileLocked, it never removes stale locks.
|
|
13
|
+
*/
|
|
14
|
+
export function listProfiles() {
|
|
15
|
+
const dataDir = pilotDataDir();
|
|
16
|
+
let names;
|
|
17
|
+
try {
|
|
18
|
+
names = readdirSync(dataDir);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
return names
|
|
24
|
+
.filter((name) => PROFILE_NAME_RE.test(name))
|
|
25
|
+
.filter((name) => {
|
|
26
|
+
try {
|
|
27
|
+
return statSync(join(dataDir, name)).isDirectory();
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
.sort()
|
|
34
|
+
.map((profile) => profileStatus(profile, join(dataDir, profile)));
|
|
35
|
+
}
|
|
36
|
+
function profileStatus(profile, userDataDir) {
|
|
37
|
+
const owner = profileLockOwner(userDataDir);
|
|
38
|
+
const base = { profile, userDataDir };
|
|
39
|
+
if (!owner) {
|
|
40
|
+
const hasLock = lockPresent(join(userDataDir, 'SingletonLock')) ||
|
|
41
|
+
existsSync(join(userDataDir, 'lockfile'));
|
|
42
|
+
return { ...base, state: hasLock ? 'locked_unknown' : 'unlocked' };
|
|
43
|
+
}
|
|
44
|
+
if (owner.lockHost !== hostname()) {
|
|
45
|
+
return {
|
|
46
|
+
...base,
|
|
47
|
+
state: 'locked_other_host',
|
|
48
|
+
pid: owner.pid,
|
|
49
|
+
host: owner.lockHost
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
if (!isProcessAlive(owner.pid)) {
|
|
53
|
+
return { ...base, state: 'stale', pid: owner.pid, host: owner.lockHost };
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
...base,
|
|
57
|
+
state: 'locked',
|
|
58
|
+
pid: owner.pid,
|
|
59
|
+
host: owner.lockHost,
|
|
60
|
+
pilotChrome: isPilotChrome(owner.pid, userDataDir)
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function lockPresent(path) {
|
|
64
|
+
try {
|
|
65
|
+
lstatSync(path);
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function ps(pid, field) {
|
|
73
|
+
if (process.platform === 'win32')
|
|
74
|
+
return null;
|
|
75
|
+
try {
|
|
76
|
+
const out = execFileSync('ps', ['-o', `${field}=`, '-p', String(pid)], {
|
|
77
|
+
encoding: 'utf8',
|
|
78
|
+
stdio: ['ignore', 'pipe', 'ignore']
|
|
79
|
+
}).trim();
|
|
80
|
+
return out || null;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/** The full command line of a process, or null when it cannot be read. */
|
|
87
|
+
export function readProcessCommand(pid) {
|
|
88
|
+
return ps(pid, 'args');
|
|
89
|
+
}
|
|
90
|
+
// Chrome's main executable: "chrome" or "chromium-browser" on Linux (comm is
|
|
91
|
+
// truncated to 15 characters), "Google Chrome" or "Chromium" on macOS.
|
|
92
|
+
const CHROME_EXECUTABLE_RE = /chrom(e|ium)/i;
|
|
93
|
+
/**
|
|
94
|
+
* Whether pid is a Chrome or Chromium browser started with exactly this Pilot
|
|
95
|
+
* profile directory. A pid read from a lock can be reused by an unrelated
|
|
96
|
+
* process, so stop-all only signals processes that pass this check.
|
|
97
|
+
*/
|
|
98
|
+
export function isPilotChrome(pid, userDataDir) {
|
|
99
|
+
const executable = ps(pid, 'comm');
|
|
100
|
+
if (!executable || !CHROME_EXECUTABLE_RE.test(basename(executable))) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
const command = readProcessCommand(pid);
|
|
104
|
+
if (!command)
|
|
105
|
+
return false;
|
|
106
|
+
const flag = ` --user-data-dir=${userDataDir}`;
|
|
107
|
+
let at = command.indexOf(flag);
|
|
108
|
+
while (at !== -1) {
|
|
109
|
+
const next = command.charAt(at + flag.length);
|
|
110
|
+
if (next === '' || next === ' ')
|
|
111
|
+
return true;
|
|
112
|
+
at = command.indexOf(flag, at + 1);
|
|
113
|
+
}
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
async function waitForProcessExit(pid, ms) {
|
|
117
|
+
const deadline = Date.now() + ms;
|
|
118
|
+
while (Date.now() < deadline) {
|
|
119
|
+
if (!isProcessAlive(pid))
|
|
120
|
+
return true;
|
|
121
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
122
|
+
}
|
|
123
|
+
return !isProcessAlive(pid);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* SIGTERM, then SIGKILL. The pid's identity is re-checked right before each
|
|
127
|
+
* signal: a process seen earlier can exit and its pid be reused while
|
|
128
|
+
* other browsers are being stopped.
|
|
129
|
+
*/
|
|
130
|
+
async function terminate(pid, userDataDir) {
|
|
131
|
+
const signal = (sig) => {
|
|
132
|
+
if (!isPilotChrome(pid, userDataDir))
|
|
133
|
+
return 'gone';
|
|
134
|
+
try {
|
|
135
|
+
process.kill(pid, sig);
|
|
136
|
+
return 'sent';
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
const code = err.code;
|
|
140
|
+
if (code === 'ESRCH')
|
|
141
|
+
return 'gone';
|
|
142
|
+
return { error: `could not send ${sig} to pid ${pid} (${code})` };
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
const term = signal('SIGTERM');
|
|
146
|
+
if (term === 'gone') {
|
|
147
|
+
return isProcessAlive(pid)
|
|
148
|
+
? { outcome: 'not_pilot' }
|
|
149
|
+
: { outcome: 'stopped' };
|
|
150
|
+
}
|
|
151
|
+
if (typeof term === 'object')
|
|
152
|
+
return { outcome: 'failed', detail: term.error };
|
|
153
|
+
if (await waitForProcessExit(pid, 5000))
|
|
154
|
+
return { outcome: 'stopped' };
|
|
155
|
+
const kill = signal('SIGKILL');
|
|
156
|
+
if (kill === 'gone') {
|
|
157
|
+
// Only a confirmed exit counts as stopped. A live pid that no longer
|
|
158
|
+
// verifies (ps failed, or the process changed) is left alone.
|
|
159
|
+
return isProcessAlive(pid)
|
|
160
|
+
? {
|
|
161
|
+
outcome: 'failed',
|
|
162
|
+
detail: `pid ${pid} did not exit after SIGTERM and could no longer be verified as Chrome using ${userDataDir}; not killed, lock kept`
|
|
163
|
+
}
|
|
164
|
+
: { outcome: 'stopped' };
|
|
165
|
+
}
|
|
166
|
+
if (typeof kill === 'object')
|
|
167
|
+
return { outcome: 'failed', detail: kill.error };
|
|
168
|
+
return (await waitForProcessExit(pid, 2000))
|
|
169
|
+
? { outcome: 'stopped' }
|
|
170
|
+
: { outcome: 'failed', detail: `pid ${pid} did not exit after SIGKILL` };
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Stop every Chrome on this host that holds a Pilot profile lock. Processes
|
|
174
|
+
* are only signalled after their command line confirms they use that
|
|
175
|
+
* profile's directory; nothing else is touched.
|
|
176
|
+
*/
|
|
177
|
+
export async function stopPilotBrowsers() {
|
|
178
|
+
const results = [];
|
|
179
|
+
for (const status of listProfiles()) {
|
|
180
|
+
const { profile, pid } = status;
|
|
181
|
+
switch (status.state) {
|
|
182
|
+
case 'unlocked':
|
|
183
|
+
continue;
|
|
184
|
+
case 'stale': {
|
|
185
|
+
const removed = cleanupLockFiles(status.userDataDir, pid);
|
|
186
|
+
results.push(removed
|
|
187
|
+
? {
|
|
188
|
+
profile,
|
|
189
|
+
pid,
|
|
190
|
+
outcome: 'cleaned',
|
|
191
|
+
detail: `removed stale lock left by pid ${pid}, which is no longer running`
|
|
192
|
+
}
|
|
193
|
+
: {
|
|
194
|
+
profile,
|
|
195
|
+
pid,
|
|
196
|
+
outcome: 'failed',
|
|
197
|
+
detail: `stale lock left by pid ${pid} could not be removed (the lock changed owner or is not writable)`
|
|
198
|
+
});
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
case 'locked_other_host':
|
|
202
|
+
results.push({
|
|
203
|
+
profile,
|
|
204
|
+
pid,
|
|
205
|
+
outcome: 'skipped',
|
|
206
|
+
detail: `locked by pid ${pid} on host "${status.host}"; Pilot can only stop browsers on this host`
|
|
207
|
+
});
|
|
208
|
+
continue;
|
|
209
|
+
case 'locked_unknown':
|
|
210
|
+
results.push({
|
|
211
|
+
profile,
|
|
212
|
+
outcome: 'skipped',
|
|
213
|
+
detail: 'lock files name no owner; left in place'
|
|
214
|
+
});
|
|
215
|
+
continue;
|
|
216
|
+
case 'locked':
|
|
217
|
+
results.push(await stopLockedProfile(status));
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return results;
|
|
221
|
+
}
|
|
222
|
+
/** Stop the Chrome holding a profile lock, if it is verifiably Pilot's. */
|
|
223
|
+
export async function stopLockedProfile(status) {
|
|
224
|
+
const { profile, pid, userDataDir } = status;
|
|
225
|
+
const notPilot = {
|
|
226
|
+
profile,
|
|
227
|
+
pid,
|
|
228
|
+
outcome: 'skipped',
|
|
229
|
+
detail: `pid ${pid} holds the lock but its command line does not show Chrome using ${userDataDir}; not stopped`
|
|
230
|
+
};
|
|
231
|
+
if (pid === undefined || !status.pilotChrome)
|
|
232
|
+
return notPilot;
|
|
233
|
+
const result = await terminate(pid, userDataDir);
|
|
234
|
+
if (result.outcome === 'not_pilot')
|
|
235
|
+
return notPilot;
|
|
236
|
+
if (result.outcome === 'failed') {
|
|
237
|
+
return { profile, pid, outcome: 'failed', detail: result.detail };
|
|
238
|
+
}
|
|
239
|
+
const removed = cleanupLockFiles(userDataDir, pid);
|
|
240
|
+
return {
|
|
241
|
+
profile,
|
|
242
|
+
pid,
|
|
243
|
+
outcome: 'stopped',
|
|
244
|
+
detail: removed
|
|
245
|
+
? `stopped Chrome pid ${pid}`
|
|
246
|
+
: `stopped Chrome pid ${pid}, but its lock could not be removed`
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=sessions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessions.js","sourceRoot":"","sources":["../../src/browser/sessions.ts"],"names":[],"mappings":"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"}
|
package/dist/browser/types.d.ts
CHANGED
|
@@ -23,6 +23,16 @@ export interface LaunchOptions {
|
|
|
23
23
|
responsive?: boolean;
|
|
24
24
|
startupTimeoutMs?: number;
|
|
25
25
|
}
|
|
26
|
+
export interface SessionInfo {
|
|
27
|
+
/** launched: Chrome started by this session; external: browser_connect. */
|
|
28
|
+
mode: 'launched' | 'external' | 'none';
|
|
29
|
+
connected: boolean;
|
|
30
|
+
profile?: string;
|
|
31
|
+
userDataDir?: string;
|
|
32
|
+
pid?: number;
|
|
33
|
+
host?: string;
|
|
34
|
+
cdpPort?: number;
|
|
35
|
+
}
|
|
26
36
|
export type SandboxDecision = {
|
|
27
37
|
disable: false;
|
|
28
38
|
} | {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/browser/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEtD,MAAM,MAAM,oBAAoB,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;AAE1E,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,MAAM,eAAe,GACzB;IAAE,OAAO,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,cAAc,GAAG,WAAW,CAAA;CAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/browser/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEtD,MAAM,MAAM,oBAAoB,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;AAE1E,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,2EAA2E;IAC3E,IAAI,EAAE,UAAU,GAAG,UAAU,GAAG,MAAM,CAAC;IACvC,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,eAAe,GACzB;IAAE,OAAO,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,cAAc,GAAG,WAAW,CAAA;CAAE,CAAC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const SKILL_CONTENT = "---\nname: pilot\ndescription: Control and debug web pages with the Pilot MCP browser tools. Use when the user asks to open, inspect, test, or troubleshoot a site in Chrome with Pilot.\n---\n\n# Pilot browser workflow\n\nUse the `pilot` MCP tools to operate Chrome through the Chrome DevTools Protocol.\n\n## Start and inspect\n\n1. Call `browser_start` before any other Pilot browser tool. Use visible mode unless the user requests headless operation or the environment has no graphical display.\n2. Navigate with `browser_navigate`, then confirm the result with `browser_page_info` or `browser_snapshot`.\n3. Use refs returned by `browser_snapshot` or `browser_find` for interaction. Take a fresh snapshot after navigation or substantial DOM changes because refs can become stale.\n4. For debugging, clear errors before reproducing the problem, then inspect `browser_errors`, `browser_console`, and `browser_network`. Use performance tracing only when the user asks about load or runtime performance.\n5. Call `browser_stop` when the browser is no longer needed.\n\nDo not enter credentials, submit consequential forms, upload files, or make other externally visible changes unless the user authorized that action.\n\n## Troubleshooting\n\n### Visible Chrome on Linux\n\nRun `pilot check` when `browser_start` fails. Visible Chrome requires `DISPLAY` or `WAYLAND_DISPLAY` in the Pilot MCP server process. Headless operation does not.\n\nIf desktop applications open but Pilot reports that the display is missing, inspect the graphical session with `printenv DISPLAY`. Forward the returned value through the MCP server configuration and restart the agent so Pilot is relaunched. For Codex:\n\n```toml\n[mcp_servers.pilot]\ncommand = \"npx\"\nargs = [\"-y\", \"@everydaydevopsio/pilot\"]\nenv = { DISPLAY = \":1\" }\n```\n\nReplace `:1` with the actual value. If the X server requires a cookie, forward `XAUTHORITY` in the same map. For SSH, use trusted X11 forwarding (`ssh -Y`) when policy permits, or use a remote desktop session and its display value. Use `PILOT_HEADLESS=true` on systems without a desktop. In CI, use headless mode or run Pilot under Xvfb.\n\n### Other Linux preflight failures\n\n- If the profile directory is not writable, set `XDG_DATA_HOME` to a writable directory.\n- If loopback binding fails with `EPERM`, the host or container must allow binding on `127.0.0.1`; disabling Chrome's renderer sandbox does not fix it.\n- If Chrome is not detected, set `PILOT_CHROME_PATH` to its executable.\n- Avoid `PILOT_CHROME_NO_SANDBOX=true` unless the runtime genuinely cannot support Chrome's sandbox and the user accepts the security tradeoff.\n\n### Connection and page failures\n\n- Confirm the active page with `browser_page_info` and list tabs if Pilot controls the wrong tab.\n- Inspect failed document, script, XHR, and fetch requests with `browser_network`.\n- If element refs stop resolving after a page update, take another snapshot and retry with the new refs.\n";
|
|
1
|
+
export declare const SKILL_CONTENT = "---\nname: pilot\ndescription: Control and debug web pages with the Pilot MCP browser tools. Use when the user asks to open, inspect, test, or troubleshoot a site in Chrome with Pilot.\n---\n\n# Pilot browser workflow\n\nUse the `pilot` MCP tools to operate Chrome through the Chrome DevTools Protocol.\n\n## Start and inspect\n\n1. Call `browser_start` before any other Pilot browser tool. Use visible mode unless the user requests headless operation or the environment has no graphical display.\n2. Navigate with `browser_navigate`, then confirm the result with `browser_page_info` or `browser_snapshot`.\n3. Use refs returned by `browser_snapshot` or `browser_find` for interaction. Take a fresh snapshot after navigation or substantial DOM changes because refs can become stale.\n4. For debugging, clear errors before reproducing the problem, then inspect `browser_errors`, `browser_console`, and `browser_network`. Use performance tracing only when the user asks about load or runtime performance.\n5. Call `browser_stop` when the browser is no longer needed.\n\nDo not enter credentials, submit consequential forms, upload files, or make other externally visible changes unless the user authorized that action.\n\n## Troubleshooting\n\n### Visible Chrome on Linux\n\nRun `pilot check` when `browser_start` fails. Visible Chrome requires `DISPLAY` or `WAYLAND_DISPLAY` in the Pilot MCP server process. Headless operation does not.\n\nIf desktop applications open but Pilot reports that the display is missing, inspect the graphical session with `printenv DISPLAY`. Forward the returned value through the MCP server configuration and restart the agent so Pilot is relaunched. For Codex:\n\n```toml\n[mcp_servers.pilot]\ncommand = \"npx\"\nargs = [\"-y\", \"@everydaydevopsio/pilot\"]\nenv = { DISPLAY = \":1\" }\n```\n\nReplace `:1` with the actual value. If the X server requires a cookie, forward `XAUTHORITY` in the same map. For SSH, use trusted X11 forwarding (`ssh -Y`) when policy permits, or use a remote desktop session and its display value. Use `PILOT_HEADLESS=true` on systems without a desktop. In CI, use headless mode or run Pilot under Xvfb.\n\n### Startup failures\n\nRead the `Launch:`, `Cleanup:`, and `Next:` lines in the `browser_start` error before retrying.\n\n- A failed `browser_start` stops the Chrome it launched and frees the profile unless `Cleanup:` names a pid that did not stop. Do not switch profiles just because a start failed.\n- On a timeout, retry once with a larger `startupTimeoutMs` (for example `180000`). First runs and software-rendered Linux desktops can be slow.\n- If Chrome exited in visible mode, check the display (above) or retry with `headless: true`.\n- If the profile is already in use, the error names the owning Chrome pid and host. `browser_stop` cannot stop a browser that this session did not launch. Call `browser_status` to see which profiles are free and who holds the others. Use a different `profileName`, or, only after the user agrees, call `browser_stop_all`. It also stops browsers that other agents may be using.\n\n### Other Linux preflight failures\n\n- If the profile directory is not writable, set `XDG_DATA_HOME` to a writable directory.\n- If loopback binding fails with `EPERM`, the host or container must allow binding on `127.0.0.1`; disabling Chrome's renderer sandbox does not fix it.\n- If Chrome is not detected, set `PILOT_CHROME_PATH` to its executable.\n- Avoid `PILOT_CHROME_NO_SANDBOX=true` unless the runtime genuinely cannot support Chrome's sandbox and the user accepts the security tradeoff.\n\n### Connection and page failures\n\n- Confirm the active page with `browser_page_info` and list tabs if Pilot controls the wrong tab.\n- Inspect failed document, script, XHR, and fetch requests with `browser_network`.\n- If element refs stop resolving after a page update, take another snapshot and retry with the new refs.\n";
|
|
2
2
|
//# sourceMappingURL=skill-template.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skill-template.d.ts","sourceRoot":"","sources":["../../src/cli/skill-template.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,aAAa,
|
|
1
|
+
{"version":3,"file":"skill-template.d.ts","sourceRoot":"","sources":["../../src/cli/skill-template.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,aAAa,g1HAC+yH,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// Generated by scripts/build-skill.mjs from skills/pilot/SKILL.md.
|
|
2
2
|
// Do not edit this file directly.
|
|
3
|
-
export const SKILL_CONTENT = '---\nname: pilot\ndescription: Control and debug web pages with the Pilot MCP browser tools. Use when the user asks to open, inspect, test, or troubleshoot a site in Chrome with Pilot.\n---\n\n# Pilot browser workflow\n\nUse the `pilot` MCP tools to operate Chrome through the Chrome DevTools Protocol.\n\n## Start and inspect\n\n1. Call `browser_start` before any other Pilot browser tool. Use visible mode unless the user requests headless operation or the environment has no graphical display.\n2. Navigate with `browser_navigate`, then confirm the result with `browser_page_info` or `browser_snapshot`.\n3. Use refs returned by `browser_snapshot` or `browser_find` for interaction. Take a fresh snapshot after navigation or substantial DOM changes because refs can become stale.\n4. For debugging, clear errors before reproducing the problem, then inspect `browser_errors`, `browser_console`, and `browser_network`. Use performance tracing only when the user asks about load or runtime performance.\n5. Call `browser_stop` when the browser is no longer needed.\n\nDo not enter credentials, submit consequential forms, upload files, or make other externally visible changes unless the user authorized that action.\n\n## Troubleshooting\n\n### Visible Chrome on Linux\n\nRun `pilot check` when `browser_start` fails. Visible Chrome requires `DISPLAY` or `WAYLAND_DISPLAY` in the Pilot MCP server process. Headless operation does not.\n\nIf desktop applications open but Pilot reports that the display is missing, inspect the graphical session with `printenv DISPLAY`. Forward the returned value through the MCP server configuration and restart the agent so Pilot is relaunched. For Codex:\n\n```toml\n[mcp_servers.pilot]\ncommand = "npx"\nargs = ["-y", "@everydaydevopsio/pilot"]\nenv = { DISPLAY = ":1" }\n```\n\nReplace `:1` with the actual value. If the X server requires a cookie, forward `XAUTHORITY` in the same map. For SSH, use trusted X11 forwarding (`ssh -Y`) when policy permits, or use a remote desktop session and its display value. Use `PILOT_HEADLESS=true` on systems without a desktop. In CI, use headless mode or run Pilot under Xvfb.\n\n### Other Linux preflight failures\n\n- If the profile directory is not writable, set `XDG_DATA_HOME` to a writable directory.\n- If loopback binding fails with `EPERM`, the host or container must allow binding on `127.0.0.1`; disabling Chrome\'s renderer sandbox does not fix it.\n- If Chrome is not detected, set `PILOT_CHROME_PATH` to its executable.\n- Avoid `PILOT_CHROME_NO_SANDBOX=true` unless the runtime genuinely cannot support Chrome\'s sandbox and the user accepts the security tradeoff.\n\n### Connection and page failures\n\n- Confirm the active page with `browser_page_info` and list tabs if Pilot controls the wrong tab.\n- Inspect failed document, script, XHR, and fetch requests with `browser_network`.\n- If element refs stop resolving after a page update, take another snapshot and retry with the new refs.\n';
|
|
3
|
+
export const SKILL_CONTENT = '---\nname: pilot\ndescription: Control and debug web pages with the Pilot MCP browser tools. Use when the user asks to open, inspect, test, or troubleshoot a site in Chrome with Pilot.\n---\n\n# Pilot browser workflow\n\nUse the `pilot` MCP tools to operate Chrome through the Chrome DevTools Protocol.\n\n## Start and inspect\n\n1. Call `browser_start` before any other Pilot browser tool. Use visible mode unless the user requests headless operation or the environment has no graphical display.\n2. Navigate with `browser_navigate`, then confirm the result with `browser_page_info` or `browser_snapshot`.\n3. Use refs returned by `browser_snapshot` or `browser_find` for interaction. Take a fresh snapshot after navigation or substantial DOM changes because refs can become stale.\n4. For debugging, clear errors before reproducing the problem, then inspect `browser_errors`, `browser_console`, and `browser_network`. Use performance tracing only when the user asks about load or runtime performance.\n5. Call `browser_stop` when the browser is no longer needed.\n\nDo not enter credentials, submit consequential forms, upload files, or make other externally visible changes unless the user authorized that action.\n\n## Troubleshooting\n\n### Visible Chrome on Linux\n\nRun `pilot check` when `browser_start` fails. Visible Chrome requires `DISPLAY` or `WAYLAND_DISPLAY` in the Pilot MCP server process. Headless operation does not.\n\nIf desktop applications open but Pilot reports that the display is missing, inspect the graphical session with `printenv DISPLAY`. Forward the returned value through the MCP server configuration and restart the agent so Pilot is relaunched. For Codex:\n\n```toml\n[mcp_servers.pilot]\ncommand = "npx"\nargs = ["-y", "@everydaydevopsio/pilot"]\nenv = { DISPLAY = ":1" }\n```\n\nReplace `:1` with the actual value. If the X server requires a cookie, forward `XAUTHORITY` in the same map. For SSH, use trusted X11 forwarding (`ssh -Y`) when policy permits, or use a remote desktop session and its display value. Use `PILOT_HEADLESS=true` on systems without a desktop. In CI, use headless mode or run Pilot under Xvfb.\n\n### Startup failures\n\nRead the `Launch:`, `Cleanup:`, and `Next:` lines in the `browser_start` error before retrying.\n\n- A failed `browser_start` stops the Chrome it launched and frees the profile unless `Cleanup:` names a pid that did not stop. Do not switch profiles just because a start failed.\n- On a timeout, retry once with a larger `startupTimeoutMs` (for example `180000`). First runs and software-rendered Linux desktops can be slow.\n- If Chrome exited in visible mode, check the display (above) or retry with `headless: true`.\n- If the profile is already in use, the error names the owning Chrome pid and host. `browser_stop` cannot stop a browser that this session did not launch. Call `browser_status` to see which profiles are free and who holds the others. Use a different `profileName`, or, only after the user agrees, call `browser_stop_all`. It also stops browsers that other agents may be using.\n\n### Other Linux preflight failures\n\n- If the profile directory is not writable, set `XDG_DATA_HOME` to a writable directory.\n- If loopback binding fails with `EPERM`, the host or container must allow binding on `127.0.0.1`; disabling Chrome\'s renderer sandbox does not fix it.\n- If Chrome is not detected, set `PILOT_CHROME_PATH` to its executable.\n- Avoid `PILOT_CHROME_NO_SANDBOX=true` unless the runtime genuinely cannot support Chrome\'s sandbox and the user accepts the security tradeoff.\n\n### Connection and page failures\n\n- Confirm the active page with `browser_page_info` and list tabs if Pilot controls the wrong tab.\n- Inspect failed document, script, XHR, and fetch requests with `browser_network`.\n- If element refs stop resolving after a page update, take another snapshot and retry with the new refs.\n';
|
|
4
4
|
//# sourceMappingURL=skill-template.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skill-template.js","sourceRoot":"","sources":["../../src/cli/skill-template.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,kCAAkC;AAClC,MAAM,CAAC,MAAM,aAAa,GACxB,
|
|
1
|
+
{"version":3,"file":"skill-template.js","sourceRoot":"","sources":["../../src/cli/skill-template.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,kCAAkC;AAClC,MAAM,CAAC,MAAM,aAAa,GACxB,u0HAAu0H,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/browser.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/browser.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAkQnD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,cAAc,EACvB,kBAAkB,EAAE,MAAM,cAAc,GACvC,IAAI,CA2gBN"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { DEFAULT_STARTUP_TIMEOUT_MS } from '../../browser/chrome-launcher.js';
|
|
3
|
+
import { listProfiles, pilotDataDir, stopPilotBrowsers } from '../../browser/sessions.js';
|
|
2
4
|
import { executeScreenshot } from '../../commands/screenshot.js';
|
|
3
5
|
import { executeNavigate } from '../../commands/navigate.js';
|
|
4
6
|
import { executeClick } from '../../commands/click.js';
|
|
@@ -154,8 +156,8 @@ const startShape = {
|
|
|
154
156
|
.number()
|
|
155
157
|
.int()
|
|
156
158
|
.positive()
|
|
157
|
-
.default(
|
|
158
|
-
.describe(
|
|
159
|
+
.default(DEFAULT_STARTUP_TIMEOUT_MS)
|
|
160
|
+
.describe(`Timeout waiting for Chrome DevTools to become ready, in milliseconds. Defaults to ${DEFAULT_STARTUP_TIMEOUT_MS}. Startup fails immediately if Chrome exits, so raising this only helps when Chrome is slow to start (for example a first run on a Linux server with software rendering).`)
|
|
159
161
|
};
|
|
160
162
|
const newTabShape = {
|
|
161
163
|
url: z
|
|
@@ -244,7 +246,12 @@ export function registerBrowserTools(server, context, makeBrowserManager) {
|
|
|
244
246
|
server.tool('browser_stop', 'Stop the Chrome browser and free all resources.', {}, async () => {
|
|
245
247
|
if (!context.manager) {
|
|
246
248
|
return {
|
|
247
|
-
content: [
|
|
249
|
+
content: [
|
|
250
|
+
{
|
|
251
|
+
type: 'text',
|
|
252
|
+
text: 'Browser is not running. This Pilot session is not tracking a launched or connected browser; a failed browser_start stops the Chrome it launched and reports the outcome in its error.'
|
|
253
|
+
}
|
|
254
|
+
]
|
|
248
255
|
};
|
|
249
256
|
}
|
|
250
257
|
await context.manager.destroy();
|
|
@@ -253,6 +260,48 @@ export function registerBrowserTools(server, context, makeBrowserManager) {
|
|
|
253
260
|
content: [{ type: 'text', text: 'Browser stopped.' }]
|
|
254
261
|
};
|
|
255
262
|
});
|
|
263
|
+
server.tool('browser_status', 'Show the browser tracked by this Pilot session and the lock state of every Pilot profile on this machine (including browsers started by other Pilot sessions). Read-only. Use it to diagnose "profile already in use" errors.', {}, async () => {
|
|
264
|
+
const status = {
|
|
265
|
+
session: context.manager?.getSessionInfo() ?? {
|
|
266
|
+
mode: 'none',
|
|
267
|
+
connected: false
|
|
268
|
+
},
|
|
269
|
+
dataDir: pilotDataDir(),
|
|
270
|
+
profiles: listProfiles()
|
|
271
|
+
};
|
|
272
|
+
return {
|
|
273
|
+
content: [
|
|
274
|
+
{ type: 'text', text: JSON.stringify(status, null, 2) }
|
|
275
|
+
]
|
|
276
|
+
};
|
|
277
|
+
});
|
|
278
|
+
server.tool('browser_stop_all', 'Stop every Pilot-managed Chrome on this machine: the browser in this session plus any Chrome holding a Pilot profile lock, including ones started by other Pilot sessions. Only processes whose command line shows Chrome using a Pilot profile directory are stopped; browsers on other hosts and unverifiable locks are skipped. Also removes stale locks. Ask the user before calling this, since it can close browsers other agents are using.', {}, async () => {
|
|
279
|
+
const lines = [];
|
|
280
|
+
if (context.manager) {
|
|
281
|
+
const info = context.manager.getSessionInfo();
|
|
282
|
+
await context.manager.destroy();
|
|
283
|
+
context.manager = null;
|
|
284
|
+
if (info.mode === 'launched') {
|
|
285
|
+
lines.push(`this session: stopped Chrome pid ${info.pid} (profile "${info.profile}")`);
|
|
286
|
+
}
|
|
287
|
+
else if (info.mode === 'external') {
|
|
288
|
+
lines.push(`this session: disconnected from ${info.host}:${info.cdpPort} (not stopped; Pilot did not launch it)`);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
for (const result of await stopPilotBrowsers()) {
|
|
292
|
+
lines.push(`${result.profile}: ${result.outcome} - ${result.detail}`);
|
|
293
|
+
}
|
|
294
|
+
return {
|
|
295
|
+
content: [
|
|
296
|
+
{
|
|
297
|
+
type: 'text',
|
|
298
|
+
text: lines.length > 0
|
|
299
|
+
? lines.join('\n')
|
|
300
|
+
: 'No Pilot-managed browsers were running.'
|
|
301
|
+
}
|
|
302
|
+
]
|
|
303
|
+
};
|
|
304
|
+
});
|
|
256
305
|
server.tool('browser_screenshot', 'Capture a screenshot of the current browser viewport or full page', screenshotShape, async ({ format, quality, fullPage }) => {
|
|
257
306
|
const { client } = requireClient(context);
|
|
258
307
|
const result = await executeScreenshot(client, {
|