@iloom/cli 0.9.2 → 0.10.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 (231) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +160 -41
  3. package/dist/{BranchNamingService-K6XNWQ6C.js → BranchNamingService-25KSZAEM.js} +2 -2
  4. package/dist/ClaudeContextManager-66GR4BGM.js +14 -0
  5. package/dist/ClaudeService-7KM5NA5Z.js +13 -0
  6. package/dist/{GitHubService-TGWJN4V4.js → GitHubService-MEHKHUQP.js} +4 -4
  7. package/dist/IssueTrackerFactory-NG53YX5S.js +14 -0
  8. package/dist/{LoomLauncher-73NXL2CL.js → LoomLauncher-TDLZSYG2.js} +9 -9
  9. package/dist/{MetadataManager-W3C54UYT.js → MetadataManager-5QZSTKNN.js} +2 -2
  10. package/dist/{ProjectCapabilityDetector-N5L7T4IY.js → ProjectCapabilityDetector-5KSYUTBJ.js} +3 -3
  11. package/dist/{PromptTemplateManager-36YLQRHP.js → PromptTemplateManager-YOE2SIPG.js} +2 -2
  12. package/dist/README.md +160 -41
  13. package/dist/{SettingsManager-AW3JTJHD.js → SettingsManager-FNKCOZMQ.js} +4 -2
  14. package/dist/agents/iloom-artifact-reviewer.md +11 -0
  15. package/dist/agents/iloom-code-reviewer.md +14 -0
  16. package/dist/agents/iloom-issue-analyze-and-plan.md +55 -12
  17. package/dist/agents/iloom-issue-analyzer.md +49 -6
  18. package/dist/agents/iloom-issue-complexity-evaluator.md +47 -6
  19. package/dist/agents/iloom-issue-enhancer.md +86 -7
  20. package/dist/agents/iloom-issue-implementer.md +48 -7
  21. package/dist/agents/iloom-issue-planner.md +115 -62
  22. package/dist/{build-THZI572G.js → build-VHGEMXBA.js} +9 -9
  23. package/dist/chunk-4232AHNQ.js +35 -0
  24. package/dist/chunk-4232AHNQ.js.map +1 -0
  25. package/dist/chunk-4E7LCFUG.js +24 -0
  26. package/dist/chunk-4E7LCFUG.js.map +1 -0
  27. package/dist/{chunk-AR5QKYNE.js → chunk-4FGEGQW4.js} +4 -4
  28. package/dist/{chunk-R4YWBGY6.js → chunk-5FJWO4IT.js} +67 -22
  29. package/dist/chunk-5FJWO4IT.js.map +1 -0
  30. package/dist/{chunk-VPTAX5TR.js → chunk-5RPBYK5Q.js} +35 -30
  31. package/dist/chunk-5RPBYK5Q.js.map +1 -0
  32. package/dist/{chunk-YKFCCV6S.js → chunk-63QWFWH3.js} +7 -7
  33. package/dist/chunk-63QWFWH3.js.map +1 -0
  34. package/dist/{chunk-RI2YL6TK.js → chunk-7VHJNVLF.js} +80 -23
  35. package/dist/chunk-7VHJNVLF.js.map +1 -0
  36. package/dist/{chunk-B7U6OKUR.js → chunk-C6HNNJIV.js} +11 -3
  37. package/dist/chunk-C6HNNJIV.js.map +1 -0
  38. package/dist/{chunk-A7NJF73J.js → chunk-CVCTIDDK.js} +4 -4
  39. package/dist/{chunk-Z2TWEXR7.js → chunk-E6KOWMKA.js} +6 -6
  40. package/dist/chunk-E6KOWMKA.js.map +1 -0
  41. package/dist/{chunk-3I4ONZRT.js → chunk-EVPZFV3K.js} +10 -10
  42. package/dist/chunk-EVPZFV3K.js.map +1 -0
  43. package/dist/{chunk-IZIYLYPK.js → chunk-G5V75JD5.js} +2 -2
  44. package/dist/chunk-GRISNU6G.js +651 -0
  45. package/dist/chunk-GRISNU6G.js.map +1 -0
  46. package/dist/chunk-HEXKPKCK.js +1396 -0
  47. package/dist/chunk-HEXKPKCK.js.map +1 -0
  48. package/dist/{chunk-TC7APDKU.js → chunk-I5T677EA.js} +2 -2
  49. package/dist/{chunk-KBEIQP4G.js → chunk-KB64WNBZ.js} +43 -3
  50. package/dist/chunk-KB64WNBZ.js.map +1 -0
  51. package/dist/{chunk-NWMORW3U.js → chunk-KIK2ZFAL.js} +2 -2
  52. package/dist/{chunk-CWRI4JC3.js → chunk-KKV5WH5M.js} +30 -31
  53. package/dist/chunk-KKV5WH5M.js.map +1 -0
  54. package/dist/{chunk-DGG2VY7B.js → chunk-KVHIAWVT.js} +9 -9
  55. package/dist/chunk-KVHIAWVT.js.map +1 -0
  56. package/dist/{chunk-OFDN5NKS.js → chunk-KXDRI47U.js} +69 -12
  57. package/dist/chunk-KXDRI47U.js.map +1 -0
  58. package/dist/{chunk-NUACL52E.js → chunk-LLHXQS3C.js} +2 -2
  59. package/dist/chunk-LUKXJSRI.js +73 -0
  60. package/dist/chunk-LUKXJSRI.js.map +1 -0
  61. package/dist/{chunk-TL72BGP6.js → chunk-MORRVYPT.js} +2 -2
  62. package/dist/chunk-OTGH2HRS.js +1427 -0
  63. package/dist/chunk-OTGH2HRS.js.map +1 -0
  64. package/dist/{chunk-7ZEHSSUP.js → chunk-P4O6EH46.js} +4 -4
  65. package/dist/{chunk-KAYXR544.js → chunk-QVLPWNE3.js} +2 -2
  66. package/dist/chunk-QZWEJVWV.js +207 -0
  67. package/dist/chunk-QZWEJVWV.js.map +1 -0
  68. package/dist/chunk-RJ3VBUFK.js +781 -0
  69. package/dist/chunk-RJ3VBUFK.js.map +1 -0
  70. package/dist/chunk-RSYT7MVI.js +202 -0
  71. package/dist/chunk-RSYT7MVI.js.map +1 -0
  72. package/dist/{chunk-6IIL5M2L.js → chunk-S7PZA6IV.js} +10 -8
  73. package/dist/{chunk-6IIL5M2L.js.map → chunk-S7PZA6IV.js.map} +1 -1
  74. package/dist/chunk-SKSYYBCU.js +229 -0
  75. package/dist/chunk-SKSYYBCU.js.map +1 -0
  76. package/dist/{chunk-ULSWCPQG.js → chunk-SWSJWA2S.js} +476 -5
  77. package/dist/chunk-SWSJWA2S.js.map +1 -0
  78. package/dist/{chunk-KXGQYLFZ.js → chunk-UKBAJ2QQ.js} +61 -7
  79. package/dist/chunk-UKBAJ2QQ.js.map +1 -0
  80. package/dist/{chunk-FO5GGFOV.js → chunk-UR5DGNUO.js} +71 -9
  81. package/dist/chunk-UR5DGNUO.js.map +1 -0
  82. package/dist/{chunk-QN47QVBX.js → chunk-UUEW5KWB.js} +1 -1
  83. package/dist/chunk-UUEW5KWB.js.map +1 -0
  84. package/dist/{chunk-4CO6KG5S.js → chunk-VG45TUYK.js} +53 -7
  85. package/dist/{chunk-4CO6KG5S.js.map → chunk-VG45TUYK.js.map} +1 -1
  86. package/dist/{chunk-4LKGCFGG.js → chunk-WWKOVDWC.js} +2 -2
  87. package/dist/{chunk-KJTVU3HZ.js → chunk-WXIM2WS7.js} +8 -8
  88. package/dist/chunk-WXIM2WS7.js.map +1 -0
  89. package/dist/{chunk-VOGGLPG5.js → chunk-YQ57ORTV.js} +14 -1
  90. package/dist/chunk-YQ57ORTV.js.map +1 -0
  91. package/dist/{chunk-SOSQILHO.js → chunk-ZNMPGMHY.js} +44 -797
  92. package/dist/chunk-ZNMPGMHY.js.map +1 -0
  93. package/dist/{claude-TP2QO3BU.js → claude-7GGEWVEM.js} +2 -2
  94. package/dist/{cleanup-PJRIFFU4.js → cleanup-6PVAC4NI.js} +85 -34
  95. package/dist/cleanup-6PVAC4NI.js.map +1 -0
  96. package/dist/cli.js +630 -801
  97. package/dist/cli.js.map +1 -1
  98. package/dist/{commit-IVP3M4HG.js → commit-FZR5XDQG.js} +26 -23
  99. package/dist/commit-FZR5XDQG.js.map +1 -0
  100. package/dist/{compile-R2J65HBQ.js → compile-7ALJHZ4N.js} +9 -9
  101. package/dist/{contribute-VDZXHK5Y.js → contribute-5GKLK3BQ.js} +14 -6
  102. package/dist/contribute-5GKLK3BQ.js.map +1 -0
  103. package/dist/{dev-server-7F622OEO.js → dev-server-7SMIB7OF.js} +29 -15
  104. package/dist/dev-server-7SMIB7OF.js.map +1 -0
  105. package/dist/{feedback-E7VET7CL.js → feedback-G2GJFN2F.js} +18 -16
  106. package/dist/{feedback-E7VET7CL.js.map → feedback-G2GJFN2F.js.map} +1 -1
  107. package/dist/{git-2QDQ2X2S.js → git-GTLKAZRJ.js} +4 -4
  108. package/dist/hooks/iloom-hook.js +15 -0
  109. package/dist/ignite-H2O5Y5A2.js +34 -0
  110. package/dist/ignite-H2O5Y5A2.js.map +1 -0
  111. package/dist/index.d.ts +482 -58
  112. package/dist/index.js +1340 -44
  113. package/dist/index.js.map +1 -1
  114. package/dist/{init-676DHF6R.js → init-32YOKXRL.js} +57 -21
  115. package/dist/init-32YOKXRL.js.map +1 -0
  116. package/dist/{issues-PJSOLOBJ.js → issues-4UUAQ5K6.js} +61 -20
  117. package/dist/issues-4UUAQ5K6.js.map +1 -0
  118. package/dist/{lint-CJM7BAIM.js → lint-AAN2NZWG.js} +9 -9
  119. package/dist/mcp/harness-server.js +140 -0
  120. package/dist/mcp/harness-server.js.map +1 -0
  121. package/dist/mcp/issue-management-server.js +2599 -262
  122. package/dist/mcp/issue-management-server.js.map +1 -1
  123. package/dist/mcp/recap-server.js +144 -21
  124. package/dist/mcp/recap-server.js.map +1 -1
  125. package/dist/{neon-helpers-VVFFTLXE.js → neon-helpers-CQN2PB4S.js} +3 -3
  126. package/dist/neon-helpers-CQN2PB4S.js.map +1 -0
  127. package/dist/{open-544H7JF5.js → open-FXWW3VI4.js} +15 -15
  128. package/dist/open-FXWW3VI4.js.map +1 -0
  129. package/dist/{plan-Q7ELXDLC.js → plan-RQ5FPIGF.js} +358 -40
  130. package/dist/plan-RQ5FPIGF.js.map +1 -0
  131. package/dist/{projects-LH362JZQ.js → projects-2UOXFLNZ.js} +4 -4
  132. package/dist/prompts/CLAUDE.md +62 -0
  133. package/dist/prompts/init-prompt.txt +430 -34
  134. package/dist/prompts/issue-prompt.txt +473 -54
  135. package/dist/prompts/plan-prompt.txt +140 -19
  136. package/dist/prompts/pr-prompt.txt +44 -1
  137. package/dist/prompts/regular-prompt.txt +42 -1
  138. package/dist/prompts/session-summary-prompt.txt +14 -0
  139. package/dist/prompts/swarm-orchestrator-prompt.txt +464 -0
  140. package/dist/{rebase-YND35CIE.js → rebase-6NVLX5V7.js} +21 -12
  141. package/dist/rebase-6NVLX5V7.js.map +1 -0
  142. package/dist/{recap-3W7COH7D.js → recap-OMBOKJST.js} +47 -19
  143. package/dist/recap-OMBOKJST.js.map +1 -0
  144. package/dist/{run-QUXJKDQQ.js → run-BBXLRIZB.js} +15 -15
  145. package/dist/run-BBXLRIZB.js.map +1 -0
  146. package/dist/schema/package-iloom.schema.json +58 -0
  147. package/dist/schema/settings.schema.json +149 -15
  148. package/dist/{shell-QGECBLST.js → shell-RF7LTND5.js} +14 -7
  149. package/dist/shell-RF7LTND5.js.map +1 -0
  150. package/dist/{summary-G2T4452H.js → summary-WTQZ7XG2.js} +27 -25
  151. package/dist/summary-WTQZ7XG2.js.map +1 -0
  152. package/dist/{test-EA5NQFDC.js → test-SGO6I5Z7.js} +9 -9
  153. package/dist/{test-git-M7LSLEFL.js → test-git-XM4TM65W.js} +4 -4
  154. package/dist/test-jira-LDTOYFSD.js +96 -0
  155. package/dist/test-jira-LDTOYFSD.js.map +1 -0
  156. package/dist/{test-prefix-64NAAUON.js → test-prefix-GBO37XCN.js} +4 -4
  157. package/dist/{test-webserver-OK6Z5FJM.js → test-webserver-NZ3JTVLL.js} +6 -6
  158. package/dist/{vscode-AR5NNXXI.js → vscode-6XUGHJKL.js} +7 -7
  159. package/package.json +5 -1
  160. package/dist/ClaudeContextManager-HR5JQKAI.js +0 -14
  161. package/dist/ClaudeService-TK7FMC2X.js +0 -13
  162. package/dist/chunk-3I4ONZRT.js.map +0 -1
  163. package/dist/chunk-B7U6OKUR.js.map +0 -1
  164. package/dist/chunk-CWRI4JC3.js.map +0 -1
  165. package/dist/chunk-DGG2VY7B.js.map +0 -1
  166. package/dist/chunk-FJDRTVJX.js +0 -520
  167. package/dist/chunk-FJDRTVJX.js.map +0 -1
  168. package/dist/chunk-FO5GGFOV.js.map +0 -1
  169. package/dist/chunk-KBEIQP4G.js.map +0 -1
  170. package/dist/chunk-KJTVU3HZ.js.map +0 -1
  171. package/dist/chunk-KXGQYLFZ.js.map +0 -1
  172. package/dist/chunk-OFDN5NKS.js.map +0 -1
  173. package/dist/chunk-QN47QVBX.js.map +0 -1
  174. package/dist/chunk-R4YWBGY6.js.map +0 -1
  175. package/dist/chunk-RI2YL6TK.js.map +0 -1
  176. package/dist/chunk-SOSQILHO.js.map +0 -1
  177. package/dist/chunk-ULSWCPQG.js.map +0 -1
  178. package/dist/chunk-VOGGLPG5.js.map +0 -1
  179. package/dist/chunk-VPTAX5TR.js.map +0 -1
  180. package/dist/chunk-W6DP5RVR.js +0 -101
  181. package/dist/chunk-W6DP5RVR.js.map +0 -1
  182. package/dist/chunk-WHI5KEOX.js +0 -121
  183. package/dist/chunk-WHI5KEOX.js.map +0 -1
  184. package/dist/chunk-YKFCCV6S.js.map +0 -1
  185. package/dist/chunk-Z2TWEXR7.js.map +0 -1
  186. package/dist/cleanup-PJRIFFU4.js.map +0 -1
  187. package/dist/commit-IVP3M4HG.js.map +0 -1
  188. package/dist/contribute-VDZXHK5Y.js.map +0 -1
  189. package/dist/dev-server-7F622OEO.js.map +0 -1
  190. package/dist/ignite-IW35CDBD.js +0 -784
  191. package/dist/ignite-IW35CDBD.js.map +0 -1
  192. package/dist/init-676DHF6R.js.map +0 -1
  193. package/dist/issues-PJSOLOBJ.js.map +0 -1
  194. package/dist/open-544H7JF5.js.map +0 -1
  195. package/dist/plan-Q7ELXDLC.js.map +0 -1
  196. package/dist/rebase-YND35CIE.js.map +0 -1
  197. package/dist/recap-3W7COH7D.js.map +0 -1
  198. package/dist/run-QUXJKDQQ.js.map +0 -1
  199. package/dist/shell-QGECBLST.js.map +0 -1
  200. package/dist/summary-G2T4452H.js.map +0 -1
  201. /package/dist/{BranchNamingService-K6XNWQ6C.js.map → BranchNamingService-25KSZAEM.js.map} +0 -0
  202. /package/dist/{ClaudeContextManager-HR5JQKAI.js.map → ClaudeContextManager-66GR4BGM.js.map} +0 -0
  203. /package/dist/{ClaudeService-TK7FMC2X.js.map → ClaudeService-7KM5NA5Z.js.map} +0 -0
  204. /package/dist/{GitHubService-TGWJN4V4.js.map → GitHubService-MEHKHUQP.js.map} +0 -0
  205. /package/dist/{MetadataManager-W3C54UYT.js.map → IssueTrackerFactory-NG53YX5S.js.map} +0 -0
  206. /package/dist/{LoomLauncher-73NXL2CL.js.map → LoomLauncher-TDLZSYG2.js.map} +0 -0
  207. /package/dist/{ProjectCapabilityDetector-N5L7T4IY.js.map → MetadataManager-5QZSTKNN.js.map} +0 -0
  208. /package/dist/{PromptTemplateManager-36YLQRHP.js.map → ProjectCapabilityDetector-5KSYUTBJ.js.map} +0 -0
  209. /package/dist/{SettingsManager-AW3JTJHD.js.map → PromptTemplateManager-YOE2SIPG.js.map} +0 -0
  210. /package/dist/{claude-TP2QO3BU.js.map → SettingsManager-FNKCOZMQ.js.map} +0 -0
  211. /package/dist/{build-THZI572G.js.map → build-VHGEMXBA.js.map} +0 -0
  212. /package/dist/{chunk-AR5QKYNE.js.map → chunk-4FGEGQW4.js.map} +0 -0
  213. /package/dist/{chunk-A7NJF73J.js.map → chunk-CVCTIDDK.js.map} +0 -0
  214. /package/dist/{chunk-IZIYLYPK.js.map → chunk-G5V75JD5.js.map} +0 -0
  215. /package/dist/{chunk-TC7APDKU.js.map → chunk-I5T677EA.js.map} +0 -0
  216. /package/dist/{chunk-NWMORW3U.js.map → chunk-KIK2ZFAL.js.map} +0 -0
  217. /package/dist/{chunk-NUACL52E.js.map → chunk-LLHXQS3C.js.map} +0 -0
  218. /package/dist/{chunk-TL72BGP6.js.map → chunk-MORRVYPT.js.map} +0 -0
  219. /package/dist/{chunk-7ZEHSSUP.js.map → chunk-P4O6EH46.js.map} +0 -0
  220. /package/dist/{chunk-KAYXR544.js.map → chunk-QVLPWNE3.js.map} +0 -0
  221. /package/dist/{chunk-4LKGCFGG.js.map → chunk-WWKOVDWC.js.map} +0 -0
  222. /package/dist/{git-2QDQ2X2S.js.map → claude-7GGEWVEM.js.map} +0 -0
  223. /package/dist/{compile-R2J65HBQ.js.map → compile-7ALJHZ4N.js.map} +0 -0
  224. /package/dist/{neon-helpers-VVFFTLXE.js.map → git-GTLKAZRJ.js.map} +0 -0
  225. /package/dist/{lint-CJM7BAIM.js.map → lint-AAN2NZWG.js.map} +0 -0
  226. /package/dist/{projects-LH362JZQ.js.map → projects-2UOXFLNZ.js.map} +0 -0
  227. /package/dist/{test-EA5NQFDC.js.map → test-SGO6I5Z7.js.map} +0 -0
  228. /package/dist/{test-git-M7LSLEFL.js.map → test-git-XM4TM65W.js.map} +0 -0
  229. /package/dist/{test-prefix-64NAAUON.js.map → test-prefix-GBO37XCN.js.map} +0 -0
  230. /package/dist/{test-webserver-OK6Z5FJM.js.map → test-webserver-NZ3JTVLL.js.map} +0 -0
  231. /package/dist/{vscode-AR5NNXXI.js.map → vscode-6XUGHJKL.js.map} +0 -0
