expandai 0.0.4 → 0.0.5

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 (319) hide show
  1. package/build/{esm/Install/Opencode → assets/opencode}/expandai-webfetch.js +22 -4
  2. package/build/dts/Mcp/RequestHeaders.d.ts +0 -1
  3. package/build/dts/Mcp/Server.d.ts +1 -2
  4. package/build/dts/index.d.ts +0 -1
  5. package/build/esm/index.js +180 -2
  6. package/build/esm/main.js +677 -200
  7. package/package.json +19 -11
  8. package/build/dts/ApiClient.d.ts +0 -165
  9. package/build/dts/ApiClient.d.ts.map +0 -1
  10. package/build/dts/Auth/Domain.d.ts +0 -95
  11. package/build/dts/Auth/Domain.d.ts.map +0 -1
  12. package/build/dts/Auth/ManualAuthorization.d.ts +0 -107
  13. package/build/dts/Auth/ManualAuthorization.d.ts.map +0 -1
  14. package/build/dts/Auth/PendingInit.d.ts +0 -35
  15. package/build/dts/Auth/PendingInit.d.ts.map +0 -1
  16. package/build/dts/Auth/Pkce.d.ts +0 -10
  17. package/build/dts/Auth/Pkce.d.ts.map +0 -1
  18. package/build/dts/Auth/SetupGrantAuthorization.d.ts +0 -34
  19. package/build/dts/Auth/SetupGrantAuthorization.d.ts.map +0 -1
  20. package/build/dts/Authentication.d.ts +0 -24
  21. package/build/dts/Authentication.d.ts.map +0 -1
  22. package/build/dts/BrowserOAuth.d.ts +0 -99
  23. package/build/dts/BrowserOAuth.d.ts.map +0 -1
  24. package/build/dts/CommandPath.d.ts +0 -2
  25. package/build/dts/CommandPath.d.ts.map +0 -1
  26. package/build/dts/Commands/Fetch.d.ts +0 -30
  27. package/build/dts/Commands/Fetch.d.ts.map +0 -1
  28. package/build/dts/Commands/Hook.d.ts +0 -17
  29. package/build/dts/Commands/Hook.d.ts.map +0 -1
  30. package/build/dts/Commands/Init.d.ts +0 -55
  31. package/build/dts/Commands/Init.d.ts.map +0 -1
  32. package/build/dts/Commands/Mcp.d.ts +0 -11
  33. package/build/dts/Commands/Mcp.d.ts.map +0 -1
  34. package/build/dts/Commands/McpRun.d.ts +0 -5
  35. package/build/dts/Commands/McpRun.d.ts.map +0 -1
  36. package/build/dts/Commands/Search.d.ts +0 -21
  37. package/build/dts/Commands/Search.d.ts.map +0 -1
  38. package/build/dts/Commands/Skill.d.ts +0 -12
  39. package/build/dts/Commands/Skill.d.ts.map +0 -1
  40. package/build/dts/Commands/Status.d.ts +0 -27
  41. package/build/dts/Commands/Status.d.ts.map +0 -1
  42. package/build/dts/Commands/Telemetry.d.ts +0 -7
  43. package/build/dts/Commands/Telemetry.d.ts.map +0 -1
  44. package/build/dts/Commands/Uninstall.d.ts +0 -9
  45. package/build/dts/Commands/Uninstall.d.ts.map +0 -1
  46. package/build/dts/Config.d.ts +0 -196
  47. package/build/dts/Config.d.ts.map +0 -1
  48. package/build/dts/Hook/Claude.d.ts +0 -13
  49. package/build/dts/Hook/Claude.d.ts.map +0 -1
  50. package/build/dts/Hook/Errors.d.ts +0 -20
  51. package/build/dts/Hook/Errors.d.ts.map +0 -1
  52. package/build/dts/Hook/Opencode.d.ts +0 -13
  53. package/build/dts/Hook/Opencode.d.ts.map +0 -1
  54. package/build/dts/Hook/SnapshotNote.d.ts +0 -12
  55. package/build/dts/Hook/SnapshotNote.d.ts.map +0 -1
  56. package/build/dts/Init/ClaudeAdapter.d.ts +0 -61
  57. package/build/dts/Init/ClaudeAdapter.d.ts.map +0 -1
  58. package/build/dts/Init/ClaudeProfile.d.ts +0 -77
  59. package/build/dts/Init/ClaudeProfile.d.ts.map +0 -1
  60. package/build/dts/Init/Domain.d.ts +0 -139
  61. package/build/dts/Init/Domain.d.ts.map +0 -1
  62. package/build/dts/Init/HarnessAdapter.d.ts +0 -33
  63. package/build/dts/Init/HarnessAdapter.d.ts.map +0 -1
  64. package/build/dts/Init/HarnessDetector.d.ts +0 -19
  65. package/build/dts/Init/HarnessDetector.d.ts.map +0 -1
  66. package/build/dts/Init/HarnessRegistry.d.ts +0 -50
  67. package/build/dts/Init/HarnessRegistry.d.ts.map +0 -1
  68. package/build/dts/Init/MutationTransaction.d.ts +0 -96
  69. package/build/dts/Init/MutationTransaction.d.ts.map +0 -1
  70. package/build/dts/Init/Service.d.ts +0 -72
  71. package/build/dts/Init/Service.d.ts.map +0 -1
  72. package/build/dts/Init/StandardAdapters.d.ts +0 -42
  73. package/build/dts/Init/StandardAdapters.d.ts.map +0 -1
  74. package/build/dts/Init/Status.d.ts +0 -149
  75. package/build/dts/Init/Status.d.ts.map +0 -1
  76. package/build/dts/Install/Claude/Hook.d.ts +0 -88
  77. package/build/dts/Install/Claude/Hook.d.ts.map +0 -1
  78. package/build/dts/Install/Claude/Mcp.d.ts +0 -48
  79. package/build/dts/Install/Claude/Mcp.d.ts.map +0 -1
  80. package/build/dts/Install/Claude/Skill.d.ts +0 -23
  81. package/build/dts/Install/Claude/Skill.d.ts.map +0 -1
  82. package/build/dts/Install/Codex/Mcp.d.ts +0 -45
  83. package/build/dts/Install/Codex/Mcp.d.ts.map +0 -1
  84. package/build/dts/Install/Codex/Skill.d.ts +0 -22
  85. package/build/dts/Install/Codex/Skill.d.ts.map +0 -1
  86. package/build/dts/Install/Cursor/Mcp.d.ts +0 -45
  87. package/build/dts/Install/Cursor/Mcp.d.ts.map +0 -1
  88. package/build/dts/Install/Cursor/Skill.d.ts +0 -29
  89. package/build/dts/Install/Cursor/Skill.d.ts.map +0 -1
  90. package/build/dts/Install/Domain.d.ts +0 -103
  91. package/build/dts/Install/Domain.d.ts.map +0 -1
  92. package/build/dts/Install/Hook.d.ts +0 -30
  93. package/build/dts/Install/Hook.d.ts.map +0 -1
  94. package/build/dts/Install/Mcp.d.ts +0 -28
  95. package/build/dts/Install/Mcp.d.ts.map +0 -1
  96. package/build/dts/Install/Opencode/Hook.d.ts +0 -24
  97. package/build/dts/Install/Opencode/Hook.d.ts.map +0 -1
  98. package/build/dts/Install/Opencode/Mcp.d.ts +0 -47
  99. package/build/dts/Install/Opencode/Mcp.d.ts.map +0 -1
  100. package/build/dts/Install/Opencode/Skill.d.ts +0 -26
  101. package/build/dts/Install/Opencode/Skill.d.ts.map +0 -1
  102. package/build/dts/Install/Skill.d.ts +0 -32
  103. package/build/dts/Install/Skill.d.ts.map +0 -1
  104. package/build/dts/Install/Uninstall.d.ts +0 -32
  105. package/build/dts/Install/Uninstall.d.ts.map +0 -1
  106. package/build/dts/MarkdownAnsi.d.ts +0 -29
  107. package/build/dts/MarkdownAnsi.d.ts.map +0 -1
  108. package/build/dts/Mcp/ExpandDocs.d.ts +0 -19
  109. package/build/dts/Mcp/ExpandDocs.d.ts.map +0 -1
  110. package/build/dts/Mcp/RequestHeaders.d.ts.map +0 -1
  111. package/build/dts/Mcp/Server.d.ts.map +0 -1
  112. package/build/dts/Mcp/Toolkit.d.ts +0 -3
  113. package/build/dts/Mcp/Toolkit.d.ts.map +0 -1
  114. package/build/dts/Mcp/tools/Citations.d.ts +0 -266
  115. package/build/dts/Mcp/tools/Citations.d.ts.map +0 -1
  116. package/build/dts/Mcp/tools/Fetch.d.ts +0 -168
  117. package/build/dts/Mcp/tools/Fetch.d.ts.map +0 -1
  118. package/build/dts/SecureFile.d.ts +0 -23
  119. package/build/dts/SecureFile.d.ts.map +0 -1
  120. package/build/dts/Snippets.d.ts +0 -18
  121. package/build/dts/Snippets.d.ts.map +0 -1
  122. package/build/dts/Telemetry.d.ts +0 -30
  123. package/build/dts/Telemetry.d.ts.map +0 -1
  124. package/build/dts/Version.d.ts +0 -2
  125. package/build/dts/Version.d.ts.map +0 -1
  126. package/build/dts/Xdg.d.ts +0 -11
  127. package/build/dts/Xdg.d.ts.map +0 -1
  128. package/build/dts/index.d.ts.map +0 -1
  129. package/build/dts/main.d.ts +0 -3
  130. package/build/dts/main.d.ts.map +0 -1
  131. package/build/esm/ApiClient.js +0 -305
  132. package/build/esm/ApiClient.js.map +0 -1
  133. package/build/esm/Auth/Domain.js +0 -56
  134. package/build/esm/Auth/Domain.js.map +0 -1
  135. package/build/esm/Auth/ManualAuthorization.js +0 -253
  136. package/build/esm/Auth/ManualAuthorization.js.map +0 -1
  137. package/build/esm/Auth/PendingInit.js +0 -267
  138. package/build/esm/Auth/PendingInit.js.map +0 -1
  139. package/build/esm/Auth/Pkce.js +0 -23
  140. package/build/esm/Auth/Pkce.js.map +0 -1
  141. package/build/esm/Auth/SetupGrantAuthorization.js +0 -91
  142. package/build/esm/Auth/SetupGrantAuthorization.js.map +0 -1
  143. package/build/esm/Authentication.js +0 -143
  144. package/build/esm/Authentication.js.map +0 -1
  145. package/build/esm/BrowserOAuth.js +0 -251
  146. package/build/esm/BrowserOAuth.js.map +0 -1
  147. package/build/esm/CommandPath.js +0 -31
  148. package/build/esm/CommandPath.js.map +0 -1
  149. package/build/esm/Commands/Fetch.js +0 -119
  150. package/build/esm/Commands/Fetch.js.map +0 -1
  151. package/build/esm/Commands/Hook.js +0 -20
  152. package/build/esm/Commands/Hook.js.map +0 -1
  153. package/build/esm/Commands/Init.js +0 -371
  154. package/build/esm/Commands/Init.js.map +0 -1
  155. package/build/esm/Commands/Mcp.js +0 -19
  156. package/build/esm/Commands/Mcp.js.map +0 -1
  157. package/build/esm/Commands/McpRun.js +0 -15
  158. package/build/esm/Commands/McpRun.js.map +0 -1
  159. package/build/esm/Commands/Search.js +0 -46
  160. package/build/esm/Commands/Search.js.map +0 -1
  161. package/build/esm/Commands/Skill.js +0 -17
  162. package/build/esm/Commands/Skill.js.map +0 -1
  163. package/build/esm/Commands/Status.js +0 -186
  164. package/build/esm/Commands/Status.js.map +0 -1
  165. package/build/esm/Commands/Telemetry.js +0 -23
  166. package/build/esm/Commands/Telemetry.js.map +0 -1
  167. package/build/esm/Commands/Uninstall.js +0 -28
  168. package/build/esm/Commands/Uninstall.js.map +0 -1
  169. package/build/esm/Config.js +0 -619
  170. package/build/esm/Config.js.map +0 -1
  171. package/build/esm/Hook/Claude.js +0 -74
  172. package/build/esm/Hook/Claude.js.map +0 -1
  173. package/build/esm/Hook/Errors.js +0 -18
  174. package/build/esm/Hook/Errors.js.map +0 -1
  175. package/build/esm/Hook/Opencode.js +0 -50
  176. package/build/esm/Hook/Opencode.js.map +0 -1
  177. package/build/esm/Hook/SnapshotNote.js +0 -65
  178. package/build/esm/Hook/SnapshotNote.js.map +0 -1
  179. package/build/esm/Init/ClaudeAdapter.js +0 -137
  180. package/build/esm/Init/ClaudeAdapter.js.map +0 -1
  181. package/build/esm/Init/ClaudeProfile.js +0 -344
  182. package/build/esm/Init/ClaudeProfile.js.map +0 -1
  183. package/build/esm/Init/Domain.js +0 -118
  184. package/build/esm/Init/Domain.js.map +0 -1
  185. package/build/esm/Init/HarnessAdapter.js +0 -21
  186. package/build/esm/Init/HarnessAdapter.js.map +0 -1
  187. package/build/esm/Init/HarnessDetector.js +0 -65
  188. package/build/esm/Init/HarnessDetector.js.map +0 -1
  189. package/build/esm/Init/HarnessRegistry.js +0 -58
  190. package/build/esm/Init/HarnessRegistry.js.map +0 -1
  191. package/build/esm/Init/MutationTransaction.js +0 -494
  192. package/build/esm/Init/MutationTransaction.js.map +0 -1
  193. package/build/esm/Init/Service.js +0 -319
  194. package/build/esm/Init/Service.js.map +0 -1
  195. package/build/esm/Init/StandardAdapters.js +0 -116
  196. package/build/esm/Init/StandardAdapters.js.map +0 -1
  197. package/build/esm/Init/Status.js +0 -215
  198. package/build/esm/Init/Status.js.map +0 -1
  199. package/build/esm/Install/Claude/Hook.js +0 -77
  200. package/build/esm/Install/Claude/Hook.js.map +0 -1
  201. package/build/esm/Install/Claude/Mcp.js +0 -101
  202. package/build/esm/Install/Claude/Mcp.js.map +0 -1
  203. package/build/esm/Install/Claude/Skill.js +0 -56
  204. package/build/esm/Install/Claude/Skill.js.map +0 -1
  205. package/build/esm/Install/Codex/Mcp.js +0 -97
  206. package/build/esm/Install/Codex/Mcp.js.map +0 -1
  207. package/build/esm/Install/Codex/Skill.js +0 -33
  208. package/build/esm/Install/Codex/Skill.js.map +0 -1
  209. package/build/esm/Install/Cursor/Mcp.js +0 -74
  210. package/build/esm/Install/Cursor/Mcp.js.map +0 -1
  211. package/build/esm/Install/Cursor/Skill.js +0 -40
  212. package/build/esm/Install/Cursor/Skill.js.map +0 -1
  213. package/build/esm/Install/Domain.js +0 -162
  214. package/build/esm/Install/Domain.js.map +0 -1
  215. package/build/esm/Install/Hook.js +0 -38
  216. package/build/esm/Install/Hook.js.map +0 -1
  217. package/build/esm/Install/Mcp.js +0 -40
  218. package/build/esm/Install/Mcp.js.map +0 -1
  219. package/build/esm/Install/Opencode/Hook.js +0 -44
  220. package/build/esm/Install/Opencode/Hook.js.map +0 -1
  221. package/build/esm/Install/Opencode/Mcp.js +0 -76
  222. package/build/esm/Install/Opencode/Mcp.js.map +0 -1
  223. package/build/esm/Install/Opencode/Skill.js +0 -37
  224. package/build/esm/Install/Opencode/Skill.js.map +0 -1
  225. package/build/esm/Install/Skill.js +0 -41
  226. package/build/esm/Install/Skill.js.map +0 -1
  227. package/build/esm/Install/Uninstall.js +0 -49
  228. package/build/esm/Install/Uninstall.js.map +0 -1
  229. package/build/esm/MarkdownAnsi.js +0 -142
  230. package/build/esm/MarkdownAnsi.js.map +0 -1
  231. package/build/esm/Mcp/ExpandDocs.js +0 -56
  232. package/build/esm/Mcp/ExpandDocs.js.map +0 -1
  233. package/build/esm/Mcp/RequestHeaders.js +0 -13
  234. package/build/esm/Mcp/RequestHeaders.js.map +0 -1
  235. package/build/esm/Mcp/Server.js +0 -12
  236. package/build/esm/Mcp/Server.js.map +0 -1
  237. package/build/esm/Mcp/Toolkit.js +0 -16
  238. package/build/esm/Mcp/Toolkit.js.map +0 -1
  239. package/build/esm/Mcp/tools/Citations.js +0 -193
  240. package/build/esm/Mcp/tools/Citations.js.map +0 -1
  241. package/build/esm/Mcp/tools/Fetch.js +0 -165
  242. package/build/esm/Mcp/tools/Fetch.js.map +0 -1
  243. package/build/esm/SecureFile.js +0 -36
  244. package/build/esm/SecureFile.js.map +0 -1
  245. package/build/esm/Snippets.js +0 -29
  246. package/build/esm/Snippets.js.map +0 -1
  247. package/build/esm/Telemetry.js +0 -157
  248. package/build/esm/Telemetry.js.map +0 -1
  249. package/build/esm/Version.js +0 -4
  250. package/build/esm/Version.js.map +0 -1
  251. package/build/esm/Xdg.js +0 -15
  252. package/build/esm/Xdg.js.map +0 -1
  253. package/build/esm/index.js.map +0 -1
  254. package/build/esm/main.js.map +0 -1
  255. package/src/ApiClient.ts +0 -450
  256. package/src/Auth/Domain.ts +0 -63
  257. package/src/Auth/ManualAuthorization.ts +0 -296
  258. package/src/Auth/PendingInit.ts +0 -338
  259. package/src/Auth/Pkce.ts +0 -26
  260. package/src/Auth/SetupGrantAuthorization.ts +0 -116
  261. package/src/Authentication.ts +0 -202
  262. package/src/BrowserOAuth.ts +0 -359
  263. package/src/CommandPath.ts +0 -30
  264. package/src/Commands/Fetch.ts +0 -188
  265. package/src/Commands/Hook.ts +0 -48
  266. package/src/Commands/Init.ts +0 -489
  267. package/src/Commands/Mcp.ts +0 -30
  268. package/src/Commands/McpRun.ts +0 -25
  269. package/src/Commands/Search.ts +0 -97
  270. package/src/Commands/Skill.ts +0 -30
  271. package/src/Commands/Status.ts +0 -228
  272. package/src/Commands/Telemetry.ts +0 -42
  273. package/src/Commands/Uninstall.ts +0 -38
  274. package/src/Config.ts +0 -840
  275. package/src/Hook/Claude.ts +0 -81
  276. package/src/Hook/Errors.ts +0 -19
  277. package/src/Hook/Opencode.ts +0 -58
  278. package/src/Hook/SnapshotNote.ts +0 -66
  279. package/src/Init/ClaudeAdapter.ts +0 -191
  280. package/src/Init/ClaudeProfile.ts +0 -453
  281. package/src/Init/Domain.ts +0 -153
  282. package/src/Init/HarnessAdapter.ts +0 -35
  283. package/src/Init/HarnessDetector.ts +0 -77
  284. package/src/Init/HarnessRegistry.ts +0 -87
  285. package/src/Init/MutationTransaction.ts +0 -747
  286. package/src/Init/Service.ts +0 -385
  287. package/src/Init/StandardAdapters.ts +0 -141
  288. package/src/Init/Status.ts +0 -253
  289. package/src/Install/Claude/Hook.ts +0 -123
  290. package/src/Install/Claude/Mcp.ts +0 -129
  291. package/src/Install/Claude/Skill.ts +0 -77
  292. package/src/Install/Codex/Mcp.ts +0 -114
  293. package/src/Install/Codex/Skill.ts +0 -44
  294. package/src/Install/Cursor/Mcp.ts +0 -85
  295. package/src/Install/Cursor/Skill.ts +0 -51
  296. package/src/Install/Domain.ts +0 -221
  297. package/src/Install/Hook.ts +0 -50
  298. package/src/Install/Mcp.ts +0 -71
  299. package/src/Install/Opencode/Hook.ts +0 -55
  300. package/src/Install/Opencode/Mcp.ts +0 -87
  301. package/src/Install/Opencode/Skill.ts +0 -48
  302. package/src/Install/Opencode/expandai-webfetch.d.ts +0 -23
  303. package/src/Install/Opencode/expandai-webfetch.js +0 -56
  304. package/src/Install/Skill.ts +0 -57
  305. package/src/Install/Uninstall.ts +0 -82
  306. package/src/MarkdownAnsi.ts +0 -162
  307. package/src/Mcp/ExpandDocs.ts +0 -62
  308. package/src/Mcp/RequestHeaders.ts +0 -16
  309. package/src/Mcp/Server.ts +0 -15
  310. package/src/Mcp/Toolkit.ts +0 -21
  311. package/src/Mcp/tools/Citations.ts +0 -219
  312. package/src/Mcp/tools/Fetch.ts +0 -203
  313. package/src/SecureFile.ts +0 -70
  314. package/src/Snippets.ts +0 -39
  315. package/src/Telemetry.ts +0 -186
  316. package/src/Version.ts +0 -3
  317. package/src/Xdg.ts +0 -18
  318. package/src/index.ts +0 -1
  319. package/src/main.ts +0 -305
