@codemieai/code 0.11.0 → 0.13.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 (253) hide show
  1. package/README.md +109 -56
  2. package/bin/codemie-copilot.js +224 -0
  3. package/bin/codemie-pi.js +18 -0
  4. package/dist/agents/core/AgentCLI.d.ts.map +1 -1
  5. package/dist/agents/core/AgentCLI.js +16 -10
  6. package/dist/agents/core/AgentCLI.js.map +1 -1
  7. package/dist/agents/core/BaseAgentAdapter.d.ts.map +1 -1
  8. package/dist/agents/core/BaseAgentAdapter.js +43 -19
  9. package/dist/agents/core/BaseAgentAdapter.js.map +1 -1
  10. package/dist/agents/core/agent-aliases.d.ts +17 -0
  11. package/dist/agents/core/agent-aliases.d.ts.map +1 -0
  12. package/dist/agents/core/agent-aliases.js +41 -0
  13. package/dist/agents/core/agent-aliases.js.map +1 -0
  14. package/dist/agents/core/session/BaseSessionAdapter.d.ts +19 -0
  15. package/dist/agents/core/session/BaseSessionAdapter.d.ts.map +1 -1
  16. package/dist/agents/core/session/session-origin-audit.d.ts +13 -0
  17. package/dist/agents/core/session/session-origin-audit.d.ts.map +1 -1
  18. package/dist/agents/core/session/session-origin-audit.js +34 -0
  19. package/dist/agents/core/session/session-origin-audit.js.map +1 -1
  20. package/dist/agents/core/session/stale-session-reconciliation.d.ts +42 -0
  21. package/dist/agents/core/session/stale-session-reconciliation.d.ts.map +1 -0
  22. package/dist/agents/core/session/stale-session-reconciliation.js +141 -0
  23. package/dist/agents/core/session/stale-session-reconciliation.js.map +1 -0
  24. package/dist/agents/core/session/types.d.ts +19 -0
  25. package/dist/agents/core/session/types.d.ts.map +1 -1
  26. package/dist/agents/core/session/types.js +17 -1
  27. package/dist/agents/core/session/types.js.map +1 -1
  28. package/dist/agents/core/types.d.ts +11 -0
  29. package/dist/agents/core/types.d.ts.map +1 -1
  30. package/dist/agents/plugins/codex/codex.reconciliation.d.ts +15 -35
  31. package/dist/agents/plugins/codex/codex.reconciliation.d.ts.map +1 -1
  32. package/dist/agents/plugins/codex/codex.reconciliation.js +8 -139
  33. package/dist/agents/plugins/codex/codex.reconciliation.js.map +1 -1
  34. package/dist/agents/plugins/copilot-cli/copilot-cli-event-types.d.ts +146 -0
  35. package/dist/agents/plugins/copilot-cli/copilot-cli-event-types.d.ts.map +1 -0
  36. package/dist/agents/plugins/copilot-cli/copilot-cli-event-types.js +12 -0
  37. package/dist/agents/plugins/copilot-cli/copilot-cli-event-types.js.map +1 -0
  38. package/dist/agents/plugins/copilot-cli/copilot-cli.constants.d.ts +15 -0
  39. package/dist/agents/plugins/copilot-cli/copilot-cli.constants.d.ts.map +1 -0
  40. package/dist/agents/plugins/copilot-cli/copilot-cli.constants.js +15 -0
  41. package/dist/agents/plugins/copilot-cli/copilot-cli.constants.js.map +1 -0
  42. package/dist/agents/plugins/copilot-cli/copilot-cli.models.d.ts +8 -0
  43. package/dist/agents/plugins/copilot-cli/copilot-cli.models.d.ts.map +1 -0
  44. package/dist/agents/plugins/copilot-cli/copilot-cli.models.js +195 -0
  45. package/dist/agents/plugins/copilot-cli/copilot-cli.models.js.map +1 -0
  46. package/dist/agents/plugins/copilot-cli/copilot-cli.paths.d.ts +11 -0
  47. package/dist/agents/plugins/copilot-cli/copilot-cli.paths.d.ts.map +1 -0
  48. package/dist/agents/plugins/copilot-cli/copilot-cli.paths.js +21 -0
  49. package/dist/agents/plugins/copilot-cli/copilot-cli.paths.js.map +1 -0
  50. package/dist/agents/plugins/copilot-cli/copilot-cli.plugin.d.ts +14 -0
  51. package/dist/agents/plugins/copilot-cli/copilot-cli.plugin.d.ts.map +1 -0
  52. package/dist/agents/plugins/copilot-cli/copilot-cli.plugin.js +263 -0
  53. package/dist/agents/plugins/copilot-cli/copilot-cli.plugin.js.map +1 -0
  54. package/dist/agents/plugins/copilot-cli/copilot-cli.session.d.ts +43 -0
  55. package/dist/agents/plugins/copilot-cli/copilot-cli.session.d.ts.map +1 -0
  56. package/dist/agents/plugins/copilot-cli/copilot-cli.session.js +343 -0
  57. package/dist/agents/plugins/copilot-cli/copilot-cli.session.js.map +1 -0
  58. package/dist/agents/plugins/copilot-cli/copilot-cli.storage-utils.d.ts +10 -0
  59. package/dist/agents/plugins/copilot-cli/copilot-cli.storage-utils.d.ts.map +1 -0
  60. package/dist/agents/plugins/copilot-cli/copilot-cli.storage-utils.js +41 -0
  61. package/dist/agents/plugins/copilot-cli/copilot-cli.storage-utils.js.map +1 -0
  62. package/dist/agents/plugins/copilot-cli/copilot-cli.usage.d.ts +37 -0
  63. package/dist/agents/plugins/copilot-cli/copilot-cli.usage.d.ts.map +1 -0
  64. package/dist/agents/plugins/copilot-cli/copilot-cli.usage.js +96 -0
  65. package/dist/agents/plugins/copilot-cli/copilot-cli.usage.js.map +1 -0
  66. package/dist/agents/plugins/copilot-cli/copilot-cli.workspace.d.ts +17 -0
  67. package/dist/agents/plugins/copilot-cli/copilot-cli.workspace.d.ts.map +1 -0
  68. package/dist/agents/plugins/copilot-cli/copilot-cli.workspace.js +58 -0
  69. package/dist/agents/plugins/copilot-cli/copilot-cli.workspace.js.map +1 -0
  70. package/dist/agents/plugins/copilot-cli/index.d.ts +3 -0
  71. package/dist/agents/plugins/copilot-cli/index.d.ts.map +1 -0
  72. package/dist/agents/plugins/copilot-cli/index.js +3 -0
  73. package/dist/agents/plugins/copilot-cli/index.js.map +1 -0
  74. package/dist/agents/plugins/copilot-cli/session/processors/copilot-cli.conversations-processor.d.ts +18 -0
  75. package/dist/agents/plugins/copilot-cli/session/processors/copilot-cli.conversations-processor.d.ts.map +1 -0
  76. package/dist/agents/plugins/copilot-cli/session/processors/copilot-cli.conversations-processor.js +313 -0
  77. package/dist/agents/plugins/copilot-cli/session/processors/copilot-cli.conversations-processor.js.map +1 -0
  78. package/dist/agents/plugins/copilot-cli/session/processors/copilot-cli.metrics-processor.d.ts +16 -0
  79. package/dist/agents/plugins/copilot-cli/session/processors/copilot-cli.metrics-processor.d.ts.map +1 -0
  80. package/dist/agents/plugins/copilot-cli/session/processors/copilot-cli.metrics-processor.js +22 -0
  81. package/dist/agents/plugins/copilot-cli/session/processors/copilot-cli.metrics-processor.js.map +1 -0
  82. package/dist/agents/plugins/pi/__tests__/home-redirect.d.ts +12 -0
  83. package/dist/agents/plugins/pi/__tests__/home-redirect.d.ts.map +1 -0
  84. package/dist/agents/plugins/pi/__tests__/home-redirect.js +27 -0
  85. package/dist/agents/plugins/pi/__tests__/home-redirect.js.map +1 -0
  86. package/dist/agents/plugins/pi/extension/README.md +68 -0
  87. package/dist/agents/plugins/pi/extension/index.js +161 -0
  88. package/dist/agents/plugins/pi/extension/package.json +8 -0
  89. package/dist/agents/plugins/pi/index.d.ts +3 -0
  90. package/dist/agents/plugins/pi/index.d.ts.map +1 -0
  91. package/dist/agents/plugins/pi/index.js +3 -0
  92. package/dist/agents/plugins/pi/index.js.map +1 -0
  93. package/dist/agents/plugins/pi/pi.extension.d.ts +60 -0
  94. package/dist/agents/plugins/pi/pi.extension.d.ts.map +1 -0
  95. package/dist/agents/plugins/pi/pi.extension.js +201 -0
  96. package/dist/agents/plugins/pi/pi.extension.js.map +1 -0
  97. package/dist/agents/plugins/pi/pi.incremental-sync.d.ts +63 -0
  98. package/dist/agents/plugins/pi/pi.incremental-sync.d.ts.map +1 -0
  99. package/dist/agents/plugins/pi/pi.incremental-sync.js +266 -0
  100. package/dist/agents/plugins/pi/pi.incremental-sync.js.map +1 -0
  101. package/dist/agents/plugins/pi/pi.models.d.ts +20 -0
  102. package/dist/agents/plugins/pi/pi.models.d.ts.map +1 -0
  103. package/dist/agents/plugins/pi/pi.models.js +201 -0
  104. package/dist/agents/plugins/pi/pi.models.js.map +1 -0
  105. package/dist/agents/plugins/pi/pi.packages.d.ts +11 -0
  106. package/dist/agents/plugins/pi/pi.packages.d.ts.map +1 -0
  107. package/dist/agents/plugins/pi/pi.packages.js +35 -0
  108. package/dist/agents/plugins/pi/pi.packages.js.map +1 -0
  109. package/dist/agents/plugins/pi/pi.paths.d.ts +37 -0
  110. package/dist/agents/plugins/pi/pi.paths.d.ts.map +1 -0
  111. package/dist/agents/plugins/pi/pi.paths.js +146 -0
  112. package/dist/agents/plugins/pi/pi.paths.js.map +1 -0
  113. package/dist/agents/plugins/pi/pi.plugin.d.ts +30 -0
  114. package/dist/agents/plugins/pi/pi.plugin.d.ts.map +1 -0
  115. package/dist/agents/plugins/pi/pi.plugin.js +453 -0
  116. package/dist/agents/plugins/pi/pi.plugin.js.map +1 -0
  117. package/dist/agents/plugins/pi/pi.session.d.ts +114 -0
  118. package/dist/agents/plugins/pi/pi.session.d.ts.map +1 -0
  119. package/dist/agents/plugins/pi/pi.session.js +388 -0
  120. package/dist/agents/plugins/pi/pi.session.js.map +1 -0
  121. package/dist/agents/plugins/pi/pi.setup.d.ts +2 -0
  122. package/dist/agents/plugins/pi/pi.setup.d.ts.map +1 -0
  123. package/dist/agents/plugins/pi/pi.setup.js +33 -0
  124. package/dist/agents/plugins/pi/pi.setup.js.map +1 -0
  125. package/dist/agents/plugins/pi/pi.types.d.ts +143 -0
  126. package/dist/agents/plugins/pi/pi.types.d.ts.map +1 -0
  127. package/dist/agents/plugins/pi/pi.types.js +74 -0
  128. package/dist/agents/plugins/pi/pi.types.js.map +1 -0
  129. package/dist/agents/plugins/pi/session/pi-file-operations.d.ts +17 -0
  130. package/dist/agents/plugins/pi/session/pi-file-operations.d.ts.map +1 -0
  131. package/dist/agents/plugins/pi/session/pi-file-operations.js +98 -0
  132. package/dist/agents/plugins/pi/session/pi-file-operations.js.map +1 -0
  133. package/dist/agents/plugins/pi/session/pi-named-invocations.d.ts +52 -0
  134. package/dist/agents/plugins/pi/session/pi-named-invocations.d.ts.map +1 -0
  135. package/dist/agents/plugins/pi/session/pi-named-invocations.js +189 -0
  136. package/dist/agents/plugins/pi/session/pi-named-invocations.js.map +1 -0
  137. package/dist/agents/plugins/pi/session/pi-user-prompt.d.ts +14 -0
  138. package/dist/agents/plugins/pi/session/pi-user-prompt.d.ts.map +1 -0
  139. package/dist/agents/plugins/pi/session/pi-user-prompt.js +51 -0
  140. package/dist/agents/plugins/pi/session/pi-user-prompt.js.map +1 -0
  141. package/dist/agents/plugins/pi/session/processors/pi.conversations-processor.d.ts +52 -0
  142. package/dist/agents/plugins/pi/session/processors/pi.conversations-processor.d.ts.map +1 -0
  143. package/dist/agents/plugins/pi/session/processors/pi.conversations-processor.js +716 -0
  144. package/dist/agents/plugins/pi/session/processors/pi.conversations-processor.js.map +1 -0
  145. package/dist/agents/plugins/pi/session/processors/pi.metrics-processor.d.ts +104 -0
  146. package/dist/agents/plugins/pi/session/processors/pi.metrics-processor.d.ts.map +1 -0
  147. package/dist/agents/plugins/pi/session/processors/pi.metrics-processor.js +595 -0
  148. package/dist/agents/plugins/pi/session/processors/pi.metrics-processor.js.map +1 -0
  149. package/dist/agents/registry.d.ts +20 -0
  150. package/dist/agents/registry.d.ts.map +1 -1
  151. package/dist/agents/registry.js +29 -2
  152. package/dist/agents/registry.js.map +1 -1
  153. package/dist/cli/commands/analytics/agent-labels.d.ts +3 -0
  154. package/dist/cli/commands/analytics/agent-labels.d.ts.map +1 -0
  155. package/dist/cli/commands/analytics/agent-labels.js +20 -0
  156. package/dist/cli/commands/analytics/agent-labels.js.map +1 -0
  157. package/dist/cli/commands/analytics/cost/cost-enricher.d.ts.map +1 -1
  158. package/dist/cli/commands/analytics/cost/cost-enricher.js +12 -0
  159. package/dist/cli/commands/analytics/cost/cost-enricher.js.map +1 -1
  160. package/dist/cli/commands/analytics/cost/types.d.ts +10 -0
  161. package/dist/cli/commands/analytics/cost/types.d.ts.map +1 -1
  162. package/dist/cli/commands/analytics/cost/usage-readers.d.ts +24 -0
  163. package/dist/cli/commands/analytics/cost/usage-readers.d.ts.map +1 -1
  164. package/dist/cli/commands/analytics/cost/usage-readers.js +253 -54
  165. package/dist/cli/commands/analytics/cost/usage-readers.js.map +1 -1
  166. package/dist/cli/commands/analytics/formatter.d.ts.map +1 -1
  167. package/dist/cli/commands/analytics/formatter.js +10 -2
  168. package/dist/cli/commands/analytics/formatter.js.map +1 -1
  169. package/dist/cli/commands/analytics/index.d.ts.map +1 -1
  170. package/dist/cli/commands/analytics/index.js +22 -0
  171. package/dist/cli/commands/analytics/index.js.map +1 -1
  172. package/dist/cli/commands/analytics/native-loader.d.ts +21 -4
  173. package/dist/cli/commands/analytics/native-loader.d.ts.map +1 -1
  174. package/dist/cli/commands/analytics/native-loader.js +267 -88
  175. package/dist/cli/commands/analytics/native-loader.js.map +1 -1
  176. package/dist/cli/commands/analytics/report/client/app.js +77 -15
  177. package/dist/cli/commands/analytics/report/payload-builder.d.ts.map +1 -1
  178. package/dist/cli/commands/analytics/report/payload-builder.js +32 -2
  179. package/dist/cli/commands/analytics/report/payload-builder.js.map +1 -1
  180. package/dist/cli/commands/analytics/report/types.d.ts +11 -0
  181. package/dist/cli/commands/analytics/report/types.d.ts.map +1 -1
  182. package/dist/cli/commands/hook.d.ts.map +1 -1
  183. package/dist/cli/commands/hook.js +71 -29
  184. package/dist/cli/commands/hook.js.map +1 -1
  185. package/dist/cli/commands/install.d.ts.map +1 -1
  186. package/dist/cli/commands/install.js +9 -7
  187. package/dist/cli/commands/install.js.map +1 -1
  188. package/dist/cli/commands/list.d.ts.map +1 -1
  189. package/dist/cli/commands/list.js +4 -2
  190. package/dist/cli/commands/list.js.map +1 -1
  191. package/dist/cli/commands/setup.d.ts +3 -1
  192. package/dist/cli/commands/setup.d.ts.map +1 -1
  193. package/dist/cli/commands/setup.js +87 -63
  194. package/dist/cli/commands/setup.js.map +1 -1
  195. package/dist/cli/commands/uninstall.d.ts.map +1 -1
  196. package/dist/cli/commands/uninstall.js +6 -4
  197. package/dist/cli/commands/uninstall.js.map +1 -1
  198. package/dist/cli/commands/update.d.ts.map +1 -1
  199. package/dist/cli/commands/update.js +7 -5
  200. package/dist/cli/commands/update.js.map +1 -1
  201. package/dist/cli/first-time.d.ts.map +1 -1
  202. package/dist/cli/first-time.js +10 -9
  203. package/dist/cli/first-time.js.map +1 -1
  204. package/dist/providers/core/auth-validation.d.ts +7 -2
  205. package/dist/providers/core/auth-validation.d.ts.map +1 -1
  206. package/dist/providers/core/auth-validation.js +11 -5
  207. package/dist/providers/core/auth-validation.js.map +1 -1
  208. package/dist/providers/core/types.d.ts +16 -0
  209. package/dist/providers/core/types.d.ts.map +1 -1
  210. package/dist/providers/core/types.js.map +1 -1
  211. package/dist/providers/plugins/sso/proxy/plugins/claude-request-normalizer.plugin.d.ts +8 -3
  212. package/dist/providers/plugins/sso/proxy/plugins/claude-request-normalizer.plugin.d.ts.map +1 -1
  213. package/dist/providers/plugins/sso/proxy/plugins/claude-request-normalizer.plugin.js +46 -11
  214. package/dist/providers/plugins/sso/proxy/plugins/claude-request-normalizer.plugin.js.map +1 -1
  215. package/dist/providers/plugins/sso/proxy/plugins/codex-encrypted-content-sanitizer.plugin.d.ts +23 -13
  216. package/dist/providers/plugins/sso/proxy/plugins/codex-encrypted-content-sanitizer.plugin.d.ts.map +1 -1
  217. package/dist/providers/plugins/sso/proxy/plugins/codex-encrypted-content-sanitizer.plugin.js +75 -18
  218. package/dist/providers/plugins/sso/proxy/plugins/codex-encrypted-content-sanitizer.plugin.js.map +1 -1
  219. package/dist/providers/plugins/sso/proxy/plugins/copilot-encrypted-content-sanitizer.plugin.d.ts +21 -0
  220. package/dist/providers/plugins/sso/proxy/plugins/copilot-encrypted-content-sanitizer.plugin.d.ts.map +1 -0
  221. package/dist/providers/plugins/sso/proxy/plugins/copilot-encrypted-content-sanitizer.plugin.js +133 -0
  222. package/dist/providers/plugins/sso/proxy/plugins/copilot-encrypted-content-sanitizer.plugin.js.map +1 -0
  223. package/dist/providers/plugins/sso/proxy/plugins/header-injection.plugin.js +1 -1
  224. package/dist/providers/plugins/sso/proxy/plugins/header-injection.plugin.js.map +1 -1
  225. package/dist/providers/plugins/sso/proxy/plugins/index.d.ts +2 -1
  226. package/dist/providers/plugins/sso/proxy/plugins/index.d.ts.map +1 -1
  227. package/dist/providers/plugins/sso/proxy/plugins/index.js +4 -2
  228. package/dist/providers/plugins/sso/proxy/plugins/index.js.map +1 -1
  229. package/dist/providers/plugins/sso/proxy/plugins/types.d.ts +11 -0
  230. package/dist/providers/plugins/sso/proxy/plugins/types.d.ts.map +1 -1
  231. package/dist/providers/plugins/sso/proxy/sso.proxy.d.ts +2 -0
  232. package/dist/providers/plugins/sso/proxy/sso.proxy.d.ts.map +1 -1
  233. package/dist/providers/plugins/sso/proxy/sso.proxy.js +37 -1
  234. package/dist/providers/plugins/sso/proxy/sso.proxy.js.map +1 -1
  235. package/dist/providers/plugins/sso/session/SessionSyncer.d.ts.map +1 -1
  236. package/dist/providers/plugins/sso/session/SessionSyncer.js +13 -0
  237. package/dist/providers/plugins/sso/session/SessionSyncer.js.map +1 -1
  238. package/dist/providers/plugins/sso/session/processors/conversations/syncProcessor.js +6 -0
  239. package/dist/providers/plugins/sso/session/processors/conversations/syncProcessor.js.map +1 -1
  240. package/dist/providers/plugins/sso/session/processors/metrics/metrics-post-processor.d.ts +0 -6
  241. package/dist/providers/plugins/sso/session/processors/metrics/metrics-post-processor.d.ts.map +1 -1
  242. package/dist/providers/plugins/sso/session/processors/metrics/metrics-post-processor.js +28 -19
  243. package/dist/providers/plugins/sso/session/processors/metrics/metrics-post-processor.js.map +1 -1
  244. package/dist/providers/plugins/sso/sso.setup-steps.d.ts.map +1 -1
  245. package/dist/providers/plugins/sso/sso.setup-steps.js +39 -22
  246. package/dist/providers/plugins/sso/sso.setup-steps.js.map +1 -1
  247. package/dist/utils/interactive.d.ts +14 -0
  248. package/dist/utils/interactive.d.ts.map +1 -0
  249. package/dist/utils/interactive.js +16 -0
  250. package/dist/utils/interactive.js.map +1 -0
  251. package/package.json +6 -5
  252. package/scripts/copy-plugins.js +6 -0
  253. package/scripts/release.sh +54 -0