@@ -9,9 +9,9 @@ import path from "path";
9
9
  import os from "os";
10
10
  import { z } from "zod";
11
11
  import deepmerge from "deepmerge";
12
- var PROJECT_CAPABILITIES = ["cli", "web"];
13
- var AgentSettingsSchema = z.object({
12
+ var BaseAgentSettingsSchema = z.object({
14
13
  model: z.enum(["sonnet", "opus", "haiku"]).optional().describe("Claude model shorthand: sonnet, opus, or haiku"),
14
+ swarmModel: z.enum(["sonnet", "opus", "haiku"]).optional().describe("Model to use for this agent in swarm mode. Overrides the base model when running inside swarm workers."),
15
15
  enabled: z.boolean().optional().describe("Whether this agent is enabled. Defaults to true."),
16
16
  providers: z.record(
17
17
  z.enum(["claude", "gemini", "codex"]),
@@ -19,8 +19,13 @@ var AgentSettingsSchema = z.object({
19
19
  ).optional().describe('Map of review providers to model names. Keys: claude, gemini, codex. Values: model name strings (e.g., "sonnet", "gemini-3-pro-preview", "gpt-5.2-codex")'),
20
20
  review: z.boolean().optional().describe("Whether artifacts from this agent should be reviewed before posting (defaults to false)")
21
21
  });
22
+ var AgentSettingsSchema = BaseAgentSettingsSchema.extend({
23
+ agents: z.record(z.string(), BaseAgentSettingsSchema).optional().describe("Nested per-agent settings. Only meaningful under the iloom-swarm-worker agent entry for sub-agent timeout configuration."),
24
+ subAgentTimeout: z.number().min(1, "Sub-agent timeout must be at least 1 minute").max(120, "Sub-agent timeout cannot exceed 120 minutes").default(10).describe("Timeout in minutes for sub-agent claude -p invocations in swarm mode. Applies to each phase agent (evaluator, analyzer, planner, implementer) when invoked via the Bash tool. Default: 10 minutes. Only meaningful under the iloom-swarm-worker agent entry.")
25
+ });
22
26
  var SpinAgentSettingsSchema = z.object({
23
- model: z.enum(["sonnet", "opus", "haiku"]).default("opus").describe("Claude model shorthand for spin orchestrator")
27
+ model: z.enum(["sonnet", "opus", "haiku"]).default("opus").describe("Claude model shorthand for spin orchestrator"),
28
+ swarmModel: z.enum(["sonnet", "opus", "haiku"]).optional().describe("Model for the spin orchestrator when running in swarm mode. Overrides spin.model for swarm workflows.")
24
29
  });
25
30
  var PlanCommandSettingsSchema = z.object({
26
31
  model: z.enum(["sonnet", "opus", "haiku"]).default("opus").describe("Claude model shorthand for plan command"),
@@ -59,19 +64,17 @@ var WorkflowsSettingsSchemaNoDefaults = z.object({
59
64
  regular: WorkflowPermissionSchemaNoDefaults.optional()
60
65
  }).optional();
61
66
  var CapabilitiesSettingsSchema = z.object({
62
- capabilities: z.array(z.enum(PROJECT_CAPABILITIES)).optional().describe("Explicitly declared project capabilities (auto-detected if not specified)"),
63
67
  web: z.object({
64
68
  basePort: z.number().min(1, "Base port must be >= 1").max(65535, "Base port must be <= 65535").optional().describe("Base port for web workspace port calculations (default: 3000)")
65
- }).optional(),
69
+ }).optional().describe('Web dev server settings. To declare a project as a web project, add "web" to the capabilities array in .iloom/package.iloom.json or .iloom/package.iloom.local.json.'),
66
70
  database: z.object({
67
71
  databaseUrlEnvVarName: z.string().min(1, "Database URL variable name cannot be empty").regex(/^[A-Z_][A-Z0-9_]*$/, "Must be valid env var name (uppercase, underscores)").optional().default("DATABASE_URL").describe("Name of environment variable for database connection URL")
68
72
  }).optional()
69
73
  }).optional();
70
74
  var CapabilitiesSettingsSchemaNoDefaults = z.object({
71
- capabilities: z.array(z.enum(PROJECT_CAPABILITIES)).optional().describe("Explicitly declared project capabilities (auto-detected if not specified)"),
72
75
  web: z.object({
73
76
  basePort: z.number().min(1, "Base port must be >= 1").max(65535, "Base port must be <= 65535").optional().describe("Base port for web workspace port calculations (default: 3000)")
74
- }).optional(),
77
+ }).optional().describe('Web dev server settings. To declare a project as a web project, add "web" to the capabilities array in .iloom/package.iloom.json or .iloom/package.iloom.local.json.'),
75
78
  database: z.object({
76
79
  databaseUrlEnvVarName: z.string().min(1, "Database URL variable name cannot be empty").regex(/^[A-Z_][A-Z0-9_]*$/, "Must be valid env var name (uppercase, underscores)").optional().describe("Name of environment variable for database connection URL")
77
80
  }).optional()
@@ -115,7 +118,7 @@ var IloomSettingsSchema = z.object({
115
118
  copyGitIgnoredPatterns: z.array(z.string().min(1, "Pattern cannot be empty")).optional().describe(`Glob patterns for gitignored files to copy to looms (e.g., ["*.db", "data/*.sqlite"]). Great for local dbs and large test data files that are too big to commit to git. Note: .env (dotenv-flow) files, iloom's and claude's local settings are automatically copied and do not need to be specified here.`),
116
119
  workflows: WorkflowsSettingsSchema.describe("Per-workflow-type permission configurations"),
117
120
  agents: z.record(z.string(), AgentSettingsSchema).optional().nullable().describe(
118
- "Per-agent configuration overrides. Available agents: iloom-issue-analyzer (analyzes issues), iloom-issue-planner (creates implementation plans), iloom-issue-analyze-and-plan (combined analysis and planning), iloom-issue-complexity-evaluator (evaluates complexity), iloom-issue-enhancer (enhances issue descriptions), iloom-issue-implementer (implements code changes), iloom-code-reviewer (reviews code changes against requirements), iloom-artifact-reviewer (reviews artifacts before posting)"
121
+ "Per-agent configuration overrides. Available agents: iloom-issue-analyzer (analyzes issues), iloom-issue-planner (creates implementation plans), iloom-issue-analyze-and-plan (combined analysis and planning), iloom-issue-complexity-evaluator (evaluates complexity), iloom-issue-enhancer (enhances issue descriptions), iloom-issue-implementer (implements code changes), iloom-code-reviewer (reviews code changes against requirements), iloom-artifact-reviewer (reviews artifacts before posting), iloom-swarm-worker (swarm worker agent, dynamically generated). Use swarmModel on any agent to override its model in swarm mode."
119
122
  ),
120
123
  spin: SpinAgentSettingsSchema.optional().describe(
121
124
  "Spin orchestrator configuration. Model defaults to opus when not configured."
@@ -130,7 +133,7 @@ var IloomSettingsSchema = z.object({
130
133
  databaseProviders: DatabaseProvidersSettingsSchema.describe("Database provider configurations"),
131
134
  issueManagement: z.object({
132
135
  // SYNC: If this default changes, update displayDefaultsBox() in src/utils/first-run-setup.ts
133
- provider: z.enum(["github", "linear"]).optional().default("github").describe("Issue tracker provider (github, linear)"),
136
+ provider: z.enum(["github", "linear", "jira"]).optional().default("github").describe("Issue tracker provider (github, linear, jira)"),
134
137
  github: z.object({
135
138
  remote: z.string().min(1, "Remote name cannot be empty").describe("Git remote name to use for GitHub operations")
136
139
  }).optional(),
@@ -138,6 +141,17 @@ var IloomSettingsSchema = z.object({
138
141
  teamId: z.string().min(1, "Team ID cannot be empty").describe('Linear team identifier (e.g., "ENG", "PLAT")'),
139
142
  branchFormat: z.string().optional().describe("Branch naming template for Linear issues"),
140
143
  apiToken: z.string().optional().describe("Linear API token (lin_api_...). SECURITY: Store in settings.local.json only, never commit to source control.")
144
+ }).optional(),
145
+ jira: z.object({
146
+ host: z.string().min(1, "Jira host cannot be empty").describe('Jira instance URL (e.g., "https://yourcompany.atlassian.net")'),
147
+ username: z.string().min(1, "Jira username/email cannot be empty").describe("Jira username or email address"),
148
+ apiToken: z.string().optional().describe("Jira API token. SECURITY: Store in settings.local.json only, never commit to source control. Generate at: https://id.atlassian.com/manage-profile/security/api-tokens"),
149
+ projectKey: z.string().min(1, "Project key cannot be empty").describe('Jira project key (e.g., "PROJ", "ENG")'),
150
+ boardId: z.string().optional().describe("Jira board ID for sprint/workflow operations (optional)"),
151
+ transitionMappings: z.record(z.string(), z.string()).optional().describe('Map iloom states to Jira transition names (e.g., {"In Review": "Start Review"})'),
152
+ defaultIssueType: z.string().min(1).optional().default("Task").describe('Default Jira issue type name for creating issues (e.g., "Task", "Story", "Bug")'),
153
+ defaultSubtaskType: z.string().min(1).optional().default("Subtask").describe('Default Jira issue type name for creating subtasks/child issues (e.g., "Subtask", "Sub-task")'),
154
+ doneStatuses: z.array(z.string()).optional().default(["Done"]).describe('Status names to exclude from issue lists (e.g., ["Done", "Closed", "Verify"])')
141
155
  }).optional()
142
156
  }).optional().describe("Issue management configuration"),
143
157
  mergeBehavior: z.object({
@@ -146,6 +160,9 @@ var IloomSettingsSchema = z.object({
146
160
  remote: z.string().optional(),
147
161
  autoCommitPush: z.boolean().optional().describe(
148
162
  "Auto-commit and push after code review in draft PR mode. Defaults to true when mode is github-draft-pr."
163
+ ),
164
+ openBrowserOnFinish: z.boolean().default(true).describe(
165
+ "Open the PR in the default browser after finishing in github-pr or github-draft-pr mode. Use --no-browser flag to override."
149
166
  )
150
167
  }).optional().describe("Merge behavior configuration: local (merge locally), github-pr (create PR), or github-draft-pr (create draft PR at start, mark ready on finish)"),
151
168
  ide: z.object({
@@ -199,10 +216,11 @@ var IloomSettingsSchemaNoDefaults = z.object({
199
216
  copyGitIgnoredPatterns: z.array(z.string().min(1, "Pattern cannot be empty")).optional().describe(`Glob patterns for gitignored files to copy to looms (e.g., ["*.db", "data/*.sqlite"]). Great for local dbs and large test data files that are too big to commit to git. Note: .env (dotenv-flow) files, iloom's and claude's local settings are automatically copied and do not need to be specified here.`),
200
217
  workflows: WorkflowsSettingsSchemaNoDefaults.describe("Per-workflow-type permission configurations"),
201
218
  agents: z.record(z.string(), AgentSettingsSchema).optional().nullable().describe(
202
- "Per-agent configuration overrides. Available agents: iloom-issue-analyzer (analyzes issues), iloom-issue-planner (creates implementation plans), iloom-issue-analyze-and-plan (combined analysis and planning), iloom-issue-complexity-evaluator (evaluates complexity), iloom-issue-enhancer (enhances issue descriptions), iloom-issue-implementer (implements code changes), iloom-code-reviewer (reviews code changes against requirements), iloom-artifact-reviewer (reviews artifacts before posting)"
219
+ "Per-agent configuration overrides. Available agents: iloom-issue-analyzer (analyzes issues), iloom-issue-planner (creates implementation plans), iloom-issue-analyze-and-plan (combined analysis and planning), iloom-issue-complexity-evaluator (evaluates complexity), iloom-issue-enhancer (enhances issue descriptions), iloom-issue-implementer (implements code changes), iloom-code-reviewer (reviews code changes against requirements), iloom-artifact-reviewer (reviews artifacts before posting), iloom-swarm-worker (swarm worker agent, dynamically generated). Use swarmModel on any agent to override its model in swarm mode."
203
220
  ),
204
221
  spin: z.object({
205
- model: z.enum(["sonnet", "opus", "haiku"]).optional()
222
+ model: z.enum(["sonnet", "opus", "haiku"]).optional(),
223
+ swarmModel: z.enum(["sonnet", "opus", "haiku"]).optional()
206
224
  }).optional().describe("Spin orchestrator configuration"),
207
225
  plan: z.object({
208
226
  model: z.enum(["sonnet", "opus", "haiku"]).optional(),
@@ -215,7 +233,7 @@ var IloomSettingsSchemaNoDefaults = z.object({
215
233
  capabilities: CapabilitiesSettingsSchemaNoDefaults.describe("Project capability configurations"),
216
234
  databaseProviders: DatabaseProvidersSettingsSchema.describe("Database provider configurations"),
217
235
  issueManagement: z.object({
218
- provider: z.enum(["github", "linear"]).optional().describe("Issue tracker provider (github, linear)"),
236
+ provider: z.enum(["github", "linear", "jira"]).optional().describe("Issue tracker provider (github, linear, jira)"),
219
237
  github: z.object({
220
238
  remote: z.string().min(1, "Remote name cannot be empty").describe("Git remote name to use for GitHub operations")
221
239
  }).optional(),
@@ -223,6 +241,17 @@ var IloomSettingsSchemaNoDefaults = z.object({
223
241
  teamId: z.string().min(1, "Team ID cannot be empty").describe('Linear team identifier (e.g., "ENG", "PLAT")'),
224
242
  branchFormat: z.string().optional().describe("Branch naming template for Linear issues"),
225
243
  apiToken: z.string().optional().describe("Linear API token (lin_api_...). SECURITY: Store in settings.local.json only, never commit to source control.")
244
+ }).optional(),
245
+ jira: z.object({
246
+ host: z.string().min(1, "Jira host cannot be empty").describe('Jira instance URL (e.g., "https://yourcompany.atlassian.net")'),
247
+ username: z.string().min(1, "Jira username/email cannot be empty").describe("Jira username or email address"),
248
+ apiToken: z.string().optional().describe("Jira API token. SECURITY: Store in settings.local.json only, never commit to source control. Generate at: https://id.atlassian.com/manage-profile/security/api-tokens"),
249
+ projectKey: z.string().min(1, "Project key cannot be empty").describe('Jira project key (e.g., "PROJ", "ENG")'),
250
+ boardId: z.string().optional().describe("Jira board ID for sprint/workflow operations (optional)"),
251
+ transitionMappings: z.record(z.string(), z.string()).optional().describe('Map iloom states to Jira transition names (e.g., {"In Review": "Start Review"})'),
252
+ defaultIssueType: z.string().min(1).optional().describe('Default Jira issue type name for creating issues (e.g., "Task", "Story", "Bug")'),
253
+ defaultSubtaskType: z.string().min(1).optional().describe('Default Jira issue type name for creating subtasks/child issues (e.g., "Subtask", "Sub-task")'),
254
+ doneStatuses: z.array(z.string()).optional().default(["Done"]).describe('Status names to exclude from issue lists (e.g., ["Done", "Closed", "Verify"])')
226
255
  }).optional()
227
256
  }).optional().describe("Issue management configuration"),
228
257
  mergeBehavior: z.object({
@@ -230,6 +259,9 @@ var IloomSettingsSchemaNoDefaults = z.object({
230
259
  remote: z.string().optional(),
231
260
  autoCommitPush: z.boolean().optional().describe(
232
261
  "Auto-commit and push after code review in draft PR mode. Defaults to true when mode is github-draft-pr."
262
+ ),
263
+ openBrowserOnFinish: z.boolean().optional().describe(
264
+ "Open the PR in the default browser after finishing in github-pr or github-draft-pr mode. Use --no-browser flag to override."
233
265
  )
234
266
  }).optional().describe("Merge behavior configuration: local (merge locally), github-pr (create PR), or github-draft-pr (create draft PR at start, mark ready on finish)"),
235
267
  ide: z.object({
@@ -252,6 +284,24 @@ var IloomSettingsSchemaNoDefaults = z.object({
252
284
  commitTimeout: z.number().min(1e3, "Commit timeout must be at least 1000ms").max(6e5, "Commit timeout cannot exceed 600000ms (10 minutes)").optional().describe("Timeout in milliseconds for git commit operations. Increase for long-running pre-commit hooks.")
253
285
  }).optional().describe("Git operation settings")
254
286
  });
287
+ function redactSensitiveFields(obj) {
288
+ if (obj === null || obj === void 0) return obj;
289
+ if (typeof obj !== "object") return obj;
290
+ if (Array.isArray(obj)) return obj.map(redactSensitiveFields);
291
+ const sensitiveKeys = ["apitoken", "token", "secret", "password"];
292
+ const result = {};
293
+ for (const [key, value] of Object.entries(obj)) {
294
+ const lowerKey = key.toLowerCase();
295
+ if (sensitiveKeys.some((s) => lowerKey.includes(s)) && typeof value === "string") {
296
+ result[key] = "[REDACTED]";
297
+ } else if (typeof value === "object" && value !== null) {
298
+ result[key] = redactSensitiveFields(value);
299
+ } else {
300
+ result[key] = value;
301
+ }
302
+ }
303
+ return result;
304
+ }
255
305
  var SettingsManager = class {
256
306
  /**
257
307
  * Load settings from global, project, and local sources with proper precedence
@@ -266,19 +316,19 @@ var SettingsManager = class {
266
316
  const root = this.getProjectRoot(projectRoot);
267
317
  const globalSettings = await this.loadGlobalSettingsFile();
268
318
  const globalSettingsPath = this.getGlobalSettingsPath();
269
- logger.debug(`\u{1F30D} Global settings from ${globalSettingsPath}:`, JSON.stringify(globalSettings, null, 2));
319
+ logger.debug(`\u{1F30D} Global settings from ${globalSettingsPath}:`, JSON.stringify(redactSensitiveFields(globalSettings), null, 2));
270
320
  const baseSettings = await this.loadSettingsFile(root, "settings.json");
271
321
  const baseSettingsPath = path.join(root, ".iloom", "settings.json");
272
- logger.debug(`\u{1F4C4} Base settings from ${baseSettingsPath}:`, JSON.stringify(baseSettings, null, 2));
322
+ logger.debug(`\u{1F4C4} Base settings from ${baseSettingsPath}:`, JSON.stringify(redactSensitiveFields(baseSettings), null, 2));
273
323
  const localSettings = await this.loadSettingsFile(root, "settings.local.json");
274
324
  const localSettingsPath = path.join(root, ".iloom", "settings.local.json");
275
- logger.debug(`\u{1F4C4} Local settings from ${localSettingsPath}:`, JSON.stringify(localSettings, null, 2));
325
+ logger.debug(`\u{1F4C4} Local settings from ${localSettingsPath}:`, JSON.stringify(redactSensitiveFields(localSettings), null, 2));
276
326
  let merged = this.mergeSettings(this.mergeSettings(globalSettings, baseSettings), localSettings);
277
- logger.debug("\u{1F504} After merging global + base + local settings:", JSON.stringify(merged, null, 2));
327
+ logger.debug("\u{1F504} After merging global + base + local settings:", JSON.stringify(redactSensitiveFields(merged), null, 2));
278
328
  if (cliOverrides && Object.keys(cliOverrides).length > 0) {
279
- logger.debug("\u2699\uFE0F CLI overrides to apply:", JSON.stringify(cliOverrides, null, 2));
329
+ logger.debug("\u2699\uFE0F CLI overrides to apply:", JSON.stringify(redactSensitiveFields(cliOverrides), null, 2));
280
330
  merged = this.mergeSettings(merged, cliOverrides);
281
- logger.debug("\u{1F504} After applying CLI overrides:", JSON.stringify(merged, null, 2));
331
+ logger.debug("\u{1F504} After applying CLI overrides:", JSON.stringify(redactSensitiveFields(merged), null, 2));
282
332
  }
283
333
  try {
284
334
  const finalSettings = IloomSettingsSchema.parse(merged);
@@ -301,7 +351,7 @@ Note: CLI overrides were applied. Check your --set arguments.`);
301
351
  * Log the final merged configuration for debugging
302
352
  */
303
353
  logFinalConfiguration(settings) {
304
- logger.debug("\u{1F4CB} Final merged configuration:", JSON.stringify(settings, null, 2));
354
+ logger.debug("\u{1F4CB} Final merged configuration:", JSON.stringify(redactSensitiveFields(settings), null, 2));
305
355
  }
306
356
  /**
307
357
  * Load and parse a single settings file
@@ -460,9 +510,15 @@ ${errorMessages.join("\n")}`
460
510
  * @param settings - Pre-loaded settings object
461
511
  * @returns Model shorthand ('opus', 'sonnet', or 'haiku')
462
512
  */
463
- getSpinModel(settings) {
464
- var _a;
465
- return ((_a = settings == null ? void 0 : settings.spin) == null ? void 0 : _a.model) ?? SpinAgentSettingsSchema.parse({}).model;
513
+ getSpinModel(settings, mode) {
514
+ var _a, _b;
515
+ if (mode === "swarm") {
516
+ if ((_a = settings == null ? void 0 : settings.spin) == null ? void 0 : _a.swarmModel) {
517
+ return settings.spin.swarmModel;
518
+ }
519
+ return "opus";
520
+ }
521
+ return ((_b = settings == null ? void 0 : settings.spin) == null ? void 0 : _b.model) ?? SpinAgentSettingsSchema.parse({}).model;
466
522
  }
467
523
  /**
468
524
  * Get the plan command model with default applied
@@ -511,6 +567,7 @@ ${errorMessages.join("\n")}`
511
567
  };
512
568
 
513
569
  export {
570
+ BaseAgentSettingsSchema,
514
571
  AgentSettingsSchema,
515
572
  SpinAgentSettingsSchema,
516
573
  PlanCommandSettingsSchema,
@@ -527,4 +584,4 @@ export {
527
584
  IloomSettingsSchemaNoDefaults,
528
585
  SettingsManager
529
586
  };
530
- //# sourceMappingURL=chunk-RI2YL6TK.js.map
587
+ //# sourceMappingURL=chunk-7VHJNVLF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/SettingsManager.ts"],"sourcesContent":["import { readFile } from 'fs/promises'\nimport path from 'path'\nimport os from 'os'\nimport { z } from 'zod'\nimport deepmerge from 'deepmerge'\nimport { logger } from '../utils/logger.js'\n\n/**\n * Zod schema for base agent settings (without nested agents)\n */\nexport const BaseAgentSettingsSchema = z.object({\n\tmodel: z\n\t\t.enum(['sonnet', 'opus', 'haiku'])\n\t\t.optional()\n\t\t.describe('Claude model shorthand: sonnet, opus, or haiku'),\n\tswarmModel: z\n\t\t.enum(['sonnet', 'opus', 'haiku'])\n\t\t.optional()\n\t\t.describe('Model to use for this agent in swarm mode. Overrides the base model when running inside swarm workers.'),\n\tenabled: z\n\t\t.boolean()\n\t\t.optional()\n\t\t.describe('Whether this agent is enabled. Defaults to true.'),\n\tproviders: z\n\t\t.record(\n\t\t\tz.enum(['claude', 'gemini', 'codex']),\n\t\t\tz.string()\n\t\t)\n\t\t.optional()\n\t\t.describe('Map of review providers to model names. Keys: claude, gemini, codex. Values: model name strings (e.g., \"sonnet\", \"gemini-3-pro-preview\", \"gpt-5.2-codex\")'),\n\treview: z\n\t\t.boolean()\n\t\t.optional()\n\t\t.describe('Whether artifacts from this agent should be reviewed before posting (defaults to false)'),\n})\n\n/**\n * Zod schema for agent settings, extends base with sub-agent timeout and nested agents record.\n */\nexport const AgentSettingsSchema = BaseAgentSettingsSchema.extend({\n\tagents: z.record(z.string(), BaseAgentSettingsSchema)\n\t\t.optional()\n\t\t.describe('Nested per-agent settings. Only meaningful under the iloom-swarm-worker agent entry for sub-agent timeout configuration.'),\n\tsubAgentTimeout: z\n\t\t.number()\n\t\t.min(1, 'Sub-agent timeout must be at least 1 minute')\n\t\t.max(120, 'Sub-agent timeout cannot exceed 120 minutes')\n\t\t.default(10)\n\t\t.describe('Timeout in minutes for sub-agent claude -p invocations in swarm mode. Applies to each phase agent (evaluator, analyzer, planner, implementer) when invoked via the Bash tool. Default: 10 minutes. Only meaningful under the iloom-swarm-worker agent entry.'),\n})\n\n/**\n * Zod schema for spin agent settings with default model\n * Used for the spin orchestrator configuration\n */\nexport const SpinAgentSettingsSchema = z.object({\n\tmodel: z\n\t\t.enum(['sonnet', 'opus', 'haiku'])\n\t\t.default('opus')\n\t\t.describe('Claude model shorthand for spin orchestrator'),\n\tswarmModel: z\n\t\t.enum(['sonnet', 'opus', 'haiku'])\n\t\t.optional()\n\t\t.describe('Model for the spin orchestrator when running in swarm mode. Overrides spin.model for swarm workflows.'),\n})\n\n/**\n * Zod schema for plan command settings with default model\n * Used for the plan command configuration\n */\nexport const PlanCommandSettingsSchema = z.object({\n\tmodel: z\n\t\t.enum(['sonnet', 'opus', 'haiku'])\n\t\t.default('opus')\n\t\t.describe('Claude model shorthand for plan command'),\n\tplanner: z\n\t\t.enum(['claude', 'gemini', 'codex'])\n\t\t.default('claude')\n\t\t.describe('AI provider for creating the plan'),\n\treviewer: z\n\t\t.enum(['claude', 'gemini', 'codex', 'none'])\n\t\t.default('none')\n\t\t.describe('AI provider for reviewing the plan (none to skip review)'),\n})\n\n/**\n * Zod schema for summary settings with default model\n * Used for session summary generation configuration\n */\nexport const SummarySettingsSchema = z.object({\n\tmodel: z\n\t\t.enum(['sonnet', 'opus', 'haiku'])\n\t\t.default('sonnet')\n\t\t.describe('Claude model shorthand for session summary generation'),\n})\n\n/**\n * Zod schema for workflow permission configuration\n */\nexport const WorkflowPermissionSchema = z.object({\n\tpermissionMode: z\n\t\t.enum(['plan', 'acceptEdits', 'bypassPermissions', 'default'])\n\t\t.optional()\n\t\t.describe('Permission mode for Claude CLI in this workflow type'),\n\tnoVerify: z\n\t\t.boolean()\n\t\t.optional()\n\t\t.describe('Skip pre-commit hooks (--no-verify) when committing during commit and finish workflows'),\n\tstartIde: z\n\t\t.boolean()\n\t\t.default(true)\n\t\t.describe('Launch IDE (code) when starting this workflow type'),\n\tstartDevServer: z\n\t\t.boolean()\n\t\t.default(true)\n\t\t.describe('Launch development server when starting this workflow type'),\n\tstartAiAgent: z\n\t\t.boolean()\n\t\t.default(true)\n\t\t.describe('Launch Claude Code agent when starting this workflow type'),\n\tstartTerminal: z\n\t\t.boolean()\n\t\t.default(false)\n\t\t.describe('Launch terminal window without dev server when starting this workflow type'),\n\tgenerateSummary: z\n\t\t.boolean()\n\t\t.default(true)\n\t\t.describe('Generate and post Claude session summary when finishing this workflow type'),\n})\n\n/**\n * Non-defaulting variant for pre-merge validation\n * This prevents Zod from polluting partial settings with default values before merge\n */\nexport const WorkflowPermissionSchemaNoDefaults = z.object({\n\tpermissionMode: z\n\t\t.enum(['plan', 'acceptEdits', 'bypassPermissions', 'default'])\n\t\t.optional()\n\t\t.describe('Permission mode for Claude CLI in this workflow type'),\n\tnoVerify: z\n\t\t.boolean()\n\t\t.optional()\n\t\t.describe('Skip pre-commit hooks (--no-verify) when committing during commit and finish workflows'),\n\tstartIde: z\n\t\t.boolean()\n\t\t.optional()\n\t\t.describe('Launch IDE (code) when starting this workflow type'),\n\tstartDevServer: z\n\t\t.boolean()\n\t\t.optional()\n\t\t.describe('Launch development server when starting this workflow type'),\n\tstartAiAgent: z\n\t\t.boolean()\n\t\t.optional()\n\t\t.describe('Launch Claude Code agent when starting this workflow type'),\n\tstartTerminal: z\n\t\t.boolean()\n\t\t.optional()\n\t\t.describe('Launch terminal window without dev server when starting this workflow type'),\n\tgenerateSummary: z\n\t\t.boolean()\n\t\t.optional()\n\t\t.describe('Generate and post Claude session summary when finishing this workflow type'),\n})\n\n/**\n * Zod schema for workflows settings\n */\nexport const WorkflowsSettingsSchema = z\n\t.object({\n\t\tissue: WorkflowPermissionSchema.optional(),\n\t\tpr: WorkflowPermissionSchema.optional(),\n\t\tregular: WorkflowPermissionSchema.optional(),\n\t})\n\t.optional()\n\n/**\n * Non-defaulting variant for pre-merge validation\n */\nexport const WorkflowsSettingsSchemaNoDefaults = z\n\t.object({\n\t\tissue: WorkflowPermissionSchemaNoDefaults.optional(),\n\t\tpr: WorkflowPermissionSchemaNoDefaults.optional(),\n\t\tregular: WorkflowPermissionSchemaNoDefaults.optional(),\n\t})\n\t.optional()\n\n/**\n * Zod schema for capabilities settings\n */\nexport const CapabilitiesSettingsSchema = z\n\t.object({\n\t\tweb: z\n\t\t\t.object({\n\t\t\t\tbasePort: z\n\t\t\t\t\t.number()\n\t\t\t\t\t.min(1, 'Base port must be >= 1')\n\t\t\t\t\t.max(65535, 'Base port must be <= 65535')\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe('Base port for web workspace port calculations (default: 3000)'),\n\t\t\t})\n\t\t\t.optional()\n\t\t\t.describe('Web dev server settings. To declare a project as a web project, add \"web\" to the capabilities array in .iloom/package.iloom.json or .iloom/package.iloom.local.json.'),\n\t\tdatabase: z\n\t\t\t.object({\n\t\t\t\tdatabaseUrlEnvVarName: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.min(1, 'Database URL variable name cannot be empty')\n\t\t\t\t\t.regex(/^[A-Z_][A-Z0-9_]*$/, 'Must be valid env var name (uppercase, underscores)')\n\t\t\t\t\t.optional()\n\t\t\t\t\t.default('DATABASE_URL')\n\t\t\t\t\t.describe('Name of environment variable for database connection URL'),\n\t\t\t})\n\t\t\t.optional(),\n\t})\n\t.optional()\n\n/**\n * Non-defaulting variant for pre-merge validation\n */\nexport const CapabilitiesSettingsSchemaNoDefaults = z\n\t.object({\n\t\tweb: z\n\t\t\t.object({\n\t\t\t\tbasePort: z\n\t\t\t\t\t.number()\n\t\t\t\t\t.min(1, 'Base port must be >= 1')\n\t\t\t\t\t.max(65535, 'Base port must be <= 65535')\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe('Base port for web workspace port calculations (default: 3000)'),\n\t\t\t})\n\t\t\t.optional()\n\t\t\t.describe('Web dev server settings. To declare a project as a web project, add \"web\" to the capabilities array in .iloom/package.iloom.json or .iloom/package.iloom.local.json.'),\n\t\tdatabase: z\n\t\t\t.object({\n\t\t\t\tdatabaseUrlEnvVarName: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.min(1, 'Database URL variable name cannot be empty')\n\t\t\t\t\t.regex(/^[A-Z_][A-Z0-9_]*$/, 'Must be valid env var name (uppercase, underscores)')\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe('Name of environment variable for database connection URL'),\n\t\t\t})\n\t\t\t.optional(),\n\t})\n\t.optional()\n\n/**\n * Zod schema for Neon database provider settings\n */\nexport const NeonSettingsSchema = z.object({\n\tprojectId: z\n\t\t.string()\n\t\t.min(1)\n\t\t.regex(/^[a-zA-Z0-9-]+$/, 'Neon project ID must contain only letters, numbers, and hyphens')\n\t\t.describe('Neon project ID found in your project URL (e.g., \"fantastic-fox-3566354\")'),\n\tparentBranch: z\n\t\t.string()\n\t\t.min(1)\n\t\t.describe('Branch from which new database branches are created'),\n})\n\n/**\n * Zod schema for database provider settings\n */\nexport const DatabaseProvidersSettingsSchema = z\n\t.object({\n\t\tneon: NeonSettingsSchema.optional().describe(\n\t\t\t'Neon database configuration. Requires Neon CLI installed and authenticated for database branching.',\n\t\t),\n\t})\n\t.optional()\n\n/**\n * Zod schema for iloom settings\n */\nexport const IloomSettingsSchema = z.object({\n\tmainBranch: z\n\t\t.string()\n\t\t.min(1, \"Settings 'mainBranch' cannot be empty\")\n\t\t.optional()\n\t\t.describe('Name of the main/primary branch for the repository'),\n\tsourceEnvOnStart: z\n\t\t.boolean()\n\t\t.default(false)\n\t\t.describe(\n\t\t\t'Source all dotenv-flow files (.env, .env.local, .env.development, .env.development.local) when launching terminal processes (Claude, dev server, terminal). ' +\n\t\t\t\t'Files are sourced in precedence order so later files override earlier ones. ' +\n\t\t\t\t'NOTE TO AI AGENTS: Before making changes to settings files, YOU MUST OFFER to check .env file compatibility. ' +\n\t\t\t\t'WARNING: Unquoted values in .env files may break sourcing in bash/zsh shells. ' +\n\t\t\t\t'Before enabling, verify ALL your .env.* files do not contain unquoted special characters ' +\n\t\t\t\t'(e.g., database URLs with ?, &, or other shell metacharacters). ' +\n\t\t\t\t'Shell compatibility issues may cause processes to fail or behave unexpectedly.',\n\t\t),\n\tworktreePrefix: z\n\t\t.string()\n\t\t.optional()\n\t\t.refine(\n\t\t\t(val) => {\n\t\t\t\tif (val === undefined) return true // undefined = use default calculation\n\t\t\t\tif (val === '') return true // empty string = no prefix mode\n\n\t\t\t\t// Allowlist: only alphanumeric, hyphens, underscores, and forward slashes\n\t\t\t\tconst allowedChars = /^[a-zA-Z0-9\\-_/]+$/\n\t\t\t\tif (!allowedChars.test(val)) return false\n\n\t\t\t\t// Reject if only special characters (no alphanumeric content)\n\t\t\t\tif (/^[-_/]+$/.test(val)) return false\n\n\t\t\t\t// Check each segment (split by /) contains at least one alphanumeric character\n\t\t\t\tconst segments = val.split('/')\n\t\t\t\tfor (const segment of segments) {\n\t\t\t\t\tif (segment && /^[-_]+$/.test(segment)) {\n\t\t\t\t\t\t// Segment exists but contains only hyphens/underscores\n\t\t\t\t\t\treturn false\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn true\n\t\t\t},\n\t\t\t{\n\t\t\t\tmessage:\n\t\t\t\t\t\"worktreePrefix contains invalid characters. Only alphanumeric characters, hyphens (-), underscores (_), and forward slashes (/) are allowed. Use forward slashes for nested directories.\",\n\t\t\t},\n\t\t)\n\t\t.describe(\n\t\t\t'Prefix for worktree directories. Empty string disables prefix. Defaults to <repo-name>-looms if not set.',\n\t\t),\n\tprotectedBranches: z\n\t\t.array(z.string().min(1, 'Protected branch name cannot be empty'))\n\t\t.optional()\n\t\t.describe('List of branches that cannot be deleted (defaults to [mainBranch, \"main\", \"master\", \"develop\"])'),\n\tcopyGitIgnoredPatterns: z\n\t\t.array(z.string().min(1, 'Pattern cannot be empty'))\n\t\t.optional()\n\t\t.describe('Glob patterns for gitignored files to copy to looms (e.g., [\"*.db\", \"data/*.sqlite\"]). Great for local dbs and large test data files that are too big to commit to git. Note: .env (dotenv-flow) files, iloom\\'s and claude\\'s local settings are automatically copied and do not need to be specified here.'),\n\tworkflows: WorkflowsSettingsSchema.describe('Per-workflow-type permission configurations'),\n\tagents: z\n\t\t.record(z.string(), AgentSettingsSchema)\n\t\t.optional()\n\t\t.nullable()\n\t\t.describe(\n\t\t\t'Per-agent configuration overrides. Available agents: ' +\n\t\t\t\t'iloom-issue-analyzer (analyzes issues), ' +\n\t\t\t\t'iloom-issue-planner (creates implementation plans), ' +\n\t\t\t\t'iloom-issue-analyze-and-plan (combined analysis and planning), ' +\n\t\t\t\t'iloom-issue-complexity-evaluator (evaluates complexity), ' +\n\t\t\t\t'iloom-issue-enhancer (enhances issue descriptions), ' +\n\t\t\t\t'iloom-issue-implementer (implements code changes), ' +\n\t\t\t\t'iloom-code-reviewer (reviews code changes against requirements), ' +\n\t\t\t\t'iloom-artifact-reviewer (reviews artifacts before posting), ' +\n\t\t\t\t'iloom-swarm-worker (swarm worker agent, dynamically generated). ' +\n\t\t\t\t'Use swarmModel on any agent to override its model in swarm mode.',\n\t\t),\n\tspin: SpinAgentSettingsSchema.optional().describe(\n\t\t'Spin orchestrator configuration. Model defaults to opus when not configured.',\n\t),\n\tplan: PlanCommandSettingsSchema.optional().describe(\n\t\t'Plan command configuration. Model defaults to opus, planner to claude, reviewer to none when not configured.',\n\t),\n\tsummary: SummarySettingsSchema.optional().describe(\n\t\t'Session summary generation configuration. Model defaults to sonnet when not configured.',\n\t),\n\tcapabilities: CapabilitiesSettingsSchema.describe('Project capability configurations'),\n\tdatabaseProviders: DatabaseProvidersSettingsSchema.describe('Database provider configurations'),\n\tissueManagement: z\n\t\t.object({\n\t\t\t// SYNC: If this default changes, update displayDefaultsBox() in src/utils/first-run-setup.ts\n\t\t\tprovider: z.enum(['github', 'linear', 'jira']).optional().default('github').describe('Issue tracker provider (github, linear, jira)'),\n\t\t\tgithub: z\n\t\t\t\t.object({\n\t\t\t\t\tremote: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.min(1, 'Remote name cannot be empty')\n\t\t\t\t\t\t.describe('Git remote name to use for GitHub operations'),\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t\tlinear: z\n\t\t\t\t.object({\n\t\t\t\t\tteamId: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.min(1, 'Team ID cannot be empty')\n\t\t\t\t\t\t.describe('Linear team identifier (e.g., \"ENG\", \"PLAT\")'),\n\t\t\t\t\tbranchFormat: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t.describe('Branch naming template for Linear issues'),\n\t\t\t\t\tapiToken: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t.describe('Linear API token (lin_api_...). SECURITY: Store in settings.local.json only, never commit to source control.'),\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t\tjira: z\n\t\t\t\t.object({\n\t\t\t\t\thost: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.min(1, 'Jira host cannot be empty')\n\t\t\t\t\t\t.describe('Jira instance URL (e.g., \"https://yourcompany.atlassian.net\")'),\n\t\t\t\t\tusername: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.min(1, 'Jira username/email cannot be empty')\n\t\t\t\t\t\t.describe('Jira username or email address'),\n\t\t\t\t\tapiToken: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t.describe('Jira API token. SECURITY: Store in settings.local.json only, never commit to source control. Generate at: https://id.atlassian.com/manage-profile/security/api-tokens'),\n\t\t\t\t\tprojectKey: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.min(1, 'Project key cannot be empty')\n\t\t\t\t\t\t.describe('Jira project key (e.g., \"PROJ\", \"ENG\")'),\n\t\t\t\t\tboardId: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t.describe('Jira board ID for sprint/workflow operations (optional)'),\n\t\t\t\t\ttransitionMappings: z\n\t\t\t\t\t\t.record(z.string(), z.string())\n\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t.describe('Map iloom states to Jira transition names (e.g., {\"In Review\": \"Start Review\"})'),\n\t\t\t\t\tdefaultIssueType: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.min(1)\n\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t.default('Task')\n\t\t\t\t\t\t.describe('Default Jira issue type name for creating issues (e.g., \"Task\", \"Story\", \"Bug\")'),\n\t\t\t\t\tdefaultSubtaskType: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.min(1)\n\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t.default('Subtask')\n\t\t\t\t\t\t.describe('Default Jira issue type name for creating subtasks/child issues (e.g., \"Subtask\", \"Sub-task\")'),\n\t\t\t\t\tdoneStatuses: z\n\t\t\t\t\t\t.array(z.string())\n\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t.default(['Done'])\n\t\t\t\t\t\t.describe('Status names to exclude from issue lists (e.g., [\"Done\", \"Closed\", \"Verify\"])'),\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t})\n\t\t.optional()\n\t\t.describe('Issue management configuration'),\n\tmergeBehavior: z\n\t\t.object({\n\t\t\t// SYNC: If this default changes, update displayDefaultsBox() in src/utils/first-run-setup.ts\n\t\t\tmode: z.enum(['local', 'github-pr', 'github-draft-pr']).default('local'),\n\t\t\tremote: z.string().optional(),\n\t\t\tautoCommitPush: z\n\t\t\t\t.boolean()\n\t\t\t\t.optional()\n\t\t\t\t.describe(\n\t\t\t\t\t'Auto-commit and push after code review in draft PR mode. Defaults to true when mode is github-draft-pr.'\n\t\t\t\t),\n\t\t\topenBrowserOnFinish: z\n\t\t\t\t.boolean()\n\t\t\t\t.default(true)\n\t\t\t\t.describe(\n\t\t\t\t\t'Open the PR in the default browser after finishing in github-pr or github-draft-pr mode. Use --no-browser flag to override.'\n\t\t\t\t),\n\t\t})\n\t\t.optional()\n\t\t.describe('Merge behavior configuration: local (merge locally), github-pr (create PR), or github-draft-pr (create draft PR at start, mark ready on finish)'),\n\tide: z\n\t\t.object({\n\t\t\t// SYNC: If this default changes, update displayDefaultsBox() in src/utils/first-run-setup.ts\n\t\t\ttype: z\n\t\t\t\t.enum(['vscode', 'cursor', 'webstorm', 'sublime', 'intellij', 'windsurf', 'antigravity'])\n\t\t\t\t.default('vscode')\n\t\t\t\t.describe(\n\t\t\t\t\t'IDE to launch when starting a loom. Options: vscode (Visual Studio Code), cursor (Cursor AI editor), ' +\n\t\t\t\t\t\t'webstorm (JetBrains WebStorm), sublime (Sublime Text), intellij (JetBrains IntelliJ IDEA), ' +\n\t\t\t\t\t\t'windsurf (Windsurf editor), antigravity (Antigravity IDE).'\n\t\t\t\t),\n\t\t})\n\t\t.optional()\n\t\t.describe(\n\t\t\t'IDE configuration for workspace launches. Controls which editor opens when you start a loom. ' +\n\t\t\t\t'Supports VSCode, Cursor, WebStorm, Sublime Text, IntelliJ, Windsurf, and Antigravity. ' +\n\t\t\t\t'Note: Color synchronization (title bar colors) only works with VSCode-compatible editors (vscode, cursor, windsurf, antigravity).'\n\t\t),\n\tcolors: z\n\t\t.object({\n\t\t\tterminal: z\n\t\t\t\t.boolean()\n\t\t\t\t.default(true)\n\t\t\t\t.describe('Apply terminal background colors based on branch name (macOS only)'),\n\t\t\tvscode: z\n\t\t\t\t.boolean()\n\t\t\t\t.default(false)\n\t\t\t\t.describe(\n\t\t\t\t\t'Apply VSCode/Cursor title bar colors based on branch name. ' +\n\t\t\t\t\t\t'Note: This modifies .vscode/settings.json which may be in source control. ' +\n\t\t\t\t\t\t'Default is false for safety; enable via init or explicitly if .vscode is gitignored.'\n\t\t\t\t),\n\t\t})\n\t\t.optional()\n\t\t.describe('Color synchronization settings for workspace identification'),\n\tattribution: z\n\t\t.enum(['off', 'upstreamOnly', 'on'])\n\t\t.default('upstreamOnly')\n\t\t.describe(\n\t\t\t'Controls when iloom attribution appears in session summaries. ' +\n\t\t\t\t'\"off\" - never show attribution. ' +\n\t\t\t\t'\"upstreamOnly\" - only show for contributions to external repositories (e.g., open source). ' +\n\t\t\t\t'\"on\" - always show attribution.'\n\t\t),\n\tgit: z\n\t\t.object({\n\t\t\tcommitTimeout: z\n\t\t\t\t.number()\n\t\t\t\t.min(1000, 'Commit timeout must be at least 1000ms')\n\t\t\t\t.max(600000, 'Commit timeout cannot exceed 600000ms (10 minutes)')\n\t\t\t\t.default(60000)\n\t\t\t\t.describe('Timeout in milliseconds for git commit operations. Increase for long-running pre-commit hooks.'),\n\t\t})\n\t\t.default({ }) // ensures the object always exists and uses default for the inner properties\n\t\t.describe('Git operation settings'),\n})\n\n/**\n * Non-defaulting variant for pre-merge validation\n * This prevents Zod from polluting partial settings with default values before merge\n */\nexport const IloomSettingsSchemaNoDefaults = z.object({\n\tmainBranch: z\n\t\t.string()\n\t\t.min(1, \"Settings 'mainBranch' cannot be empty\")\n\t\t.optional()\n\t\t.describe('Name of the main/primary branch for the repository'),\n\tsourceEnvOnStart: z\n\t\t.boolean()\n\t\t.optional()\n\t\t.describe(\n\t\t\t'Source all dotenv-flow files (.env, .env.local, .env.development, .env.development.local) when launching terminal processes (Claude, dev server, terminal). ' +\n\t\t\t\t'Files are sourced in precedence order so later files override earlier ones. ' +\n\t\t\t\t'NOTE TO AI AGENTS: Before making changes to settings files, YOU MUST OFFER to check .env compatibility. ' +\n\t\t\t\t'WARNING: Unquoted values in .env files may break sourcing in bash/zsh shells. ' +\n\t\t\t\t'Before enabling, verify ALL your .env.* files do not contain unquoted special characters ' +\n\t\t\t\t'(e.g., database URLs with ?, &, or other shell metacharacters). ' +\n\t\t\t\t'Shell compatibility issues may cause processes to fail or behave unexpectedly.',\n\t\t),\n\tworktreePrefix: z\n\t\t.string()\n\t\t.optional()\n\t\t.refine(\n\t\t\t(val) => {\n\t\t\t\tif (val === undefined) return true // undefined = use default calculation\n\t\t\t\tif (val === '') return true // empty string = no prefix mode\n\n\t\t\t\t// Allowlist: only alphanumeric, hyphens, underscores, and forward slashes\n\t\t\t\tconst allowedChars = /^[a-zA-Z0-9\\-_/]+$/\n\t\t\t\tif (!allowedChars.test(val)) return false\n\n\t\t\t\t// Reject if only special characters (no alphanumeric content)\n\t\t\t\tif (/^[-_/]+$/.test(val)) return false\n\n\t\t\t\t// Check each segment (split by /) contains at least one alphanumeric character\n\t\t\t\tconst segments = val.split('/')\n\t\t\t\tfor (const segment of segments) {\n\t\t\t\t\tif (segment && /^[-_]+$/.test(segment)) {\n\t\t\t\t\t\t// Segment exists but contains only hyphens/underscores\n\t\t\t\t\t\treturn false\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn true\n\t\t\t},\n\t\t\t{\n\t\t\t\tmessage:\n\t\t\t\t\t\"worktreePrefix contains invalid characters. Only alphanumeric characters, hyphens (-), underscores (_), and forward slashes (/) are allowed. Use forward slashes for nested directories.\",\n\t\t\t},\n\t\t)\n\t\t.describe(\n\t\t\t'Prefix for worktree directories. Empty string disables prefix. Defaults to <repo-name>-looms if not set.',\n\t\t),\n\tprotectedBranches: z\n\t\t.array(z.string().min(1, 'Protected branch name cannot be empty'))\n\t\t.optional()\n\t\t.describe('List of branches that cannot be deleted (defaults to [mainBranch, \"main\", \"master\", \"develop\"])'),\n\tcopyGitIgnoredPatterns: z\n\t\t.array(z.string().min(1, 'Pattern cannot be empty'))\n\t\t.optional()\n\t\t.describe('Glob patterns for gitignored files to copy to looms (e.g., [\"*.db\", \"data/*.sqlite\"]). Great for local dbs and large test data files that are too big to commit to git. Note: .env (dotenv-flow) files, iloom\\'s and claude\\'s local settings are automatically copied and do not need to be specified here.'),\n\tworkflows: WorkflowsSettingsSchemaNoDefaults.describe('Per-workflow-type permission configurations'),\n\tagents: z\n\t\t.record(z.string(), AgentSettingsSchema)\n\t\t.optional()\n\t\t.nullable()\n\t\t.describe(\n\t\t\t'Per-agent configuration overrides. Available agents: ' +\n\t\t\t\t'iloom-issue-analyzer (analyzes issues), ' +\n\t\t\t\t'iloom-issue-planner (creates implementation plans), ' +\n\t\t\t\t'iloom-issue-analyze-and-plan (combined analysis and planning), ' +\n\t\t\t\t'iloom-issue-complexity-evaluator (evaluates complexity), ' +\n\t\t\t\t'iloom-issue-enhancer (enhances issue descriptions), ' +\n\t\t\t\t'iloom-issue-implementer (implements code changes), ' +\n\t\t\t\t'iloom-code-reviewer (reviews code changes against requirements), ' +\n\t\t\t\t'iloom-artifact-reviewer (reviews artifacts before posting), ' +\n\t\t\t\t'iloom-swarm-worker (swarm worker agent, dynamically generated). ' +\n\t\t\t\t'Use swarmModel on any agent to override its model in swarm mode.',\n\t\t),\n\tspin: z\n\t\t.object({\n\t\t\tmodel: z.enum(['sonnet', 'opus', 'haiku']).optional(),\n\t\t\tswarmModel: z.enum(['sonnet', 'opus', 'haiku']).optional(),\n\t\t})\n\t\t.optional()\n\t\t.describe('Spin orchestrator configuration'),\n\tplan: z\n\t\t.object({\n\t\t\tmodel: z.enum(['sonnet', 'opus', 'haiku']).optional(),\n\t\t\tplanner: z.enum(['claude', 'gemini', 'codex']).optional(),\n\t\t\treviewer: z.enum(['claude', 'gemini', 'codex', 'none']).optional(),\n\t\t})\n\t\t.optional()\n\t\t.describe('Plan command configuration'),\n\tsummary: z\n\t\t.object({\n\t\t\tmodel: z.enum(['sonnet', 'opus', 'haiku']).optional(),\n\t\t})\n\t\t.optional()\n\t\t.describe('Session summary generation configuration'),\n\tcapabilities: CapabilitiesSettingsSchemaNoDefaults.describe('Project capability configurations'),\n\tdatabaseProviders: DatabaseProvidersSettingsSchema.describe('Database provider configurations'),\n\tissueManagement: z\n\t\t.object({\n\t\t\tprovider: z.enum(['github', 'linear', 'jira']).optional().describe('Issue tracker provider (github, linear, jira)'),\n\t\t\tgithub: z\n\t\t\t\t.object({\n\t\t\t\t\tremote: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.min(1, 'Remote name cannot be empty')\n\t\t\t\t\t\t.describe('Git remote name to use for GitHub operations'),\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t\tlinear: z\n\t\t\t\t.object({\n\t\t\t\t\tteamId: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.min(1, 'Team ID cannot be empty')\n\t\t\t\t\t\t.describe('Linear team identifier (e.g., \"ENG\", \"PLAT\")'),\n\t\t\t\t\tbranchFormat: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t.describe('Branch naming template for Linear issues'),\n\t\t\t\t\tapiToken: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t.describe('Linear API token (lin_api_...). SECURITY: Store in settings.local.json only, never commit to source control.'),\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t\tjira: z\n\t\t\t\t.object({\n\t\t\t\t\thost: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.min(1, 'Jira host cannot be empty')\n\t\t\t\t\t\t.describe('Jira instance URL (e.g., \"https://yourcompany.atlassian.net\")'),\n\t\t\t\t\tusername: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.min(1, 'Jira username/email cannot be empty')\n\t\t\t\t\t\t.describe('Jira username or email address'),\n\t\t\t\t\tapiToken: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t.describe('Jira API token. SECURITY: Store in settings.local.json only, never commit to source control. Generate at: https://id.atlassian.com/manage-profile/security/api-tokens'),\n\t\t\t\t\tprojectKey: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.min(1, 'Project key cannot be empty')\n\t\t\t\t\t\t.describe('Jira project key (e.g., \"PROJ\", \"ENG\")'),\n\t\t\t\t\tboardId: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t.describe('Jira board ID for sprint/workflow operations (optional)'),\n\t\t\t\t\ttransitionMappings: z\n\t\t\t\t\t\t.record(z.string(), z.string())\n\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t.describe('Map iloom states to Jira transition names (e.g., {\"In Review\": \"Start Review\"})'),\n\t\t\t\t\tdefaultIssueType: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.min(1)\n\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t.describe('Default Jira issue type name for creating issues (e.g., \"Task\", \"Story\", \"Bug\")'),\n\t\t\t\t\tdefaultSubtaskType: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.min(1)\n\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t.describe('Default Jira issue type name for creating subtasks/child issues (e.g., \"Subtask\", \"Sub-task\")'),\n\t\t\t\t\tdoneStatuses: z\n\t\t\t\t\t\t.array(z.string())\n\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t.default(['Done'])\n\t\t\t\t\t\t.describe('Status names to exclude from issue lists (e.g., [\"Done\", \"Closed\", \"Verify\"])'),\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t})\n\t\t.optional()\n\t\t.describe('Issue management configuration'),\n\tmergeBehavior: z\n\t\t.object({\n\t\t\tmode: z.enum(['local', 'github-pr', 'github-draft-pr']).optional(),\n\t\t\tremote: z.string().optional(),\n\t\t\tautoCommitPush: z\n\t\t\t\t.boolean()\n\t\t\t\t.optional()\n\t\t\t\t.describe(\n\t\t\t\t\t'Auto-commit and push after code review in draft PR mode. Defaults to true when mode is github-draft-pr.'\n\t\t\t\t),\n\t\t\topenBrowserOnFinish: z\n\t\t\t\t.boolean()\n\t\t\t\t.optional()\n\t\t\t\t.describe(\n\t\t\t\t\t'Open the PR in the default browser after finishing in github-pr or github-draft-pr mode. Use --no-browser flag to override.'\n\t\t\t\t),\n\t\t})\n\t\t.optional()\n\t\t.describe('Merge behavior configuration: local (merge locally), github-pr (create PR), or github-draft-pr (create draft PR at start, mark ready on finish)'),\n\tide: z\n\t\t.object({\n\t\t\ttype: z\n\t\t\t\t.enum(['vscode', 'cursor', 'webstorm', 'sublime', 'intellij', 'windsurf', 'antigravity'])\n\t\t\t\t.optional()\n\t\t\t\t.describe(\n\t\t\t\t\t'IDE to launch when starting a loom. Options: vscode (Visual Studio Code), cursor (Cursor AI editor), ' +\n\t\t\t\t\t\t'webstorm (JetBrains WebStorm), sublime (Sublime Text), intellij (JetBrains IntelliJ IDEA), ' +\n\t\t\t\t\t\t'windsurf (Windsurf editor), antigravity (Antigravity IDE).'\n\t\t\t\t),\n\t\t})\n\t\t.optional()\n\t\t.describe(\n\t\t\t'IDE configuration for workspace launches. Controls which editor opens when you start a loom. ' +\n\t\t\t\t'Supports VSCode, Cursor, WebStorm, Sublime Text, IntelliJ, Windsurf, and Antigravity. ' +\n\t\t\t\t'Note: Color synchronization (title bar colors) only works with VSCode-compatible editors (vscode, cursor, windsurf, antigravity).'\n\t\t),\n\tcolors: z\n\t\t.object({\n\t\t\tterminal: z\n\t\t\t\t.boolean()\n\t\t\t\t.optional()\n\t\t\t\t.describe('Apply terminal background colors based on branch name (macOS only)'),\n\t\t\tvscode: z\n\t\t\t\t.boolean()\n\t\t\t\t.optional()\n\t\t\t\t.describe(\n\t\t\t\t\t'Apply VSCode/Cursor title bar colors based on branch name. ' +\n\t\t\t\t\t\t'Note: This modifies .vscode/settings.json which may be in source control.'\n\t\t\t\t),\n\t\t})\n\t\t.optional()\n\t\t.describe('Color synchronization settings for workspace identification'),\n\tattribution: z\n\t\t.enum(['off', 'upstreamOnly', 'on'])\n\t\t.optional()\n\t\t.describe(\n\t\t\t'Controls when iloom attribution appears in session summaries. ' +\n\t\t\t\t'\"off\" - never show attribution. ' +\n\t\t\t\t'\"upstreamOnly\" - only show for contributions to external repositories (e.g., open source). ' +\n\t\t\t\t'\"on\" - always show attribution.'\n\t\t),\n\tgit: z\n\t\t.object({\n\t\t\tcommitTimeout: z\n\t\t\t\t.number()\n\t\t\t\t.min(1000, 'Commit timeout must be at least 1000ms')\n\t\t\t\t.max(600000, 'Commit timeout cannot exceed 600000ms (10 minutes)')\n\t\t\t\t.optional()\n\t\t\t\t.describe('Timeout in milliseconds for git commit operations. Increase for long-running pre-commit hooks.'),\n\t\t})\n\t\t.optional()\n\t\t.describe('Git operation settings'),\n})\n\n/**\n * TypeScript type for Neon settings derived from Zod schema\n */\nexport type NeonSettings = z.infer<typeof NeonSettingsSchema>\n\n/**\n * TypeScript type for database providers settings derived from Zod schema\n */\nexport type DatabaseProvidersSettings = z.infer<typeof DatabaseProvidersSettingsSchema>\n\n/**\n * TypeScript type for agent settings derived from Zod schema\n */\nexport type AgentSettings = z.infer<typeof AgentSettingsSchema>\n\n/**\n * TypeScript type for spin agent settings derived from Zod schema\n */\nexport type SpinAgentSettings = z.infer<typeof SpinAgentSettingsSchema>\n\n/**\n * TypeScript type for plan command settings derived from Zod schema\n */\nexport type PlanCommandSettings = z.infer<typeof PlanCommandSettingsSchema>\n\n/**\n * TypeScript type for summary settings derived from Zod schema\n */\nexport type SummarySettings = z.infer<typeof SummarySettingsSchema>\n\n/**\n * TypeScript type for workflow permission configuration derived from Zod schema\n */\nexport type WorkflowPermission = z.infer<typeof WorkflowPermissionSchema>\n\n/**\n * TypeScript type for workflows settings derived from Zod schema\n */\nexport type WorkflowsSettings = z.infer<typeof WorkflowsSettingsSchema>\n\n/**\n * TypeScript type for capabilities settings derived from Zod schema\n */\nexport type CapabilitiesSettings = z.infer<typeof CapabilitiesSettingsSchema>\n\n/**\n * TypeScript type for IDE settings derived from Zod schema\n */\nexport type IdeSettings = z.infer<typeof IloomSettingsSchema>['ide']\n\n/**\n * TypeScript type for iloom settings derived from Zod schema\n */\nexport type IloomSettings = z.infer<typeof IloomSettingsSchema>\n\n/**\n * TypeScript input type for iloom settings (before Zod defaults are applied)\n * Used for validation where partial/input objects need to be accepted\n */\nexport type IloomSettingsInput = z.input<typeof IloomSettingsSchema>\n\nfunction redactSensitiveFields(obj: unknown): unknown {\n\tif (obj === null || obj === undefined) return obj\n\tif (typeof obj !== 'object') return obj\n\tif (Array.isArray(obj)) return obj.map(redactSensitiveFields)\n\tconst sensitiveKeys = ['apitoken', 'token', 'secret', 'password']\n\tconst result: Record<string, unknown> = {}\n\tfor (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n\t\tconst lowerKey = key.toLowerCase()\n\t\tif (sensitiveKeys.some(s => lowerKey.includes(s)) && typeof value === 'string') {\n\t\t\tresult[key] = '[REDACTED]'\n\t\t} else if (typeof value === 'object' && value !== null) {\n\t\t\tresult[key] = redactSensitiveFields(value)\n\t\t} else {\n\t\t\tresult[key] = value\n\t\t}\n\t}\n\treturn result\n}\n\n/**\n * Manages project-level settings from .iloom/settings.json\n */\nexport class SettingsManager {\n\t/**\n\t * Load settings from global, project, and local sources with proper precedence\n\t * Merge hierarchy (lowest to highest priority):\n\t * 1. Global settings (~/.config/iloom-ai/settings.json)\n\t * 2. Project settings (<PROJECT_ROOT>/.iloom/settings.json)\n\t * 3. Local settings (<PROJECT_ROOT>/.iloom/settings.local.json)\n\t * 4. CLI overrides (--set flags)\n\t * Returns empty object if all files don't exist (not an error)\n\t */\n\tasync loadSettings(\n\t\tprojectRoot?: string,\n\t\tcliOverrides?: Partial<IloomSettings>,\n\t): Promise<IloomSettings> {\n\t\tconst root = this.getProjectRoot(projectRoot)\n\n\t\t// Load global settings (lowest priority)\n\t\tconst globalSettings = await this.loadGlobalSettingsFile()\n\t\tconst globalSettingsPath = this.getGlobalSettingsPath()\n\t\tlogger.debug(`🌍 Global settings from ${globalSettingsPath}:`, JSON.stringify(redactSensitiveFields(globalSettings), null, 2))\n\n\t\t// Load base settings from settings.json\n\t\tconst baseSettings = await this.loadSettingsFile(root, 'settings.json')\n\t\tconst baseSettingsPath = path.join(root, '.iloom', 'settings.json')\n\t\tlogger.debug(`📄 Base settings from ${baseSettingsPath}:`, JSON.stringify(redactSensitiveFields(baseSettings), null, 2))\n\n\t\t// Load local overrides from settings.local.json\n\t\tconst localSettings = await this.loadSettingsFile(root, 'settings.local.json')\n\t\tconst localSettingsPath = path.join(root, '.iloom', 'settings.local.json')\n\t\tlogger.debug(`📄 Local settings from ${localSettingsPath}:`, JSON.stringify(redactSensitiveFields(localSettings), null, 2))\n\n\t\t// Deep merge with priority: cliOverrides > localSettings > baseSettings > globalSettings\n\t\tlet merged = this.mergeSettings(this.mergeSettings(globalSettings, baseSettings), localSettings)\n\t\tlogger.debug('🔄 After merging global + base + local settings:', JSON.stringify(redactSensitiveFields(merged), null, 2))\n\n\t\tif (cliOverrides && Object.keys(cliOverrides).length > 0) {\n\t\t\tlogger.debug('⚙️ CLI overrides to apply:', JSON.stringify(redactSensitiveFields(cliOverrides), null, 2))\n\t\t\tmerged = this.mergeSettings(merged, cliOverrides)\n\t\t\tlogger.debug('🔄 After applying CLI overrides:', JSON.stringify(redactSensitiveFields(merged), null, 2))\n\t\t}\n\n\t\t// Validate merged result\n\t\ttry {\n\t\t\tconst finalSettings = IloomSettingsSchema.parse(merged)\n\n\t\t\t// Debug: Log final merged configuration\n\t\t\tthis.logFinalConfiguration(finalSettings)\n\n\t\t\treturn finalSettings\n\t\t} catch (error) {\n\t\t\t// Show all Zod validation errors\n\t\t\tif (error instanceof z.ZodError) {\n\t\t\t\tconst errorMsg = this.formatAllZodErrors(error, '<merged settings>')\n\t\t\t\t// Enhance error message if CLI overrides were applied\n\t\t\t\tif (cliOverrides && Object.keys(cliOverrides).length > 0) {\n\t\t\t\t\tthrow new Error(`${errorMsg.message}\\n\\nNote: CLI overrides were applied. Check your --set arguments.`)\n\t\t\t\t}\n\t\t\t\tthrow errorMsg\n\t\t\t}\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t/**\n\t * Log the final merged configuration for debugging\n\t */\n\tprivate logFinalConfiguration(settings: IloomSettings): void {\n\t\tlogger.debug('📋 Final merged configuration:', JSON.stringify(redactSensitiveFields(settings), null, 2))\n\t}\n\n\t/**\n\t * Load and parse a single settings file\n\t * Returns empty object if file doesn't exist (not an error)\n\t * Uses non-defaulting schema to prevent polluting partial settings with defaults before merge\n\t */\n\tprivate async loadSettingsFile(\n\t\tprojectRoot: string,\n\t\tfilename: string,\n\t): Promise<z.infer<typeof IloomSettingsSchemaNoDefaults>> {\n\t\tconst settingsPath = path.join(projectRoot, '.iloom', filename)\n\n\t\ttry {\n\t\t\tconst content = await readFile(settingsPath, 'utf-8')\n\t\t\tlet parsed: unknown\n\n\t\t\ttry {\n\t\t\t\tparsed = JSON.parse(content)\n\t\t\t} catch (error) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Failed to parse settings file at ${settingsPath}: ${error instanceof Error ? error.message : 'Invalid JSON'}`,\n\t\t\t\t)\n\t\t\t}\n\n\t\t\t// Basic type checking - ensure it's an object, but don't validate schema completeness\n\t\t\t// Individual files may be incomplete (e.g., Linear config split between files)\n\t\t\t// Final validation will happen on the merged result in loadSettings()\n\t\t\tif (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Settings validation failed at ${filename}:\\n - root: Expected object, received ${typeof parsed}`\n\t\t\t\t)\n\t\t\t}\n\t\t\treturn parsed as z.infer<typeof IloomSettingsSchemaNoDefaults>\n\t\t} catch (error) {\n\t\t\t// File not found is not an error - return empty settings\n\t\t\tif ((error as { code?: string }).code === 'ENOENT') {\n\t\t\t\tlogger.debug(`No settings file found at ${settingsPath}, using defaults`)\n\t\t\t\treturn {}\n\t\t\t}\n\n\t\t\t// Re-throw parsing errors\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t/**\n\t * Deep merge two settings objects with priority to override\n\t * Uses deepmerge library with array replacement strategy\n\t */\n\tprivate mergeSettings(\n\t\tbase: Partial<IloomSettings> | z.infer<typeof IloomSettingsSchemaNoDefaults>,\n\t\toverride: Partial<IloomSettings> | z.infer<typeof IloomSettingsSchemaNoDefaults>,\n\t): IloomSettings {\n\t\t// Use deepmerge with array replacement (not concatenation)\n\t\t// Type assertion is safe because the merged result will be validated with IloomSettingsSchema\n\t\t// which applies all the defaults after merging\n\t\treturn deepmerge(base as Record<string, unknown>, override as Record<string, unknown>, {\n\t\t\t// Replace arrays instead of concatenating them\n\t\t\tarrayMerge: (_destinationArray, sourceArray) => sourceArray,\n\t\t}) as IloomSettings\n\t}\n\n\t/**\n\t * Format all Zod validation errors into a single error message\n\t */\n\tprivate formatAllZodErrors(error: z.ZodError, settingsPath: string): Error {\n\t\tconst errorMessages = error.issues.map(issue => {\n\t\t\tconst path = issue.path.length > 0 ? issue.path.join('.') : 'root'\n\t\t\treturn ` - ${path}: ${issue.message}`\n\t\t})\n\n\t\treturn new Error(\n\t\t\t`Settings validation failed at ${settingsPath}:\\n${errorMessages.join('\\n')}`,\n\t\t)\n\t}\n\n\t/**\n\t * Validate settings structure and model names using Zod schema\n\t * This method is kept for testing purposes but uses Zod internally\n\t * @internal - Only used in tests via bracket notation\n\t */\n\t// @ts-expect-error - Used in tests via bracket notation, TypeScript can't detect this usage\n\tprivate validateSettings(settings: IloomSettingsInput): void {\n\t\ttry {\n\t\t\tIloomSettingsSchema.parse(settings)\n\t\t} catch (error) {\n\t\t\tif (error instanceof z.ZodError) {\n\t\t\t\tthrow this.formatAllZodErrors(error, '<validation>')\n\t\t\t}\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t/**\n\t * Get project root (defaults to process.cwd())\n\t */\n\tprivate getProjectRoot(projectRoot?: string): string {\n\t\treturn projectRoot ?? process.cwd()\n\t}\n\n\t/**\n\t * Get global config directory path (~/.config/iloom-ai)\n\t */\n\tprivate getGlobalConfigDir(): string {\n\t\treturn path.join(os.homedir(), '.config', 'iloom-ai')\n\t}\n\n\t/**\n\t * Get global settings file path (~/.config/iloom-ai/settings.json)\n\t */\n\tprivate getGlobalSettingsPath(): string {\n\t\treturn path.join(this.getGlobalConfigDir(), 'settings.json')\n\t}\n\n\t/**\n\t * Load and parse global settings file\n\t * Returns empty object if file doesn't exist (not an error)\n\t * Warns but returns empty object on validation/parse errors (graceful degradation)\n\t */\n\tprivate async loadGlobalSettingsFile(): Promise<z.infer<typeof IloomSettingsSchemaNoDefaults>> {\n\t\tconst settingsPath = this.getGlobalSettingsPath()\n\n\t\ttry {\n\t\t\tconst content = await readFile(settingsPath, 'utf-8')\n\t\t\tlet parsed: unknown\n\n\t\t\ttry {\n\t\t\t\tparsed = JSON.parse(content)\n\t\t\t} catch (error) {\n\t\t\t\tlogger.warn(\n\t\t\t\t\t`Failed to parse global settings file at ${settingsPath}: ${error instanceof Error ? error.message : 'Invalid JSON'}. Ignoring global settings.`,\n\t\t\t\t)\n\t\t\t\treturn {}\n\t\t\t}\n\n\t\t\t// Validate with non-defaulting schema\n\t\t\ttry {\n\t\t\t\tconst validated = IloomSettingsSchemaNoDefaults.strict().parse(parsed)\n\t\t\t\treturn validated\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof z.ZodError) {\n\t\t\t\t\tconst errorMsg = this.formatAllZodErrors(error, 'global settings')\n\t\t\t\t\tlogger.warn(`${errorMsg.message}. Ignoring global settings.`)\n\t\t\t\t} else {\n\t\t\t\t\tlogger.warn(`Validation error in global settings: ${error instanceof Error ? error.message : 'Unknown error'}. Ignoring global settings.`)\n\t\t\t\t}\n\t\t\t\treturn {}\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// File not found is not an error - return empty settings\n\t\t\tif ((error as { code?: string }).code === 'ENOENT') {\n\t\t\t\tlogger.debug(`No global settings file found at ${settingsPath}`)\n\t\t\t\treturn {}\n\t\t\t}\n\n\t\t\t// Other file system errors - warn and continue\n\t\t\tlogger.warn(`Error reading global settings file at ${settingsPath}: ${error instanceof Error ? error.message : 'Unknown error'}. Ignoring global settings.`)\n\t\t\treturn {}\n\t\t}\n\t}\n\n\t/**\n\t * Get effective protected branches list with mainBranch always included\n\t *\n\t * This method provides a single source of truth for protected branches logic:\n\t * 1. Use configured protectedBranches if provided\n\t * 2. Otherwise use defaults: [mainBranch, 'main', 'master', 'develop']\n\t * 3. ALWAYS ensure mainBranch is included even if user configured custom list\n\t *\n\t * @param projectRoot - Optional project root directory (defaults to process.cwd())\n\t * @returns Array of protected branch names with mainBranch guaranteed to be included\n\t */\n\tasync getProtectedBranches(projectRoot?: string): Promise<string[]> {\n\t\tconst settings = await this.loadSettings(projectRoot)\n\t\t// SYNC: If this default changes, update displayDefaultsBox() in src/utils/first-run-setup.ts\n\t\tconst mainBranch = settings.mainBranch ?? 'main'\n\n\t\t// Build protected branches list:\n\t\t// 1. Use configured protectedBranches if provided\n\t\t// 2. Otherwise use defaults: [mainBranch, 'main', 'master', 'develop']\n\t\t// 3. ALWAYS ensure mainBranch is included even if user configured custom list\n\t\tlet protectedBranches: string[]\n\t\tif (settings.protectedBranches) {\n\t\t\t// Use configured list but ensure mainBranch is always included\n\t\t\tprotectedBranches = settings.protectedBranches.includes(mainBranch)\n\t\t\t\t? settings.protectedBranches\n\t\t\t\t: [mainBranch, ...settings.protectedBranches]\n\t\t} else {\n\t\t\t// Use defaults with current mainBranch\n\t\t\tprotectedBranches = [mainBranch, 'main', 'master', 'develop']\n\t\t}\n\n\t\treturn protectedBranches\n\t}\n\n\t/**\n\t * Get the spin orchestrator model with default applied\n\t * Default is defined in SpinAgentSettingsSchema\n\t *\n\t * @param settings - Pre-loaded settings object\n\t * @returns Model shorthand ('opus', 'sonnet', or 'haiku')\n\t */\n\tgetSpinModel(settings?: IloomSettings, mode?: 'swarm'): 'sonnet' | 'opus' | 'haiku' {\n\t\tif (mode === 'swarm') {\n\t\t\tif (settings?.spin?.swarmModel) {\n\t\t\t\treturn settings.spin.swarmModel\n\t\t\t}\n\t\t\t// Default to opus for swarm orchestrator (\"Balanced\" mode)\n\t\t\treturn 'opus'\n\t\t}\n\t\treturn settings?.spin?.model ?? SpinAgentSettingsSchema.parse({}).model\n\t}\n\n\t/**\n\t * Get the plan command model with default applied\n\t * Default is defined in PlanCommandSettingsSchema\n\t *\n\t * @param settings - Pre-loaded settings object\n\t * @returns Model shorthand ('opus', 'sonnet', or 'haiku')\n\t */\n\tgetPlanModel(settings?: IloomSettings): 'sonnet' | 'opus' | 'haiku' {\n\t\treturn settings?.plan?.model ?? PlanCommandSettingsSchema.parse({}).model\n\t}\n\n\t/**\n\t * Get the plan command planner with default applied\n\t * Default is 'claude'\n\t *\n\t * @param settings - Pre-loaded settings object\n\t * @returns Planner provider ('claude', 'gemini', or 'codex')\n\t */\n\tgetPlanPlanner(settings?: IloomSettings): 'claude' | 'gemini' | 'codex' {\n\t\treturn settings?.plan?.planner ?? 'claude'\n\t}\n\n\t/**\n\t * Get the plan command reviewer with default applied\n\t * Default is 'none' (no review step)\n\t *\n\t * @param settings - Pre-loaded settings object\n\t * @returns Reviewer provider ('claude', 'gemini', 'codex', or 'none')\n\t */\n\tgetPlanReviewer(settings?: IloomSettings): 'claude' | 'gemini' | 'codex' | 'none' {\n\t\treturn settings?.plan?.reviewer ?? 'none'\n\t}\n\n\t/**\n\t * Get the session summary model with default applied\n\t * Default is defined in SummarySettingsSchema\n\t *\n\t * @param settings - Pre-loaded settings object\n\t * @returns Model shorthand ('opus', 'sonnet', or 'haiku')\n\t */\n\tgetSummaryModel(settings?: IloomSettings): 'sonnet' | 'opus' | 'haiku' {\n\t\treturn settings?.summary?.model ?? SummarySettingsSchema.parse({}).model\n\t}\n}\n"],"mappings":"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","names":["path"]}
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  PromptTemplateManager,
4
4
  buildReviewTemplateVariables
5
- } from "./chunk-QN47QVBX.js";
5
+ } from "./chunk-UUEW5KWB.js";
6
6
  import {
7
7
  logger
8
8
  } from "./chunk-VT4PDUYT.js";
@@ -191,7 +191,15 @@ var AgentManager = class {
191
191
  model: agentSettings.model
192
192
  };
193
193
  } else if (!agents[agentName]) {
194
- logger.warn(`Settings reference unknown agent: ${agentName}`);
194
+ const RUNTIME_GENERATED_AGENTS = ["iloom-swarm-worker"];
195
+ if (!RUNTIME_GENERATED_AGENTS.includes(agentName)) {
196
+ const agentFile = path.join(this.agentDir, `${agentName}.md`);
197
+ try {
198
+ accessSync(agentFile);
199
+ } catch {
200
+ logger.warn(`Settings reference unknown agent: ${agentName}`);
201
+ }
202
+ }
195
203
  }
196
204
  }
197
205
  }
@@ -266,4 +274,4 @@ var AgentManager = class {
266
274
  export {
267
275
  AgentManager
268
276
  };
269
- //# sourceMappingURL=chunk-B7U6OKUR.js.map
277
+ //# sourceMappingURL=chunk-C6HNNJIV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/AgentManager.ts","../src/utils/MarkdownAgentParser.ts"],"sourcesContent":["import { readFile } from 'fs/promises'\nimport { accessSync } from 'fs'\nimport path from 'path'\nimport { fileURLToPath } from 'url'\nimport fg from 'fast-glob'\nimport { MarkdownAgentParser } from '../utils/MarkdownAgentParser.js'\nimport { logger } from '../utils/logger.js'\nimport type { IloomSettings } from './SettingsManager.js'\nimport { PromptTemplateManager, TemplateVariables, buildReviewTemplateVariables } from './PromptTemplateManager.js'\n\n// Agent schema interface\nexport interface AgentConfig {\n\tdescription: string\n\tprompt: string\n\ttools?: string[] // Optional - when omitted, agent inherits all tools from parent\n\tmodel: string\n\tcolor?: string\n}\n\n// Container for all loaded agents (keyed by agent name without extension)\nexport interface AgentConfigs {\n\t[agentName: string]: AgentConfig\n}\n\nexport class AgentManager {\n\tprivate agentDir: string\n\tprivate templateManager: PromptTemplateManager\n\n\tconstructor(agentDir?: string, templateManager?: PromptTemplateManager) {\n\t\tthis.templateManager = templateManager ?? new PromptTemplateManager()\n\t\tif (agentDir) {\n\t\t\tthis.agentDir = agentDir\n\t\t} else {\n\t\t\t// Find agents relative to package installation\n\t\t\t// Same pattern as PromptTemplateManager\n\t\t\t// When running from dist/, agents are copied to dist/agents/\n\t\t\tconst currentFileUrl = import.meta.url\n\t\t\tconst currentFilePath = fileURLToPath(currentFileUrl)\n\t\t\tconst distDir = path.dirname(currentFilePath)\n\n\t\t\t// Walk up to find the agents directory\n\t\t\tlet agentDirPath = path.join(distDir, 'agents')\n\t\t\tlet currentDir = distDir\n\n\t\t\twhile (currentDir !== path.dirname(currentDir)) {\n\t\t\t\tconst candidatePath = path.join(currentDir, 'agents')\n\t\t\t\ttry {\n\t\t\t\t\taccessSync(candidatePath)\n\t\t\t\t\tagentDirPath = candidatePath\n\t\t\t\t\tbreak\n\t\t\t\t} catch {\n\t\t\t\t\tcurrentDir = path.dirname(currentDir)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.agentDir = agentDirPath\n\t\t\tlogger.debug('AgentManager initialized', { agentDir: this.agentDir })\n\t\t}\n\t}\n\n\t/**\n\t * Load agent configuration files from markdown (.md) format\n\t * Optionally apply model overrides from settings and template variable substitution\n\t * Throws error if agents directory doesn't exist or files are malformed\n\t * @param settings - Optional project settings with per-agent model overrides\n\t * @param templateVariables - Optional variables for template substitution in agent prompts\n\t * @param patterns - Optional glob patterns to filter which agents to load (default: ['*.md'])\n\t * Supports negation patterns like ['*.md', '!iloom-framework-detector.md']\n\t */\n\tasync loadAgents(\n\t\tsettings?: IloomSettings,\n\t\ttemplateVariables?: TemplateVariables,\n\t\tpatterns: string[] = ['*.md']\n\t): Promise<AgentConfigs> {\n\t\t// Use fast-glob to filter agent files based on patterns\n\t\tconst agentFiles = await fg(patterns, {\n\t\t\tcwd: this.agentDir,\n\t\t\tonlyFiles: true,\n\t\t})\n\n\t\tconst agents: AgentConfigs = {}\n\n\t\tfor (const filename of agentFiles) {\n\t\t\tconst agentPath = path.join(this.agentDir, filename)\n\n\t\t\ttry {\n\t\t\t\tconst content = await readFile(agentPath, 'utf-8')\n\n\t\t\t\t// Parse markdown with frontmatter\n\t\t\t\tconst parsed = this.parseMarkdownAgent(content, filename)\n\t\t\t\tconst agentConfig = parsed.config\n\t\t\t\tconst agentName = parsed.name\n\n\t\t\t\t// Validate required fields\n\t\t\t\tthis.validateAgentConfig(agentConfig, agentName)\n\n\t\t\t\tagents[agentName] = agentConfig\n\t\t\t\tlogger.debug(`Loaded agent: ${agentName}`)\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(`Failed to load agent from ${filename}`, { error })\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Failed to load agent from ${filename}: ${error instanceof Error ? error.message : 'Unknown error'}`,\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\t// Apply template variable substitution to agent prompts if variables provided\n\t\tif (templateVariables) {\n\t\t\t// Extract review config from settings and add to template variables\n\t\t\tObject.assign(templateVariables, buildReviewTemplateVariables(settings?.agents))\n\n\t\t\tfor (const [agentName, agentConfig] of Object.entries(agents)) {\n\t\t\t\tagents[agentName] = {\n\t\t\t\t\t...agentConfig,\n\t\t\t\t\tprompt: this.templateManager.substituteVariables(agentConfig.prompt, templateVariables),\n\t\t\t\t}\n\t\t\t\tlogger.debug(`Applied template substitution to agent: ${agentName}`)\n\t\t\t}\n\t\t}\n\n\t\t// Apply settings overrides if provided\n\t\tif (settings?.agents) {\n\t\t\tfor (const [agentName, agentSettings] of Object.entries(settings.agents)) {\n\t\t\t\tif (agents[agentName] && agentSettings.model) {\n\t\t\t\t\tlogger.debug(`Overriding model for ${agentName}: ${agents[agentName].model} -> ${agentSettings.model}`)\n\t\t\t\t\tagents[agentName] = {\n\t\t\t\t\t\t...agents[agentName],\n\t\t\t\t\t\tmodel: agentSettings.model,\n\t\t\t\t\t}\n\t\t\t\t} else if (!agents[agentName]) {\n\t\t\t\t\t// Skip warning for runtime-generated agents (e.g., swarm worker)\n\t\t\t\t\tconst RUNTIME_GENERATED_AGENTS = ['iloom-swarm-worker']\n\t\t\t\t\tif (!RUNTIME_GENERATED_AGENTS.includes(agentName)) {\n\t\t\t\t\t\t// Only warn if the agent file doesn't exist at all (typo in settings)\n\t\t\t\t\t\t// Skip warning if the agent exists but wasn't loaded due to pattern filtering\n\t\t\t\t\t\tconst agentFile = path.join(this.agentDir, `${agentName}.md`)\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\taccessSync(agentFile)\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\tlogger.warn(`Settings reference unknown agent: ${agentName}`)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn agents\n\t}\n\n\t/**\n\t * Validate agent configuration has required fields\n\t * Note: tools is optional - when omitted, agent inherits all tools from parent\n\t */\n\tprivate validateAgentConfig(config: AgentConfig, agentName: string): void {\n\t\tconst requiredFields: (keyof AgentConfig)[] = ['description', 'prompt', 'model']\n\n\t\tfor (const field of requiredFields) {\n\t\t\tif (!config[field]) {\n\t\t\t\tthrow new Error(`Agent ${agentName} missing required field: ${field}`)\n\t\t\t}\n\t\t}\n\n\t\t// Tools is optional, but if present must be an array\n\t\tif (config.tools !== undefined && !Array.isArray(config.tools)) {\n\t\t\tthrow new Error(`Agent ${agentName} tools must be an array`)\n\t\t}\n\t}\n\n\t/**\n\t * Parse markdown agent file with YAML frontmatter\n\t * @param content - Raw markdown file content\n\t * @param filename - Original filename for error messages\n\t * @returns Parsed agent config and name\n\t */\n\tprivate parseMarkdownAgent(content: string, filename: string): { config: AgentConfig; name: string } {\n\t\ttry {\n\t\t\t// Parse frontmatter using custom parser\n\t\t\tconst { data, content: markdownBody } = MarkdownAgentParser.parse(content)\n\n\t\t\t// Validate frontmatter has required fields\n\t\t\tif (!data.name) {\n\t\t\t\tthrow new Error('Missing required field: name')\n\t\t\t}\n\t\t\tif (!data.description) {\n\t\t\t\tthrow new Error('Missing required field: description')\n\t\t\t}\n\t\t\t// Note: tools is now optional - when omitted, agent inherits all tools from parent\n\t\t\tif (!data.model) {\n\t\t\t\tthrow new Error('Missing required field: model')\n\t\t\t}\n\n\t\t\t// Parse tools from comma-separated string to array (only if tools field is present)\n\t\t\tlet tools: string[] | undefined\n\t\t\tif (data.tools) {\n\t\t\t\ttools = data.tools\n\t\t\t\t\t.split(',')\n\t\t\t\t\t.map((tool: string) => tool.trim())\n\t\t\t\t\t.filter((tool: string) => tool.length > 0)\n\t\t\t}\n\n\t\t\t// Validate model and warn if non-standard\n\t\t\tconst validModels = ['sonnet', 'opus', 'haiku']\n\t\t\tif (!validModels.includes(data.model)) {\n\t\t\t\tlogger.warn(\n\t\t\t\t\t`Agent ${data.name} uses model \"${data.model}\" which may not be recognized by Claude CLI, and your workflow may fail or produce unexpected results. ` +\n\t\t\t\t\t\t`Valid values are: ${validModels.join(', ')}`\n\t\t\t\t)\n\t\t\t}\n\n\t\t\t// Construct AgentConfig\n\t\t\tconst config: AgentConfig = {\n\t\t\t\tdescription: data.description,\n\t\t\t\tprompt: markdownBody.trim(),\n\t\t\t\tmodel: data.model,\n\t\t\t\t...(tools && { tools }),\n\t\t\t\t...(data.color && { color: data.color }),\n\t\t\t}\n\n\t\t\treturn { config, name: data.name }\n\t\t} catch (error) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to parse markdown agent ${filename}: ${error instanceof Error ? error.message : 'Unknown error'}`\n\t\t\t)\n\t\t}\n\t}\n\n\t/**\n\t * Format loaded agents for Claude CLI --agents flag\n\t * Returns object suitable for JSON.stringify\n\t */\n\tformatForCli(agents: AgentConfigs): Record<string, unknown> {\n\t\t// The agents object is already in the correct format\n\t\t// Just return it - launchClaude will JSON.stringify it\n\t\treturn agents as Record<string, unknown>\n\t}\n}\n","/**\n * Custom YAML frontmatter parser for agent markdown files\n * Replaces gray-matter dependency with lightweight custom implementation\n */\n\ninterface ParseResult {\n\tdata: Record<string, string>\n\tcontent: string\n}\n\nexport class MarkdownAgentParser {\n\t/**\n\t * Parse markdown content with YAML frontmatter\n\t * @param content - Raw markdown file content\n\t * @returns Object with parsed frontmatter data and markdown body content\n\t * @throws Error if frontmatter is malformed or missing\n\t */\n\tstatic parse(content: string): ParseResult {\n\t\tconst lines = content.split('\\n')\n\n\t\t// Check for opening frontmatter delimiter\n\t\tif (lines[0]?.trim() !== '---') {\n\t\t\tthrow new Error('Missing opening frontmatter delimiter (---)')\n\t\t}\n\n\t\t// Find closing frontmatter delimiter\n\t\tlet closingDelimiterIndex = -1\n\t\tfor (let i = 1; i < lines.length; i++) {\n\t\t\tif (lines[i]?.trim() === '---') {\n\t\t\t\tclosingDelimiterIndex = i\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif (closingDelimiterIndex === -1) {\n\t\t\tthrow new Error('Missing closing frontmatter delimiter (---)')\n\t\t}\n\n\t\t// Extract frontmatter lines (between the delimiters)\n\t\tconst frontmatterLines = lines.slice(1, closingDelimiterIndex)\n\n\t\t// Extract markdown body (after closing delimiter)\n\t\tconst bodyLines = lines.slice(closingDelimiterIndex + 1)\n\t\tconst markdownBody = bodyLines.join('\\n')\n\n\t\t// Parse YAML frontmatter into key-value pairs\n\t\tconst data = this.parseYaml(frontmatterLines.join('\\n'))\n\n\t\treturn {\n\t\t\tdata,\n\t\t\tcontent: markdownBody,\n\t\t}\n\t}\n\n\t/**\n\t * Parse simplified YAML into key-value object\n\t * Supports:\n\t * - Simple key: value pairs\n\t * - Multiline values with | indicator\n\t * - Values with special characters and newlines\n\t *\n\t * @param yaml - YAML string to parse\n\t * @returns Object with parsed key-value pairs\n\t */\n\tprivate static parseYaml(yaml: string): Record<string, string> {\n\t\tconst result: Record<string, string> = {}\n\t\tconst lines = yaml.split('\\n')\n\t\tlet currentKey: string | null = null\n\t\tlet currentValue: string[] = []\n\t\tlet isMultiline = false\n\n\t\tconst finalizeCurrent = (): void => {\n\t\t\tif (currentKey && currentValue.length > 0) {\n\t\t\t\tresult[currentKey] = currentValue.join('\\n').trim()\n\t\t\t\tcurrentKey = null\n\t\t\t\tcurrentValue = []\n\t\t\t}\n\t\t}\n\n\t\tfor (const line of lines) {\n\t\t\t// Skip empty lines when not in multiline mode\n\t\t\tif (!isMultiline && line.trim() === '') {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Check if this is a new key-value pair\n\t\t\tconst keyValueMatch = line.match(/^([a-zA-Z_][a-zA-Z0-9_-]*)\\s*:\\s*(.*)$/)\n\n\t\t\tif (keyValueMatch && !isMultiline) {\n\t\t\t\t// Finalize previous key if exists\n\t\t\t\tfinalizeCurrent()\n\n\t\t\t\tconst [, key, value] = keyValueMatch\n\t\t\t\tif (!key || value === undefined) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tcurrentKey = key\n\n\t\t\t\t// Check for multiline indicator\n\t\t\t\tif (value.trim() === '|') {\n\t\t\t\t\tisMultiline = true\n\t\t\t\t\tcurrentValue = []\n\t\t\t\t} else {\n\t\t\t\t\t// Single line value\n\t\t\t\t\tcurrentValue = [value]\n\t\t\t\t\tfinalizeCurrent()\n\t\t\t\t\tisMultiline = false\n\t\t\t\t}\n\t\t\t} else if (isMultiline && currentKey) {\n\t\t\t\t// Continuation of multiline value\n\t\t\t\t// Check if we've returned to normal indentation (new key)\n\t\t\t\tif (line.match(/^[a-zA-Z_][a-zA-Z0-9_-]*\\s*:/) && !line.startsWith(' ')) {\n\t\t\t\t\t// End of multiline, this is a new key\n\t\t\t\t\tfinalizeCurrent()\n\t\t\t\t\tisMultiline = false\n\n\t\t\t\t\t// Process this line as a new key\n\t\t\t\t\tconst match = line.match(/^([a-zA-Z_][a-zA-Z0-9_-]*)\\s*:\\s*(.*)$/)\n\t\t\t\t\tif (match) {\n\t\t\t\t\t\tconst [, key, value] = match\n\t\t\t\t\t\tif (key && value !== undefined) {\n\t\t\t\t\t\t\tcurrentKey = key\n\t\t\t\t\t\t\tcurrentValue = [value]\n\t\t\t\t\t\t\tfinalizeCurrent()\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Remove leading spaces (common indentation) from multiline values\n\t\t\t\t\tconst trimmedLine = line.replace(/^ {2}/, '')\n\t\t\t\t\tcurrentValue.push(trimmedLine)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Finalize last key\n\t\tfinalizeCurrent()\n\n\t\treturn result\n\t}\n}\n"],"mappings":"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","names":[]}
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ProcessManager
4
- } from "./chunk-IZIYLYPK.js";
4
+ } from "./chunk-G5V75JD5.js";
5
5
  import {
6
6
  detectPackageManager,
7
7
  runScript
8
- } from "./chunk-4LKGCFGG.js";
8
+ } from "./chunk-WWKOVDWC.js";
9
9
  import {
10
10
  getPackageScripts
11
- } from "./chunk-VOGGLPG5.js";
11
+ } from "./chunk-YQ57ORTV.js";
12
12
  import {
13
13
  logger
14
14
  } from "./chunk-VT4PDUYT.js";
@@ -217,4 +217,4 @@ var DevServerManager = class {
217
217
  export {
218
218
  DevServerManager
219
219
  };
220
- //# sourceMappingURL=chunk-A7NJF73J.js.map
220
+ //# sourceMappingURL=chunk-CVCTIDDK.js.map
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ClaudeService
4
- } from "./chunk-6IIL5M2L.js";
4
+ } from "./chunk-S7PZA6IV.js";
5
5
  import {
6
6
  logger
7
7
  } from "./chunk-VT4PDUYT.js";
@@ -19,11 +19,11 @@ var ClaudeContextManager = class {
19
19
  if (!context.workspacePath) {
20
20
  throw new Error("Workspace path is required");
21
21
  }
22
- if (context.type === "issue" && typeof context.identifier !== "number") {
23
- throw new Error("Issue identifier must be a number");
22
+ if (context.type === "issue" && context.identifier === void 0) {
23
+ throw new Error("Issue identifier is required");
24
24
  }
25
- if (context.type === "pr" && typeof context.identifier !== "number") {
26
- throw new Error("PR identifier must be a number");
25
+ if (context.type === "pr" && context.identifier === void 0) {
26
+ throw new Error("PR identifier is required");
27
27
  }
28
28
  logger.debug("Context prepared", { context });
29
29
  }
@@ -63,4 +63,4 @@ var ClaudeContextManager = class {
63
63
  export {
64
64
  ClaudeContextManager
65
65
  };
66
- //# sourceMappingURL=chunk-Z2TWEXR7.js.map
66
+ //# sourceMappingURL=chunk-E6KOWMKA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/ClaudeContextManager.ts"],"sourcesContent":["import { ClaudeService, ClaudeWorkflowOptions } from './ClaudeService.js'\nimport { PromptTemplateManager } from './PromptTemplateManager.js'\nimport { logger } from '../utils/logger.js'\n\nexport interface ClaudeContext {\n\ttype: 'issue' | 'pr' | 'regular'\n\tidentifier: number | string\n\ttitle?: string\n\tworkspacePath: string\n\tport?: number\n\tbranchName?: string\n\toneShot?: import('../types/index.js').OneShotMode\n\tsetArguments?: string[] // Raw --set arguments to forward\n\texecutablePath?: string // Executable path to use for spin command\n}\n\nexport class ClaudeContextManager {\n\tprivate claudeService: ClaudeService\n\n\tconstructor(claudeService?: ClaudeService, _promptTemplateManager?: PromptTemplateManager, settingsManager?: import('./SettingsManager.js').SettingsManager) {\n\t\tthis.claudeService = claudeService ?? new ClaudeService(undefined, settingsManager)\n\t\t// promptTemplateManager is accepted for dependency injection but not used yet\n\t\t// Will be used in Issue #11 for .claude-context.md generation\n\t}\n\n\t/**\n\t * Prepare context for Claude launch\n\t * Placeholder for future .claude-context.md generation (Issue #11)\n\t */\n\tasync prepareContext(context: ClaudeContext): Promise<void> {\n\t\t// Validate context object\n\t\tif (!context.workspacePath) {\n\t\t\tthrow new Error('Workspace path is required')\n\t\t}\n\n\t\tif (context.type === 'issue' && context.identifier === undefined) {\n\t\t\tthrow new Error('Issue identifier is required')\n\t\t}\n\n\t\tif (context.type === 'pr' && context.identifier === undefined) {\n\t\t\tthrow new Error('PR identifier is required')\n\t\t}\n\n\t\tlogger.debug('Context prepared', { context })\n\t\t// Future: Generate .claude-context.md file in workspace\n\t}\n\n\t/**\n\t * Launch Claude with the prepared context\n\t */\n\tasync launchWithContext(context: ClaudeContext, headless: boolean = false): Promise<string | void> {\n\t\t// Prepare context first\n\t\tawait this.prepareContext(context)\n\n\t\t// Convert ClaudeContext to ClaudeWorkflowOptions\n\t\tconst workflowOptions: ClaudeWorkflowOptions = {\n\t\t\ttype: context.type,\n\t\t\tworkspacePath: context.workspacePath,\n\t\t\t...(context.port !== undefined && { port: context.port }),\n\t\t\theadless,\n\t\t\toneShot: context.oneShot ?? 'default',\n\t\t}\n\n\t\t// Add optional title if present\n\t\tif (context.title !== undefined) {\n\t\t\tworkflowOptions.title = context.title\n\t\t}\n\n\t\t// Add optional branch name if present\n\t\tif (context.branchName !== undefined) {\n\t\t\tworkflowOptions.branchName = context.branchName\n\t\t}\n\n\t\t// Add optional setArguments if present\n\t\tif (context.setArguments !== undefined) {\n\t\t\tworkflowOptions.setArguments = context.setArguments\n\t\t}\n\n\t\t// Add optional executablePath if present\n\t\tif (context.executablePath !== undefined) {\n\t\t\tworkflowOptions.executablePath = context.executablePath\n\t\t}\n\n\t\t// Set issue or PR number based on type\n\t\tif (context.type === 'issue') {\n\t\t\tworkflowOptions.issueNumber = context.identifier as number\n\t\t} else if (context.type === 'pr') {\n\t\t\tworkflowOptions.prNumber = context.identifier as number\n\t\t}\n\n\t\t// Delegate to Claude service\n\t\treturn this.claudeService.launchForWorkflow(workflowOptions)\n\t}\n}\n"],"mappings":";;;;;;;;;AAgBO,IAAM,uBAAN,MAA2B;AAAA,EAGjC,YAAY,eAA+B,wBAAgD,iBAAkE;AAC5J,SAAK,gBAAgB,iBAAiB,IAAI,cAAc,QAAW,eAAe;AAAA,EAGnF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,eAAe,SAAuC;AAE3D,QAAI,CAAC,QAAQ,eAAe;AAC3B,YAAM,IAAI,MAAM,4BAA4B;AAAA,IAC7C;AAEA,QAAI,QAAQ,SAAS,WAAW,QAAQ,eAAe,QAAW;AACjE,YAAM,IAAI,MAAM,8BAA8B;AAAA,IAC/C;AAEA,QAAI,QAAQ,SAAS,QAAQ,QAAQ,eAAe,QAAW;AAC9D,YAAM,IAAI,MAAM,2BAA2B;AAAA,IAC5C;AAEA,WAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC;AAAA,EAE7C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,kBAAkB,SAAwB,WAAoB,OAA+B;AAElG,UAAM,KAAK,eAAe,OAAO;AAGjC,UAAM,kBAAyC;AAAA,MAC9C,MAAM,QAAQ;AAAA,MACd,eAAe,QAAQ;AAAA,MACvB,GAAI,QAAQ,SAAS,UAAa,EAAE,MAAM,QAAQ,KAAK;AAAA,MACvD;AAAA,MACA,SAAS,QAAQ,WAAW;AAAA,IAC7B;AAGA,QAAI,QAAQ,UAAU,QAAW;AAChC,sBAAgB,QAAQ,QAAQ;AAAA,IACjC;AAGA,QAAI,QAAQ,eAAe,QAAW;AACrC,sBAAgB,aAAa,QAAQ;AAAA,IACtC;AAGA,QAAI,QAAQ,iBAAiB,QAAW;AACvC,sBAAgB,eAAe,QAAQ;AAAA,IACxC;AAGA,QAAI,QAAQ,mBAAmB,QAAW;AACzC,sBAAgB,iBAAiB,QAAQ;AAAA,IAC1C;AAGA,QAAI,QAAQ,SAAS,SAAS;AAC7B,sBAAgB,cAAc,QAAQ;AAAA,IACvC,WAAW,QAAQ,SAAS,MAAM;AACjC,sBAAgB,WAAW,QAAQ;AAAA,IACpC;AAGA,WAAO,KAAK,cAAc,kBAAkB,eAAe;AAAA,EAC5D;AACD;","names":[]}
@@ -4,23 +4,23 @@ import {
4
4
  } from "./chunk-NXMDEL3F.js";
5
5
  import {
6
6
  IssueManagementProviderFactory
7
- } from "./chunk-ULSWCPQG.js";
7
+ } from "./chunk-SWSJWA2S.js";
8
8
  import {
9
9
  hasMultipleRemotes
10
10
  } from "./chunk-FXDYIV3K.js";
11
+ import {
12
+ generateDeterministicSessionId,
13
+ launchClaude
14
+ } from "./chunk-UR5DGNUO.js";
11
15
  import {
12
16
  PromptTemplateManager
13
- } from "./chunk-QN47QVBX.js";
17
+ } from "./chunk-UUEW5KWB.js";
14
18
  import {
15
19
  SettingsManager
16
- } from "./chunk-RI2YL6TK.js";
20
+ } from "./chunk-7VHJNVLF.js";
17
21
  import {
18
22
  MetadataManager
19
- } from "./chunk-KBEIQP4G.js";
20
- import {
21
- generateDeterministicSessionId,
22
- launchClaude
23
- } from "./chunk-FO5GGFOV.js";
23
+ } from "./chunk-KB64WNBZ.js";
24
24
  import {
25
25
  logger
26
26
  } from "./chunk-VT4PDUYT.js";
@@ -354,7 +354,7 @@ var SessionSummaryService = class {
354
354
  async postSummaryToIssue(issueNumber, summary, settings, worktreePath, prNumber) {
355
355
  var _a;
356
356
  const providerType = prNumber !== void 0 ? "github" : ((_a = settings.issueManagement) == null ? void 0 : _a.provider) ?? "github";
357
- const provider = IssueManagementProviderFactory.create(providerType);
357
+ const provider = IssueManagementProviderFactory.create(providerType, settings);
358
358
  const finalSummary = await this.applyAttributionWithSettings(summary, settings, worktreePath);
359
359
  const targetNumber = prNumber ?? issueNumber;
360
360
  const targetType = prNumber !== void 0 ? "pr" : "issue";
@@ -369,4 +369,4 @@ var SessionSummaryService = class {
369
369
  export {
370
370
  SessionSummaryService
371
371
  };
372
- //# sourceMappingURL=chunk-3I4ONZRT.js.map
372
+ //# sourceMappingURL=chunk-EVPZFV3K.js.map