@ai-devkit/agent-manager 0.41.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.
Files changed (101) hide show
  1. package/dist/AgentManager.d.ts.map +1 -1
  2. package/dist/AgentManager.js +25 -9
  3. package/dist/AgentManager.js.map +1 -1
  4. package/dist/__tests__/fixtures.test.js.map +1 -1
  5. package/dist/__tests__/harnesses/devin/DevinAdapter.test.js.map +1 -1
  6. package/dist/__tests__/harnesses/devin/DevinSessionParser.test.js.map +1 -1
  7. package/dist/__tests__/harnesses/muse/MuseAdapter.test.js +247 -0
  8. package/dist/__tests__/harnesses/muse/MuseAdapter.test.js.map +1 -0
  9. package/dist/__tests__/harnesses/muse/MuseAgentMapper.test.js +81 -0
  10. package/dist/__tests__/harnesses/muse/MuseAgentMapper.test.js.map +1 -0
  11. package/dist/__tests__/harnesses/muse/MuseSessionLocator.test.js +185 -0
  12. package/dist/__tests__/harnesses/muse/MuseSessionLocator.test.js.map +1 -0
  13. package/dist/__tests__/harnesses/muse/MuseSessionParser.test.js +328 -0
  14. package/dist/__tests__/harnesses/muse/MuseSessionParser.test.js.map +1 -0
  15. package/dist/__tests__/harnesses/opencode/OpenCodeSessionParser.test.js.map +1 -1
  16. package/dist/__tests__/harnesses/readiness/AgentReadiness.test.js +42 -1
  17. package/dist/__tests__/harnesses/readiness/AgentReadiness.test.js.map +1 -1
  18. package/dist/__tests__/harnesses/runtimeProfiles.test.js +12 -0
  19. package/dist/__tests__/harnesses/runtimeProfiles.test.js.map +1 -1
  20. package/dist/__tests__/utils/process.test.js +71 -1
  21. package/dist/__tests__/utils/process.test.js.map +1 -1
  22. package/dist/adapters/AgentAdapter.d.ts +8 -1
  23. package/dist/adapters/AgentAdapter.d.ts.map +1 -1
  24. package/dist/adapters/AgentAdapter.js +2 -1
  25. package/dist/adapters/AgentAdapter.js.map +1 -1
  26. package/dist/fixtures/capture.d.ts.map +1 -1
  27. package/dist/fixtures/capture.js +5 -4
  28. package/dist/fixtures/capture.js.map +1 -1
  29. package/dist/harnesses/devin/DevinAdapter.d.ts.map +1 -1
  30. package/dist/harnesses/devin/DevinAdapter.js.map +1 -1
  31. package/dist/harnesses/devin/DevinAgentMapper.d.ts.map +1 -1
  32. package/dist/harnesses/devin/DevinAgentMapper.js.map +1 -1
  33. package/dist/harnesses/devin/DevinSessionParser.d.ts.map +1 -1
  34. package/dist/harnesses/devin/DevinSessionParser.js.map +1 -1
  35. package/dist/harnesses/index.d.ts.map +1 -1
  36. package/dist/harnesses/index.js +3 -1
  37. package/dist/harnesses/index.js.map +1 -1
  38. package/dist/harnesses/muse/MuseAdapter.d.ts +33 -0
  39. package/dist/harnesses/muse/MuseAdapter.d.ts.map +1 -0
  40. package/dist/harnesses/muse/MuseAdapter.js +122 -0
  41. package/dist/harnesses/muse/MuseAdapter.js.map +1 -0
  42. package/dist/harnesses/muse/MuseAgentMapper.d.ts +15 -0
  43. package/dist/harnesses/muse/MuseAgentMapper.d.ts.map +1 -0
  44. package/dist/harnesses/muse/MuseAgentMapper.js +29 -0
  45. package/dist/harnesses/muse/MuseAgentMapper.js.map +1 -0
  46. package/dist/harnesses/muse/MuseSessionLocator.d.ts +61 -0
  47. package/dist/harnesses/muse/MuseSessionLocator.d.ts.map +1 -0
  48. package/dist/harnesses/muse/MuseSessionLocator.js +233 -0
  49. package/dist/harnesses/muse/MuseSessionLocator.js.map +1 -0
  50. package/dist/harnesses/muse/MuseSessionParser.d.ts +77 -0
  51. package/dist/harnesses/muse/MuseSessionParser.d.ts.map +1 -0
  52. package/dist/harnesses/muse/MuseSessionParser.js +350 -0
  53. package/dist/harnesses/muse/MuseSessionParser.js.map +1 -0
  54. package/dist/harnesses/muse/readiness.d.ts +3 -0
  55. package/dist/harnesses/muse/readiness.d.ts.map +1 -0
  56. package/dist/harnesses/muse/readiness.js +37 -0
  57. package/dist/harnesses/muse/readiness.js.map +1 -0
  58. package/dist/harnesses/readiness/AgentReadiness.d.ts.map +1 -1
  59. package/dist/harnesses/readiness/AgentReadiness.js +3 -1
  60. package/dist/harnesses/readiness/AgentReadiness.js.map +1 -1
  61. package/dist/harnesses/readiness/types.d.ts +1 -1
  62. package/dist/harnesses/readiness/types.d.ts.map +1 -1
  63. package/dist/harnesses/runtimeProfiles.d.ts.map +1 -1
  64. package/dist/harnesses/runtimeProfiles.js +2 -1
  65. package/dist/harnesses/runtimeProfiles.js.map +1 -1
  66. package/dist/harnesses/shared.d.ts +1 -1
  67. package/dist/harnesses/shared.d.ts.map +1 -1
  68. package/dist/harnesses/shared.js +6 -5
  69. package/dist/harnesses/shared.js.map +1 -1
  70. package/dist/utils/process.d.ts +23 -1
  71. package/dist/utils/process.d.ts.map +1 -1
  72. package/dist/utils/process.js +44 -8
  73. package/dist/utils/process.js.map +1 -1
  74. package/package.json +1 -1
  75. package/src/AgentManager.ts +34 -8
  76. package/src/__tests__/fixtures.test.ts +15 -17
  77. package/src/__tests__/harnesses/devin/DevinAdapter.test.ts +1 -3
  78. package/src/__tests__/harnesses/devin/DevinSessionParser.test.ts +3 -9
  79. package/src/__tests__/harnesses/muse/MuseAdapter.test.ts +197 -0
  80. package/src/__tests__/harnesses/muse/MuseAgentMapper.test.ts +83 -0
  81. package/src/__tests__/harnesses/muse/MuseSessionLocator.test.ts +177 -0
  82. package/src/__tests__/harnesses/muse/MuseSessionParser.test.ts +279 -0
  83. package/src/__tests__/harnesses/opencode/OpenCodeSessionParser.test.ts +3 -2
  84. package/src/__tests__/harnesses/readiness/AgentReadiness.test.ts +36 -0
  85. package/src/__tests__/harnesses/runtimeProfiles.test.ts +13 -0
  86. package/src/__tests__/utils/process.test.ts +30 -0
  87. package/src/adapters/AgentAdapter.ts +9 -0
  88. package/src/fixtures/capture.ts +32 -17
  89. package/src/harnesses/devin/DevinAdapter.ts +3 -15
  90. package/src/harnesses/devin/DevinAgentMapper.ts +1 -5
  91. package/src/harnesses/devin/DevinSessionParser.ts +3 -12
  92. package/src/harnesses/index.ts +2 -0
  93. package/src/harnesses/muse/MuseAdapter.ts +157 -0
  94. package/src/harnesses/muse/MuseAgentMapper.ts +33 -0
  95. package/src/harnesses/muse/MuseSessionLocator.ts +286 -0
  96. package/src/harnesses/muse/MuseSessionParser.ts +435 -0
  97. package/src/harnesses/muse/readiness.ts +38 -0
  98. package/src/harnesses/readiness/AgentReadiness.ts +2 -0
  99. package/src/harnesses/runtimeProfiles.ts +1 -0
  100. package/src/harnesses/shared.ts +10 -5
  101. package/src/utils/process.ts +61 -9
