@ai-devkit/agent-manager 0.40.0 → 0.42.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.
- package/dist/AgentManager.d.ts +12 -0
- package/dist/AgentManager.d.ts.map +1 -1
- package/dist/AgentManager.js +45 -10
- package/dist/AgentManager.js.map +1 -1
- package/dist/__tests__/AgentManager.test.js +111 -0
- package/dist/__tests__/AgentManager.test.js.map +1 -1
- package/dist/__tests__/fixtures.test.js +218 -0
- package/dist/__tests__/fixtures.test.js.map +1 -0
- package/dist/__tests__/harnesses/devin/DevinAdapter.test.js.map +1 -1
- package/dist/__tests__/harnesses/devin/DevinSessionParser.test.js.map +1 -1
- package/dist/__tests__/harnesses/muse/MuseAdapter.test.js +247 -0
- package/dist/__tests__/harnesses/muse/MuseAdapter.test.js.map +1 -0
- package/dist/__tests__/harnesses/muse/MuseAgentMapper.test.js +81 -0
- package/dist/__tests__/harnesses/muse/MuseAgentMapper.test.js.map +1 -0
- package/dist/__tests__/harnesses/muse/MuseSessionLocator.test.js +185 -0
- package/dist/__tests__/harnesses/muse/MuseSessionLocator.test.js.map +1 -0
- package/dist/__tests__/harnesses/muse/MuseSessionParser.test.js +328 -0
- package/dist/__tests__/harnesses/muse/MuseSessionParser.test.js.map +1 -0
- package/dist/__tests__/harnesses/opencode/OpenCodeSessionParser.test.js.map +1 -1
- package/dist/__tests__/harnesses/readiness/AgentReadiness.test.js +42 -1
- package/dist/__tests__/harnesses/readiness/AgentReadiness.test.js.map +1 -1
- package/dist/__tests__/harnesses/runtimeProfiles.test.js +12 -0
- package/dist/__tests__/harnesses/runtimeProfiles.test.js.map +1 -1
- package/dist/__tests__/readiness-fixtures.test.js +54 -0
- package/dist/__tests__/readiness-fixtures.test.js.map +1 -0
- package/dist/__tests__/utils/process.test.js +71 -1
- package/dist/__tests__/utils/process.test.js.map +1 -1
- package/dist/adapters/AgentAdapter.d.ts +8 -1
- package/dist/adapters/AgentAdapter.d.ts.map +1 -1
- package/dist/adapters/AgentAdapter.js +2 -1
- package/dist/adapters/AgentAdapter.js.map +1 -1
- package/dist/fixtures/bundle.d.ts +67 -0
- package/dist/fixtures/bundle.d.ts.map +1 -0
- package/dist/fixtures/bundle.js +86 -0
- package/dist/fixtures/bundle.js.map +1 -0
- package/dist/fixtures/capture.d.ts +11 -0
- package/dist/fixtures/capture.d.ts.map +1 -0
- package/dist/fixtures/capture.js +318 -0
- package/dist/fixtures/capture.js.map +1 -0
- package/dist/harnesses/devin/DevinAdapter.d.ts.map +1 -1
- package/dist/harnesses/devin/DevinAdapter.js.map +1 -1
- package/dist/harnesses/devin/DevinAgentMapper.d.ts.map +1 -1
- package/dist/harnesses/devin/DevinAgentMapper.js.map +1 -1
- package/dist/harnesses/devin/DevinSessionParser.d.ts.map +1 -1
- package/dist/harnesses/devin/DevinSessionParser.js.map +1 -1
- package/dist/harnesses/index.d.ts.map +1 -1
- package/dist/harnesses/index.js +3 -1
- package/dist/harnesses/index.js.map +1 -1
- package/dist/harnesses/muse/MuseAdapter.d.ts +33 -0
- package/dist/harnesses/muse/MuseAdapter.d.ts.map +1 -0
- package/dist/harnesses/muse/MuseAdapter.js +122 -0
- package/dist/harnesses/muse/MuseAdapter.js.map +1 -0
- package/dist/harnesses/muse/MuseAgentMapper.d.ts +15 -0
- package/dist/harnesses/muse/MuseAgentMapper.d.ts.map +1 -0
- package/dist/harnesses/muse/MuseAgentMapper.js +29 -0
- package/dist/harnesses/muse/MuseAgentMapper.js.map +1 -0
- package/dist/harnesses/muse/MuseSessionLocator.d.ts +61 -0
- package/dist/harnesses/muse/MuseSessionLocator.d.ts.map +1 -0
- package/dist/harnesses/muse/MuseSessionLocator.js +233 -0
- package/dist/harnesses/muse/MuseSessionLocator.js.map +1 -0
- package/dist/harnesses/muse/MuseSessionParser.d.ts +77 -0
- package/dist/harnesses/muse/MuseSessionParser.d.ts.map +1 -0
- package/dist/harnesses/muse/MuseSessionParser.js +350 -0
- package/dist/harnesses/muse/MuseSessionParser.js.map +1 -0
- package/dist/harnesses/muse/readiness.d.ts +3 -0
- package/dist/harnesses/muse/readiness.d.ts.map +1 -0
- package/dist/harnesses/muse/readiness.js +37 -0
- package/dist/harnesses/muse/readiness.js.map +1 -0
- package/dist/harnesses/readiness/AgentReadiness.d.ts.map +1 -1
- package/dist/harnesses/readiness/AgentReadiness.js +3 -1
- package/dist/harnesses/readiness/AgentReadiness.js.map +1 -1
- package/dist/harnesses/readiness/types.d.ts +1 -1
- package/dist/harnesses/readiness/types.d.ts.map +1 -1
- package/dist/harnesses/runtimeProfiles.d.ts.map +1 -1
- package/dist/harnesses/runtimeProfiles.js +2 -1
- package/dist/harnesses/runtimeProfiles.js.map +1 -1
- package/dist/harnesses/shared.d.ts +1 -1
- package/dist/harnesses/shared.d.ts.map +1 -1
- package/dist/harnesses/shared.js +7 -6
- package/dist/harnesses/shared.js.map +1 -1
- package/dist/utils/process.d.ts +23 -1
- package/dist/utils/process.d.ts.map +1 -1
- package/dist/utils/process.js +44 -8
- package/dist/utils/process.js.map +1 -1
- package/package.json +1 -1
- package/src/AgentManager.ts +71 -9
- package/src/__tests__/AgentManager.test.ts +84 -0
- package/src/__tests__/fixtures.test.ts +245 -0
- package/src/__tests__/harnesses/devin/DevinAdapter.test.ts +1 -3
- package/src/__tests__/harnesses/devin/DevinSessionParser.test.ts +3 -9
- package/src/__tests__/harnesses/muse/MuseAdapter.test.ts +197 -0
- package/src/__tests__/harnesses/muse/MuseAgentMapper.test.ts +83 -0
- package/src/__tests__/harnesses/muse/MuseSessionLocator.test.ts +177 -0
- package/src/__tests__/harnesses/muse/MuseSessionParser.test.ts +279 -0
- package/src/__tests__/harnesses/opencode/OpenCodeSessionParser.test.ts +3 -2
- package/src/__tests__/harnesses/readiness/AgentReadiness.test.ts +36 -0
- package/src/__tests__/harnesses/runtimeProfiles.test.ts +13 -0
- package/src/__tests__/readiness-fixtures.test.ts +79 -0
- package/src/__tests__/utils/process.test.ts +30 -0
- package/src/adapters/AgentAdapter.ts +9 -0
- package/src/fixtures/bundle.ts +130 -0
- package/src/fixtures/capture.ts +364 -0
- package/src/harnesses/devin/DevinAdapter.ts +3 -15
- package/src/harnesses/devin/DevinAgentMapper.ts +1 -5
- package/src/harnesses/devin/DevinSessionParser.ts +3 -12
- package/src/harnesses/index.ts +2 -0
- package/src/harnesses/muse/MuseAdapter.ts +157 -0
- package/src/harnesses/muse/MuseAgentMapper.ts +33 -0
- package/src/harnesses/muse/MuseSessionLocator.ts +286 -0
- package/src/harnesses/muse/MuseSessionParser.ts +435 -0
- package/src/harnesses/muse/readiness.ts +38 -0
- package/src/harnesses/readiness/AgentReadiness.ts +2 -0
- package/src/harnesses/runtimeProfiles.ts +1 -0
- package/src/harnesses/shared.ts +11 -6
- package/src/utils/process.ts +61 -9
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Golden-fixture bundles: the parity oracle for the devkit-harness Rust port.
|
|
3
|
+
* A bundle records everything `detectAgents` consumed and produced so both
|
|
4
|
+
* the TS adapter and its Rust port can be run against identical inputs.
|
|
5
|
+
*
|
|
6
|
+
* Format (committed under fixtures/harness/<type>/<case>.json):
|
|
7
|
+
* {
|
|
8
|
+
* adapter, capturedAt, frozenNow,
|
|
9
|
+
* processes: ProcessInfo[],
|
|
10
|
+
* home: { "<relpath under $FIXTURE_HOME>": "<content with $FIXTURE_HOME refs>" },
|
|
11
|
+
* expected: AgentInfo[] (dates as ISO strings)
|
|
12
|
+
* }
|
|
13
|
+
*/ export const HOME_PLACEHOLDER = "$FIXTURE_HOME";
|
|
14
|
+
/** Resolves to the instant home files were written (birthtime matching). */ export const NOW_PLACEHOLDER = "$NOW";
|
|
15
|
+
/** Resolves to the local `YYYY/MM/DD` day dir at replay (Codex sessions). */ export const TODAY_PLACEHOLDER = "$TODAY";
|
|
16
|
+
/**
|
|
17
|
+
* Rewrite harness dot-dir paths (`<home>/.claude`, `<home>/.codex`, …) to the
|
|
18
|
+
* placeholder — nothing else. Project cwds share the home prefix
|
|
19
|
+
* (`<home>/Code/proj`) and MUST stay literal: harnesses encode them into
|
|
20
|
+
* session-dir names (`-Users-foo-proj`), so rewriting them breaks
|
|
21
|
+
* cwd↔session matching on replay.
|
|
22
|
+
*/ export function sanitize(value, realHome) {
|
|
23
|
+
const homeDot = `${realHome}/.`;
|
|
24
|
+
if (typeof value === "string") {
|
|
25
|
+
return value.split(homeDot).join(`${HOME_PLACEHOLDER}/.`);
|
|
26
|
+
}
|
|
27
|
+
if (Array.isArray(value)) return value.map((v)=>sanitize(v, realHome));
|
|
28
|
+
if (value && typeof value === "object") {
|
|
29
|
+
if (value instanceof Date) return value.toISOString();
|
|
30
|
+
const out = {};
|
|
31
|
+
for (const [k, v] of Object.entries(value))out[k] = sanitize(v, realHome);
|
|
32
|
+
return out;
|
|
33
|
+
}
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
|
+
/** Inverse of sanitize: expand the placeholder to a concrete dir. */ export function expand(value, fixtureHome) {
|
|
37
|
+
if (typeof value === "string") {
|
|
38
|
+
return value.split(HOME_PLACEHOLDER).join(fixtureHome);
|
|
39
|
+
}
|
|
40
|
+
if (Array.isArray(value)) return value.map((v)=>expand(v, fixtureHome));
|
|
41
|
+
if (value && typeof value === "object" && !(value instanceof Date)) {
|
|
42
|
+
const out = {};
|
|
43
|
+
for (const [k, v] of Object.entries(value))out[k] = expand(v, fixtureHome);
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
return value;
|
|
47
|
+
}
|
|
48
|
+
/** Replace NOW_PLACEHOLDER strings with a resolved ISO instant. */ export function expandNow(value, isoInstant) {
|
|
49
|
+
if (typeof value === "string") {
|
|
50
|
+
return value.split(NOW_PLACEHOLDER).join(isoInstant);
|
|
51
|
+
}
|
|
52
|
+
if (Array.isArray(value)) return value.map((v)=>expandNow(v, isoInstant));
|
|
53
|
+
if (value && typeof value === "object" && !(value instanceof Date)) {
|
|
54
|
+
const out = {};
|
|
55
|
+
for (const [k, v] of Object.entries(value))out[k] = expandNow(v, isoInstant);
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
return value;
|
|
59
|
+
}
|
|
60
|
+
/** Agents normalized the way the wire carries them (Date → ISO string). */ export function normalizeAgents(agents, realHome) {
|
|
61
|
+
return sanitize(JSON.parse(JSON.stringify(agents)), realHome);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Freeze `Date` at `epochMs` for the duration of `fn`. Adapters stamp
|
|
65
|
+
* `new Date()` in several places; parity requires a fixed clock.
|
|
66
|
+
*/ export async function withFrozenClock(epochMs, fn) {
|
|
67
|
+
const RealDate = Date;
|
|
68
|
+
let FrozenDate = class FrozenDate extends RealDate {
|
|
69
|
+
constructor(...args){
|
|
70
|
+
if (args.length === 0) super(epochMs);
|
|
71
|
+
else super(...args);
|
|
72
|
+
}
|
|
73
|
+
static now() {
|
|
74
|
+
return epochMs;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
const g = globalThis;
|
|
78
|
+
g.Date = FrozenDate;
|
|
79
|
+
try {
|
|
80
|
+
return await fn();
|
|
81
|
+
} finally{
|
|
82
|
+
g.Date = RealDate;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
//# sourceMappingURL=bundle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/fixtures/bundle.ts"],"sourcesContent":["/**\n * Golden-fixture bundles: the parity oracle for the devkit-harness Rust port.\n * A bundle records everything `detectAgents` consumed and produced so both\n * the TS adapter and its Rust port can be run against identical inputs.\n *\n * Format (committed under fixtures/harness/<type>/<case>.json):\n * {\n * adapter, capturedAt, frozenNow,\n * processes: ProcessInfo[],\n * home: { \"<relpath under $FIXTURE_HOME>\": \"<content with $FIXTURE_HOME refs>\" },\n * expected: AgentInfo[] (dates as ISO strings)\n * }\n */\n\nimport type { AgentInfo, ProcessInfo } from \"../adapters/AgentAdapter.js\";\n\nexport const HOME_PLACEHOLDER = \"$FIXTURE_HOME\";\n/** Resolves to the instant home files were written (birthtime matching). */\nexport const NOW_PLACEHOLDER = \"$NOW\";\n/** Resolves to the local `YYYY/MM/DD` day dir at replay (Codex sessions). */\nexport const TODAY_PLACEHOLDER = \"$TODAY\";\n\nexport interface FixtureBundle {\n adapter: string;\n capturedAt: string;\n /** Epoch ms the clock was frozen at; `\"$NOW\"` = materialization instant. */\n frozenNow: number | string;\n processes: ProcessInfo[];\n /** Files under the fixture HOME; content may embed HOME_PLACEHOLDER. */\n home: Record<string, string>;\n /**\n * mtime overrides keyed by `home` relpath — epoch ms, or \"$NOW\" for the\n * materialization instant. Adapters whose output derives from file mtimes\n * (Grok's lastActive / latest-session pick) need deterministic mtimes.\n */\n mtimes?: Record<string, number | string>;\n /**\n * AgentRegistry rows (pid→sessionFilePath etc.) visible at capture time,\n * restricted to captured process pids — adapters' registry caches read\n * this state, so replay seeds an isolated registry with it.\n */\n registry?: Record<string, unknown>[];\n /**\n * SQLite stores adapters consult (OpenCode's opencode.db), keyed by\n * relpath under $FIXTURE_HOME: SQL statements (DDL + INSERTs) executed\n * in order to materialize each db. Statements may embed HOME_PLACEHOLDER.\n */\n sqlite?: Record<string, string[]>;\n expected: Record<string, unknown>[];\n}\n\n/**\n * Rewrite harness dot-dir paths (`<home>/.claude`, `<home>/.codex`, …) to the\n * placeholder — nothing else. Project cwds share the home prefix\n * (`<home>/Code/proj`) and MUST stay literal: harnesses encode them into\n * session-dir names (`-Users-foo-proj`), so rewriting them breaks\n * cwd↔session matching on replay.\n */\nexport function sanitize<T>(value: T, realHome: string): T {\n const homeDot = `${realHome}/.`;\n if (typeof value === \"string\") {\n return value.split(homeDot).join(`${HOME_PLACEHOLDER}/.`) as T;\n }\n if (Array.isArray(value)) return value.map((v) => sanitize(v, realHome)) as T;\n if (value && typeof value === \"object\") {\n if (value instanceof Date) return value.toISOString() as T;\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value)) out[k] = sanitize(v, realHome);\n return out as T;\n }\n return value;\n}\n\n/** Inverse of sanitize: expand the placeholder to a concrete dir. */\nexport function expand<T>(value: T, fixtureHome: string): T {\n if (typeof value === \"string\") {\n return value.split(HOME_PLACEHOLDER).join(fixtureHome) as T;\n }\n if (Array.isArray(value)) return value.map((v) => expand(v, fixtureHome)) as T;\n if (value && typeof value === \"object\" && !(value instanceof Date)) {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value)) out[k] = expand(v, fixtureHome);\n return out as T;\n }\n return value;\n}\n\n/** Replace NOW_PLACEHOLDER strings with a resolved ISO instant. */\nexport function expandNow<T>(value: T, isoInstant: string): T {\n if (typeof value === \"string\") {\n return value.split(NOW_PLACEHOLDER).join(isoInstant) as T;\n }\n if (Array.isArray(value)) return value.map((v) => expandNow(v, isoInstant)) as T;\n if (value && typeof value === \"object\" && !(value instanceof Date)) {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value)) out[k] = expandNow(v, isoInstant);\n return out as T;\n }\n return value;\n}\n\n/** Agents normalized the way the wire carries them (Date → ISO string). */\nexport function normalizeAgents(agents: AgentInfo[], realHome: string) {\n return sanitize(JSON.parse(JSON.stringify(agents)), realHome);\n}\n\n/**\n * Freeze `Date` at `epochMs` for the duration of `fn`. Adapters stamp\n * `new Date()` in several places; parity requires a fixed clock.\n */\nexport async function withFrozenClock<T>(epochMs: number, fn: () => Promise<T>): Promise<T> {\n const RealDate = Date;\n class FrozenDate extends RealDate {\n constructor(...args: unknown[]) {\n if (args.length === 0) super(epochMs);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n else super(...(args as [any]));\n }\n static override now() {\n return epochMs;\n }\n }\n const g = globalThis as { Date: DateConstructor };\n g.Date = FrozenDate as DateConstructor;\n try {\n return await fn();\n } finally {\n g.Date = RealDate;\n }\n}\n"],"names":["HOME_PLACEHOLDER","NOW_PLACEHOLDER","TODAY_PLACEHOLDER","sanitize","value","realHome","homeDot","split","join","Array","isArray","map","v","Date","toISOString","out","k","Object","entries","expand","fixtureHome","expandNow","isoInstant","normalizeAgents","agents","JSON","parse","stringify","withFrozenClock","epochMs","fn","RealDate","FrozenDate","args","length","now","g","globalThis"],"mappings":"AAAA;;;;;;;;;;;;CAYC,GAID,OAAO,MAAMA,mBAAmB,gBAAgB;AAChD,0EAA0E,GAC1E,OAAO,MAAMC,kBAAkB,OAAO;AACtC,2EAA2E,GAC3E,OAAO,MAAMC,oBAAoB,SAAS;AA+B1C;;;;;;CAMC,GACD,OAAO,SAASC,SAAYC,KAAQ,EAAEC,QAAgB;IACpD,MAAMC,UAAU,GAAGD,SAAS,EAAE,CAAC;IAC/B,IAAI,OAAOD,UAAU,UAAU;QAC7B,OAAOA,MAAMG,KAAK,CAACD,SAASE,IAAI,CAAC,GAAGR,iBAAiB,EAAE,CAAC;IAC1D;IACA,IAAIS,MAAMC,OAAO,CAACN,QAAQ,OAAOA,MAAMO,GAAG,CAAC,CAACC,IAAMT,SAASS,GAAGP;IAC9D,IAAID,SAAS,OAAOA,UAAU,UAAU;QACtC,IAAIA,iBAAiBS,MAAM,OAAOT,MAAMU,WAAW;QACnD,MAAMC,MAA+B,CAAC;QACtC,KAAK,MAAM,CAACC,GAAGJ,EAAE,IAAIK,OAAOC,OAAO,CAACd,OAAQW,GAAG,CAACC,EAAE,GAAGb,SAASS,GAAGP;QACjE,OAAOU;IACT;IACA,OAAOX;AACT;AAEA,mEAAmE,GACnE,OAAO,SAASe,OAAUf,KAAQ,EAAEgB,WAAmB;IACrD,IAAI,OAAOhB,UAAU,UAAU;QAC7B,OAAOA,MAAMG,KAAK,CAACP,kBAAkBQ,IAAI,CAACY;IAC5C;IACA,IAAIX,MAAMC,OAAO,CAACN,QAAQ,OAAOA,MAAMO,GAAG,CAAC,CAACC,IAAMO,OAAOP,GAAGQ;IAC5D,IAAIhB,SAAS,OAAOA,UAAU,YAAY,CAAEA,CAAAA,iBAAiBS,IAAG,GAAI;QAClE,MAAME,MAA+B,CAAC;QACtC,KAAK,MAAM,CAACC,GAAGJ,EAAE,IAAIK,OAAOC,OAAO,CAACd,OAAQW,GAAG,CAACC,EAAE,GAAGG,OAAOP,GAAGQ;QAC/D,OAAOL;IACT;IACA,OAAOX;AACT;AAEA,iEAAiE,GACjE,OAAO,SAASiB,UAAajB,KAAQ,EAAEkB,UAAkB;IACvD,IAAI,OAAOlB,UAAU,UAAU;QAC7B,OAAOA,MAAMG,KAAK,CAACN,iBAAiBO,IAAI,CAACc;IAC3C;IACA,IAAIb,MAAMC,OAAO,CAACN,QAAQ,OAAOA,MAAMO,GAAG,CAAC,CAACC,IAAMS,UAAUT,GAAGU;IAC/D,IAAIlB,SAAS,OAAOA,UAAU,YAAY,CAAEA,CAAAA,iBAAiBS,IAAG,GAAI;QAClE,MAAME,MAA+B,CAAC;QACtC,KAAK,MAAM,CAACC,GAAGJ,EAAE,IAAIK,OAAOC,OAAO,CAACd,OAAQW,GAAG,CAACC,EAAE,GAAGK,UAAUT,GAAGU;QAClE,OAAOP;IACT;IACA,OAAOX;AACT;AAEA,yEAAyE,GACzE,OAAO,SAASmB,gBAAgBC,MAAmB,EAAEnB,QAAgB;IACnE,OAAOF,SAASsB,KAAKC,KAAK,CAACD,KAAKE,SAAS,CAACH,UAAUnB;AACtD;AAEA;;;CAGC,GACD,OAAO,eAAeuB,gBAAmBC,OAAe,EAAEC,EAAoB;IAC5E,MAAMC,WAAWlB;IACjB,IAAA,AAAMmB,aAAN,MAAMA,mBAAmBD;QACvB,YAAY,GAAGE,IAAe,CAAE;YAC9B,IAAIA,KAAKC,MAAM,KAAK,GAAG,KAAK,CAACL;iBAExB,KAAK,IAAKI;QACjB;QACA,OAAgBE,MAAM;YACpB,OAAON;QACT;IACF;IACA,MAAMO,IAAIC;IACVD,EAAEvB,IAAI,GAAGmB;IACT,IAAI;QACF,OAAO,MAAMF;IACf,SAAU;QACRM,EAAEvB,IAAI,GAAGkB;IACX;AACF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capture a live fixture bundle for an adapter: snapshot the real process
|
|
3
|
+
* list, run detectAgents with a frozen clock, and record expected output
|
|
4
|
+
* plus the session files the detection touched.
|
|
5
|
+
*
|
|
6
|
+
* Run via `AI_DEVKIT_FIXTURE_CAPTURE=1 npx vitest run fixtures.capture`.
|
|
7
|
+
*/
|
|
8
|
+
import type { AgentAdapter } from "../adapters/AgentAdapter.js";
|
|
9
|
+
export declare const FIXTURES_ROOT: string;
|
|
10
|
+
export declare function captureLive(adapter: AgentAdapter, caseName?: string): Promise<string>;
|
|
11
|
+
//# sourceMappingURL=capture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../../src/fixtures/capture.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH,OAAO,KAAK,EAAE,YAAY,EAAa,MAAM,6BAA6B,CAAC;AAM3E,eAAO,MAAM,aAAa,QAA6C,CAAC;AAgTxE,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,EAAE,QAAQ,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAwC3F"}
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capture a live fixture bundle for an adapter: snapshot the real process
|
|
3
|
+
* list, run detectAgents with a frozen clock, and record expected output
|
|
4
|
+
* plus the session files the detection touched.
|
|
5
|
+
*
|
|
6
|
+
* Run via `AI_DEVKIT_FIXTURE_CAPTURE=1 npx vitest run fixtures.capture`.
|
|
7
|
+
*/ import * as fs from "node:fs";
|
|
8
|
+
import * as os from "node:os";
|
|
9
|
+
import * as path from "node:path";
|
|
10
|
+
import { fileURLToPath } from "node:url";
|
|
11
|
+
import Database from "better-sqlite3";
|
|
12
|
+
import { AgentRegistry } from "../utils/AgentRegistry.js";
|
|
13
|
+
import { captureProcessSnapshot, snapshotOptions } from "../utils/process.js";
|
|
14
|
+
import { normalizeAgents, sanitize, withFrozenClock } from "./bundle.js";
|
|
15
|
+
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../../..");
|
|
16
|
+
export const FIXTURES_ROOT = path.join(repoRoot, "fixtures", "harness");
|
|
17
|
+
/** Session-file trees each harness consults during detection. */ const HARNESS_DIRS = {
|
|
18
|
+
claude: [
|
|
19
|
+
".claude/sessions",
|
|
20
|
+
".claude/projects"
|
|
21
|
+
],
|
|
22
|
+
codex: [
|
|
23
|
+
".codex/sessions",
|
|
24
|
+
".codex/archived_sessions",
|
|
25
|
+
".codex/ai-devkit"
|
|
26
|
+
],
|
|
27
|
+
pi: [
|
|
28
|
+
".pi/agent/sessions"
|
|
29
|
+
],
|
|
30
|
+
// tmp/<shortId>/{.project_root,chats/*} — small tree; index-style capture
|
|
31
|
+
// keeps the ownership markers replay needs for slug-dir attribution.
|
|
32
|
+
gemini_cli: [
|
|
33
|
+
".gemini/tmp"
|
|
34
|
+
],
|
|
35
|
+
// session-state/<id>/{inuse.*.lock,events.jsonl,workspace.yaml} — the lock
|
|
36
|
+
// files drive attribution, so the whole tree must materialize on replay.
|
|
37
|
+
copilot: [
|
|
38
|
+
".copilot/session-state"
|
|
39
|
+
],
|
|
40
|
+
grok_cli: [
|
|
41
|
+
".grok/sessions"
|
|
42
|
+
],
|
|
43
|
+
// session_locks/<slug>.lock — pid-holder files read on every detect.
|
|
44
|
+
devin: [
|
|
45
|
+
".local/share/devin/cli/session_locks"
|
|
46
|
+
],
|
|
47
|
+
// sessions/cli/<id>.{lock,json,jsonl} — locks drive attribution; the
|
|
48
|
+
// whole flat dir is lightweight enough for index-style capture.
|
|
49
|
+
kiro: [
|
|
50
|
+
".kiro/sessions/cli"
|
|
51
|
+
],
|
|
52
|
+
// antigravity-cli/{cache,brain} — last_conversations.json (small .json
|
|
53
|
+
// aux) plus only the transcripts referenced by matched agents; the
|
|
54
|
+
// brain tree is tens of MB so it stays referenced-only (not index).
|
|
55
|
+
antigravity_cli: [
|
|
56
|
+
".gemini/antigravity-cli"
|
|
57
|
+
]
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Dirs captured wholesale (lock/index trees where every file matters —
|
|
61
|
+
* copilot lock dirs, kiro/devin locks, the codex mapping dir, the gemini
|
|
62
|
+
* tmp tree). Everything else captures agent-referenced session files
|
|
63
|
+
* plus small .json aux files.
|
|
64
|
+
*/ const HARNESS_INDEX_DIRS = new Set([
|
|
65
|
+
".gemini/tmp",
|
|
66
|
+
".copilot/session-state",
|
|
67
|
+
".codex/ai-devkit",
|
|
68
|
+
".local/share/devin/cli/session_locks",
|
|
69
|
+
".kiro/sessions/cli"
|
|
70
|
+
]);
|
|
71
|
+
/** Individual files (not dirs) each harness consults during detection. */ const HARNESS_FILES = {
|
|
72
|
+
pi: [
|
|
73
|
+
".pi/agent/sessions.json"
|
|
74
|
+
],
|
|
75
|
+
grok_cli: [
|
|
76
|
+
".grok/active_sessions.json"
|
|
77
|
+
]
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Copy the harness's session dirs into `home` — only files the detection
|
|
81
|
+
* actually touched (referenced sessionFilePath) plus index/pid files.
|
|
82
|
+
* Transcript trees can be large; we include full files only for sessions
|
|
83
|
+
* that produced an agent, plus every file in lightweight index dirs.
|
|
84
|
+
*/ function collectHomeFiles(adapterType, realHome, agents) {
|
|
85
|
+
const home = {};
|
|
86
|
+
const mtimes = {};
|
|
87
|
+
const referenced = new Set(agents.map((a)=>a.sessionFilePath).filter((p)=>Boolean(p)));
|
|
88
|
+
const put = (rel, file)=>{
|
|
89
|
+
home[rel] = sanitize(fs.readFileSync(file, "utf8"), realHome);
|
|
90
|
+
// Real mtimes are captured too — adapters that read them (Grok
|
|
91
|
+
// lastActive, latest-session pick) replay deterministically.
|
|
92
|
+
mtimes[rel] = fs.statSync(file).mtimeMs;
|
|
93
|
+
};
|
|
94
|
+
for (const relDir of HARNESS_DIRS[adapterType] ?? []){
|
|
95
|
+
const dir = path.join(realHome, relDir);
|
|
96
|
+
if (!fs.existsSync(dir)) continue;
|
|
97
|
+
// Session trees can hold months of transcripts; files that produced no
|
|
98
|
+
// agent cannot influence replayed output, so only agent-referenced
|
|
99
|
+
// session files plus small aux/index files are copied.
|
|
100
|
+
const isIndexDir = HARNESS_INDEX_DIRS.has(relDir);
|
|
101
|
+
walk(dir, (file)=>{
|
|
102
|
+
const rel = path.join(relDir, path.relative(dir, file));
|
|
103
|
+
const isAuxIndex = rel.endsWith("sessions.json") || rel.endsWith(".json");
|
|
104
|
+
if (isIndexDir || referenced.has(file) || isAuxIndex && fileSize(file) < 64 * 1024) {
|
|
105
|
+
put(rel, file);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
for (const relFile of HARNESS_FILES[adapterType] ?? []){
|
|
110
|
+
const file = path.join(realHome, relFile);
|
|
111
|
+
if (fs.existsSync(file) && fileSize(file) < 64 * 1024) {
|
|
112
|
+
put(relFile, file);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
home,
|
|
117
|
+
mtimes
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* SQLite stores adapters consult (OpenCode's opencode.db). Sessions are
|
|
122
|
+
* reachable only through captured processes' cwds, so the dump keeps the
|
|
123
|
+
* table DDL plus every session row for those directories and their
|
|
124
|
+
* message/part rows — replay answers identical queries against the same
|
|
125
|
+
* view. Rows are serialized as executable SQL (binary dbs can't travel in
|
|
126
|
+
* the JSON `home` map); the key is the canonical `~/.local/share` relpath,
|
|
127
|
+
* which replay pins via XDG_DATA_HOME.
|
|
128
|
+
*/ function collectSqliteDumps(adapterType, realHome, processes) {
|
|
129
|
+
const share = process.env.XDG_DATA_HOME || path.join(realHome, ".local", "share");
|
|
130
|
+
if (adapterType === "opencode") {
|
|
131
|
+
return dumpSqliteDb(path.join(share, "opencode", "opencode.db"), ".local/share/opencode/opencode.db", realHome, (dump)=>{
|
|
132
|
+
const dirs = uniqueCwds(processes);
|
|
133
|
+
if (dirs.length === 0) return;
|
|
134
|
+
const sessions = dump.rows("session", `WHERE directory IN ${dump.inList(dirs)} ORDER BY rowid`, dirs);
|
|
135
|
+
const sids = sessions.map((s)=>s.id);
|
|
136
|
+
dump.insertRows("session", sessions);
|
|
137
|
+
if (sids.length === 0) return;
|
|
138
|
+
dump.insertRows("message", dump.rows("message", `WHERE session_id IN ${dump.inList(sids)} ORDER BY rowid`, sids));
|
|
139
|
+
dump.insertRows("part", dump.rows("part", `WHERE session_id IN ${dump.inList(sids)} ORDER BY rowid`, sids));
|
|
140
|
+
}, [
|
|
141
|
+
"session",
|
|
142
|
+
"message",
|
|
143
|
+
"part"
|
|
144
|
+
]);
|
|
145
|
+
}
|
|
146
|
+
if (adapterType === "devin") {
|
|
147
|
+
const dbPath = path.join(share, "devin", "cli", "sessions.db");
|
|
148
|
+
// Locks are captured separately as text files; slugs here widen the
|
|
149
|
+
// session row set so lock-slug lookups resolve identically on replay.
|
|
150
|
+
const lockSids = fs.existsSync(path.join(path.dirname(dbPath), "session_locks")) ? fs.readdirSync(path.join(path.dirname(dbPath), "session_locks")).filter((f)=>f.endsWith(".lock")).map((f)=>f.slice(0, -".lock".length)).filter(Boolean) : [];
|
|
151
|
+
return dumpSqliteDb(dbPath, ".local/share/devin/cli/sessions.db", realHome, (dump)=>{
|
|
152
|
+
const dirs = uniqueCwds(processes);
|
|
153
|
+
const clauses = [];
|
|
154
|
+
const args = [];
|
|
155
|
+
if (dirs.length) {
|
|
156
|
+
clauses.push(`working_directory IN ${dump.inList(dirs)}`);
|
|
157
|
+
args.push(...dirs);
|
|
158
|
+
}
|
|
159
|
+
if (lockSids.length) {
|
|
160
|
+
clauses.push(`id IN ${dump.inList(lockSids)}`);
|
|
161
|
+
args.push(...lockSids);
|
|
162
|
+
}
|
|
163
|
+
const sessions = clauses.length ? dump.rows("sessions", `WHERE ${clauses.join(" OR ")} ORDER BY rowid`, args) : [];
|
|
164
|
+
const sids = sessions.map((s)=>s.id);
|
|
165
|
+
dump.insertRows("sessions", sessions);
|
|
166
|
+
if (sids.length === 0) return;
|
|
167
|
+
// Only the rows getSessionStats can reach: the frontier node, the
|
|
168
|
+
// MAX(created_at) node, the 8 newest role='user' nodes, and the
|
|
169
|
+
// newest non-shell non-slash prompt — identical query results on
|
|
170
|
+
// replay without hauling full transcripts into the bundle.
|
|
171
|
+
for (const sid of sids){
|
|
172
|
+
const reachable = [
|
|
173
|
+
...dump.rows("message_nodes", "WHERE session_id = ? ORDER BY node_id DESC LIMIT 1", [
|
|
174
|
+
sid
|
|
175
|
+
]),
|
|
176
|
+
// The newest-created_at row — `MAX(created_at)` reads only the
|
|
177
|
+
// value, and `= MAX(...)` unbounded explodes when batch-written
|
|
178
|
+
// nodes share a timestamp.
|
|
179
|
+
...dump.rows("message_nodes", "WHERE session_id = ? ORDER BY created_at DESC, node_id DESC LIMIT 1", [
|
|
180
|
+
sid
|
|
181
|
+
]),
|
|
182
|
+
...dump.rows("message_nodes", "WHERE session_id = ? AND json_extract(chat_message, '$.role') = 'user' ORDER BY node_id DESC LIMIT 8", [
|
|
183
|
+
sid
|
|
184
|
+
])
|
|
185
|
+
];
|
|
186
|
+
const seen = new Set();
|
|
187
|
+
dump.insertRows("message_nodes", reachable.filter((r)=>seen.has(r.node_id) ? false : (seen.add(r.node_id), true)));
|
|
188
|
+
dump.insertRows("prompt_history", dump.rows("prompt_history", "WHERE session_id = ? AND is_shell = 0 AND content NOT LIKE '/%' ORDER BY timestamp DESC LIMIT 1", [
|
|
189
|
+
sid
|
|
190
|
+
]));
|
|
191
|
+
}
|
|
192
|
+
}, [
|
|
193
|
+
"sessions",
|
|
194
|
+
"message_nodes",
|
|
195
|
+
"prompt_history"
|
|
196
|
+
]);
|
|
197
|
+
}
|
|
198
|
+
return {};
|
|
199
|
+
}
|
|
200
|
+
function uniqueCwds(processes) {
|
|
201
|
+
return [
|
|
202
|
+
...new Set(processes.map((p)=>p.cwd).filter((c)=>Boolean(c)))
|
|
203
|
+
];
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Dump `dbPath`'s tables (DDL + caller-selected rows) as executable SQL,
|
|
207
|
+
* keyed under `relKey`. `fill` receives helpers that append INSERTs for
|
|
208
|
+
* the rows the adapter's detection can reach.
|
|
209
|
+
*/ function dumpSqliteDb(dbPath, relKey, realHome, fill, tables) {
|
|
210
|
+
if (!fs.existsSync(dbPath)) return {};
|
|
211
|
+
const db = new Database(dbPath, {
|
|
212
|
+
readonly: true
|
|
213
|
+
});
|
|
214
|
+
try {
|
|
215
|
+
const stmts = db.prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name IN (${tables.map(()=>"?").join(",")})`).all(...tables).map((r)=>`${r.sql};`);
|
|
216
|
+
const dump = {
|
|
217
|
+
inList: (xs)=>`(${xs.map(()=>"?").join(",")})`,
|
|
218
|
+
rows: (table, clause, args)=>db.prepare(`SELECT * FROM "${table}" ${clause}`).all(...args),
|
|
219
|
+
insertRows: (table, rs)=>{
|
|
220
|
+
for (const r of rs){
|
|
221
|
+
stmts.push(`INSERT INTO "${table}" VALUES (${Object.values(r).map(sqlLit).join(",")});`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
fill(dump);
|
|
226
|
+
return {
|
|
227
|
+
[relKey]: stmts.map((s)=>sanitize(s, realHome))
|
|
228
|
+
};
|
|
229
|
+
} finally{
|
|
230
|
+
db.close();
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
function sqlLit(v) {
|
|
234
|
+
if (v === null || v === undefined) return "NULL";
|
|
235
|
+
if (typeof v === "number" || typeof v === "bigint") return String(v);
|
|
236
|
+
if (v instanceof Uint8Array) return `X'${Buffer.from(v).toString("hex")}'`;
|
|
237
|
+
return `'${String(v).split("'").join("''")}'`;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Registry rows keyed to captured pids — adapters' registry caches consult
|
|
241
|
+
* them during detection, so replay must see the same view (otherwise
|
|
242
|
+
* ordering/attribution diverges: cache hits precede locator matches).
|
|
243
|
+
*/ function collectRegistryEntries(realHome, processes) {
|
|
244
|
+
const pids = new Set(processes.map((p)=>p.pid));
|
|
245
|
+
try {
|
|
246
|
+
return AgentRegistry.default().list().filter((e)=>pids.has(e.pid)).map((e)=>sanitize({
|
|
247
|
+
...e
|
|
248
|
+
}, realHome));
|
|
249
|
+
} catch {
|
|
250
|
+
return [];
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
function fileSize(file) {
|
|
254
|
+
try {
|
|
255
|
+
return fs.statSync(file).size;
|
|
256
|
+
} catch {
|
|
257
|
+
return Infinity;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
function walk(dir, visit, depth = 0) {
|
|
261
|
+
if (depth > 4) return;
|
|
262
|
+
for (const entry of fs.readdirSync(dir, {
|
|
263
|
+
withFileTypes: true
|
|
264
|
+
})){
|
|
265
|
+
const p = path.join(dir, entry.name);
|
|
266
|
+
if (entry.isDirectory()) walk(p, visit, depth + 1);
|
|
267
|
+
else if (entry.isFile()) visit(p);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
export async function captureLive(adapter, caseName = "live") {
|
|
271
|
+
const realHome = os.homedir();
|
|
272
|
+
const frozenNow = Date.now();
|
|
273
|
+
const names = adapter.processNames;
|
|
274
|
+
if (!names?.length) {
|
|
275
|
+
throw new Error(`adapter ${adapter.type} has no processNames — can't snapshot`);
|
|
276
|
+
}
|
|
277
|
+
const { processes, agents, registry } = await withFrozenClock(frozenNow, async ()=>{
|
|
278
|
+
const prefixes = adapter.processNamePrefixes ? [
|
|
279
|
+
...adapter.processNamePrefixes
|
|
280
|
+
] : [];
|
|
281
|
+
const snapshot = await captureProcessSnapshot([
|
|
282
|
+
...names
|
|
283
|
+
], snapshotOptions(prefixes, (p)=>adapter.canHandle(p)));
|
|
284
|
+
// Registry read must precede detection — detectAgents persists its own
|
|
285
|
+
// results, which would poison the captured view.
|
|
286
|
+
const registryBefore = collectRegistryEntries(realHome, snapshot);
|
|
287
|
+
const detected = await adapter.detectAgents({
|
|
288
|
+
processes: snapshot
|
|
289
|
+
});
|
|
290
|
+
return {
|
|
291
|
+
processes: snapshot,
|
|
292
|
+
agents: detected,
|
|
293
|
+
registry: registryBefore
|
|
294
|
+
};
|
|
295
|
+
});
|
|
296
|
+
const { home, mtimes } = collectHomeFiles(adapter.type, realHome, agents);
|
|
297
|
+
const sqlite = collectSqliteDumps(adapter.type, realHome, processes);
|
|
298
|
+
const bundle = {
|
|
299
|
+
adapter: adapter.type,
|
|
300
|
+
capturedAt: new Date(frozenNow).toISOString(),
|
|
301
|
+
frozenNow,
|
|
302
|
+
processes: sanitize(processes, realHome),
|
|
303
|
+
home,
|
|
304
|
+
mtimes,
|
|
305
|
+
registry,
|
|
306
|
+
sqlite: Object.keys(sqlite).length > 0 ? sqlite : undefined,
|
|
307
|
+
expected: normalizeAgents(agents, realHome)
|
|
308
|
+
};
|
|
309
|
+
const dir = path.join(FIXTURES_ROOT, adapter.type);
|
|
310
|
+
fs.mkdirSync(dir, {
|
|
311
|
+
recursive: true
|
|
312
|
+
});
|
|
313
|
+
const out = path.join(dir, `${caseName}.json`);
|
|
314
|
+
fs.writeFileSync(out, JSON.stringify(bundle, null, 2));
|
|
315
|
+
return out;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
//# sourceMappingURL=capture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/fixtures/capture.ts"],"sourcesContent":["/**\n * Capture a live fixture bundle for an adapter: snapshot the real process\n * list, run detectAgents with a frozen clock, and record expected output\n * plus the session files the detection touched.\n *\n * Run via `AI_DEVKIT_FIXTURE_CAPTURE=1 npx vitest run fixtures.capture`.\n */\n\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport Database from \"better-sqlite3\";\nimport type { AgentAdapter, AgentInfo } from \"../adapters/AgentAdapter.js\";\nimport { AgentRegistry } from \"../utils/AgentRegistry.js\";\nimport { captureProcessSnapshot, snapshotOptions } from \"../utils/process.js\";\nimport { FixtureBundle, normalizeAgents, sanitize, withFrozenClock } from \"./bundle.js\";\n\nconst repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), \"../../../..\");\nexport const FIXTURES_ROOT = path.join(repoRoot, \"fixtures\", \"harness\");\n\n/** Session-file trees each harness consults during detection. */\nconst HARNESS_DIRS: Record<string, string[]> = {\n claude: [\".claude/sessions\", \".claude/projects\"],\n codex: [\".codex/sessions\", \".codex/archived_sessions\", \".codex/ai-devkit\"],\n pi: [\".pi/agent/sessions\"],\n // tmp/<shortId>/{.project_root,chats/*} — small tree; index-style capture\n // keeps the ownership markers replay needs for slug-dir attribution.\n gemini_cli: [\".gemini/tmp\"],\n // session-state/<id>/{inuse.*.lock,events.jsonl,workspace.yaml} — the lock\n // files drive attribution, so the whole tree must materialize on replay.\n copilot: [\".copilot/session-state\"],\n grok_cli: [\".grok/sessions\"],\n // session_locks/<slug>.lock — pid-holder files read on every detect.\n devin: [\".local/share/devin/cli/session_locks\"],\n // sessions/cli/<id>.{lock,json,jsonl} — locks drive attribution; the\n // whole flat dir is lightweight enough for index-style capture.\n kiro: [\".kiro/sessions/cli\"],\n // antigravity-cli/{cache,brain} — last_conversations.json (small .json\n // aux) plus only the transcripts referenced by matched agents; the\n // brain tree is tens of MB so it stays referenced-only (not index).\n antigravity_cli: [\".gemini/antigravity-cli\"],\n};\n\n/**\n * Dirs captured wholesale (lock/index trees where every file matters —\n * copilot lock dirs, kiro/devin locks, the codex mapping dir, the gemini\n * tmp tree). Everything else captures agent-referenced session files\n * plus small .json aux files.\n */\nconst HARNESS_INDEX_DIRS = new Set([\n \".gemini/tmp\",\n \".copilot/session-state\",\n \".codex/ai-devkit\",\n \".local/share/devin/cli/session_locks\",\n \".kiro/sessions/cli\",\n]);\n\n/** Individual files (not dirs) each harness consults during detection. */\nconst HARNESS_FILES: Record<string, string[]> = {\n pi: [\".pi/agent/sessions.json\"],\n grok_cli: [\".grok/active_sessions.json\"],\n};\n\n/**\n * Copy the harness's session dirs into `home` — only files the detection\n * actually touched (referenced sessionFilePath) plus index/pid files.\n * Transcript trees can be large; we include full files only for sessions\n * that produced an agent, plus every file in lightweight index dirs.\n */\nfunction collectHomeFiles(\n adapterType: string,\n realHome: string,\n agents: AgentInfo[],\n): { home: Record<string, string>; mtimes: Record<string, number> } {\n const home: Record<string, string> = {};\n const mtimes: Record<string, number> = {};\n const referenced = new Set(\n agents.map((a) => a.sessionFilePath).filter((p): p is string => Boolean(p)),\n );\n\n const put = (rel: string, file: string) => {\n home[rel] = sanitize(fs.readFileSync(file, \"utf8\"), realHome);\n // Real mtimes are captured too — adapters that read them (Grok\n // lastActive, latest-session pick) replay deterministically.\n mtimes[rel] = fs.statSync(file).mtimeMs;\n };\n\n for (const relDir of HARNESS_DIRS[adapterType] ?? []) {\n const dir = path.join(realHome, relDir);\n if (!fs.existsSync(dir)) continue;\n // Session trees can hold months of transcripts; files that produced no\n // agent cannot influence replayed output, so only agent-referenced\n // session files plus small aux/index files are copied.\n const isIndexDir = HARNESS_INDEX_DIRS.has(relDir);\n walk(dir, (file) => {\n const rel = path.join(relDir, path.relative(dir, file));\n const isAuxIndex = rel.endsWith(\"sessions.json\") || rel.endsWith(\".json\");\n if (isIndexDir || referenced.has(file) || (isAuxIndex && fileSize(file) < 64 * 1024)) {\n put(rel, file);\n }\n });\n }\n for (const relFile of HARNESS_FILES[adapterType] ?? []) {\n const file = path.join(realHome, relFile);\n if (fs.existsSync(file) && fileSize(file) < 64 * 1024) {\n put(relFile, file);\n }\n }\n return { home, mtimes };\n}\n\n/**\n * SQLite stores adapters consult (OpenCode's opencode.db). Sessions are\n * reachable only through captured processes' cwds, so the dump keeps the\n * table DDL plus every session row for those directories and their\n * message/part rows — replay answers identical queries against the same\n * view. Rows are serialized as executable SQL (binary dbs can't travel in\n * the JSON `home` map); the key is the canonical `~/.local/share` relpath,\n * which replay pins via XDG_DATA_HOME.\n */\nfunction collectSqliteDumps(\n adapterType: string,\n realHome: string,\n processes: { cwd?: string | null }[],\n): Record<string, string[]> {\n const share = process.env.XDG_DATA_HOME || path.join(realHome, \".local\", \"share\");\n if (adapterType === \"opencode\") {\n return dumpSqliteDb(\n path.join(share, \"opencode\", \"opencode.db\"),\n \".local/share/opencode/opencode.db\",\n realHome,\n (dump) => {\n const dirs = uniqueCwds(processes);\n if (dirs.length === 0) return;\n const sessions = dump.rows(\n \"session\",\n `WHERE directory IN ${dump.inList(dirs)} ORDER BY rowid`,\n dirs,\n );\n const sids = sessions.map((s) => s.id);\n dump.insertRows(\"session\", sessions);\n if (sids.length === 0) return;\n dump.insertRows(\n \"message\",\n dump.rows(\"message\", `WHERE session_id IN ${dump.inList(sids)} ORDER BY rowid`, sids),\n );\n dump.insertRows(\n \"part\",\n dump.rows(\"part\", `WHERE session_id IN ${dump.inList(sids)} ORDER BY rowid`, sids),\n );\n },\n [\"session\", \"message\", \"part\"],\n );\n }\n if (adapterType === \"devin\") {\n const dbPath = path.join(share, \"devin\", \"cli\", \"sessions.db\");\n // Locks are captured separately as text files; slugs here widen the\n // session row set so lock-slug lookups resolve identically on replay.\n const lockSids = fs.existsSync(path.join(path.dirname(dbPath), \"session_locks\"))\n ? fs\n .readdirSync(path.join(path.dirname(dbPath), \"session_locks\"))\n .filter((f) => f.endsWith(\".lock\"))\n .map((f) => f.slice(0, -\".lock\".length))\n .filter(Boolean)\n : [];\n return dumpSqliteDb(\n dbPath,\n \".local/share/devin/cli/sessions.db\",\n realHome,\n (dump) => {\n const dirs = uniqueCwds(processes);\n const clauses: string[] = [];\n const args: unknown[] = [];\n if (dirs.length) {\n clauses.push(`working_directory IN ${dump.inList(dirs)}`);\n args.push(...dirs);\n }\n if (lockSids.length) {\n clauses.push(`id IN ${dump.inList(lockSids)}`);\n args.push(...lockSids);\n }\n const sessions = clauses.length\n ? dump.rows(\"sessions\", `WHERE ${clauses.join(\" OR \")} ORDER BY rowid`, args)\n : [];\n const sids = sessions.map((s) => s.id);\n dump.insertRows(\"sessions\", sessions);\n if (sids.length === 0) return;\n // Only the rows getSessionStats can reach: the frontier node, the\n // MAX(created_at) node, the 8 newest role='user' nodes, and the\n // newest non-shell non-slash prompt — identical query results on\n // replay without hauling full transcripts into the bundle.\n for (const sid of sids) {\n const reachable = [\n ...dump.rows(\"message_nodes\", \"WHERE session_id = ? ORDER BY node_id DESC LIMIT 1\", [\n sid,\n ]),\n // The newest-created_at row — `MAX(created_at)` reads only the\n // value, and `= MAX(...)` unbounded explodes when batch-written\n // nodes share a timestamp.\n ...dump.rows(\n \"message_nodes\",\n \"WHERE session_id = ? ORDER BY created_at DESC, node_id DESC LIMIT 1\",\n [sid],\n ),\n ...dump.rows(\n \"message_nodes\",\n \"WHERE session_id = ? AND json_extract(chat_message, '$.role') = 'user' ORDER BY node_id DESC LIMIT 8\",\n [sid],\n ),\n ];\n const seen = new Set<unknown>();\n dump.insertRows(\n \"message_nodes\",\n reachable.filter((r) => (seen.has(r.node_id) ? false : (seen.add(r.node_id), true))),\n );\n dump.insertRows(\n \"prompt_history\",\n dump.rows(\n \"prompt_history\",\n \"WHERE session_id = ? AND is_shell = 0 AND content NOT LIKE '/%' ORDER BY timestamp DESC LIMIT 1\",\n [sid],\n ),\n );\n }\n },\n [\"sessions\", \"message_nodes\", \"prompt_history\"],\n );\n }\n return {};\n}\n\nfunction uniqueCwds(processes: { cwd?: string | null }[]): string[] {\n return [...new Set(processes.map((p) => p.cwd).filter((c): c is string => Boolean(c)))];\n}\n\n/**\n * Dump `dbPath`'s tables (DDL + caller-selected rows) as executable SQL,\n * keyed under `relKey`. `fill` receives helpers that append INSERTs for\n * the rows the adapter's detection can reach.\n */\nfunction dumpSqliteDb(\n dbPath: string,\n relKey: string,\n realHome: string,\n fill: (dump: {\n inList: (xs: unknown[]) => string;\n rows: (table: string, where: string, args: unknown[]) => Record<string, unknown>[];\n insertRows: (table: string, rs: Record<string, unknown>[]) => void;\n }) => void,\n tables: string[],\n): Record<string, string[]> {\n if (!fs.existsSync(dbPath)) return {};\n const db = new Database(dbPath, { readonly: true });\n try {\n const stmts = (\n db\n .prepare(\n `SELECT sql FROM sqlite_master WHERE type='table' AND name IN (${tables.map(() => \"?\").join(\",\")})`,\n )\n .all(...tables) as { sql: string }[]\n ).map((r) => `${r.sql};`);\n const dump = {\n inList: (xs: unknown[]) => `(${xs.map(() => \"?\").join(\",\")})`,\n rows: (table: string, clause: string, args: unknown[]) =>\n db.prepare(`SELECT * FROM \"${table}\" ${clause}`).all(...args) as Record<string, unknown>[],\n insertRows: (table: string, rs: Record<string, unknown>[]) => {\n for (const r of rs) {\n stmts.push(`INSERT INTO \"${table}\" VALUES (${Object.values(r).map(sqlLit).join(\",\")});`);\n }\n },\n };\n fill(dump);\n return { [relKey]: stmts.map((s) => sanitize(s, realHome)) };\n } finally {\n db.close();\n }\n}\n\nfunction sqlLit(v: unknown): string {\n if (v === null || v === undefined) return \"NULL\";\n if (typeof v === \"number\" || typeof v === \"bigint\") return String(v);\n if (v instanceof Uint8Array) return `X'${Buffer.from(v).toString(\"hex\")}'`;\n return `'${String(v).split(\"'\").join(\"''\")}'`;\n}\n\n/**\n * Registry rows keyed to captured pids — adapters' registry caches consult\n * them during detection, so replay must see the same view (otherwise\n * ordering/attribution diverges: cache hits precede locator matches).\n */\nfunction collectRegistryEntries(\n realHome: string,\n processes: { pid: number }[],\n): Record<string, unknown>[] {\n const pids = new Set(processes.map((p) => p.pid));\n try {\n return AgentRegistry.default()\n .list()\n .filter((e) => pids.has(e.pid))\n .map((e) => sanitize({ ...e }, realHome) as Record<string, unknown>);\n } catch {\n return [];\n }\n}\n\nfunction fileSize(file: string): number {\n try {\n return fs.statSync(file).size;\n } catch {\n return Infinity;\n }\n}\n\nfunction walk(dir: string, visit: (file: string) => void, depth = 0) {\n if (depth > 4) return;\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const p = path.join(dir, entry.name);\n if (entry.isDirectory()) walk(p, visit, depth + 1);\n else if (entry.isFile()) visit(p);\n }\n}\n\nexport async function captureLive(adapter: AgentAdapter, caseName = \"live\"): Promise<string> {\n const realHome = os.homedir();\n const frozenNow = Date.now();\n const names = adapter.processNames;\n if (!names?.length) {\n throw new Error(`adapter ${adapter.type} has no processNames — can't snapshot`);\n }\n\n const { processes, agents, registry } = await withFrozenClock(frozenNow, async () => {\n const prefixes = adapter.processNamePrefixes ? [...adapter.processNamePrefixes] : [];\n const snapshot = await captureProcessSnapshot(\n [...names],\n snapshotOptions(prefixes, (p) => adapter.canHandle(p)),\n );\n // Registry read must precede detection — detectAgents persists its own\n // results, which would poison the captured view.\n const registryBefore = collectRegistryEntries(realHome, snapshot);\n const detected = await adapter.detectAgents({ processes: snapshot });\n return { processes: snapshot, agents: detected, registry: registryBefore };\n });\n\n const { home, mtimes } = collectHomeFiles(adapter.type, realHome, agents);\n const sqlite = collectSqliteDumps(adapter.type, realHome, processes);\n const bundle: FixtureBundle = {\n adapter: adapter.type,\n capturedAt: new Date(frozenNow).toISOString(),\n frozenNow,\n processes: sanitize(processes, realHome),\n home,\n mtimes,\n registry,\n sqlite: Object.keys(sqlite).length > 0 ? sqlite : undefined,\n expected: normalizeAgents(agents, realHome),\n };\n\n const dir = path.join(FIXTURES_ROOT, adapter.type);\n fs.mkdirSync(dir, { recursive: true });\n const out = path.join(dir, `${caseName}.json`);\n fs.writeFileSync(out, JSON.stringify(bundle, null, 2));\n return out;\n}\n"],"names":["fs","os","path","fileURLToPath","Database","AgentRegistry","captureProcessSnapshot","snapshotOptions","normalizeAgents","sanitize","withFrozenClock","repoRoot","resolve","dirname","url","FIXTURES_ROOT","join","HARNESS_DIRS","claude","codex","pi","gemini_cli","copilot","grok_cli","devin","kiro","antigravity_cli","HARNESS_INDEX_DIRS","Set","HARNESS_FILES","collectHomeFiles","adapterType","realHome","agents","home","mtimes","referenced","map","a","sessionFilePath","filter","p","Boolean","put","rel","file","readFileSync","statSync","mtimeMs","relDir","dir","existsSync","isIndexDir","has","walk","relative","isAuxIndex","endsWith","fileSize","relFile","collectSqliteDumps","processes","share","process","env","XDG_DATA_HOME","dumpSqliteDb","dump","dirs","uniqueCwds","length","sessions","rows","inList","sids","s","id","insertRows","dbPath","lockSids","readdirSync","f","slice","clauses","args","push","sid","reachable","seen","r","node_id","add","cwd","c","relKey","fill","tables","db","readonly","stmts","prepare","all","sql","xs","table","clause","rs","Object","values","sqlLit","close","v","undefined","String","Uint8Array","Buffer","from","toString","split","collectRegistryEntries","pids","pid","default","list","e","size","Infinity","visit","depth","entry","withFileTypes","name","isDirectory","isFile","captureLive","adapter","caseName","homedir","frozenNow","Date","now","names","processNames","Error","type","registry","prefixes","processNamePrefixes","snapshot","canHandle","registryBefore","detected","detectAgents","sqlite","bundle","capturedAt","toISOString","keys","expected","mkdirSync","recursive","out","writeFileSync","JSON","stringify"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DevinAdapter.d.ts","sourceRoot":"","sources":["../../../src/harnesses/devin/DevinAdapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,SAAS,EACT,WAAW,EACX,mBAAmB,EACnB,mBAAmB,EACnB,cAAc,EACd,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"DevinAdapter.d.ts","sourceRoot":"","sources":["../../../src/harnesses/devin/DevinAdapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,SAAS,EACT,WAAW,EACX,mBAAmB,EACnB,mBAAmB,EACnB,cAAc,EACd,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,gCAAgC,CAAC;AAgFxC,qBAAa,YAAa,YAAW,YAAY;IAC/C,QAAQ,CAAC,IAAI,EAAG,OAAO,CAAU;IACjC,QAAQ,CAAC,YAAY,qBAAsB;IAE3C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmB;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;gBAExC,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;IAU9C,KAAK,IAAI,IAAI;IAOb,SAAS,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO;IAMtC,YAAY,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IA6CzE,eAAe,CAAC,eAAe,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,mBAAmB,EAAE;IAUxF,YAAY,CAAC,IAAI,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAInE,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAIpE;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;CAK1B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/harnesses/devin/DevinAdapter.ts"],"sourcesContent":["/**\n * Devin Adapter\n *\n * Detects running Devin CLI agents by:\n * 1. Filtering `devin` processes from a shared process snapshot, rejecting\n * utility subcommands (list, doctor, ssh, ...) and `devin acp` children\n * spawned by a Devin TUI\n * 2. Matching processes to sessions via `session_locks/<slug>.lock` files,\n * which contain the PID of the session's `devin acp` backend (lock-first;\n * a TUI is matched through its backend child's ppid)\n * 3. Falling back to `sessions.working_directory` matching in\n * ~/.local/share/devin/cli/sessions.db (WAL SQLite, opened read-only)\n *\n * sessionFilePath encodes \"<dbPath>::<sessionSlug>\" so getConversation() can\n * address a session row without extending the AgentAdapter interface.\n */\n\nimport type {\n AgentAdapter,\n AgentInfo,\n ProcessInfo,\n ConversationMessage,\n ConversationOptions,\n SessionSummary,\n ListSessionsOptions,\n AgentDetectionContext,\n} from \"../../adapters/AgentAdapter.js\";\nimport { DevinAgentMapper } from \"./DevinAgentMapper.js\";\nimport { DevinSessionLocator, decodeDevinSessionRef } from \"./DevinSessionLocator.js\";\nimport { DevinSessionParser } from \"./DevinSessionParser.js\";\nimport { findHarnessProcesses, matchesExecutable } from \"../shared.js\";\nimport { executablePath } from \"../../utils/process.js\";\n\n/**\n * `devin` invocations that are utilities, not agent sessions. `acp` is\n * deliberately absent: a standalone `devin acp` serves an external client\n * and is itself an agent.\n */\nconst UTILITY_SUBCOMMANDS = new Set([\n \"auth\",\n \"cloud\",\n \"desktop\",\n \"doctor\",\n \"forward\",\n \"help\",\n \"list\",\n \"ls\",\n \"mcp\",\n \"migrate\",\n \"models\",\n \"plugins\",\n \"rm\",\n \"rules\",\n \"sandbox\",\n \"setup\",\n \"skills\",\n \"ssh\",\n \"uninstall\",\n \"update\",\n \"version\",\n]);\n\n/**\n * Flags that always consume the next argv token as their value.\n * (`devin --help`, main-command options.)\n */\nconst REQUIRED_VALUE_FLAGS = new Set([\n \"--prompt-file\",\n \"--config\",\n \"--permission-mode\",\n \"--model\",\n]);\n\n/**\n * Flags whose value is optional: the next token is consumed only when it\n * isn't itself a flag (commander `[<VALUE>]` semantics).\n */\nconst OPTIONAL_VALUE_FLAGS = new Set([\n \"-p\",\n \"--print\",\n \"-r\",\n \"--resume\",\n \"--export\",\n \"--respect-workspace-trust\",\n]);\n\n/**\n * First positional argv token after argv[0] — the subcommand candidate.\n * Flag values are skipped (so `devin -p \"update deps\"` isn't mistaken for\n * the `update` subcommand); `--` ends the search.\n */\nfunction firstPositionalToken(command: string): string | null {\n const argv0 = executablePath(command);\n const tokens = command\n .trim()\n .slice(argv0.length)\n .trim()\n .split(/\\s+/);\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i];\n if (!token) continue;\n if (token === \"--\") return null;\n if (!token.startsWith(\"-\")) return token;\n const flag = token.split(\"=\", 1)[0];\n if (flag === token) {\n if (REQUIRED_VALUE_FLAGS.has(flag)) {\n i++;\n } else if (OPTIONAL_VALUE_FLAGS.has(flag) && !tokens[i + 1]?.startsWith(\"-\")) {\n i++;\n }\n }\n }\n return null;\n}\n\nexport class DevinAdapter implements AgentAdapter {\n readonly type = \"devin\" as const;\n readonly processNames = [\"devin\"] as const;\n\n private readonly parser: DevinSessionParser;\n private readonly locator: DevinSessionLocator;\n private readonly mapper: DevinAgentMapper;\n private readonly cleanup = (): void => this.close();\n\n constructor(dbPath?: string, locksDir?: string) {\n this.parser = new DevinSessionParser();\n // Locator defaults resolve dbPath itself and derive locksDir from it.\n this.locator = new DevinSessionLocator(dbPath, locksDir, this.parser);\n this.mapper = new DevinAgentMapper(this.locator.dbFilePath);\n process.once(\"exit\", this.cleanup);\n process.once(\"SIGINT\", this.cleanup);\n process.once(\"SIGTERM\", this.cleanup);\n }\n\n close(): void {\n process.off(\"exit\", this.cleanup);\n process.off(\"SIGINT\", this.cleanup);\n process.off(\"SIGTERM\", this.cleanup);\n this.locator.close();\n }\n\n canHandle(processInfo: ProcessInfo): boolean {\n if (!matchesExecutable(processInfo.command, \"devin\")) return false;\n const subcommand = firstPositionalToken(processInfo.command);\n return subcommand === null || !UTILITY_SUBCOMMANDS.has(subcommand.toLowerCase());\n }\n\n async detectAgents(context?: AgentDetectionContext): Promise<AgentInfo[]> {\n const { processes } = await findHarnessProcesses(this, context);\n if (processes.length === 0) return [];\n\n const db = this.locator.openDb();\n const processByPid = new Map(processes.map((proc) => [proc.pid, proc]));\n\n // Locks map a session to its holder PID (the `devin acp` backend); a TUI\n // is matched through its backend child's ppid. Only trust locks whose\n // holder is a live devin process in this snapshot (stale files and PID\n // reuse are filtered out).\n const sessionByPid = new Map<number, string>();\n for (const lock of this.locator.listActiveLocks()) {\n const holder = processByPid.get(lock.pid);\n if (!holder || !this.canHandle(holder)) continue;\n sessionByPid.set(lock.pid, lock.sessionId);\n if (holder.ppid !== undefined) sessionByPid.set(holder.ppid, lock.sessionId);\n }\n\n const agents: AgentInfo[] = [];\n\n for (const proc of processes) {\n if (this.isAcpBackendChild(proc, processByPid)) continue;\n\n const slug = sessionByPid.get(proc.pid);\n const session = !db\n ? null\n : slug\n ? this.locator.findSessionById(db, slug)\n : proc.cwd\n ? this.locator.findSessionForDirectory(db, proc.cwd)\n : null;\n\n if (!session || !db) {\n agents.push(this.mapper.mapProcessOnlyAgent(proc));\n continue;\n }\n\n const stats = this.parser.getSessionStats(db, session.sessionId);\n agents.push(this.mapper.mapSessionToAgent(session, stats, proc));\n }\n\n return agents;\n }\n\n getConversation(sessionFilePath: string, options?: ConversationOptions): ConversationMessage[] {\n const sessionId = decodeDevinSessionRef(sessionFilePath);\n if (!sessionId) return [];\n\n const db = this.locator.openDb();\n if (!db) return [];\n\n return this.parser.getConversation(db, sessionId, options);\n }\n\n async listSessions(opts?: ListSessionsOptions): Promise<SessionSummary[]> {\n return this.locator.listSessions(opts);\n }\n\n async findSessionsById(sessionId: string): Promise<SessionSummary[]> {\n return this.locator.findSessionsById(sessionId);\n }\n\n /**\n * A `devin acp` process spawned by another devin process is that session's\n * backend, not a separate agent. Standalone `acp` processes (external ACP\n * clients) keep their own agent entry.\n */\n private isAcpBackendChild(\n proc: ProcessInfo,\n processByPid: Map<number, ProcessInfo>,\n ): boolean {\n if (firstPositionalToken(proc.command)?.toLowerCase() !== \"acp\") return false;\n if (proc.ppid === undefined) return false;\n return processByPid.has(proc.ppid);\n }\n}\n"],"names":["DevinAgentMapper","DevinSessionLocator","decodeDevinSessionRef","DevinSessionParser","findHarnessProcesses","matchesExecutable","executablePath","UTILITY_SUBCOMMANDS","Set","REQUIRED_VALUE_FLAGS","OPTIONAL_VALUE_FLAGS","firstPositionalToken","command","argv0","tokens","trim","slice","length","split","i","token","startsWith","flag","has","DevinAdapter","type","processNames","parser","locator","mapper","cleanup","close","dbPath","locksDir","dbFilePath","process","once","off","canHandle","processInfo","subcommand","toLowerCase","detectAgents","context","processes","db","openDb","processByPid","Map","map","proc","pid","sessionByPid","lock","listActiveLocks","holder","get","set","sessionId","ppid","undefined","agents","isAcpBackendChild","slug","session","findSessionById","cwd","findSessionForDirectory","push","mapProcessOnlyAgent","stats","getSessionStats","mapSessionToAgent","getConversation","sessionFilePath","options","listSessions","opts","findSessionsById"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/harnesses/devin/DevinAdapter.ts"],"sourcesContent":["/**\n * Devin Adapter\n *\n * Detects running Devin CLI agents by:\n * 1. Filtering `devin` processes from a shared process snapshot, rejecting\n * utility subcommands (list, doctor, ssh, ...) and `devin acp` children\n * spawned by a Devin TUI\n * 2. Matching processes to sessions via `session_locks/<slug>.lock` files,\n * which contain the PID of the session's `devin acp` backend (lock-first;\n * a TUI is matched through its backend child's ppid)\n * 3. Falling back to `sessions.working_directory` matching in\n * ~/.local/share/devin/cli/sessions.db (WAL SQLite, opened read-only)\n *\n * sessionFilePath encodes \"<dbPath>::<sessionSlug>\" so getConversation() can\n * address a session row without extending the AgentAdapter interface.\n */\n\nimport type {\n AgentAdapter,\n AgentInfo,\n ProcessInfo,\n ConversationMessage,\n ConversationOptions,\n SessionSummary,\n ListSessionsOptions,\n AgentDetectionContext,\n} from \"../../adapters/AgentAdapter.js\";\nimport { DevinAgentMapper } from \"./DevinAgentMapper.js\";\nimport { DevinSessionLocator, decodeDevinSessionRef } from \"./DevinSessionLocator.js\";\nimport { DevinSessionParser } from \"./DevinSessionParser.js\";\nimport { findHarnessProcesses, matchesExecutable } from \"../shared.js\";\nimport { executablePath } from \"../../utils/process.js\";\n\n/**\n * `devin` invocations that are utilities, not agent sessions. `acp` is\n * deliberately absent: a standalone `devin acp` serves an external client\n * and is itself an agent.\n */\nconst UTILITY_SUBCOMMANDS = new Set([\n \"auth\",\n \"cloud\",\n \"desktop\",\n \"doctor\",\n \"forward\",\n \"help\",\n \"list\",\n \"ls\",\n \"mcp\",\n \"migrate\",\n \"models\",\n \"plugins\",\n \"rm\",\n \"rules\",\n \"sandbox\",\n \"setup\",\n \"skills\",\n \"ssh\",\n \"uninstall\",\n \"update\",\n \"version\",\n]);\n\n/**\n * Flags that always consume the next argv token as their value.\n * (`devin --help`, main-command options.)\n */\nconst REQUIRED_VALUE_FLAGS = new Set([\"--prompt-file\", \"--config\", \"--permission-mode\", \"--model\"]);\n\n/**\n * Flags whose value is optional: the next token is consumed only when it\n * isn't itself a flag (commander `[<VALUE>]` semantics).\n */\nconst OPTIONAL_VALUE_FLAGS = new Set([\n \"-p\",\n \"--print\",\n \"-r\",\n \"--resume\",\n \"--export\",\n \"--respect-workspace-trust\",\n]);\n\n/**\n * First positional argv token after argv[0] — the subcommand candidate.\n * Flag values are skipped (so `devin -p \"update deps\"` isn't mistaken for\n * the `update` subcommand); `--` ends the search.\n */\nfunction firstPositionalToken(command: string): string | null {\n const argv0 = executablePath(command);\n const tokens = command.trim().slice(argv0.length).trim().split(/\\s+/);\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i];\n if (!token) continue;\n if (token === \"--\") return null;\n if (!token.startsWith(\"-\")) return token;\n const flag = token.split(\"=\", 1)[0];\n if (flag === token) {\n if (REQUIRED_VALUE_FLAGS.has(flag)) {\n i++;\n } else if (OPTIONAL_VALUE_FLAGS.has(flag) && !tokens[i + 1]?.startsWith(\"-\")) {\n i++;\n }\n }\n }\n return null;\n}\n\nexport class DevinAdapter implements AgentAdapter {\n readonly type = \"devin\" as const;\n readonly processNames = [\"devin\"] as const;\n\n private readonly parser: DevinSessionParser;\n private readonly locator: DevinSessionLocator;\n private readonly mapper: DevinAgentMapper;\n private readonly cleanup = (): void => this.close();\n\n constructor(dbPath?: string, locksDir?: string) {\n this.parser = new DevinSessionParser();\n // Locator defaults resolve dbPath itself and derive locksDir from it.\n this.locator = new DevinSessionLocator(dbPath, locksDir, this.parser);\n this.mapper = new DevinAgentMapper(this.locator.dbFilePath);\n process.once(\"exit\", this.cleanup);\n process.once(\"SIGINT\", this.cleanup);\n process.once(\"SIGTERM\", this.cleanup);\n }\n\n close(): void {\n process.off(\"exit\", this.cleanup);\n process.off(\"SIGINT\", this.cleanup);\n process.off(\"SIGTERM\", this.cleanup);\n this.locator.close();\n }\n\n canHandle(processInfo: ProcessInfo): boolean {\n if (!matchesExecutable(processInfo.command, \"devin\")) return false;\n const subcommand = firstPositionalToken(processInfo.command);\n return subcommand === null || !UTILITY_SUBCOMMANDS.has(subcommand.toLowerCase());\n }\n\n async detectAgents(context?: AgentDetectionContext): Promise<AgentInfo[]> {\n const { processes } = await findHarnessProcesses(this, context);\n if (processes.length === 0) return [];\n\n const db = this.locator.openDb();\n const processByPid = new Map(processes.map((proc) => [proc.pid, proc]));\n\n // Locks map a session to its holder PID (the `devin acp` backend); a TUI\n // is matched through its backend child's ppid. Only trust locks whose\n // holder is a live devin process in this snapshot (stale files and PID\n // reuse are filtered out).\n const sessionByPid = new Map<number, string>();\n for (const lock of this.locator.listActiveLocks()) {\n const holder = processByPid.get(lock.pid);\n if (!holder || !this.canHandle(holder)) continue;\n sessionByPid.set(lock.pid, lock.sessionId);\n if (holder.ppid !== undefined) sessionByPid.set(holder.ppid, lock.sessionId);\n }\n\n const agents: AgentInfo[] = [];\n\n for (const proc of processes) {\n if (this.isAcpBackendChild(proc, processByPid)) continue;\n\n const slug = sessionByPid.get(proc.pid);\n const session = !db\n ? null\n : slug\n ? this.locator.findSessionById(db, slug)\n : proc.cwd\n ? this.locator.findSessionForDirectory(db, proc.cwd)\n : null;\n\n if (!session || !db) {\n agents.push(this.mapper.mapProcessOnlyAgent(proc));\n continue;\n }\n\n const stats = this.parser.getSessionStats(db, session.sessionId);\n agents.push(this.mapper.mapSessionToAgent(session, stats, proc));\n }\n\n return agents;\n }\n\n getConversation(sessionFilePath: string, options?: ConversationOptions): ConversationMessage[] {\n const sessionId = decodeDevinSessionRef(sessionFilePath);\n if (!sessionId) return [];\n\n const db = this.locator.openDb();\n if (!db) return [];\n\n return this.parser.getConversation(db, sessionId, options);\n }\n\n async listSessions(opts?: ListSessionsOptions): Promise<SessionSummary[]> {\n return this.locator.listSessions(opts);\n }\n\n async findSessionsById(sessionId: string): Promise<SessionSummary[]> {\n return this.locator.findSessionsById(sessionId);\n }\n\n /**\n * A `devin acp` process spawned by another devin process is that session's\n * backend, not a separate agent. Standalone `acp` processes (external ACP\n * clients) keep their own agent entry.\n */\n private isAcpBackendChild(proc: ProcessInfo, processByPid: Map<number, ProcessInfo>): boolean {\n if (firstPositionalToken(proc.command)?.toLowerCase() !== \"acp\") return false;\n if (proc.ppid === undefined) return false;\n return processByPid.has(proc.ppid);\n }\n}\n"],"names":["DevinAgentMapper","DevinSessionLocator","decodeDevinSessionRef","DevinSessionParser","findHarnessProcesses","matchesExecutable","executablePath","UTILITY_SUBCOMMANDS","Set","REQUIRED_VALUE_FLAGS","OPTIONAL_VALUE_FLAGS","firstPositionalToken","command","argv0","tokens","trim","slice","length","split","i","token","startsWith","flag","has","DevinAdapter","type","processNames","parser","locator","mapper","cleanup","close","dbPath","locksDir","dbFilePath","process","once","off","canHandle","processInfo","subcommand","toLowerCase","detectAgents","context","processes","db","openDb","processByPid","Map","map","proc","pid","sessionByPid","lock","listActiveLocks","holder","get","set","sessionId","ppid","undefined","agents","isAcpBackendChild","slug","session","findSessionById","cwd","findSessionForDirectory","push","mapProcessOnlyAgent","stats","getSessionStats","mapSessionToAgent","getConversation","sessionFilePath","options","listSessions","opts","findSessionsById"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DevinAgentMapper.d.ts","sourceRoot":"","sources":["../../../src/harnesses/devin/DevinAgentMapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAG7E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAGjE,qBAAa,gBAAgB;IACf,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAE3C,iBAAiB,
|
|
1
|
+
{"version":3,"file":"DevinAgentMapper.d.ts","sourceRoot":"","sources":["../../../src/harnesses/devin/DevinAgentMapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAG7E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAGjE,qBAAa,gBAAgB;IACf,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAE3C,iBAAiB,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE,WAAW,GAAG,SAAS;IAmBhG,mBAAmB,CAAC,IAAI,EAAE,WAAW,GAAG,SAAS;IAIjD,OAAO,CAAC,eAAe;CAIxB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/harnesses/devin/DevinAgentMapper.ts"],"sourcesContent":["import type { AgentInfo, ProcessInfo } from \"../../adapters/AgentAdapter.js\";\nimport { AgentStatus } from \"../../adapters/AgentAdapter.js\";\nimport { generateAgentName } from \"../../utils/matching.js\";\nimport type { DevinSession } from \"./DevinSessionLocator.js\";\nimport { encodeDevinSessionRef } from \"./DevinSessionLocator.js\";\nimport type { DevinSessionStats } from \"./DevinSessionParser.js\";\nimport { isIdle, processOnlyAgent } from \"../shared.js\";\n\nexport class DevinAgentMapper {\n constructor(private readonly dbPath: string) {}\n\n mapSessionToAgent(
|
|
1
|
+
{"version":3,"sources":["../../../src/harnesses/devin/DevinAgentMapper.ts"],"sourcesContent":["import type { AgentInfo, ProcessInfo } from \"../../adapters/AgentAdapter.js\";\nimport { AgentStatus } from \"../../adapters/AgentAdapter.js\";\nimport { generateAgentName } from \"../../utils/matching.js\";\nimport type { DevinSession } from \"./DevinSessionLocator.js\";\nimport { encodeDevinSessionRef } from \"./DevinSessionLocator.js\";\nimport type { DevinSessionStats } from \"./DevinSessionParser.js\";\nimport { isIdle, processOnlyAgent } from \"../shared.js\";\n\nexport class DevinAgentMapper {\n constructor(private readonly dbPath: string) {}\n\n mapSessionToAgent(session: DevinSession, stats: DevinSessionStats, proc: ProcessInfo): AgentInfo {\n const lastActive =\n stats.lastTimeUpdated > 0\n ? new Date(stats.lastTimeUpdated)\n : new Date(session.lastActivityAt || session.timeCreated);\n\n return {\n name: generateAgentName(session.directory || proc.cwd || \"\", proc.pid),\n type: \"devin\",\n status: this.determineStatus(stats, lastActive),\n summary: stats.summary || session.title || \"Devin session active\",\n pid: proc.pid,\n projectPath: session.directory || proc.cwd || \"\",\n sessionId: session.sessionId,\n lastActive,\n sessionFilePath: encodeDevinSessionRef(this.dbPath, session.sessionId),\n };\n }\n\n mapProcessOnlyAgent(proc: ProcessInfo): AgentInfo {\n return processOnlyAgent(\"devin\", proc, { summary: \"Devin process running\" });\n }\n\n private determineStatus(stats: DevinSessionStats, lastActive: Date): AgentStatus {\n if (isIdle(lastActive)) return AgentStatus.IDLE;\n return stats.lastRole === \"assistant\" ? AgentStatus.WAITING : AgentStatus.RUNNING;\n }\n}\n"],"names":["AgentStatus","generateAgentName","encodeDevinSessionRef","isIdle","processOnlyAgent","DevinAgentMapper","dbPath","mapSessionToAgent","session","stats","proc","lastActive","lastTimeUpdated","Date","lastActivityAt","timeCreated","name","directory","cwd","pid","type","status","determineStatus","summary","title","projectPath","sessionId","sessionFilePath","mapProcessOnlyAgent","IDLE","lastRole","WAITING","RUNNING"],"mappings":"AACA,SAASA,WAAW,QAAQ,iCAAiC;AAC7D,SAASC,iBAAiB,QAAQ,0BAA0B;AAE5D,SAASC,qBAAqB,QAAQ,2BAA2B;AAEjE,SAASC,MAAM,EAAEC,gBAAgB,QAAQ,eAAe;AAExD,OAAO,MAAMC;;IACX,YAAY,AAAiBC,MAAc,CAAE;aAAhBA,SAAAA;IAAiB;IAE9CC,kBAAkBC,OAAqB,EAAEC,KAAwB,EAAEC,IAAiB,EAAa;QAC/F,MAAMC,aACJF,MAAMG,eAAe,GAAG,IACpB,IAAIC,KAAKJ,MAAMG,eAAe,IAC9B,IAAIC,KAAKL,QAAQM,cAAc,IAAIN,QAAQO,WAAW;QAE5D,OAAO;YACLC,MAAMf,kBAAkBO,QAAQS,SAAS,IAAIP,KAAKQ,GAAG,IAAI,IAAIR,KAAKS,GAAG;YACrEC,MAAM;YACNC,QAAQ,IAAI,CAACC,eAAe,CAACb,OAAOE;YACpCY,SAASd,MAAMc,OAAO,IAAIf,QAAQgB,KAAK,IAAI;YAC3CL,KAAKT,KAAKS,GAAG;YACbM,aAAajB,QAAQS,SAAS,IAAIP,KAAKQ,GAAG,IAAI;YAC9CQ,WAAWlB,QAAQkB,SAAS;YAC5Bf;YACAgB,iBAAiBzB,sBAAsB,IAAI,CAACI,MAAM,EAAEE,QAAQkB,SAAS;QACvE;IACF;IAEAE,oBAAoBlB,IAAiB,EAAa;QAChD,OAAON,iBAAiB,SAASM,MAAM;YAAEa,SAAS;QAAwB;IAC5E;IAEQD,gBAAgBb,KAAwB,EAAEE,UAAgB,EAAe;QAC/E,IAAIR,OAAOQ,aAAa,OAAOX,YAAY6B,IAAI;QAC/C,OAAOpB,MAAMqB,QAAQ,KAAK,cAAc9B,YAAY+B,OAAO,GAAG/B,YAAYgC,OAAO;IACnF;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DevinSessionParser.d.ts","sourceRoot":"","sources":["../../../src/harnesses/devin/DevinSessionParser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAG/F,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAE3C,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,qDAAqD;IACrD,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;CACjB;AA2BD,qBAAa,kBAAkB;IAC7B,eAAe,CACb,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,mBAAmB,EAAE;
|
|
1
|
+
{"version":3,"file":"DevinSessionParser.d.ts","sourceRoot":"","sources":["../../../src/harnesses/devin/DevinSessionParser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAG/F,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAE3C,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,qDAAqD;IACrD,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;CACjB;AA2BD,qBAAa,kBAAkB;IAC7B,eAAe,CACb,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,mBAAmB,EAAE;IAoFxB,eAAe,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,iBAAiB;IA8B5E;;;OAGG;IACH,iBAAiB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IAInE;;OAEG;IACH,mBAAmB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IAIrE;;;;OAIG;IACH,OAAO,CAAC,UAAU;IA2ClB,OAAO,CAAC,gBAAgB;CAOzB"}
|