@@ -1,453 +0,0 @@
1
- import { homedir } from 'node:os'
2
- import { FileSystem, Path } from '@effect/platform'
3
- import { NodeFileSystem, NodePath } from '@effect/platform-node'
4
- import { Array, Config, Effect, Either, Layer, Option, Schema } from 'effect'
5
- import { SettingsSchema } from '../Install/Claude/Hook.js'
6
- import { planClaudeMcp } from '../Install/Claude/Mcp.js'
7
- import { planClaudeSkill, SKILL_FILE_NAME, SKILL_NAME } from '../Install/Claude/Skill.js'
8
- import { type CliCommand, CliInvocation, McpServersConfigSchema, SERVER_KEY } from '../Install/Domain.js'
9
- import { CLI_VERSION } from '../Version.js'
10
- import type { InitComponent, InitScope } from './Domain.js'
11
- import type { MutationExpectedState, MutationOperation } from './MutationTransaction.js'
12
-
13
- export const CLAUDE_PROFILE_VERSION = CLI_VERSION
14
-
15
- export const CLAUDE_POLICY_MANAGED_MCP = 'managed_mcp_only'
16
- export const CLAUDE_POLICY_MCP_DENIED = 'managed_mcp_denied'
17
- export const CLAUDE_POLICY_MCP_NOT_ALLOWED = 'managed_mcp_not_allowed'
18
- export const CLAUDE_POLICY_READ_ONLY = 'target_read_only'
19
-
20
- interface ClaudeTargetLocations {
21
- readonly settingsFile: string
22
- readonly skillDirectory: string
23
- readonly skillFile: string
24
- readonly mcpFile: string
25
- readonly managedSettingsFiles: string[]
26
- readonly managedSettingsDirectories: string[]
27
- }
28
-
29
- export interface ClaudeManagedSettingsLocationSet {
30
- readonly files: string[]
31
- readonly directories: string[]
32
- }
33
-
34
- interface ClaudeRegistrationInspection {
35
- readonly current: boolean
36
- readonly installed: boolean
37
- readonly legacyVariants: string[]
38
- readonly version?: string
39
- }
40
-
41
- export interface ClaudeProfileInspection {
42
- readonly scope: InitScope
43
- readonly targets: ClaudeTargetLocations
44
- readonly hook: ClaudeRegistrationInspection
45
- readonly skill: ClaudeRegistrationInspection
46
- readonly mcp: ClaudeRegistrationInspection
47
- readonly components: InitComponent[]
48
- readonly configured: boolean
49
- readonly profileVersion: string
50
- readonly componentVersions: {
51
- readonly hook?: string
52
- readonly skill?: string
53
- readonly mcp?: string
54
- }
55
- readonly policyBlocks: string[]
56
- readonly remotePolicyMayApply: true
57
- readonly reloadMayBeRequired: boolean
58
- readonly consentMayBeRequired: boolean
59
- }
60
-
61
- export interface ClaudeProfileMutationPlan {
62
- readonly changed: boolean
63
- readonly inspection: ClaudeProfileInspection
64
- readonly resultInspection: ClaudeProfileInspection
65
- readonly operations: MutationOperation[]
66
- }
67
-
68
- interface LoadedClaudeProfile {
69
- readonly targets: ClaudeTargetLocations
70
- readonly settings: typeof SettingsSchema.Type
71
- readonly settingsExpected: MutationExpectedState
72
- readonly settingsText?: string
73
- readonly skillExpected: MutationExpectedState
74
- readonly skillText?: string
75
- readonly bundledSkillText: string
76
- readonly mcp: typeof McpServersConfigSchema.Type
77
- readonly mcpExpected: MutationExpectedState
78
- readonly mcpText?: string
79
- readonly managedSettings: ReadonlyArray<Record<string, unknown>>
80
- readonly readOnlyTargets: string[]
81
- }
82
-
83
- const JsonRecord = Schema.parseJson(Schema.Record({ key: Schema.String, value: Schema.Unknown }))
84
- const PROFILE_VERSION_PATTERN = /^\s*expandai-profile-version:\s*([^\s]+)\s*$/mu
85
- const textEncoder = new TextEncoder()
86
- const textDecoder = new TextDecoder()
87
- const MODE_MAX = 0o7777
88
-
89
- function isUnknownRecord(value: unknown): value is Record<string, unknown> {
90
- return typeof value === 'object' && value !== null && !Array.isArray(value)
91
- }
92
-
93
- function defaultManagedSettingsLocations(): ClaudeManagedSettingsLocationSet {
94
- if (process.platform === 'darwin') {
95
- const root = '/Library/Application Support/ClaudeCode'
96
- return {
97
- files: [`${root}/managed-settings.json`, `${root}/managed-mcp.json`],
98
- directories: [`${root}/managed-settings.d`],
99
- }
100
- }
101
- if (process.platform === 'win32') {
102
- const root = 'C:\\Program Files\\ClaudeCode'
103
- return {
104
- files: [`${root}\\managed-settings.json`, `${root}\\managed-mcp.json`],
105
- directories: [`${root}\\managed-settings.d`],
106
- }
107
- }
108
- return {
109
- files: ['/etc/claude-code/managed-settings.json', '/etc/claude-code/managed-mcp.json'],
110
- directories: ['/etc/claude-code/managed-settings.d'],
111
- }
112
- }
113
-
114
- /** Discoverable file-based Claude managed-policy locations for the current platform. */
115
- export class ClaudeManagedSettingsLocations extends Effect.Service<ClaudeManagedSettingsLocations>()(
116
- '@expandai/cli/Init/ClaudeManagedSettingsLocations',
117
- {
118
- sync: defaultManagedSettingsLocations,
119
- },
120
- ) {
121
- static testLayer(locations: ClaudeManagedSettingsLocationSet) {
122
- return Layer.succeed(ClaudeManagedSettingsLocations, ClaudeManagedSettingsLocations.make(locations))
123
- }
124
- }
125
-
126
- function listContainsExpandai(value: unknown): boolean {
127
- if (!Array.isArray(value)) return false
128
- return value.some((entry) => {
129
- if (entry === SERVER_KEY) return true
130
- if (!isUnknownRecord(entry)) return false
131
- return entry.name === SERVER_KEY || entry.serverName === SERVER_KEY
132
- })
133
- }
134
-
135
- function managedPolicyBlocks(settings: ReadonlyArray<Record<string, unknown>>): string[] {
136
- const blocks = new Set<string>()
137
- const managedMcpOnly = settings.some((value) => value.allowManagedMcpServersOnly === true)
138
- const allowedMcpConfigured = settings.some((value) => Array.isArray(value.allowedMcpServers))
139
- const expandaiAllowed = settings.some((value) => listContainsExpandai(value.allowedMcpServers))
140
- // `allowManagedHooksOnly` is deliberately not consulted. It restricts which hooks
141
- // may be installed, and this profile installs none — blocking on it would refuse
142
- // a skill-plus-MCP setup the policy has no objection to.
143
- for (const value of settings) {
144
- if (listContainsExpandai(value.deniedMcpServers)) blocks.add(CLAUDE_POLICY_MCP_DENIED)
145
- }
146
- if (managedMcpOnly && !expandaiAllowed) blocks.add(CLAUDE_POLICY_MANAGED_MCP)
147
- if (allowedMcpConfigured && !expandaiAllowed) blocks.add(CLAUDE_POLICY_MCP_NOT_ALLOWED)
148
- return [...blocks].sort()
149
- }
150
-
151
- function skillVersion(text: string | undefined): string | undefined {
152
- if (text === undefined) return undefined
153
- return PROFILE_VERSION_PATTERN.exec(text)?.[1]
154
- }
155
-
156
- function mcpLegacyVariant(value: unknown): string[] {
157
- if (!isUnknownRecord(value)) return value === undefined ? [] : ['owned-entry']
158
- const command = value.command
159
- const args = value.args
160
- if (command === 'npx' && Array.isArray(args) && args[0] === '-y') return ['npx-y']
161
- if (typeof command === 'string' && command !== 'expandai' && /(?:^|[\\/])expandai(?:\.exe)?$/u.test(command)) {
162
- return ['absolute-path']
163
- }
164
- return ['owned-entry']
165
- }
166
-
167
- function makeInspection(scope: InitScope, loaded: LoadedClaudeProfile, cli: CliCommand): ClaudeProfileInspection {
168
- const plannedSkill = planClaudeSkill(loaded.skillText, loaded.bundledSkillText, CLAUDE_PROFILE_VERSION)
169
- const currentSkillVersion = skillVersion(loaded.skillText)
170
- const skillCurrent = loaded.skillText !== undefined && !plannedSkill.changed
171
-
172
- const mcpValue = loaded.mcp.mcpServers[SERVER_KEY]
173
- const mcpCurrent = !planClaudeMcp(loaded.mcp, cli).changed
174
- const components: InitComponent[] = []
175
- if (skillCurrent) components.push('runtime-skill')
176
- if (mcpCurrent) components.push('mcp')
177
-
178
- const policyBlocks = managedPolicyBlocks(loaded.managedSettings)
179
- if (loaded.readOnlyTargets.length > 0) policyBlocks.push(CLAUDE_POLICY_READ_ONLY)
180
-
181
- return {
182
- scope,
183
- targets: loaded.targets,
184
- // Claude Code has no hook component. Reported as absent-and-current so a
185
- // caller that still reads this field cannot conclude something is missing.
186
- hook: { current: true, installed: false, legacyVariants: [] },
187
- skill: {
188
- current: skillCurrent,
189
- installed: loaded.skillText !== undefined,
190
- legacyVariants: loaded.skillText === undefined || skillCurrent ? [] : ['outdated-runtime-skill'],
191
- ...(currentSkillVersion === undefined ? {} : { version: currentSkillVersion }),
192
- },
193
- mcp: {
194
- current: mcpCurrent,
195
- installed: mcpValue !== undefined,
196
- legacyVariants: mcpCurrent ? [] : mcpLegacyVariant(mcpValue),
197
- },
198
- components,
199
- configured: components.length === 2,
200
- profileVersion: CLAUDE_PROFILE_VERSION,
201
- componentVersions: {
202
- ...(currentSkillVersion === undefined ? {} : { skill: currentSkillVersion }),
203
- ...(mcpCurrent ? { mcp: CLAUDE_PROFILE_VERSION } : {}),
204
- },
205
- policyBlocks: [...new Set(policyBlocks)].sort(),
206
- remotePolicyMayApply: true,
207
- reloadMayBeRequired: !mcpCurrent,
208
- consentMayBeRequired: scope === 'project',
209
- }
210
- }
211
-
212
- const makeClaudeProfile = Effect.gen(function* () {
213
- const fileSystem = yield* FileSystem.FileSystem
214
- const path = yield* Path.Path
215
- const managedSettingsLocations = yield* ClaudeManagedSettingsLocations
216
- // Resolved once per service: whether `expandai` is on PATH decides what the
217
- // written hook and MCP entries invoke, and it cannot change mid-install.
218
- const cli = yield* (yield* CliInvocation).resolve()
219
- const home = yield* Config.string('HOME').pipe(Config.withDefault(homedir()))
220
- const cwd = yield* Config.string('PWD').pipe(Config.withDefault(process.cwd()))
221
- const moduleFile = yield* path.fromFileUrl(new URL(import.meta.url))
222
- const bundledSkillFile = path.resolve(path.dirname(moduleFile), '..', '..', 'skills', SKILL_NAME, SKILL_FILE_NAME)
223
-
224
- const readOptional = Effect.fnUntraced(function* (file: string) {
225
- return (yield* fileSystem.exists(file)) ? yield* fileSystem.readFileString(file) : undefined
226
- })
227
-
228
- const readPlannedFile = Effect.fnUntraced(function* (file: string) {
229
- if (!(yield* fileSystem.exists(file))) {
230
- return { expected: { exists: false } as const }
231
- }
232
- const info = yield* fileSystem.stat(file)
233
- const bytes = yield* fileSystem.readFile(file)
234
- return {
235
- expected: {
236
- exists: true,
237
- type: 'File',
238
- bytes,
239
- mode: info.mode & MODE_MAX,
240
- } as const,
241
- text: textDecoder.decode(bytes),
242
- }
243
- })
244
-
245
- const expectedDirectory = Effect.fnUntraced(function* (directory: string) {
246
- if (!(yield* fileSystem.exists(directory))) return { exists: false } as const
247
- const info = yield* fileSystem.stat(directory)
248
- if (info.type !== 'Directory') throw new Error('Planned directory target is not a directory')
249
- return {
250
- exists: true,
251
- type: 'Directory',
252
- mode: info.mode & MODE_MAX,
253
- } as const
254
- })
255
-
256
- const writableAncestor = Effect.fnUntraced(function* (target: string) {
257
- function ancestors(candidate: string): string[] {
258
- const parent = path.dirname(candidate)
259
- return parent === candidate ? [candidate] : [candidate, ...ancestors(parent)]
260
- }
261
- const candidates = ancestors(target)
262
- const states = yield* Effect.forEach(candidates, (candidate) =>
263
- fileSystem.exists(candidate).pipe(Effect.map((exists) => ({ candidate, exists }))),
264
- )
265
- const candidate = states.find((state) => state.exists)?.candidate ?? candidates[candidates.length - 1]
266
- if (candidate === undefined) return false
267
- const info = yield* fileSystem.stat(candidate)
268
- return (info.mode & 0o222) !== 0
269
- })
270
-
271
- const mutationRequirementsWritable = Effect.fnUntraced(function* (operation: MutationOperation) {
272
- if (
273
- operation.type === 'write' &&
274
- operation.expected?.exists === true &&
275
- operation.expected.type === 'File' &&
276
- !(yield* Effect.either(fileSystem.access(operation.path, { writable: true }))).pipe(Either.isRight)
277
- ) {
278
- return false
279
- }
280
- if (operation.type === 'mkdir' && operation.expected?.exists === true) return true
281
-
282
- const parent = path.dirname(operation.path)
283
- function ancestors(candidate: string): string[] {
284
- const next = path.dirname(candidate)
285
- return next === candidate ? [candidate] : [candidate, ...ancestors(next)]
286
- }
287
- const candidates = ancestors(parent)
288
- const states = yield* Effect.forEach(candidates, (candidate) =>
289
- fileSystem.exists(candidate).pipe(Effect.map((exists) => ({ candidate, exists }))),
290
- )
291
- const nearest = states.find((state) => state.exists)?.candidate
292
- if (nearest === undefined) return false
293
- const existing = states.filter((state) => state.exists)
294
- const traversable = yield* Effect.forEach(existing, ({ candidate }) =>
295
- fileSystem.stat(candidate).pipe(
296
- Effect.map((info) => info.type === 'Directory' && (process.platform === 'win32' || (info.mode & 0o111) !== 0)),
297
- Effect.orElseSucceed(() => false),
298
- ),
299
- )
300
- if (!traversable.every(Boolean)) return false
301
- // FileSystem.access performs the platform's effective writable check.
302
- // Windows has no separate directory-traverse/ACL primitive here, so the
303
- // transaction remains the final fail-closed enforcement for that facet.
304
- return (yield* Effect.either(fileSystem.access(nearest, { writable: true }))).pipe(Either.isRight)
305
- })
306
-
307
- const load = Effect.fn('ClaudeProfile.load')(function* (scope: InitScope) {
308
- const root = scope === 'global' ? home : cwd
309
- const skillDirectory = path.join(root, '.claude', 'skills', SKILL_NAME)
310
- const managed = managedSettingsLocations
311
- const dropInFiles = yield* Effect.flatMap(
312
- Effect.forEach(managed.directories, (directory) =>
313
- fileSystem.exists(directory).pipe(
314
- Effect.flatMap((exists) => (exists ? fileSystem.readDirectory(directory) : Effect.succeed([]))),
315
- Effect.map((entries) =>
316
- entries
317
- .filter((entry) => !entry.startsWith('.') && entry.endsWith('.json'))
318
- .sort()
319
- .map((entry) => path.join(directory, entry)),
320
- ),
321
- ),
322
- ),
323
- (files) => Effect.succeed(files.flat()),
324
- )
325
- const targets: ClaudeTargetLocations = {
326
- settingsFile: path.join(root, '.claude', 'settings.json'),
327
- skillDirectory,
328
- skillFile: path.join(skillDirectory, SKILL_FILE_NAME),
329
- mcpFile: scope === 'global' ? path.join(home, '.claude.json') : path.join(cwd, '.mcp.json'),
330
- managedSettingsFiles: [...managed.files, ...dropInFiles],
331
- managedSettingsDirectories: managed.directories,
332
- }
333
-
334
- const settingsFile = yield* readPlannedFile(targets.settingsFile)
335
- const skillFile = yield* readPlannedFile(targets.skillFile)
336
- const mcpFile = yield* readPlannedFile(targets.mcpFile)
337
- const settingsText = settingsFile.text
338
- const skillText = skillFile.text
339
- const mcpText = mcpFile.text
340
- const bundledSkillText = yield* fileSystem.readFileString(bundledSkillFile)
341
- const settings = yield* Schema.decode(SettingsSchema)(settingsText ?? '{}')
342
- const mcp = yield* Schema.decode(McpServersConfigSchema)(mcpText ?? '{}')
343
- const managedSettings = yield* Effect.forEach(targets.managedSettingsFiles, (file) =>
344
- readOptional(file).pipe(
345
- Effect.flatMap((text) =>
346
- text === undefined
347
- ? Effect.succeed(Option.none())
348
- : Schema.decode(JsonRecord)(text).pipe(Effect.map(Option.some)),
349
- ),
350
- ),
351
- )
352
- // Only the files this profile writes. `settings.json` is left alone, so its
353
- // being read-only says nothing about whether setup can succeed — checking it
354
- // would refuse an install that never touches it.
355
- const readOnlyTargets = yield* Effect.filter([targets.skillFile, targets.mcpFile], (target) =>
356
- writableAncestor(target).pipe(Effect.map((writable) => !writable)),
357
- )
358
-
359
- return {
360
- targets,
361
- settings,
362
- settingsExpected: settingsFile.expected,
363
- ...(settingsText === undefined ? {} : { settingsText }),
364
- skillExpected: skillFile.expected,
365
- ...(skillText === undefined ? {} : { skillText }),
366
- bundledSkillText,
367
- mcp,
368
- mcpExpected: mcpFile.expected,
369
- ...(mcpText === undefined ? {} : { mcpText }),
370
- managedSettings: Array.getSomes(managedSettings),
371
- readOnlyTargets,
372
- } satisfies LoadedClaudeProfile
373
- })
374
-
375
- const inspect = Effect.fn('ClaudeProfile.inspect')(function* (scope: InitScope) {
376
- return makeInspection(scope, yield* load(scope), cli)
377
- })
378
-
379
- const plan = Effect.fn('ClaudeProfile.plan')(function* (scope: InitScope) {
380
- const loaded = yield* load(scope)
381
- // The Claude Code profile is the MCP server plus the runtime skill, and nothing
382
- // else. `settings.json` is not written at all: no `permissions` entry, no
383
- // PreToolUse hook. Both of those can disable a built-in tool, and a install
384
- // that can disable a built-in tool can also fail leaving it disabled.
385
- const skillPlan = planClaudeSkill(loaded.skillText, loaded.bundledSkillText, CLAUDE_PROFILE_VERSION)
386
- const mcpPlan = planClaudeMcp(loaded.mcp, cli)
387
- const mcpText = `${yield* Schema.encode(McpServersConfigSchema)(mcpPlan.config)}\n`
388
- const settingsDirectory = path.dirname(loaded.targets.settingsFile)
389
- const skillsDirectory = path.dirname(loaded.targets.skillDirectory)
390
- const operations: MutationOperation[] = []
391
- if (skillPlan.changed) {
392
- operations.push({
393
- type: 'mkdir',
394
- path: settingsDirectory,
395
- expected: yield* expectedDirectory(settingsDirectory),
396
- })
397
- }
398
- if (skillPlan.changed) {
399
- operations.push({
400
- type: 'mkdir',
401
- path: skillsDirectory,
402
- expected: yield* expectedDirectory(skillsDirectory),
403
- })
404
- operations.push({
405
- type: 'mkdir',
406
- path: loaded.targets.skillDirectory,
407
- expected: yield* expectedDirectory(loaded.targets.skillDirectory),
408
- })
409
- operations.push({
410
- type: 'write',
411
- path: loaded.targets.skillFile,
412
- bytes: textEncoder.encode(skillPlan.text),
413
- expected: loaded.skillExpected,
414
- })
415
- }
416
- if (mcpPlan.changed) {
417
- operations.push({
418
- type: 'write',
419
- path: loaded.targets.mcpFile,
420
- bytes: textEncoder.encode(mcpText),
421
- expected: loaded.mcpExpected,
422
- })
423
- }
424
- const requirements = yield* Effect.forEach(operations, mutationRequirementsWritable)
425
- const inspectedLoaded = requirements.every(Boolean)
426
- ? loaded
427
- : { ...loaded, readOnlyTargets: [...loaded.readOnlyTargets, 'mutation-requirement'] }
428
- const inspection = makeInspection(scope, inspectedLoaded, cli)
429
- const resultInspection = makeInspection(
430
- scope,
431
- {
432
- ...inspectedLoaded,
433
- skillText: skillPlan.text,
434
- mcp: mcpPlan.config,
435
- mcpText,
436
- },
437
- cli,
438
- )
439
- return {
440
- changed: skillPlan.changed || mcpPlan.changed,
441
- inspection,
442
- resultInspection,
443
- operations,
444
- } satisfies ClaudeProfileMutationPlan
445
- })
446
-
447
- return { inspect, plan } as const
448
- })
449
-
450
- export class ClaudeProfile extends Effect.Service<ClaudeProfile>()('@expandai/cli/Init/ClaudeProfile', {
451
- dependencies: [NodeFileSystem.layer, NodePath.layer, ClaudeManagedSettingsLocations.Default, CliInvocation.Default],
452
- effect: makeClaudeProfile,
453
- }) {}
@@ -1,153 +0,0 @@
1
- import { Schema } from 'effect'
2
-
3
- // Relayed verbatim by the agent, and printed as-is in the terminal, so it has to
4
- // carry the whole browser round-trip on its own — the guide no longer restates it.
5
- export const AUTHORIZATION_REQUIRED_MESSAGE =
6
- 'Open the approval page in your browser, type in the code shown here, and approve. Only enter this code on the Expand approval page your terminal named — never a code someone sent you, and never on a page from a link you did not expect. When you have approved, say so, and the same command will pick the authorization up.'
7
-
8
- export const AUTHORIZATION_CONSUMED_MESSAGE =
9
- 'Authorization complete. That setup code has been consumed and cannot be reused.'
10
-
11
- export const ALREADY_AUTHENTICATED_MESSAGE = 'Expand is already authorized. Agent setup is complete.'
12
-
13
- /**
14
- * Some harnesses were configured and some were not. This has to be its own
15
- * message: the agent relays `userMessage` verbatim, so reporting a partial run
16
- * with "Agent setup is complete" tells the user something untrue about a
17
- * machine they are about to rely on.
18
- */
19
- export const PARTIAL_CONFIGURATION_MESSAGE =
20
- 'Expand is authorized, but not every harness could be configured. The harnesses that failed are listed under `failures`; the ones under `installations` are ready to use.'
21
-
22
- export const HARNESS_SELECTION_MESSAGE =
23
- 'Show these harnesses to the user and ask which to configure. Pass the chosen ones to `expandai init --harnesses`. Harnesses that are not chosen are left untouched.'
24
-
25
- /** There is nothing to choose from, so the agent must not present an empty list. */
26
- export const NO_HARNESS_DETECTED_MESSAGE =
27
- 'No supported agent harness was found on this machine. Do not ask the user to choose from an empty list. Tell them Expand supports claude-code, cursor, opencode, and codex, and that setup cannot continue until one of them is installed.'
28
-
29
- export const InitHarness = Schema.Literal('claude-code', 'cursor', 'opencode', 'codex')
30
- export type InitHarness = typeof InitHarness.Type
31
-
32
- /**
33
- * Answer to `init --detect`: what setup *would* touch, before it touches
34
- * anything. Separate from `InitResult` because detection never authorizes,
35
- * never writes, and can legitimately find nothing.
36
- */
37
- export class InitDetectionResult extends Schema.Class<InitDetectionResult>('InitDetectionResult')({
38
- schemaVersion: Schema.Literal(1),
39
- status: Schema.Literal('detected'),
40
- harnesses: Schema.Array(InitHarness),
41
- current: Schema.optional(InitHarness),
42
- userMessage: Schema.Literal(HARNESS_SELECTION_MESSAGE, NO_HARNESS_DETECTED_MESSAGE),
43
- }) {}
44
-
45
- export const InitHarnesses = Schema.NonEmptyArray(InitHarness)
46
- export type InitHarnesses = typeof InitHarnesses.Type
47
-
48
- export const InitScope = Schema.Literal('project', 'global')
49
- export type InitScope = typeof InitScope.Type
50
-
51
- export const InitComponent = Schema.Literal('webfetch-hook', 'runtime-skill', 'mcp')
52
- export type InitComponent = typeof InitComponent.Type
53
-
54
- export const InitRuntimeState = Schema.Literal('unverified', 'observed', 'reload_required', 'blocked')
55
- export type InitRuntimeState = typeof InitRuntimeState.Type
56
-
57
- export const InitStatus = Schema.Literal('authorization_required', 'completed')
58
- export type InitStatus = typeof InitStatus.Type
59
-
60
- // A dashboard setup token is a pre-approved RFC 8628 device code minted by
61
- // better-auth: opaque, bounded, single-use.
62
- const SetupToken = Schema.String.pipe(Schema.minLength(20), Schema.maxLength(256))
63
-
64
- const SafeSetupToken = Schema.transform(SetupToken, Schema.Redacted(Schema.String), {
65
- strict: true,
66
- decode: (setupToken) => setupToken,
67
- // Long enough to satisfy the base schema on re-encode; still obviously not a token.
68
- encode: () => '<redacted-redacted-setup-token>',
69
- })
70
-
71
- export class InitRequest extends Schema.Class<InitRequest>('InitRequest')({
72
- harnesses: InitHarnesses,
73
- scope: InitScope,
74
- setupToken: Schema.optional(SafeSetupToken),
75
- }) {}
76
-
77
- const InitAuthorizationRequiredResult = Schema.Struct({
78
- schemaVersion: Schema.Literal(1),
79
- status: Schema.Literal('authorization_required'),
80
- harnesses: InitHarnesses,
81
- scope: InitScope,
82
- userMessage: Schema.Literal(AUTHORIZATION_REQUIRED_MESSAGE),
83
- authorization: Schema.Struct({
84
- url: Schema.URL,
85
- // Typed by the human into the approval page. Deliberately not embedded in
86
- // the URL: entering it is the one moment a phished user can notice the
87
- // request is not theirs.
88
- userCode: Schema.String,
89
- approvalExpiresAt: Schema.DateTimeUtc,
90
- }),
91
- })
92
-
93
- /** Whether the harness has actually loaded what we wrote, and what to do if not. */
94
- const InitVerification = Schema.Struct({
95
- runtimeState: InitRuntimeState,
96
- nextAction: Schema.String,
97
- })
98
-
99
- /** One harness that setup wrote to, and what it now reports about itself. */
100
- const InitInstallation = Schema.Struct({
101
- harness: InitHarness,
102
- configured: Schema.Boolean,
103
- changed: Schema.Boolean,
104
- components: Schema.Array(InitComponent),
105
- version: Schema.String,
106
- verification: InitVerification,
107
- })
108
-
109
- /**
110
- * A harness that was attempted and did not land. Named separately because the
111
- * agent is asked to tell the user *which* of their agents is not set up, and it
112
- * has no other way to know: `harnesses` lists what was requested and
113
- * `installations` what worked, but the difference alone says neither why nor
114
- * whether retrying helps.
115
- */
116
- const InitFailure = Schema.Struct({
117
- harness: InitHarness,
118
- code: Schema.String,
119
- recoverable: Schema.Boolean,
120
- })
121
-
122
- const InitCompletedResult = Schema.Struct({
123
- schemaVersion: Schema.Literal(1),
124
- status: Schema.Literal('completed'),
125
- harnesses: InitHarnesses,
126
- scope: InitScope,
127
- userMessage: Schema.Literal(
128
- AUTHORIZATION_CONSUMED_MESSAGE,
129
- ALREADY_AUTHENTICATED_MESSAGE,
130
- PARTIAL_CONFIGURATION_MESSAGE,
131
- ),
132
- auth: Schema.Struct({
133
- healthy: Schema.Boolean,
134
- }),
135
- // Which project `scope: 'project'` actually meant. It resolves to the working
136
- // directory, which for an agent may be anywhere — a repo, a home directory,
137
- // a temp folder — and nothing else in this result says where config landed.
138
- projectPath: Schema.optional(Schema.String),
139
- installations: Schema.NonEmptyArray(InitInstallation),
140
- // Absent when every selected harness succeeded.
141
- failures: Schema.optional(Schema.Array(InitFailure)),
142
- })
143
-
144
- export const InitResult = Schema.Union(InitAuthorizationRequiredResult, InitCompletedResult)
145
- export type InitResult = typeof InitResult.Type
146
-
147
- export class InitErrorEnvelope extends Schema.Class<InitErrorEnvelope>('InitErrorEnvelope')({
148
- schemaVersion: Schema.Literal(1),
149
- status: Schema.Literal('error'),
150
- code: Schema.String,
151
- message: Schema.String,
152
- recoverable: Schema.Boolean,
153
- }) {}
@@ -1,35 +0,0 @@
1
- import { Inspectable, Schema } from 'effect'
2
- import { type InitComponent, InitHarness, type InitRuntimeState, InitScope } from './Domain.js'
3
-
4
- export interface HarnessInspection {
5
- readonly configured: boolean
6
- readonly changed?: boolean
7
- readonly components: InitComponent[]
8
- readonly integrationVersion?: string
9
- readonly policyBlock?: string
10
- readonly nextAction: string
11
- readonly runtimeState?: InitRuntimeState
12
- }
13
-
14
- export class HarnessInspectionError extends Schema.TaggedError<HarnessInspectionError>()('HarnessInspectionError', {
15
- harness: InitHarness,
16
- scope: InitScope,
17
- error: Schema.Defect,
18
- }) {
19
- get message() {
20
- return `Failed to inspect ${this.harness} (${this.scope}): ${Inspectable.format(this.error)}`
21
- }
22
- }
23
-
24
- export class HarnessConfigurationError extends Schema.TaggedError<HarnessConfigurationError>()(
25
- 'HarnessConfigurationError',
26
- {
27
- harness: InitHarness,
28
- scope: InitScope,
29
- error: Schema.Defect,
30
- },
31
- ) {
32
- get message() {
33
- return `Failed to configure ${this.harness} (${this.scope}): ${Inspectable.format(this.error)}`
34
- }
35
- }