@fidelios/server 0.0.1

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 (743) hide show
  1. package/dist/adapters/codex-models.d.ts +4 -0
  2. package/dist/adapters/codex-models.d.ts.map +1 -0
  3. package/dist/adapters/codex-models.js +98 -0
  4. package/dist/adapters/codex-models.js.map +1 -0
  5. package/dist/adapters/cursor-models.d.ts +13 -0
  6. package/dist/adapters/cursor-models.d.ts.map +1 -0
  7. package/dist/adapters/cursor-models.js +148 -0
  8. package/dist/adapters/cursor-models.js.map +1 -0
  9. package/dist/adapters/http/execute.d.ts +3 -0
  10. package/dist/adapters/http/execute.d.ts.map +1 -0
  11. package/dist/adapters/http/execute.js +39 -0
  12. package/dist/adapters/http/execute.js.map +1 -0
  13. package/dist/adapters/http/index.d.ts +3 -0
  14. package/dist/adapters/http/index.d.ts.map +1 -0
  15. package/dist/adapters/http/index.js +20 -0
  16. package/dist/adapters/http/index.js.map +1 -0
  17. package/dist/adapters/http/test.d.ts +3 -0
  18. package/dist/adapters/http/test.d.ts.map +1 -0
  19. package/dist/adapters/http/test.js +106 -0
  20. package/dist/adapters/http/test.js.map +1 -0
  21. package/dist/adapters/index.d.ts +4 -0
  22. package/dist/adapters/index.d.ts.map +1 -0
  23. package/dist/adapters/index.js +3 -0
  24. package/dist/adapters/index.js.map +1 -0
  25. package/dist/adapters/process/execute.d.ts +3 -0
  26. package/dist/adapters/process/execute.d.ts.map +1 -0
  27. package/dist/adapters/process/execute.js +63 -0
  28. package/dist/adapters/process/execute.js.map +1 -0
  29. package/dist/adapters/process/index.d.ts +3 -0
  30. package/dist/adapters/process/index.d.ts.map +1 -0
  31. package/dist/adapters/process/index.js +23 -0
  32. package/dist/adapters/process/index.js.map +1 -0
  33. package/dist/adapters/process/test.d.ts +3 -0
  34. package/dist/adapters/process/test.d.ts.map +1 -0
  35. package/dist/adapters/process/test.js +77 -0
  36. package/dist/adapters/process/test.js.map +1 -0
  37. package/dist/adapters/registry.d.ts +14 -0
  38. package/dist/adapters/registry.d.ts.map +1 -0
  39. package/dist/adapters/registry.js +164 -0
  40. package/dist/adapters/registry.js.map +1 -0
  41. package/dist/adapters/types.d.ts +2 -0
  42. package/dist/adapters/types.d.ts.map +1 -0
  43. package/dist/adapters/types.js +2 -0
  44. package/dist/adapters/types.js.map +1 -0
  45. package/dist/adapters/utils.d.ts +10 -0
  46. package/dist/adapters/utils.d.ts.map +1 -0
  47. package/dist/adapters/utils.js +14 -0
  48. package/dist/adapters/utils.js.map +1 -0
  49. package/dist/agent-auth-jwt.d.ts +14 -0
  50. package/dist/agent-auth-jwt.d.ts.map +1 -0
  51. package/dist/agent-auth-jwt.js +117 -0
  52. package/dist/agent-auth-jwt.js.map +1 -0
  53. package/dist/app.d.ts +25 -0
  54. package/dist/app.d.ts.map +1 -0
  55. package/dist/app.js +265 -0
  56. package/dist/app.js.map +1 -0
  57. package/dist/attachment-types.d.ts +33 -0
  58. package/dist/attachment-types.d.ts.map +1 -0
  59. package/dist/attachment-types.js +67 -0
  60. package/dist/attachment-types.js.map +1 -0
  61. package/dist/auth/better-auth.d.ts +24 -0
  62. package/dist/auth/better-auth.d.ts.map +1 -0
  63. package/dist/auth/better-auth.js +108 -0
  64. package/dist/auth/better-auth.js.map +1 -0
  65. package/dist/board-claim.d.ts +23 -0
  66. package/dist/board-claim.d.ts.map +1 -0
  67. package/dist/board-claim.js +115 -0
  68. package/dist/board-claim.js.map +1 -0
  69. package/dist/config-file.d.ts +3 -0
  70. package/dist/config-file.d.ts.map +1 -0
  71. package/dist/config-file.js +16 -0
  72. package/dist/config-file.js.map +1 -0
  73. package/dist/config.d.ts +45 -0
  74. package/dist/config.d.ts.map +1 -0
  75. package/dist/config.js +171 -0
  76. package/dist/config.js.map +1 -0
  77. package/dist/dev-server-status.d.ts +27 -0
  78. package/dist/dev-server-status.d.ts.map +1 -0
  79. package/dist/dev-server-status.js +70 -0
  80. package/dist/dev-server-status.js.map +1 -0
  81. package/dist/dev-watch-ignore.d.ts +2 -0
  82. package/dist/dev-watch-ignore.d.ts.map +1 -0
  83. package/dist/dev-watch-ignore.js +33 -0
  84. package/dist/dev-watch-ignore.js.map +1 -0
  85. package/dist/errors.d.ts +12 -0
  86. package/dist/errors.d.ts.map +1 -0
  87. package/dist/errors.js +28 -0
  88. package/dist/errors.js.map +1 -0
  89. package/dist/home-paths.d.ts +17 -0
  90. package/dist/home-paths.d.ts.map +1 -0
  91. package/dist/home-paths.js +75 -0
  92. package/dist/home-paths.js.map +1 -0
  93. package/dist/index.d.ts +10 -0
  94. package/dist/index.d.ts.map +1 -0
  95. package/dist/index.js +642 -0
  96. package/dist/index.js.map +1 -0
  97. package/dist/log-redaction.d.ts +11 -0
  98. package/dist/log-redaction.d.ts.map +1 -0
  99. package/dist/log-redaction.js +118 -0
  100. package/dist/log-redaction.js.map +1 -0
  101. package/dist/middleware/auth.d.ts +12 -0
  102. package/dist/middleware/auth.d.ts.map +1 -0
  103. package/dist/middleware/auth.js +144 -0
  104. package/dist/middleware/auth.js.map +1 -0
  105. package/dist/middleware/board-mutation-guard.d.ts +3 -0
  106. package/dist/middleware/board-mutation-guard.d.ts.map +1 -0
  107. package/dist/middleware/board-mutation-guard.js +59 -0
  108. package/dist/middleware/board-mutation-guard.js.map +1 -0
  109. package/dist/middleware/error-handler.d.ts +17 -0
  110. package/dist/middleware/error-handler.d.ts.map +1 -0
  111. package/dist/middleware/error-handler.js +37 -0
  112. package/dist/middleware/error-handler.js.map +1 -0
  113. package/dist/middleware/index.d.ts +4 -0
  114. package/dist/middleware/index.d.ts.map +1 -0
  115. package/dist/middleware/index.js +4 -0
  116. package/dist/middleware/index.js.map +1 -0
  117. package/dist/middleware/logger.d.ts +4 -0
  118. package/dist/middleware/logger.d.ts.map +1 -0
  119. package/dist/middleware/logger.js +87 -0
  120. package/dist/middleware/logger.js.map +1 -0
  121. package/dist/middleware/private-hostname-guard.d.ts +11 -0
  122. package/dist/middleware/private-hostname-guard.d.ts.map +1 -0
  123. package/dist/middleware/private-hostname-guard.js +78 -0
  124. package/dist/middleware/private-hostname-guard.js.map +1 -0
  125. package/dist/middleware/validate.d.ts +4 -0
  126. package/dist/middleware/validate.d.ts.map +1 -0
  127. package/dist/middleware/validate.js +7 -0
  128. package/dist/middleware/validate.js.map +1 -0
  129. package/dist/onboarding-assets/ceo/AGENTS.md +54 -0
  130. package/dist/onboarding-assets/ceo/HEARTBEAT.md +72 -0
  131. package/dist/onboarding-assets/ceo/SOUL.md +33 -0
  132. package/dist/onboarding-assets/ceo/TOOLS.md +3 -0
  133. package/dist/onboarding-assets/default/AGENTS.md +3 -0
  134. package/dist/paths.d.ts +3 -0
  135. package/dist/paths.d.ts.map +1 -0
  136. package/dist/paths.js +31 -0
  137. package/dist/paths.js.map +1 -0
  138. package/dist/realtime/live-events-ws.d.ts +28 -0
  139. package/dist/realtime/live-events-ws.d.ts.map +1 -0
  140. package/dist/realtime/live-events-ws.js +187 -0
  141. package/dist/realtime/live-events-ws.js.map +1 -0
  142. package/dist/redaction.d.ts +4 -0
  143. package/dist/redaction.d.ts.map +1 -0
  144. package/dist/redaction.js +63 -0
  145. package/dist/redaction.js.map +1 -0
  146. package/dist/routes/access.d.ts +61 -0
  147. package/dist/routes/access.d.ts.map +1 -0
  148. package/dist/routes/access.js +2265 -0
  149. package/dist/routes/access.js.map +1 -0
  150. package/dist/routes/activity.d.ts +3 -0
  151. package/dist/routes/activity.d.ts.map +1 -0
  152. package/dist/routes/activity.js +78 -0
  153. package/dist/routes/activity.js.map +1 -0
  154. package/dist/routes/agents.d.ts +3 -0
  155. package/dist/routes/agents.d.ts.map +1 -0
  156. package/dist/routes/agents.js +1828 -0
  157. package/dist/routes/agents.js.map +1 -0
  158. package/dist/routes/approvals.d.ts +3 -0
  159. package/dist/routes/approvals.d.ts.map +1 -0
  160. package/dist/routes/approvals.js +275 -0
  161. package/dist/routes/approvals.js.map +1 -0
  162. package/dist/routes/assets.d.ts +4 -0
  163. package/dist/routes/assets.d.ts.map +1 -0
  164. package/dist/routes/assets.js +309 -0
  165. package/dist/routes/assets.js.map +1 -0
  166. package/dist/routes/authz.d.ts +16 -0
  167. package/dist/routes/authz.d.ts.map +1 -0
  168. package/dist/routes/authz.js +47 -0
  169. package/dist/routes/authz.js.map +1 -0
  170. package/dist/routes/companies.d.ts +4 -0
  171. package/dist/routes/companies.d.ts.map +1 -0
  172. package/dist/routes/companies.js +303 -0
  173. package/dist/routes/companies.js.map +1 -0
  174. package/dist/routes/company-skills.d.ts +3 -0
  175. package/dist/routes/company-skills.d.ts.map +1 -0
  176. package/dist/routes/company-skills.js +228 -0
  177. package/dist/routes/company-skills.js.map +1 -0
  178. package/dist/routes/costs.d.ts +3 -0
  179. package/dist/routes/costs.d.ts.map +1 -0
  180. package/dist/routes/costs.js +268 -0
  181. package/dist/routes/costs.js.map +1 -0
  182. package/dist/routes/dashboard.d.ts +3 -0
  183. package/dist/routes/dashboard.d.ts.map +1 -0
  184. package/dist/routes/dashboard.js +15 -0
  185. package/dist/routes/dashboard.js.map +1 -0
  186. package/dist/routes/execution-workspaces.d.ts +3 -0
  187. package/dist/routes/execution-workspaces.d.ts.map +1 -0
  188. package/dist/routes/execution-workspaces.js +165 -0
  189. package/dist/routes/execution-workspaces.js.map +1 -0
  190. package/dist/routes/goals.d.ts +3 -0
  191. package/dist/routes/goals.d.ts.map +1 -0
  192. package/dist/routes/goals.js +95 -0
  193. package/dist/routes/goals.js.map +1 -0
  194. package/dist/routes/health.d.ts +9 -0
  195. package/dist/routes/health.d.ts.map +1 -0
  196. package/dist/routes/health.js +69 -0
  197. package/dist/routes/health.js.map +1 -0
  198. package/dist/routes/index.d.ts +18 -0
  199. package/dist/routes/index.d.ts.map +1 -0
  200. package/dist/routes/index.js +18 -0
  201. package/dist/routes/index.js.map +1 -0
  202. package/dist/routes/instance-settings.d.ts +3 -0
  203. package/dist/routes/instance-settings.d.ts.map +1 -0
  204. package/dist/routes/instance-settings.js +71 -0
  205. package/dist/routes/instance-settings.js.map +1 -0
  206. package/dist/routes/issues-checkout-wakeup.d.ts +9 -0
  207. package/dist/routes/issues-checkout-wakeup.d.ts.map +1 -0
  208. package/dist/routes/issues-checkout-wakeup.js +12 -0
  209. package/dist/routes/issues-checkout-wakeup.js.map +1 -0
  210. package/dist/routes/issues.d.ts +4 -0
  211. package/dist/routes/issues.d.ts.map +1 -0
  212. package/dist/routes/issues.js +1520 -0
  213. package/dist/routes/issues.js.map +1 -0
  214. package/dist/routes/llms.d.ts +3 -0
  215. package/dist/routes/llms.d.ts.map +1 -0
  216. package/dist/routes/llms.js +78 -0
  217. package/dist/routes/llms.js.map +1 -0
  218. package/dist/routes/org-chart-svg.d.ts +25 -0
  219. package/dist/routes/org-chart-svg.d.ts.map +1 -0
  220. package/dist/routes/org-chart-svg.js +656 -0
  221. package/dist/routes/org-chart-svg.js.map +1 -0
  222. package/dist/routes/plugin-ui-static.d.ts +69 -0
  223. package/dist/routes/plugin-ui-static.d.ts.map +1 -0
  224. package/dist/routes/plugin-ui-static.js +411 -0
  225. package/dist/routes/plugin-ui-static.js.map +1 -0
  226. package/dist/routes/plugins.d.ts +120 -0
  227. package/dist/routes/plugins.d.ts.map +1 -0
  228. package/dist/routes/plugins.js +1784 -0
  229. package/dist/routes/plugins.js.map +1 -0
  230. package/dist/routes/projects.d.ts +3 -0
  231. package/dist/routes/projects.d.ts.map +1 -0
  232. package/dist/routes/projects.js +257 -0
  233. package/dist/routes/projects.js.map +1 -0
  234. package/dist/routes/routines.d.ts +3 -0
  235. package/dist/routes/routines.d.ts.map +1 -0
  236. package/dist/routes/routines.js +277 -0
  237. package/dist/routes/routines.js.map +1 -0
  238. package/dist/routes/secrets.d.ts +3 -0
  239. package/dist/routes/secrets.d.ts.map +1 -0
  240. package/dist/routes/secrets.js +128 -0
  241. package/dist/routes/secrets.js.map +1 -0
  242. package/dist/routes/sidebar-badges.d.ts +3 -0
  243. package/dist/routes/sidebar-badges.d.ts.map +1 -0
  244. package/dist/routes/sidebar-badges.js +45 -0
  245. package/dist/routes/sidebar-badges.js.map +1 -0
  246. package/dist/secrets/external-stub-providers.d.ts +5 -0
  247. package/dist/secrets/external-stub-providers.d.ts.map +1 -0
  248. package/dist/secrets/external-stub-providers.js +21 -0
  249. package/dist/secrets/external-stub-providers.js.map +1 -0
  250. package/dist/secrets/local-encrypted-provider.d.ts +3 -0
  251. package/dist/secrets/local-encrypted-provider.d.ts.map +1 -0
  252. package/dist/secrets/local-encrypted-provider.js +116 -0
  253. package/dist/secrets/local-encrypted-provider.js.map +1 -0
  254. package/dist/secrets/provider-registry.d.ts +5 -0
  255. package/dist/secrets/provider-registry.d.ts.map +1 -0
  256. package/dist/secrets/provider-registry.js +20 -0
  257. package/dist/secrets/provider-registry.js.map +1 -0
  258. package/dist/secrets/types.d.ts +21 -0
  259. package/dist/secrets/types.d.ts.map +1 -0
  260. package/dist/secrets/types.js +2 -0
  261. package/dist/secrets/types.js.map +1 -0
  262. package/dist/services/access.d.ts +113 -0
  263. package/dist/services/access.d.ts.map +1 -0
  264. package/dist/services/access.js +247 -0
  265. package/dist/services/access.js.map +1 -0
  266. package/dist/services/activity-log.d.ts +17 -0
  267. package/dist/services/activity-log.d.ts.map +1 -0
  268. package/dist/services/activity-log.js +74 -0
  269. package/dist/services/activity-log.js.map +1 -0
  270. package/dist/services/activity.d.ts +764 -0
  271. package/dist/services/activity.d.ts.map +1 -0
  272. package/dist/services/activity.js +105 -0
  273. package/dist/services/activity.js.map +1 -0
  274. package/dist/services/agent-instructions.d.ts +91 -0
  275. package/dist/services/agent-instructions.d.ts.map +1 -0
  276. package/dist/services/agent-instructions.js +580 -0
  277. package/dist/services/agent-instructions.js.map +1 -0
  278. package/dist/services/agent-permissions.d.ts +6 -0
  279. package/dist/services/agent-permissions.d.ts.map +1 -0
  280. package/dist/services/agent-permissions.js +18 -0
  281. package/dist/services/agent-permissions.js.map +1 -0
  282. package/dist/services/agents.d.ts +1670 -0
  283. package/dist/services/agents.d.ts.map +1 -0
  284. package/dist/services/agents.js +566 -0
  285. package/dist/services/agents.js.map +1 -0
  286. package/dist/services/approvals.d.ts +546 -0
  287. package/dist/services/approvals.d.ts.map +1 -0
  288. package/dist/services/approvals.js +212 -0
  289. package/dist/services/approvals.js.map +1 -0
  290. package/dist/services/assets.d.ts +33 -0
  291. package/dist/services/assets.d.ts.map +1 -0
  292. package/dist/services/assets.js +17 -0
  293. package/dist/services/assets.js.map +1 -0
  294. package/dist/services/board-auth.d.ts +234 -0
  295. package/dist/services/board-auth.d.ts.map +1 -0
  296. package/dist/services/board-auth.js +295 -0
  297. package/dist/services/board-auth.js.map +1 -0
  298. package/dist/services/budgets.d.ts +38 -0
  299. package/dist/services/budgets.d.ts.map +1 -0
  300. package/dist/services/budgets.js +784 -0
  301. package/dist/services/budgets.js.map +1 -0
  302. package/dist/services/companies.d.ts +124 -0
  303. package/dist/services/companies.d.ts.map +1 -0
  304. package/dist/services/companies.js +256 -0
  305. package/dist/services/companies.js.map +1 -0
  306. package/dist/services/company-export-readme.d.ts +17 -0
  307. package/dist/services/company-export-readme.d.ts.map +1 -0
  308. package/dist/services/company-export-readme.js +148 -0
  309. package/dist/services/company-export-readme.js.map +1 -0
  310. package/dist/services/company-portability.d.ts +23 -0
  311. package/dist/services/company-portability.d.ts.map +1 -0
  312. package/dist/services/company-portability.js +3739 -0
  313. package/dist/services/company-portability.js.map +1 -0
  314. package/dist/services/company-skills.d.ts +77 -0
  315. package/dist/services/company-skills.d.ts.map +1 -0
  316. package/dist/services/company-skills.js +2042 -0
  317. package/dist/services/company-skills.js.map +1 -0
  318. package/dist/services/costs.d.ts +114 -0
  319. package/dist/services/costs.d.ts.map +1 -0
  320. package/dist/services/costs.js +294 -0
  321. package/dist/services/costs.js.map +1 -0
  322. package/dist/services/cron.d.ts +80 -0
  323. package/dist/services/cron.d.ts.map +1 -0
  324. package/dist/services/cron.js +300 -0
  325. package/dist/services/cron.js.map +1 -0
  326. package/dist/services/dashboard.d.ts +26 -0
  327. package/dist/services/dashboard.d.ts.map +1 -0
  328. package/dist/services/dashboard.js +98 -0
  329. package/dist/services/dashboard.js.map +1 -0
  330. package/dist/services/default-agent-instructions.d.ts +9 -0
  331. package/dist/services/default-agent-instructions.d.ts.map +1 -0
  332. package/dist/services/default-agent-instructions.js +20 -0
  333. package/dist/services/default-agent-instructions.js.map +1 -0
  334. package/dist/services/documents.d.ts +164 -0
  335. package/dist/services/documents.d.ts.map +1 -0
  336. package/dist/services/documents.js +382 -0
  337. package/dist/services/documents.js.map +1 -0
  338. package/dist/services/execution-workspace-policy.d.ts +21 -0
  339. package/dist/services/execution-workspace-policy.d.ts.map +1 -0
  340. package/dist/services/execution-workspace-policy.js +177 -0
  341. package/dist/services/execution-workspace-policy.js.map +1 -0
  342. package/dist/services/execution-workspaces.d.ts +19 -0
  343. package/dist/services/execution-workspaces.d.ts.map +1 -0
  344. package/dist/services/execution-workspaces.js +87 -0
  345. package/dist/services/execution-workspaces.js.map +1 -0
  346. package/dist/services/finance.d.ts +93 -0
  347. package/dist/services/finance.d.ts.map +1 -0
  348. package/dist/services/finance.js +120 -0
  349. package/dist/services/finance.js.map +1 -0
  350. package/dist/services/goals.d.ts +433 -0
  351. package/dist/services/goals.d.ts.map +1 -0
  352. package/dist/services/goals.js +54 -0
  353. package/dist/services/goals.js.map +1 -0
  354. package/dist/services/heartbeat-run-summary.d.ts +2 -0
  355. package/dist/services/heartbeat-run-summary.d.ts.map +1 -0
  356. package/dist/services/heartbeat-run-summary.js +30 -0
  357. package/dist/services/heartbeat-run-summary.js.map +1 -0
  358. package/dist/services/heartbeat.d.ts +812 -0
  359. package/dist/services/heartbeat.d.ts.map +1 -0
  360. package/dist/services/heartbeat.js +3156 -0
  361. package/dist/services/heartbeat.js.map +1 -0
  362. package/dist/services/hire-hook.d.ts +14 -0
  363. package/dist/services/hire-hook.d.ts.map +1 -0
  364. package/dist/services/hire-hook.js +85 -0
  365. package/dist/services/hire-hook.js.map +1 -0
  366. package/dist/services/index.d.ts +33 -0
  367. package/dist/services/index.d.ts.map +1 -0
  368. package/dist/services/index.js +33 -0
  369. package/dist/services/index.js.map +1 -0
  370. package/dist/services/instance-settings.d.ts +11 -0
  371. package/dist/services/instance-settings.d.ts.map +1 -0
  372. package/dist/services/instance-settings.js +116 -0
  373. package/dist/services/instance-settings.js.map +1 -0
  374. package/dist/services/issue-approvals.d.ts +56 -0
  375. package/dist/services/issue-approvals.d.ts.map +1 -0
  376. package/dist/services/issue-approvals.js +153 -0
  377. package/dist/services/issue-approvals.js.map +1 -0
  378. package/dist/services/issue-assignment-wakeup.d.ts +29 -0
  379. package/dist/services/issue-assignment-wakeup.d.ts.map +1 -0
  380. package/dist/services/issue-assignment-wakeup.js +22 -0
  381. package/dist/services/issue-assignment-wakeup.js.map +1 -0
  382. package/dist/services/issue-goal-fallback.d.ts +18 -0
  383. package/dist/services/issue-goal-fallback.d.ts.map +1 -0
  384. package/dist/services/issue-goal-fallback.js +33 -0
  385. package/dist/services/issue-goal-fallback.js.map +1 -0
  386. package/dist/services/issues.d.ts +560 -0
  387. package/dist/services/issues.d.ts.map +1 -0
  388. package/dist/services/issues.js +1478 -0
  389. package/dist/services/issues.js.map +1 -0
  390. package/dist/services/live-events.d.ts +17 -0
  391. package/dist/services/live-events.d.ts.map +1 -0
  392. package/dist/services/live-events.js +33 -0
  393. package/dist/services/live-events.js.map +1 -0
  394. package/dist/services/plugin-capability-validator.d.ts +108 -0
  395. package/dist/services/plugin-capability-validator.d.ts.map +1 -0
  396. package/dist/services/plugin-capability-validator.js +268 -0
  397. package/dist/services/plugin-capability-validator.js.map +1 -0
  398. package/dist/services/plugin-config-validator.d.ts +26 -0
  399. package/dist/services/plugin-config-validator.d.ts.map +1 -0
  400. package/dist/services/plugin-config-validator.js +41 -0
  401. package/dist/services/plugin-config-validator.js.map +1 -0
  402. package/dist/services/plugin-dev-watcher.d.ts +30 -0
  403. package/dist/services/plugin-dev-watcher.d.ts.map +1 -0
  404. package/dist/services/plugin-dev-watcher.js +241 -0
  405. package/dist/services/plugin-dev-watcher.js.map +1 -0
  406. package/dist/services/plugin-event-bus.d.ts +149 -0
  407. package/dist/services/plugin-event-bus.d.ts.map +1 -0
  408. package/dist/services/plugin-event-bus.js +258 -0
  409. package/dist/services/plugin-event-bus.js.map +1 -0
  410. package/dist/services/plugin-host-service-cleanup.d.ts +14 -0
  411. package/dist/services/plugin-host-service-cleanup.d.ts.map +1 -0
  412. package/dist/services/plugin-host-service-cleanup.js +37 -0
  413. package/dist/services/plugin-host-service-cleanup.js.map +1 -0
  414. package/dist/services/plugin-host-services.d.ts +13 -0
  415. package/dist/services/plugin-host-services.d.ts.map +1 -0
  416. package/dist/services/plugin-host-services.js +969 -0
  417. package/dist/services/plugin-host-services.js.map +1 -0
  418. package/dist/services/plugin-job-coordinator.d.ts +81 -0
  419. package/dist/services/plugin-job-coordinator.d.ts.map +1 -0
  420. package/dist/services/plugin-job-coordinator.js +172 -0
  421. package/dist/services/plugin-job-coordinator.js.map +1 -0
  422. package/dist/services/plugin-job-scheduler.d.ts +163 -0
  423. package/dist/services/plugin-job-scheduler.d.ts.map +1 -0
  424. package/dist/services/plugin-job-scheduler.js +454 -0
  425. package/dist/services/plugin-job-scheduler.js.map +1 -0
  426. package/dist/services/plugin-job-store.d.ts +208 -0
  427. package/dist/services/plugin-job-store.d.ts.map +1 -0
  428. package/dist/services/plugin-job-store.js +350 -0
  429. package/dist/services/plugin-job-store.js.map +1 -0
  430. package/dist/services/plugin-lifecycle.d.ts +203 -0
  431. package/dist/services/plugin-lifecycle.d.ts.map +1 -0
  432. package/dist/services/plugin-lifecycle.js +476 -0
  433. package/dist/services/plugin-lifecycle.js.map +1 -0
  434. package/dist/services/plugin-loader.d.ts +441 -0
  435. package/dist/services/plugin-loader.d.ts.map +1 -0
  436. package/dist/services/plugin-loader.js +1192 -0
  437. package/dist/services/plugin-loader.js.map +1 -0
  438. package/dist/services/plugin-log-retention.d.ts +20 -0
  439. package/dist/services/plugin-log-retention.d.ts.map +1 -0
  440. package/dist/services/plugin-log-retention.js +63 -0
  441. package/dist/services/plugin-log-retention.js.map +1 -0
  442. package/dist/services/plugin-manifest-validator.d.ts +79 -0
  443. package/dist/services/plugin-manifest-validator.d.ts.map +1 -0
  444. package/dist/services/plugin-manifest-validator.js +84 -0
  445. package/dist/services/plugin-manifest-validator.js.map +1 -0
  446. package/dist/services/plugin-registry.d.ts +2542 -0
  447. package/dist/services/plugin-registry.d.ts.map +1 -0
  448. package/dist/services/plugin-registry.js +539 -0
  449. package/dist/services/plugin-registry.js.map +1 -0
  450. package/dist/services/plugin-runtime-sandbox.d.ts +40 -0
  451. package/dist/services/plugin-runtime-sandbox.d.ts.map +1 -0
  452. package/dist/services/plugin-runtime-sandbox.js +154 -0
  453. package/dist/services/plugin-runtime-sandbox.js.map +1 -0
  454. package/dist/services/plugin-secrets-handler.d.ts +81 -0
  455. package/dist/services/plugin-secrets-handler.d.ts.map +1 -0
  456. package/dist/services/plugin-secrets-handler.js +275 -0
  457. package/dist/services/plugin-secrets-handler.js.map +1 -0
  458. package/dist/services/plugin-state-store.d.ts +92 -0
  459. package/dist/services/plugin-state-store.d.ts.map +1 -0
  460. package/dist/services/plugin-state-store.js +190 -0
  461. package/dist/services/plugin-state-store.js.map +1 -0
  462. package/dist/services/plugin-stream-bus.d.ts +29 -0
  463. package/dist/services/plugin-stream-bus.d.ts.map +1 -0
  464. package/dist/services/plugin-stream-bus.js +48 -0
  465. package/dist/services/plugin-stream-bus.js.map +1 -0
  466. package/dist/services/plugin-tool-dispatcher.d.ts +180 -0
  467. package/dist/services/plugin-tool-dispatcher.d.ts.map +1 -0
  468. package/dist/services/plugin-tool-dispatcher.js +224 -0
  469. package/dist/services/plugin-tool-dispatcher.js.map +1 -0
  470. package/dist/services/plugin-tool-registry.d.ts +192 -0
  471. package/dist/services/plugin-tool-registry.d.ts.map +1 -0
  472. package/dist/services/plugin-tool-registry.js +224 -0
  473. package/dist/services/plugin-tool-registry.js.map +1 -0
  474. package/dist/services/plugin-worker-manager.d.ts +260 -0
  475. package/dist/services/plugin-worker-manager.d.ts.map +1 -0
  476. package/dist/services/plugin-worker-manager.js +835 -0
  477. package/dist/services/plugin-worker-manager.js.map +1 -0
  478. package/dist/services/projects.d.ts +87 -0
  479. package/dist/services/projects.d.ts.map +1 -0
  480. package/dist/services/projects.js +656 -0
  481. package/dist/services/projects.js.map +1 -0
  482. package/dist/services/quota-windows.d.ts +9 -0
  483. package/dist/services/quota-windows.d.ts.map +1 -0
  484. package/dist/services/quota-windows.js +56 -0
  485. package/dist/services/quota-windows.js.map +1 -0
  486. package/dist/services/routines.d.ts +135 -0
  487. package/dist/services/routines.d.ts.map +1 -0
  488. package/dist/services/routines.js +1105 -0
  489. package/dist/services/routines.js.map +1 -0
  490. package/dist/services/run-log-store.d.ts +34 -0
  491. package/dist/services/run-log-store.d.ts.map +1 -0
  492. package/dist/services/run-log-store.js +109 -0
  493. package/dist/services/run-log-store.js.map +1 -0
  494. package/dist/services/secrets.d.ts +511 -0
  495. package/dist/services/secrets.d.ts.map +1 -0
  496. package/dist/services/secrets.js +289 -0
  497. package/dist/services/secrets.js.map +1 -0
  498. package/dist/services/sidebar-badges.d.ts +9 -0
  499. package/dist/services/sidebar-badges.d.ts.map +1 -0
  500. package/dist/services/sidebar-badges.js +33 -0
  501. package/dist/services/sidebar-badges.js.map +1 -0
  502. package/dist/services/work-products.d.ts +14 -0
  503. package/dist/services/work-products.d.ts.map +1 -0
  504. package/dist/services/work-products.js +100 -0
  505. package/dist/services/work-products.js.map +1 -0
  506. package/dist/services/workspace-operation-log-store.d.ts +33 -0
  507. package/dist/services/workspace-operation-log-store.d.ts.map +1 -0
  508. package/dist/services/workspace-operation-log-store.js +110 -0
  509. package/dist/services/workspace-operation-log-store.js.map +1 -0
  510. package/dist/services/workspace-operations.d.ts +44 -0
  511. package/dist/services/workspace-operations.d.ts.map +1 -0
  512. package/dist/services/workspace-operations.js +211 -0
  513. package/dist/services/workspace-operations.js.map +1 -0
  514. package/dist/services/workspace-runtime.d.ts +164 -0
  515. package/dist/services/workspace-runtime.d.ts.map +1 -0
  516. package/dist/services/workspace-runtime.js +1235 -0
  517. package/dist/services/workspace-runtime.js.map +1 -0
  518. package/dist/startup-banner.d.ts +31 -0
  519. package/dist/startup-banner.d.ts.map +1 -0
  520. package/dist/startup-banner.js +117 -0
  521. package/dist/startup-banner.js.map +1 -0
  522. package/dist/storage/index.d.ts +6 -0
  523. package/dist/storage/index.d.ts.map +1 -0
  524. package/dist/storage/index.js +29 -0
  525. package/dist/storage/index.js.map +1 -0
  526. package/dist/storage/local-disk-provider.d.ts +3 -0
  527. package/dist/storage/local-disk-provider.d.ts.map +1 -0
  528. package/dist/storage/local-disk-provider.js +79 -0
  529. package/dist/storage/local-disk-provider.js.map +1 -0
  530. package/dist/storage/provider-registry.d.ts +4 -0
  531. package/dist/storage/provider-registry.d.ts.map +1 -0
  532. package/dist/storage/provider-registry.js +15 -0
  533. package/dist/storage/provider-registry.js.map +1 -0
  534. package/dist/storage/s3-provider.d.ts +11 -0
  535. package/dist/storage/s3-provider.d.ts.map +1 -0
  536. package/dist/storage/s3-provider.js +123 -0
  537. package/dist/storage/s3-provider.js.map +1 -0
  538. package/dist/storage/service.d.ts +3 -0
  539. package/dist/storage/service.d.ts.map +1 -0
  540. package/dist/storage/service.js +120 -0
  541. package/dist/storage/service.js.map +1 -0
  542. package/dist/storage/types.d.ts +55 -0
  543. package/dist/storage/types.d.ts.map +1 -0
  544. package/dist/storage/types.js +2 -0
  545. package/dist/storage/types.js.map +1 -0
  546. package/dist/ui-branding.d.ts +13 -0
  547. package/dist/ui-branding.d.ts.map +1 -0
  548. package/dist/ui-branding.js +187 -0
  549. package/dist/ui-branding.js.map +1 -0
  550. package/dist/version.d.ts +2 -0
  551. package/dist/version.d.ts.map +1 -0
  552. package/dist/version.js +5 -0
  553. package/dist/version.js.map +1 -0
  554. package/dist/worktree-config.d.ts +19 -0
  555. package/dist/worktree-config.d.ts.map +1 -0
  556. package/dist/worktree-config.js +365 -0
  557. package/dist/worktree-config.js.map +1 -0
  558. package/package.json +95 -0
  559. package/ui-dist/android-chrome-192x192.png +0 -0
  560. package/ui-dist/android-chrome-512x512.png +0 -0
  561. package/ui-dist/apple-touch-icon.png +0 -0
  562. package/ui-dist/assets/_basePickBy-BB1S19s0.js +1 -0
  563. package/ui-dist/assets/_baseUniq-BNk0p-bq.js +1 -0
  564. package/ui-dist/assets/apl-B4CMkyY2.js +1 -0
  565. package/ui-dist/assets/arc-Ds13x1NW.js +1 -0
  566. package/ui-dist/assets/architectureDiagram-VXUJARFQ-D8Br-_jt.js +36 -0
  567. package/ui-dist/assets/asciiarmor-Df11BRmG.js +1 -0
  568. package/ui-dist/assets/asn1-EdZsLKOL.js +1 -0
  569. package/ui-dist/assets/asterisk-B-8jnY81.js +1 -0
  570. package/ui-dist/assets/blockDiagram-VD42YOAC-CCYsAhQ5.js +122 -0
  571. package/ui-dist/assets/brainfuck-C4LP7Hcl.js +1 -0
  572. package/ui-dist/assets/c4Diagram-YG6GDRKO-CsrnTJYB.js +10 -0
  573. package/ui-dist/assets/channel-Df4ReTUQ.js +1 -0
  574. package/ui-dist/assets/chunk-4BX2VUAB-s-S3bm2a.js +1 -0
  575. package/ui-dist/assets/chunk-55IACEB6-AlPeSG3C.js +1 -0
  576. package/ui-dist/assets/chunk-B4BG7PRW-Dlv3zmp0.js +165 -0
  577. package/ui-dist/assets/chunk-DI55MBZ5-y3Hfc2F6.js +220 -0
  578. package/ui-dist/assets/chunk-FMBD7UC4-ZbmFZ8uD.js +15 -0
  579. package/ui-dist/assets/chunk-QN33PNHL-g7XrAaL5.js +1 -0
  580. package/ui-dist/assets/chunk-QZHKN3VN-DQz2X_ZR.js +1 -0
  581. package/ui-dist/assets/chunk-TZMSLE5B-NRbDhryd.js +1 -0
  582. package/ui-dist/assets/classDiagram-2ON5EDUG-CdLb01dH.js +1 -0
  583. package/ui-dist/assets/classDiagram-v2-WZHVMYZB-CdLb01dH.js +1 -0
  584. package/ui-dist/assets/clike-B9uivgTg.js +1 -0
  585. package/ui-dist/assets/clojure-BMjYHr_A.js +1 -0
  586. package/ui-dist/assets/clone-ycTwxHSX.js +1 -0
  587. package/ui-dist/assets/cmake-BQqOBYOt.js +1 -0
  588. package/ui-dist/assets/cobol-CWcv1MsR.js +1 -0
  589. package/ui-dist/assets/coffeescript-S37ZYGWr.js +1 -0
  590. package/ui-dist/assets/commonlisp-DBKNyK5s.js +1 -0
  591. package/ui-dist/assets/cose-bilkent-S5V4N54A-CifA3UGC.js +1 -0
  592. package/ui-dist/assets/crystal-SjHAIU92.js +1 -0
  593. package/ui-dist/assets/css-BnMrqG3P.js +1 -0
  594. package/ui-dist/assets/cypher-C_CwsFkJ.js +1 -0
  595. package/ui-dist/assets/cytoscape.esm-BQaXIfA_.js +331 -0
  596. package/ui-dist/assets/d-pRatUO7H.js +1 -0
  597. package/ui-dist/assets/dagre-6UL2VRFP-Cy4_402x.js +4 -0
  598. package/ui-dist/assets/defaultLocale-DX6XiGOO.js +1 -0
  599. package/ui-dist/assets/diagram-PSM6KHXK-CUA-Vqxe.js +24 -0
  600. package/ui-dist/assets/diagram-QEK2KX5R-D763Ackt.js +43 -0
  601. package/ui-dist/assets/diagram-S2PKOQOG-Cu1xEKHt.js +24 -0
  602. package/ui-dist/assets/diff-DbItnlRl.js +1 -0
  603. package/ui-dist/assets/dockerfile-BKs6k2Af.js +1 -0
  604. package/ui-dist/assets/dtd-DF_7sFjM.js +1 -0
  605. package/ui-dist/assets/dylan-DwRh75JA.js +1 -0
  606. package/ui-dist/assets/ebnf-CDyGwa7X.js +1 -0
  607. package/ui-dist/assets/ecl-Cabwm37j.js +1 -0
  608. package/ui-dist/assets/eiffel-CnydiIhH.js +1 -0
  609. package/ui-dist/assets/elm-vLlmbW-K.js +1 -0
  610. package/ui-dist/assets/erDiagram-Q2GNP2WA-9RlN9oCi.js +60 -0
  611. package/ui-dist/assets/erlang-BNw1qcRV.js +1 -0
  612. package/ui-dist/assets/factor-kuTfRLto.js +1 -0
  613. package/ui-dist/assets/fcl-Kvtd6kyn.js +1 -0
  614. package/ui-dist/assets/flowDiagram-NV44I4VS-Ddv1tq-H.js +162 -0
  615. package/ui-dist/assets/forth-Ffai-XNe.js +1 -0
  616. package/ui-dist/assets/fortran-DYz_wnZ1.js +1 -0
  617. package/ui-dist/assets/ganttDiagram-JELNMOA3-DAw7UfVT.js +267 -0
  618. package/ui-dist/assets/gas-Bneqetm1.js +1 -0
  619. package/ui-dist/assets/gherkin-heZmZLOM.js +1 -0
  620. package/ui-dist/assets/gitGraphDiagram-V2S2FVAM-CLPkzwpF.js +65 -0
  621. package/ui-dist/assets/graph-B1ThnnK5.js +1 -0
  622. package/ui-dist/assets/groovy-D9Dt4D0W.js +1 -0
  623. package/ui-dist/assets/haskell-Cw1EW3IL.js +1 -0
  624. package/ui-dist/assets/haxe-H-WmDvRZ.js +1 -0
  625. package/ui-dist/assets/http-DBlCnlav.js +1 -0
  626. package/ui-dist/assets/idl-BEugSyMb.js +1 -0
  627. package/ui-dist/assets/index-0DYmQxT3.js +2 -0
  628. package/ui-dist/assets/index-1BRIjwwa.js +1 -0
  629. package/ui-dist/assets/index-4pxn9bje.js +1 -0
  630. package/ui-dist/assets/index-B02pjBpR.js +7 -0
  631. package/ui-dist/assets/index-BGjMkZzC.js +1 -0
  632. package/ui-dist/assets/index-BHsjaYJ1.js +1 -0
  633. package/ui-dist/assets/index-BTwpjL-6.js +1 -0
  634. package/ui-dist/assets/index-BZ72uG4K.js +6 -0
  635. package/ui-dist/assets/index-BpC8VHcj.js +3 -0
  636. package/ui-dist/assets/index-BrvXvCkd.js +1 -0
  637. package/ui-dist/assets/index-CEBcI-2f.js +1 -0
  638. package/ui-dist/assets/index-CkmjCahV.js +1 -0
  639. package/ui-dist/assets/index-Cp84QmJD.css +1 -0
  640. package/ui-dist/assets/index-CpVjtxma.js +1 -0
  641. package/ui-dist/assets/index-D3AJPUjv.js +1 -0
  642. package/ui-dist/assets/index-DRkeP4vs.js +13 -0
  643. package/ui-dist/assets/index-DXeNhnre.js +1180 -0
  644. package/ui-dist/assets/index-DXvXmooU.js +1 -0
  645. package/ui-dist/assets/index-DZdwValG.js +1 -0
  646. package/ui-dist/assets/index-DbWj5-qO.js +1 -0
  647. package/ui-dist/assets/index-DbcKBTbp.js +1 -0
  648. package/ui-dist/assets/index-DdAQdjTR.js +1 -0
  649. package/ui-dist/assets/index-DlImcHKo.js +1 -0
  650. package/ui-dist/assets/index-X9LdJDbl.js +1 -0
  651. package/ui-dist/assets/infoDiagram-HS3SLOUP-CbJm6kuq.js +2 -0
  652. package/ui-dist/assets/init-Gi6I4Gst.js +1 -0
  653. package/ui-dist/assets/javascript-iXu5QeM3.js +1 -0
  654. package/ui-dist/assets/journeyDiagram-XKPGCS4Q-CeNVFpGu.js +139 -0
  655. package/ui-dist/assets/julia-DuME0IfC.js +1 -0
  656. package/ui-dist/assets/kanban-definition-3W4ZIXB7-DRqPoDRI.js +89 -0
  657. package/ui-dist/assets/katex-O9d3_IXG.js +261 -0
  658. package/ui-dist/assets/layout-CZTKj8OD.js +1 -0
  659. package/ui-dist/assets/linear-BDJjeIco.js +1 -0
  660. package/ui-dist/assets/livescript-BwQOo05w.js +1 -0
  661. package/ui-dist/assets/lua-BgMRiT3U.js +1 -0
  662. package/ui-dist/assets/mathematica-DTrFuWx2.js +1 -0
  663. package/ui-dist/assets/mbox-CNhZ1qSd.js +1 -0
  664. package/ui-dist/assets/mermaid.core-B5v7dPHY.js +256 -0
  665. package/ui-dist/assets/mindmap-definition-VGOIOE7T-zjw0AyzL.js +68 -0
  666. package/ui-dist/assets/mirc-CjQqDB4T.js +1 -0
  667. package/ui-dist/assets/mllike-CXdrOF99.js +1 -0
  668. package/ui-dist/assets/modelica-Dc1JOy9r.js +1 -0
  669. package/ui-dist/assets/mscgen-BA5vi2Kp.js +1 -0
  670. package/ui-dist/assets/mumps-BT43cFF4.js +1 -0
  671. package/ui-dist/assets/nginx-DdIZxoE0.js +1 -0
  672. package/ui-dist/assets/nsis-LdVXkNf5.js +1 -0
  673. package/ui-dist/assets/ntriples-BfvgReVJ.js +1 -0
  674. package/ui-dist/assets/octave-Ck1zUtKM.js +1 -0
  675. package/ui-dist/assets/ordinal-Cboi1Yqb.js +1 -0
  676. package/ui-dist/assets/oz-BzwKVEFT.js +1 -0
  677. package/ui-dist/assets/pascal--L3eBynH.js +1 -0
  678. package/ui-dist/assets/perl-CdXCOZ3F.js +1 -0
  679. package/ui-dist/assets/pieDiagram-ADFJNKIX-ojNQ8Ukr.js +30 -0
  680. package/ui-dist/assets/pig-CevX1Tat.js +1 -0
  681. package/ui-dist/assets/powershell-CFHJl5sT.js +1 -0
  682. package/ui-dist/assets/properties-C78fOPTZ.js +1 -0
  683. package/ui-dist/assets/protobuf-ChK-085T.js +1 -0
  684. package/ui-dist/assets/pug-DeIclll2.js +1 -0
  685. package/ui-dist/assets/puppet-DMA9R1ak.js +1 -0
  686. package/ui-dist/assets/python-BuPzkPfP.js +1 -0
  687. package/ui-dist/assets/q-pXgVlZs6.js +1 -0
  688. package/ui-dist/assets/quadrantDiagram-AYHSOK5B-B8K2F86x.js +7 -0
  689. package/ui-dist/assets/r-B6wPVr8A.js +1 -0
  690. package/ui-dist/assets/requirementDiagram-UZGBJVZJ-DA_Bjcpk.js +64 -0
  691. package/ui-dist/assets/rpm-CTu-6PCP.js +1 -0
  692. package/ui-dist/assets/ruby-B2Rjki9n.js +1 -0
  693. package/ui-dist/assets/sankeyDiagram-TZEHDZUN-yQfMgroQ.js +10 -0
  694. package/ui-dist/assets/sas-B4kiWyti.js +1 -0
  695. package/ui-dist/assets/scheme-C41bIUwD.js +1 -0
  696. package/ui-dist/assets/sequenceDiagram-WL72ISMW-CWQm0UQc.js +145 -0
  697. package/ui-dist/assets/shell-CjFT_Tl9.js +1 -0
  698. package/ui-dist/assets/sieve-C3Gn_uJK.js +1 -0
  699. package/ui-dist/assets/simple-mode-GW_nhZxv.js +1 -0
  700. package/ui-dist/assets/smalltalk-CnHTOXQT.js +1 -0
  701. package/ui-dist/assets/solr-DehyRSwq.js +1 -0
  702. package/ui-dist/assets/sparql-DkYu6x3z.js +1 -0
  703. package/ui-dist/assets/spreadsheet-BCZA_wO0.js +1 -0
  704. package/ui-dist/assets/sql-D0XecflT.js +1 -0
  705. package/ui-dist/assets/stateDiagram-FKZM4ZOC-C9L_ELvE.js +1 -0
  706. package/ui-dist/assets/stateDiagram-v2-4FDKWEC3-D3i22gRM.js +1 -0
  707. package/ui-dist/assets/stex-C3f8Ysf7.js +1 -0
  708. package/ui-dist/assets/stylus-B533Al4x.js +1 -0
  709. package/ui-dist/assets/swift-BzpIVaGY.js +1 -0
  710. package/ui-dist/assets/tcl-DVfN8rqt.js +1 -0
  711. package/ui-dist/assets/textile-CnDTJFAw.js +1 -0
  712. package/ui-dist/assets/tiddlywiki-DO-Gjzrf.js +1 -0
  713. package/ui-dist/assets/tiki-DGYXhP31.js +1 -0
  714. package/ui-dist/assets/timeline-definition-IT6M3QCI-Bfva-2zq.js +61 -0
  715. package/ui-dist/assets/toml-Bm5Em-hy.js +1 -0
  716. package/ui-dist/assets/treemap-GDKQZRPO-6wTQWQt4.js +162 -0
  717. package/ui-dist/assets/troff-wAsdV37c.js +1 -0
  718. package/ui-dist/assets/ttcn-CfJYG6tj.js +1 -0
  719. package/ui-dist/assets/ttcn-cfg-B9xdYoR4.js +1 -0
  720. package/ui-dist/assets/turtle-B1tBg_DP.js +1 -0
  721. package/ui-dist/assets/vb-CmGdzxic.js +1 -0
  722. package/ui-dist/assets/vbscript-BuJXcnF6.js +1 -0
  723. package/ui-dist/assets/velocity-D8B20fx6.js +1 -0
  724. package/ui-dist/assets/verilog-C6RDOZhf.js +1 -0
  725. package/ui-dist/assets/vhdl-lSbBsy5d.js +1 -0
  726. package/ui-dist/assets/webidl-ZXfAyPTL.js +1 -0
  727. package/ui-dist/assets/xquery-DzFWVndE.js +1 -0
  728. package/ui-dist/assets/xychartDiagram-PRI3JC2R-DNsmIw3v.js +7 -0
  729. package/ui-dist/assets/yacas-BJ4BC0dw.js +1 -0
  730. package/ui-dist/assets/z80-Hz9HOZM7.js +1 -0
  731. package/ui-dist/brands/opencode-logo-dark-square.svg +18 -0
  732. package/ui-dist/brands/opencode-logo-light-square.svg +18 -0
  733. package/ui-dist/favicon-16x16.png +0 -0
  734. package/ui-dist/favicon-32x32.png +0 -0
  735. package/ui-dist/favicon.ico +0 -0
  736. package/ui-dist/favicon.svg +9 -0
  737. package/ui-dist/index.html +48 -0
  738. package/ui-dist/site.webmanifest +30 -0
  739. package/ui-dist/sw.js +42 -0
  740. package/ui-dist/worktree-favicon-16x16.png +0 -0
  741. package/ui-dist/worktree-favicon-32x32.png +0 -0
  742. package/ui-dist/worktree-favicon.ico +0 -0
  743. package/ui-dist/worktree-favicon.svg +9 -0