@@ -0,0 +1,313 @@
1
+ /**
2
+ * Conversations processor for Copilot CLI sessions.
3
+ *
4
+ * Copilot persists prompt text in `events.jsonl`; `parseSessionFile` captures it into
5
+ * `ParsedSession.messages`. Unlike Claude and Pi, Copilot does not currently emit
6
+ * mid-turn hook events through CodeMie, so this processor drains the whole discovered
7
+ * transcript on SessionEnd and appends pending payload windows to the standard
8
+ * `_conversation.jsonl` spool for the shared sync pipeline.
9
+ */
10
+ import { appendFile, mkdir } from 'fs/promises';
11
+ import { dirname } from 'path';
12
+ import { getSessionConversationPath } from '../../../../core/session/session-config.js';
13
+ import { CODEMIE_ASSISTANT_ID, CONVERSATION_PROCESSOR_NAME } from '../../../../../providers/plugins/sso/session/processors/conversations/constants.js';
14
+ import { CONVERSATION_SYNC_STATUS } from '../../../../../providers/plugins/sso/session/processors/conversations/types.js';
15
+ import { readJSONL } from '../../../../../providers/plugins/sso/session/utils/jsonl-reader.js';
16
+ import { logger } from '../../../../../utils/logger.js';
17
+ function asTurnRecord(value) {
18
+ if (!value || typeof value !== 'object')
19
+ return null;
20
+ return value;
21
+ }
22
+ function parseTimestampMs(value) {
23
+ if (!value)
24
+ return undefined;
25
+ const parsed = Date.parse(value);
26
+ return Number.isNaN(parsed) ? undefined : parsed;
27
+ }
28
+ function calculateResponseTimeSeconds(start, end) {
29
+ const startMs = parseTimestampMs(start);
30
+ const endMs = parseTimestampMs(end);
31
+ if (startMs === undefined || endMs === undefined || endMs < startMs) {
32
+ return undefined;
33
+ }
34
+ return Math.max(0, Math.round(((endMs - startMs) / 1000) * 100) / 100);
35
+ }
36
+ function stringify(value) {
37
+ if (value === undefined || value === null)
38
+ return '';
39
+ if (typeof value === 'string')
40
+ return value;
41
+ try {
42
+ return JSON.stringify(value, null, 2);
43
+ }
44
+ catch {
45
+ return String(value);
46
+ }
47
+ }
48
+ function buildThoughts(events, historyIndex) {
49
+ const thoughts = [];
50
+ const toolThoughtByCallId = new Map();
51
+ for (const event of events) {
52
+ if (event.kind === 'assistant_commentary') {
53
+ if (!event.text?.trim())
54
+ continue;
55
+ thoughts.push({
56
+ id: `copilot-commentary-${historyIndex}-${event.sourceIndex}`,
57
+ parent_id: null,
58
+ metadata: {
59
+ timestamp: event.timestamp,
60
+ source_index: event.sourceIndex,
61
+ event_kind: event.kind,
62
+ ...(event.metadata ?? {}),
63
+ },
64
+ in_progress: false,
65
+ input_text: '',
66
+ message: event.text,
67
+ author_type: 'Agent',
68
+ author_name: 'GitHub Copilot CLI',
69
+ output_format: 'text',
70
+ error: false,
71
+ interrupted: false,
72
+ aborted: false,
73
+ children: [],
74
+ });
75
+ continue;
76
+ }
77
+ if (event.kind === 'tool_output') {
78
+ const pending = event.callId ? toolThoughtByCallId.get(event.callId) : undefined;
79
+ if (pending) {
80
+ pending.message = event.text ?? '';
81
+ pending.error = event.error === true;
82
+ pending.metadata = {
83
+ ...pending.metadata,
84
+ output_source_index: event.sourceIndex,
85
+ output_timestamp: event.timestamp,
86
+ ...(event.metadata ?? {}),
87
+ };
88
+ toolThoughtByCallId.delete(event.callId);
89
+ continue;
90
+ }
91
+ }
92
+ const thought = {
93
+ id: event.callId || `copilot-tool-${historyIndex}-${event.sourceIndex}`,
94
+ parent_id: null,
95
+ metadata: {
96
+ timestamp: event.timestamp,
97
+ source_index: event.sourceIndex,
98
+ event_kind: event.kind,
99
+ ...(event.callId && { call_id: event.callId }),
100
+ ...(event.metadata ?? {}),
101
+ },
102
+ in_progress: false,
103
+ input_text: event.inputText ?? '',
104
+ message: event.text ?? '',
105
+ author_type: 'Tool',
106
+ author_name: event.toolName || 'Unknown Tool',
107
+ output_format: 'text',
108
+ error: event.error === true,
109
+ interrupted: false,
110
+ aborted: false,
111
+ children: [],
112
+ };
113
+ thoughts.push(thought);
114
+ if (event.kind === 'tool_call' && event.callId) {
115
+ toolThoughtByCallId.set(event.callId, thought);
116
+ }
117
+ }
118
+ return thoughts;
119
+ }
120
+ function toHistory(turn) {
121
+ const history = [];
122
+ if (turn.user?.text) {
123
+ history.push({
124
+ role: 'User',
125
+ message: turn.user.text,
126
+ message_raw: turn.user.text,
127
+ history_index: turn.historyIndex,
128
+ date: turn.user.timestamp,
129
+ file_names: [],
130
+ });
131
+ }
132
+ if (turn.assistant?.text) {
133
+ const thoughts = buildThoughts(turn.events, turn.historyIndex);
134
+ history.push({
135
+ role: 'Assistant',
136
+ message: turn.assistant.text,
137
+ message_raw: turn.assistant.text,
138
+ history_index: turn.historyIndex,
139
+ date: turn.assistant.timestamp,
140
+ response_time: calculateResponseTimeSeconds(turn.user?.timestamp, turn.assistant.timestamp),
141
+ assistant_id: CODEMIE_ASSISTANT_ID,
142
+ thoughts: thoughts.length > 0 ? thoughts : undefined,
143
+ });
144
+ }
145
+ return history;
146
+ }
147
+ function buildTurns(messages) {
148
+ const turns = [];
149
+ let current = null;
150
+ let historyIndex = -1;
151
+ for (const [sourceIndex, raw] of messages.entries()) {
152
+ const record = asTurnRecord(raw);
153
+ const role = record?.message?.role;
154
+ const content = record?.message?.content?.trim();
155
+ if (!role || !content) {
156
+ continue;
157
+ }
158
+ if (role === 'user') {
159
+ historyIndex += 1;
160
+ current = {
161
+ historyIndex,
162
+ user: {
163
+ text: content,
164
+ timestamp: record.timestamp,
165
+ },
166
+ events: [],
167
+ };
168
+ turns.push(current);
169
+ continue;
170
+ }
171
+ if (!current) {
172
+ continue;
173
+ }
174
+ current.assistant = {
175
+ text: content,
176
+ timestamp: record.timestamp,
177
+ model: record.message?.model,
178
+ };
179
+ const toolRequests = Array.isArray(record.message?.toolRequests)
180
+ ? record.message?.toolRequests
181
+ : [];
182
+ if (toolRequests.length > 0) {
183
+ for (const request of toolRequests) {
184
+ current.events.push({
185
+ kind: 'tool_call',
186
+ sourceIndex,
187
+ timestamp: record.timestamp,
188
+ callId: request.toolCallId,
189
+ toolName: request.name,
190
+ inputText: stringify(request.arguments),
191
+ metadata: {
192
+ tool_arguments: request.arguments,
193
+ },
194
+ });
195
+ }
196
+ }
197
+ else {
198
+ current.events.push({
199
+ kind: 'assistant_commentary',
200
+ sourceIndex,
201
+ timestamp: record.timestamp,
202
+ text: content,
203
+ });
204
+ }
205
+ }
206
+ return turns;
207
+ }
208
+ export class CopilotCliConversationsProcessor {
209
+ name = 'copilot-cli-conversations';
210
+ priority = 2;
211
+ shouldProcess(session) {
212
+ if (process.env.CODEMIE_CONV_SYNC_DISABLED === '1')
213
+ return false;
214
+ return session.messages.length > 0;
215
+ }
216
+ async process(session, context) {
217
+ const conversationId = context.agentSessionId?.trim();
218
+ if (!conversationId) {
219
+ logger.warn(`[${this.name}] Missing agentSessionId for session ${session.sessionId}; skipping conversation sync`);
220
+ return {
221
+ success: true,
222
+ message: 'Skipped: missing Copilot conversation id',
223
+ metadata: { recordsProcessed: 0, skipReason: 'MISSING_CONVERSATION_ID' },
224
+ };
225
+ }
226
+ const turns = buildTurns(session.messages);
227
+ if (turns.length === 0) {
228
+ return {
229
+ success: true,
230
+ message: 'No conversation turns generated',
231
+ metadata: { recordsProcessed: 0 },
232
+ };
233
+ }
234
+ const conversationsPath = getSessionConversationPath(session.sessionId);
235
+ await mkdir(dirname(conversationsPath), { recursive: true });
236
+ const existingPayloads = await readJSONL(conversationsPath);
237
+ const { SessionStore } = await import('../../../../core/session/SessionStore.js');
238
+ const sessionStore = new SessionStore();
239
+ const sessionMetadata = await sessionStore.loadSession(session.sessionId);
240
+ let lastHistoryIndex = sessionMetadata?.sync?.conversations?.lastSyncedHistoryIndex ?? -1;
241
+ for (const payload of existingPayloads) {
242
+ if (payload.payload.conversationId !== conversationId)
243
+ continue;
244
+ for (const idx of payload.historyIndices) {
245
+ lastHistoryIndex = Math.max(lastHistoryIndex, idx);
246
+ }
247
+ }
248
+ let payloadsWritten = 0;
249
+ let recordsProcessed = 0;
250
+ let lastSentinel;
251
+ let lastModel;
252
+ for (const turn of turns) {
253
+ if (turn.historyIndex <= lastHistoryIndex) {
254
+ continue;
255
+ }
256
+ const history = toHistory(turn);
257
+ if (history.length === 0) {
258
+ continue;
259
+ }
260
+ const sentinel = `${conversationId}@${turn.historyIndex}`;
261
+ const payloadRecord = {
262
+ payloadId: sentinel,
263
+ timestamp: Date.now(),
264
+ isTurnContinuation: false,
265
+ historyIndices: history.map((entry) => entry.history_index),
266
+ messageCount: history.length,
267
+ lastProcessedMessageUuid: sentinel,
268
+ payload: {
269
+ conversationId,
270
+ history,
271
+ assistantId: CODEMIE_ASSISTANT_ID,
272
+ llmModel: turn.assistant?.model,
273
+ },
274
+ status: CONVERSATION_SYNC_STATUS.PENDING,
275
+ };
276
+ await appendFile(conversationsPath, JSON.stringify(payloadRecord) + '\n');
277
+ payloadsWritten += 1;
278
+ recordsProcessed += history.length;
279
+ lastHistoryIndex = turn.historyIndex;
280
+ lastSentinel = sentinel;
281
+ lastModel = turn.assistant?.model ?? lastModel;
282
+ }
283
+ if (payloadsWritten === 0) {
284
+ return {
285
+ success: true,
286
+ message: 'No new conversation payloads',
287
+ metadata: { recordsProcessed: 0 },
288
+ };
289
+ }
290
+ logger.info(`[${CONVERSATION_PROCESSOR_NAME}] Queued ${payloadsWritten} Copilot conversation payload` +
291
+ `${payloadsWritten === 1 ? '' : 's'} for session ${session.sessionId}`);
292
+ return {
293
+ success: true,
294
+ message: `Queued ${payloadsWritten} Copilot conversation payload(s)`,
295
+ metadata: {
296
+ recordsProcessed,
297
+ payloadsWritten,
298
+ syncUpdates: {
299
+ conversations: {
300
+ lastSyncedMessageUuid: lastSentinel,
301
+ lastSyncedHistoryIndex: lastHistoryIndex,
302
+ conversationId,
303
+ totalMessagesSynced: recordsProcessed,
304
+ totalSyncAttempts: 1,
305
+ lastSyncAt: Date.now(),
306
+ },
307
+ },
308
+ llmModel: lastModel,
309
+ },
310
+ };
311
+ }
312
+ }
313
+ //# sourceMappingURL=copilot-cli.conversations-processor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copilot-cli.conversations-processor.js","sourceRoot":"","sources":["../../../../../../src/agents/plugins/copilot-cli/session/processors/copilot-cli.conversations-processor.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAO/B,OAAO,EAAE,0BAA0B,EAAE,MAAM,4CAA4C,CAAC;AACxF,OAAO,EAAE,oBAAoB,EAAE,2BAA2B,EAAE,MAAM,oFAAoF,CAAC;AAEvJ,OAAO,EAAE,wBAAwB,EAAE,MAAM,gFAAgF,CAAC;AAC1H,OAAO,EAAE,SAAS,EAAE,MAAM,oEAAoE,CAAC;AAC/F,OAAO,EAAE,MAAM,EAAE,MAAM,gCAAgC,CAAC;AAsDxD,SAAS,YAAY,CAAC,KAAc;IAClC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACrD,OAAO,KAA0B,CAAC;AACpC,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAc;IACtC,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACjC,OAAO,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;AACnD,CAAC;AAED,SAAS,4BAA4B,CAAC,KAAc,EAAE,GAAY;IAChE,MAAM,OAAO,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,KAAK,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,OAAO,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,GAAG,OAAO,EAAE,CAAC;QACpE,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC;AACzE,CAAC;AAED,SAAS,SAAS,CAAC,KAAc;IAC/B,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,EAAE,CAAC;IACrD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,MAA0B,EAAE,YAAoB;IACrE,MAAM,QAAQ,GAAqB,EAAE,CAAC;IACtC,MAAM,mBAAmB,GAAG,IAAI,GAAG,EAA0B,CAAC;IAE9D,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,IAAI,KAAK,sBAAsB,EAAE,CAAC;YAC1C,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE;gBAAE,SAAS;YAClC,QAAQ,CAAC,IAAI,CAAC;gBACZ,EAAE,EAAE,sBAAsB,YAAY,IAAI,KAAK,CAAC,WAAW,EAAE;gBAC7D,SAAS,EAAE,IAAI;gBACf,QAAQ,EAAE;oBACR,SAAS,EAAE,KAAK,CAAC,SAAS;oBAC1B,YAAY,EAAE,KAAK,CAAC,WAAW;oBAC/B,UAAU,EAAE,KAAK,CAAC,IAAI;oBACtB,GAAG,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC;iBAC1B;gBACD,WAAW,EAAE,KAAK;gBAClB,UAAU,EAAE,EAAE;gBACd,OAAO,EAAE,KAAK,CAAC,IAAI;gBACnB,WAAW,EAAE,OAAO;gBACpB,WAAW,EAAE,oBAAoB;gBACjC,aAAa,EAAE,MAAM;gBACrB,KAAK,EAAE,KAAK;gBACZ,WAAW,EAAE,KAAK;gBAClB,OAAO,EAAE,KAAK;gBACd,QAAQ,EAAE,EAAE;aACb,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QAED,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YACjC,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YACjF,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,CAAC,OAAO,GAAG,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC;gBACnC,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,KAAK,IAAI,CAAC;gBACrC,OAAO,CAAC,QAAQ,GAAG;oBACjB,GAAG,OAAO,CAAC,QAAQ;oBACnB,mBAAmB,EAAE,KAAK,CAAC,WAAW;oBACtC,gBAAgB,EAAE,KAAK,CAAC,SAAS;oBACjC,GAAG,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC;iBAC1B,CAAC;gBACF,mBAAmB,CAAC,MAAM,CAAC,KAAK,CAAC,MAAO,CAAC,CAAC;gBAC1C,SAAS;YACX,CAAC;QACH,CAAC;QAED,MAAM,OAAO,GAAmB;YAC9B,EAAE,EAAE,KAAK,CAAC,MAAM,IAAI,gBAAgB,YAAY,IAAI,KAAK,CAAC,WAAW,EAAE;YACvE,SAAS,EAAE,IAAI;YACf,QAAQ,EAAE;gBACR,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,YAAY,EAAE,KAAK,CAAC,WAAW;gBAC/B,UAAU,EAAE,KAAK,CAAC,IAAI;gBACtB,GAAG,CAAC,KAAK,CAAC,MAAM,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;gBAC9C,GAAG,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC;aAC1B;YACD,WAAW,EAAE,KAAK;YAClB,UAAU,EAAE,KAAK,CAAC,SAAS,IAAI,EAAE;YACjC,OAAO,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE;YACzB,WAAW,EAAE,MAAM;YACnB,WAAW,EAAE,KAAK,CAAC,QAAQ,IAAI,cAAc;YAC7C,aAAa,EAAE,MAAM;YACrB,KAAK,EAAE,KAAK,CAAC,KAAK,KAAK,IAAI;YAC3B,WAAW,EAAE,KAAK;YAClB,OAAO,EAAE,KAAK;YACd,QAAQ,EAAE,EAAE;SACb,CAAC;QACF,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACvB,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;YAC/C,mBAAmB,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,SAAS,CAAC,IAA6B;IAC9C,MAAM,OAAO,GAAU,EAAE,CAAC;IAE1B,IAAI,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;QACpB,OAAO,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI;YACvB,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI;YAC3B,aAAa,EAAE,IAAI,CAAC,YAAY;YAChC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS;YACzB,UAAU,EAAE,EAAE;SACf,CAAC,CAAC;IACL,CAAC;IAED,IAAI,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAC/D,OAAO,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,WAAW;YACjB,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI;YAC5B,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI;YAChC,aAAa,EAAE,IAAI,CAAC,YAAY;YAChC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS;YAC9B,aAAa,EAAE,4BAA4B,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC;YAC3F,YAAY,EAAE,oBAAoB;YAClC,QAAQ,EAAE,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;SACrD,CAAC,CAAC;IACL,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,UAAU,CAAC,QAAmB;IACrC,MAAM,KAAK,GAA8B,EAAE,CAAC;IAC5C,IAAI,OAAO,GAAmC,IAAI,CAAC;IACnD,IAAI,YAAY,GAAG,CAAC,CAAC,CAAC;IAEtB,KAAK,MAAM,CAAC,WAAW,EAAE,GAAG,CAAC,IAAI,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;QACpD,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC;QACnC,MAAM,OAAO,GAAG,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAEjD,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACtB,SAAS;QACX,CAAC;QAED,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;YACpB,YAAY,IAAI,CAAC,CAAC;YAClB,OAAO,GAAG;gBACR,YAAY;gBACZ,IAAI,EAAE;oBACJ,IAAI,EAAE,OAAO;oBACb,SAAS,EAAE,MAAM,CAAC,SAAS;iBAC5B;gBACD,MAAM,EAAE,EAAE;aACX,CAAC;YACF,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACpB,SAAS;QACX,CAAC;QAED,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,SAAS;QACX,CAAC;QAED,OAAO,CAAC,SAAS,GAAG;YAClB,IAAI,EAAE,OAAO;YACb,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,KAAK;SAC7B,CAAC;QAEF,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,YAAY,CAAC;YAC9D,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,YAAY;YAC9B,CAAC,CAAC,EAAE,CAAC;QAEP,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE,CAAC;gBACnC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC;oBAClB,IAAI,EAAE,WAAW;oBACjB,WAAW;oBACX,SAAS,EAAE,MAAM,CAAC,SAAS;oBAC3B,MAAM,EAAE,OAAO,CAAC,UAAU;oBAC1B,QAAQ,EAAE,OAAO,CAAC,IAAI;oBACtB,SAAS,EAAE,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC;oBACvC,QAAQ,EAAE;wBACR,cAAc,EAAE,OAAO,CAAC,SAAS;qBAClC;iBACF,CAAC,CAAC;YACL,CAAC;QACH,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC;gBAClB,IAAI,EAAE,sBAAsB;gBAC5B,WAAW;gBACX,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,IAAI,EAAE,OAAO;aACd,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,OAAO,gCAAgC;IAClC,IAAI,GAAG,2BAA2B,CAAC;IACnC,QAAQ,GAAG,CAAC,CAAC;IAEtB,aAAa,CAAC,OAAsB;QAClC,IAAI,OAAO,CAAC,GAAG,CAAC,0BAA0B,KAAK,GAAG;YAAE,OAAO,KAAK,CAAC;QACjE,OAAO,OAAO,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAAsB,EAAE,OAA0B;QAC9D,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,EAAE,IAAI,EAAE,CAAC;QACtD,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,wCAAwC,OAAO,CAAC,SAAS,8BAA8B,CAAC,CAAC;YAClH,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,0CAA0C;gBACnD,QAAQ,EAAE,EAAE,gBAAgB,EAAE,CAAC,EAAE,UAAU,EAAE,yBAAyB,EAAE;aACzE,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC3C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,iCAAiC;gBAC1C,QAAQ,EAAE,EAAE,gBAAgB,EAAE,CAAC,EAAE;aAClC,CAAC;QACJ,CAAC;QAED,MAAM,iBAAiB,GAAG,0BAA0B,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACxE,MAAM,KAAK,CAAC,OAAO,CAAC,iBAAiB,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAE7D,MAAM,gBAAgB,GAAG,MAAM,SAAS,CAA4B,iBAAiB,CAAC,CAAC;QAEvF,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,0CAA0C,CAAC,CAAC;QAClF,MAAM,YAAY,GAAG,IAAI,YAAY,EAAE,CAAC;QACxC,MAAM,eAAe,GAAG,MAAM,YAAY,CAAC,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAE1E,IAAI,gBAAgB,GAAG,eAAe,EAAE,IAAI,EAAE,aAAa,EAAE,sBAAsB,IAAI,CAAC,CAAC,CAAC;QAC1F,KAAK,MAAM,OAAO,IAAI,gBAAgB,EAAE,CAAC;YACvC,IAAI,OAAO,CAAC,OAAO,CAAC,cAAc,KAAK,cAAc;gBAAE,SAAS;YAChE,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;gBACzC,gBAAgB,GAAG,IAAI,CAAC,GAAG,CAAC,gBAAgB,EAAE,GAAG,CAAC,CAAC;YACrD,CAAC;QACH,CAAC;QAED,IAAI,eAAe,GAAG,CAAC,CAAC;QACxB,IAAI,gBAAgB,GAAG,CAAC,CAAC;QACzB,IAAI,YAAgC,CAAC;QACrC,IAAI,SAA6B,CAAC;QAElC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,YAAY,IAAI,gBAAgB,EAAE,CAAC;gBAC1C,SAAS;YACX,CAAC;YAED,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;YAChC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACzB,SAAS;YACX,CAAC;YAED,MAAM,QAAQ,GAAG,GAAG,cAAc,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YAC1D,MAAM,aAAa,GAA8B;gBAC/C,SAAS,EAAE,QAAQ;gBACnB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;gBACrB,kBAAkB,EAAE,KAAK;gBACzB,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC;gBAChE,YAAY,EAAE,OAAO,CAAC,MAAM;gBAC5B,wBAAwB,EAAE,QAAQ;gBAClC,OAAO,EAAE;oBACP,cAAc;oBACd,OAAO;oBACP,WAAW,EAAE,oBAAoB;oBACjC,QAAQ,EAAE,IAAI,CAAC,SAAS,EAAE,KAAK;iBAChC;gBACD,MAAM,EAAE,wBAAwB,CAAC,OAAO;aACzC,CAAC;YAEF,MAAM,UAAU,CAAC,iBAAiB,EAAE,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,GAAG,IAAI,CAAC,CAAC;YAE1E,eAAe,IAAI,CAAC,CAAC;YACrB,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC;YACnC,gBAAgB,GAAG,IAAI,CAAC,YAAY,CAAC;YACrC,YAAY,GAAG,QAAQ,CAAC;YACxB,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE,KAAK,IAAI,SAAS,CAAC;QACjD,CAAC;QAED,IAAI,eAAe,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,8BAA8B;gBACvC,QAAQ,EAAE,EAAE,gBAAgB,EAAE,CAAC,EAAE;aAClC,CAAC;QACJ,CAAC;QAED,MAAM,CAAC,IAAI,CACT,IAAI,2BAA2B,YAAY,eAAe,+BAA+B;YACzF,GAAG,eAAe,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,gBAAgB,OAAO,CAAC,SAAS,EAAE,CACvE,CAAC;QAEF,OAAO;YACL,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,UAAU,eAAe,kCAAkC;YACpE,QAAQ,EAAE;gBACR,gBAAgB;gBAChB,eAAe;gBACf,WAAW,EAAE;oBACX,aAAa,EAAE;wBACb,qBAAqB,EAAE,YAAY;wBACnC,sBAAsB,EAAE,gBAAgB;wBACxC,cAAc;wBACd,mBAAmB,EAAE,gBAAgB;wBACrC,iBAAiB,EAAE,CAAC;wBACpB,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE;qBACvB;iBACF;gBACD,QAAQ,EAAE,SAAS;aACpB;SACF,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Metrics processor for Copilot CLI sessions.
3
+ *
4
+ * Extraction itself happens in `parseSessionFile` (one pass over `events.jsonl`); this
5
+ * processor exists so the adapter follows the same `SessionProcessor` orchestration every
6
+ * other agent uses.
7
+ */
8
+ import type { SessionProcessor, ProcessingContext, ProcessingResult } from '../../../../core/session/BaseProcessor.js';
9
+ import type { ParsedSession } from '../../../../core/session/BaseSessionAdapter.js';
10
+ export declare class CopilotCliMetricsProcessor implements SessionProcessor {
11
+ readonly name = "copilot-cli-metrics";
12
+ readonly priority = 10;
13
+ shouldProcess(session: ParsedSession): boolean;
14
+ process(session: ParsedSession, _context: ProcessingContext): Promise<ProcessingResult>;
15
+ }
16
+ //# sourceMappingURL=copilot-cli.metrics-processor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copilot-cli.metrics-processor.d.ts","sourceRoot":"","sources":["../../../../../../src/agents/plugins/copilot-cli/session/processors/copilot-cli.metrics-processor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EACjB,MAAM,2CAA2C,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gDAAgD,CAAC;AAEpF,qBAAa,0BAA2B,YAAW,gBAAgB;IACjE,QAAQ,CAAC,IAAI,yBAAyB;IACtC,QAAQ,CAAC,QAAQ,MAAM;IAEvB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO;IAIxC,OAAO,CAAC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAO9F"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Metrics processor for Copilot CLI sessions.
3
+ *
4
+ * Extraction itself happens in `parseSessionFile` (one pass over `events.jsonl`); this
5
+ * processor exists so the adapter follows the same `SessionProcessor` orchestration every
6
+ * other agent uses.
7
+ */
8
+ export class CopilotCliMetricsProcessor {
9
+ name = 'copilot-cli-metrics';
10
+ priority = 10;
11
+ shouldProcess(session) {
12
+ return session.metrics !== undefined;
13
+ }
14
+ async process(session, _context) {
15
+ const toolCalls = Object.values(session.metrics?.tools ?? {}).reduce((sum, n) => sum + n, 0);
16
+ return {
17
+ success: true,
18
+ metadata: { recordsProcessed: toolCalls },
19
+ };
20
+ }
21
+ }
22
+ //# sourceMappingURL=copilot-cli.metrics-processor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copilot-cli.metrics-processor.js","sourceRoot":"","sources":["../../../../../../src/agents/plugins/copilot-cli/session/processors/copilot-cli.metrics-processor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH,MAAM,OAAO,0BAA0B;IAC5B,IAAI,GAAG,qBAAqB,CAAC;IAC7B,QAAQ,GAAG,EAAE,CAAC;IAEvB,aAAa,CAAC,OAAsB;QAClC,OAAO,OAAO,CAAC,OAAO,KAAK,SAAS,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAAsB,EAAE,QAA2B;QAC/D,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QAC7F,OAAO;YACL,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,EAAE,gBAAgB,EAAE,SAAS,EAAE;SAC1C,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Point `os.homedir()` at a fixture directory for the duration of a test.
3
+ *
4
+ * `homedir()` reads `$HOME` on POSIX but `%USERPROFILE%` on Windows, so setting only one of
5
+ * them leaves the other platform resolving `~/.pi/agent` against the real user profile. The
6
+ * user-scope fixtures are then invisible and every count comes back zero — indistinguishable
7
+ * from the broken mapping these suites exist to catch.
8
+ *
9
+ * @returns a function that restores both variables to their previous state.
10
+ */
11
+ export declare function redirectHomeDir(dir: string): () => void;
12
+ //# sourceMappingURL=home-redirect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"home-redirect.d.ts","sourceRoot":"","sources":["../../../../../src/agents/plugins/pi/__tests__/home-redirect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,IAAI,CAcvD"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Point `os.homedir()` at a fixture directory for the duration of a test.
3
+ *
4
+ * `homedir()` reads `$HOME` on POSIX but `%USERPROFILE%` on Windows, so setting only one of
5
+ * them leaves the other platform resolving `~/.pi/agent` against the real user profile. The
6
+ * user-scope fixtures are then invisible and every count comes back zero — indistinguishable
7
+ * from the broken mapping these suites exist to catch.
8
+ *
9
+ * @returns a function that restores both variables to their previous state.
10
+ */
11
+ export function redirectHomeDir(dir) {
12
+ const saved = {
13
+ HOME: process.env.HOME,
14
+ USERPROFILE: process.env.USERPROFILE,
15
+ };
16
+ process.env.HOME = dir;
17
+ process.env.USERPROFILE = dir;
18
+ return () => {
19
+ for (const [name, value] of Object.entries(saved)) {
20
+ if (value === undefined)
21
+ delete process.env[name];
22
+ else
23
+ process.env[name] = value;
24
+ }
25
+ };
26
+ }
27
+ //# sourceMappingURL=home-redirect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"home-redirect.js","sourceRoot":"","sources":["../../../../../src/agents/plugins/pi/__tests__/home-redirect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,MAAM,KAAK,GAAuC;QAChD,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI;QACtB,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW;KACrC,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC;IACvB,OAAO,CAAC,GAAG,CAAC,WAAW,GAAG,GAAG,CAAC;IAE9B,OAAO,GAAG,EAAE;QACV,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAClD,IAAI,KAAK,KAAK,SAAS;gBAAE,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;;gBAC7C,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;QACjC,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,68 @@
1
+ # CodeMie run ledger — Pi extension
2
+
3
+ `index.js` is copied verbatim into `<piAgentDir>/extensions/codemie-metrics/` before every
4
+ `codemie pi` run and loaded by Pi's own extension discovery. It records which transcript files the
5
+ run produced so `onSessionEnd` can read a fact instead of inferring one.
6
+
7
+ ## Why this exists
8
+
9
+ Pi names its transcripts itself, writes them lazily, and can produce several per run (`/new`,
10
+ `/fork`, `--session` into another project). Working out afterwards which files belong to the run you
11
+ just launched is guesswork — a concurrent `pi` in the same directory produces files that are
12
+ indistinguishable by id, mtime, or `parentSession` lineage. Eight review rounds of increasingly
13
+ careful heuristics kept yielding the same class of defect, and the failure mode is not lost metrics
14
+ but **uploading a stranger's prompts and tool output under this user's session**.
15
+
16
+ Inside Pi the question is not hard: `ctx.sessionManager.getSessionFile()` is the transcript being
17
+ written. This extension appends that, plus every session transition, to a ledger.
18
+
19
+ ## Layout — why a directory and not a single file
20
+
21
+ Pi's discovery accepts `extensions/*.js` and `extensions/*/index.js` (upstream
22
+ `core/extensions/loader.ts:597-599`, `:610-638`). A bare `.js` file would inherit its module system
23
+ from the nearest `package.json` on the *user's* disk, where a CommonJS context would make
24
+ `export default` a syntax error. Shipping a directory lets `package.json` declare
25
+ `{"type":"module"}` next to the code, so Pi's jiti loader and CodeMie's pre-flight `import()`
26
+ self-test resolve it identically. `.mjs` would sidestep this too but is rejected by
27
+ `isExtensionFile`.
28
+
29
+ ## The hard constraint
30
+
31
+ **Any extension load failure makes Pi call `process.exit(1)`** — bad import, factory throw,
32
+ non-function export — in every mode (upstream `main.ts:893-899`). A mistake here kills the user's
33
+ coding session, which is much worse than collecting nothing. Hence, in `index.js`:
34
+
35
+ - node builtins only; nothing from `@earendil-works/*`, not even `import type`
36
+ - the whole factory body, and every handler body, wrapped in `try/catch`
37
+ - never subscribes to `tool_call` (a throwing `tool_call` handler *blocks the tool*)
38
+ - handlers return `undefined`, so the `input` handler cannot alter what the user typed
39
+ - synchronous appends, each individually guarded
40
+ - only parsed command *names* are recorded — never prompt or argument text
41
+
42
+ `pi.extension.ts` additionally runs a pre-flight `import()` of the materialized copy and deletes it
43
+ if it does not export a function, so a corrupted asset degrades to "no metrics" rather than "no
44
+ session".
45
+
46
+ ## Ledger format
47
+
48
+ `~/.codemie/sessions/<CODEMIE_SESSION_ID>_pi-run.jsonl`, append-only, one JSON object per line. The
49
+ path arrives as `CODEMIE_PI_LEDGER`, so this file holds no assumptions about CodeMie's layout — no
50
+ env var, no subscriptions.
51
+
52
+ | `t` | Fields |
53
+ |---|---|
54
+ | `boot` | `pid` |
55
+ | `session` | `reason`, `file`, `piSessionId`, `cwd`, `prevFile`, `mode` |
56
+ | `cmd` | `kind` (`skill`\|`prompt`), `name` |
57
+ | `shutdown` | `reason`, `file`, `target`, `piSessionId`, `cwd`, `mode` |
58
+
59
+ `cwd` is `sessionManager.getCwd()` — the *transcript's* cwd, which is what `--session <path>` runs
60
+ under, not the directory the wrapper was launched from.
61
+
62
+ `file` may name a path Pi has not written yet: `_persist` only flushes once the session holds an
63
+ assistant message. Consumers must filter on existence.
64
+
65
+ ## Disabling
66
+
67
+ `CODEMIE_PI_EXTENSION_DISABLED=1` — the extension registers nothing, and `ensurePiCodeMieExtension`
68
+ removes the materialized copy.
@@ -0,0 +1,161 @@
1
+ /**
2
+ * CodeMie run ledger — a Pi extension.
3
+ *
4
+ * Pi writes its session transcripts lazily, under names it chooses, and a single
5
+ * run can produce several of them (`/new`, `/fork`, `--session` into another
6
+ * project). A wrapper that tries to work out afterwards which files belong to the
7
+ * run it just launched is guessing: transcripts from a concurrent `pi` in the same
8
+ * directory are indistinguishable by id, mtime or lineage. Guessing wrong does not
9
+ * merely lose metrics — it uploads a stranger's prompts and tool output under this
10
+ * user's session.
11
+ *
12
+ * So we do not guess. This extension runs inside Pi, where the answer is a fact:
13
+ * `ctx.sessionManager.getSessionFile()` is the transcript being written right now.
14
+ * It appends that fact, plus every session transition, to a ledger keyed to the
15
+ * CodeMie session id. `onSessionEnd` reads the ledger instead of scanning a
16
+ * directory.
17
+ *
18
+ * ## Invariants — do not relax any of these without reading the note below
19
+ *
20
+ * Pi turns ANY extension load failure into a `type:"error"` diagnostic and then
21
+ * calls `process.exit(1)` (upstream `main.ts:893-899`) — in every mode. A throw in
22
+ * this file's import or factory therefore kills the user's coding session outright.
23
+ * That is a far worse outcome than collecting no metrics, so:
24
+ *
25
+ * 1. Imports are node builtins only. Nothing from `@earendil-works/*`, not even
26
+ * `import type` — a zero-import file removes the question entirely.
27
+ * 2. The whole factory body is wrapped in try/catch.
28
+ * 3. Every handler body is separately wrapped — a throw in `session_shutdown`
29
+ * would truncate the ledger even though Pi catches it (`runner.ts:815-830`).
30
+ * 4. We never subscribe to `tool_call`: a throwing `tool_call` handler *blocks
31
+ * the tool*, which would change what the user's agent can do.
32
+ * 5. Handlers return `undefined`, never a result object, so the `input` handler
33
+ * cannot transform or swallow what the user typed.
34
+ * 6. Only parsed *names* are recorded. Prompt and argument text never enters the
35
+ * ledger.
36
+ *
37
+ * Writes are synchronous (`appendFileSync`) so a hard exit cannot lose the last
38
+ * line, and every write is individually guarded — a read-only disk degrades this
39
+ * to "no metrics", never to a broken session.
40
+ *
41
+ * The ledger path arrives as `CODEMIE_PI_LEDGER` rather than being derived here,
42
+ * so this file holds no assumptions about CodeMie's directory layout. No env var,
43
+ * no ledger, no subscriptions.
44
+ *
45
+ * @see src/agents/plugins/pi/pi.extension.ts — writes this file out and reads it back
46
+ */
47
+
48
+ import { appendFileSync, mkdirSync } from 'node:fs';
49
+ import { dirname } from 'node:path';
50
+
51
+ const LEDGER_VERSION = 1;
52
+
53
+ /** `/skill:<name>` — Pi's own form, per its interactive skill dispatcher. */
54
+ const SKILL_COMMAND = /^\/skill:([A-Za-z0-9][\w.-]*)/;
55
+
56
+ /** `/<name>` — a prompt template. Anchored and charset-limited so `/usr/local/bin` does not match. */
57
+ const PROMPT_COMMAND = /^\/([A-Za-z][\w.-]*)(?:\s|$)/;
58
+
59
+ /** Call a getter that belongs to Pi, never letting its failure cost us the record. */
60
+ function safe(read) {
61
+ try {
62
+ const value = read();
63
+ return value === undefined ? null : value;
64
+ } catch {
65
+ return null;
66
+ }
67
+ }
68
+
69
+ export default function codemieMetrics(pi) {
70
+ try {
71
+ const ledgerPath = process.env.CODEMIE_PI_LEDGER;
72
+ if (!ledgerPath || process.env.CODEMIE_PI_EXTENSION_DISABLED === '1') {
73
+ return;
74
+ }
75
+
76
+ let ledgerDirReady = false;
77
+ const append = (record) => {
78
+ try {
79
+ if (!ledgerDirReady) {
80
+ mkdirSync(dirname(ledgerPath), { recursive: true });
81
+ ledgerDirReady = true;
82
+ }
83
+ appendFileSync(ledgerPath, `${JSON.stringify({ v: LEDGER_VERSION, ts: Date.now(), ...record })}\n`);
84
+ } catch {
85
+ // A ledger we cannot write is a metrics problem, not a session problem.
86
+ }
87
+ };
88
+
89
+ /**
90
+ * `getCwd()` is the transcript's own cwd, which is what we want: `--session
91
+ * <path>` runs the whole session under the cwd recorded in that file's header,
92
+ * not the directory the wrapper was launched from.
93
+ */
94
+ const sessionFacts = (ctx) => ({
95
+ file: safe(() => ctx.sessionManager.getSessionFile()),
96
+ piSessionId: safe(() => ctx.sessionManager.getSessionId()),
97
+ cwd: safe(() => ctx.sessionManager.getCwd()),
98
+ mode: safe(() => ctx.mode),
99
+ });
100
+
101
+ append({ t: 'boot', pid: process.pid });
102
+
103
+ pi.on('session_start', (event, ctx) => {
104
+ try {
105
+ append({
106
+ t: 'session',
107
+ reason: safe(() => event.reason),
108
+ prevFile: safe(() => event.previousSessionFile),
109
+ ...sessionFacts(ctx),
110
+ });
111
+ } catch {
112
+ // never propagate
113
+ }
114
+ return undefined;
115
+ });
116
+
117
+ pi.on('session_shutdown', (event, ctx) => {
118
+ try {
119
+ append({
120
+ t: 'shutdown',
121
+ reason: safe(() => event.reason),
122
+ target: safe(() => event.targetSessionFile),
123
+ ...sessionFacts(ctx),
124
+ });
125
+ } catch {
126
+ // never propagate
127
+ }
128
+ return undefined;
129
+ });
130
+
131
+ /**
132
+ * Slash commands are the one signal the transcript cannot carry: Pi expands a
133
+ * prompt template into plain user text before persisting it, so `/review` is
134
+ * gone by the time the entry is written. `input` fires with the raw text.
135
+ *
136
+ * Only the command name is recorded — never its arguments.
137
+ */
138
+ pi.on('input', (event) => {
139
+ try {
140
+ const text = safe(() => event.text);
141
+ if (typeof text !== 'string' || text.charCodeAt(0) !== 47 /* '/' */) {
142
+ return undefined;
143
+ }
144
+ const skill = SKILL_COMMAND.exec(text);
145
+ if (skill) {
146
+ append({ t: 'cmd', kind: 'skill', name: skill[1] });
147
+ return undefined;
148
+ }
149
+ const prompt = PROMPT_COMMAND.exec(text);
150
+ if (prompt) {
151
+ append({ t: 'cmd', kind: 'prompt', name: prompt[1] });
152
+ }
153
+ } catch {
154
+ // never propagate
155
+ }
156
+ return undefined;
157
+ });
158
+ } catch {
159
+ // A throw here would make Pi exit(1) and take the user's session with it.
160
+ }
161
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "codemie-pi-run-ledger",
3
+ "version": "1.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "description": "Records which transcripts a codemie-pi run produced, from inside Pi."
8
+ }