@codemieai/code 0.0.32 → 0.0.34

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 (203) hide show
  1. package/README.md +73 -7
  2. package/bin/codemie-opencode.js +11 -0
  3. package/dist/agents/codemie-code/agent.d.ts +17 -1
  4. package/dist/agents/codemie-code/agent.d.ts.map +1 -1
  5. package/dist/agents/codemie-code/agent.js +62 -3
  6. package/dist/agents/codemie-code/agent.js.map +1 -1
  7. package/dist/agents/codemie-code/index.d.ts +1 -0
  8. package/dist/agents/codemie-code/index.d.ts.map +1 -1
  9. package/dist/agents/codemie-code/index.js +28 -2
  10. package/dist/agents/codemie-code/index.js.map +1 -1
  11. package/dist/agents/codemie-code/prompts.d.ts +12 -3
  12. package/dist/agents/codemie-code/prompts.d.ts.map +1 -1
  13. package/dist/agents/codemie-code/prompts.js +25 -5
  14. package/dist/agents/codemie-code/prompts.js.map +1 -1
  15. package/dist/agents/codemie-code/types.d.ts +3 -0
  16. package/dist/agents/codemie-code/types.d.ts.map +1 -1
  17. package/dist/agents/codemie-code/types.js.map +1 -1
  18. package/dist/agents/codemie-code/ui/todoPanel.d.ts.map +1 -1
  19. package/dist/agents/codemie-code/ui/todoPanel.js +4 -0
  20. package/dist/agents/codemie-code/ui/todoPanel.js.map +1 -1
  21. package/dist/agents/core/AgentCLI.d.ts.map +1 -1
  22. package/dist/agents/core/AgentCLI.js +3 -1
  23. package/dist/agents/core/AgentCLI.js.map +1 -1
  24. package/dist/agents/core/BaseAgentAdapter.d.ts.map +1 -1
  25. package/dist/agents/core/BaseAgentAdapter.js +46 -2
  26. package/dist/agents/core/BaseAgentAdapter.js.map +1 -1
  27. package/dist/agents/core/session/BaseSessionAdapter.d.ts +25 -0
  28. package/dist/agents/core/session/BaseSessionAdapter.d.ts.map +1 -1
  29. package/dist/agents/core/session/SessionStore.d.ts +15 -0
  30. package/dist/agents/core/session/SessionStore.d.ts.map +1 -1
  31. package/dist/agents/core/session/SessionStore.js +46 -0
  32. package/dist/agents/core/session/SessionStore.js.map +1 -1
  33. package/dist/agents/core/session/discovery-types.d.ts +53 -0
  34. package/dist/agents/core/session/discovery-types.d.ts.map +1 -0
  35. package/dist/agents/core/session/discovery-types.js +8 -0
  36. package/dist/agents/core/session/discovery-types.js.map +1 -0
  37. package/dist/agents/core/session/types.d.ts +2 -0
  38. package/dist/agents/core/session/types.d.ts.map +1 -1
  39. package/dist/agents/core/types.d.ts +45 -0
  40. package/dist/agents/core/types.d.ts.map +1 -1
  41. package/dist/agents/plugins/claude/claude.plugin.d.ts +44 -1
  42. package/dist/agents/plugins/claude/claude.plugin.d.ts.map +1 -1
  43. package/dist/agents/plugins/claude/claude.plugin.js +214 -0
  44. package/dist/agents/plugins/claude/claude.plugin.js.map +1 -1
  45. package/dist/agents/plugins/claude/plugin/.claude-plugin/plugin.json +1 -1
  46. package/dist/agents/plugins/claude/plugin/README.md +40 -2
  47. package/dist/agents/plugins/claude/plugin/claude-templates/README.md +5 -5
  48. package/dist/agents/plugins/claude/plugin/claude-templates/templates/CLAUDE.md.template +177 -436
  49. package/dist/agents/plugins/claude/plugin/claude-templates/templates/agents/code-review-agent-template.md.template +49 -82
  50. package/dist/agents/plugins/claude/plugin/claude-templates/templates/agents/refactor-cleaner-agent.md.template +337 -0
  51. package/dist/agents/plugins/claude/plugin/claude-templates/templates/agents/solution-architect-agent.md.template +129 -419
  52. package/dist/agents/plugins/claude/plugin/claude-templates/templates/agents/unit-tester-agent.md.template +146 -693
  53. package/dist/agents/plugins/claude/plugin/claude-templates/templates/guides/api/api-patterns.md.template +110 -138
  54. package/dist/agents/plugins/claude/plugin/claude-templates/templates/guides/architecture/architecture.md.template +197 -0
  55. package/dist/agents/plugins/claude/plugin/claude-templates/templates/guides/data/database-patterns.md.template +171 -91
  56. package/dist/agents/plugins/claude/plugin/claude-templates/templates/guides/development/development-practices.md.template +219 -131
  57. package/dist/agents/plugins/claude/plugin/claude-templates/templates/guides/security/security-practices.md.template +223 -98
  58. package/dist/agents/plugins/claude/plugin/claude-templates/templates/guides/standards/code-quality.md.template +131 -95
  59. package/dist/agents/plugins/claude/plugin/claude-templates/templates/guides/testing/testing-patterns.md.template +247 -75
  60. package/dist/agents/plugins/claude/plugin/commands/README.md +133 -0
  61. package/dist/agents/plugins/claude/plugin/commands/codemie-init.md +336 -544
  62. package/dist/agents/plugins/claude/plugin/commands/codemie-subagents.md +232 -503
  63. package/dist/agents/plugins/claude/plugin/commands/memory-add.md +311 -30
  64. package/dist/agents/plugins/claude/plugin/commands/memory-refresh.md +218 -39
  65. package/dist/agents/plugins/claude/plugin/hooks/hooks.json +11 -0
  66. package/dist/agents/plugins/gemini/extension/gemini-extension.json +1 -1
  67. package/dist/agents/plugins/gemini/extension/hooks/hooks.json +12 -0
  68. package/dist/agents/plugins/gemini/gemini.plugin.d.ts.map +1 -1
  69. package/dist/agents/plugins/gemini/gemini.plugin.js +2 -4
  70. package/dist/agents/plugins/gemini/gemini.plugin.js.map +1 -1
  71. package/dist/agents/plugins/opencode/index.d.ts +8 -0
  72. package/dist/agents/plugins/opencode/index.d.ts.map +1 -0
  73. package/dist/agents/plugins/opencode/index.js +12 -0
  74. package/dist/agents/plugins/opencode/index.js.map +1 -0
  75. package/dist/agents/plugins/opencode/opencode-message-types.d.ts +207 -0
  76. package/dist/agents/plugins/opencode/opencode-message-types.d.ts.map +1 -0
  77. package/dist/agents/plugins/opencode/opencode-message-types.js +59 -0
  78. package/dist/agents/plugins/opencode/opencode-message-types.js.map +1 -0
  79. package/dist/agents/plugins/opencode/opencode-model-configs.d.ts +65 -0
  80. package/dist/agents/plugins/opencode/opencode-model-configs.d.ts.map +1 -0
  81. package/dist/agents/plugins/opencode/opencode-model-configs.js +184 -0
  82. package/dist/agents/plugins/opencode/opencode-model-configs.js.map +1 -0
  83. package/dist/agents/plugins/opencode/opencode.paths.d.ts +62 -0
  84. package/dist/agents/plugins/opencode/opencode.paths.d.ts.map +1 -0
  85. package/dist/agents/plugins/opencode/opencode.paths.js +148 -0
  86. package/dist/agents/plugins/opencode/opencode.paths.js.map +1 -0
  87. package/dist/agents/plugins/opencode/opencode.plugin.d.ts +35 -0
  88. package/dist/agents/plugins/opencode/opencode.plugin.d.ts.map +1 -0
  89. package/dist/agents/plugins/opencode/opencode.plugin.js +338 -0
  90. package/dist/agents/plugins/opencode/opencode.plugin.js.map +1 -0
  91. package/dist/agents/plugins/opencode/opencode.session.d.ts +77 -0
  92. package/dist/agents/plugins/opencode/opencode.session.d.ts.map +1 -0
  93. package/dist/agents/plugins/opencode/opencode.session.js +424 -0
  94. package/dist/agents/plugins/opencode/opencode.session.js.map +1 -0
  95. package/dist/agents/plugins/opencode/opencode.storage-utils.d.ts +25 -0
  96. package/dist/agents/plugins/opencode/opencode.storage-utils.d.ts.map +1 -0
  97. package/dist/agents/plugins/opencode/opencode.storage-utils.js +96 -0
  98. package/dist/agents/plugins/opencode/opencode.storage-utils.js.map +1 -0
  99. package/dist/agents/plugins/opencode/session/processors/opencode.conversations-processor.d.ts +30 -0
  100. package/dist/agents/plugins/opencode/session/processors/opencode.conversations-processor.d.ts.map +1 -0
  101. package/dist/agents/plugins/opencode/session/processors/opencode.conversations-processor.js +116 -0
  102. package/dist/agents/plugins/opencode/session/processors/opencode.conversations-processor.js.map +1 -0
  103. package/dist/agents/plugins/opencode/session/processors/opencode.metrics-processor.d.ts +102 -0
  104. package/dist/agents/plugins/opencode/session/processors/opencode.metrics-processor.d.ts.map +1 -0
  105. package/dist/agents/plugins/opencode/session/processors/opencode.metrics-processor.js +584 -0
  106. package/dist/agents/plugins/opencode/session/processors/opencode.metrics-processor.js.map +1 -0
  107. package/dist/agents/registry.d.ts.map +1 -1
  108. package/dist/agents/registry.js +2 -0
  109. package/dist/agents/registry.js.map +1 -1
  110. package/dist/cli/commands/doctor/checks/AgentsCheck.d.ts +5 -0
  111. package/dist/cli/commands/doctor/checks/AgentsCheck.d.ts.map +1 -1
  112. package/dist/cli/commands/doctor/checks/AgentsCheck.js +29 -0
  113. package/dist/cli/commands/doctor/checks/AgentsCheck.js.map +1 -1
  114. package/dist/cli/commands/hook.d.ts.map +1 -1
  115. package/dist/cli/commands/hook.js +63 -6
  116. package/dist/cli/commands/hook.js.map +1 -1
  117. package/dist/cli/commands/install.d.ts.map +1 -1
  118. package/dist/cli/commands/install.js +86 -7
  119. package/dist/cli/commands/install.js.map +1 -1
  120. package/dist/cli/commands/opencode-metrics.d.ts +13 -0
  121. package/dist/cli/commands/opencode-metrics.d.ts.map +1 -0
  122. package/dist/cli/commands/opencode-metrics.js +200 -0
  123. package/dist/cli/commands/opencode-metrics.js.map +1 -0
  124. package/dist/cli/commands/setup.d.ts.map +1 -1
  125. package/dist/cli/commands/setup.js +113 -0
  126. package/dist/cli/commands/setup.js.map +1 -1
  127. package/dist/cli/commands/skill.d.ts +6 -0
  128. package/dist/cli/commands/skill.d.ts.map +1 -0
  129. package/dist/cli/commands/skill.js +196 -0
  130. package/dist/cli/commands/skill.js.map +1 -0
  131. package/dist/cli/commands/update.d.ts.map +1 -1
  132. package/dist/cli/commands/update.js +34 -6
  133. package/dist/cli/commands/update.js.map +1 -1
  134. package/dist/cli/index.js +4 -0
  135. package/dist/cli/index.js.map +1 -1
  136. package/dist/migrations/003-remove-hooks-node.migration.d.ts +22 -0
  137. package/dist/migrations/003-remove-hooks-node.migration.d.ts.map +1 -0
  138. package/dist/migrations/003-remove-hooks-node.migration.js +103 -0
  139. package/dist/migrations/003-remove-hooks-node.migration.js.map +1 -0
  140. package/dist/migrations/index.d.ts +1 -0
  141. package/dist/migrations/index.d.ts.map +1 -1
  142. package/dist/migrations/index.js +1 -1
  143. package/dist/migrations/index.js.map +1 -1
  144. package/dist/providers/plugins/sso/session/processors/metrics/metrics-api-client.d.ts +3 -2
  145. package/dist/providers/plugins/sso/session/processors/metrics/metrics-api-client.d.ts.map +1 -1
  146. package/dist/providers/plugins/sso/session/processors/metrics/metrics-api-client.js +6 -2
  147. package/dist/providers/plugins/sso/session/processors/metrics/metrics-api-client.js.map +1 -1
  148. package/dist/providers/plugins/sso/sso.http-client.js +2 -2
  149. package/dist/providers/plugins/sso/sso.http-client.js.map +1 -1
  150. package/dist/providers/plugins/sso/sso.setup-steps.d.ts.map +1 -1
  151. package/dist/providers/plugins/sso/sso.setup-steps.js +14 -10
  152. package/dist/providers/plugins/sso/sso.setup-steps.js.map +1 -1
  153. package/dist/skills/core/SkillDiscovery.d.ts +83 -0
  154. package/dist/skills/core/SkillDiscovery.d.ts.map +1 -0
  155. package/dist/skills/core/SkillDiscovery.js +237 -0
  156. package/dist/skills/core/SkillDiscovery.js.map +1 -0
  157. package/dist/skills/core/SkillManager.d.ts +86 -0
  158. package/dist/skills/core/SkillManager.d.ts.map +1 -0
  159. package/dist/skills/core/SkillManager.js +155 -0
  160. package/dist/skills/core/SkillManager.js.map +1 -0
  161. package/dist/skills/core/types.d.ts +120 -0
  162. package/dist/skills/core/types.d.ts.map +1 -0
  163. package/dist/skills/core/types.js +20 -0
  164. package/dist/skills/core/types.js.map +1 -0
  165. package/dist/skills/index.d.ts +12 -0
  166. package/dist/skills/index.d.ts.map +1 -0
  167. package/dist/skills/index.js +12 -0
  168. package/dist/skills/index.js.map +1 -0
  169. package/dist/skills/utils/content-loader.d.ts +25 -0
  170. package/dist/skills/utils/content-loader.d.ts.map +1 -0
  171. package/dist/skills/utils/content-loader.js +161 -0
  172. package/dist/skills/utils/content-loader.js.map +1 -0
  173. package/dist/skills/utils/frontmatter.d.ts +60 -0
  174. package/dist/skills/utils/frontmatter.d.ts.map +1 -0
  175. package/dist/skills/utils/frontmatter.js +114 -0
  176. package/dist/skills/utils/frontmatter.js.map +1 -0
  177. package/dist/skills/utils/pattern-matcher.d.ts +60 -0
  178. package/dist/skills/utils/pattern-matcher.d.ts.map +1 -0
  179. package/dist/skills/utils/pattern-matcher.js +97 -0
  180. package/dist/skills/utils/pattern-matcher.js.map +1 -0
  181. package/dist/utils/exec.d.ts.map +1 -1
  182. package/dist/utils/exec.js +11 -1
  183. package/dist/utils/exec.js.map +1 -1
  184. package/dist/utils/installation-detector.d.ts +22 -0
  185. package/dist/utils/installation-detector.d.ts.map +1 -0
  186. package/dist/utils/installation-detector.js +49 -0
  187. package/dist/utils/installation-detector.js.map +1 -0
  188. package/dist/utils/native-installer.d.ts +49 -0
  189. package/dist/utils/native-installer.d.ts.map +1 -0
  190. package/dist/utils/native-installer.js +194 -0
  191. package/dist/utils/native-installer.js.map +1 -0
  192. package/dist/utils/version-utils.d.ts +50 -0
  193. package/dist/utils/version-utils.d.ts.map +1 -0
  194. package/dist/utils/version-utils.js +92 -0
  195. package/dist/utils/version-utils.js.map +1 -0
  196. package/package.json +5 -2
  197. package/scripts/copy-mr-skill-to-global.ts +252 -0
  198. package/scripts/demo-hooks.sh +125 -0
  199. package/scripts/test-hooks.sh +196 -0
  200. package/dist/agents/plugins/claude/plugin/claude-templates/templates/INDEX.md +0 -205
  201. package/dist/agents/plugins/claude/plugin/claude-templates/templates/TEMPLATE_SIZES.md +0 -74
  202. package/dist/agents/plugins/claude/plugin/claude-templates/templates/guides/architecture/layered-architecture.md.template +0 -143
  203. package/dist/agents/plugins/claude/plugin/claude-templates/templates/guides/architecture/project-structure.md.template +0 -127
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Storage layout detection result
3
+ * Per tech spec ADR-2
4
+ */
5
+ export interface StorageLayoutResult {
6
+ layout: 'post-migration' | 'legacy' | 'mixed' | 'unknown';
7
+ migrationVersion: number;
8
+ postMigrationPath?: string;
9
+ legacyPaths?: string[];
10
+ }
11
+ /**
12
+ * Detect OpenCode storage layout (post-migration vs legacy)
13
+ *
14
+ * Per tech spec ADR-2:
15
+ * - Post-migration: storage/session/, storage/message/, storage/part/
16
+ * - Legacy: project/{projectDir}/storage/session/info/
17
+ * - Migration file: plain text numeric version (not JSON)
18
+ */
19
+ export declare function detectStorageLayout(storagePath: string): Promise<StorageLayoutResult>;
20
+ /**
21
+ * Get OpenCode storage root path based on platform
22
+ *
23
+ * OpenCode uses XDG conventions for data storage:
24
+ * - Linux/WSL: ~/.local/share/opencode/storage/
25
+ * - macOS: ~/Library/Application Support/opencode/storage/
26
+ * - Windows: %LOCALAPPDATA%/opencode/storage/
27
+ *
28
+ * @returns Path to storage root directory or null if not found
29
+ */
30
+ export declare function getOpenCodeStoragePath(): string | null;
31
+ /**
32
+ * Get OpenCode sessions directory path
33
+ * Sessions are stored at: storage/session/{projectID}/{sessionID}.json
34
+ *
35
+ * @returns Path to sessions directory or null if storage not found
36
+ */
37
+ export declare function getOpenCodeSessionsPath(): string | null;
38
+ /**
39
+ * Get OpenCode messages directory path
40
+ * Messages are stored at: storage/message/{sessionID}/{messageID}.json
41
+ *
42
+ * @returns Path to messages directory or null if storage not found
43
+ */
44
+ export declare function getOpenCodeMessagesPath(): string | null;
45
+ /**
46
+ * Get OpenCode parts directory path
47
+ * Parts are stored at: storage/part/{messageID}/{partID}.json
48
+ *
49
+ * @returns Path to parts directory or null if storage not found
50
+ */
51
+ export declare function getOpenCodePartsPath(): string | null;
52
+ /**
53
+ * Get OpenCode home directory (~/.opencode)
54
+ */
55
+ export declare function getOpenCodeHome(): string;
56
+ /**
57
+ * Get OpenCode config directory
58
+ */
59
+ export declare function getOpenCodeConfigDir(): string;
60
+ /** @deprecated Use getOpenCodeStoragePath() instead */
61
+ export declare const getSessionStoragePath: typeof getOpenCodeStoragePath;
62
+ //# sourceMappingURL=opencode.paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode.paths.d.ts","sourceRoot":"","sources":["../../../../src/agents/plugins/opencode/opencode.paths.ts"],"names":[],"mappings":"AAOA;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,gBAAgB,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;IAC1D,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAyC3F;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,GAAG,IAAI,CA8BtD;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,GAAG,IAAI,CAKvD;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,GAAG,IAAI,CAKvD;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,GAAG,IAAI,CAKpD;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAK7C;AAGD,uDAAuD;AACvD,eAAO,MAAM,qBAAqB,+BAAyB,CAAC"}
@@ -0,0 +1,148 @@
1
+ // src/agents/plugins/opencode/opencode.paths.ts
2
+ // FIXED: Use named imports per repo conventions
3
+ import { homedir } from 'os';
4
+ import { join, dirname } from 'path';
5
+ import { existsSync } from 'fs';
6
+ import { readFile } from 'fs/promises';
7
+ /**
8
+ * Detect OpenCode storage layout (post-migration vs legacy)
9
+ *
10
+ * Per tech spec ADR-2:
11
+ * - Post-migration: storage/session/, storage/message/, storage/part/
12
+ * - Legacy: project/{projectDir}/storage/session/info/
13
+ * - Migration file: plain text numeric version (not JSON)
14
+ */
15
+ export async function detectStorageLayout(storagePath) {
16
+ let migrationVersion = 0;
17
+ // Check migration file (numeric string, not just presence)
18
+ const migrationFile = join(storagePath, 'migration');
19
+ if (existsSync(migrationFile)) {
20
+ try {
21
+ const content = await readFile(migrationFile, 'utf-8');
22
+ migrationVersion = parseInt(content.trim(), 10) || 0;
23
+ }
24
+ catch {
25
+ migrationVersion = 0;
26
+ }
27
+ }
28
+ // Post-migration structure check
29
+ const hasPostMigration = (existsSync(join(storagePath, 'session')) &&
30
+ existsSync(join(storagePath, 'message')) &&
31
+ existsSync(join(storagePath, 'part')));
32
+ // Legacy structure check (project directories above storage/)
33
+ const dataDir = dirname(storagePath); // Goes up to ~/.local/share/opencode/
34
+ const projectDir = join(dataDir, 'project');
35
+ const hasLegacy = existsSync(projectDir);
36
+ // Determine layout
37
+ if (migrationVersion >= 1 && hasPostMigration) {
38
+ return { layout: 'post-migration', migrationVersion, postMigrationPath: storagePath };
39
+ }
40
+ if (hasPostMigration && hasLegacy) {
41
+ return { layout: 'mixed', migrationVersion, postMigrationPath: storagePath, legacyPaths: [projectDir] };
42
+ }
43
+ if (hasPostMigration) {
44
+ return { layout: 'post-migration', migrationVersion, postMigrationPath: storagePath };
45
+ }
46
+ if (hasLegacy) {
47
+ return { layout: 'legacy', migrationVersion, legacyPaths: [projectDir] };
48
+ }
49
+ return { layout: 'unknown', migrationVersion };
50
+ }
51
+ /**
52
+ * Get OpenCode storage root path based on platform
53
+ *
54
+ * OpenCode uses XDG conventions for data storage:
55
+ * - Linux/WSL: ~/.local/share/opencode/storage/
56
+ * - macOS: ~/Library/Application Support/opencode/storage/
57
+ * - Windows: %LOCALAPPDATA%/opencode/storage/
58
+ *
59
+ * @returns Path to storage root directory or null if not found
60
+ */
61
+ export function getOpenCodeStoragePath() {
62
+ const home = homedir();
63
+ let storagePath;
64
+ // XDG_DATA_HOME always takes precedence (any platform)
65
+ if (process.env.XDG_DATA_HOME) {
66
+ storagePath = join(process.env.XDG_DATA_HOME, 'opencode', 'storage');
67
+ }
68
+ else {
69
+ // Platform-specific defaults
70
+ switch (process.platform) {
71
+ case 'darwin': // macOS
72
+ storagePath = join(home, 'Library', 'Application Support', 'opencode', 'storage');
73
+ break;
74
+ case 'win32': { // Native Windows (WSL reports 'linux')
75
+ const appData = process.env.LOCALAPPDATA;
76
+ storagePath = appData
77
+ ? join(appData, 'opencode', 'storage')
78
+ : join(home, '.local', 'share', 'opencode', 'storage');
79
+ break;
80
+ }
81
+ default: // Linux, WSL, other Unix
82
+ storagePath = join(home, '.local', 'share', 'opencode', 'storage');
83
+ }
84
+ }
85
+ // Return null if path doesn't exist (don't create directories)
86
+ if (!existsSync(storagePath)) {
87
+ return null;
88
+ }
89
+ return storagePath;
90
+ }
91
+ /**
92
+ * Get OpenCode sessions directory path
93
+ * Sessions are stored at: storage/session/{projectID}/{sessionID}.json
94
+ *
95
+ * @returns Path to sessions directory or null if storage not found
96
+ */
97
+ export function getOpenCodeSessionsPath() {
98
+ const storagePath = getOpenCodeStoragePath();
99
+ if (!storagePath)
100
+ return null;
101
+ const sessionsPath = join(storagePath, 'session');
102
+ return existsSync(sessionsPath) ? sessionsPath : null;
103
+ }
104
+ /**
105
+ * Get OpenCode messages directory path
106
+ * Messages are stored at: storage/message/{sessionID}/{messageID}.json
107
+ *
108
+ * @returns Path to messages directory or null if storage not found
109
+ */
110
+ export function getOpenCodeMessagesPath() {
111
+ const storagePath = getOpenCodeStoragePath();
112
+ if (!storagePath)
113
+ return null;
114
+ const messagesPath = join(storagePath, 'message');
115
+ return existsSync(messagesPath) ? messagesPath : null;
116
+ }
117
+ /**
118
+ * Get OpenCode parts directory path
119
+ * Parts are stored at: storage/part/{messageID}/{partID}.json
120
+ *
121
+ * @returns Path to parts directory or null if storage not found
122
+ */
123
+ export function getOpenCodePartsPath() {
124
+ const storagePath = getOpenCodeStoragePath();
125
+ if (!storagePath)
126
+ return null;
127
+ const partsPath = join(storagePath, 'part');
128
+ return existsSync(partsPath) ? partsPath : null;
129
+ }
130
+ /**
131
+ * Get OpenCode home directory (~/.opencode)
132
+ */
133
+ export function getOpenCodeHome() {
134
+ return join(homedir(), '.opencode');
135
+ }
136
+ /**
137
+ * Get OpenCode config directory
138
+ */
139
+ export function getOpenCodeConfigDir() {
140
+ if (process.env.XDG_CONFIG_HOME) {
141
+ return join(process.env.XDG_CONFIG_HOME, 'opencode');
142
+ }
143
+ return join(homedir(), '.config', 'opencode');
144
+ }
145
+ // Legacy alias for backward compatibility
146
+ /** @deprecated Use getOpenCodeStoragePath() instead */
147
+ export const getSessionStoragePath = getOpenCodeStoragePath;
148
+ //# sourceMappingURL=opencode.paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode.paths.js","sourceRoot":"","sources":["../../../../src/agents/plugins/opencode/opencode.paths.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,gDAAgD;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAavC;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,WAAmB;IAC3D,IAAI,gBAAgB,GAAG,CAAC,CAAC;IAEzB,2DAA2D;IAC3D,MAAM,aAAa,GAAG,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IACrD,IAAI,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QAC9B,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;YACvD,gBAAgB,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;QACvD,CAAC;QAAC,MAAM,CAAC;YACP,gBAAgB,GAAG,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED,iCAAiC;IACjC,MAAM,gBAAgB,GAAG,CACvB,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;QACxC,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;QACxC,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CACtC,CAAC;IAEF,8DAA8D;IAC9D,MAAM,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAE,sCAAsC;IAC7E,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAC5C,MAAM,SAAS,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IAEzC,mBAAmB;IACnB,IAAI,gBAAgB,IAAI,CAAC,IAAI,gBAAgB,EAAE,CAAC;QAC9C,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,WAAW,EAAE,CAAC;IACxF,CAAC;IACD,IAAI,gBAAgB,IAAI,SAAS,EAAE,CAAC;QAClC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;IAC1G,CAAC;IACD,IAAI,gBAAgB,EAAE,CAAC;QACrB,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,WAAW,EAAE,CAAC;IACxF,CAAC;IACD,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;IAC3E,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,CAAC;AACjD,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,sBAAsB;IACpC,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,IAAI,WAAmB,CAAC;IAExB,uDAAuD;IACvD,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;QAC9B,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;IACvE,CAAC;SAAM,CAAC;QACN,6BAA6B;QAC7B,QAAQ,OAAO,CAAC,QAAQ,EAAE,CAAC;YACzB,KAAK,QAAQ,EAAG,QAAQ;gBACtB,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,qBAAqB,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;gBAClF,MAAM;YACR,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,uCAAuC;gBACrD,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;gBACzC,WAAW,GAAG,OAAO;oBACnB,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,SAAS,CAAC;oBACtC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;gBACzD,MAAM;YACR,CAAC;YACD,SAAgB,yBAAyB;gBACvC,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;IAED,+DAA+D;IAC/D,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB;IACrC,MAAM,WAAW,GAAG,sBAAsB,EAAE,CAAC;IAC7C,IAAI,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IAC9B,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAClD,OAAO,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;AACxD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB;IACrC,MAAM,WAAW,GAAG,sBAAsB,EAAE,CAAC;IAC7C,IAAI,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IAC9B,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAClD,OAAO,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;AACxD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB;IAClC,MAAM,WAAW,GAAG,sBAAsB,EAAE,CAAC;IAC7C,IAAI,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAC5C,OAAO,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;AAClD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,WAAW,CAAC,CAAC;AACtC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB;IAClC,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,CAAC;QAChC,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;AAChD,CAAC;AAED,0CAA0C;AAC1C,uDAAuD;AACvD,MAAM,CAAC,MAAM,qBAAqB,GAAG,sBAAsB,CAAC"}
@@ -0,0 +1,35 @@
1
+ import type { AgentMetadata } from '../../core/types.js';
2
+ import { BaseAgentAdapter } from '../../core/BaseAgentAdapter.js';
3
+ import type { SessionAdapter } from '../../core/session/BaseSessionAdapter.js';
4
+ import type { BaseExtensionInstaller } from '../../core/extension/BaseExtensionInstaller.js';
5
+ export declare const OpenCodePluginMetadata: AgentMetadata;
6
+ /**
7
+ * OpenCode agent plugin
8
+ * Phase 1: Core plugin with CLI wrapping and SSO proxy support
9
+ * Phase 2: Session analytics integration
10
+ */
11
+ export declare class OpenCodePlugin extends BaseAgentAdapter {
12
+ private sessionAdapter;
13
+ constructor();
14
+ /**
15
+ * Check if OpenCode is installed
16
+ * Overridden to provide custom install instructions (AC-1.2)
17
+ *
18
+ * NOTE (GPT-5.5 review): This method should be SIDE-EFFECT FREE.
19
+ * Install instructions are displayed via logger (file-only in non-debug mode)
20
+ * so they appear in logs but don't pollute stdout during programmatic checks
21
+ * like `codemie doctor`. The CLI layer (AgentCLI) handles user-facing output.
22
+ */
23
+ isInstalled(): Promise<boolean>;
24
+ /**
25
+ * Return session adapter for analytics
26
+ * Phase 2: Returns OpenCodeSessionAdapter instance
27
+ */
28
+ getSessionAdapter(): SessionAdapter;
29
+ /**
30
+ * No extension installer - OpenCode installed manually
31
+ * Returns undefined (interface allows optional return)
32
+ */
33
+ getExtensionInstaller(): BaseExtensionInstaller | undefined;
34
+ }
35
+ //# sourceMappingURL=opencode.plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode.plugin.d.ts","sourceRoot":"","sources":["../../../../src/agents/plugins/opencode/opencode.plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAe,MAAM,qBAAqB,CAAC;AAMtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0CAA0C,CAAC;AAC/E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gDAAgD,CAAC;AAkH7F,eAAO,MAAM,sBAAsB,EAAE,aA6MpC,CAAC;AAEF;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,gBAAgB;IAClD,OAAO,CAAC,cAAc,CAAiB;;IAQvC;;;;;;;;OAQG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAkBrC;;;OAGG;IACH,iBAAiB,IAAI,cAAc;IAInC;;;OAGG;IACH,qBAAqB,IAAI,sBAAsB,GAAG,SAAS;CAG5D"}
@@ -0,0 +1,338 @@
1
+ import { tmpdir } from 'os';
2
+ import { join } from 'path';
3
+ import { writeFileSync, unlinkSync } from 'fs';
4
+ import { logger } from '../../../utils/logger.js';
5
+ import { getModelConfig } from './opencode-model-configs.js';
6
+ import { BaseAgentAdapter } from '../../core/BaseAgentAdapter.js';
7
+ import { commandExists } from '../../../utils/processes.js';
8
+ import { OpenCodeSessionAdapter } from './opencode.session.js';
9
+ const OPENCODE_SUBCOMMANDS = ['run', 'chat', 'config', 'init', 'help', 'version'];
10
+ // Environment variable size limit (conservative - varies by platform)
11
+ // Linux: ~128KB per var, Windows: ~32KB total env block
12
+ const MAX_ENV_SIZE = 32 * 1024;
13
+ // Track temp config files for cleanup on process exit
14
+ const tempConfigFiles = [];
15
+ let cleanupRegistered = false;
16
+ /**
17
+ * Register process exit handler for temp file cleanup (best effort)
18
+ * Only registers once, even if beforeRun is called multiple times
19
+ */
20
+ function registerCleanupHandler() {
21
+ if (cleanupRegistered)
22
+ return;
23
+ cleanupRegistered = true;
24
+ process.on('exit', () => {
25
+ for (const file of tempConfigFiles) {
26
+ try {
27
+ unlinkSync(file);
28
+ logger.debug(`[opencode] Cleaned up temp config: ${file}`);
29
+ }
30
+ catch {
31
+ // Ignore cleanup errors - file may already be deleted
32
+ }
33
+ }
34
+ });
35
+ }
36
+ /**
37
+ * Write config to temp file as fallback when env var size exceeded
38
+ * Returns the temp file path
39
+ */
40
+ function writeConfigToTempFile(configJson) {
41
+ const configPath = join(tmpdir(), `codemie-opencode-config-${process.pid}-${Date.now()}.json`);
42
+ writeFileSync(configPath, configJson, 'utf-8');
43
+ tempConfigFiles.push(configPath);
44
+ registerCleanupHandler();
45
+ return configPath;
46
+ }
47
+ // NOTE: dataPaths in AgentMetadata only supports `home` and optional `settings`.
48
+ // OpenCode session storage paths are resolved separately in opencode.paths.ts
49
+ // since they follow XDG conventions and differ from the home directory.
50
+ /**
51
+ * Ensure session metadata file exists for SessionSyncer
52
+ * Creates or updates the session file in ~/.codemie/sessions/
53
+ */
54
+ async function ensureSessionFile(sessionId, env) {
55
+ try {
56
+ const { SessionStore } = await import('../../core/session/SessionStore.js');
57
+ const sessionStore = new SessionStore();
58
+ // Check if session already exists
59
+ const existing = await sessionStore.loadSession(sessionId);
60
+ if (existing) {
61
+ logger.debug('[opencode] Session file already exists');
62
+ return;
63
+ }
64
+ // Create new session file
65
+ const agentName = env.CODEMIE_AGENT || 'opencode';
66
+ const provider = env.CODEMIE_PROVIDER || 'unknown';
67
+ const project = env.CODEMIE_PROJECT;
68
+ const workingDirectory = process.cwd();
69
+ // Detect git branch
70
+ let gitBranch;
71
+ try {
72
+ const { detectGitBranch } = await import('../../../utils/processes.js');
73
+ gitBranch = await detectGitBranch(workingDirectory);
74
+ }
75
+ catch {
76
+ // Git detection optional
77
+ }
78
+ // Estimate startTime from grace period (session ended ~2 seconds ago during grace period)
79
+ // This prevents negative session durations in metrics aggregation
80
+ const estimatedStartTime = Date.now() - 2000;
81
+ const session = {
82
+ sessionId,
83
+ agentName,
84
+ provider,
85
+ ...(project && { project }),
86
+ startTime: estimatedStartTime,
87
+ workingDirectory,
88
+ ...(gitBranch && { gitBranch }),
89
+ status: 'completed', // Session already ended
90
+ activeDurationMs: 0,
91
+ correlation: {
92
+ status: 'matched',
93
+ agentSessionId: 'unknown', // Will be updated after discovery
94
+ retryCount: 0
95
+ }
96
+ };
97
+ await sessionStore.saveSession(session);
98
+ logger.debug('[opencode] Created session metadata file');
99
+ }
100
+ catch (error) {
101
+ logger.warn('[opencode] Failed to create session file:', error);
102
+ // Don't throw - processing can continue without session file (sync will fail though)
103
+ }
104
+ }
105
+ export const OpenCodePluginMetadata = {
106
+ name: 'opencode',
107
+ displayName: 'OpenCode CLI',
108
+ description: 'OpenCode - open-source AI coding assistant',
109
+ npmPackage: 'opencode-ai', // Official npm package (npm i -g opencode-ai)
110
+ cliCommand: process.env.CODEMIE_OPENCODE_BIN || 'opencode',
111
+ dataPaths: {
112
+ home: '.opencode'
113
+ // NOTE: Session storage is NOT in home - it's in XDG_DATA_HOME/opencode/storage/
114
+ // This is handled by getSessionStoragePath() in opencode.paths.ts
115
+ },
116
+ envMapping: {
117
+ baseUrl: [],
118
+ apiKey: [],
119
+ model: []
120
+ },
121
+ supportedProviders: ['litellm', 'ai-run-sso'],
122
+ ssoConfig: { enabled: true, clientType: 'codemie-opencode' },
123
+ lifecycle: {
124
+ // NOTE: beforeRun signature is (env, config) per AgentLifecycle interface
125
+ // Claude plugin only uses (env), but interface supports both
126
+ async beforeRun(env, config) {
127
+ // Create session metadata file at startup (before config setup)
128
+ // This ensures SessionSyncer can sync metrics to v1/metrics API (matching Claude/Gemini)
129
+ const sessionId = env.CODEMIE_SESSION_ID;
130
+ if (sessionId) {
131
+ try {
132
+ logger.debug(`[opencode] Creating session metadata file before startup`);
133
+ await ensureSessionFile(sessionId, env);
134
+ logger.debug(`[opencode] Session metadata file ready for SessionSyncer`);
135
+ }
136
+ catch (error) {
137
+ logger.error('[opencode] Failed to create session file in beforeRun', { error });
138
+ // Don't throw - let OpenCode run even if session file creation fails
139
+ }
140
+ }
141
+ const proxyUrl = env.CODEMIE_BASE_URL;
142
+ if (!proxyUrl) {
143
+ return env;
144
+ }
145
+ if (!proxyUrl.startsWith('http://') && !proxyUrl.startsWith('https://')) {
146
+ logger.warn(`Invalid CODEMIE_BASE_URL format: ${proxyUrl}`, { agent: 'opencode' });
147
+ return env;
148
+ }
149
+ // Model selection priority: env var > config > default
150
+ const selectedModel = env.CODEMIE_MODEL || config?.model || 'gpt-5-2-2025-12-11';
151
+ const modelConfig = getModelConfig(selectedModel);
152
+ // Extract OpenCode-compatible model config (remove CodeMie-specific fields)
153
+ const { displayName: _displayName, providerOptions, ...opencodeModelConfig } = modelConfig;
154
+ const openCodeConfig = {
155
+ enabled_providers: ['codemie-proxy'],
156
+ provider: {
157
+ 'codemie-proxy': {
158
+ npm: '@ai-sdk/openai-compatible',
159
+ name: 'CodeMie SSO',
160
+ options: {
161
+ baseURL: `${proxyUrl}/`,
162
+ apiKey: 'proxy-handled',
163
+ timeout: providerOptions?.timeout ||
164
+ parseInt(env.CODEMIE_TIMEOUT || '600') * 1000,
165
+ ...(providerOptions?.headers && {
166
+ headers: providerOptions.headers
167
+ })
168
+ },
169
+ models: {
170
+ [modelConfig.id]: opencodeModelConfig
171
+ }
172
+ }
173
+ },
174
+ defaults: {
175
+ model: `codemie-proxy/${modelConfig.id}`
176
+ }
177
+ };
178
+ const configJson = JSON.stringify(openCodeConfig);
179
+ // Config injection strategy:
180
+ // 1. Primary: OPENCODE_CONFIG_CONTENT env var (inline JSON)
181
+ // 2. Fallback: OPENCODE_CONFIG env var pointing to temp file
182
+ // See tech spec ADR-002 and "Fallback Strategy" section
183
+ if (configJson.length > MAX_ENV_SIZE) {
184
+ logger.warn(`Config size (${configJson.length} bytes) exceeds env var limit (${MAX_ENV_SIZE}), using temp file fallback`, {
185
+ agent: 'opencode'
186
+ });
187
+ const configPath = writeConfigToTempFile(configJson);
188
+ logger.debug(`[opencode] Wrote config to temp file: ${configPath}`);
189
+ // OPENCODE_CONFIG is verified in OpenCode source: src/flag/flag.ts
190
+ env.OPENCODE_CONFIG = configPath;
191
+ return env;
192
+ }
193
+ // Primary path: inject config inline via OPENCODE_CONFIG_CONTENT
194
+ // Verified in OpenCode source: src/config/config.ts:93-96
195
+ env.OPENCODE_CONFIG_CONTENT = configJson;
196
+ return env;
197
+ },
198
+ enrichArgs: (args, _config) => {
199
+ if (args.length > 0 && OPENCODE_SUBCOMMANDS.includes(args[0])) {
200
+ return args;
201
+ }
202
+ const taskIndex = args.indexOf('--task');
203
+ if (taskIndex !== -1 && taskIndex < args.length - 1) {
204
+ const taskValue = args[taskIndex + 1];
205
+ const otherArgs = args.filter((arg, i, arr) => {
206
+ if (i === taskIndex || i === taskIndex + 1)
207
+ return false;
208
+ if (arg === '-m' || arg === '--message')
209
+ return false;
210
+ if (i > 0 && (arr[i - 1] === '-m' || arr[i - 1] === '--message'))
211
+ return false;
212
+ return true;
213
+ });
214
+ return ['run', '-m', taskValue, ...otherArgs];
215
+ }
216
+ return args;
217
+ },
218
+ /**
219
+ * Process OpenCode session metrics before SessionSyncer runs
220
+ *
221
+ * Called by BaseAgentAdapter when OpenCode session ends, BEFORE SessionSyncer.
222
+ * This hook ensures metrics are written to JSONL in time for SessionSyncer's
223
+ * metrics-sync processor to send them to v1/metrics API.
224
+ *
225
+ * Lifecycle order:
226
+ * 1. OpenCode exits
227
+ * 2. Grace period (wait for file writes)
228
+ * 3. onSessionEnd ← WE ARE HERE (process metrics to JSONL)
229
+ * 4. SessionSyncer runs (reads JSONL, sends to v1/metrics)
230
+ * 5. Proxy stops
231
+ * 6. afterRun (cleanup)
232
+ *
233
+ * This matches Claude/Gemini real-time sync behavior where SessionSyncer
234
+ * automatically sends metrics during the session lifecycle.
235
+ */
236
+ async onSessionEnd(exitCode, env) {
237
+ const sessionId = env.CODEMIE_SESSION_ID;
238
+ if (!sessionId) {
239
+ logger.debug('[opencode] No CODEMIE_SESSION_ID in environment, skipping metrics processing');
240
+ return;
241
+ }
242
+ try {
243
+ logger.info(`[opencode] Processing session metrics before SessionSyncer (code=${exitCode})`);
244
+ // 1. Initialize session adapter
245
+ const adapter = new OpenCodeSessionAdapter(OpenCodePluginMetadata);
246
+ // 2. Discover recent sessions (last 24 hours)
247
+ const sessions = await adapter.discoverSessions({ maxAgeDays: 1 });
248
+ if (sessions.length === 0) {
249
+ logger.warn('[opencode] No recent OpenCode sessions found for processing');
250
+ return;
251
+ }
252
+ // 3. Process the most recent session
253
+ const latestSession = sessions[0];
254
+ logger.debug(`[opencode] Processing latest session: ${latestSession.sessionId}`);
255
+ logger.debug(`[opencode] OpenCode session ID: ${latestSession.sessionId}`);
256
+ logger.debug(`[opencode] CodeMie session ID: ${sessionId}`);
257
+ // 4. Build processing context (same as CLI command)
258
+ const context = {
259
+ sessionId,
260
+ apiBaseUrl: env.CODEMIE_BASE_URL || '',
261
+ cookies: '', // Will be loaded by processors if needed
262
+ clientType: 'codemie-opencode',
263
+ version: env.CODEMIE_CLI_VERSION || '1.0.0',
264
+ dryRun: false
265
+ };
266
+ // 5. Process session (extracts metrics + conversations to JSONL)
267
+ const result = await adapter.processSession(latestSession.filePath, sessionId, context);
268
+ if (result.success) {
269
+ logger.info(`[opencode] Metrics processing complete: ${result.totalRecords} records processed`);
270
+ logger.info(`[opencode] Metrics written to JSONL - SessionSyncer will sync to v1/metrics next`);
271
+ }
272
+ else {
273
+ logger.warn(`[opencode] Metrics processing had failures: ${result.failedProcessors.join(', ')}`);
274
+ }
275
+ // Note: SessionSyncer runs IMMEDIATELY after this hook completes.
276
+ // It will read the JSONL deltas we just wrote and send them to v1/metrics API.
277
+ // This matches Claude/Gemini real-time sync behavior during session lifecycle.
278
+ }
279
+ catch (error) {
280
+ const errorMessage = error instanceof Error ? error.message : String(error);
281
+ logger.error(`[opencode] Failed to process session metrics automatically: ${errorMessage}`);
282
+ // Don't throw - metrics failure shouldn't block exit
283
+ }
284
+ }
285
+ }
286
+ };
287
+ /**
288
+ * OpenCode agent plugin
289
+ * Phase 1: Core plugin with CLI wrapping and SSO proxy support
290
+ * Phase 2: Session analytics integration
291
+ */
292
+ export class OpenCodePlugin extends BaseAgentAdapter {
293
+ sessionAdapter;
294
+ constructor() {
295
+ super(OpenCodePluginMetadata);
296
+ // Initialize session adapter with metadata for unified session sync
297
+ this.sessionAdapter = new OpenCodeSessionAdapter(OpenCodePluginMetadata);
298
+ }
299
+ /**
300
+ * Check if OpenCode is installed
301
+ * Overridden to provide custom install instructions (AC-1.2)
302
+ *
303
+ * NOTE (GPT-5.5 review): This method should be SIDE-EFFECT FREE.
304
+ * Install instructions are displayed via logger (file-only in non-debug mode)
305
+ * so they appear in logs but don't pollute stdout during programmatic checks
306
+ * like `codemie doctor`. The CLI layer (AgentCLI) handles user-facing output.
307
+ */
308
+ async isInstalled() {
309
+ // Use metadata.cliCommand which respects CODEMIE_OPENCODE_BIN
310
+ const cliCommand = this.metadata.cliCommand;
311
+ if (!cliCommand)
312
+ return false;
313
+ const installed = await commandExists(cliCommand);
314
+ if (!installed) {
315
+ // Log install guidance to debug log (file-only unless CODEMIE_DEBUG=true)
316
+ // Actual user-facing message is handled by AgentCLI layer
317
+ logger.debug('[opencode-plugin] OpenCode not installed. Install with:');
318
+ logger.debug('[opencode-plugin] codemie install opencode');
319
+ logger.debug('[opencode-plugin] Or directly: npm i -g opencode-ai');
320
+ }
321
+ return installed;
322
+ }
323
+ /**
324
+ * Return session adapter for analytics
325
+ * Phase 2: Returns OpenCodeSessionAdapter instance
326
+ */
327
+ getSessionAdapter() {
328
+ return this.sessionAdapter;
329
+ }
330
+ /**
331
+ * No extension installer - OpenCode installed manually
332
+ * Returns undefined (interface allows optional return)
333
+ */
334
+ getExtensionInstaller() {
335
+ return undefined;
336
+ }
337
+ }
338
+ //# sourceMappingURL=opencode.plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode.plugin.js","sourceRoot":"","sources":["../../../../src/agents/plugins/opencode/opencode.plugin.ts"],"names":[],"mappings":"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"}