@@ -0,0 +1,3739 @@
1
+ import { createHash } from "node:crypto";
2
+ import { execFile } from "node:child_process";
3
+ import path from "node:path";
4
+ import { promisify } from "node:util";
5
+ import { ISSUE_PRIORITIES, ISSUE_STATUSES, PROJECT_STATUSES, ROUTINE_CATCH_UP_POLICIES, ROUTINE_CONCURRENCY_POLICIES, ROUTINE_STATUSES, ROUTINE_TRIGGER_KINDS, ROUTINE_TRIGGER_SIGNING_MODES, deriveProjectUrlKey, normalizeAgentUrlKey, } from "@fidelios/shared";
6
+ import { readFideliOSSkillSyncPreference, writeFideliOSSkillSyncPreference, } from "@fidelios/adapter-utils/server-utils";
7
+ import { notFound, unprocessable } from "../errors.js";
8
+ import { accessService } from "./access.js";
9
+ import { agentService } from "./agents.js";
10
+ import { agentInstructionsService } from "./agent-instructions.js";
11
+ import { assetService } from "./assets.js";
12
+ import { generateReadme } from "./company-export-readme.js";
13
+ import { renderOrgChartPng } from "../routes/org-chart-svg.js";
14
+ import { companySkillService } from "./company-skills.js";
15
+ import { companyService } from "./companies.js";
16
+ import { validateCron } from "./cron.js";
17
+ import { issueService } from "./issues.js";
18
+ import { projectService } from "./projects.js";
19
+ import { routineService } from "./routines.js";
20
+ /** Build OrgNode tree from manifest agent list (slug + reportsToSlug). */
21
+ function buildOrgTreeFromManifest(agents) {
22
+ const ROLE_LABELS = {
23
+ ceo: "Chief Executive", cto: "Technology", cmo: "Marketing",
24
+ cfo: "Finance", coo: "Operations", vp: "VP", manager: "Manager",
25
+ engineer: "Engineer", agent: "Agent",
26
+ };
27
+ const bySlug = new Map(agents.map((a) => [a.slug, a]));
28
+ const childrenOf = new Map();
29
+ for (const a of agents) {
30
+ const parent = a.reportsToSlug ?? null;
31
+ const list = childrenOf.get(parent) ?? [];
32
+ list.push(a);
33
+ childrenOf.set(parent, list);
34
+ }
35
+ const build = (parentSlug) => {
36
+ const members = childrenOf.get(parentSlug) ?? [];
37
+ return members.map((m) => ({
38
+ id: m.slug,
39
+ name: m.name,
40
+ role: ROLE_LABELS[m.role] ?? m.role,
41
+ status: "active",
42
+ reports: build(m.slug),
43
+ }));
44
+ };
45
+ // Find roots: agents whose reportsToSlug is null or points to a non-existent slug
46
+ const roots = agents.filter((a) => !a.reportsToSlug || !bySlug.has(a.reportsToSlug));
47
+ const rootSlugs = new Set(roots.map((r) => r.slug));
48
+ // Start from null parent, but also include orphans
49
+ const tree = build(null);
50
+ for (const root of roots) {
51
+ if (root.reportsToSlug && !bySlug.has(root.reportsToSlug)) {
52
+ // Orphan root (parent slug doesn't exist)
53
+ tree.push({
54
+ id: root.slug,
55
+ name: root.name,
56
+ role: ROLE_LABELS[root.role] ?? root.role,
57
+ status: "active",
58
+ reports: build(root.slug),
59
+ });
60
+ }
61
+ }
62
+ return tree;
63
+ }
64
+ const DEFAULT_INCLUDE = {
65
+ company: true,
66
+ agents: true,
67
+ projects: false,
68
+ issues: false,
69
+ skills: false,
70
+ };
71
+ const DEFAULT_COLLISION_STRATEGY = "rename";
72
+ const execFileAsync = promisify(execFile);
73
+ let bundledSkillsCommitPromise = null;
74
+ function resolveImportMode(options) {
75
+ return options?.mode ?? "board_full";
76
+ }
77
+ function resolveSkillConflictStrategy(mode, collisionStrategy) {
78
+ if (mode === "board_full")
79
+ return "replace";
80
+ return collisionStrategy === "skip" ? "skip" : "rename";
81
+ }
82
+ function classifyPortableFileKind(pathValue) {
83
+ const normalized = normalizePortablePath(pathValue);
84
+ if (normalized === "COMPANY.md")
85
+ return "company";
86
+ if (normalized === ".fidelios.yaml" || normalized === ".fidelios.yml")
87
+ return "extension";
88
+ if (normalized === "README.md")
89
+ return "readme";
90
+ if (normalized.startsWith("agents/"))
91
+ return "agent";
92
+ if (normalized.startsWith("skills/"))
93
+ return "skill";
94
+ if (normalized.startsWith("projects/"))
95
+ return "project";
96
+ if (normalized.startsWith("tasks/"))
97
+ return "issue";
98
+ return "other";
99
+ }
100
+ function normalizeSkillSlug(value) {
101
+ return value ? normalizeAgentUrlKey(value) ?? null : null;
102
+ }
103
+ function normalizeSkillKey(value) {
104
+ if (!value)
105
+ return null;
106
+ const segments = value
107
+ .split("/")
108
+ .map((segment) => normalizeSkillSlug(segment))
109
+ .filter((segment) => Boolean(segment));
110
+ return segments.length > 0 ? segments.join("/") : null;
111
+ }
112
+ function readSkillKey(frontmatter) {
113
+ const metadata = isPlainRecord(frontmatter.metadata) ? frontmatter.metadata : null;
114
+ const fidelios = isPlainRecord(metadata?.fidelios) ? metadata?.fidelios : null;
115
+ return normalizeSkillKey(asString(frontmatter.key)
116
+ ?? asString(frontmatter.skillKey)
117
+ ?? asString(metadata?.skillKey)
118
+ ?? asString(metadata?.canonicalKey)
119
+ ?? asString(metadata?.fideliosSkillKey)
120
+ ?? asString(fidelios?.skillKey)
121
+ ?? asString(fidelios?.key));
122
+ }
123
+ function deriveManifestSkillKey(frontmatter, fallbackSlug, metadata, sourceType, sourceLocator) {
124
+ const explicit = readSkillKey(frontmatter);
125
+ if (explicit)
126
+ return explicit;
127
+ const slug = normalizeSkillSlug(asString(frontmatter.slug) ?? fallbackSlug) ?? "skill";
128
+ const sourceKind = asString(metadata?.sourceKind);
129
+ const owner = normalizeSkillSlug(asString(metadata?.owner));
130
+ const repo = normalizeSkillSlug(asString(metadata?.repo));
131
+ if ((sourceType === "github" || sourceType === "skills_sh" || sourceKind === "github" || sourceKind === "skills_sh") && owner && repo) {
132
+ return `${owner}/${repo}/${slug}`;
133
+ }
134
+ if (sourceKind === "fidelios_bundled") {
135
+ return `maxzemtsov/fidelios/${slug}`;
136
+ }
137
+ if (sourceType === "url" || sourceKind === "url") {
138
+ try {
139
+ const host = normalizeSkillSlug(sourceLocator ? new URL(sourceLocator).host : null) ?? "url";
140
+ return `url/${host}/${slug}`;
141
+ }
142
+ catch {
143
+ return `url/unknown/${slug}`;
144
+ }
145
+ }
146
+ return slug;
147
+ }
148
+ function hashSkillValue(value) {
149
+ return createHash("sha256").update(value).digest("hex").slice(0, 8);
150
+ }
151
+ function normalizeExportPathSegment(value, preserveCase = false) {
152
+ if (!value)
153
+ return null;
154
+ const trimmed = value.trim();
155
+ if (!trimmed)
156
+ return null;
157
+ const normalized = trimmed
158
+ .replace(/[^A-Za-z0-9._-]+/g, "-")
159
+ .replace(/-+/g, "-")
160
+ .replace(/^-+|-+$/g, "");
161
+ if (!normalized)
162
+ return null;
163
+ return preserveCase ? normalized : normalized.toLowerCase();
164
+ }
165
+ function readSkillSourceKind(skill) {
166
+ const metadata = isPlainRecord(skill.metadata) ? skill.metadata : null;
167
+ return asString(metadata?.sourceKind);
168
+ }
169
+ function deriveLocalExportNamespace(skill, slug) {
170
+ const metadata = isPlainRecord(skill.metadata) ? skill.metadata : null;
171
+ const candidates = [
172
+ asString(metadata?.projectName),
173
+ asString(metadata?.workspaceName),
174
+ ];
175
+ if (skill.sourceLocator) {
176
+ const basename = path.basename(skill.sourceLocator);
177
+ candidates.push(basename.toLowerCase() === "skill.md" ? path.basename(path.dirname(skill.sourceLocator)) : basename);
178
+ }
179
+ for (const value of candidates) {
180
+ const normalized = normalizeSkillSlug(value);
181
+ if (normalized && normalized !== slug)
182
+ return normalized;
183
+ }
184
+ return null;
185
+ }
186
+ function derivePrimarySkillExportDir(skill, slug, companyIssuePrefix) {
187
+ const normalizedKey = normalizeSkillKey(skill.key);
188
+ const keySegments = normalizedKey?.split("/") ?? [];
189
+ const primaryNamespace = keySegments[0] ?? null;
190
+ if (primaryNamespace === "company") {
191
+ const companySegment = normalizeExportPathSegment(companyIssuePrefix, true)
192
+ ?? normalizeExportPathSegment(keySegments[1], true)
193
+ ?? "company";
194
+ return `skills/company/${companySegment}/${slug}`;
195
+ }
196
+ if (primaryNamespace === "local") {
197
+ const localNamespace = deriveLocalExportNamespace(skill, slug);
198
+ return localNamespace
199
+ ? `skills/local/${localNamespace}/${slug}`
200
+ : `skills/local/${slug}`;
201
+ }
202
+ if (primaryNamespace === "url") {
203
+ let derivedHost = keySegments[1] ?? null;
204
+ if (!derivedHost) {
205
+ try {
206
+ derivedHost = normalizeSkillSlug(skill.sourceLocator ? new URL(skill.sourceLocator).host : null);
207
+ }
208
+ catch {
209
+ derivedHost = null;
210
+ }
211
+ }
212
+ const host = derivedHost ?? "url";
213
+ return `skills/url/${host}/${slug}`;
214
+ }
215
+ if (keySegments.length > 1) {
216
+ return `skills/${keySegments.join("/")}`;
217
+ }
218
+ return `skills/${slug}`;
219
+ }
220
+ function appendSkillExportDirSuffix(packageDir, suffix) {
221
+ const lastSeparator = packageDir.lastIndexOf("/");
222
+ if (lastSeparator < 0)
223
+ return `${packageDir}--${suffix}`;
224
+ return `${packageDir.slice(0, lastSeparator + 1)}${packageDir.slice(lastSeparator + 1)}--${suffix}`;
225
+ }
226
+ function deriveSkillExportDirCandidates(skill, slug, companyIssuePrefix) {
227
+ const primaryDir = derivePrimarySkillExportDir(skill, slug, companyIssuePrefix);
228
+ const metadata = isPlainRecord(skill.metadata) ? skill.metadata : null;
229
+ const sourceKind = readSkillSourceKind(skill);
230
+ const suffixes = new Set();
231
+ const pushSuffix = (value, preserveCase = false) => {
232
+ const normalized = normalizeExportPathSegment(value, preserveCase);
233
+ if (normalized && normalized !== slug) {
234
+ suffixes.add(normalized);
235
+ }
236
+ };
237
+ if (sourceKind === "fidelios_bundled") {
238
+ pushSuffix("fidelios");
239
+ }
240
+ if (skill.sourceType === "github" || skill.sourceType === "skills_sh") {
241
+ pushSuffix(asString(metadata?.repo));
242
+ pushSuffix(asString(metadata?.owner));
243
+ pushSuffix(skill.sourceType === "skills_sh" ? "skills_sh" : "github");
244
+ }
245
+ else if (skill.sourceType === "url") {
246
+ try {
247
+ pushSuffix(skill.sourceLocator ? new URL(skill.sourceLocator).host : null);
248
+ }
249
+ catch {
250
+ // Ignore URL parse failures and fall through to generic suffixes.
251
+ }
252
+ pushSuffix("url");
253
+ }
254
+ else if (skill.sourceType === "local_path") {
255
+ pushSuffix(asString(metadata?.projectName));
256
+ pushSuffix(asString(metadata?.workspaceName));
257
+ pushSuffix(deriveLocalExportNamespace(skill, slug));
258
+ if (sourceKind === "managed_local")
259
+ pushSuffix("company");
260
+ if (sourceKind === "project_scan")
261
+ pushSuffix("project");
262
+ pushSuffix("local");
263
+ }
264
+ else {
265
+ pushSuffix(sourceKind);
266
+ pushSuffix("skill");
267
+ }
268
+ return [primaryDir, ...Array.from(suffixes, (suffix) => appendSkillExportDirSuffix(primaryDir, suffix))];
269
+ }
270
+ function buildSkillExportDirMap(skills, companyIssuePrefix) {
271
+ const usedDirs = new Set();
272
+ const keyToDir = new Map();
273
+ const orderedSkills = [...skills].sort((left, right) => left.key.localeCompare(right.key));
274
+ for (const skill of orderedSkills) {
275
+ const slug = normalizeSkillSlug(skill.slug) ?? "skill";
276
+ const candidates = deriveSkillExportDirCandidates(skill, slug, companyIssuePrefix);
277
+ let packageDir = candidates.find((candidate) => !usedDirs.has(candidate)) ?? null;
278
+ if (!packageDir) {
279
+ packageDir = appendSkillExportDirSuffix(candidates[0] ?? `skills/${slug}`, hashSkillValue(skill.key));
280
+ while (usedDirs.has(packageDir)) {
281
+ packageDir = appendSkillExportDirSuffix(candidates[0] ?? `skills/${slug}`, hashSkillValue(`${skill.key}:${packageDir}`));
282
+ }
283
+ }
284
+ usedDirs.add(packageDir);
285
+ keyToDir.set(skill.key, packageDir);
286
+ }
287
+ return keyToDir;
288
+ }
289
+ function isSensitiveEnvKey(key) {
290
+ const normalized = key.trim().toLowerCase();
291
+ return (normalized === "token" ||
292
+ normalized.endsWith("_token") ||
293
+ normalized.endsWith("-token") ||
294
+ normalized.includes("apikey") ||
295
+ normalized.includes("api_key") ||
296
+ normalized.includes("api-key") ||
297
+ normalized.includes("access_token") ||
298
+ normalized.includes("access-token") ||
299
+ normalized.includes("auth") ||
300
+ normalized.includes("auth_token") ||
301
+ normalized.includes("auth-token") ||
302
+ normalized.includes("authorization") ||
303
+ normalized.includes("bearer") ||
304
+ normalized.includes("secret") ||
305
+ normalized.includes("passwd") ||
306
+ normalized.includes("password") ||
307
+ normalized.includes("credential") ||
308
+ normalized.includes("jwt") ||
309
+ normalized.includes("privatekey") ||
310
+ normalized.includes("private_key") ||
311
+ normalized.includes("private-key") ||
312
+ normalized.includes("cookie") ||
313
+ normalized.includes("connectionstring"));
314
+ }
315
+ const COMPANY_LOGO_CONTENT_TYPE_EXTENSIONS = {
316
+ "image/gif": ".gif",
317
+ "image/jpeg": ".jpg",
318
+ "image/png": ".png",
319
+ "image/svg+xml": ".svg",
320
+ "image/webp": ".webp",
321
+ };
322
+ const COMPANY_LOGO_FILE_NAME = "company-logo";
323
+ const RUNTIME_DEFAULT_RULES = [
324
+ { path: ["heartbeat", "cooldownSec"], value: 10 },
325
+ { path: ["heartbeat", "intervalSec"], value: 3600 },
326
+ { path: ["heartbeat", "wakeOnOnDemand"], value: true },
327
+ { path: ["heartbeat", "wakeOnAssignment"], value: true },
328
+ { path: ["heartbeat", "wakeOnAutomation"], value: true },
329
+ { path: ["heartbeat", "wakeOnDemand"], value: true },
330
+ { path: ["heartbeat", "maxConcurrentRuns"], value: 3 },
331
+ ];
332
+ const ADAPTER_DEFAULT_RULES_BY_TYPE = {
333
+ codex_local: [
334
+ { path: ["timeoutSec"], value: 0 },
335
+ { path: ["graceSec"], value: 15 },
336
+ ],
337
+ gemini_local: [
338
+ { path: ["timeoutSec"], value: 0 },
339
+ { path: ["graceSec"], value: 15 },
340
+ ],
341
+ opencode_local: [
342
+ { path: ["timeoutSec"], value: 0 },
343
+ { path: ["graceSec"], value: 15 },
344
+ ],
345
+ cursor: [
346
+ { path: ["timeoutSec"], value: 0 },
347
+ { path: ["graceSec"], value: 15 },
348
+ ],
349
+ claude_local: [
350
+ { path: ["timeoutSec"], value: 0 },
351
+ { path: ["graceSec"], value: 15 },
352
+ { path: ["maxTurnsPerRun"], value: 300 },
353
+ ],
354
+ openclaw_gateway: [
355
+ { path: ["timeoutSec"], value: 120 },
356
+ { path: ["waitTimeoutMs"], value: 120000 },
357
+ { path: ["sessionKeyStrategy"], value: "fixed" },
358
+ { path: ["sessionKey"], value: "fidelios" },
359
+ { path: ["role"], value: "operator" },
360
+ { path: ["scopes"], value: ["operator.admin"] },
361
+ ],
362
+ };
363
+ function isPlainRecord(value) {
364
+ return typeof value === "object" && value !== null && !Array.isArray(value);
365
+ }
366
+ function asString(value) {
367
+ if (typeof value !== "string")
368
+ return null;
369
+ const trimmed = value.trim();
370
+ return trimmed.length > 0 ? trimmed : null;
371
+ }
372
+ function asBoolean(value) {
373
+ return typeof value === "boolean" ? value : null;
374
+ }
375
+ function asInteger(value) {
376
+ return typeof value === "number" && Number.isInteger(value) ? value : null;
377
+ }
378
+ function normalizeRoutineTriggerExtension(value) {
379
+ if (!isPlainRecord(value))
380
+ return null;
381
+ const kind = asString(value.kind);
382
+ if (!kind)
383
+ return null;
384
+ return {
385
+ kind,
386
+ label: asString(value.label),
387
+ enabled: asBoolean(value.enabled) ?? true,
388
+ cronExpression: asString(value.cronExpression),
389
+ timezone: asString(value.timezone),
390
+ signingMode: asString(value.signingMode),
391
+ replayWindowSec: asInteger(value.replayWindowSec),
392
+ };
393
+ }
394
+ function normalizeRoutineExtension(value) {
395
+ if (!isPlainRecord(value))
396
+ return null;
397
+ const triggers = Array.isArray(value.triggers)
398
+ ? value.triggers
399
+ .map((entry) => normalizeRoutineTriggerExtension(entry))
400
+ .filter((entry) => entry !== null)
401
+ : [];
402
+ const routine = {
403
+ concurrencyPolicy: asString(value.concurrencyPolicy),
404
+ catchUpPolicy: asString(value.catchUpPolicy),
405
+ triggers,
406
+ };
407
+ return stripEmptyValues(routine) ? routine : null;
408
+ }
409
+ function buildRoutineManifestFromLiveRoutine(routine) {
410
+ return {
411
+ concurrencyPolicy: routine.concurrencyPolicy,
412
+ catchUpPolicy: routine.catchUpPolicy,
413
+ triggers: routine.triggers.map((trigger) => ({
414
+ kind: trigger.kind,
415
+ label: trigger.label ?? null,
416
+ enabled: Boolean(trigger.enabled),
417
+ cronExpression: trigger.kind === "schedule" ? trigger.cronExpression ?? null : null,
418
+ timezone: trigger.kind === "schedule" ? trigger.timezone ?? null : null,
419
+ signingMode: trigger.kind === "webhook" ? trigger.signingMode ?? null : null,
420
+ replayWindowSec: trigger.kind === "webhook" ? trigger.replayWindowSec ?? null : null,
421
+ })),
422
+ };
423
+ }
424
+ function containsAbsolutePathFragment(value) {
425
+ return /(^|\s)(\/[^/\s]|[A-Za-z]:[\\/])/.test(value);
426
+ }
427
+ function containsSystemDependentPathValue(value) {
428
+ if (typeof value === "string") {
429
+ return path.isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value) || containsAbsolutePathFragment(value);
430
+ }
431
+ if (Array.isArray(value)) {
432
+ return value.some((entry) => containsSystemDependentPathValue(entry));
433
+ }
434
+ if (isPlainRecord(value)) {
435
+ return Object.values(value).some((entry) => containsSystemDependentPathValue(entry));
436
+ }
437
+ return false;
438
+ }
439
+ function clonePortableRecord(value) {
440
+ if (!isPlainRecord(value))
441
+ return null;
442
+ return structuredClone(value);
443
+ }
444
+ function disableImportedTimerHeartbeat(runtimeConfig) {
445
+ const next = clonePortableRecord(runtimeConfig) ?? {};
446
+ const heartbeat = isPlainRecord(next.heartbeat) ? { ...next.heartbeat } : {};
447
+ heartbeat.enabled = false;
448
+ next.heartbeat = heartbeat;
449
+ return next;
450
+ }
451
+ function normalizePortableProjectWorkspaceExtension(workspaceKey, value) {
452
+ if (!isPlainRecord(value))
453
+ return null;
454
+ const normalizedKey = normalizeAgentUrlKey(workspaceKey) ?? workspaceKey.trim();
455
+ if (!normalizedKey)
456
+ return null;
457
+ return {
458
+ key: normalizedKey,
459
+ name: asString(value.name) ?? normalizedKey,
460
+ sourceType: asString(value.sourceType),
461
+ repoUrl: asString(value.repoUrl),
462
+ repoRef: asString(value.repoRef),
463
+ defaultRef: asString(value.defaultRef),
464
+ visibility: asString(value.visibility),
465
+ setupCommand: asString(value.setupCommand),
466
+ cleanupCommand: asString(value.cleanupCommand),
467
+ metadata: isPlainRecord(value.metadata) ? value.metadata : null,
468
+ isPrimary: asBoolean(value.isPrimary) ?? false,
469
+ };
470
+ }
471
+ function derivePortableProjectWorkspaceKey(workspace, usedKeys) {
472
+ const baseKey = normalizeAgentUrlKey(workspace.name)
473
+ ?? normalizeAgentUrlKey(asString(workspace.repoUrl)?.split("/").pop()?.replace(/\.git$/i, "") ?? "")
474
+ ?? "workspace";
475
+ return uniqueSlug(baseKey, usedKeys);
476
+ }
477
+ function exportPortableProjectExecutionWorkspacePolicy(projectSlug, policy, workspaceKeyById, warnings) {
478
+ const next = clonePortableRecord(policy);
479
+ if (!next)
480
+ return null;
481
+ const defaultWorkspaceId = asString(next.defaultProjectWorkspaceId);
482
+ if (defaultWorkspaceId) {
483
+ const defaultWorkspaceKey = workspaceKeyById.get(defaultWorkspaceId);
484
+ if (defaultWorkspaceKey) {
485
+ next.defaultProjectWorkspaceKey = defaultWorkspaceKey;
486
+ }
487
+ else {
488
+ warnings.push(`Project ${projectSlug} default workspace ${defaultWorkspaceId} was omitted from export because that workspace is not portable.`);
489
+ }
490
+ delete next.defaultProjectWorkspaceId;
491
+ }
492
+ const cleaned = stripEmptyValues(next);
493
+ return isPlainRecord(cleaned) ? cleaned : null;
494
+ }
495
+ function importPortableProjectExecutionWorkspacePolicy(projectSlug, policy, workspaceIdByKey, warnings) {
496
+ const next = clonePortableRecord(policy);
497
+ if (!next)
498
+ return null;
499
+ const defaultWorkspaceKey = asString(next.defaultProjectWorkspaceKey);
500
+ if (defaultWorkspaceKey) {
501
+ const defaultWorkspaceId = workspaceIdByKey.get(defaultWorkspaceKey);
502
+ if (defaultWorkspaceId) {
503
+ next.defaultProjectWorkspaceId = defaultWorkspaceId;
504
+ }
505
+ else {
506
+ warnings.push(`Project ${projectSlug} references missing workspace key ${defaultWorkspaceKey}; imported execution workspace policy without a default workspace.`);
507
+ }
508
+ }
509
+ delete next.defaultProjectWorkspaceKey;
510
+ const cleaned = stripEmptyValues(next);
511
+ return isPlainRecord(cleaned) ? cleaned : null;
512
+ }
513
+ function stripPortableProjectExecutionWorkspaceRefs(policy) {
514
+ const next = clonePortableRecord(policy);
515
+ if (!next)
516
+ return null;
517
+ delete next.defaultProjectWorkspaceId;
518
+ delete next.defaultProjectWorkspaceKey;
519
+ const cleaned = stripEmptyValues(next);
520
+ return isPlainRecord(cleaned) ? cleaned : null;
521
+ }
522
+ async function readGitOutput(cwd, args) {
523
+ const { stdout } = await execFileAsync("git", ["-C", cwd, ...args], { cwd });
524
+ const trimmed = stdout.trim();
525
+ return trimmed.length > 0 ? trimmed : null;
526
+ }
527
+ async function inferPortableWorkspaceGitMetadata(workspace) {
528
+ const cwd = asString(workspace.cwd);
529
+ if (!cwd) {
530
+ return {
531
+ repoUrl: null,
532
+ repoRef: null,
533
+ defaultRef: null,
534
+ };
535
+ }
536
+ let repoUrl = null;
537
+ try {
538
+ repoUrl = await readGitOutput(cwd, ["remote", "get-url", "origin"]);
539
+ }
540
+ catch {
541
+ try {
542
+ const firstRemote = await readGitOutput(cwd, ["remote"]);
543
+ const remoteName = firstRemote?.split("\n").map((entry) => entry.trim()).find(Boolean) ?? null;
544
+ if (remoteName) {
545
+ repoUrl = await readGitOutput(cwd, ["remote", "get-url", remoteName]);
546
+ }
547
+ }
548
+ catch {
549
+ repoUrl = null;
550
+ }
551
+ }
552
+ let repoRef = null;
553
+ try {
554
+ repoRef = await readGitOutput(cwd, ["branch", "--show-current"]);
555
+ }
556
+ catch {
557
+ repoRef = null;
558
+ }
559
+ let defaultRef = null;
560
+ try {
561
+ const remoteHead = await readGitOutput(cwd, ["symbolic-ref", "--quiet", "--short", "refs/remotes/origin/HEAD"]);
562
+ defaultRef = remoteHead?.startsWith("origin/") ? remoteHead.slice("origin/".length) : remoteHead;
563
+ }
564
+ catch {
565
+ defaultRef = null;
566
+ }
567
+ return {
568
+ repoUrl,
569
+ repoRef,
570
+ defaultRef,
571
+ };
572
+ }
573
+ async function buildPortableProjectWorkspaces(projectSlug, workspaces, warnings) {
574
+ const exportedWorkspaces = {};
575
+ const manifestWorkspaces = [];
576
+ const workspaceKeyById = new Map();
577
+ const workspaceKeyBySignature = new Map();
578
+ const manifestWorkspaceByKey = new Map();
579
+ const usedKeys = new Set();
580
+ for (const workspace of workspaces ?? []) {
581
+ const inferredGitMetadata = !asString(workspace.repoUrl) || !asString(workspace.repoRef) || !asString(workspace.defaultRef)
582
+ ? await inferPortableWorkspaceGitMetadata(workspace)
583
+ : { repoUrl: null, repoRef: null, defaultRef: null };
584
+ const repoUrl = asString(workspace.repoUrl) ?? inferredGitMetadata.repoUrl;
585
+ if (!repoUrl) {
586
+ warnings.push(`Project ${projectSlug} workspace ${workspace.name} was omitted from export because it does not have a portable repoUrl.`);
587
+ continue;
588
+ }
589
+ const repoRef = asString(workspace.repoRef) ?? inferredGitMetadata.repoRef;
590
+ const defaultRef = asString(workspace.defaultRef) ?? inferredGitMetadata.defaultRef ?? repoRef;
591
+ const workspaceSignature = JSON.stringify({
592
+ name: workspace.name,
593
+ repoUrl,
594
+ repoRef,
595
+ defaultRef,
596
+ });
597
+ const existingWorkspaceKey = workspaceKeyBySignature.get(workspaceSignature);
598
+ if (existingWorkspaceKey) {
599
+ workspaceKeyById.set(workspace.id, existingWorkspaceKey);
600
+ const existingManifestWorkspace = manifestWorkspaceByKey.get(existingWorkspaceKey);
601
+ if (existingManifestWorkspace && workspace.isPrimary) {
602
+ existingManifestWorkspace.isPrimary = true;
603
+ const existingExtensionWorkspace = exportedWorkspaces[existingWorkspaceKey];
604
+ if (isPlainRecord(existingExtensionWorkspace))
605
+ existingExtensionWorkspace.isPrimary = true;
606
+ }
607
+ continue;
608
+ }
609
+ const workspaceKey = derivePortableProjectWorkspaceKey(workspace, usedKeys);
610
+ workspaceKeyById.set(workspace.id, workspaceKey);
611
+ workspaceKeyBySignature.set(workspaceSignature, workspaceKey);
612
+ let setupCommand = asString(workspace.setupCommand);
613
+ if (setupCommand && containsAbsolutePathFragment(setupCommand)) {
614
+ warnings.push(`Project ${projectSlug} workspace ${workspaceKey} setupCommand was omitted from export because it is system-dependent.`);
615
+ setupCommand = null;
616
+ }
617
+ let cleanupCommand = asString(workspace.cleanupCommand);
618
+ if (cleanupCommand && containsAbsolutePathFragment(cleanupCommand)) {
619
+ warnings.push(`Project ${projectSlug} workspace ${workspaceKey} cleanupCommand was omitted from export because it is system-dependent.`);
620
+ cleanupCommand = null;
621
+ }
622
+ const metadata = isPlainRecord(workspace.metadata) && !containsSystemDependentPathValue(workspace.metadata)
623
+ ? workspace.metadata
624
+ : null;
625
+ if (isPlainRecord(workspace.metadata) && metadata == null) {
626
+ warnings.push(`Project ${projectSlug} workspace ${workspaceKey} metadata was omitted from export because it contains system-dependent paths.`);
627
+ }
628
+ const portableWorkspace = stripEmptyValues({
629
+ name: workspace.name,
630
+ sourceType: workspace.sourceType,
631
+ repoUrl,
632
+ repoRef,
633
+ defaultRef,
634
+ visibility: asString(workspace.visibility),
635
+ setupCommand,
636
+ cleanupCommand,
637
+ metadata,
638
+ isPrimary: workspace.isPrimary ? true : undefined,
639
+ });
640
+ if (!isPlainRecord(portableWorkspace))
641
+ continue;
642
+ exportedWorkspaces[workspaceKey] = portableWorkspace;
643
+ const manifestWorkspace = {
644
+ key: workspaceKey,
645
+ name: workspace.name,
646
+ sourceType: asString(workspace.sourceType),
647
+ repoUrl,
648
+ repoRef,
649
+ defaultRef,
650
+ visibility: asString(workspace.visibility),
651
+ setupCommand,
652
+ cleanupCommand,
653
+ metadata,
654
+ isPrimary: workspace.isPrimary,
655
+ };
656
+ manifestWorkspaces.push(manifestWorkspace);
657
+ manifestWorkspaceByKey.set(workspaceKey, manifestWorkspace);
658
+ }
659
+ return {
660
+ extension: Object.keys(exportedWorkspaces).length > 0 ? exportedWorkspaces : undefined,
661
+ manifest: manifestWorkspaces,
662
+ workspaceKeyById,
663
+ };
664
+ }
665
+ const WEEKDAY_TO_CRON = {
666
+ sunday: "0",
667
+ monday: "1",
668
+ tuesday: "2",
669
+ wednesday: "3",
670
+ thursday: "4",
671
+ friday: "5",
672
+ saturday: "6",
673
+ };
674
+ function readZonedDateParts(startsAt, timeZone) {
675
+ try {
676
+ const date = new Date(startsAt);
677
+ if (Number.isNaN(date.getTime()))
678
+ return null;
679
+ const formatter = new Intl.DateTimeFormat("en-US", {
680
+ timeZone,
681
+ hour12: false,
682
+ weekday: "long",
683
+ month: "numeric",
684
+ day: "numeric",
685
+ hour: "numeric",
686
+ minute: "numeric",
687
+ });
688
+ const parts = Object.fromEntries(formatter
689
+ .formatToParts(date)
690
+ .filter((entry) => entry.type !== "literal")
691
+ .map((entry) => [entry.type, entry.value]));
692
+ const weekday = WEEKDAY_TO_CRON[parts.weekday?.toLowerCase() ?? ""];
693
+ const month = Number(parts.month);
694
+ const day = Number(parts.day);
695
+ const hour = Number(parts.hour);
696
+ const minute = Number(parts.minute);
697
+ if (!weekday || !Number.isFinite(month) || !Number.isFinite(day) || !Number.isFinite(hour) || !Number.isFinite(minute)) {
698
+ return null;
699
+ }
700
+ return { weekday, month, day, hour, minute };
701
+ }
702
+ catch {
703
+ return null;
704
+ }
705
+ }
706
+ function normalizeCronList(values) {
707
+ return Array.from(new Set(values)).sort((left, right) => Number(left) - Number(right)).join(",");
708
+ }
709
+ function buildLegacyRoutineTriggerFromRecurrence(issue, scheduleValue) {
710
+ const warnings = [];
711
+ const errors = [];
712
+ if (!issue.legacyRecurrence || !isPlainRecord(issue.legacyRecurrence)) {
713
+ return { trigger: null, warnings, errors };
714
+ }
715
+ const schedule = isPlainRecord(scheduleValue) ? scheduleValue : null;
716
+ const frequency = asString(issue.legacyRecurrence.frequency);
717
+ const interval = asInteger(issue.legacyRecurrence.interval) ?? 1;
718
+ if (!frequency) {
719
+ errors.push(`Recurring task ${issue.slug} uses legacy recurrence without frequency; add .fidelios.yaml routines.${issue.slug}.triggers.`);
720
+ return { trigger: null, warnings, errors };
721
+ }
722
+ if (interval < 1) {
723
+ errors.push(`Recurring task ${issue.slug} uses legacy recurrence with an invalid interval; add .fidelios.yaml routines.${issue.slug}.triggers.`);
724
+ return { trigger: null, warnings, errors };
725
+ }
726
+ const timezone = asString(schedule?.timezone) ?? "UTC";
727
+ const startsAt = asString(schedule?.startsAt);
728
+ const zonedStartsAt = startsAt ? readZonedDateParts(startsAt, timezone) : null;
729
+ if (startsAt && !zonedStartsAt) {
730
+ errors.push(`Recurring task ${issue.slug} has an invalid legacy startsAt/timezone combination; add .fidelios.yaml routines.${issue.slug}.triggers.`);
731
+ return { trigger: null, warnings, errors };
732
+ }
733
+ const time = isPlainRecord(issue.legacyRecurrence.time) ? issue.legacyRecurrence.time : null;
734
+ const hour = asInteger(time?.hour) ?? zonedStartsAt?.hour ?? 0;
735
+ const minute = asInteger(time?.minute) ?? zonedStartsAt?.minute ?? 0;
736
+ if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
737
+ errors.push(`Recurring task ${issue.slug} uses legacy recurrence with an invalid time; add .fidelios.yaml routines.${issue.slug}.triggers.`);
738
+ return { trigger: null, warnings, errors };
739
+ }
740
+ if (issue.legacyRecurrence.until != null || issue.legacyRecurrence.count != null) {
741
+ warnings.push(`Recurring task ${issue.slug} uses legacy recurrence end bounds; FideliOS will import the routine trigger without those limits.`);
742
+ }
743
+ let cronExpression = null;
744
+ if (frequency === "hourly") {
745
+ const hourField = interval === 1
746
+ ? "*"
747
+ : zonedStartsAt
748
+ ? `${zonedStartsAt.hour}-23/${interval}`
749
+ : `*/${interval}`;
750
+ cronExpression = `${minute} ${hourField} * * *`;
751
+ }
752
+ else if (frequency === "daily") {
753
+ if (Array.isArray(issue.legacyRecurrence.weekdays) || Array.isArray(issue.legacyRecurrence.monthDays) || Array.isArray(issue.legacyRecurrence.months)) {
754
+ errors.push(`Recurring task ${issue.slug} uses unsupported legacy daily recurrence constraints; add .fidelios.yaml routines.${issue.slug}.triggers.`);
755
+ return { trigger: null, warnings, errors };
756
+ }
757
+ const dayField = interval === 1 ? "*" : `*/${interval}`;
758
+ cronExpression = `${minute} ${hour} ${dayField} * *`;
759
+ }
760
+ else if (frequency === "weekly") {
761
+ if (interval !== 1) {
762
+ errors.push(`Recurring task ${issue.slug} uses legacy weekly recurrence with interval > 1; add .fidelios.yaml routines.${issue.slug}.triggers.`);
763
+ return { trigger: null, warnings, errors };
764
+ }
765
+ const weekdays = Array.isArray(issue.legacyRecurrence.weekdays)
766
+ ? issue.legacyRecurrence.weekdays
767
+ .map((entry) => asString(entry))
768
+ .filter((entry) => Boolean(entry))
769
+ : [];
770
+ const cronWeekdays = weekdays
771
+ .map((entry) => WEEKDAY_TO_CRON[entry.toLowerCase()])
772
+ .filter((entry) => Boolean(entry));
773
+ if (cronWeekdays.length === 0 && zonedStartsAt?.weekday) {
774
+ cronWeekdays.push(zonedStartsAt.weekday);
775
+ }
776
+ if (cronWeekdays.length === 0) {
777
+ errors.push(`Recurring task ${issue.slug} uses legacy weekly recurrence without weekdays; add .fidelios.yaml routines.${issue.slug}.triggers.`);
778
+ return { trigger: null, warnings, errors };
779
+ }
780
+ cronExpression = `${minute} ${hour} * * ${normalizeCronList(cronWeekdays)}`;
781
+ }
782
+ else if (frequency === "monthly") {
783
+ if (interval !== 1) {
784
+ errors.push(`Recurring task ${issue.slug} uses legacy monthly recurrence with interval > 1; add .fidelios.yaml routines.${issue.slug}.triggers.`);
785
+ return { trigger: null, warnings, errors };
786
+ }
787
+ if (Array.isArray(issue.legacyRecurrence.ordinalWeekdays) && issue.legacyRecurrence.ordinalWeekdays.length > 0) {
788
+ errors.push(`Recurring task ${issue.slug} uses legacy ordinal monthly recurrence; add .fidelios.yaml routines.${issue.slug}.triggers.`);
789
+ return { trigger: null, warnings, errors };
790
+ }
791
+ const monthDays = Array.isArray(issue.legacyRecurrence.monthDays)
792
+ ? issue.legacyRecurrence.monthDays
793
+ .map((entry) => asInteger(entry))
794
+ .filter((entry) => entry != null && entry >= 1 && entry <= 31)
795
+ : [];
796
+ if (monthDays.length === 0 && zonedStartsAt?.day) {
797
+ monthDays.push(zonedStartsAt.day);
798
+ }
799
+ if (monthDays.length === 0) {
800
+ errors.push(`Recurring task ${issue.slug} uses legacy monthly recurrence without monthDays; add .fidelios.yaml routines.${issue.slug}.triggers.`);
801
+ return { trigger: null, warnings, errors };
802
+ }
803
+ const months = Array.isArray(issue.legacyRecurrence.months)
804
+ ? issue.legacyRecurrence.months
805
+ .map((entry) => asInteger(entry))
806
+ .filter((entry) => entry != null && entry >= 1 && entry <= 12)
807
+ : [];
808
+ const monthField = months.length > 0 ? normalizeCronList(months.map(String)) : "*";
809
+ cronExpression = `${minute} ${hour} ${normalizeCronList(monthDays.map(String))} ${monthField} *`;
810
+ }
811
+ else if (frequency === "yearly") {
812
+ if (interval !== 1) {
813
+ errors.push(`Recurring task ${issue.slug} uses legacy yearly recurrence with interval > 1; add .fidelios.yaml routines.${issue.slug}.triggers.`);
814
+ return { trigger: null, warnings, errors };
815
+ }
816
+ const months = Array.isArray(issue.legacyRecurrence.months)
817
+ ? issue.legacyRecurrence.months
818
+ .map((entry) => asInteger(entry))
819
+ .filter((entry) => entry != null && entry >= 1 && entry <= 12)
820
+ : [];
821
+ if (months.length === 0 && zonedStartsAt?.month) {
822
+ months.push(zonedStartsAt.month);
823
+ }
824
+ const monthDays = Array.isArray(issue.legacyRecurrence.monthDays)
825
+ ? issue.legacyRecurrence.monthDays
826
+ .map((entry) => asInteger(entry))
827
+ .filter((entry) => entry != null && entry >= 1 && entry <= 31)
828
+ : [];
829
+ if (monthDays.length === 0 && zonedStartsAt?.day) {
830
+ monthDays.push(zonedStartsAt.day);
831
+ }
832
+ if (months.length === 0 || monthDays.length === 0) {
833
+ errors.push(`Recurring task ${issue.slug} uses legacy yearly recurrence without month/monthDay anchors; add .fidelios.yaml routines.${issue.slug}.triggers.`);
834
+ return { trigger: null, warnings, errors };
835
+ }
836
+ cronExpression = `${minute} ${hour} ${normalizeCronList(monthDays.map(String))} ${normalizeCronList(months.map(String))} *`;
837
+ }
838
+ else {
839
+ errors.push(`Recurring task ${issue.slug} uses unsupported legacy recurrence frequency "${frequency}"; add .fidelios.yaml routines.${issue.slug}.triggers.`);
840
+ return { trigger: null, warnings, errors };
841
+ }
842
+ return {
843
+ trigger: {
844
+ kind: "schedule",
845
+ label: "Migrated legacy recurrence",
846
+ enabled: true,
847
+ cronExpression,
848
+ timezone,
849
+ signingMode: null,
850
+ replayWindowSec: null,
851
+ },
852
+ warnings,
853
+ errors,
854
+ };
855
+ }
856
+ function resolvePortableRoutineDefinition(issue, scheduleValue) {
857
+ const warnings = [];
858
+ const errors = [];
859
+ if (!issue.recurring) {
860
+ return { routine: null, warnings, errors };
861
+ }
862
+ const routine = issue.routine
863
+ ? {
864
+ concurrencyPolicy: issue.routine.concurrencyPolicy,
865
+ catchUpPolicy: issue.routine.catchUpPolicy,
866
+ triggers: [...issue.routine.triggers],
867
+ }
868
+ : {
869
+ concurrencyPolicy: null,
870
+ catchUpPolicy: null,
871
+ triggers: [],
872
+ };
873
+ if (routine.concurrencyPolicy && !ROUTINE_CONCURRENCY_POLICIES.includes(routine.concurrencyPolicy)) {
874
+ errors.push(`Recurring task ${issue.slug} uses unsupported routine concurrencyPolicy "${routine.concurrencyPolicy}".`);
875
+ }
876
+ if (routine.catchUpPolicy && !ROUTINE_CATCH_UP_POLICIES.includes(routine.catchUpPolicy)) {
877
+ errors.push(`Recurring task ${issue.slug} uses unsupported routine catchUpPolicy "${routine.catchUpPolicy}".`);
878
+ }
879
+ for (const trigger of routine.triggers) {
880
+ if (!ROUTINE_TRIGGER_KINDS.includes(trigger.kind)) {
881
+ errors.push(`Recurring task ${issue.slug} uses unsupported trigger kind "${trigger.kind}".`);
882
+ continue;
883
+ }
884
+ if (trigger.kind === "schedule") {
885
+ if (!trigger.cronExpression || !trigger.timezone) {
886
+ errors.push(`Recurring task ${issue.slug} has a schedule trigger missing cronExpression/timezone.`);
887
+ continue;
888
+ }
889
+ const cronError = validateCron(trigger.cronExpression);
890
+ if (cronError) {
891
+ errors.push(`Recurring task ${issue.slug} has an invalid schedule trigger: ${cronError}`);
892
+ }
893
+ continue;
894
+ }
895
+ if (trigger.kind === "webhook" && trigger.signingMode && !ROUTINE_TRIGGER_SIGNING_MODES.includes(trigger.signingMode)) {
896
+ errors.push(`Recurring task ${issue.slug} uses unsupported webhook signingMode "${trigger.signingMode}".`);
897
+ }
898
+ }
899
+ if (routine.triggers.length === 0 && issue.legacyRecurrence) {
900
+ const migrated = buildLegacyRoutineTriggerFromRecurrence(issue, scheduleValue);
901
+ warnings.push(...migrated.warnings);
902
+ errors.push(...migrated.errors);
903
+ if (migrated.trigger) {
904
+ routine.triggers.push(migrated.trigger);
905
+ }
906
+ }
907
+ return { routine, warnings, errors };
908
+ }
909
+ function toSafeSlug(input, fallback) {
910
+ return normalizeAgentUrlKey(input) ?? fallback;
911
+ }
912
+ function uniqueSlug(base, used) {
913
+ if (!used.has(base)) {
914
+ used.add(base);
915
+ return base;
916
+ }
917
+ let idx = 2;
918
+ while (true) {
919
+ const candidate = `${base}-${idx}`;
920
+ if (!used.has(candidate)) {
921
+ used.add(candidate);
922
+ return candidate;
923
+ }
924
+ idx += 1;
925
+ }
926
+ }
927
+ function uniqueNameBySlug(baseName, existingSlugs) {
928
+ const baseSlug = normalizeAgentUrlKey(baseName) ?? "agent";
929
+ if (!existingSlugs.has(baseSlug))
930
+ return baseName;
931
+ let idx = 2;
932
+ while (true) {
933
+ const candidateName = `${baseName} ${idx}`;
934
+ const candidateSlug = normalizeAgentUrlKey(candidateName) ?? `agent-${idx}`;
935
+ if (!existingSlugs.has(candidateSlug))
936
+ return candidateName;
937
+ idx += 1;
938
+ }
939
+ }
940
+ function uniqueProjectName(baseName, existingProjectSlugs) {
941
+ const baseSlug = deriveProjectUrlKey(baseName, baseName);
942
+ if (!existingProjectSlugs.has(baseSlug))
943
+ return baseName;
944
+ let idx = 2;
945
+ while (true) {
946
+ const candidateName = `${baseName} ${idx}`;
947
+ const candidateSlug = deriveProjectUrlKey(candidateName, candidateName);
948
+ if (!existingProjectSlugs.has(candidateSlug))
949
+ return candidateName;
950
+ idx += 1;
951
+ }
952
+ }
953
+ function normalizeInclude(input) {
954
+ return {
955
+ company: input?.company ?? DEFAULT_INCLUDE.company,
956
+ agents: input?.agents ?? DEFAULT_INCLUDE.agents,
957
+ projects: input?.projects ?? DEFAULT_INCLUDE.projects,
958
+ issues: input?.issues ?? DEFAULT_INCLUDE.issues,
959
+ skills: input?.skills ?? DEFAULT_INCLUDE.skills,
960
+ };
961
+ }
962
+ function normalizePortablePath(input) {
963
+ const normalized = input.replace(/\\/g, "/").replace(/^\.\/+/, "");
964
+ const parts = [];
965
+ for (const segment of normalized.split("/")) {
966
+ if (!segment || segment === ".")
967
+ continue;
968
+ if (segment === "..") {
969
+ if (parts.length > 0)
970
+ parts.pop();
971
+ continue;
972
+ }
973
+ parts.push(segment);
974
+ }
975
+ return parts.join("/");
976
+ }
977
+ function resolvePortablePath(fromPath, targetPath) {
978
+ const baseDir = path.posix.dirname(fromPath.replace(/\\/g, "/"));
979
+ return normalizePortablePath(path.posix.join(baseDir, targetPath.replace(/\\/g, "/")));
980
+ }
981
+ function isPortableBinaryFile(value) {
982
+ return typeof value === "object" && value !== null && value.encoding === "base64" && typeof value.data === "string";
983
+ }
984
+ function readPortableTextFile(files, filePath) {
985
+ const value = files[filePath];
986
+ return typeof value === "string" ? value : null;
987
+ }
988
+ function inferContentTypeFromPath(filePath) {
989
+ const extension = path.posix.extname(filePath).toLowerCase();
990
+ switch (extension) {
991
+ case ".gif":
992
+ return "image/gif";
993
+ case ".jpeg":
994
+ case ".jpg":
995
+ return "image/jpeg";
996
+ case ".png":
997
+ return "image/png";
998
+ case ".svg":
999
+ return "image/svg+xml";
1000
+ case ".webp":
1001
+ return "image/webp";
1002
+ default:
1003
+ return null;
1004
+ }
1005
+ }
1006
+ function resolveCompanyLogoExtension(contentType, originalFilename) {
1007
+ const fromContentType = contentType ? COMPANY_LOGO_CONTENT_TYPE_EXTENSIONS[contentType.toLowerCase()] : null;
1008
+ if (fromContentType)
1009
+ return fromContentType;
1010
+ const extension = originalFilename ? path.extname(originalFilename).toLowerCase() : "";
1011
+ return extension || ".png";
1012
+ }
1013
+ function portableBinaryFileToBuffer(entry) {
1014
+ return Buffer.from(entry.data, "base64");
1015
+ }
1016
+ function portableFileToBuffer(entry, filePath) {
1017
+ if (typeof entry === "string") {
1018
+ return Buffer.from(entry, "utf8");
1019
+ }
1020
+ if (isPortableBinaryFile(entry)) {
1021
+ return portableBinaryFileToBuffer(entry);
1022
+ }
1023
+ throw unprocessable(`Unsupported file entry encoding for ${filePath}`);
1024
+ }
1025
+ function bufferToPortableBinaryFile(buffer, contentType) {
1026
+ return {
1027
+ encoding: "base64",
1028
+ data: buffer.toString("base64"),
1029
+ contentType,
1030
+ };
1031
+ }
1032
+ async function streamToBuffer(stream) {
1033
+ const chunks = [];
1034
+ for await (const chunk of stream) {
1035
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
1036
+ }
1037
+ return Buffer.concat(chunks);
1038
+ }
1039
+ function normalizeFileMap(files, rootPath) {
1040
+ const normalizedRoot = rootPath ? normalizePortablePath(rootPath) : null;
1041
+ const out = {};
1042
+ for (const [rawPath, content] of Object.entries(files)) {
1043
+ let nextPath = normalizePortablePath(rawPath);
1044
+ if (normalizedRoot && nextPath === normalizedRoot) {
1045
+ continue;
1046
+ }
1047
+ if (normalizedRoot && nextPath.startsWith(`${normalizedRoot}/`)) {
1048
+ nextPath = nextPath.slice(normalizedRoot.length + 1);
1049
+ }
1050
+ if (!nextPath)
1051
+ continue;
1052
+ out[nextPath] = content;
1053
+ }
1054
+ return out;
1055
+ }
1056
+ function pickTextFiles(files) {
1057
+ const out = {};
1058
+ for (const [filePath, content] of Object.entries(files)) {
1059
+ if (typeof content === "string") {
1060
+ out[filePath] = content;
1061
+ }
1062
+ }
1063
+ return out;
1064
+ }
1065
+ function collectSelectedExportSlugs(selectedFiles) {
1066
+ const agents = new Set();
1067
+ const projects = new Set();
1068
+ const tasks = new Set();
1069
+ for (const filePath of selectedFiles) {
1070
+ const agentMatch = filePath.match(/^agents\/([^/]+)\//);
1071
+ if (agentMatch)
1072
+ agents.add(agentMatch[1]);
1073
+ const projectMatch = filePath.match(/^projects\/([^/]+)\//);
1074
+ if (projectMatch)
1075
+ projects.add(projectMatch[1]);
1076
+ const taskMatch = filePath.match(/^tasks\/([^/]+)\//);
1077
+ if (taskMatch)
1078
+ tasks.add(taskMatch[1]);
1079
+ }
1080
+ return { agents, projects, tasks, routines: new Set(tasks) };
1081
+ }
1082
+ function normalizePortableSlugList(value) {
1083
+ if (!Array.isArray(value))
1084
+ return [];
1085
+ const seen = new Set();
1086
+ const normalized = [];
1087
+ for (const entry of value) {
1088
+ if (typeof entry !== "string")
1089
+ continue;
1090
+ const trimmed = entry.trim();
1091
+ if (!trimmed || seen.has(trimmed))
1092
+ continue;
1093
+ seen.add(trimmed);
1094
+ normalized.push(trimmed);
1095
+ }
1096
+ return normalized;
1097
+ }
1098
+ function normalizePortableSidebarOrder(value) {
1099
+ if (!isPlainRecord(value))
1100
+ return null;
1101
+ const sidebar = {
1102
+ agents: normalizePortableSlugList(value.agents),
1103
+ projects: normalizePortableSlugList(value.projects),
1104
+ };
1105
+ return sidebar.agents.length > 0 || sidebar.projects.length > 0 ? sidebar : null;
1106
+ }
1107
+ function sortAgentsBySidebarOrder(agents) {
1108
+ if (agents.length === 0)
1109
+ return [];
1110
+ const byId = new Map(agents.map((agent) => [agent.id, agent]));
1111
+ const childrenOf = new Map();
1112
+ for (const agent of agents) {
1113
+ const parentId = agent.reportsTo && byId.has(agent.reportsTo) ? agent.reportsTo : null;
1114
+ const siblings = childrenOf.get(parentId) ?? [];
1115
+ siblings.push(agent);
1116
+ childrenOf.set(parentId, siblings);
1117
+ }
1118
+ for (const siblings of childrenOf.values()) {
1119
+ siblings.sort((left, right) => left.name.localeCompare(right.name));
1120
+ }
1121
+ const sorted = [];
1122
+ const queue = [...(childrenOf.get(null) ?? [])];
1123
+ while (queue.length > 0) {
1124
+ const agent = queue.shift();
1125
+ if (!agent)
1126
+ continue;
1127
+ sorted.push(agent);
1128
+ const children = childrenOf.get(agent.id);
1129
+ if (children)
1130
+ queue.push(...children);
1131
+ }
1132
+ return sorted;
1133
+ }
1134
+ function filterPortableExtensionYaml(yaml, selectedFiles) {
1135
+ const selected = collectSelectedExportSlugs(selectedFiles);
1136
+ const parsed = parseYamlFile(yaml);
1137
+ for (const section of ["agents", "projects", "tasks", "routines"]) {
1138
+ const sectionValue = parsed[section];
1139
+ if (!isPlainRecord(sectionValue))
1140
+ continue;
1141
+ const sectionSlugs = selected[section];
1142
+ const filteredEntries = Object.fromEntries(Object.entries(sectionValue).filter(([slug]) => sectionSlugs.has(slug)));
1143
+ if (Object.keys(filteredEntries).length > 0) {
1144
+ parsed[section] = filteredEntries;
1145
+ }
1146
+ else {
1147
+ delete parsed[section];
1148
+ }
1149
+ }
1150
+ const companySection = parsed.company;
1151
+ if (isPlainRecord(companySection)) {
1152
+ const logoPath = asString(companySection.logoPath) ?? asString(companySection.logo);
1153
+ if (logoPath && !selectedFiles.has(logoPath)) {
1154
+ delete companySection.logoPath;
1155
+ delete companySection.logo;
1156
+ }
1157
+ }
1158
+ const sidebarOrder = normalizePortableSidebarOrder(parsed.sidebar);
1159
+ if (sidebarOrder) {
1160
+ const filteredSidebar = stripEmptyValues({
1161
+ agents: sidebarOrder.agents.filter((slug) => selected.agents.has(slug)),
1162
+ projects: sidebarOrder.projects.filter((slug) => selected.projects.has(slug)),
1163
+ });
1164
+ if (isPlainRecord(filteredSidebar)) {
1165
+ parsed.sidebar = filteredSidebar;
1166
+ }
1167
+ else {
1168
+ delete parsed.sidebar;
1169
+ }
1170
+ }
1171
+ else {
1172
+ delete parsed.sidebar;
1173
+ }
1174
+ return buildYamlFile(parsed, { preserveEmptyStrings: true });
1175
+ }
1176
+ function filterExportFiles(files, selectedFilesInput, fideliosExtensionPath) {
1177
+ if (!selectedFilesInput || selectedFilesInput.length === 0) {
1178
+ return files;
1179
+ }
1180
+ const selectedFiles = new Set(selectedFilesInput
1181
+ .map((entry) => normalizePortablePath(entry))
1182
+ .filter((entry) => entry.length > 0));
1183
+ const filtered = {};
1184
+ for (const [filePath, content] of Object.entries(files)) {
1185
+ if (!selectedFiles.has(filePath))
1186
+ continue;
1187
+ filtered[filePath] = content;
1188
+ }
1189
+ const extensionEntry = filtered[fideliosExtensionPath];
1190
+ if (selectedFiles.has(fideliosExtensionPath) && typeof extensionEntry === "string") {
1191
+ filtered[fideliosExtensionPath] = filterPortableExtensionYaml(extensionEntry, selectedFiles);
1192
+ }
1193
+ return filtered;
1194
+ }
1195
+ function findFideliOSExtensionPath(files) {
1196
+ if (typeof files[".fidelios.yaml"] === "string")
1197
+ return ".fidelios.yaml";
1198
+ if (typeof files[".fidelios.yml"] === "string")
1199
+ return ".fidelios.yml";
1200
+ return Object.keys(files).find((entry) => entry.endsWith("/.fidelios.yaml") || entry.endsWith("/.fidelios.yml")) ?? null;
1201
+ }
1202
+ function ensureMarkdownPath(pathValue) {
1203
+ const normalized = pathValue.replace(/\\/g, "/");
1204
+ if (!normalized.endsWith(".md")) {
1205
+ throw unprocessable(`Manifest file path must end in .md: ${pathValue}`);
1206
+ }
1207
+ return normalized;
1208
+ }
1209
+ function normalizePortableConfig(value) {
1210
+ if (typeof value !== "object" || value === null || Array.isArray(value))
1211
+ return {};
1212
+ const input = value;
1213
+ const next = {};
1214
+ for (const [key, entry] of Object.entries(input)) {
1215
+ if (key === "cwd" ||
1216
+ key === "instructionsFilePath" ||
1217
+ key === "instructionsBundleMode" ||
1218
+ key === "instructionsRootPath" ||
1219
+ key === "instructionsEntryFile" ||
1220
+ key === "promptTemplate" ||
1221
+ key === "bootstrapPromptTemplate" || // deprecated — kept for backward compat
1222
+ key === "fideliosSkillSync")
1223
+ continue;
1224
+ if (key === "env")
1225
+ continue;
1226
+ next[key] = entry;
1227
+ }
1228
+ return next;
1229
+ }
1230
+ function isAbsoluteCommand(value) {
1231
+ return path.isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value);
1232
+ }
1233
+ function extractPortableEnvInputs(agentSlug, envValue, warnings) {
1234
+ if (!isPlainRecord(envValue))
1235
+ return [];
1236
+ const env = envValue;
1237
+ const inputs = [];
1238
+ for (const [key, binding] of Object.entries(env)) {
1239
+ if (key.toUpperCase() === "PATH") {
1240
+ warnings.push(`Agent ${agentSlug} PATH override was omitted from export because it is system-dependent.`);
1241
+ continue;
1242
+ }
1243
+ if (isPlainRecord(binding) && binding.type === "secret_ref") {
1244
+ inputs.push({
1245
+ key,
1246
+ description: `Provide ${key} for agent ${agentSlug}`,
1247
+ agentSlug,
1248
+ kind: "secret",
1249
+ requirement: "optional",
1250
+ defaultValue: "",
1251
+ portability: "portable",
1252
+ });
1253
+ continue;
1254
+ }
1255
+ if (isPlainRecord(binding) && binding.type === "plain") {
1256
+ const defaultValue = asString(binding.value);
1257
+ const isSensitive = isSensitiveEnvKey(key);
1258
+ const portability = defaultValue && isAbsoluteCommand(defaultValue)
1259
+ ? "system_dependent"
1260
+ : "portable";
1261
+ if (portability === "system_dependent") {
1262
+ warnings.push(`Agent ${agentSlug} env ${key} default was exported as system-dependent.`);
1263
+ }
1264
+ inputs.push({
1265
+ key,
1266
+ description: `Optional default for ${key} on agent ${agentSlug}`,
1267
+ agentSlug,
1268
+ kind: isSensitive ? "secret" : "plain",
1269
+ requirement: "optional",
1270
+ defaultValue: isSensitive ? "" : defaultValue ?? "",
1271
+ portability,
1272
+ });
1273
+ continue;
1274
+ }
1275
+ if (typeof binding === "string") {
1276
+ const portability = isAbsoluteCommand(binding) ? "system_dependent" : "portable";
1277
+ if (portability === "system_dependent") {
1278
+ warnings.push(`Agent ${agentSlug} env ${key} default was exported as system-dependent.`);
1279
+ }
1280
+ inputs.push({
1281
+ key,
1282
+ description: `Optional default for ${key} on agent ${agentSlug}`,
1283
+ agentSlug,
1284
+ kind: isSensitiveEnvKey(key) ? "secret" : "plain",
1285
+ requirement: "optional",
1286
+ defaultValue: binding,
1287
+ portability,
1288
+ });
1289
+ }
1290
+ }
1291
+ return inputs;
1292
+ }
1293
+ function jsonEqual(left, right) {
1294
+ return JSON.stringify(left) === JSON.stringify(right);
1295
+ }
1296
+ function isPathDefault(pathSegments, value, rules) {
1297
+ return rules.some((rule) => jsonEqual(rule.path, pathSegments) && jsonEqual(rule.value, value));
1298
+ }
1299
+ function pruneDefaultLikeValue(value, opts) {
1300
+ const pathSegments = opts.path ?? [];
1301
+ if (opts.defaultRules && isPathDefault(pathSegments, value, opts.defaultRules)) {
1302
+ return undefined;
1303
+ }
1304
+ if (Array.isArray(value)) {
1305
+ return value.map((entry) => pruneDefaultLikeValue(entry, { ...opts, path: pathSegments }));
1306
+ }
1307
+ if (isPlainRecord(value)) {
1308
+ const out = {};
1309
+ for (const [key, entry] of Object.entries(value)) {
1310
+ const next = pruneDefaultLikeValue(entry, {
1311
+ ...opts,
1312
+ path: [...pathSegments, key],
1313
+ });
1314
+ if (next === undefined)
1315
+ continue;
1316
+ out[key] = next;
1317
+ }
1318
+ return out;
1319
+ }
1320
+ if (value === undefined)
1321
+ return undefined;
1322
+ if (opts.dropFalseBooleans && value === false)
1323
+ return undefined;
1324
+ return value;
1325
+ }
1326
+ function renderYamlScalar(value) {
1327
+ if (value === null)
1328
+ return "null";
1329
+ if (typeof value === "boolean" || typeof value === "number")
1330
+ return String(value);
1331
+ if (typeof value === "string")
1332
+ return JSON.stringify(value);
1333
+ return JSON.stringify(value);
1334
+ }
1335
+ function isEmptyObject(value) {
1336
+ return isPlainRecord(value) && Object.keys(value).length === 0;
1337
+ }
1338
+ function isEmptyArray(value) {
1339
+ return Array.isArray(value) && value.length === 0;
1340
+ }
1341
+ function stripEmptyValues(value, opts) {
1342
+ if (Array.isArray(value)) {
1343
+ const next = value
1344
+ .map((entry) => stripEmptyValues(entry, opts))
1345
+ .filter((entry) => entry !== undefined);
1346
+ return next.length > 0 ? next : undefined;
1347
+ }
1348
+ if (isPlainRecord(value)) {
1349
+ const next = {};
1350
+ for (const [key, entry] of Object.entries(value)) {
1351
+ const cleaned = stripEmptyValues(entry, opts);
1352
+ if (cleaned === undefined)
1353
+ continue;
1354
+ next[key] = cleaned;
1355
+ }
1356
+ return Object.keys(next).length > 0 ? next : undefined;
1357
+ }
1358
+ if (value === undefined ||
1359
+ value === null ||
1360
+ (!opts?.preserveEmptyStrings && value === "") ||
1361
+ isEmptyArray(value) ||
1362
+ isEmptyObject(value)) {
1363
+ return undefined;
1364
+ }
1365
+ return value;
1366
+ }
1367
+ const YAML_KEY_PRIORITY = [
1368
+ "name",
1369
+ "description",
1370
+ "title",
1371
+ "schema",
1372
+ "kind",
1373
+ "slug",
1374
+ "reportsTo",
1375
+ "skills",
1376
+ "owner",
1377
+ "assignee",
1378
+ "project",
1379
+ "schedule",
1380
+ "version",
1381
+ "license",
1382
+ "authors",
1383
+ "homepage",
1384
+ "tags",
1385
+ "includes",
1386
+ "requirements",
1387
+ "role",
1388
+ "icon",
1389
+ "capabilities",
1390
+ "brandColor",
1391
+ "logoPath",
1392
+ "adapter",
1393
+ "runtime",
1394
+ "permissions",
1395
+ "budgetMonthlyCents",
1396
+ "metadata",
1397
+ ];
1398
+ const YAML_KEY_PRIORITY_INDEX = new Map(YAML_KEY_PRIORITY.map((key, index) => [key, index]));
1399
+ function compareYamlKeys(left, right) {
1400
+ const leftPriority = YAML_KEY_PRIORITY_INDEX.get(left);
1401
+ const rightPriority = YAML_KEY_PRIORITY_INDEX.get(right);
1402
+ if (leftPriority !== undefined || rightPriority !== undefined) {
1403
+ if (leftPriority === undefined)
1404
+ return 1;
1405
+ if (rightPriority === undefined)
1406
+ return -1;
1407
+ if (leftPriority !== rightPriority)
1408
+ return leftPriority - rightPriority;
1409
+ }
1410
+ return left.localeCompare(right);
1411
+ }
1412
+ function orderedYamlEntries(value) {
1413
+ return Object.entries(value).sort(([leftKey], [rightKey]) => compareYamlKeys(leftKey, rightKey));
1414
+ }
1415
+ function renderYamlBlock(value, indentLevel) {
1416
+ const indent = " ".repeat(indentLevel);
1417
+ if (Array.isArray(value)) {
1418
+ if (value.length === 0)
1419
+ return [`${indent}[]`];
1420
+ const lines = [];
1421
+ for (const entry of value) {
1422
+ const scalar = entry === null ||
1423
+ typeof entry === "string" ||
1424
+ typeof entry === "boolean" ||
1425
+ typeof entry === "number" ||
1426
+ Array.isArray(entry) && entry.length === 0 ||
1427
+ isEmptyObject(entry);
1428
+ if (scalar) {
1429
+ lines.push(`${indent}- ${renderYamlScalar(entry)}`);
1430
+ continue;
1431
+ }
1432
+ lines.push(`${indent}-`);
1433
+ lines.push(...renderYamlBlock(entry, indentLevel + 1));
1434
+ }
1435
+ return lines;
1436
+ }
1437
+ if (isPlainRecord(value)) {
1438
+ const entries = orderedYamlEntries(value);
1439
+ if (entries.length === 0)
1440
+ return [`${indent}{}`];
1441
+ const lines = [];
1442
+ for (const [key, entry] of entries) {
1443
+ const scalar = entry === null ||
1444
+ typeof entry === "string" ||
1445
+ typeof entry === "boolean" ||
1446
+ typeof entry === "number" ||
1447
+ Array.isArray(entry) && entry.length === 0 ||
1448
+ isEmptyObject(entry);
1449
+ if (scalar) {
1450
+ lines.push(`${indent}${key}: ${renderYamlScalar(entry)}`);
1451
+ continue;
1452
+ }
1453
+ lines.push(`${indent}${key}:`);
1454
+ lines.push(...renderYamlBlock(entry, indentLevel + 1));
1455
+ }
1456
+ return lines;
1457
+ }
1458
+ return [`${indent}${renderYamlScalar(value)}`];
1459
+ }
1460
+ function renderFrontmatter(frontmatter) {
1461
+ const lines = ["---"];
1462
+ for (const [key, value] of orderedYamlEntries(frontmatter)) {
1463
+ // Skip null/undefined values — don't export empty fields
1464
+ if (value === null || value === undefined)
1465
+ continue;
1466
+ const scalar = typeof value === "string" ||
1467
+ typeof value === "boolean" ||
1468
+ typeof value === "number" ||
1469
+ Array.isArray(value) && value.length === 0 ||
1470
+ isEmptyObject(value);
1471
+ if (scalar) {
1472
+ lines.push(`${key}: ${renderYamlScalar(value)}`);
1473
+ continue;
1474
+ }
1475
+ lines.push(`${key}:`);
1476
+ lines.push(...renderYamlBlock(value, 1));
1477
+ }
1478
+ lines.push("---");
1479
+ return `${lines.join("\n")}\n`;
1480
+ }
1481
+ function buildMarkdown(frontmatter, body) {
1482
+ const cleanBody = body.replace(/\r\n/g, "\n").trim();
1483
+ if (!cleanBody) {
1484
+ return `${renderFrontmatter(frontmatter)}\n`;
1485
+ }
1486
+ return `${renderFrontmatter(frontmatter)}\n${cleanBody}\n`;
1487
+ }
1488
+ function normalizeSelectedFiles(selectedFiles) {
1489
+ if (!selectedFiles)
1490
+ return null;
1491
+ return new Set(selectedFiles
1492
+ .map((entry) => normalizePortablePath(entry))
1493
+ .filter((entry) => entry.length > 0));
1494
+ }
1495
+ function filterCompanyMarkdownIncludes(companyPath, markdown, selectedFiles) {
1496
+ const parsed = parseFrontmatterMarkdown(markdown);
1497
+ const includeEntries = readIncludeEntries(parsed.frontmatter);
1498
+ const filteredIncludes = includeEntries.filter((entry) => selectedFiles.has(resolvePortablePath(companyPath, entry.path)));
1499
+ const nextFrontmatter = { ...parsed.frontmatter };
1500
+ if (filteredIncludes.length > 0) {
1501
+ nextFrontmatter.includes = filteredIncludes.map((entry) => entry.path);
1502
+ }
1503
+ else {
1504
+ delete nextFrontmatter.includes;
1505
+ }
1506
+ return buildMarkdown(nextFrontmatter, parsed.body);
1507
+ }
1508
+ function applySelectedFilesToSource(source, selectedFiles) {
1509
+ const normalizedSelection = normalizeSelectedFiles(selectedFiles);
1510
+ if (!normalizedSelection)
1511
+ return source;
1512
+ const companyPath = source.manifest.company
1513
+ ? ensureMarkdownPath(source.manifest.company.path)
1514
+ : Object.keys(source.files).find((entry) => entry.endsWith("/COMPANY.md") || entry === "COMPANY.md") ?? null;
1515
+ if (!companyPath) {
1516
+ throw unprocessable("Company package is missing COMPANY.md");
1517
+ }
1518
+ const companyMarkdown = source.files[companyPath];
1519
+ if (typeof companyMarkdown !== "string") {
1520
+ throw unprocessable("Company package is missing COMPANY.md");
1521
+ }
1522
+ const effectiveFiles = {};
1523
+ for (const [filePath, content] of Object.entries(source.files)) {
1524
+ const normalizedPath = normalizePortablePath(filePath);
1525
+ if (!normalizedSelection.has(normalizedPath))
1526
+ continue;
1527
+ effectiveFiles[normalizedPath] = content;
1528
+ }
1529
+ effectiveFiles[companyPath] = filterCompanyMarkdownIncludes(companyPath, companyMarkdown, normalizedSelection);
1530
+ const filtered = buildManifestFromPackageFiles(effectiveFiles, {
1531
+ sourceLabel: source.manifest.source,
1532
+ });
1533
+ if (!normalizedSelection.has(companyPath)) {
1534
+ filtered.manifest.company = null;
1535
+ }
1536
+ filtered.manifest.includes = {
1537
+ company: filtered.manifest.company !== null,
1538
+ agents: filtered.manifest.agents.length > 0,
1539
+ projects: filtered.manifest.projects.length > 0,
1540
+ issues: filtered.manifest.issues.length > 0,
1541
+ skills: filtered.manifest.skills.length > 0,
1542
+ };
1543
+ return filtered;
1544
+ }
1545
+ async function resolveBundledSkillsCommit() {
1546
+ if (!bundledSkillsCommitPromise) {
1547
+ bundledSkillsCommitPromise = execFileAsync("git", ["rev-parse", "HEAD"], {
1548
+ cwd: process.cwd(),
1549
+ encoding: "utf8",
1550
+ })
1551
+ .then(({ stdout }) => stdout.trim() || null)
1552
+ .catch(() => null);
1553
+ }
1554
+ return bundledSkillsCommitPromise;
1555
+ }
1556
+ async function buildSkillSourceEntry(skill) {
1557
+ const metadata = isPlainRecord(skill.metadata) ? skill.metadata : null;
1558
+ if (asString(metadata?.sourceKind) === "fidelios_bundled") {
1559
+ const commit = await resolveBundledSkillsCommit();
1560
+ return {
1561
+ kind: "github-dir",
1562
+ repo: "maxzemtsov/fidelios",
1563
+ path: `skills/${skill.slug}`,
1564
+ commit,
1565
+ trackingRef: "master",
1566
+ url: `https://github.com/maxzemtsov/fidelios/tree/master/skills/${skill.slug}`,
1567
+ };
1568
+ }
1569
+ if (skill.sourceType === "github" || skill.sourceType === "skills_sh") {
1570
+ const owner = asString(metadata?.owner);
1571
+ const repo = asString(metadata?.repo);
1572
+ const repoSkillDir = asString(metadata?.repoSkillDir);
1573
+ if (!owner || !repo || !repoSkillDir)
1574
+ return null;
1575
+ return {
1576
+ kind: "github-dir",
1577
+ repo: `${owner}/${repo}`,
1578
+ path: repoSkillDir,
1579
+ commit: skill.sourceRef ?? null,
1580
+ trackingRef: asString(metadata?.trackingRef),
1581
+ url: skill.sourceLocator,
1582
+ };
1583
+ }
1584
+ if (skill.sourceType === "url" && skill.sourceLocator) {
1585
+ return {
1586
+ kind: "url",
1587
+ url: skill.sourceLocator,
1588
+ };
1589
+ }
1590
+ return null;
1591
+ }
1592
+ function shouldReferenceSkillOnExport(skill, expandReferencedSkills) {
1593
+ if (expandReferencedSkills)
1594
+ return false;
1595
+ const metadata = isPlainRecord(skill.metadata) ? skill.metadata : null;
1596
+ if (asString(metadata?.sourceKind) === "fidelios_bundled")
1597
+ return true;
1598
+ return skill.sourceType === "github" || skill.sourceType === "skills_sh" || skill.sourceType === "url";
1599
+ }
1600
+ async function buildReferencedSkillMarkdown(skill) {
1601
+ const sourceEntry = await buildSkillSourceEntry(skill);
1602
+ const frontmatter = {
1603
+ key: skill.key,
1604
+ slug: skill.slug,
1605
+ name: skill.name,
1606
+ description: skill.description ?? null,
1607
+ };
1608
+ if (sourceEntry) {
1609
+ frontmatter.metadata = {
1610
+ sources: [sourceEntry],
1611
+ };
1612
+ }
1613
+ return buildMarkdown(frontmatter, "");
1614
+ }
1615
+ async function withSkillSourceMetadata(skill, markdown) {
1616
+ const sourceEntry = await buildSkillSourceEntry(skill);
1617
+ const parsed = parseFrontmatterMarkdown(markdown);
1618
+ const metadata = isPlainRecord(parsed.frontmatter.metadata)
1619
+ ? { ...parsed.frontmatter.metadata }
1620
+ : {};
1621
+ const existingSources = Array.isArray(metadata.sources)
1622
+ ? metadata.sources.filter((entry) => isPlainRecord(entry))
1623
+ : [];
1624
+ if (sourceEntry) {
1625
+ metadata.sources = [...existingSources, sourceEntry];
1626
+ }
1627
+ metadata.skillKey = skill.key;
1628
+ metadata.fideliosSkillKey = skill.key;
1629
+ metadata.fidelios = {
1630
+ ...(isPlainRecord(metadata.fidelios) ? metadata.fidelios : {}),
1631
+ skillKey: skill.key,
1632
+ slug: skill.slug,
1633
+ };
1634
+ const frontmatter = {
1635
+ ...parsed.frontmatter,
1636
+ key: skill.key,
1637
+ slug: skill.slug,
1638
+ metadata,
1639
+ };
1640
+ return buildMarkdown(frontmatter, parsed.body);
1641
+ }
1642
+ function parseYamlScalar(rawValue) {
1643
+ const trimmed = rawValue.trim();
1644
+ if (trimmed === "")
1645
+ return "";
1646
+ if (trimmed === "null" || trimmed === "~")
1647
+ return null;
1648
+ if (trimmed === "true")
1649
+ return true;
1650
+ if (trimmed === "false")
1651
+ return false;
1652
+ if (trimmed === "[]")
1653
+ return [];
1654
+ if (trimmed === "{}")
1655
+ return {};
1656
+ if (/^-?\d+(\.\d+)?$/.test(trimmed))
1657
+ return Number(trimmed);
1658
+ if (trimmed.startsWith("\"") ||
1659
+ trimmed.startsWith("[") ||
1660
+ trimmed.startsWith("{")) {
1661
+ try {
1662
+ return JSON.parse(trimmed);
1663
+ }
1664
+ catch {
1665
+ return trimmed;
1666
+ }
1667
+ }
1668
+ return trimmed;
1669
+ }
1670
+ function prepareYamlLines(raw) {
1671
+ return raw
1672
+ .split("\n")
1673
+ .map((line) => ({
1674
+ indent: line.match(/^ */)?.[0].length ?? 0,
1675
+ content: line.trim(),
1676
+ }))
1677
+ .filter((line) => line.content.length > 0 && !line.content.startsWith("#"));
1678
+ }
1679
+ function parseYamlBlock(lines, startIndex, indentLevel) {
1680
+ let index = startIndex;
1681
+ while (index < lines.length && lines[index].content.length === 0) {
1682
+ index += 1;
1683
+ }
1684
+ if (index >= lines.length || lines[index].indent < indentLevel) {
1685
+ return { value: {}, nextIndex: index };
1686
+ }
1687
+ const isArray = lines[index].indent === indentLevel && lines[index].content.startsWith("-");
1688
+ if (isArray) {
1689
+ const values = [];
1690
+ while (index < lines.length) {
1691
+ const line = lines[index];
1692
+ if (line.indent < indentLevel)
1693
+ break;
1694
+ if (line.indent !== indentLevel || !line.content.startsWith("-"))
1695
+ break;
1696
+ const remainder = line.content.slice(1).trim();
1697
+ index += 1;
1698
+ if (!remainder) {
1699
+ const nested = parseYamlBlock(lines, index, indentLevel + 2);
1700
+ values.push(nested.value);
1701
+ index = nested.nextIndex;
1702
+ continue;
1703
+ }
1704
+ const inlineObjectSeparator = remainder.indexOf(":");
1705
+ if (inlineObjectSeparator > 0 &&
1706
+ !remainder.startsWith("\"") &&
1707
+ !remainder.startsWith("{") &&
1708
+ !remainder.startsWith("[")) {
1709
+ const key = remainder.slice(0, inlineObjectSeparator).trim();
1710
+ const rawValue = remainder.slice(inlineObjectSeparator + 1).trim();
1711
+ const nextObject = {
1712
+ [key]: parseYamlScalar(rawValue),
1713
+ };
1714
+ if (index < lines.length && lines[index].indent > indentLevel) {
1715
+ const nested = parseYamlBlock(lines, index, indentLevel + 2);
1716
+ if (isPlainRecord(nested.value)) {
1717
+ Object.assign(nextObject, nested.value);
1718
+ }
1719
+ index = nested.nextIndex;
1720
+ }
1721
+ values.push(nextObject);
1722
+ continue;
1723
+ }
1724
+ values.push(parseYamlScalar(remainder));
1725
+ }
1726
+ return { value: values, nextIndex: index };
1727
+ }
1728
+ const record = {};
1729
+ while (index < lines.length) {
1730
+ const line = lines[index];
1731
+ if (line.indent < indentLevel)
1732
+ break;
1733
+ if (line.indent !== indentLevel) {
1734
+ index += 1;
1735
+ continue;
1736
+ }
1737
+ const separatorIndex = line.content.indexOf(":");
1738
+ if (separatorIndex <= 0) {
1739
+ index += 1;
1740
+ continue;
1741
+ }
1742
+ const key = line.content.slice(0, separatorIndex).trim();
1743
+ const remainder = line.content.slice(separatorIndex + 1).trim();
1744
+ index += 1;
1745
+ if (!remainder) {
1746
+ const nested = parseYamlBlock(lines, index, indentLevel + 2);
1747
+ record[key] = nested.value;
1748
+ index = nested.nextIndex;
1749
+ continue;
1750
+ }
1751
+ record[key] = parseYamlScalar(remainder);
1752
+ }
1753
+ return { value: record, nextIndex: index };
1754
+ }
1755
+ function parseYamlFrontmatter(raw) {
1756
+ const prepared = prepareYamlLines(raw);
1757
+ if (prepared.length === 0)
1758
+ return {};
1759
+ const parsed = parseYamlBlock(prepared, 0, prepared[0].indent);
1760
+ return isPlainRecord(parsed.value) ? parsed.value : {};
1761
+ }
1762
+ function parseYamlFile(raw) {
1763
+ return parseYamlFrontmatter(raw);
1764
+ }
1765
+ function buildYamlFile(value, opts) {
1766
+ const cleaned = stripEmptyValues(value, opts);
1767
+ if (!isPlainRecord(cleaned))
1768
+ return "{}\n";
1769
+ return renderYamlBlock(cleaned, 0).join("\n") + "\n";
1770
+ }
1771
+ function parseFrontmatterMarkdown(raw) {
1772
+ const normalized = raw.replace(/\r\n/g, "\n");
1773
+ if (!normalized.startsWith("---\n")) {
1774
+ return { frontmatter: {}, body: normalized.trim() };
1775
+ }
1776
+ const closing = normalized.indexOf("\n---\n", 4);
1777
+ if (closing < 0) {
1778
+ return { frontmatter: {}, body: normalized.trim() };
1779
+ }
1780
+ const frontmatterRaw = normalized.slice(4, closing).trim();
1781
+ const body = normalized.slice(closing + 5).trim();
1782
+ return {
1783
+ frontmatter: parseYamlFrontmatter(frontmatterRaw),
1784
+ body,
1785
+ };
1786
+ }
1787
+ async function fetchText(url) {
1788
+ const response = await fetch(url);
1789
+ if (!response.ok) {
1790
+ throw unprocessable(`Failed to fetch ${url}: ${response.status}`);
1791
+ }
1792
+ return response.text();
1793
+ }
1794
+ async function fetchOptionalText(url) {
1795
+ const response = await fetch(url);
1796
+ if (response.status === 404)
1797
+ return null;
1798
+ if (!response.ok) {
1799
+ throw unprocessable(`Failed to fetch ${url}: ${response.status}`);
1800
+ }
1801
+ return response.text();
1802
+ }
1803
+ async function fetchBinary(url) {
1804
+ const response = await fetch(url);
1805
+ if (!response.ok) {
1806
+ throw unprocessable(`Failed to fetch ${url}: ${response.status}`);
1807
+ }
1808
+ return Buffer.from(await response.arrayBuffer());
1809
+ }
1810
+ async function fetchJson(url) {
1811
+ const response = await fetch(url, {
1812
+ headers: {
1813
+ accept: "application/vnd.github+json",
1814
+ },
1815
+ });
1816
+ if (!response.ok) {
1817
+ throw unprocessable(`Failed to fetch ${url}: ${response.status}`);
1818
+ }
1819
+ return response.json();
1820
+ }
1821
+ function dedupeEnvInputs(values) {
1822
+ const seen = new Set();
1823
+ const out = [];
1824
+ for (const value of values) {
1825
+ const key = `${value.agentSlug ?? ""}:${value.key.toUpperCase()}`;
1826
+ if (seen.has(key))
1827
+ continue;
1828
+ seen.add(key);
1829
+ out.push(value);
1830
+ }
1831
+ return out;
1832
+ }
1833
+ function buildEnvInputMap(inputs) {
1834
+ const env = {};
1835
+ for (const input of inputs) {
1836
+ const entry = {
1837
+ kind: input.kind,
1838
+ requirement: input.requirement,
1839
+ };
1840
+ if (input.defaultValue !== null)
1841
+ entry.default = input.defaultValue;
1842
+ if (input.description)
1843
+ entry.description = input.description;
1844
+ if (input.portability === "system_dependent")
1845
+ entry.portability = "system_dependent";
1846
+ env[input.key] = entry;
1847
+ }
1848
+ return env;
1849
+ }
1850
+ function readCompanyApprovalDefault(_frontmatter) {
1851
+ return true;
1852
+ }
1853
+ function readIncludeEntries(frontmatter) {
1854
+ const includes = frontmatter.includes;
1855
+ if (!Array.isArray(includes))
1856
+ return [];
1857
+ return includes.flatMap((entry) => {
1858
+ if (typeof entry === "string") {
1859
+ return [{ path: entry }];
1860
+ }
1861
+ if (isPlainRecord(entry)) {
1862
+ const pathValue = asString(entry.path);
1863
+ return pathValue ? [{ path: pathValue }] : [];
1864
+ }
1865
+ return [];
1866
+ });
1867
+ }
1868
+ function readAgentEnvInputs(extension, agentSlug) {
1869
+ const inputs = isPlainRecord(extension.inputs) ? extension.inputs : null;
1870
+ const env = inputs && isPlainRecord(inputs.env) ? inputs.env : null;
1871
+ if (!env)
1872
+ return [];
1873
+ return Object.entries(env).flatMap(([key, value]) => {
1874
+ if (!isPlainRecord(value))
1875
+ return [];
1876
+ const record = value;
1877
+ return [{
1878
+ key,
1879
+ description: asString(record.description) ?? null,
1880
+ agentSlug,
1881
+ kind: record.kind === "plain" ? "plain" : "secret",
1882
+ requirement: record.requirement === "required" ? "required" : "optional",
1883
+ defaultValue: typeof record.default === "string" ? record.default : null,
1884
+ portability: record.portability === "system_dependent" ? "system_dependent" : "portable",
1885
+ }];
1886
+ });
1887
+ }
1888
+ function readAgentSkillRefs(frontmatter) {
1889
+ const skills = frontmatter.skills;
1890
+ if (!Array.isArray(skills))
1891
+ return [];
1892
+ return Array.from(new Set(skills
1893
+ .filter((entry) => typeof entry === "string")
1894
+ .map((entry) => normalizeSkillKey(entry) ?? entry.trim())
1895
+ .filter(Boolean)));
1896
+ }
1897
+ function buildManifestFromPackageFiles(files, opts) {
1898
+ const normalizedFiles = normalizeFileMap(files);
1899
+ const companyPath = typeof normalizedFiles["COMPANY.md"] === "string"
1900
+ ? normalizedFiles["COMPANY.md"]
1901
+ : undefined;
1902
+ const resolvedCompanyPath = companyPath !== undefined
1903
+ ? "COMPANY.md"
1904
+ : Object.keys(normalizedFiles).find((entry) => entry.endsWith("/COMPANY.md") || entry === "COMPANY.md");
1905
+ if (!resolvedCompanyPath) {
1906
+ throw unprocessable("Company package is missing COMPANY.md");
1907
+ }
1908
+ const companyMarkdown = readPortableTextFile(normalizedFiles, resolvedCompanyPath);
1909
+ if (typeof companyMarkdown !== "string") {
1910
+ throw unprocessable(`Company package file is not readable as text: ${resolvedCompanyPath}`);
1911
+ }
1912
+ const companyDoc = parseFrontmatterMarkdown(companyMarkdown);
1913
+ const companyFrontmatter = companyDoc.frontmatter;
1914
+ const fideliosExtensionPath = findFideliOSExtensionPath(normalizedFiles);
1915
+ const fideliosExtension = fideliosExtensionPath
1916
+ ? parseYamlFile(readPortableTextFile(normalizedFiles, fideliosExtensionPath) ?? "")
1917
+ : {};
1918
+ const fideliosCompany = isPlainRecord(fideliosExtension.company) ? fideliosExtension.company : {};
1919
+ const fideliosSidebar = normalizePortableSidebarOrder(fideliosExtension.sidebar);
1920
+ const fideliosAgents = isPlainRecord(fideliosExtension.agents) ? fideliosExtension.agents : {};
1921
+ const fideliosProjects = isPlainRecord(fideliosExtension.projects) ? fideliosExtension.projects : {};
1922
+ const fideliosTasks = isPlainRecord(fideliosExtension.tasks) ? fideliosExtension.tasks : {};
1923
+ const fideliosRoutines = isPlainRecord(fideliosExtension.routines) ? fideliosExtension.routines : {};
1924
+ const companyName = asString(companyFrontmatter.name)
1925
+ ?? opts?.sourceLabel?.companyName
1926
+ ?? "Imported Company";
1927
+ const companySlug = asString(companyFrontmatter.slug)
1928
+ ?? normalizeAgentUrlKey(companyName)
1929
+ ?? "company";
1930
+ const includeEntries = readIncludeEntries(companyFrontmatter);
1931
+ const referencedAgentPaths = includeEntries
1932
+ .map((entry) => resolvePortablePath(resolvedCompanyPath, entry.path))
1933
+ .filter((entry) => entry.endsWith("/AGENTS.md") || entry === "AGENTS.md");
1934
+ const referencedProjectPaths = includeEntries
1935
+ .map((entry) => resolvePortablePath(resolvedCompanyPath, entry.path))
1936
+ .filter((entry) => entry.endsWith("/PROJECT.md") || entry === "PROJECT.md");
1937
+ const referencedTaskPaths = includeEntries
1938
+ .map((entry) => resolvePortablePath(resolvedCompanyPath, entry.path))
1939
+ .filter((entry) => entry.endsWith("/TASK.md") || entry === "TASK.md");
1940
+ const referencedSkillPaths = includeEntries
1941
+ .map((entry) => resolvePortablePath(resolvedCompanyPath, entry.path))
1942
+ .filter((entry) => entry.endsWith("/SKILL.md") || entry === "SKILL.md");
1943
+ const discoveredAgentPaths = Object.keys(normalizedFiles).filter((entry) => entry.endsWith("/AGENTS.md") || entry === "AGENTS.md");
1944
+ const discoveredProjectPaths = Object.keys(normalizedFiles).filter((entry) => entry.endsWith("/PROJECT.md") || entry === "PROJECT.md");
1945
+ const discoveredTaskPaths = Object.keys(normalizedFiles).filter((entry) => entry.endsWith("/TASK.md") || entry === "TASK.md");
1946
+ const discoveredSkillPaths = Object.keys(normalizedFiles).filter((entry) => entry.endsWith("/SKILL.md") || entry === "SKILL.md");
1947
+ const agentPaths = Array.from(new Set([...referencedAgentPaths, ...discoveredAgentPaths])).sort();
1948
+ const projectPaths = Array.from(new Set([...referencedProjectPaths, ...discoveredProjectPaths])).sort();
1949
+ const taskPaths = Array.from(new Set([...referencedTaskPaths, ...discoveredTaskPaths])).sort();
1950
+ const skillPaths = Array.from(new Set([...referencedSkillPaths, ...discoveredSkillPaths])).sort();
1951
+ const manifest = {
1952
+ schemaVersion: 4,
1953
+ generatedAt: new Date().toISOString(),
1954
+ source: opts?.sourceLabel ?? null,
1955
+ includes: {
1956
+ company: true,
1957
+ agents: true,
1958
+ projects: projectPaths.length > 0,
1959
+ issues: taskPaths.length > 0,
1960
+ skills: skillPaths.length > 0,
1961
+ },
1962
+ company: {
1963
+ path: resolvedCompanyPath,
1964
+ name: companyName,
1965
+ description: asString(companyFrontmatter.description),
1966
+ brandColor: asString(fideliosCompany.brandColor),
1967
+ logoPath: asString(fideliosCompany.logoPath) ?? asString(fideliosCompany.logo),
1968
+ requireBoardApprovalForNewAgents: typeof fideliosCompany.requireBoardApprovalForNewAgents === "boolean"
1969
+ ? fideliosCompany.requireBoardApprovalForNewAgents
1970
+ : readCompanyApprovalDefault(companyFrontmatter),
1971
+ },
1972
+ sidebar: fideliosSidebar,
1973
+ agents: [],
1974
+ skills: [],
1975
+ projects: [],
1976
+ issues: [],
1977
+ envInputs: [],
1978
+ };
1979
+ const warnings = [];
1980
+ if (manifest.company?.logoPath && !normalizedFiles[manifest.company.logoPath]) {
1981
+ warnings.push(`Referenced company logo file is missing from package: ${manifest.company.logoPath}`);
1982
+ }
1983
+ for (const agentPath of agentPaths) {
1984
+ const markdownRaw = readPortableTextFile(normalizedFiles, agentPath);
1985
+ if (typeof markdownRaw !== "string") {
1986
+ warnings.push(`Referenced agent file is missing from package: ${agentPath}`);
1987
+ continue;
1988
+ }
1989
+ const agentDoc = parseFrontmatterMarkdown(markdownRaw);
1990
+ const frontmatter = agentDoc.frontmatter;
1991
+ const fallbackSlug = normalizeAgentUrlKey(path.posix.basename(path.posix.dirname(agentPath))) ?? "agent";
1992
+ const slug = asString(frontmatter.slug) ?? fallbackSlug;
1993
+ const extension = isPlainRecord(fideliosAgents[slug]) ? fideliosAgents[slug] : {};
1994
+ const extensionAdapter = isPlainRecord(extension.adapter) ? extension.adapter : null;
1995
+ const extensionRuntime = isPlainRecord(extension.runtime) ? extension.runtime : null;
1996
+ const extensionPermissions = isPlainRecord(extension.permissions) ? extension.permissions : null;
1997
+ const extensionMetadata = isPlainRecord(extension.metadata) ? extension.metadata : null;
1998
+ const adapterConfig = isPlainRecord(extensionAdapter?.config)
1999
+ ? extensionAdapter.config
2000
+ : {};
2001
+ const runtimeConfig = extensionRuntime ?? {};
2002
+ const title = asString(frontmatter.title);
2003
+ manifest.agents.push({
2004
+ slug,
2005
+ name: asString(frontmatter.name) ?? title ?? slug,
2006
+ path: agentPath,
2007
+ skills: readAgentSkillRefs(frontmatter),
2008
+ role: asString(extension.role) ?? "agent",
2009
+ title,
2010
+ icon: asString(extension.icon),
2011
+ capabilities: asString(extension.capabilities),
2012
+ reportsToSlug: asString(frontmatter.reportsTo) ?? asString(extension.reportsTo),
2013
+ adapterType: asString(extensionAdapter?.type) ?? "process",
2014
+ adapterConfig,
2015
+ runtimeConfig,
2016
+ permissions: extensionPermissions ?? {},
2017
+ budgetMonthlyCents: typeof extension.budgetMonthlyCents === "number" && Number.isFinite(extension.budgetMonthlyCents)
2018
+ ? Math.max(0, Math.floor(extension.budgetMonthlyCents))
2019
+ : 0,
2020
+ metadata: extensionMetadata,
2021
+ });
2022
+ manifest.envInputs.push(...readAgentEnvInputs(extension, slug));
2023
+ if (frontmatter.kind && frontmatter.kind !== "agent") {
2024
+ warnings.push(`Agent markdown ${agentPath} does not declare kind: agent in frontmatter.`);
2025
+ }
2026
+ }
2027
+ for (const skillPath of skillPaths) {
2028
+ const markdownRaw = readPortableTextFile(normalizedFiles, skillPath);
2029
+ if (typeof markdownRaw !== "string") {
2030
+ warnings.push(`Referenced skill file is missing from package: ${skillPath}`);
2031
+ continue;
2032
+ }
2033
+ const skillDoc = parseFrontmatterMarkdown(markdownRaw);
2034
+ const frontmatter = skillDoc.frontmatter;
2035
+ const skillDir = path.posix.dirname(skillPath);
2036
+ const fallbackSlug = normalizeAgentUrlKey(path.posix.basename(skillDir)) ?? "skill";
2037
+ const slug = asString(frontmatter.slug) ?? normalizeAgentUrlKey(asString(frontmatter.name) ?? "") ?? fallbackSlug;
2038
+ const inventory = Object.keys(normalizedFiles)
2039
+ .filter((entry) => entry === skillPath || entry.startsWith(`${skillDir}/`))
2040
+ .map((entry) => ({
2041
+ path: entry === skillPath ? "SKILL.md" : entry.slice(skillDir.length + 1),
2042
+ kind: entry === skillPath
2043
+ ? "skill"
2044
+ : entry.startsWith(`${skillDir}/references/`)
2045
+ ? "reference"
2046
+ : entry.startsWith(`${skillDir}/scripts/`)
2047
+ ? "script"
2048
+ : entry.startsWith(`${skillDir}/assets/`)
2049
+ ? "asset"
2050
+ : entry.endsWith(".md")
2051
+ ? "markdown"
2052
+ : "other",
2053
+ }));
2054
+ const metadata = isPlainRecord(frontmatter.metadata) ? frontmatter.metadata : null;
2055
+ const sources = metadata && Array.isArray(metadata.sources) ? metadata.sources : [];
2056
+ const primarySource = sources.find((entry) => isPlainRecord(entry));
2057
+ const sourceKind = asString(primarySource?.kind);
2058
+ let sourceType = "catalog";
2059
+ let sourceLocator = null;
2060
+ let sourceRef = null;
2061
+ let normalizedMetadata = null;
2062
+ if (sourceKind === "github-dir" || sourceKind === "github-file") {
2063
+ const repo = asString(primarySource?.repo);
2064
+ const repoPath = asString(primarySource?.path);
2065
+ const commit = asString(primarySource?.commit);
2066
+ const trackingRef = asString(primarySource?.trackingRef);
2067
+ const [owner, repoName] = (repo ?? "").split("/");
2068
+ sourceType = "github";
2069
+ sourceLocator = asString(primarySource?.url)
2070
+ ?? (repo ? `https://github.com/${repo}${repoPath ? `/tree/${trackingRef ?? commit ?? "main"}/${repoPath}` : ""}` : null);
2071
+ sourceRef = commit;
2072
+ normalizedMetadata = owner && repoName
2073
+ ? {
2074
+ sourceKind: "github",
2075
+ owner,
2076
+ repo: repoName,
2077
+ ref: commit,
2078
+ trackingRef,
2079
+ repoSkillDir: repoPath ?? `skills/${slug}`,
2080
+ }
2081
+ : null;
2082
+ }
2083
+ else if (sourceKind === "url") {
2084
+ sourceType = "url";
2085
+ sourceLocator = asString(primarySource?.url) ?? asString(primarySource?.rawUrl);
2086
+ normalizedMetadata = {
2087
+ sourceKind: "url",
2088
+ };
2089
+ }
2090
+ else if (metadata) {
2091
+ normalizedMetadata = {
2092
+ sourceKind: "catalog",
2093
+ };
2094
+ }
2095
+ const key = deriveManifestSkillKey(frontmatter, slug, normalizedMetadata, sourceType, sourceLocator);
2096
+ manifest.skills.push({
2097
+ key,
2098
+ slug,
2099
+ name: asString(frontmatter.name) ?? slug,
2100
+ path: skillPath,
2101
+ description: asString(frontmatter.description),
2102
+ sourceType,
2103
+ sourceLocator,
2104
+ sourceRef,
2105
+ trustLevel: null,
2106
+ compatibility: "compatible",
2107
+ metadata: normalizedMetadata,
2108
+ fileInventory: inventory,
2109
+ });
2110
+ }
2111
+ for (const projectPath of projectPaths) {
2112
+ const markdownRaw = readPortableTextFile(normalizedFiles, projectPath);
2113
+ if (typeof markdownRaw !== "string") {
2114
+ warnings.push(`Referenced project file is missing from package: ${projectPath}`);
2115
+ continue;
2116
+ }
2117
+ const projectDoc = parseFrontmatterMarkdown(markdownRaw);
2118
+ const frontmatter = projectDoc.frontmatter;
2119
+ const fallbackSlug = deriveProjectUrlKey(asString(frontmatter.name) ?? path.posix.basename(path.posix.dirname(projectPath)) ?? "project", projectPath);
2120
+ const slug = asString(frontmatter.slug) ?? fallbackSlug;
2121
+ const extension = isPlainRecord(fideliosProjects[slug]) ? fideliosProjects[slug] : {};
2122
+ const workspaceExtensions = isPlainRecord(extension.workspaces) ? extension.workspaces : {};
2123
+ const workspaces = Object.entries(workspaceExtensions)
2124
+ .map(([workspaceKey, entry]) => normalizePortableProjectWorkspaceExtension(workspaceKey, entry))
2125
+ .filter((entry) => entry !== null);
2126
+ manifest.projects.push({
2127
+ slug,
2128
+ name: asString(frontmatter.name) ?? slug,
2129
+ path: projectPath,
2130
+ description: asString(frontmatter.description),
2131
+ ownerAgentSlug: asString(frontmatter.owner),
2132
+ leadAgentSlug: asString(extension.leadAgentSlug),
2133
+ targetDate: asString(extension.targetDate),
2134
+ color: asString(extension.color),
2135
+ status: asString(extension.status),
2136
+ executionWorkspacePolicy: isPlainRecord(extension.executionWorkspacePolicy)
2137
+ ? extension.executionWorkspacePolicy
2138
+ : null,
2139
+ workspaces,
2140
+ metadata: isPlainRecord(extension.metadata) ? extension.metadata : null,
2141
+ });
2142
+ if (frontmatter.kind && frontmatter.kind !== "project") {
2143
+ warnings.push(`Project markdown ${projectPath} does not declare kind: project in frontmatter.`);
2144
+ }
2145
+ }
2146
+ for (const taskPath of taskPaths) {
2147
+ const markdownRaw = readPortableTextFile(normalizedFiles, taskPath);
2148
+ if (typeof markdownRaw !== "string") {
2149
+ warnings.push(`Referenced task file is missing from package: ${taskPath}`);
2150
+ continue;
2151
+ }
2152
+ const taskDoc = parseFrontmatterMarkdown(markdownRaw);
2153
+ const frontmatter = taskDoc.frontmatter;
2154
+ const fallbackSlug = normalizeAgentUrlKey(path.posix.basename(path.posix.dirname(taskPath))) ?? "task";
2155
+ const slug = asString(frontmatter.slug) ?? fallbackSlug;
2156
+ const extension = isPlainRecord(fideliosTasks[slug]) ? fideliosTasks[slug] : {};
2157
+ const routineExtension = normalizeRoutineExtension(fideliosRoutines[slug]);
2158
+ const routineExtensionRaw = isPlainRecord(fideliosRoutines[slug]) ? fideliosRoutines[slug] : {};
2159
+ const schedule = isPlainRecord(frontmatter.schedule) ? frontmatter.schedule : null;
2160
+ const legacyRecurrence = schedule && isPlainRecord(schedule.recurrence)
2161
+ ? schedule.recurrence
2162
+ : isPlainRecord(extension.recurrence)
2163
+ ? extension.recurrence
2164
+ : null;
2165
+ const recurring = asBoolean(frontmatter.recurring) === true
2166
+ || routineExtension !== null
2167
+ || legacyRecurrence !== null;
2168
+ manifest.issues.push({
2169
+ slug,
2170
+ identifier: asString(extension.identifier),
2171
+ title: asString(frontmatter.name) ?? asString(frontmatter.title) ?? slug,
2172
+ path: taskPath,
2173
+ projectSlug: asString(frontmatter.project),
2174
+ projectWorkspaceKey: asString(extension.projectWorkspaceKey),
2175
+ assigneeAgentSlug: asString(frontmatter.assignee),
2176
+ description: taskDoc.body || asString(frontmatter.description),
2177
+ recurring,
2178
+ routine: routineExtension,
2179
+ legacyRecurrence,
2180
+ status: asString(extension.status) ?? asString(routineExtensionRaw.status),
2181
+ priority: asString(extension.priority) ?? asString(routineExtensionRaw.priority),
2182
+ labelIds: Array.isArray(extension.labelIds)
2183
+ ? extension.labelIds.filter((entry) => typeof entry === "string")
2184
+ : [],
2185
+ billingCode: asString(extension.billingCode),
2186
+ executionWorkspaceSettings: isPlainRecord(extension.executionWorkspaceSettings)
2187
+ ? extension.executionWorkspaceSettings
2188
+ : null,
2189
+ assigneeAdapterOverrides: isPlainRecord(extension.assigneeAdapterOverrides)
2190
+ ? extension.assigneeAdapterOverrides
2191
+ : null,
2192
+ metadata: isPlainRecord(extension.metadata) ? extension.metadata : null,
2193
+ });
2194
+ if (frontmatter.kind && frontmatter.kind !== "task") {
2195
+ warnings.push(`Task markdown ${taskPath} does not declare kind: task in frontmatter.`);
2196
+ }
2197
+ }
2198
+ manifest.envInputs = dedupeEnvInputs(manifest.envInputs);
2199
+ return {
2200
+ manifest,
2201
+ files: normalizedFiles,
2202
+ warnings,
2203
+ };
2204
+ }
2205
+ function normalizeGitHubSourcePath(value) {
2206
+ if (!value)
2207
+ return "";
2208
+ return value.trim().replace(/\\/g, "/").replace(/^\/+|\/+$/g, "");
2209
+ }
2210
+ export function parseGitHubSourceUrl(rawUrl) {
2211
+ const url = new URL(rawUrl);
2212
+ if (url.hostname !== "github.com") {
2213
+ throw unprocessable("GitHub source must use github.com URL");
2214
+ }
2215
+ const parts = url.pathname.split("/").filter(Boolean);
2216
+ if (parts.length < 2) {
2217
+ throw unprocessable("Invalid GitHub URL");
2218
+ }
2219
+ const owner = parts[0];
2220
+ const repo = parts[1].replace(/\.git$/i, "");
2221
+ const queryRef = url.searchParams.get("ref")?.trim();
2222
+ const queryPath = normalizeGitHubSourcePath(url.searchParams.get("path"));
2223
+ const queryCompanyPath = normalizeGitHubSourcePath(url.searchParams.get("companyPath"));
2224
+ if (queryRef || queryPath || queryCompanyPath) {
2225
+ const companyPath = queryCompanyPath || [queryPath, "COMPANY.md"].filter(Boolean).join("/") || "COMPANY.md";
2226
+ let basePath = queryPath;
2227
+ if (!basePath && companyPath !== "COMPANY.md") {
2228
+ basePath = path.posix.dirname(companyPath);
2229
+ if (basePath === ".")
2230
+ basePath = "";
2231
+ }
2232
+ return {
2233
+ owner,
2234
+ repo,
2235
+ ref: queryRef || "main",
2236
+ basePath,
2237
+ companyPath,
2238
+ };
2239
+ }
2240
+ let ref = "main";
2241
+ let basePath = "";
2242
+ let companyPath = "COMPANY.md";
2243
+ if (parts[2] === "tree") {
2244
+ ref = parts[3] ?? "main";
2245
+ basePath = parts.slice(4).join("/");
2246
+ }
2247
+ else if (parts[2] === "blob") {
2248
+ ref = parts[3] ?? "main";
2249
+ const blobPath = parts.slice(4).join("/");
2250
+ if (!blobPath) {
2251
+ throw unprocessable("Invalid GitHub blob URL");
2252
+ }
2253
+ companyPath = blobPath;
2254
+ basePath = path.posix.dirname(blobPath);
2255
+ if (basePath === ".")
2256
+ basePath = "";
2257
+ }
2258
+ return { owner, repo, ref, basePath, companyPath };
2259
+ }
2260
+ function resolveRawGitHubUrl(owner, repo, ref, filePath) {
2261
+ const normalizedFilePath = filePath.replace(/^\/+/, "");
2262
+ return `https://raw.githubusercontent.com/${owner}/${repo}/${ref}/${normalizedFilePath}`;
2263
+ }
2264
+ export function companyPortabilityService(db, storage) {
2265
+ const companies = companyService(db);
2266
+ const agents = agentService(db);
2267
+ const assetRecords = assetService(db);
2268
+ const instructions = agentInstructionsService();
2269
+ const access = accessService(db);
2270
+ const projects = projectService(db);
2271
+ const issues = issueService(db);
2272
+ const companySkills = companySkillService(db);
2273
+ async function resolveSource(source) {
2274
+ if (source.type === "inline") {
2275
+ return buildManifestFromPackageFiles(normalizeFileMap(source.files, source.rootPath));
2276
+ }
2277
+ const parsed = parseGitHubSourceUrl(source.url);
2278
+ let ref = parsed.ref;
2279
+ const warnings = [];
2280
+ const companyRelativePath = parsed.companyPath === "COMPANY.md"
2281
+ ? [parsed.basePath, "COMPANY.md"].filter(Boolean).join("/")
2282
+ : parsed.companyPath;
2283
+ let companyMarkdown = null;
2284
+ try {
2285
+ companyMarkdown = await fetchOptionalText(resolveRawGitHubUrl(parsed.owner, parsed.repo, ref, companyRelativePath));
2286
+ }
2287
+ catch (err) {
2288
+ if (ref === "main") {
2289
+ ref = "master";
2290
+ warnings.push("GitHub ref main not found; falling back to master.");
2291
+ companyMarkdown = await fetchOptionalText(resolveRawGitHubUrl(parsed.owner, parsed.repo, ref, companyRelativePath));
2292
+ }
2293
+ else {
2294
+ throw err;
2295
+ }
2296
+ }
2297
+ if (!companyMarkdown) {
2298
+ throw unprocessable("GitHub company package is missing COMPANY.md");
2299
+ }
2300
+ const companyPath = parsed.companyPath === "COMPANY.md"
2301
+ ? "COMPANY.md"
2302
+ : normalizePortablePath(path.posix.relative(parsed.basePath || ".", parsed.companyPath));
2303
+ const files = {
2304
+ [companyPath]: companyMarkdown,
2305
+ };
2306
+ const tree = await fetchJson(`https://api.github.com/repos/${parsed.owner}/${parsed.repo}/git/trees/${ref}?recursive=1`).catch(() => ({ tree: [] }));
2307
+ const basePrefix = parsed.basePath ? `${parsed.basePath.replace(/^\/+|\/+$/g, "")}/` : "";
2308
+ const candidatePaths = (tree.tree ?? [])
2309
+ .filter((entry) => entry.type === "blob")
2310
+ .map((entry) => entry.path)
2311
+ .filter((entry) => typeof entry === "string")
2312
+ .filter((entry) => {
2313
+ if (basePrefix && !entry.startsWith(basePrefix))
2314
+ return false;
2315
+ const relative = basePrefix ? entry.slice(basePrefix.length) : entry;
2316
+ return (relative.endsWith(".md") ||
2317
+ relative.startsWith("skills/") ||
2318
+ relative === ".fidelios.yaml" ||
2319
+ relative === ".fidelios.yml");
2320
+ });
2321
+ for (const repoPath of candidatePaths) {
2322
+ const relativePath = basePrefix ? repoPath.slice(basePrefix.length) : repoPath;
2323
+ if (files[relativePath] !== undefined)
2324
+ continue;
2325
+ files[normalizePortablePath(relativePath)] = await fetchText(resolveRawGitHubUrl(parsed.owner, parsed.repo, ref, repoPath));
2326
+ }
2327
+ const companyDoc = parseFrontmatterMarkdown(companyMarkdown);
2328
+ const includeEntries = readIncludeEntries(companyDoc.frontmatter);
2329
+ for (const includeEntry of includeEntries) {
2330
+ const repoPath = [parsed.basePath, includeEntry.path].filter(Boolean).join("/");
2331
+ const relativePath = normalizePortablePath(includeEntry.path);
2332
+ if (files[relativePath] !== undefined)
2333
+ continue;
2334
+ if (!(repoPath.endsWith(".md") || repoPath.endsWith(".yaml") || repoPath.endsWith(".yml")))
2335
+ continue;
2336
+ files[relativePath] = await fetchText(resolveRawGitHubUrl(parsed.owner, parsed.repo, ref, repoPath));
2337
+ }
2338
+ const resolved = buildManifestFromPackageFiles(files);
2339
+ const companyLogoPath = resolved.manifest.company?.logoPath;
2340
+ if (companyLogoPath && !resolved.files[companyLogoPath]) {
2341
+ const repoPath = [parsed.basePath, companyLogoPath].filter(Boolean).join("/");
2342
+ try {
2343
+ const binary = await fetchBinary(resolveRawGitHubUrl(parsed.owner, parsed.repo, ref, repoPath));
2344
+ resolved.files[companyLogoPath] = bufferToPortableBinaryFile(binary, inferContentTypeFromPath(companyLogoPath));
2345
+ }
2346
+ catch (err) {
2347
+ warnings.push(`Failed to fetch company logo ${companyLogoPath} from GitHub: ${err instanceof Error ? err.message : String(err)}`);
2348
+ }
2349
+ }
2350
+ resolved.warnings.unshift(...warnings);
2351
+ return resolved;
2352
+ }
2353
+ async function exportBundle(companyId, input) {
2354
+ const include = normalizeInclude({
2355
+ ...input.include,
2356
+ agents: input.agents && input.agents.length > 0 ? true : input.include?.agents,
2357
+ projects: input.projects && input.projects.length > 0 ? true : input.include?.projects,
2358
+ issues: (input.issues && input.issues.length > 0) || (input.projectIssues && input.projectIssues.length > 0)
2359
+ ? true
2360
+ : input.include?.issues,
2361
+ skills: input.skills && input.skills.length > 0 ? true : input.include?.skills,
2362
+ });
2363
+ const company = await companies.getById(companyId);
2364
+ if (!company)
2365
+ throw notFound("Company not found");
2366
+ const files = {};
2367
+ const warnings = [];
2368
+ const envInputs = [];
2369
+ const requestedSidebarOrder = normalizePortableSidebarOrder(input.sidebarOrder);
2370
+ const rootPath = normalizeAgentUrlKey(company.name) ?? "company-package";
2371
+ let companyLogoPath = null;
2372
+ const allAgentRows = include.agents ? await agents.list(companyId, { includeTerminated: true }) : [];
2373
+ const liveAgentRows = allAgentRows.filter((agent) => agent.status !== "terminated");
2374
+ const companySkillRows = include.skills || include.agents ? await companySkills.listFull(companyId) : [];
2375
+ if (include.agents) {
2376
+ const skipped = allAgentRows.length - liveAgentRows.length;
2377
+ if (skipped > 0) {
2378
+ warnings.push(`Skipped ${skipped} terminated agent${skipped === 1 ? "" : "s"} from export.`);
2379
+ }
2380
+ }
2381
+ const agentByReference = new Map();
2382
+ for (const agent of liveAgentRows) {
2383
+ agentByReference.set(agent.id, agent);
2384
+ agentByReference.set(agent.name, agent);
2385
+ const normalizedName = normalizeAgentUrlKey(agent.name);
2386
+ if (normalizedName) {
2387
+ agentByReference.set(normalizedName, agent);
2388
+ }
2389
+ }
2390
+ const selectedAgents = new Map();
2391
+ for (const selector of input.agents ?? []) {
2392
+ const trimmed = selector.trim();
2393
+ if (!trimmed)
2394
+ continue;
2395
+ const normalized = normalizeAgentUrlKey(trimmed) ?? trimmed;
2396
+ const match = agentByReference.get(trimmed) ?? agentByReference.get(normalized);
2397
+ if (!match) {
2398
+ warnings.push(`Agent selector "${selector}" was not found and was skipped.`);
2399
+ continue;
2400
+ }
2401
+ selectedAgents.set(match.id, match);
2402
+ }
2403
+ if (include.agents && selectedAgents.size === 0) {
2404
+ for (const agent of liveAgentRows) {
2405
+ selectedAgents.set(agent.id, agent);
2406
+ }
2407
+ }
2408
+ const agentRows = Array.from(selectedAgents.values())
2409
+ .sort((left, right) => left.name.localeCompare(right.name));
2410
+ const usedSlugs = new Set();
2411
+ const idToSlug = new Map();
2412
+ for (const agent of agentRows) {
2413
+ const baseSlug = toSafeSlug(agent.name, "agent");
2414
+ const slug = uniqueSlug(baseSlug, usedSlugs);
2415
+ idToSlug.set(agent.id, slug);
2416
+ }
2417
+ const projectsSvc = projectService(db);
2418
+ const issuesSvc = issueService(db);
2419
+ const routinesSvc = routineService(db);
2420
+ const allProjectsRaw = include.projects || include.issues ? await projectsSvc.list(companyId) : [];
2421
+ const allProjects = allProjectsRaw.filter((project) => !project.archivedAt);
2422
+ const allRoutines = include.issues ? await routinesSvc.list(companyId) : [];
2423
+ const projectById = new Map(allProjects.map((project) => [project.id, project]));
2424
+ const projectByReference = new Map();
2425
+ for (const project of allProjects) {
2426
+ projectByReference.set(project.id, project);
2427
+ projectByReference.set(project.urlKey, project);
2428
+ }
2429
+ const selectedProjects = new Map();
2430
+ const normalizeProjectSelector = (selector) => selector.trim().toLowerCase();
2431
+ for (const selector of input.projects ?? []) {
2432
+ const match = projectByReference.get(selector) ?? projectByReference.get(normalizeProjectSelector(selector));
2433
+ if (!match) {
2434
+ warnings.push(`Project selector "${selector}" was not found and was skipped.`);
2435
+ continue;
2436
+ }
2437
+ selectedProjects.set(match.id, match);
2438
+ }
2439
+ const selectedIssues = new Map();
2440
+ const selectedRoutines = new Map();
2441
+ const routineById = new Map(allRoutines.map((routine) => [routine.id, routine]));
2442
+ const resolveIssueBySelector = async (selector) => {
2443
+ const trimmed = selector.trim();
2444
+ if (!trimmed)
2445
+ return null;
2446
+ return trimmed.includes("-")
2447
+ ? issuesSvc.getByIdentifier(trimmed)
2448
+ : issuesSvc.getById(trimmed);
2449
+ };
2450
+ for (const selector of input.issues ?? []) {
2451
+ const issue = await resolveIssueBySelector(selector);
2452
+ if (!issue || issue.companyId !== companyId) {
2453
+ const routine = routineById.get(selector.trim());
2454
+ if (routine) {
2455
+ selectedRoutines.set(routine.id, routine);
2456
+ if (routine.projectId) {
2457
+ const parentProject = projectById.get(routine.projectId);
2458
+ if (parentProject)
2459
+ selectedProjects.set(parentProject.id, parentProject);
2460
+ }
2461
+ continue;
2462
+ }
2463
+ warnings.push(`Issue selector "${selector}" was not found and was skipped.`);
2464
+ continue;
2465
+ }
2466
+ selectedIssues.set(issue.id, issue);
2467
+ if (issue.projectId) {
2468
+ const parentProject = projectById.get(issue.projectId);
2469
+ if (parentProject)
2470
+ selectedProjects.set(parentProject.id, parentProject);
2471
+ }
2472
+ }
2473
+ for (const selector of input.projectIssues ?? []) {
2474
+ const match = projectByReference.get(selector) ?? projectByReference.get(normalizeProjectSelector(selector));
2475
+ if (!match) {
2476
+ warnings.push(`Project-issues selector "${selector}" was not found and was skipped.`);
2477
+ continue;
2478
+ }
2479
+ selectedProjects.set(match.id, match);
2480
+ const projectIssues = await issuesSvc.list(companyId, { projectId: match.id });
2481
+ for (const issue of projectIssues) {
2482
+ selectedIssues.set(issue.id, issue);
2483
+ }
2484
+ for (const routine of allRoutines.filter((entry) => entry.projectId === match.id)) {
2485
+ selectedRoutines.set(routine.id, routine);
2486
+ }
2487
+ }
2488
+ if (include.projects && selectedProjects.size === 0) {
2489
+ for (const project of allProjects) {
2490
+ selectedProjects.set(project.id, project);
2491
+ }
2492
+ }
2493
+ if (include.issues && selectedIssues.size === 0) {
2494
+ const allIssues = await issuesSvc.list(companyId);
2495
+ for (const issue of allIssues) {
2496
+ selectedIssues.set(issue.id, issue);
2497
+ if (issue.projectId) {
2498
+ const parentProject = projectById.get(issue.projectId);
2499
+ if (parentProject)
2500
+ selectedProjects.set(parentProject.id, parentProject);
2501
+ }
2502
+ }
2503
+ if (selectedRoutines.size === 0) {
2504
+ for (const routine of allRoutines) {
2505
+ selectedRoutines.set(routine.id, routine);
2506
+ if (routine.projectId) {
2507
+ const parentProject = projectById.get(routine.projectId);
2508
+ if (parentProject)
2509
+ selectedProjects.set(parentProject.id, parentProject);
2510
+ }
2511
+ }
2512
+ }
2513
+ }
2514
+ const selectedProjectRows = Array.from(selectedProjects.values())
2515
+ .sort((left, right) => left.name.localeCompare(right.name));
2516
+ const selectedIssueRows = Array.from(selectedIssues.values())
2517
+ .filter((issue) => issue != null)
2518
+ .sort((left, right) => (left.identifier ?? left.title).localeCompare(right.identifier ?? right.title));
2519
+ const selectedRoutineSummaries = Array.from(selectedRoutines.values())
2520
+ .sort((left, right) => left.title.localeCompare(right.title));
2521
+ const selectedRoutineRows = (await Promise.all(selectedRoutineSummaries.map((routine) => routinesSvc.getDetail(routine.id)))).filter((routine) => routine !== null);
2522
+ const taskSlugByIssueId = new Map();
2523
+ const taskSlugByRoutineId = new Map();
2524
+ const usedTaskSlugs = new Set();
2525
+ for (const issue of selectedIssueRows) {
2526
+ const baseSlug = normalizeAgentUrlKey(issue.identifier ?? issue.title) ?? "task";
2527
+ taskSlugByIssueId.set(issue.id, uniqueSlug(baseSlug, usedTaskSlugs));
2528
+ }
2529
+ for (const routine of selectedRoutineRows) {
2530
+ const baseSlug = normalizeAgentUrlKey(routine.title) ?? "task";
2531
+ taskSlugByRoutineId.set(routine.id, uniqueSlug(baseSlug, usedTaskSlugs));
2532
+ }
2533
+ const projectSlugById = new Map();
2534
+ const projectWorkspaceKeyByProjectId = new Map();
2535
+ const usedProjectSlugs = new Set();
2536
+ for (const project of selectedProjectRows) {
2537
+ const baseSlug = deriveProjectUrlKey(project.name, project.name);
2538
+ projectSlugById.set(project.id, uniqueSlug(baseSlug, usedProjectSlugs));
2539
+ }
2540
+ const sidebarOrder = requestedSidebarOrder ?? stripEmptyValues({
2541
+ agents: sortAgentsBySidebarOrder(Array.from(selectedAgents.values()))
2542
+ .map((agent) => idToSlug.get(agent.id))
2543
+ .filter((slug) => Boolean(slug)),
2544
+ projects: selectedProjectRows
2545
+ .map((project) => projectSlugById.get(project.id))
2546
+ .filter((slug) => Boolean(slug)),
2547
+ });
2548
+ const companyPath = "COMPANY.md";
2549
+ files[companyPath] = buildMarkdown({
2550
+ name: company.name,
2551
+ description: company.description ?? null,
2552
+ schema: "agentcompanies/v1",
2553
+ slug: rootPath,
2554
+ }, "");
2555
+ if (include.company && company.logoAssetId) {
2556
+ if (!storage) {
2557
+ warnings.push("Skipped company logo from export because storage is unavailable.");
2558
+ }
2559
+ else {
2560
+ const logoAsset = await assetRecords.getById(company.logoAssetId);
2561
+ if (!logoAsset) {
2562
+ warnings.push(`Skipped company logo ${company.logoAssetId} because the asset record was not found.`);
2563
+ }
2564
+ else {
2565
+ try {
2566
+ const object = await storage.getObject(company.id, logoAsset.objectKey);
2567
+ const body = await streamToBuffer(object.stream);
2568
+ companyLogoPath = `images/${COMPANY_LOGO_FILE_NAME}${resolveCompanyLogoExtension(logoAsset.contentType, logoAsset.originalFilename)}`;
2569
+ files[companyLogoPath] = bufferToPortableBinaryFile(body, logoAsset.contentType);
2570
+ }
2571
+ catch (err) {
2572
+ warnings.push(`Failed to export company logo ${company.logoAssetId}: ${err instanceof Error ? err.message : String(err)}`);
2573
+ }
2574
+ }
2575
+ }
2576
+ }
2577
+ const fideliosAgentsOut = {};
2578
+ const fideliosProjectsOut = {};
2579
+ const fideliosTasksOut = {};
2580
+ const unportableTaskWorkspaceRefs = new Map();
2581
+ const fideliosRoutinesOut = {};
2582
+ const skillByReference = new Map();
2583
+ for (const skill of companySkillRows) {
2584
+ skillByReference.set(skill.id, skill);
2585
+ skillByReference.set(skill.key, skill);
2586
+ skillByReference.set(skill.slug, skill);
2587
+ skillByReference.set(skill.name, skill);
2588
+ }
2589
+ const selectedSkills = new Map();
2590
+ for (const selector of input.skills ?? []) {
2591
+ const trimmed = selector.trim();
2592
+ if (!trimmed)
2593
+ continue;
2594
+ const normalized = normalizeSkillKey(trimmed) ?? normalizeSkillSlug(trimmed) ?? trimmed;
2595
+ const match = skillByReference.get(trimmed) ?? skillByReference.get(normalized);
2596
+ if (!match) {
2597
+ warnings.push(`Skill selector "${selector}" was not found and was skipped.`);
2598
+ continue;
2599
+ }
2600
+ selectedSkills.set(match.id, match);
2601
+ }
2602
+ if (selectedSkills.size === 0) {
2603
+ for (const skill of companySkillRows) {
2604
+ selectedSkills.set(skill.id, skill);
2605
+ }
2606
+ }
2607
+ const selectedSkillRows = Array.from(selectedSkills.values())
2608
+ .sort((left, right) => left.key.localeCompare(right.key));
2609
+ const skillExportDirs = buildSkillExportDirMap(selectedSkillRows, company.issuePrefix);
2610
+ for (const skill of selectedSkillRows) {
2611
+ const packageDir = skillExportDirs.get(skill.key) ?? `skills/${normalizeSkillSlug(skill.slug) ?? "skill"}`;
2612
+ if (shouldReferenceSkillOnExport(skill, Boolean(input.expandReferencedSkills))) {
2613
+ files[`${packageDir}/SKILL.md`] = await buildReferencedSkillMarkdown(skill);
2614
+ continue;
2615
+ }
2616
+ for (const inventoryEntry of skill.fileInventory) {
2617
+ const fileDetail = await companySkills.readFile(companyId, skill.id, inventoryEntry.path).catch(() => null);
2618
+ if (!fileDetail)
2619
+ continue;
2620
+ const filePath = `${packageDir}/${inventoryEntry.path}`;
2621
+ files[filePath] = inventoryEntry.path === "SKILL.md"
2622
+ ? await withSkillSourceMetadata(skill, fileDetail.content)
2623
+ : fileDetail.content;
2624
+ }
2625
+ }
2626
+ if (include.agents) {
2627
+ for (const agent of agentRows) {
2628
+ const slug = idToSlug.get(agent.id);
2629
+ const exportedInstructions = await instructions.exportFiles(agent);
2630
+ warnings.push(...exportedInstructions.warnings);
2631
+ const envInputsStart = envInputs.length;
2632
+ const exportedEnvInputs = extractPortableEnvInputs(slug, agent.adapterConfig.env, warnings);
2633
+ envInputs.push(...exportedEnvInputs);
2634
+ const adapterDefaultRules = ADAPTER_DEFAULT_RULES_BY_TYPE[agent.adapterType] ?? [];
2635
+ const portableAdapterConfig = pruneDefaultLikeValue(normalizePortableConfig(agent.adapterConfig), {
2636
+ dropFalseBooleans: true,
2637
+ defaultRules: adapterDefaultRules,
2638
+ });
2639
+ const portableRuntimeConfig = pruneDefaultLikeValue(normalizePortableConfig(agent.runtimeConfig), {
2640
+ dropFalseBooleans: true,
2641
+ defaultRules: RUNTIME_DEFAULT_RULES,
2642
+ });
2643
+ const portablePermissions = pruneDefaultLikeValue(agent.permissions ?? {}, { dropFalseBooleans: true });
2644
+ const agentEnvInputs = dedupeEnvInputs(envInputs
2645
+ .slice(envInputsStart)
2646
+ .filter((inputValue) => inputValue.agentSlug === slug));
2647
+ const reportsToSlug = agent.reportsTo ? (idToSlug.get(agent.reportsTo) ?? null) : null;
2648
+ const desiredSkills = readFideliOSSkillSyncPreference(agent.adapterConfig ?? {}).desiredSkills;
2649
+ const commandValue = asString(portableAdapterConfig.command);
2650
+ if (commandValue && isAbsoluteCommand(commandValue)) {
2651
+ warnings.push(`Agent ${slug} command ${commandValue} was omitted from export because it is system-dependent.`);
2652
+ delete portableAdapterConfig.command;
2653
+ }
2654
+ for (const [relativePath, content] of Object.entries(exportedInstructions.files)) {
2655
+ const targetPath = `agents/${slug}/${relativePath}`;
2656
+ if (relativePath === exportedInstructions.entryFile) {
2657
+ files[targetPath] = buildMarkdown(stripEmptyValues({
2658
+ name: agent.name,
2659
+ title: agent.title ?? null,
2660
+ reportsTo: reportsToSlug,
2661
+ skills: desiredSkills.length > 0 ? desiredSkills : undefined,
2662
+ }), content);
2663
+ }
2664
+ else {
2665
+ files[targetPath] = content;
2666
+ }
2667
+ }
2668
+ const extension = stripEmptyValues({
2669
+ role: agent.role !== "agent" ? agent.role : undefined,
2670
+ icon: agent.icon ?? null,
2671
+ capabilities: agent.capabilities ?? null,
2672
+ adapter: {
2673
+ type: agent.adapterType,
2674
+ config: portableAdapterConfig,
2675
+ },
2676
+ runtime: portableRuntimeConfig,
2677
+ permissions: portablePermissions,
2678
+ budgetMonthlyCents: (agent.budgetMonthlyCents ?? 0) > 0 ? agent.budgetMonthlyCents : undefined,
2679
+ metadata: agent.metadata ?? null,
2680
+ });
2681
+ if (isPlainRecord(extension) && agentEnvInputs.length > 0) {
2682
+ extension.inputs = {
2683
+ env: buildEnvInputMap(agentEnvInputs),
2684
+ };
2685
+ }
2686
+ fideliosAgentsOut[slug] = isPlainRecord(extension) ? extension : {};
2687
+ }
2688
+ }
2689
+ for (const project of selectedProjectRows) {
2690
+ const slug = projectSlugById.get(project.id);
2691
+ const projectPath = `projects/${slug}/PROJECT.md`;
2692
+ const portableWorkspaces = await buildPortableProjectWorkspaces(slug, project.workspaces, warnings);
2693
+ projectWorkspaceKeyByProjectId.set(project.id, portableWorkspaces.workspaceKeyById);
2694
+ files[projectPath] = buildMarkdown({
2695
+ name: project.name,
2696
+ description: project.description ?? null,
2697
+ owner: project.leadAgentId ? (idToSlug.get(project.leadAgentId) ?? null) : null,
2698
+ }, project.description ?? "");
2699
+ const extension = stripEmptyValues({
2700
+ leadAgentSlug: project.leadAgentId ? (idToSlug.get(project.leadAgentId) ?? null) : null,
2701
+ targetDate: project.targetDate ?? null,
2702
+ color: project.color ?? null,
2703
+ status: project.status,
2704
+ executionWorkspacePolicy: exportPortableProjectExecutionWorkspacePolicy(slug, project.executionWorkspacePolicy, portableWorkspaces.workspaceKeyById, warnings) ?? undefined,
2705
+ workspaces: portableWorkspaces.extension,
2706
+ });
2707
+ fideliosProjectsOut[slug] = isPlainRecord(extension) ? extension : {};
2708
+ }
2709
+ for (const issue of selectedIssueRows) {
2710
+ const taskSlug = taskSlugByIssueId.get(issue.id);
2711
+ const projectSlug = issue.projectId ? (projectSlugById.get(issue.projectId) ?? null) : null;
2712
+ // All tasks go in top-level tasks/ folder, never nested under projects/
2713
+ const taskPath = `tasks/${taskSlug}/TASK.md`;
2714
+ const assigneeSlug = issue.assigneeAgentId ? (idToSlug.get(issue.assigneeAgentId) ?? null) : null;
2715
+ const projectWorkspaceKey = issue.projectId && issue.projectWorkspaceId
2716
+ ? projectWorkspaceKeyByProjectId.get(issue.projectId)?.get(issue.projectWorkspaceId) ?? null
2717
+ : null;
2718
+ if (issue.projectWorkspaceId && !projectWorkspaceKey) {
2719
+ const aggregateKey = `${issue.projectId ?? "no-project"}:${issue.projectWorkspaceId}`;
2720
+ const existing = unportableTaskWorkspaceRefs.get(aggregateKey);
2721
+ if (existing) {
2722
+ existing.taskSlugs.push(taskSlug);
2723
+ }
2724
+ else {
2725
+ unportableTaskWorkspaceRefs.set(aggregateKey, {
2726
+ workspaceId: issue.projectWorkspaceId,
2727
+ taskSlugs: [taskSlug],
2728
+ });
2729
+ }
2730
+ }
2731
+ files[taskPath] = buildMarkdown({
2732
+ name: issue.title,
2733
+ project: projectSlug,
2734
+ assignee: assigneeSlug,
2735
+ }, issue.description ?? "");
2736
+ const extension = stripEmptyValues({
2737
+ identifier: issue.identifier,
2738
+ status: issue.status,
2739
+ priority: issue.priority,
2740
+ labelIds: issue.labelIds ?? undefined,
2741
+ billingCode: issue.billingCode ?? null,
2742
+ projectWorkspaceKey: projectWorkspaceKey ?? undefined,
2743
+ executionWorkspaceSettings: issue.executionWorkspaceSettings ?? undefined,
2744
+ assigneeAdapterOverrides: issue.assigneeAdapterOverrides ?? undefined,
2745
+ });
2746
+ fideliosTasksOut[taskSlug] = isPlainRecord(extension) ? extension : {};
2747
+ }
2748
+ for (const { workspaceId, taskSlugs } of unportableTaskWorkspaceRefs.values()) {
2749
+ const preview = taskSlugs.slice(0, 4).join(", ");
2750
+ const remainder = taskSlugs.length > 4 ? ` and ${taskSlugs.length - 4} more` : "";
2751
+ warnings.push(`Tasks ${preview}${remainder} reference workspace ${workspaceId}, but that workspace could not be exported portably.`);
2752
+ }
2753
+ for (const routine of selectedRoutineRows) {
2754
+ const taskSlug = taskSlugByRoutineId.get(routine.id);
2755
+ const projectSlug = projectSlugById.get(routine.projectId) ?? null;
2756
+ const taskPath = `tasks/${taskSlug}/TASK.md`;
2757
+ const assigneeSlug = idToSlug.get(routine.assigneeAgentId) ?? null;
2758
+ files[taskPath] = buildMarkdown({
2759
+ name: routine.title,
2760
+ project: projectSlug,
2761
+ assignee: assigneeSlug,
2762
+ recurring: true,
2763
+ }, routine.description ?? "");
2764
+ const extension = stripEmptyValues({
2765
+ status: routine.status !== "active" ? routine.status : undefined,
2766
+ priority: routine.priority !== "medium" ? routine.priority : undefined,
2767
+ concurrencyPolicy: routine.concurrencyPolicy !== "coalesce_if_active" ? routine.concurrencyPolicy : undefined,
2768
+ catchUpPolicy: routine.catchUpPolicy !== "skip_missed" ? routine.catchUpPolicy : undefined,
2769
+ triggers: routine.triggers.map((trigger) => stripEmptyValues({
2770
+ kind: trigger.kind,
2771
+ label: trigger.label ?? null,
2772
+ enabled: trigger.enabled ? undefined : false,
2773
+ cronExpression: trigger.kind === "schedule" ? trigger.cronExpression ?? null : undefined,
2774
+ timezone: trigger.kind === "schedule" ? trigger.timezone ?? null : undefined,
2775
+ signingMode: trigger.kind === "webhook" && trigger.signingMode !== "bearer" ? trigger.signingMode ?? null : undefined,
2776
+ replayWindowSec: trigger.kind === "webhook" && trigger.replayWindowSec !== 300
2777
+ ? trigger.replayWindowSec ?? null
2778
+ : undefined,
2779
+ })),
2780
+ });
2781
+ fideliosRoutinesOut[taskSlug] = isPlainRecord(extension) ? extension : {};
2782
+ }
2783
+ const fideliosExtensionPath = ".fidelios.yaml";
2784
+ const fideliosAgents = Object.fromEntries(Object.entries(fideliosAgentsOut).filter(([, value]) => isPlainRecord(value) && Object.keys(value).length > 0));
2785
+ const fideliosProjects = Object.fromEntries(Object.entries(fideliosProjectsOut).filter(([, value]) => isPlainRecord(value) && Object.keys(value).length > 0));
2786
+ const fideliosTasks = Object.fromEntries(Object.entries(fideliosTasksOut).filter(([, value]) => isPlainRecord(value) && Object.keys(value).length > 0));
2787
+ const fideliosRoutines = Object.fromEntries(Object.entries(fideliosRoutinesOut).filter(([, value]) => isPlainRecord(value) && Object.keys(value).length > 0));
2788
+ files[fideliosExtensionPath] = buildYamlFile({
2789
+ schema: "fidelios/v1",
2790
+ company: stripEmptyValues({
2791
+ brandColor: company.brandColor ?? null,
2792
+ logoPath: companyLogoPath,
2793
+ requireBoardApprovalForNewAgents: company.requireBoardApprovalForNewAgents ? undefined : false,
2794
+ }),
2795
+ sidebar: stripEmptyValues(sidebarOrder),
2796
+ agents: Object.keys(fideliosAgents).length > 0 ? fideliosAgents : undefined,
2797
+ projects: Object.keys(fideliosProjects).length > 0 ? fideliosProjects : undefined,
2798
+ tasks: Object.keys(fideliosTasks).length > 0 ? fideliosTasks : undefined,
2799
+ routines: Object.keys(fideliosRoutines).length > 0 ? fideliosRoutines : undefined,
2800
+ }, { preserveEmptyStrings: true });
2801
+ let finalFiles = filterExportFiles(files, input.selectedFiles, fideliosExtensionPath);
2802
+ let resolved = buildManifestFromPackageFiles(finalFiles, {
2803
+ sourceLabel: {
2804
+ companyId: company.id,
2805
+ companyName: company.name,
2806
+ },
2807
+ });
2808
+ resolved.manifest.includes = {
2809
+ company: resolved.manifest.company !== null,
2810
+ agents: resolved.manifest.agents.length > 0,
2811
+ projects: resolved.manifest.projects.length > 0,
2812
+ issues: resolved.manifest.issues.length > 0,
2813
+ skills: resolved.manifest.skills.length > 0,
2814
+ };
2815
+ resolved.manifest.envInputs = dedupeEnvInputs(envInputs);
2816
+ resolved.warnings.unshift(...warnings);
2817
+ // Generate org chart PNG from manifest agents
2818
+ if (resolved.manifest.agents.length > 0) {
2819
+ try {
2820
+ const orgNodes = buildOrgTreeFromManifest(resolved.manifest.agents);
2821
+ const pngBuffer = await renderOrgChartPng(orgNodes);
2822
+ finalFiles["images/org-chart.png"] = bufferToPortableBinaryFile(pngBuffer, "image/png");
2823
+ }
2824
+ catch {
2825
+ // Non-fatal: export still works without the org chart image
2826
+ }
2827
+ }
2828
+ if (!input.selectedFiles || input.selectedFiles.some((entry) => normalizePortablePath(entry) === "README.md")) {
2829
+ finalFiles["README.md"] = generateReadme(resolved.manifest, {
2830
+ companyName: company.name,
2831
+ companyDescription: company.description ?? null,
2832
+ });
2833
+ }
2834
+ resolved = buildManifestFromPackageFiles(finalFiles, {
2835
+ sourceLabel: {
2836
+ companyId: company.id,
2837
+ companyName: company.name,
2838
+ },
2839
+ });
2840
+ resolved.manifest.includes = {
2841
+ company: resolved.manifest.company !== null,
2842
+ agents: resolved.manifest.agents.length > 0,
2843
+ projects: resolved.manifest.projects.length > 0,
2844
+ issues: resolved.manifest.issues.length > 0,
2845
+ skills: resolved.manifest.skills.length > 0,
2846
+ };
2847
+ resolved.manifest.envInputs = dedupeEnvInputs(envInputs);
2848
+ resolved.warnings.unshift(...warnings);
2849
+ return {
2850
+ rootPath,
2851
+ manifest: resolved.manifest,
2852
+ files: finalFiles,
2853
+ warnings: resolved.warnings,
2854
+ fideliosExtensionPath,
2855
+ };
2856
+ }
2857
+ async function previewExport(companyId, input) {
2858
+ const previewInput = {
2859
+ ...input,
2860
+ include: {
2861
+ ...input.include,
2862
+ issues: input.include?.issues
2863
+ ?? Boolean((input.issues && input.issues.length > 0) || (input.projectIssues && input.projectIssues.length > 0))
2864
+ ?? false,
2865
+ },
2866
+ };
2867
+ if (previewInput.include && previewInput.include.issues === undefined) {
2868
+ previewInput.include.issues = false;
2869
+ }
2870
+ const exported = await exportBundle(companyId, previewInput);
2871
+ return {
2872
+ ...exported,
2873
+ fileInventory: Object.keys(exported.files)
2874
+ .sort((left, right) => left.localeCompare(right))
2875
+ .map((filePath) => ({
2876
+ path: filePath,
2877
+ kind: classifyPortableFileKind(filePath),
2878
+ })),
2879
+ counts: {
2880
+ files: Object.keys(exported.files).length,
2881
+ agents: exported.manifest.agents.length,
2882
+ skills: exported.manifest.skills.length,
2883
+ projects: exported.manifest.projects.length,
2884
+ issues: exported.manifest.issues.length,
2885
+ },
2886
+ };
2887
+ }
2888
+ async function buildPreview(input, options) {
2889
+ const mode = resolveImportMode(options);
2890
+ const requestedInclude = normalizeInclude(input.include);
2891
+ const source = applySelectedFilesToSource(await resolveSource(input.source), input.selectedFiles);
2892
+ const manifest = source.manifest;
2893
+ const include = {
2894
+ company: requestedInclude.company && manifest.company !== null,
2895
+ agents: requestedInclude.agents && manifest.agents.length > 0,
2896
+ projects: requestedInclude.projects && manifest.projects.length > 0,
2897
+ issues: requestedInclude.issues && manifest.issues.length > 0,
2898
+ skills: requestedInclude.skills && manifest.skills.length > 0,
2899
+ };
2900
+ const collisionStrategy = input.collisionStrategy ?? DEFAULT_COLLISION_STRATEGY;
2901
+ if (mode === "agent_safe" && collisionStrategy === "replace") {
2902
+ throw unprocessable("Safe import routes do not allow replace collision strategy.");
2903
+ }
2904
+ const warnings = [...source.warnings];
2905
+ const errors = [];
2906
+ if (include.company && !manifest.company) {
2907
+ errors.push("Manifest does not include company metadata.");
2908
+ }
2909
+ const selectedSlugs = include.agents
2910
+ ? (input.agents && input.agents !== "all"
2911
+ ? Array.from(new Set(input.agents))
2912
+ : manifest.agents.map((agent) => agent.slug))
2913
+ : [];
2914
+ const selectedAgents = include.agents
2915
+ ? manifest.agents.filter((agent) => selectedSlugs.includes(agent.slug))
2916
+ : [];
2917
+ const selectedMissing = selectedSlugs.filter((slug) => !manifest.agents.some((agent) => agent.slug === slug));
2918
+ for (const missing of selectedMissing) {
2919
+ errors.push(`Selected agent slug not found in manifest: ${missing}`);
2920
+ }
2921
+ if (include.agents && selectedAgents.length === 0) {
2922
+ warnings.push("No agents selected for import.");
2923
+ }
2924
+ const availableSkillKeys = new Set(source.manifest.skills.map((skill) => skill.key));
2925
+ const availableSkillSlugs = new Map();
2926
+ for (const skill of source.manifest.skills) {
2927
+ const existing = availableSkillSlugs.get(skill.slug) ?? [];
2928
+ existing.push(skill);
2929
+ availableSkillSlugs.set(skill.slug, existing);
2930
+ }
2931
+ for (const agent of selectedAgents) {
2932
+ const filePath = ensureMarkdownPath(agent.path);
2933
+ const markdown = readPortableTextFile(source.files, filePath);
2934
+ if (typeof markdown !== "string") {
2935
+ errors.push(`Missing markdown file for agent ${agent.slug}: ${filePath}`);
2936
+ continue;
2937
+ }
2938
+ const parsed = parseFrontmatterMarkdown(markdown);
2939
+ if (parsed.frontmatter.kind && parsed.frontmatter.kind !== "agent") {
2940
+ warnings.push(`Agent markdown ${filePath} does not declare kind: agent in frontmatter.`);
2941
+ }
2942
+ for (const skillRef of agent.skills) {
2943
+ const slugMatches = availableSkillSlugs.get(skillRef) ?? [];
2944
+ if (!availableSkillKeys.has(skillRef) && slugMatches.length !== 1) {
2945
+ warnings.push(`Agent ${agent.slug} references skill ${skillRef}, but that skill is not present in the package.`);
2946
+ }
2947
+ }
2948
+ }
2949
+ if (include.projects) {
2950
+ for (const project of manifest.projects) {
2951
+ const markdown = readPortableTextFile(source.files, ensureMarkdownPath(project.path));
2952
+ if (typeof markdown !== "string") {
2953
+ errors.push(`Missing markdown file for project ${project.slug}: ${project.path}`);
2954
+ continue;
2955
+ }
2956
+ const parsed = parseFrontmatterMarkdown(markdown);
2957
+ if (parsed.frontmatter.kind && parsed.frontmatter.kind !== "project") {
2958
+ warnings.push(`Project markdown ${project.path} does not declare kind: project in frontmatter.`);
2959
+ }
2960
+ }
2961
+ }
2962
+ if (include.issues) {
2963
+ const projectBySlug = new Map(manifest.projects.map((project) => [project.slug, project]));
2964
+ for (const issue of manifest.issues) {
2965
+ const markdown = readPortableTextFile(source.files, ensureMarkdownPath(issue.path));
2966
+ if (typeof markdown !== "string") {
2967
+ errors.push(`Missing markdown file for task ${issue.slug}: ${issue.path}`);
2968
+ continue;
2969
+ }
2970
+ const parsed = parseFrontmatterMarkdown(markdown);
2971
+ if (parsed.frontmatter.kind && parsed.frontmatter.kind !== "task") {
2972
+ warnings.push(`Task markdown ${issue.path} does not declare kind: task in frontmatter.`);
2973
+ }
2974
+ if (issue.projectWorkspaceKey) {
2975
+ const project = issue.projectSlug ? projectBySlug.get(issue.projectSlug) ?? null : null;
2976
+ if (!project) {
2977
+ warnings.push(`Task ${issue.slug} references workspace key ${issue.projectWorkspaceKey}, but its project is not present in the package.`);
2978
+ }
2979
+ else if (!project.workspaces.some((workspace) => workspace.key === issue.projectWorkspaceKey)) {
2980
+ warnings.push(`Task ${issue.slug} references missing project workspace key ${issue.projectWorkspaceKey}.`);
2981
+ }
2982
+ }
2983
+ if (issue.recurring) {
2984
+ if (!issue.projectSlug) {
2985
+ errors.push(`Recurring task ${issue.slug} must declare a project to import as a routine.`);
2986
+ }
2987
+ if (!issue.assigneeAgentSlug) {
2988
+ errors.push(`Recurring task ${issue.slug} must declare an assignee to import as a routine.`);
2989
+ }
2990
+ const resolvedRoutine = resolvePortableRoutineDefinition(issue, parsed.frontmatter.schedule);
2991
+ warnings.push(...resolvedRoutine.warnings);
2992
+ errors.push(...resolvedRoutine.errors);
2993
+ }
2994
+ }
2995
+ }
2996
+ for (const envInput of manifest.envInputs) {
2997
+ if (envInput.portability === "system_dependent") {
2998
+ warnings.push(`Environment input ${envInput.key}${envInput.agentSlug ? ` for ${envInput.agentSlug}` : ""} is system-dependent and may need manual adjustment after import.`);
2999
+ }
3000
+ }
3001
+ let targetCompanyId = null;
3002
+ let targetCompanyName = null;
3003
+ if (input.target.mode === "existing_company") {
3004
+ const targetCompany = await companies.getById(input.target.companyId);
3005
+ if (!targetCompany)
3006
+ throw notFound("Target company not found");
3007
+ targetCompanyId = targetCompany.id;
3008
+ targetCompanyName = targetCompany.name;
3009
+ }
3010
+ const agentPlans = [];
3011
+ const existingSlugToAgent = new Map();
3012
+ const existingSlugs = new Set();
3013
+ const projectPlans = [];
3014
+ const issuePlans = [];
3015
+ const existingProjectSlugToProject = new Map();
3016
+ const existingProjectSlugs = new Set();
3017
+ if (input.target.mode === "existing_company") {
3018
+ const existingAgents = await agents.list(input.target.companyId);
3019
+ for (const existing of existingAgents) {
3020
+ const slug = normalizeAgentUrlKey(existing.name) ?? existing.id;
3021
+ if (!existingSlugToAgent.has(slug))
3022
+ existingSlugToAgent.set(slug, existing);
3023
+ existingSlugs.add(slug);
3024
+ }
3025
+ const existingProjects = await projects.list(input.target.companyId);
3026
+ for (const existing of existingProjects) {
3027
+ if (!existingProjectSlugToProject.has(existing.urlKey)) {
3028
+ existingProjectSlugToProject.set(existing.urlKey, { id: existing.id, name: existing.name });
3029
+ }
3030
+ existingProjectSlugs.add(existing.urlKey);
3031
+ }
3032
+ const existingSkills = await companySkills.listFull(input.target.companyId);
3033
+ const existingSkillKeys = new Set(existingSkills.map((skill) => skill.key));
3034
+ const existingSkillSlugs = new Set(existingSkills.map((skill) => normalizeSkillSlug(skill.slug) ?? skill.slug));
3035
+ for (const skill of manifest.skills) {
3036
+ const skillSlug = normalizeSkillSlug(skill.slug) ?? skill.slug;
3037
+ if (existingSkillKeys.has(skill.key) || existingSkillSlugs.has(skillSlug)) {
3038
+ if (mode === "agent_safe") {
3039
+ warnings.push(`Existing skill "${skill.slug}" matched during safe import and will ${collisionStrategy === "skip" ? "be skipped" : "be renamed"} instead of overwritten.`);
3040
+ }
3041
+ else if (collisionStrategy === "replace") {
3042
+ warnings.push(`Existing skill "${skill.slug}" (${skill.key}) will be overwritten by import.`);
3043
+ }
3044
+ }
3045
+ }
3046
+ }
3047
+ for (const manifestAgent of selectedAgents) {
3048
+ const existing = existingSlugToAgent.get(manifestAgent.slug) ?? null;
3049
+ if (!existing) {
3050
+ agentPlans.push({
3051
+ slug: manifestAgent.slug,
3052
+ action: "create",
3053
+ plannedName: manifestAgent.name,
3054
+ existingAgentId: null,
3055
+ reason: null,
3056
+ });
3057
+ continue;
3058
+ }
3059
+ if (mode === "board_full" && collisionStrategy === "replace") {
3060
+ agentPlans.push({
3061
+ slug: manifestAgent.slug,
3062
+ action: "update",
3063
+ plannedName: existing.name,
3064
+ existingAgentId: existing.id,
3065
+ reason: "Existing slug matched; replace strategy.",
3066
+ });
3067
+ continue;
3068
+ }
3069
+ if (collisionStrategy === "skip") {
3070
+ agentPlans.push({
3071
+ slug: manifestAgent.slug,
3072
+ action: "skip",
3073
+ plannedName: existing.name,
3074
+ existingAgentId: existing.id,
3075
+ reason: "Existing slug matched; skip strategy.",
3076
+ });
3077
+ continue;
3078
+ }
3079
+ const renamed = uniqueNameBySlug(manifestAgent.name, existingSlugs);
3080
+ existingSlugs.add(normalizeAgentUrlKey(renamed) ?? manifestAgent.slug);
3081
+ agentPlans.push({
3082
+ slug: manifestAgent.slug,
3083
+ action: "create",
3084
+ plannedName: renamed,
3085
+ existingAgentId: existing.id,
3086
+ reason: "Existing slug matched; rename strategy.",
3087
+ });
3088
+ }
3089
+ if (include.projects) {
3090
+ for (const manifestProject of manifest.projects) {
3091
+ const existing = existingProjectSlugToProject.get(manifestProject.slug) ?? null;
3092
+ if (!existing) {
3093
+ projectPlans.push({
3094
+ slug: manifestProject.slug,
3095
+ action: "create",
3096
+ plannedName: manifestProject.name,
3097
+ existingProjectId: null,
3098
+ reason: null,
3099
+ });
3100
+ continue;
3101
+ }
3102
+ if (mode === "board_full" && collisionStrategy === "replace") {
3103
+ projectPlans.push({
3104
+ slug: manifestProject.slug,
3105
+ action: "update",
3106
+ plannedName: existing.name,
3107
+ existingProjectId: existing.id,
3108
+ reason: "Existing slug matched; replace strategy.",
3109
+ });
3110
+ continue;
3111
+ }
3112
+ if (collisionStrategy === "skip") {
3113
+ projectPlans.push({
3114
+ slug: manifestProject.slug,
3115
+ action: "skip",
3116
+ plannedName: existing.name,
3117
+ existingProjectId: existing.id,
3118
+ reason: "Existing slug matched; skip strategy.",
3119
+ });
3120
+ continue;
3121
+ }
3122
+ const renamed = uniqueProjectName(manifestProject.name, existingProjectSlugs);
3123
+ existingProjectSlugs.add(deriveProjectUrlKey(renamed, renamed));
3124
+ projectPlans.push({
3125
+ slug: manifestProject.slug,
3126
+ action: "create",
3127
+ plannedName: renamed,
3128
+ existingProjectId: existing.id,
3129
+ reason: "Existing slug matched; rename strategy.",
3130
+ });
3131
+ }
3132
+ }
3133
+ // Apply user-specified name overrides (keyed by slug)
3134
+ if (input.nameOverrides) {
3135
+ for (const ap of agentPlans) {
3136
+ const override = input.nameOverrides[ap.slug];
3137
+ if (override) {
3138
+ ap.plannedName = override;
3139
+ }
3140
+ }
3141
+ for (const pp of projectPlans) {
3142
+ const override = input.nameOverrides[pp.slug];
3143
+ if (override) {
3144
+ pp.plannedName = override;
3145
+ }
3146
+ }
3147
+ for (const ip of issuePlans) {
3148
+ const override = input.nameOverrides[ip.slug];
3149
+ if (override) {
3150
+ ip.plannedTitle = override;
3151
+ }
3152
+ }
3153
+ }
3154
+ // Warn about agents that will be overwritten/updated
3155
+ for (const ap of agentPlans) {
3156
+ if (ap.action === "update") {
3157
+ warnings.push(`Existing agent "${ap.plannedName}" (${ap.slug}) will be overwritten by import.`);
3158
+ }
3159
+ }
3160
+ // Warn about projects that will be overwritten/updated
3161
+ for (const pp of projectPlans) {
3162
+ if (pp.action === "update") {
3163
+ warnings.push(`Existing project "${pp.plannedName}" (${pp.slug}) will be overwritten by import.`);
3164
+ }
3165
+ }
3166
+ if (include.issues) {
3167
+ for (const manifestIssue of manifest.issues) {
3168
+ issuePlans.push({
3169
+ slug: manifestIssue.slug,
3170
+ action: "create",
3171
+ plannedTitle: manifestIssue.title,
3172
+ reason: manifestIssue.recurring ? "Recurring task will be imported as a routine." : null,
3173
+ });
3174
+ }
3175
+ }
3176
+ const preview = {
3177
+ include,
3178
+ targetCompanyId,
3179
+ targetCompanyName,
3180
+ collisionStrategy,
3181
+ selectedAgentSlugs: selectedAgents.map((agent) => agent.slug),
3182
+ plan: {
3183
+ companyAction: input.target.mode === "new_company"
3184
+ ? "create"
3185
+ : include.company && mode === "board_full"
3186
+ ? "update"
3187
+ : "none",
3188
+ agentPlans,
3189
+ projectPlans,
3190
+ issuePlans,
3191
+ },
3192
+ manifest,
3193
+ files: source.files,
3194
+ envInputs: manifest.envInputs ?? [],
3195
+ warnings,
3196
+ errors,
3197
+ };
3198
+ return {
3199
+ preview,
3200
+ source,
3201
+ include,
3202
+ collisionStrategy,
3203
+ selectedAgents,
3204
+ };
3205
+ }
3206
+ async function previewImport(input, options) {
3207
+ const plan = await buildPreview(input, options);
3208
+ return plan.preview;
3209
+ }
3210
+ async function importBundle(input, actorUserId, options) {
3211
+ const mode = resolveImportMode(options);
3212
+ const plan = await buildPreview(input, options);
3213
+ if (plan.preview.errors.length > 0) {
3214
+ throw unprocessable(`Import preview has errors: ${plan.preview.errors.join("; ")}`);
3215
+ }
3216
+ if (mode === "agent_safe"
3217
+ && (plan.preview.plan.companyAction === "update"
3218
+ || plan.preview.plan.agentPlans.some((entry) => entry.action === "update")
3219
+ || plan.preview.plan.projectPlans.some((entry) => entry.action === "update"))) {
3220
+ throw unprocessable("Safe import routes only allow create or skip actions.");
3221
+ }
3222
+ const sourceManifest = plan.source.manifest;
3223
+ const warnings = [...plan.preview.warnings];
3224
+ const include = plan.include;
3225
+ let targetCompany = null;
3226
+ let companyAction = "unchanged";
3227
+ if (input.target.mode === "new_company") {
3228
+ if (mode === "agent_safe" && !options?.sourceCompanyId) {
3229
+ throw unprocessable("Safe new-company imports require a source company context.");
3230
+ }
3231
+ if (mode === "agent_safe" && options?.sourceCompanyId) {
3232
+ const sourceMemberships = await access.listActiveUserMemberships(options.sourceCompanyId);
3233
+ if (sourceMemberships.length === 0) {
3234
+ throw unprocessable("Safe new-company import requires at least one active user membership on the source company.");
3235
+ }
3236
+ }
3237
+ const companyName = asString(input.target.newCompanyName) ??
3238
+ sourceManifest.company?.name ??
3239
+ sourceManifest.source?.companyName ??
3240
+ "Imported Company";
3241
+ const created = await companies.create({
3242
+ name: companyName,
3243
+ description: include.company ? (sourceManifest.company?.description ?? null) : null,
3244
+ brandColor: include.company ? (sourceManifest.company?.brandColor ?? null) : null,
3245
+ requireBoardApprovalForNewAgents: include.company
3246
+ ? (sourceManifest.company?.requireBoardApprovalForNewAgents ?? true)
3247
+ : true,
3248
+ });
3249
+ if (mode === "agent_safe" && options?.sourceCompanyId) {
3250
+ await access.copyActiveUserMemberships(options.sourceCompanyId, created.id);
3251
+ }
3252
+ else {
3253
+ await access.ensureMembership(created.id, "user", actorUserId ?? "board", "owner", "active");
3254
+ }
3255
+ targetCompany = created;
3256
+ companyAction = "created";
3257
+ }
3258
+ else {
3259
+ targetCompany = await companies.getById(input.target.companyId);
3260
+ if (!targetCompany)
3261
+ throw notFound("Target company not found");
3262
+ if (include.company && sourceManifest.company && mode === "board_full") {
3263
+ const updated = await companies.update(targetCompany.id, {
3264
+ name: sourceManifest.company.name,
3265
+ description: sourceManifest.company.description,
3266
+ brandColor: sourceManifest.company.brandColor,
3267
+ requireBoardApprovalForNewAgents: sourceManifest.company.requireBoardApprovalForNewAgents,
3268
+ });
3269
+ targetCompany = updated ?? targetCompany;
3270
+ companyAction = "updated";
3271
+ }
3272
+ }
3273
+ if (!targetCompany)
3274
+ throw notFound("Target company not found");
3275
+ if (include.company) {
3276
+ const logoPath = sourceManifest.company?.logoPath ?? null;
3277
+ if (!logoPath) {
3278
+ const cleared = await companies.update(targetCompany.id, { logoAssetId: null });
3279
+ targetCompany = cleared ?? targetCompany;
3280
+ }
3281
+ else {
3282
+ const logoFile = plan.source.files[logoPath];
3283
+ if (!logoFile) {
3284
+ warnings.push(`Skipped company logo import because ${logoPath} is missing from the package.`);
3285
+ }
3286
+ else if (!storage) {
3287
+ warnings.push("Skipped company logo import because storage is unavailable.");
3288
+ }
3289
+ else {
3290
+ const contentType = isPortableBinaryFile(logoFile)
3291
+ ? (logoFile.contentType ?? inferContentTypeFromPath(logoPath))
3292
+ : inferContentTypeFromPath(logoPath);
3293
+ if (!contentType || !COMPANY_LOGO_CONTENT_TYPE_EXTENSIONS[contentType]) {
3294
+ warnings.push(`Skipped company logo import for ${logoPath} because the file type is unsupported.`);
3295
+ }
3296
+ else {
3297
+ try {
3298
+ const body = portableFileToBuffer(logoFile, logoPath);
3299
+ const stored = await storage.putFile({
3300
+ companyId: targetCompany.id,
3301
+ namespace: "assets/companies",
3302
+ originalFilename: path.posix.basename(logoPath),
3303
+ contentType,
3304
+ body,
3305
+ });
3306
+ const createdAsset = await assetRecords.create(targetCompany.id, {
3307
+ provider: stored.provider,
3308
+ objectKey: stored.objectKey,
3309
+ contentType: stored.contentType,
3310
+ byteSize: stored.byteSize,
3311
+ sha256: stored.sha256,
3312
+ originalFilename: stored.originalFilename,
3313
+ createdByAgentId: null,
3314
+ createdByUserId: actorUserId ?? null,
3315
+ });
3316
+ const updated = await companies.update(targetCompany.id, {
3317
+ logoAssetId: createdAsset.id,
3318
+ });
3319
+ targetCompany = updated ?? targetCompany;
3320
+ }
3321
+ catch (err) {
3322
+ warnings.push(`Failed to import company logo ${logoPath}: ${err instanceof Error ? err.message : String(err)}`);
3323
+ }
3324
+ }
3325
+ }
3326
+ }
3327
+ }
3328
+ const resultAgents = [];
3329
+ const resultProjects = [];
3330
+ const importedSlugToAgentId = new Map();
3331
+ const existingSlugToAgentId = new Map();
3332
+ const existingAgents = await agents.list(targetCompany.id);
3333
+ for (const existing of existingAgents) {
3334
+ existingSlugToAgentId.set(normalizeAgentUrlKey(existing.name) ?? existing.id, existing.id);
3335
+ }
3336
+ const importedSlugToProjectId = new Map();
3337
+ const importedProjectWorkspaceIdByProjectSlug = new Map();
3338
+ const existingProjectSlugToId = new Map();
3339
+ const existingProjects = await projects.list(targetCompany.id);
3340
+ for (const existing of existingProjects) {
3341
+ existingProjectSlugToId.set(existing.urlKey, existing.id);
3342
+ }
3343
+ const importedSkills = include.skills || include.agents
3344
+ ? await companySkills.importPackageFiles(targetCompany.id, pickTextFiles(plan.source.files), {
3345
+ onConflict: resolveSkillConflictStrategy(mode, plan.collisionStrategy),
3346
+ })
3347
+ : [];
3348
+ const desiredSkillRefMap = new Map();
3349
+ for (const importedSkill of importedSkills) {
3350
+ desiredSkillRefMap.set(importedSkill.originalKey, importedSkill.skill.key);
3351
+ desiredSkillRefMap.set(importedSkill.originalSlug, importedSkill.skill.key);
3352
+ if (importedSkill.action === "skipped") {
3353
+ warnings.push(`Skipped skill ${importedSkill.originalSlug}; existing skill ${importedSkill.skill.slug} was kept.`);
3354
+ }
3355
+ else if (importedSkill.originalKey !== importedSkill.skill.key) {
3356
+ warnings.push(`Imported skill ${importedSkill.originalSlug} as ${importedSkill.skill.slug} to avoid overwriting an existing skill.`);
3357
+ }
3358
+ }
3359
+ if (include.agents) {
3360
+ for (const planAgent of plan.preview.plan.agentPlans) {
3361
+ const manifestAgent = plan.selectedAgents.find((agent) => agent.slug === planAgent.slug);
3362
+ if (!manifestAgent)
3363
+ continue;
3364
+ if (planAgent.action === "skip") {
3365
+ resultAgents.push({
3366
+ slug: planAgent.slug,
3367
+ id: planAgent.existingAgentId,
3368
+ action: "skipped",
3369
+ name: planAgent.plannedName,
3370
+ reason: planAgent.reason,
3371
+ });
3372
+ continue;
3373
+ }
3374
+ const bundlePrefix = `agents/${manifestAgent.slug}/`;
3375
+ const bundleFiles = Object.fromEntries(Object.entries(plan.source.files)
3376
+ .filter(([filePath]) => filePath.startsWith(bundlePrefix))
3377
+ .flatMap(([filePath, content]) => typeof content === "string"
3378
+ ? [[normalizePortablePath(filePath.slice(bundlePrefix.length)), content]]
3379
+ : []));
3380
+ const markdownRaw = bundleFiles["AGENTS.md"] ?? readPortableTextFile(plan.source.files, manifestAgent.path);
3381
+ const entryRelativePath = normalizePortablePath(manifestAgent.path).startsWith(bundlePrefix)
3382
+ ? normalizePortablePath(manifestAgent.path).slice(bundlePrefix.length)
3383
+ : "AGENTS.md";
3384
+ if (typeof markdownRaw === "string") {
3385
+ const importedInstructionsBody = parseFrontmatterMarkdown(markdownRaw).body;
3386
+ bundleFiles[entryRelativePath] = importedInstructionsBody;
3387
+ if (entryRelativePath !== "AGENTS.md") {
3388
+ bundleFiles["AGENTS.md"] = importedInstructionsBody;
3389
+ }
3390
+ }
3391
+ const fallbackPromptTemplate = asString(manifestAgent.adapterConfig.promptTemplate) || "";
3392
+ if (!markdownRaw && fallbackPromptTemplate) {
3393
+ bundleFiles["AGENTS.md"] = fallbackPromptTemplate;
3394
+ }
3395
+ if (!markdownRaw && !fallbackPromptTemplate) {
3396
+ warnings.push(`Missing AGENTS markdown for ${manifestAgent.slug}; imported with an empty managed bundle.`);
3397
+ }
3398
+ // Apply adapter overrides from request if present
3399
+ const adapterOverride = input.adapterOverrides?.[planAgent.slug];
3400
+ const effectiveAdapterType = adapterOverride?.adapterType ?? manifestAgent.adapterType;
3401
+ const baseAdapterConfig = adapterOverride?.adapterConfig
3402
+ ? { ...adapterOverride.adapterConfig }
3403
+ : { ...manifestAgent.adapterConfig };
3404
+ const desiredSkills = (manifestAgent.skills ?? []).map((skillRef) => desiredSkillRefMap.get(skillRef) ?? skillRef);
3405
+ const adapterConfigWithSkills = writeFideliOSSkillSyncPreference(baseAdapterConfig, desiredSkills);
3406
+ delete adapterConfigWithSkills.promptTemplate;
3407
+ delete adapterConfigWithSkills.bootstrapPromptTemplate; // deprecated
3408
+ delete adapterConfigWithSkills.instructionsFilePath;
3409
+ delete adapterConfigWithSkills.instructionsBundleMode;
3410
+ delete adapterConfigWithSkills.instructionsRootPath;
3411
+ delete adapterConfigWithSkills.instructionsEntryFile;
3412
+ const patch = {
3413
+ name: planAgent.plannedName,
3414
+ role: manifestAgent.role,
3415
+ title: manifestAgent.title,
3416
+ icon: manifestAgent.icon,
3417
+ capabilities: manifestAgent.capabilities,
3418
+ reportsTo: null,
3419
+ adapterType: effectiveAdapterType,
3420
+ adapterConfig: adapterConfigWithSkills,
3421
+ runtimeConfig: disableImportedTimerHeartbeat(manifestAgent.runtimeConfig),
3422
+ budgetMonthlyCents: manifestAgent.budgetMonthlyCents,
3423
+ permissions: manifestAgent.permissions,
3424
+ metadata: manifestAgent.metadata,
3425
+ };
3426
+ if (planAgent.action === "update" && planAgent.existingAgentId) {
3427
+ let updated = await agents.update(planAgent.existingAgentId, patch);
3428
+ if (!updated) {
3429
+ warnings.push(`Skipped update for missing agent ${planAgent.existingAgentId}.`);
3430
+ resultAgents.push({
3431
+ slug: planAgent.slug,
3432
+ id: null,
3433
+ action: "skipped",
3434
+ name: planAgent.plannedName,
3435
+ reason: "Existing target agent not found.",
3436
+ });
3437
+ continue;
3438
+ }
3439
+ try {
3440
+ const materialized = await instructions.materializeManagedBundle(updated, bundleFiles, {
3441
+ clearLegacyPromptTemplate: true,
3442
+ replaceExisting: true,
3443
+ });
3444
+ updated = await agents.update(updated.id, { adapterConfig: materialized.adapterConfig }) ?? updated;
3445
+ }
3446
+ catch (err) {
3447
+ warnings.push(`Failed to materialize instructions bundle for ${manifestAgent.slug}: ${err instanceof Error ? err.message : String(err)}`);
3448
+ }
3449
+ importedSlugToAgentId.set(planAgent.slug, updated.id);
3450
+ existingSlugToAgentId.set(normalizeAgentUrlKey(updated.name) ?? updated.id, updated.id);
3451
+ resultAgents.push({
3452
+ slug: planAgent.slug,
3453
+ id: updated.id,
3454
+ action: "updated",
3455
+ name: updated.name,
3456
+ reason: planAgent.reason,
3457
+ });
3458
+ continue;
3459
+ }
3460
+ let created = await agents.create(targetCompany.id, patch);
3461
+ await access.ensureMembership(targetCompany.id, "agent", created.id, "member", "active");
3462
+ await access.setPrincipalPermission(targetCompany.id, "agent", created.id, "tasks:assign", true, actorUserId ?? null);
3463
+ try {
3464
+ const materialized = await instructions.materializeManagedBundle(created, bundleFiles, {
3465
+ clearLegacyPromptTemplate: true,
3466
+ replaceExisting: true,
3467
+ });
3468
+ created = await agents.update(created.id, { adapterConfig: materialized.adapterConfig }) ?? created;
3469
+ }
3470
+ catch (err) {
3471
+ warnings.push(`Failed to materialize instructions bundle for ${manifestAgent.slug}: ${err instanceof Error ? err.message : String(err)}`);
3472
+ }
3473
+ importedSlugToAgentId.set(planAgent.slug, created.id);
3474
+ existingSlugToAgentId.set(normalizeAgentUrlKey(created.name) ?? created.id, created.id);
3475
+ resultAgents.push({
3476
+ slug: planAgent.slug,
3477
+ id: created.id,
3478
+ action: "created",
3479
+ name: created.name,
3480
+ reason: planAgent.reason,
3481
+ });
3482
+ }
3483
+ // Apply reporting links once all imported agent ids are available.
3484
+ for (const manifestAgent of plan.selectedAgents) {
3485
+ const agentId = importedSlugToAgentId.get(manifestAgent.slug);
3486
+ if (!agentId)
3487
+ continue;
3488
+ const managerSlug = manifestAgent.reportsToSlug;
3489
+ if (!managerSlug)
3490
+ continue;
3491
+ const managerId = importedSlugToAgentId.get(managerSlug) ?? existingSlugToAgentId.get(managerSlug) ?? null;
3492
+ if (!managerId || managerId === agentId)
3493
+ continue;
3494
+ try {
3495
+ await agents.update(agentId, { reportsTo: managerId });
3496
+ }
3497
+ catch {
3498
+ warnings.push(`Could not assign manager ${managerSlug} for imported agent ${manifestAgent.slug}.`);
3499
+ }
3500
+ }
3501
+ }
3502
+ if (include.projects) {
3503
+ for (const planProject of plan.preview.plan.projectPlans) {
3504
+ const manifestProject = sourceManifest.projects.find((project) => project.slug === planProject.slug);
3505
+ if (!manifestProject)
3506
+ continue;
3507
+ if (planProject.action === "skip") {
3508
+ resultProjects.push({
3509
+ slug: planProject.slug,
3510
+ id: planProject.existingProjectId,
3511
+ action: "skipped",
3512
+ name: planProject.plannedName,
3513
+ reason: planProject.reason,
3514
+ });
3515
+ continue;
3516
+ }
3517
+ const projectLeadAgentId = manifestProject.leadAgentSlug
3518
+ ? importedSlugToAgentId.get(manifestProject.leadAgentSlug)
3519
+ ?? existingSlugToAgentId.get(manifestProject.leadAgentSlug)
3520
+ ?? null
3521
+ : null;
3522
+ const projectWorkspaceIdByKey = new Map();
3523
+ const projectPatch = {
3524
+ name: planProject.plannedName,
3525
+ description: manifestProject.description,
3526
+ leadAgentId: projectLeadAgentId,
3527
+ targetDate: manifestProject.targetDate,
3528
+ color: manifestProject.color,
3529
+ status: manifestProject.status && PROJECT_STATUSES.includes(manifestProject.status)
3530
+ ? manifestProject.status
3531
+ : "backlog",
3532
+ executionWorkspacePolicy: stripPortableProjectExecutionWorkspaceRefs(manifestProject.executionWorkspacePolicy),
3533
+ };
3534
+ let projectId = null;
3535
+ if (planProject.action === "update" && planProject.existingProjectId) {
3536
+ const updated = await projects.update(planProject.existingProjectId, projectPatch);
3537
+ if (!updated) {
3538
+ warnings.push(`Skipped update for missing project ${planProject.existingProjectId}.`);
3539
+ resultProjects.push({
3540
+ slug: planProject.slug,
3541
+ id: null,
3542
+ action: "skipped",
3543
+ name: planProject.plannedName,
3544
+ reason: "Existing target project not found.",
3545
+ });
3546
+ continue;
3547
+ }
3548
+ projectId = updated.id;
3549
+ importedSlugToProjectId.set(planProject.slug, updated.id);
3550
+ existingProjectSlugToId.set(updated.urlKey, updated.id);
3551
+ resultProjects.push({
3552
+ slug: planProject.slug,
3553
+ id: updated.id,
3554
+ action: "updated",
3555
+ name: updated.name,
3556
+ reason: planProject.reason,
3557
+ });
3558
+ }
3559
+ else {
3560
+ const created = await projects.create(targetCompany.id, projectPatch);
3561
+ projectId = created.id;
3562
+ importedSlugToProjectId.set(planProject.slug, created.id);
3563
+ existingProjectSlugToId.set(created.urlKey, created.id);
3564
+ resultProjects.push({
3565
+ slug: planProject.slug,
3566
+ id: created.id,
3567
+ action: "created",
3568
+ name: created.name,
3569
+ reason: planProject.reason,
3570
+ });
3571
+ }
3572
+ if (!projectId)
3573
+ continue;
3574
+ for (const workspace of manifestProject.workspaces) {
3575
+ const createdWorkspace = await projects.createWorkspace(projectId, {
3576
+ name: workspace.name,
3577
+ sourceType: workspace.sourceType ?? undefined,
3578
+ repoUrl: workspace.repoUrl ?? undefined,
3579
+ repoRef: workspace.repoRef ?? undefined,
3580
+ defaultRef: workspace.defaultRef ?? undefined,
3581
+ visibility: workspace.visibility ?? undefined,
3582
+ setupCommand: workspace.setupCommand ?? undefined,
3583
+ cleanupCommand: workspace.cleanupCommand ?? undefined,
3584
+ metadata: workspace.metadata ?? undefined,
3585
+ isPrimary: workspace.isPrimary,
3586
+ });
3587
+ if (!createdWorkspace) {
3588
+ warnings.push(`Project ${planProject.slug} workspace ${workspace.key} could not be created during import.`);
3589
+ continue;
3590
+ }
3591
+ projectWorkspaceIdByKey.set(workspace.key, createdWorkspace.id);
3592
+ }
3593
+ importedProjectWorkspaceIdByProjectSlug.set(planProject.slug, projectWorkspaceIdByKey);
3594
+ const hydratedProjectExecutionWorkspacePolicy = importPortableProjectExecutionWorkspacePolicy(planProject.slug, manifestProject.executionWorkspacePolicy, projectWorkspaceIdByKey, warnings);
3595
+ if (hydratedProjectExecutionWorkspacePolicy) {
3596
+ await projects.update(projectId, {
3597
+ executionWorkspacePolicy: hydratedProjectExecutionWorkspacePolicy,
3598
+ });
3599
+ }
3600
+ }
3601
+ }
3602
+ if (include.issues) {
3603
+ const routines = routineService(db);
3604
+ for (const manifestIssue of sourceManifest.issues) {
3605
+ const markdownRaw = readPortableTextFile(plan.source.files, manifestIssue.path);
3606
+ const parsed = markdownRaw ? parseFrontmatterMarkdown(markdownRaw) : null;
3607
+ const description = parsed?.body || manifestIssue.description || null;
3608
+ const assigneeAgentId = manifestIssue.assigneeAgentSlug
3609
+ ? importedSlugToAgentId.get(manifestIssue.assigneeAgentSlug)
3610
+ ?? existingSlugToAgentId.get(manifestIssue.assigneeAgentSlug)
3611
+ ?? null
3612
+ : null;
3613
+ const projectId = manifestIssue.projectSlug
3614
+ ? importedSlugToProjectId.get(manifestIssue.projectSlug)
3615
+ ?? existingProjectSlugToId.get(manifestIssue.projectSlug)
3616
+ ?? null
3617
+ : null;
3618
+ const projectWorkspaceId = manifestIssue.projectSlug && manifestIssue.projectWorkspaceKey
3619
+ ? importedProjectWorkspaceIdByProjectSlug.get(manifestIssue.projectSlug)?.get(manifestIssue.projectWorkspaceKey) ?? null
3620
+ : null;
3621
+ if (manifestIssue.projectWorkspaceKey && !projectWorkspaceId) {
3622
+ warnings.push(`Task ${manifestIssue.slug} references workspace key ${manifestIssue.projectWorkspaceKey}, but that workspace was not imported.`);
3623
+ }
3624
+ if (manifestIssue.recurring) {
3625
+ if (!projectId || !assigneeAgentId) {
3626
+ throw unprocessable(`Recurring task ${manifestIssue.slug} is missing the project or assignee required to create a routine.`);
3627
+ }
3628
+ const resolvedRoutine = resolvePortableRoutineDefinition(manifestIssue, parsed?.frontmatter.schedule);
3629
+ if (resolvedRoutine.errors.length > 0) {
3630
+ throw unprocessable(`Recurring task ${manifestIssue.slug} could not be imported as a routine: ${resolvedRoutine.errors.join("; ")}`);
3631
+ }
3632
+ warnings.push(...resolvedRoutine.warnings);
3633
+ const routineDefinition = resolvedRoutine.routine ?? {
3634
+ concurrencyPolicy: null,
3635
+ catchUpPolicy: null,
3636
+ triggers: [],
3637
+ };
3638
+ const createdRoutine = await routines.create(targetCompany.id, {
3639
+ projectId,
3640
+ goalId: null,
3641
+ parentIssueId: null,
3642
+ title: manifestIssue.title,
3643
+ description,
3644
+ assigneeAgentId,
3645
+ priority: manifestIssue.priority && ISSUE_PRIORITIES.includes(manifestIssue.priority)
3646
+ ? manifestIssue.priority
3647
+ : "medium",
3648
+ status: manifestIssue.status && ROUTINE_STATUSES.includes(manifestIssue.status)
3649
+ ? manifestIssue.status
3650
+ : "active",
3651
+ concurrencyPolicy: routineDefinition.concurrencyPolicy && ROUTINE_CONCURRENCY_POLICIES.includes(routineDefinition.concurrencyPolicy)
3652
+ ? routineDefinition.concurrencyPolicy
3653
+ : "coalesce_if_active",
3654
+ catchUpPolicy: routineDefinition.catchUpPolicy && ROUTINE_CATCH_UP_POLICIES.includes(routineDefinition.catchUpPolicy)
3655
+ ? routineDefinition.catchUpPolicy
3656
+ : "skip_missed",
3657
+ }, {
3658
+ agentId: null,
3659
+ userId: actorUserId ?? null,
3660
+ });
3661
+ for (const trigger of routineDefinition.triggers) {
3662
+ if (trigger.kind === "schedule") {
3663
+ await routines.createTrigger(createdRoutine.id, {
3664
+ kind: "schedule",
3665
+ label: trigger.label,
3666
+ enabled: trigger.enabled,
3667
+ cronExpression: trigger.cronExpression,
3668
+ timezone: trigger.timezone,
3669
+ }, {
3670
+ agentId: null,
3671
+ userId: actorUserId ?? null,
3672
+ });
3673
+ continue;
3674
+ }
3675
+ if (trigger.kind === "webhook") {
3676
+ await routines.createTrigger(createdRoutine.id, {
3677
+ kind: "webhook",
3678
+ label: trigger.label,
3679
+ enabled: trigger.enabled,
3680
+ signingMode: trigger.signingMode && ROUTINE_TRIGGER_SIGNING_MODES.includes(trigger.signingMode)
3681
+ ? trigger.signingMode
3682
+ : "bearer",
3683
+ replayWindowSec: trigger.replayWindowSec ?? 300,
3684
+ }, {
3685
+ agentId: null,
3686
+ userId: actorUserId ?? null,
3687
+ });
3688
+ continue;
3689
+ }
3690
+ await routines.createTrigger(createdRoutine.id, {
3691
+ kind: "api",
3692
+ label: trigger.label,
3693
+ enabled: trigger.enabled,
3694
+ }, {
3695
+ agentId: null,
3696
+ userId: actorUserId ?? null,
3697
+ });
3698
+ }
3699
+ continue;
3700
+ }
3701
+ await issues.create(targetCompany.id, {
3702
+ projectId,
3703
+ projectWorkspaceId,
3704
+ title: manifestIssue.title,
3705
+ description,
3706
+ assigneeAgentId,
3707
+ status: manifestIssue.status && ISSUE_STATUSES.includes(manifestIssue.status)
3708
+ ? manifestIssue.status
3709
+ : "backlog",
3710
+ priority: manifestIssue.priority && ISSUE_PRIORITIES.includes(manifestIssue.priority)
3711
+ ? manifestIssue.priority
3712
+ : "medium",
3713
+ billingCode: manifestIssue.billingCode,
3714
+ assigneeAdapterOverrides: manifestIssue.assigneeAdapterOverrides,
3715
+ executionWorkspaceSettings: manifestIssue.executionWorkspaceSettings,
3716
+ labelIds: [],
3717
+ });
3718
+ }
3719
+ }
3720
+ return {
3721
+ company: {
3722
+ id: targetCompany.id,
3723
+ name: targetCompany.name,
3724
+ action: companyAction,
3725
+ },
3726
+ agents: resultAgents,
3727
+ projects: resultProjects,
3728
+ envInputs: sourceManifest.envInputs ?? [],
3729
+ warnings,
3730
+ };
3731
+ }
3732
+ return {
3733
+ exportBundle,
3734
+ previewExport,
3735
+ previewImport,
3736
+ importBundle,
3737
+ };
3738
+ }
3739
+ //# sourceMappingURL=company-portability.js.map