@@ -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;AAyFxC,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;CAQ1B"}
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,CACf,OAAO,EAAE,YAAY,EACrB,KAAK,EAAE,iBAAiB,EACxB,IAAI,EAAE,WAAW,GAChB,SAAS;IAmBZ,mBAAmB,CAAC,IAAI,EAAE,WAAW,GAAG,SAAS;IAIjD,OAAO,CAAC,eAAe;CAIxB"}
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(\n session: DevinSession,\n stats: DevinSessionStats,\n proc: ProcessInfo,\n ): 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,kBACEC,OAAqB,EACrBC,KAAwB,EACxBC,IAAiB,EACN;QACX,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
+ {"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;IAyFxB,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;IA+ClB,OAAO,CAAC,gBAAgB;CAOzB"}
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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/harnesses/devin/DevinSessionParser.ts"],"sourcesContent":["import type { ConversationMessage, ConversationOptions } from \"../../adapters/AgentAdapter.js\";\nimport { sliceTail } from \"../../utils/jsonlTail.js\";\nimport { SUMMARY_MAX_LENGTH, truncate } from \"../shared.js\";\nimport type Database from \"better-sqlite3\";\n\nexport interface DevinSessionStats {\n lastRole: string | null;\n /** Epoch milliseconds of the newest message node. */\n lastTimeUpdated: number;\n summary: string;\n}\n\ninterface DevinChatMessage {\n message_id?: string;\n role?: string;\n content?: unknown;\n tool_calls?: { name?: string; function?: { name?: string } }[];\n thinking?: { thinking?: string } | string;\n name?: string;\n metadata?: { is_user_input?: boolean };\n}\n\ninterface MessageNodeRow {\n node_id: number;\n chat_message: string;\n}\n\nconst EMPTY_STATS: DevinSessionStats = {\n lastRole: null,\n lastTimeUpdated: 0,\n summary: \"\",\n};\n\n/** Rows fetched per requested tail message; revisions/tools eat into the window. */\nconst TAIL_OVERFETCH = 8;\nconst TOOL_CONTENT_MAX = 500;\n\nexport class DevinSessionParser {\n getConversation(\n db: Database.Database,\n sessionId: string,\n options?: ConversationOptions,\n ): ConversationMessage[] {\n const verbose = options?.verbose ?? false;\n const tail =\n options?.tail && Number.isInteger(options.tail) && options.tail > 0\n ? options.tail\n : undefined;\n\n try {\n // LIMIT -1 = unbounded in SQLite; one query serves the full and tail paths.\n const limit = tail ? tail * TAIL_OVERFETCH : -1;\n const rows = db\n .prepare<[string, number], MessageNodeRow>(`\n SELECT node_id, chat_message\n FROM message_nodes\n WHERE session_id = ?\n ORDER BY node_id DESC\n LIMIT ?\n `)\n .all(sessionId, limit)\n .reverse();\n\n const messages: ConversationMessage[] = [];\n const latestNodeByMessageId = new Map<string, number>();\n const parsed: { nodeId: number; message: DevinChatMessage }[] = [];\n\n for (const row of rows) {\n const message = this.parseChatMessage(row.chat_message);\n if (!message) continue;\n parsed.push({ nodeId: row.node_id, message });\n if (message.message_id) {\n latestNodeByMessageId.set(\n message.message_id,\n Math.max(latestNodeByMessageId.get(message.message_id) ?? 0, row.node_id),\n );\n }\n }\n\n for (const { nodeId, message } of parsed) {\n if (\n message.message_id &&\n latestNodeByMessageId.get(message.message_id) !== nodeId\n ) {\n continue;\n }\n\n const role = message.role;\n if (role === \"system\") continue;\n\n const content = typeof message.content === \"string\" ? message.content : \"\";\n\n if (role === \"user\") {\n if (message.metadata?.is_user_input === false || !content.trim()) continue;\n messages.push({ role: \"user\", content });\n continue;\n }\n\n if (role === \"assistant\") {\n const thinking =\n typeof message.thinking === \"string\"\n ? message.thinking\n : message.thinking?.thinking;\n if (verbose && thinking) {\n messages.push({ role: \"assistant\", content: `[thinking] ${thinking}` });\n }\n if (content.trim()) messages.push({ role: \"assistant\", content });\n if (verbose) {\n for (const call of message.tool_calls ?? []) {\n const name = call.function?.name ?? call.name ?? \"tool\";\n messages.push({ role: \"assistant\", content: `[tool: ${name}]` });\n }\n }\n continue;\n }\n\n if (role === \"tool\" && verbose) {\n const label = message.name ? `[tool: ${message.name}]` : \"[tool]\";\n messages.push({\n role: \"assistant\",\n content: `${label} ${truncate(content.trim(), TOOL_CONTENT_MAX)}`.trim(),\n });\n }\n }\n\n return sliceTail(messages, tail);\n } catch {\n return [];\n }\n }\n\n getSessionStats(db: Database.Database, sessionId: string): DevinSessionStats {\n try {\n const frontier = db\n .prepare<[string], { chat_message: string }>(`\n SELECT chat_message\n FROM message_nodes\n WHERE session_id = ?\n ORDER BY node_id DESC\n LIMIT 1\n `)\n .get(sessionId);\n\n const heartbeat = db\n .prepare<[string], { maxCreated: number | null }>(`\n SELECT MAX(created_at) AS maxCreated\n FROM message_nodes\n WHERE session_id = ?\n `)\n .get(sessionId);\n\n return {\n lastRole: this.parseChatMessage(frontier?.chat_message ?? \"\")?.role ?? null,\n lastTimeUpdated: (heartbeat?.maxCreated ?? 0) * 1000,\n summary: this.getLastUserPrompt(db, sessionId),\n };\n } catch {\n return EMPTY_STATS;\n }\n }\n\n /**\n * Most recent typed prompt for the \"working on\" summary, matching the\n * last-user-message convention of the other adapters.\n */\n getLastUserPrompt(db: Database.Database, sessionId: string): string {\n return this.userPrompt(db, sessionId, \"DESC\");\n }\n\n /**\n * First typed prompt for session-list identity (`firstUserMessage`).\n */\n getFirstUserMessage(db: Database.Database, sessionId: string): string {\n return this.userPrompt(db, sessionId, \"ASC\");\n }\n\n /**\n * Typed prompt in the given direction. `prompt_history` is authoritative;\n * shell `!` commands and `/` slash commands are skipped. Falls back to a\n * bounded `is_user_input` node scan in the same direction.\n */\n private userPrompt(\n db: Database.Database,\n sessionId: string,\n direction: \"ASC\" | \"DESC\",\n ): string {\n try {\n const prompt = db\n .prepare<[string], { content: string }>(`\n SELECT content\n FROM prompt_history\n WHERE session_id = ? AND is_shell = 0 AND content NOT LIKE '/%'\n ORDER BY timestamp ${direction}\n LIMIT 1\n `)\n .get(sessionId);\n if (prompt?.content?.trim()) return truncate(prompt.content.trim(), SUMMARY_MAX_LENGTH);\n } catch {\n /* fall through to message_nodes */\n }\n\n try {\n const rows = db\n .prepare<[string], { chat_message: string }>(`\n SELECT chat_message\n FROM message_nodes\n WHERE session_id = ? AND json_extract(chat_message, '$.role') = 'user'\n ORDER BY node_id ${direction}\n LIMIT 8\n `)\n .all(sessionId);\n for (const row of rows) {\n const message = this.parseChatMessage(row.chat_message);\n if (\n message?.role === \"user\" &&\n message.metadata?.is_user_input !== false &&\n typeof message.content === \"string\" &&\n message.content.trim()\n ) {\n return truncate(message.content.trim(), SUMMARY_MAX_LENGTH);\n }\n }\n } catch {\n /* ignore */\n }\n return \"\";\n }\n\n private parseChatMessage(raw: string): DevinChatMessage | null {\n try {\n return JSON.parse(raw) as DevinChatMessage;\n } catch {\n return null;\n }\n }\n}\n"],"names":["sliceTail","SUMMARY_MAX_LENGTH","truncate","EMPTY_STATS","lastRole","lastTimeUpdated","summary","TAIL_OVERFETCH","TOOL_CONTENT_MAX","DevinSessionParser","getConversation","db","sessionId","options","verbose","tail","Number","isInteger","undefined","limit","rows","prepare","all","reverse","messages","latestNodeByMessageId","Map","parsed","row","message","parseChatMessage","chat_message","push","nodeId","node_id","message_id","set","Math","max","get","role","content","metadata","is_user_input","trim","thinking","call","tool_calls","name","function","label","getSessionStats","frontier","heartbeat","maxCreated","getLastUserPrompt","userPrompt","getFirstUserMessage","direction","prompt","raw","JSON","parse"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/harnesses/devin/DevinSessionParser.ts"],"sourcesContent":["import type { ConversationMessage, ConversationOptions } from \"../../adapters/AgentAdapter.js\";\nimport { sliceTail } from \"../../utils/jsonlTail.js\";\nimport { SUMMARY_MAX_LENGTH, truncate } from \"../shared.js\";\nimport type Database from \"better-sqlite3\";\n\nexport interface DevinSessionStats {\n lastRole: string | null;\n /** Epoch milliseconds of the newest message node. */\n lastTimeUpdated: number;\n summary: string;\n}\n\ninterface DevinChatMessage {\n message_id?: string;\n role?: string;\n content?: unknown;\n tool_calls?: { name?: string; function?: { name?: string } }[];\n thinking?: { thinking?: string } | string;\n name?: string;\n metadata?: { is_user_input?: boolean };\n}\n\ninterface MessageNodeRow {\n node_id: number;\n chat_message: string;\n}\n\nconst EMPTY_STATS: DevinSessionStats = {\n lastRole: null,\n lastTimeUpdated: 0,\n summary: \"\",\n};\n\n/** Rows fetched per requested tail message; revisions/tools eat into the window. */\nconst TAIL_OVERFETCH = 8;\nconst TOOL_CONTENT_MAX = 500;\n\nexport class DevinSessionParser {\n getConversation(\n db: Database.Database,\n sessionId: string,\n options?: ConversationOptions,\n ): ConversationMessage[] {\n const verbose = options?.verbose ?? false;\n const tail =\n options?.tail && Number.isInteger(options.tail) && options.tail > 0\n ? options.tail\n : undefined;\n\n try {\n // LIMIT -1 = unbounded in SQLite; one query serves the full and tail paths.\n const limit = tail ? tail * TAIL_OVERFETCH : -1;\n const rows = db\n .prepare<[string, number], MessageNodeRow>(`\n SELECT node_id, chat_message\n FROM message_nodes\n WHERE session_id = ?\n ORDER BY node_id DESC\n LIMIT ?\n `)\n .all(sessionId, limit)\n .reverse();\n\n const messages: ConversationMessage[] = [];\n const latestNodeByMessageId = new Map<string, number>();\n const parsed: { nodeId: number; message: DevinChatMessage }[] = [];\n\n for (const row of rows) {\n const message = this.parseChatMessage(row.chat_message);\n if (!message) continue;\n parsed.push({ nodeId: row.node_id, message });\n if (message.message_id) {\n latestNodeByMessageId.set(\n message.message_id,\n Math.max(latestNodeByMessageId.get(message.message_id) ?? 0, row.node_id),\n );\n }\n }\n\n for (const { nodeId, message } of parsed) {\n if (message.message_id && latestNodeByMessageId.get(message.message_id) !== nodeId) {\n continue;\n }\n\n const role = message.role;\n if (role === \"system\") continue;\n\n const content = typeof message.content === \"string\" ? message.content : \"\";\n\n if (role === \"user\") {\n if (message.metadata?.is_user_input === false || !content.trim()) continue;\n messages.push({ role: \"user\", content });\n continue;\n }\n\n if (role === \"assistant\") {\n const thinking =\n typeof message.thinking === \"string\" ? message.thinking : message.thinking?.thinking;\n if (verbose && thinking) {\n messages.push({ role: \"assistant\", content: `[thinking] ${thinking}` });\n }\n if (content.trim()) messages.push({ role: \"assistant\", content });\n if (verbose) {\n for (const call of message.tool_calls ?? []) {\n const name = call.function?.name ?? call.name ?? \"tool\";\n messages.push({ role: \"assistant\", content: `[tool: ${name}]` });\n }\n }\n continue;\n }\n\n if (role === \"tool\" && verbose) {\n const label = message.name ? `[tool: ${message.name}]` : \"[tool]\";\n messages.push({\n role: \"assistant\",\n content: `${label} ${truncate(content.trim(), TOOL_CONTENT_MAX)}`.trim(),\n });\n }\n }\n\n return sliceTail(messages, tail);\n } catch {\n return [];\n }\n }\n\n getSessionStats(db: Database.Database, sessionId: string): DevinSessionStats {\n try {\n const frontier = db\n .prepare<[string], { chat_message: string }>(`\n SELECT chat_message\n FROM message_nodes\n WHERE session_id = ?\n ORDER BY node_id DESC\n LIMIT 1\n `)\n .get(sessionId);\n\n const heartbeat = db\n .prepare<[string], { maxCreated: number | null }>(`\n SELECT MAX(created_at) AS maxCreated\n FROM message_nodes\n WHERE session_id = ?\n `)\n .get(sessionId);\n\n return {\n lastRole: this.parseChatMessage(frontier?.chat_message ?? \"\")?.role ?? null,\n lastTimeUpdated: (heartbeat?.maxCreated ?? 0) * 1000,\n summary: this.getLastUserPrompt(db, sessionId),\n };\n } catch {\n return EMPTY_STATS;\n }\n }\n\n /**\n * Most recent typed prompt for the \"working on\" summary, matching the\n * last-user-message convention of the other adapters.\n */\n getLastUserPrompt(db: Database.Database, sessionId: string): string {\n return this.userPrompt(db, sessionId, \"DESC\");\n }\n\n /**\n * First typed prompt for session-list identity (`firstUserMessage`).\n */\n getFirstUserMessage(db: Database.Database, sessionId: string): string {\n return this.userPrompt(db, sessionId, \"ASC\");\n }\n\n /**\n * Typed prompt in the given direction. `prompt_history` is authoritative;\n * shell `!` commands and `/` slash commands are skipped. Falls back to a\n * bounded `is_user_input` node scan in the same direction.\n */\n private userPrompt(db: Database.Database, sessionId: string, direction: \"ASC\" | \"DESC\"): string {\n try {\n const prompt = db\n .prepare<[string], { content: string }>(`\n SELECT content\n FROM prompt_history\n WHERE session_id = ? AND is_shell = 0 AND content NOT LIKE '/%'\n ORDER BY timestamp ${direction}\n LIMIT 1\n `)\n .get(sessionId);\n if (prompt?.content?.trim()) return truncate(prompt.content.trim(), SUMMARY_MAX_LENGTH);\n } catch {\n /* fall through to message_nodes */\n }\n\n try {\n const rows = db\n .prepare<[string], { chat_message: string }>(`\n SELECT chat_message\n FROM message_nodes\n WHERE session_id = ? AND json_extract(chat_message, '$.role') = 'user'\n ORDER BY node_id ${direction}\n LIMIT 8\n `)\n .all(sessionId);\n for (const row of rows) {\n const message = this.parseChatMessage(row.chat_message);\n if (\n message?.role === \"user\" &&\n message.metadata?.is_user_input !== false &&\n typeof message.content === \"string\" &&\n message.content.trim()\n ) {\n return truncate(message.content.trim(), SUMMARY_MAX_LENGTH);\n }\n }\n } catch {\n /* ignore */\n }\n return \"\";\n }\n\n private parseChatMessage(raw: string): DevinChatMessage | null {\n try {\n return JSON.parse(raw) as DevinChatMessage;\n } catch {\n return null;\n }\n }\n}\n"],"names":["sliceTail","SUMMARY_MAX_LENGTH","truncate","EMPTY_STATS","lastRole","lastTimeUpdated","summary","TAIL_OVERFETCH","TOOL_CONTENT_MAX","DevinSessionParser","getConversation","db","sessionId","options","verbose","tail","Number","isInteger","undefined","limit","rows","prepare","all","reverse","messages","latestNodeByMessageId","Map","parsed","row","message","parseChatMessage","chat_message","push","nodeId","node_id","message_id","set","Math","max","get","role","content","metadata","is_user_input","trim","thinking","call","tool_calls","name","function","label","getSessionStats","frontier","heartbeat","maxCreated","getLastUserPrompt","userPrompt","getFirstUserMessage","direction","prompt","raw","JSON","parse"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/harnesses/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAYhE;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,YAAY,EAAE,CAatD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/harnesses/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAahE;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,YAAY,EAAE,CActD"}
@@ -8,6 +8,7 @@ import { KiroAdapter } from "./kiro/KiroAdapter.js";
8
8
  import { OpenCodeAdapter } from "./opencode/OpenCodeAdapter.js";
9
9
  import { PiAdapter } from "./pi/PiAdapter.js";
10
10
  import { DevinAdapter } from "./devin/DevinAdapter.js";
11
+ import { MuseAdapter } from "./muse/MuseAdapter.js";
11
12
  /**
12
13
  * One instance of every built-in harness adapter, in registration order
13
14
  * (which is also the order agents are listed in). Register a new harness here.
@@ -22,7 +23,8 @@ import { DevinAdapter } from "./devin/DevinAdapter.js";
22
23
  new AntigravityCliAdapter(),
23
24
  new OpenCodeAdapter(),
24
25
  new PiAdapter(),
25
- new DevinAdapter()
26
+ new DevinAdapter(),
27
+ new MuseAdapter()
26
28
  ];
27
29
  }
28
30
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/harnesses/index.ts"],"sourcesContent":["import type { AgentAdapter } from \"../adapters/AgentAdapter.js\";\nimport { AntigravityCliAdapter } from \"./antigravity/AntigravityCliAdapter.js\";\nimport { ClaudeCodeAdapter } from \"./claude/ClaudeCodeAdapter.js\";\nimport { CodexAdapter } from \"./codex/CodexAdapter.js\";\nimport { CopilotAdapter } from \"./copilot/CopilotAdapter.js\";\nimport { GeminiCliAdapter } from \"./gemini/GeminiCliAdapter.js\";\nimport { GrokCliAdapter } from \"./grok/GrokCliAdapter.js\";\nimport { KiroAdapter } from \"./kiro/KiroAdapter.js\";\nimport { OpenCodeAdapter } from \"./opencode/OpenCodeAdapter.js\";\nimport { PiAdapter } from \"./pi/PiAdapter.js\";\nimport { DevinAdapter } from \"./devin/DevinAdapter.js\";\n\n/**\n * One instance of every built-in harness adapter, in registration order\n * (which is also the order agents are listed in). Register a new harness here.\n */\nexport function createBuiltinAdapters(): AgentAdapter[] {\n return [\n new ClaudeCodeAdapter(),\n new CodexAdapter(),\n new CopilotAdapter(),\n new GeminiCliAdapter(),\n new GrokCliAdapter(),\n new KiroAdapter(),\n new AntigravityCliAdapter(),\n new OpenCodeAdapter(),\n new PiAdapter(),\n new DevinAdapter(),\n ];\n}\n"],"names":["AntigravityCliAdapter","ClaudeCodeAdapter","CodexAdapter","CopilotAdapter","GeminiCliAdapter","GrokCliAdapter","KiroAdapter","OpenCodeAdapter","PiAdapter","DevinAdapter","createBuiltinAdapters"],"mappings":"AACA,SAASA,qBAAqB,QAAQ,yCAAyC;AAC/E,SAASC,iBAAiB,QAAQ,gCAAgC;AAClE,SAASC,YAAY,QAAQ,0BAA0B;AACvD,SAASC,cAAc,QAAQ,8BAA8B;AAC7D,SAASC,gBAAgB,QAAQ,+BAA+B;AAChE,SAASC,cAAc,QAAQ,2BAA2B;AAC1D,SAASC,WAAW,QAAQ,wBAAwB;AACpD,SAASC,eAAe,QAAQ,gCAAgC;AAChE,SAASC,SAAS,QAAQ,oBAAoB;AAC9C,SAASC,YAAY,QAAQ,0BAA0B;AAEvD;;;CAGC,GACD,OAAO,SAASC;IACd,OAAO;QACL,IAAIT;QACJ,IAAIC;QACJ,IAAIC;QACJ,IAAIC;QACJ,IAAIC;QACJ,IAAIC;QACJ,IAAIN;QACJ,IAAIO;QACJ,IAAIC;QACJ,IAAIC;KACL;AACH"}
1
+ {"version":3,"sources":["../../src/harnesses/index.ts"],"sourcesContent":["import type { AgentAdapter } from \"../adapters/AgentAdapter.js\";\nimport { AntigravityCliAdapter } from \"./antigravity/AntigravityCliAdapter.js\";\nimport { ClaudeCodeAdapter } from \"./claude/ClaudeCodeAdapter.js\";\nimport { CodexAdapter } from \"./codex/CodexAdapter.js\";\nimport { CopilotAdapter } from \"./copilot/CopilotAdapter.js\";\nimport { GeminiCliAdapter } from \"./gemini/GeminiCliAdapter.js\";\nimport { GrokCliAdapter } from \"./grok/GrokCliAdapter.js\";\nimport { KiroAdapter } from \"./kiro/KiroAdapter.js\";\nimport { OpenCodeAdapter } from \"./opencode/OpenCodeAdapter.js\";\nimport { PiAdapter } from \"./pi/PiAdapter.js\";\nimport { DevinAdapter } from \"./devin/DevinAdapter.js\";\nimport { MuseAdapter } from \"./muse/MuseAdapter.js\";\n\n/**\n * One instance of every built-in harness adapter, in registration order\n * (which is also the order agents are listed in). Register a new harness here.\n */\nexport function createBuiltinAdapters(): AgentAdapter[] {\n return [\n new ClaudeCodeAdapter(),\n new CodexAdapter(),\n new CopilotAdapter(),\n new GeminiCliAdapter(),\n new GrokCliAdapter(),\n new KiroAdapter(),\n new AntigravityCliAdapter(),\n new OpenCodeAdapter(),\n new PiAdapter(),\n new DevinAdapter(),\n new MuseAdapter(),\n ];\n}\n"],"names":["AntigravityCliAdapter","ClaudeCodeAdapter","CodexAdapter","CopilotAdapter","GeminiCliAdapter","GrokCliAdapter","KiroAdapter","OpenCodeAdapter","PiAdapter","DevinAdapter","MuseAdapter","createBuiltinAdapters"],"mappings":"AACA,SAASA,qBAAqB,QAAQ,yCAAyC;AAC/E,SAASC,iBAAiB,QAAQ,gCAAgC;AAClE,SAASC,YAAY,QAAQ,0BAA0B;AACvD,SAASC,cAAc,QAAQ,8BAA8B;AAC7D,SAASC,gBAAgB,QAAQ,+BAA+B;AAChE,SAASC,cAAc,QAAQ,2BAA2B;AAC1D,SAASC,WAAW,QAAQ,wBAAwB;AACpD,SAASC,eAAe,QAAQ,gCAAgC;AAChE,SAASC,SAAS,QAAQ,oBAAoB;AAC9C,SAASC,YAAY,QAAQ,0BAA0B;AACvD,SAASC,WAAW,QAAQ,wBAAwB;AAEpD;;;CAGC,GACD,OAAO,SAASC;IACd,OAAO;QACL,IAAIV;QACJ,IAAIC;QACJ,IAAIC;QACJ,IAAIC;QACJ,IAAIC;QACJ,IAAIC;QACJ,IAAIN;QACJ,IAAIO;QACJ,IAAIC;QACJ,IAAIC;QACJ,IAAIC;KACL;AACH"}
@@ -0,0 +1,33 @@
1
+ import type { AgentAdapter, AgentDetectionContext, AgentInfo, ConversationMessage, ConversationOptions, ListSessionsOptions, ProcessInfo, SessionSummary } from "../../adapters/AgentAdapter.js";
2
+ export interface MuseAdapterOptions {
3
+ homeDir?: string;
4
+ }
5
+ /**
6
+ * Muse (Meta Muse Code) adapter.
7
+ *
8
+ * Detection joins two sources:
9
+ * 1. Live runtime entries (`~/.local/share/muse/runtime/muse/sessions/<id>.json`)
10
+ * matched to processes by `process_generation_hint: "pid=<n>"`.
11
+ * 2. The dated transcript archive (`sessions/yyyy/mm/dd/<uuid>/session.jsonl`).
12
+ *
13
+ * The launcher binary is versioned (`muse-bin-<version>-<build>`), so discovery
14
+ * uses `processNamePrefixes`; `canHandle` keeps the precise shape check.
15
+ */
16
+ export declare class MuseAdapter implements AgentAdapter {
17
+ readonly type: "muse";
18
+ readonly processNames: readonly ["muse"];
19
+ readonly processNamePrefixes: readonly ["muse"];
20
+ private readonly home;
21
+ private readonly parser;
22
+ private readonly mapper;
23
+ constructor(options?: MuseAdapterOptions);
24
+ canHandle(processInfo: ProcessInfo): boolean;
25
+ detectAgents(context?: AgentDetectionContext): Promise<AgentInfo[]>;
26
+ private detectRunningAgents;
27
+ private createLocator;
28
+ getConversation(sessionFilePath: string, options?: ConversationOptions): ConversationMessage[];
29
+ listSessions(opts?: ListSessionsOptions): Promise<SessionSummary[]>;
30
+ findSessionsById(sessionId: string): Promise<SessionSummary[]>;
31
+ private toSessionSummary;
32
+ }
33
+ //# sourceMappingURL=MuseAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MuseAdapter.d.ts","sourceRoot":"","sources":["../../../src/harnesses/muse/MuseAdapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,YAAY,EACZ,qBAAqB,EACrB,SAAS,EACT,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,WAAW,EACX,cAAc,EACf,MAAM,gCAAgC,CAAC;AAOxC,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;GAUG;AACH,qBAAa,WAAY,YAAW,YAAY;IAC9C,QAAQ,CAAC,IAAI,EAAG,MAAM,CAAU;IAChC,QAAQ,CAAC,YAAY,oBAAqB;IAC1C,QAAQ,CAAC,mBAAmB,oBAAqB;IAEjD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAC3C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;gBAE7B,OAAO,GAAE,kBAAuB;IAM5C,SAAS,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO;IAKtC,YAAY,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;YAQ3D,mBAAmB;IAuDjC,OAAO,CAAC,aAAa;IAIrB,eAAe,CAAC,eAAe,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,mBAAmB,EAAE;IAIxF,YAAY,CAAC,IAAI,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAYnE,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAOpE,OAAO,CAAC,gBAAgB;CAczB"}
@@ -0,0 +1,122 @@
1
+ import * as path from "path";
2
+ import { safeStat } from "../../utils/session.js";
3
+ import { MuseAgentMapper } from "./MuseAgentMapper.js";
4
+ import { MuseSessionLocator } from "./MuseSessionLocator.js";
5
+ import { MuseSessionParser } from "./MuseSessionParser.js";
6
+ import { findHarnessProcesses, homeDir } from "../shared.js";
7
+ /**
8
+ * Muse (Meta Muse Code) adapter.
9
+ *
10
+ * Detection joins two sources:
11
+ * 1. Live runtime entries (`~/.local/share/muse/runtime/muse/sessions/<id>.json`)
12
+ * matched to processes by `process_generation_hint: "pid=<n>"`.
13
+ * 2. The dated transcript archive (`sessions/yyyy/mm/dd/<uuid>/session.jsonl`).
14
+ *
15
+ * The launcher binary is versioned (`muse-bin-<version>-<build>`), so discovery
16
+ * uses `processNamePrefixes`; `canHandle` keeps the precise shape check.
17
+ */ export class MuseAdapter {
18
+ type = "muse";
19
+ processNames = [
20
+ "muse"
21
+ ];
22
+ processNamePrefixes = [
23
+ "muse"
24
+ ];
25
+ home;
26
+ parser;
27
+ mapper;
28
+ constructor(options = {}){
29
+ this.home = options.homeDir ?? homeDir();
30
+ this.parser = new MuseSessionParser();
31
+ this.mapper = new MuseAgentMapper(this.parser);
32
+ }
33
+ canHandle(processInfo) {
34
+ const base = path.basename(processInfo.command.trim().split(/\s+/)[0] ?? "").toLowerCase();
35
+ return base === "muse" || base === "muse.exe" || base.startsWith("muse-bin-");
36
+ }
37
+ async detectAgents(context) {
38
+ try {
39
+ return await this.detectRunningAgents(context);
40
+ } finally{
41
+ this.parser.pruneSessionCache();
42
+ }
43
+ }
44
+ async detectRunningAgents(context) {
45
+ const { processes } = await findHarnessProcesses(this, context);
46
+ if (processes.length === 0) return [];
47
+ const { direct, legacyMatches } = this.createLocator().matchRunningProcesses(processes);
48
+ const matchedPids = new Set([
49
+ ...direct.map((d)=>d.process.pid),
50
+ ...legacyMatches.map((m)=>m.process.pid)
51
+ ]);
52
+ const agents = [];
53
+ for (const match of direct){
54
+ const sessionData = this.parser.readSessionIncremental(match.sessionFile.filePath, match.sessionFile.resolvedCwd);
55
+ if (sessionData) {
56
+ agents.push(this.mapper.mapSessionToAgent({
57
+ session: sessionData,
58
+ processInfo: match.process,
59
+ sessionFile: match.sessionFile
60
+ }));
61
+ } else {
62
+ matchedPids.delete(match.process.pid);
63
+ }
64
+ }
65
+ for (const match of legacyMatches){
66
+ const sessionData = this.parser.readSessionIncremental(match.session.filePath, match.session.resolvedCwd);
67
+ if (sessionData) {
68
+ agents.push(this.mapper.mapSessionToAgent({
69
+ session: sessionData,
70
+ processInfo: match.process,
71
+ sessionFile: match.session
72
+ }));
73
+ } else {
74
+ matchedPids.delete(match.process.pid);
75
+ }
76
+ }
77
+ for (const proc of processes){
78
+ if (!matchedPids.has(proc.pid)) {
79
+ agents.push(this.mapper.mapProcessOnlyAgent(proc));
80
+ }
81
+ }
82
+ return agents;
83
+ }
84
+ createLocator() {
85
+ return new MuseSessionLocator({
86
+ homeDir: this.home
87
+ });
88
+ }
89
+ getConversation(sessionFilePath, options) {
90
+ return this.parser.getConversation(sessionFilePath, options);
91
+ }
92
+ async listSessions(opts) {
93
+ const filterCwd = opts?.cwd;
94
+ const summaries = [];
95
+ for (const { filePath, defaultCwd } of this.createLocator().discoverHistoricalSessionFiles()){
96
+ const summary = this.toSessionSummary(filePath, defaultCwd);
97
+ if (!summary) continue;
98
+ if (filterCwd !== undefined && summary.cwd !== filterCwd) continue;
99
+ summaries.push(summary);
100
+ }
101
+ return summaries;
102
+ }
103
+ async findSessionsById(sessionId) {
104
+ return this.createLocator().findHistoricalSessionFilesById(sessionId).map(({ filePath, defaultCwd })=>this.toSessionSummary(filePath, defaultCwd)).filter((summary)=>summary?.sessionId === sessionId);
105
+ }
106
+ toSessionSummary(filePath, defaultCwd) {
107
+ const session = this.parser.readSession(filePath, defaultCwd);
108
+ if (!session?.lastSignal && !session?.firstUserMessage) return null;
109
+ const stat = safeStat(filePath);
110
+ return {
111
+ type: "muse",
112
+ sessionId: session.sessionId,
113
+ cwd: session.projectPath || defaultCwd,
114
+ firstUserMessage: session.firstUserMessage || "",
115
+ lastActive: session.lastActive ?? stat?.mtime ?? new Date(),
116
+ startedAt: session.sessionStart ?? stat?.birthtime ?? stat?.mtime ?? new Date(),
117
+ sessionFilePath: filePath
118
+ };
119
+ }
120
+ }
121
+
122
+ //# sourceMappingURL=MuseAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/harnesses/muse/MuseAdapter.ts"],"sourcesContent":["import * as path from \"path\";\nimport type {\n AgentAdapter,\n AgentDetectionContext,\n AgentInfo,\n ConversationMessage,\n ConversationOptions,\n ListSessionsOptions,\n ProcessInfo,\n SessionSummary,\n} from \"../../adapters/AgentAdapter.js\";\nimport { safeStat } from \"../../utils/session.js\";\nimport { MuseAgentMapper } from \"./MuseAgentMapper.js\";\nimport { MuseSessionLocator } from \"./MuseSessionLocator.js\";\nimport { MuseSessionParser } from \"./MuseSessionParser.js\";\nimport { findHarnessProcesses, homeDir } from \"../shared.js\";\n\nexport interface MuseAdapterOptions {\n homeDir?: string;\n}\n\n/**\n * Muse (Meta Muse Code) adapter.\n *\n * Detection joins two sources:\n * 1. Live runtime entries (`~/.local/share/muse/runtime/muse/sessions/<id>.json`)\n * matched to processes by `process_generation_hint: \"pid=<n>\"`.\n * 2. The dated transcript archive (`sessions/yyyy/mm/dd/<uuid>/session.jsonl`).\n *\n * The launcher binary is versioned (`muse-bin-<version>-<build>`), so discovery\n * uses `processNamePrefixes`; `canHandle` keeps the precise shape check.\n */\nexport class MuseAdapter implements AgentAdapter {\n readonly type = \"muse\" as const;\n readonly processNames = [\"muse\"] as const;\n readonly processNamePrefixes = [\"muse\"] as const;\n\n private readonly home: string;\n private readonly parser: MuseSessionParser;\n private readonly mapper: MuseAgentMapper;\n\n constructor(options: MuseAdapterOptions = {}) {\n this.home = options.homeDir ?? homeDir();\n this.parser = new MuseSessionParser();\n this.mapper = new MuseAgentMapper(this.parser);\n }\n\n canHandle(processInfo: ProcessInfo): boolean {\n const base = path.basename(processInfo.command.trim().split(/\\s+/)[0] ?? \"\").toLowerCase();\n return base === \"muse\" || base === \"muse.exe\" || base.startsWith(\"muse-bin-\");\n }\n\n async detectAgents(context?: AgentDetectionContext): Promise<AgentInfo[]> {\n try {\n return await this.detectRunningAgents(context);\n } finally {\n this.parser.pruneSessionCache();\n }\n }\n\n private async detectRunningAgents(context?: AgentDetectionContext): Promise<AgentInfo[]> {\n const { processes } = await findHarnessProcesses(this, context);\n if (processes.length === 0) return [];\n\n const { direct, legacyMatches } = this.createLocator().matchRunningProcesses(processes);\n const matchedPids = new Set([\n ...direct.map((d) => d.process.pid),\n ...legacyMatches.map((m) => m.process.pid),\n ]);\n const agents: AgentInfo[] = [];\n\n for (const match of direct) {\n const sessionData = this.parser.readSessionIncremental(\n match.sessionFile.filePath,\n match.sessionFile.resolvedCwd,\n );\n if (sessionData) {\n agents.push(\n this.mapper.mapSessionToAgent({\n session: sessionData,\n processInfo: match.process,\n sessionFile: match.sessionFile,\n }),\n );\n } else {\n matchedPids.delete(match.process.pid);\n }\n }\n\n for (const match of legacyMatches) {\n const sessionData = this.parser.readSessionIncremental(\n match.session.filePath,\n match.session.resolvedCwd,\n );\n if (sessionData) {\n agents.push(\n this.mapper.mapSessionToAgent({\n session: sessionData,\n processInfo: match.process,\n sessionFile: match.session,\n }),\n );\n } else {\n matchedPids.delete(match.process.pid);\n }\n }\n\n for (const proc of processes) {\n if (!matchedPids.has(proc.pid)) {\n agents.push(this.mapper.mapProcessOnlyAgent(proc));\n }\n }\n return agents;\n }\n\n private createLocator(): MuseSessionLocator {\n return new MuseSessionLocator({ homeDir: this.home });\n }\n\n getConversation(sessionFilePath: string, options?: ConversationOptions): ConversationMessage[] {\n return this.parser.getConversation(sessionFilePath, options);\n }\n\n async listSessions(opts?: ListSessionsOptions): Promise<SessionSummary[]> {\n const filterCwd = opts?.cwd;\n const summaries: SessionSummary[] = [];\n for (const { filePath, defaultCwd } of this.createLocator().discoverHistoricalSessionFiles()) {\n const summary = this.toSessionSummary(filePath, defaultCwd);\n if (!summary) continue;\n if (filterCwd !== undefined && summary.cwd !== filterCwd) continue;\n summaries.push(summary);\n }\n return summaries;\n }\n\n async findSessionsById(sessionId: string): Promise<SessionSummary[]> {\n return this.createLocator()\n .findHistoricalSessionFilesById(sessionId)\n .map(({ filePath, defaultCwd }) => this.toSessionSummary(filePath, defaultCwd))\n .filter((summary): summary is SessionSummary => summary?.sessionId === sessionId);\n }\n\n private toSessionSummary(filePath: string, defaultCwd: string): SessionSummary | null {\n const session = this.parser.readSession(filePath, defaultCwd);\n if (!session?.lastSignal && !session?.firstUserMessage) return null;\n const stat = safeStat(filePath);\n return {\n type: \"muse\",\n sessionId: session.sessionId,\n cwd: session.projectPath || defaultCwd,\n firstUserMessage: session.firstUserMessage || \"\",\n lastActive: session.lastActive ?? stat?.mtime ?? new Date(),\n startedAt: session.sessionStart ?? stat?.birthtime ?? stat?.mtime ?? new Date(),\n sessionFilePath: filePath,\n };\n }\n}\n"],"names":["path","safeStat","MuseAgentMapper","MuseSessionLocator","MuseSessionParser","findHarnessProcesses","homeDir","MuseAdapter","type","processNames","processNamePrefixes","home","parser","mapper","options","canHandle","processInfo","base","basename","command","trim","split","toLowerCase","startsWith","detectAgents","context","detectRunningAgents","pruneSessionCache","processes","length","direct","legacyMatches","createLocator","matchRunningProcesses","matchedPids","Set","map","d","process","pid","m","agents","match","sessionData","readSessionIncremental","sessionFile","filePath","resolvedCwd","push","mapSessionToAgent","session","delete","proc","has","mapProcessOnlyAgent","getConversation","sessionFilePath","listSessions","opts","filterCwd","cwd","summaries","defaultCwd","discoverHistoricalSessionFiles","summary","toSessionSummary","undefined","findSessionsById","sessionId","findHistoricalSessionFilesById","filter","readSession","lastSignal","firstUserMessage","stat","projectPath","lastActive","mtime","Date","startedAt","sessionStart","birthtime"],"mappings":"AAAA,YAAYA,UAAU,OAAO;AAW7B,SAASC,QAAQ,QAAQ,yBAAyB;AAClD,SAASC,eAAe,QAAQ,uBAAuB;AACvD,SAASC,kBAAkB,QAAQ,0BAA0B;AAC7D,SAASC,iBAAiB,QAAQ,yBAAyB;AAC3D,SAASC,oBAAoB,EAAEC,OAAO,QAAQ,eAAe;AAM7D;;;;;;;;;;CAUC,GACD,OAAO,MAAMC;IACFC,OAAO,OAAgB;IACvBC,eAAe;QAAC;KAAO,CAAU;IACjCC,sBAAsB;QAAC;KAAO,CAAU;IAEhCC,KAAa;IACbC,OAA0B;IAC1BC,OAAwB;IAEzC,YAAYC,UAA8B,CAAC,CAAC,CAAE;QAC5C,IAAI,CAACH,IAAI,GAAGG,QAAQR,OAAO,IAAIA;QAC/B,IAAI,CAACM,MAAM,GAAG,IAAIR;QAClB,IAAI,CAACS,MAAM,GAAG,IAAIX,gBAAgB,IAAI,CAACU,MAAM;IAC/C;IAEAG,UAAUC,WAAwB,EAAW;QAC3C,MAAMC,OAAOjB,KAAKkB,QAAQ,CAACF,YAAYG,OAAO,CAACC,IAAI,GAAGC,KAAK,CAAC,MAAM,CAAC,EAAE,IAAI,IAAIC,WAAW;QACxF,OAAOL,SAAS,UAAUA,SAAS,cAAcA,KAAKM,UAAU,CAAC;IACnE;IAEA,MAAMC,aAAaC,OAA+B,EAAwB;QACxE,IAAI;YACF,OAAO,MAAM,IAAI,CAACC,mBAAmB,CAACD;QACxC,SAAU;YACR,IAAI,CAACb,MAAM,CAACe,iBAAiB;QAC/B;IACF;IAEA,MAAcD,oBAAoBD,OAA+B,EAAwB;QACvF,MAAM,EAAEG,SAAS,EAAE,GAAG,MAAMvB,qBAAqB,IAAI,EAAEoB;QACvD,IAAIG,UAAUC,MAAM,KAAK,GAAG,OAAO,EAAE;QAErC,MAAM,EAAEC,MAAM,EAAEC,aAAa,EAAE,GAAG,IAAI,CAACC,aAAa,GAAGC,qBAAqB,CAACL;QAC7E,MAAMM,cAAc,IAAIC,IAAI;eACvBL,OAAOM,GAAG,CAAC,CAACC,IAAMA,EAAEC,OAAO,CAACC,GAAG;eAC/BR,cAAcK,GAAG,CAAC,CAACI,IAAMA,EAAEF,OAAO,CAACC,GAAG;SAC1C;QACD,MAAME,SAAsB,EAAE;QAE9B,KAAK,MAAMC,SAASZ,OAAQ;YAC1B,MAAMa,cAAc,IAAI,CAAC/B,MAAM,CAACgC,sBAAsB,CACpDF,MAAMG,WAAW,CAACC,QAAQ,EAC1BJ,MAAMG,WAAW,CAACE,WAAW;YAE/B,IAAIJ,aAAa;gBACfF,OAAOO,IAAI,CACT,IAAI,CAACnC,MAAM,CAACoC,iBAAiB,CAAC;oBAC5BC,SAASP;oBACT3B,aAAa0B,MAAMJ,OAAO;oBAC1BO,aAAaH,MAAMG,WAAW;gBAChC;YAEJ,OAAO;gBACLX,YAAYiB,MAAM,CAACT,MAAMJ,OAAO,CAACC,GAAG;YACtC;QACF;QAEA,KAAK,MAAMG,SAASX,cAAe;YACjC,MAAMY,cAAc,IAAI,CAAC/B,MAAM,CAACgC,sBAAsB,CACpDF,MAAMQ,OAAO,CAACJ,QAAQ,EACtBJ,MAAMQ,OAAO,CAACH,WAAW;YAE3B,IAAIJ,aAAa;gBACfF,OAAOO,IAAI,CACT,IAAI,CAACnC,MAAM,CAACoC,iBAAiB,CAAC;oBAC5BC,SAASP;oBACT3B,aAAa0B,MAAMJ,OAAO;oBAC1BO,aAAaH,MAAMQ,OAAO;gBAC5B;YAEJ,OAAO;gBACLhB,YAAYiB,MAAM,CAACT,MAAMJ,OAAO,CAACC,GAAG;YACtC;QACF;QAEA,KAAK,MAAMa,QAAQxB,UAAW;YAC5B,IAAI,CAACM,YAAYmB,GAAG,CAACD,KAAKb,GAAG,GAAG;gBAC9BE,OAAOO,IAAI,CAAC,IAAI,CAACnC,MAAM,CAACyC,mBAAmB,CAACF;YAC9C;QACF;QACA,OAAOX;IACT;IAEQT,gBAAoC;QAC1C,OAAO,IAAI7B,mBAAmB;YAAEG,SAAS,IAAI,CAACK,IAAI;QAAC;IACrD;IAEA4C,gBAAgBC,eAAuB,EAAE1C,OAA6B,EAAyB;QAC7F,OAAO,IAAI,CAACF,MAAM,CAAC2C,eAAe,CAACC,iBAAiB1C;IACtD;IAEA,MAAM2C,aAAaC,IAA0B,EAA6B;QACxE,MAAMC,YAAYD,MAAME;QACxB,MAAMC,YAA8B,EAAE;QACtC,KAAK,MAAM,EAAEf,QAAQ,EAAEgB,UAAU,EAAE,IAAI,IAAI,CAAC9B,aAAa,GAAG+B,8BAA8B,GAAI;YAC5F,MAAMC,UAAU,IAAI,CAACC,gBAAgB,CAACnB,UAAUgB;YAChD,IAAI,CAACE,SAAS;YACd,IAAIL,cAAcO,aAAaF,QAAQJ,GAAG,KAAKD,WAAW;YAC1DE,UAAUb,IAAI,CAACgB;QACjB;QACA,OAAOH;IACT;IAEA,MAAMM,iBAAiBC,SAAiB,EAA6B;QACnE,OAAO,IAAI,CAACpC,aAAa,GACtBqC,8BAA8B,CAACD,WAC/BhC,GAAG,CAAC,CAAC,EAAEU,QAAQ,EAAEgB,UAAU,EAAE,GAAK,IAAI,CAACG,gBAAgB,CAACnB,UAAUgB,aAClEQ,MAAM,CAAC,CAACN,UAAuCA,SAASI,cAAcA;IAC3E;IAEQH,iBAAiBnB,QAAgB,EAAEgB,UAAkB,EAAyB;QACpF,MAAMZ,UAAU,IAAI,CAACtC,MAAM,CAAC2D,WAAW,CAACzB,UAAUgB;QAClD,IAAI,CAACZ,SAASsB,cAAc,CAACtB,SAASuB,kBAAkB,OAAO;QAC/D,MAAMC,OAAOzE,SAAS6C;QACtB,OAAO;YACLtC,MAAM;YACN4D,WAAWlB,QAAQkB,SAAS;YAC5BR,KAAKV,QAAQyB,WAAW,IAAIb;YAC5BW,kBAAkBvB,QAAQuB,gBAAgB,IAAI;YAC9CG,YAAY1B,QAAQ0B,UAAU,IAAIF,MAAMG,SAAS,IAAIC;YACrDC,WAAW7B,QAAQ8B,YAAY,IAAIN,MAAMO,aAAaP,MAAMG,SAAS,IAAIC;YACzEtB,iBAAiBV;QACnB;IACF;AACF"}
@@ -0,0 +1,15 @@
1
+ import type { AgentInfo, ProcessInfo } from "../../adapters/AgentAdapter.js";
2
+ import type { SessionFile } from "../../utils/session.js";
3
+ import { MuseSessionParser, type MuseSession } from "./MuseSessionParser.js";
4
+ export interface MuseSessionAgentInput {
5
+ session: MuseSession;
6
+ processInfo: ProcessInfo;
7
+ sessionFile: SessionFile;
8
+ }
9
+ export declare class MuseAgentMapper {
10
+ private readonly parser;
11
+ constructor(parser?: MuseSessionParser);
12
+ mapSessionToAgent({ session, processInfo, sessionFile }: MuseSessionAgentInput): AgentInfo;
13
+ mapProcessOnlyAgent(processInfo: ProcessInfo): AgentInfo;
14
+ }
15
+ //# sourceMappingURL=MuseAgentMapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MuseAgentMapper.d.ts","sourceRoot":"","sources":["../../../src/harnesses/muse/MuseAgentMapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAE7E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAG7E,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,WAAW,CAAC;IACrB,WAAW,EAAE,WAAW,CAAC;IACzB,WAAW,EAAE,WAAW,CAAC;CAC1B;AAED,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,GAAE,iBAA2C;IAEhF,iBAAiB,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,EAAE,qBAAqB,GAAG,SAAS;IAc1F,mBAAmB,CAAC,WAAW,EAAE,WAAW,GAAG,SAAS;CAGzD"}
@@ -0,0 +1,29 @@
1
+ import { generateAgentName } from "../../utils/matching.js";
2
+ import { MuseSessionParser } from "./MuseSessionParser.js";
3
+ import { processOnlyAgent } from "../shared.js";
4
+ export class MuseAgentMapper {
5
+ parser;
6
+ constructor(parser = new MuseSessionParser()){
7
+ this.parser = parser;
8
+ }
9
+ mapSessionToAgent({ session, processInfo, sessionFile }) {
10
+ return {
11
+ name: generateAgentName(processInfo.cwd, processInfo.pid),
12
+ type: "muse",
13
+ status: this.parser.determineStatus(session),
14
+ summary: session.lastUserMessage || "Session started",
15
+ pid: processInfo.pid,
16
+ projectPath: session.projectPath || sessionFile.resolvedCwd || processInfo.cwd || "",
17
+ sessionId: sessionFile.sessionId,
18
+ lastActive: session.lastActive,
19
+ sessionFilePath: sessionFile.filePath
20
+ };
21
+ }
22
+ mapProcessOnlyAgent(processInfo) {
23
+ return processOnlyAgent("muse", processInfo, {
24
+ summary: "Muse process running"
25
+ });
26
+ }
27
+ }
28
+
29
+ //# sourceMappingURL=MuseAgentMapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/harnesses/muse/MuseAgentMapper.ts"],"sourcesContent":["import type { AgentInfo, ProcessInfo } from \"../../adapters/AgentAdapter.js\";\nimport { generateAgentName } from \"../../utils/matching.js\";\nimport type { SessionFile } from \"../../utils/session.js\";\nimport { MuseSessionParser, type MuseSession } from \"./MuseSessionParser.js\";\nimport { processOnlyAgent } from \"../shared.js\";\n\nexport interface MuseSessionAgentInput {\n session: MuseSession;\n processInfo: ProcessInfo;\n sessionFile: SessionFile;\n}\n\nexport class MuseAgentMapper {\n constructor(private readonly parser: MuseSessionParser = new MuseSessionParser()) {}\n\n mapSessionToAgent({ session, processInfo, sessionFile }: MuseSessionAgentInput): AgentInfo {\n return {\n name: generateAgentName(processInfo.cwd, processInfo.pid),\n type: \"muse\",\n status: this.parser.determineStatus(session),\n summary: session.lastUserMessage || \"Session started\",\n pid: processInfo.pid,\n projectPath: session.projectPath || sessionFile.resolvedCwd || processInfo.cwd || \"\",\n sessionId: sessionFile.sessionId,\n lastActive: session.lastActive,\n sessionFilePath: sessionFile.filePath,\n };\n }\n\n mapProcessOnlyAgent(processInfo: ProcessInfo): AgentInfo {\n return processOnlyAgent(\"muse\", processInfo, { summary: \"Muse process running\" });\n }\n}\n"],"names":["generateAgentName","MuseSessionParser","processOnlyAgent","MuseAgentMapper","parser","mapSessionToAgent","session","processInfo","sessionFile","name","cwd","pid","type","status","determineStatus","summary","lastUserMessage","projectPath","resolvedCwd","sessionId","lastActive","sessionFilePath","filePath","mapProcessOnlyAgent"],"mappings":"AACA,SAASA,iBAAiB,QAAQ,0BAA0B;AAE5D,SAASC,iBAAiB,QAA0B,yBAAyB;AAC7E,SAASC,gBAAgB,QAAQ,eAAe;AAQhD,OAAO,MAAMC;;IACX,YAAY,AAAiBC,SAA4B,IAAIH,mBAAmB,CAAE;aAArDG,SAAAA;IAAsD;IAEnFC,kBAAkB,EAAEC,OAAO,EAAEC,WAAW,EAAEC,WAAW,EAAyB,EAAa;QACzF,OAAO;YACLC,MAAMT,kBAAkBO,YAAYG,GAAG,EAAEH,YAAYI,GAAG;YACxDC,MAAM;YACNC,QAAQ,IAAI,CAACT,MAAM,CAACU,eAAe,CAACR;YACpCS,SAAST,QAAQU,eAAe,IAAI;YACpCL,KAAKJ,YAAYI,GAAG;YACpBM,aAAaX,QAAQW,WAAW,IAAIT,YAAYU,WAAW,IAAIX,YAAYG,GAAG,IAAI;YAClFS,WAAWX,YAAYW,SAAS;YAChCC,YAAYd,QAAQc,UAAU;YAC9BC,iBAAiBb,YAAYc,QAAQ;QACvC;IACF;IAEAC,oBAAoBhB,WAAwB,EAAa;QACvD,OAAOL,iBAAiB,QAAQK,aAAa;YAAEQ,SAAS;QAAuB;IACjF;AACF"}
@@ -0,0 +1,61 @@
1
+ import type { ProcessInfo } from "../../adapters/AgentAdapter.js";
2
+ import { type MatchResult } from "../../utils/matching.js";
3
+ import { type SessionFile } from "../../utils/session.js";
4
+ /** Entry in `~/.local/share/muse/runtime/muse/sessions/<session-id>.json`. */
5
+ export interface MuseRuntimeEntry {
6
+ sessionId: string;
7
+ pid: number;
8
+ }
9
+ /** A live Muse process paired with its transcript through the runtime file. */
10
+ export interface MuseDirectMatch {
11
+ process: ProcessInfo;
12
+ sessionFile: SessionFile;
13
+ }
14
+ export interface MuseProcessSessionMatches {
15
+ direct: MuseDirectMatch[];
16
+ legacyMatches: MatchResult[];
17
+ /** Muse processes no strategy could pair (become process-only agents). */
18
+ fallback: ProcessInfo[];
19
+ }
20
+ export interface MuseSessionLocatorOptions {
21
+ homeDir?: string;
22
+ runtimeDir?: string;
23
+ archiveDir?: string;
24
+ }
25
+ export declare class MuseSessionLocator {
26
+ private readonly home;
27
+ private readonly runtimeDir;
28
+ private readonly archiveDir;
29
+ constructor(options?: MuseSessionLocatorOptions);
30
+ /**
31
+ * Pair live Muse processes with transcripts.
32
+ *
33
+ * Two staged strategies, each handing unmatched processes onward:
34
+ * 1. Runtime-file matching via `runtime/muse/sessions/<id>.json`
35
+ * (authoritative; guarded against recycled pids).
36
+ * 2. Legacy cwd+birthtime heuristic over recent transcripts.
37
+ */
38
+ matchRunningProcesses(processes: ProcessInfo[]): MuseProcessSessionMatches;
39
+ private tryRuntimeFileMatching;
40
+ /** Recent transcripts for legacy cwd+birthtime matching (today-first, bounded). */
41
+ discoverLiveSessions(processes: ProcessInfo[]): SessionFile[];
42
+ /**
43
+ * Every archived transcript: walks `sessions/yyyy/mm/dd/<uuid>/session.jsonl`.
44
+ * Only directories matching the session-id pattern that contain a transcript
45
+ * are returned; `subagent/`, logs, and databases never match.
46
+ */
47
+ discoverHistoricalSessionFiles(): Array<{
48
+ filePath: string;
49
+ defaultCwd: string;
50
+ }>;
51
+ findHistoricalSessionFilesById(sessionId: string): Array<{
52
+ filePath: string;
53
+ defaultCwd: string;
54
+ }>;
55
+ /** Exact transcript lookup by session id across dated dirs. */
56
+ findTranscriptById(sessionId: string): string | null;
57
+ private walkTranscripts;
58
+ /** Dated directories `sessions/yyyy/mm/dd`, each level guarded by a pattern. */
59
+ private listDayDirs;
60
+ }
61
+ //# sourceMappingURL=MuseSessionLocator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MuseSessionLocator.d.ts","sourceRoot":"","sources":["../../../src/harnesses/muse/MuseSessionLocator.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,EAA4B,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACrF,OAAO,EAKL,KAAK,WAAW,EACjB,MAAM,wBAAwB,CAAC;AAGhC,8EAA8E;AAC9E,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,+EAA+E;AAC/E,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,WAAW,CAAC;IACrB,WAAW,EAAE,WAAW,CAAC;CAC1B;AAED,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,aAAa,EAAE,WAAW,EAAE,CAAC;IAC7B,0EAA0E;IAC1E,QAAQ,EAAE,WAAW,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,yBAAyB;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AA6ED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAExB,OAAO,GAAE,yBAA8B;IAOnD;;;;;;;OAOG;IACH,qBAAqB,CAAC,SAAS,EAAE,WAAW,EAAE,GAAG,yBAAyB;IAmB1E,OAAO,CAAC,sBAAsB;IAyC9B,mFAAmF;IACnF,oBAAoB,CAAC,SAAS,EAAE,WAAW,EAAE,GAAG,WAAW,EAAE;IA2B7D;;;;OAIG;IACH,8BAA8B,IAAI,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAQjF,8BAA8B,CAC5B,SAAS,EAAE,MAAM,GAChB,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAMlD,+DAA+D;IAC/D,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IASpD,OAAO,CAAC,eAAe;IAYvB,gFAAgF;IAChF,OAAO,CAAC,WAAW;CAoBpB"}