@kynetic-ai/spec 0.10.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (487) hide show
  1. package/README.md +55 -455
  2. package/dist/agent-runtime/bootstrap.d.ts +31 -0
  3. package/dist/agent-runtime/bootstrap.d.ts.map +1 -0
  4. package/dist/agent-runtime/bootstrap.js +302 -0
  5. package/dist/agent-runtime/bootstrap.js.map +1 -0
  6. package/dist/agent-runtime/dispatch.d.ts +150 -10
  7. package/dist/agent-runtime/dispatch.d.ts.map +1 -1
  8. package/dist/agent-runtime/dispatch.js +1248 -244
  9. package/dist/agent-runtime/dispatch.js.map +1 -1
  10. package/dist/agent-runtime/invocation.d.ts +28 -1
  11. package/dist/agent-runtime/invocation.d.ts.map +1 -1
  12. package/dist/agent-runtime/invocation.js +172 -60
  13. package/dist/agent-runtime/invocation.js.map +1 -1
  14. package/dist/agent-runtime/prompts.d.ts +9 -0
  15. package/dist/agent-runtime/prompts.d.ts.map +1 -1
  16. package/dist/agent-runtime/prompts.js +42 -7
  17. package/dist/agent-runtime/prompts.js.map +1 -1
  18. package/dist/agent-runtime/session-event-accumulator.d.ts +83 -0
  19. package/dist/agent-runtime/session-event-accumulator.d.ts.map +1 -0
  20. package/dist/agent-runtime/session-event-accumulator.js +203 -0
  21. package/dist/agent-runtime/session-event-accumulator.js.map +1 -0
  22. package/dist/agent-runtime/session-event-types.d.ts +67 -0
  23. package/dist/agent-runtime/session-event-types.d.ts.map +1 -0
  24. package/dist/agent-runtime/session-event-types.js +13 -0
  25. package/dist/agent-runtime/session-event-types.js.map +1 -0
  26. package/dist/agent-runtime/workspace.d.ts +244 -0
  27. package/dist/agent-runtime/workspace.d.ts.map +1 -0
  28. package/dist/agent-runtime/workspace.js +2025 -0
  29. package/dist/agent-runtime/workspace.js.map +1 -0
  30. package/dist/agents/adapters.d.ts.map +1 -1
  31. package/dist/agents/adapters.js +58 -13
  32. package/dist/agents/adapters.js.map +1 -1
  33. package/dist/agents/spawner.d.ts +8 -0
  34. package/dist/agents/spawner.d.ts.map +1 -1
  35. package/dist/agents/spawner.js +25 -3
  36. package/dist/agents/spawner.js.map +1 -1
  37. package/dist/cli/batch-exec.js +1 -1
  38. package/dist/cli/batch-exec.js.map +1 -1
  39. package/dist/cli/command-annotations.d.ts +15 -3
  40. package/dist/cli/command-annotations.d.ts.map +1 -1
  41. package/dist/cli/command-annotations.js +23 -3
  42. package/dist/cli/command-annotations.js.map +1 -1
  43. package/dist/cli/commands/agent.d.ts +2 -0
  44. package/dist/cli/commands/agent.d.ts.map +1 -1
  45. package/dist/cli/commands/agent.js +144 -27
  46. package/dist/cli/commands/agent.js.map +1 -1
  47. package/dist/cli/commands/agents.d.ts.map +1 -1
  48. package/dist/cli/commands/agents.js +5 -5
  49. package/dist/cli/commands/agents.js.map +1 -1
  50. package/dist/cli/commands/derive.d.ts.map +1 -1
  51. package/dist/cli/commands/derive.js +118 -3
  52. package/dist/cli/commands/derive.js.map +1 -1
  53. package/dist/cli/commands/guard.d.ts.map +1 -1
  54. package/dist/cli/commands/guard.js +8 -6
  55. package/dist/cli/commands/guard.js.map +1 -1
  56. package/dist/cli/commands/index.d.ts +1 -0
  57. package/dist/cli/commands/index.d.ts.map +1 -1
  58. package/dist/cli/commands/index.js +1 -0
  59. package/dist/cli/commands/index.js.map +1 -1
  60. package/dist/cli/commands/init.d.ts.map +1 -1
  61. package/dist/cli/commands/init.js +20 -0
  62. package/dist/cli/commands/init.js.map +1 -1
  63. package/dist/cli/commands/item.d.ts.map +1 -1
  64. package/dist/cli/commands/item.js +205 -47
  65. package/dist/cli/commands/item.js.map +1 -1
  66. package/dist/cli/commands/log.d.ts.map +1 -1
  67. package/dist/cli/commands/log.js +24 -10
  68. package/dist/cli/commands/log.js.map +1 -1
  69. package/dist/cli/commands/meta.d.ts.map +1 -1
  70. package/dist/cli/commands/meta.js +10 -1
  71. package/dist/cli/commands/meta.js.map +1 -1
  72. package/dist/cli/commands/plan-import.d.ts +3 -3
  73. package/dist/cli/commands/plan-import.d.ts.map +1 -1
  74. package/dist/cli/commands/plan-import.js +213 -528
  75. package/dist/cli/commands/plan-import.js.map +1 -1
  76. package/dist/cli/commands/plan.d.ts.map +1 -1
  77. package/dist/cli/commands/plan.js +533 -83
  78. package/dist/cli/commands/plan.js.map +1 -1
  79. package/dist/cli/commands/review.d.ts +14 -0
  80. package/dist/cli/commands/review.d.ts.map +1 -0
  81. package/dist/cli/commands/review.js +1142 -0
  82. package/dist/cli/commands/review.js.map +1 -0
  83. package/dist/cli/commands/serve.d.ts +1 -0
  84. package/dist/cli/commands/serve.d.ts.map +1 -1
  85. package/dist/cli/commands/serve.js +33 -10
  86. package/dist/cli/commands/serve.js.map +1 -1
  87. package/dist/cli/commands/session/checkpoint.d.ts +2 -4
  88. package/dist/cli/commands/session/checkpoint.d.ts.map +1 -1
  89. package/dist/cli/commands/session/checkpoint.js +6 -107
  90. package/dist/cli/commands/session/checkpoint.js.map +1 -1
  91. package/dist/cli/commands/session/commands.d.ts.map +1 -1
  92. package/dist/cli/commands/session/commands.js +33 -23
  93. package/dist/cli/commands/session/commands.js.map +1 -1
  94. package/dist/cli/commands/session/compact.js +4 -4
  95. package/dist/cli/commands/session/compact.js.map +1 -1
  96. package/dist/cli/commands/session/create.js +2 -2
  97. package/dist/cli/commands/session/create.js.map +1 -1
  98. package/dist/cli/commands/session/format.d.ts.map +1 -1
  99. package/dist/cli/commands/session/format.js +1 -6
  100. package/dist/cli/commands/session/format.js.map +1 -1
  101. package/dist/cli/commands/session/log.d.ts +32 -7
  102. package/dist/cli/commands/session/log.d.ts.map +1 -1
  103. package/dist/cli/commands/session/log.js +166 -60
  104. package/dist/cli/commands/session/log.js.map +1 -1
  105. package/dist/cli/commands/session/migrate.d.ts +9 -0
  106. package/dist/cli/commands/session/migrate.d.ts.map +1 -0
  107. package/dist/cli/commands/session/migrate.js +46 -0
  108. package/dist/cli/commands/session/migrate.js.map +1 -0
  109. package/dist/cli/commands/session/stale-close.d.ts.map +1 -1
  110. package/dist/cli/commands/session/stale-close.js +5 -8
  111. package/dist/cli/commands/session/stale-close.js.map +1 -1
  112. package/dist/cli/commands/session/types.d.ts +1 -1
  113. package/dist/cli/commands/session/types.d.ts.map +1 -1
  114. package/dist/cli/commands/setup.d.ts +2 -2
  115. package/dist/cli/commands/setup.d.ts.map +1 -1
  116. package/dist/cli/commands/setup.js +287 -257
  117. package/dist/cli/commands/setup.js.map +1 -1
  118. package/dist/cli/commands/shadow.d.ts.map +1 -1
  119. package/dist/cli/commands/shadow.js +147 -31
  120. package/dist/cli/commands/shadow.js.map +1 -1
  121. package/dist/cli/commands/skill-crud.d.ts +7 -0
  122. package/dist/cli/commands/skill-crud.d.ts.map +1 -1
  123. package/dist/cli/commands/skill-crud.js +41 -18
  124. package/dist/cli/commands/skill-crud.js.map +1 -1
  125. package/dist/cli/commands/skill-diff.d.ts.map +1 -1
  126. package/dist/cli/commands/skill-diff.js +29 -3
  127. package/dist/cli/commands/skill-diff.js.map +1 -1
  128. package/dist/cli/commands/skill-install.d.ts.map +1 -1
  129. package/dist/cli/commands/skill-install.js +5 -4
  130. package/dist/cli/commands/skill-install.js.map +1 -1
  131. package/dist/cli/commands/task.d.ts.map +1 -1
  132. package/dist/cli/commands/task.js +359 -49
  133. package/dist/cli/commands/task.js.map +1 -1
  134. package/dist/cli/commands/trait.d.ts.map +1 -1
  135. package/dist/cli/commands/trait.js +5 -27
  136. package/dist/cli/commands/trait.js.map +1 -1
  137. package/dist/cli/commands/validate.d.ts.map +1 -1
  138. package/dist/cli/commands/validate.js +113 -52
  139. package/dist/cli/commands/validate.js.map +1 -1
  140. package/dist/cli/index.d.ts.map +1 -1
  141. package/dist/cli/index.js +69 -2
  142. package/dist/cli/index.js.map +1 -1
  143. package/dist/cli/output.d.ts +26 -0
  144. package/dist/cli/output.d.ts.map +1 -1
  145. package/dist/cli/output.js +108 -1
  146. package/dist/cli/output.js.map +1 -1
  147. package/dist/cli/sync-mode.d.ts +44 -0
  148. package/dist/cli/sync-mode.d.ts.map +1 -0
  149. package/dist/cli/sync-mode.js +64 -0
  150. package/dist/cli/sync-mode.js.map +1 -0
  151. package/dist/daemon/middleware/project-context.ts +25 -7
  152. package/dist/daemon/project-context.ts +18 -0
  153. package/dist/daemon/routes/agent-dispatch.ts +107 -23
  154. package/dist/daemon/routes/aggregation.ts +184 -0
  155. package/dist/daemon/routes/inbox.ts +5 -0
  156. package/dist/daemon/routes/items.ts +167 -0
  157. package/dist/daemon/routes/meta.ts +141 -1
  158. package/dist/daemon/routes/plans.ts +147 -0
  159. package/dist/daemon/routes/projects.ts +28 -6
  160. package/dist/daemon/routes/ref-resolution.ts +119 -0
  161. package/dist/daemon/routes/refs.ts +42 -0
  162. package/dist/daemon/routes/session-related.ts +140 -0
  163. package/dist/daemon/routes/sessions.ts +581 -0
  164. package/dist/daemon/routes/tasks.ts +257 -2
  165. package/dist/daemon/routes/triage.ts +40 -1
  166. package/dist/daemon/routes/validation.ts +1 -1
  167. package/dist/daemon/server.ts +165 -50
  168. package/dist/daemon/session-sync.ts +11 -0
  169. package/dist/daemon/shadow-sync.ts +11 -0
  170. package/dist/daemon/watcher.ts +56 -5
  171. package/dist/daemon/websocket/project-resolution.ts +77 -0
  172. package/dist/export/json.d.ts.map +1 -1
  173. package/dist/export/json.js +104 -1
  174. package/dist/export/json.js.map +1 -1
  175. package/dist/export/types.d.ts +52 -1
  176. package/dist/export/types.d.ts.map +1 -1
  177. package/dist/index.d.ts +1 -0
  178. package/dist/index.d.ts.map +1 -1
  179. package/dist/index.js +1 -0
  180. package/dist/index.js.map +1 -1
  181. package/dist/parser/agent-detection.d.ts +1 -1
  182. package/dist/parser/agent-detection.d.ts.map +1 -1
  183. package/dist/parser/agent-detection.js +10 -0
  184. package/dist/parser/agent-detection.js.map +1 -1
  185. package/dist/parser/alignment.d.ts.map +1 -1
  186. package/dist/parser/alignment.js +4 -2
  187. package/dist/parser/alignment.js.map +1 -1
  188. package/dist/parser/config.d.ts +397 -2
  189. package/dist/parser/config.d.ts.map +1 -1
  190. package/dist/parser/config.js +125 -3
  191. package/dist/parser/config.js.map +1 -1
  192. package/dist/parser/dispatch-workspaces.d.ts +18 -0
  193. package/dist/parser/dispatch-workspaces.d.ts.map +1 -0
  194. package/dist/parser/dispatch-workspaces.js +209 -0
  195. package/dist/parser/dispatch-workspaces.js.map +1 -0
  196. package/dist/parser/doctor.d.ts.map +1 -1
  197. package/dist/parser/doctor.js +27 -8
  198. package/dist/parser/doctor.js.map +1 -1
  199. package/dist/parser/file-lock.d.ts.map +1 -1
  200. package/dist/parser/file-lock.js +9 -2
  201. package/dist/parser/file-lock.js.map +1 -1
  202. package/dist/parser/index.d.ts +6 -0
  203. package/dist/parser/index.d.ts.map +1 -1
  204. package/dist/parser/index.js +6 -0
  205. package/dist/parser/index.js.map +1 -1
  206. package/dist/parser/plans.d.ts.map +1 -1
  207. package/dist/parser/plans.js +1 -0
  208. package/dist/parser/plans.js.map +1 -1
  209. package/dist/parser/refs.d.ts +8 -1
  210. package/dist/parser/refs.d.ts.map +1 -1
  211. package/dist/parser/refs.js +27 -1
  212. package/dist/parser/refs.js.map +1 -1
  213. package/dist/parser/review-operations.d.ts +72 -0
  214. package/dist/parser/review-operations.d.ts.map +1 -0
  215. package/dist/parser/review-operations.js +185 -0
  216. package/dist/parser/review-operations.js.map +1 -0
  217. package/dist/parser/review-task-integration.d.ts +78 -0
  218. package/dist/parser/review-task-integration.d.ts.map +1 -0
  219. package/dist/parser/review-task-integration.js +173 -0
  220. package/dist/parser/review-task-integration.js.map +1 -0
  221. package/dist/parser/review-threads.d.ts +101 -0
  222. package/dist/parser/review-threads.d.ts.map +1 -0
  223. package/dist/parser/review-threads.js +222 -0
  224. package/dist/parser/review-threads.js.map +1 -0
  225. package/dist/parser/review-validation.d.ts +69 -0
  226. package/dist/parser/review-validation.d.ts.map +1 -0
  227. package/dist/parser/review-validation.js +207 -0
  228. package/dist/parser/review-validation.js.map +1 -0
  229. package/dist/parser/reviews.d.ts +58 -0
  230. package/dist/parser/reviews.d.ts.map +1 -0
  231. package/dist/parser/reviews.js +230 -0
  232. package/dist/parser/reviews.js.map +1 -0
  233. package/dist/parser/session-branch.d.ts +91 -0
  234. package/dist/parser/session-branch.d.ts.map +1 -0
  235. package/dist/parser/session-branch.js +565 -0
  236. package/dist/parser/session-branch.js.map +1 -0
  237. package/dist/parser/session-sync-scheduler.d.ts +53 -0
  238. package/dist/parser/session-sync-scheduler.d.ts.map +1 -0
  239. package/dist/parser/session-sync-scheduler.js +100 -0
  240. package/dist/parser/session-sync-scheduler.js.map +1 -0
  241. package/dist/parser/setup-status.d.ts +7 -1
  242. package/dist/parser/setup-status.d.ts.map +1 -1
  243. package/dist/parser/setup-status.js +104 -39
  244. package/dist/parser/setup-status.js.map +1 -1
  245. package/dist/parser/shadow-sync-scheduler.d.ts +71 -0
  246. package/dist/parser/shadow-sync-scheduler.d.ts.map +1 -0
  247. package/dist/parser/shadow-sync-scheduler.js +139 -0
  248. package/dist/parser/shadow-sync-scheduler.js.map +1 -0
  249. package/dist/parser/shadow.d.ts +121 -14
  250. package/dist/parser/shadow.d.ts.map +1 -1
  251. package/dist/parser/shadow.js +752 -27
  252. package/dist/parser/shadow.js.map +1 -1
  253. package/dist/parser/skill-render.d.ts +24 -0
  254. package/dist/parser/skill-render.d.ts.map +1 -1
  255. package/dist/parser/skill-render.js +98 -26
  256. package/dist/parser/skill-render.js.map +1 -1
  257. package/dist/parser/validate.d.ts +43 -3
  258. package/dist/parser/validate.d.ts.map +1 -1
  259. package/dist/parser/validate.js +204 -30
  260. package/dist/parser/validate.js.map +1 -1
  261. package/dist/parser/yaml.d.ts +47 -11
  262. package/dist/parser/yaml.d.ts.map +1 -1
  263. package/dist/parser/yaml.js +329 -149
  264. package/dist/parser/yaml.js.map +1 -1
  265. package/dist/review/checks.d.ts +97 -0
  266. package/dist/review/checks.d.ts.map +1 -0
  267. package/dist/review/checks.js +175 -0
  268. package/dist/review/checks.js.map +1 -0
  269. package/dist/review/index.d.ts +3 -0
  270. package/dist/review/index.d.ts.map +1 -0
  271. package/dist/review/index.js +3 -0
  272. package/dist/review/index.js.map +1 -0
  273. package/dist/review/subject-bindings.d.ts +83 -0
  274. package/dist/review/subject-bindings.d.ts.map +1 -0
  275. package/dist/review/subject-bindings.js +175 -0
  276. package/dist/review/subject-bindings.js.map +1 -0
  277. package/dist/schema/common.d.ts +26 -0
  278. package/dist/schema/common.d.ts.map +1 -1
  279. package/dist/schema/common.js +13 -0
  280. package/dist/schema/common.js.map +1 -1
  281. package/dist/schema/dispatch-workspace.d.ts +2643 -0
  282. package/dist/schema/dispatch-workspace.d.ts.map +1 -0
  283. package/dist/schema/dispatch-workspace.js +187 -0
  284. package/dist/schema/dispatch-workspace.js.map +1 -0
  285. package/dist/schema/inbox.d.ts +8 -8
  286. package/dist/schema/index.d.ts +2 -0
  287. package/dist/schema/index.d.ts.map +1 -1
  288. package/dist/schema/index.js +2 -0
  289. package/dist/schema/index.js.map +1 -1
  290. package/dist/schema/meta.d.ts +663 -116
  291. package/dist/schema/meta.d.ts.map +1 -1
  292. package/dist/schema/meta.js +28 -0
  293. package/dist/schema/meta.js.map +1 -1
  294. package/dist/schema/plan.d.ts +30 -19
  295. package/dist/schema/plan.d.ts.map +1 -1
  296. package/dist/schema/plan.js +3 -1
  297. package/dist/schema/plan.js.map +1 -1
  298. package/dist/schema/review-records.d.ts +2676 -0
  299. package/dist/schema/review-records.d.ts.map +1 -0
  300. package/dist/schema/review-records.js +232 -0
  301. package/dist/schema/review-records.js.map +1 -0
  302. package/dist/schema/spec.d.ts +32 -14
  303. package/dist/schema/spec.d.ts.map +1 -1
  304. package/dist/schema/spec.js +5 -0
  305. package/dist/schema/spec.js.map +1 -1
  306. package/dist/schema/task.d.ts +187 -29
  307. package/dist/schema/task.d.ts.map +1 -1
  308. package/dist/schema/task.js +12 -2
  309. package/dist/schema/task.js.map +1 -1
  310. package/dist/schema/triage.d.ts +22 -22
  311. package/dist/sessions/cache.d.ts +119 -0
  312. package/dist/sessions/cache.d.ts.map +1 -0
  313. package/dist/sessions/cache.js +284 -0
  314. package/dist/sessions/cache.js.map +1 -0
  315. package/dist/sessions/index.d.ts +1 -0
  316. package/dist/sessions/index.d.ts.map +1 -1
  317. package/dist/sessions/index.js +2 -0
  318. package/dist/sessions/index.js.map +1 -1
  319. package/dist/sessions/legacy.d.ts +77 -0
  320. package/dist/sessions/legacy.d.ts.map +1 -0
  321. package/dist/sessions/legacy.js +146 -0
  322. package/dist/sessions/legacy.js.map +1 -0
  323. package/dist/sessions/store.d.ts +115 -71
  324. package/dist/sessions/store.d.ts.map +1 -1
  325. package/dist/sessions/store.js +357 -182
  326. package/dist/sessions/store.js.map +1 -1
  327. package/dist/sessions/types.d.ts +44 -16
  328. package/dist/sessions/types.d.ts.map +1 -1
  329. package/dist/sessions/types.js +11 -2
  330. package/dist/sessions/types.js.map +1 -1
  331. package/dist/strings/errors.d.ts +32 -0
  332. package/dist/strings/errors.d.ts.map +1 -1
  333. package/dist/strings/errors.js +17 -0
  334. package/dist/strings/errors.js.map +1 -1
  335. package/dist/strings/labels.d.ts +1 -0
  336. package/dist/strings/labels.d.ts.map +1 -1
  337. package/dist/strings/labels.js +1 -0
  338. package/dist/strings/labels.js.map +1 -1
  339. package/dist/utils/activity.d.ts +101 -0
  340. package/dist/utils/activity.d.ts.map +1 -0
  341. package/dist/utils/activity.js +408 -0
  342. package/dist/utils/activity.js.map +1 -0
  343. package/dist/utils/git.d.ts +31 -0
  344. package/dist/utils/git.d.ts.map +1 -1
  345. package/dist/utils/git.js +87 -0
  346. package/dist/utils/git.js.map +1 -1
  347. package/dist/utils/index.d.ts +2 -0
  348. package/dist/utils/index.d.ts.map +1 -1
  349. package/dist/utils/index.js +1 -0
  350. package/dist/utils/index.js.map +1 -1
  351. package/dist/web-ui/_app/immutable/assets/0.tmlwn-Ih.css +1 -0
  352. package/dist/web-ui/_app/immutable/assets/9.BwwJybWx.css +1 -0
  353. package/dist/web-ui/_app/immutable/chunks/2KqE8gtn.js +1 -0
  354. package/dist/web-ui/_app/immutable/chunks/70-t_QvE.js +1 -0
  355. package/dist/web-ui/_app/immutable/chunks/AiWQj974.js +1 -0
  356. package/dist/web-ui/_app/immutable/chunks/B25nWFyA.js +5 -0
  357. package/dist/web-ui/_app/immutable/chunks/B2bcA_Q_.js +1 -0
  358. package/dist/web-ui/_app/immutable/chunks/B5e5HYyB.js +1 -0
  359. package/dist/web-ui/_app/immutable/chunks/B7-5z6eA.js +1 -0
  360. package/dist/web-ui/_app/immutable/chunks/B7bGmhK0.js +1 -0
  361. package/dist/web-ui/_app/immutable/chunks/B8tYZKAE.js +1 -0
  362. package/dist/web-ui/_app/immutable/chunks/BFGAyJjD.js +1 -0
  363. package/dist/web-ui/_app/immutable/chunks/BG0850zf.js +1 -0
  364. package/dist/web-ui/_app/immutable/chunks/BG8eSzAd.js +1 -0
  365. package/dist/web-ui/_app/immutable/chunks/BIMxXS8I.js +1 -0
  366. package/dist/web-ui/_app/immutable/chunks/BSzL1fpU.js +1 -0
  367. package/dist/web-ui/_app/immutable/chunks/BYtjHfeq.js +1 -0
  368. package/dist/web-ui/_app/immutable/chunks/{D1ArdqNb.js → Bp5pFYXL.js} +1 -1
  369. package/dist/web-ui/_app/immutable/chunks/BsJFsuAT.js +1 -0
  370. package/dist/web-ui/_app/immutable/chunks/BvpNHcD6.js +1 -0
  371. package/dist/web-ui/_app/immutable/chunks/BypqA25-.js +1 -0
  372. package/dist/web-ui/_app/immutable/chunks/C0w6WDm5.js +1 -0
  373. package/dist/web-ui/_app/immutable/chunks/C5_PAZ0y.js +1 -0
  374. package/dist/web-ui/_app/immutable/chunks/CDRO15Iv.js +1 -0
  375. package/dist/web-ui/_app/immutable/chunks/CF1CoqD5.js +1 -0
  376. package/dist/web-ui/_app/immutable/chunks/CS2sa4_m.js +1 -0
  377. package/dist/web-ui/_app/immutable/chunks/CWUQwB9H.js +1 -0
  378. package/dist/web-ui/_app/immutable/chunks/CY5FDdSU.js +1 -0
  379. package/dist/web-ui/_app/immutable/chunks/C_7MTDoj.js +1 -0
  380. package/dist/web-ui/_app/immutable/chunks/CaAJD3dl.js +1 -0
  381. package/dist/web-ui/_app/immutable/chunks/{i-XnOIX0.js → ChB5iyEL.js} +1 -1
  382. package/dist/web-ui/_app/immutable/chunks/ChQD-6N8.js +1 -0
  383. package/dist/web-ui/_app/immutable/chunks/{BCkp8Hs8.js → CqbsoCwA.js} +1 -1
  384. package/dist/web-ui/_app/immutable/chunks/DCeJW50p.js +1 -0
  385. package/dist/web-ui/_app/immutable/chunks/DJtZNgcs.js +1 -0
  386. package/dist/web-ui/_app/immutable/chunks/DKIeaprD.js +1 -0
  387. package/dist/web-ui/_app/immutable/chunks/DLd2uVIA.js +1 -0
  388. package/dist/web-ui/_app/immutable/chunks/DW_subyT.js +2 -0
  389. package/dist/web-ui/_app/immutable/chunks/DbU6lVn0.js +1 -0
  390. package/dist/web-ui/_app/immutable/chunks/Dc7ZCC5m.js +1 -0
  391. package/dist/web-ui/_app/immutable/chunks/Dd5umPsk.js +2 -0
  392. package/dist/web-ui/_app/immutable/chunks/Dg_zDpDS.js +1 -0
  393. package/dist/web-ui/_app/immutable/chunks/Dgqu8Yuc.js +1 -0
  394. package/dist/web-ui/_app/immutable/chunks/DmxsPZTB.js +1 -0
  395. package/dist/web-ui/_app/immutable/chunks/DphTaFUB.js +1 -0
  396. package/dist/web-ui/_app/immutable/chunks/DqK4iHp0.js +1 -0
  397. package/dist/web-ui/_app/immutable/chunks/DqT6OH_u.js +2 -0
  398. package/dist/web-ui/_app/immutable/chunks/Ds9I9wQb.js +1 -0
  399. package/dist/web-ui/_app/immutable/chunks/Du5ng3u4.js +1 -0
  400. package/dist/web-ui/_app/immutable/chunks/DxJw79Wi.js +1 -0
  401. package/dist/web-ui/_app/immutable/chunks/GFTX8GgV.js +1 -0
  402. package/dist/web-ui/_app/immutable/chunks/HNjs76Zz.js +1 -0
  403. package/dist/web-ui/_app/immutable/chunks/HVMjDi4_.js +1 -0
  404. package/dist/web-ui/_app/immutable/chunks/P0A_fJvS.js +1 -0
  405. package/dist/web-ui/_app/immutable/chunks/T3vGWjIL.js +1 -0
  406. package/dist/web-ui/_app/immutable/chunks/VTmrX9Qu.js +1 -0
  407. package/dist/web-ui/_app/immutable/chunks/Xvwhx_F1.js +1 -0
  408. package/dist/web-ui/_app/immutable/chunks/Yyz1XMQA.js +1 -0
  409. package/dist/web-ui/_app/immutable/chunks/dh5HeqUr.js +1 -0
  410. package/dist/web-ui/_app/immutable/chunks/fZMteyca.js +62 -0
  411. package/dist/web-ui/_app/immutable/chunks/{D28BF5MJ.js → gPrj-hqC.js} +1 -1
  412. package/dist/web-ui/_app/immutable/chunks/htcWMiYN.js +1 -0
  413. package/dist/web-ui/_app/immutable/chunks/oTsvd9y4.js +1 -0
  414. package/dist/web-ui/_app/immutable/chunks/qJfLUwU4.js +1 -0
  415. package/dist/web-ui/_app/immutable/chunks/xCtiO_JE.js +1 -0
  416. package/dist/web-ui/_app/immutable/chunks/y4GeEH6k.js +1 -0
  417. package/dist/web-ui/_app/immutable/entry/app.C4h_eOn6.js +2 -0
  418. package/dist/web-ui/_app/immutable/entry/start.CQFTf9ep.js +1 -0
  419. package/dist/web-ui/_app/immutable/nodes/0.Dh1xO970.js +1 -0
  420. package/dist/web-ui/_app/immutable/nodes/1.l75D3Opx.js +1 -0
  421. package/dist/web-ui/_app/immutable/nodes/10.DBidBPc-.js +1 -0
  422. package/dist/web-ui/_app/immutable/nodes/11.Ab0gUKWe.js +1 -0
  423. package/dist/web-ui/_app/immutable/nodes/12.CMsnoxfs.js +1 -0
  424. package/dist/web-ui/_app/immutable/nodes/13.D8YKuknB.js +1 -0
  425. package/dist/web-ui/_app/immutable/nodes/14.DZ0aan7y.js +1 -0
  426. package/dist/web-ui/_app/immutable/nodes/15.CUIKreDL.js +2 -0
  427. package/dist/web-ui/_app/immutable/nodes/16.BWc8--BO.js +1 -0
  428. package/dist/web-ui/_app/immutable/nodes/2.CDUonbuh.js +1 -0
  429. package/dist/web-ui/_app/immutable/nodes/3.Ctg3M00i.js +1 -0
  430. package/dist/web-ui/_app/immutable/nodes/4.Ci-JDwbA.js +2 -0
  431. package/dist/web-ui/_app/immutable/nodes/5.CTyEDAq0.js +1 -0
  432. package/dist/web-ui/_app/immutable/nodes/6.BTZZqsAb.js +1 -0
  433. package/dist/web-ui/_app/immutable/nodes/7.BI52g_Jo.js +137 -0
  434. package/dist/web-ui/_app/immutable/nodes/8.3hZPaB9x.js +1 -0
  435. package/dist/web-ui/_app/immutable/nodes/9.DS49kvwl.js +29 -0
  436. package/dist/web-ui/_app/version.json +1 -1
  437. package/dist/web-ui/favicon-192.png +0 -0
  438. package/dist/web-ui/favicon-32.png +0 -0
  439. package/dist/web-ui/favicon.ico +0 -0
  440. package/dist/web-ui/index.html +14 -11
  441. package/package.json +14 -7
  442. package/plugin/.claude-plugin/marketplace.json +1 -1
  443. package/plugin/.claude-plugin/plugin.json +1 -1
  444. package/plugin/plugins/kspec/skills/merge/SKILL.md +127 -0
  445. package/plugin/plugins/kspec/skills/plan/SKILL.md +55 -26
  446. package/plugin/plugins/kspec/skills/review/SKILL.md +350 -133
  447. package/plugin/plugins/kspec/skills/task-work/SKILL.md +96 -106
  448. package/templates/agents-sections/04-pr-workflow.md +15 -12
  449. package/templates/agents-sections/06-ralph-loop.md +15 -10
  450. package/templates/skills/manifest.yaml +25 -7
  451. package/templates/skills/merge/SKILL.md +120 -0
  452. package/templates/skills/plan/SKILL.md +55 -26
  453. package/templates/skills/review/SKILL.md +346 -130
  454. package/templates/skills/task-work/SKILL.md +93 -103
  455. package/dist/web-ui/_app/immutable/assets/0.BxCxvrZR.css +0 -1
  456. package/dist/web-ui/_app/immutable/chunks/B-CZR0q8.js +0 -1
  457. package/dist/web-ui/_app/immutable/chunks/B1IR5Su5.js +0 -1
  458. package/dist/web-ui/_app/immutable/chunks/B_Cvvtc4.js +0 -1
  459. package/dist/web-ui/_app/immutable/chunks/BtFaGGII.js +0 -1
  460. package/dist/web-ui/_app/immutable/chunks/Bu8JVsCH.js +0 -1
  461. package/dist/web-ui/_app/immutable/chunks/C87u-CNA.js +0 -1
  462. package/dist/web-ui/_app/immutable/chunks/CrFkBTYp.js +0 -1
  463. package/dist/web-ui/_app/immutable/chunks/D6RtLpzL.js +0 -1
  464. package/dist/web-ui/_app/immutable/chunks/D7FHSgx2.js +0 -1
  465. package/dist/web-ui/_app/immutable/chunks/DBXrsxZQ.js +0 -2
  466. package/dist/web-ui/_app/immutable/chunks/Da_hHMuA.js +0 -1
  467. package/dist/web-ui/_app/immutable/chunks/Do6LchSF.js +0 -1
  468. package/dist/web-ui/_app/immutable/chunks/DoNPtcAw.js +0 -1
  469. package/dist/web-ui/_app/immutable/chunks/DtUbXRZz.js +0 -1
  470. package/dist/web-ui/_app/immutable/chunks/DyFPRlLl.js +0 -1
  471. package/dist/web-ui/_app/immutable/chunks/DzAP8lRM.js +0 -1
  472. package/dist/web-ui/_app/immutable/chunks/DzVXElzN.js +0 -2
  473. package/dist/web-ui/_app/immutable/chunks/aoPBFken.js +0 -1
  474. package/dist/web-ui/_app/immutable/chunks/laxtrUO3.js +0 -1
  475. package/dist/web-ui/_app/immutable/chunks/q1nIWgqB.js +0 -1
  476. package/dist/web-ui/_app/immutable/chunks/sTLbk5Nm.js +0 -1
  477. package/dist/web-ui/_app/immutable/chunks/vwKgQu5P.js +0 -5
  478. package/dist/web-ui/_app/immutable/entry/app.BCwMcqnT.js +0 -2
  479. package/dist/web-ui/_app/immutable/entry/start.wKCQH-tt.js +0 -1
  480. package/dist/web-ui/_app/immutable/nodes/0.CjGVMG74.js +0 -1
  481. package/dist/web-ui/_app/immutable/nodes/1.B6_AIPan.js +0 -1
  482. package/dist/web-ui/_app/immutable/nodes/2.q4oCS7Ws.js +0 -1
  483. package/dist/web-ui/_app/immutable/nodes/3.rTKZf9o2.js +0 -1
  484. package/dist/web-ui/_app/immutable/nodes/4.DVIDRu1d.js +0 -1
  485. package/dist/web-ui/_app/immutable/nodes/5.8PtPXIOd.js +0 -1
  486. package/dist/web-ui/_app/immutable/nodes/6.ZZrTemy_.js +0 -1
  487. package/dist/web-ui/_app/immutable/nodes/7.IP-gxCxi.js +0 -1
@@ -23,8 +23,10 @@ import * as os from "node:os";
23
23
  import * as path from "node:path";
24
24
  import * as readline from "node:readline/promises";
25
25
  import chalk from "chalk";
26
- import { getGitRoot, getShadowStatus, repairShadow, SHADOW_BRANCH_NAME, } from "../../parser/shadow.js";
26
+ import { getGitRoot, getShadowStatus, repairShadow, remoteShadowBranchExists, SHADOW_BRANCH_NAME, SHADOW_WORKTREE_DIR, SESSIONS_WORKTREE_DIR, ensureSessionsGitignore, ensureShadowSessionsGitignore, needsSessionsGitignore, needsShadowSessionsGitignore, } from "../../parser/shadow.js";
27
+ import { loadProjectConfig } from "../../parser/config.js";
27
28
  import { detectAgentFromEnv, } from "../../parser/agent-detection.js";
29
+ import { getSetupStatus as getSharedSetupStatus, } from "../../parser/setup-status.js";
28
30
  import { errors } from "../../strings/index.js";
29
31
  import { EXIT_CODES } from "../exit-codes.js";
30
32
  import { error, output, success, warn } from "../output.js";
@@ -45,6 +47,7 @@ function debugLog(message, detail) {
45
47
  const SETUP_AGENT_OVERRIDES = [
46
48
  "claude-code",
47
49
  "cline",
50
+ "droid",
48
51
  "cursor",
49
52
  "windsurf",
50
53
  "unknown",
@@ -65,6 +68,13 @@ function buildDetectedAgent(type) {
65
68
  configPath: path.join(os.homedir(), ".claude", "settings.json"),
66
69
  };
67
70
  }
71
+ if (type === "droid") {
72
+ return {
73
+ type,
74
+ confidence: "high",
75
+ configPath: path.join(os.homedir(), ".factory", "settings.json"),
76
+ };
77
+ }
68
78
  return { type, confidence: "high" };
69
79
  }
70
80
  /**
@@ -86,6 +96,13 @@ export function detectAgent() {
86
96
  configPath: path.join(os.homedir(), ".claude", "settings.json"),
87
97
  };
88
98
  }
99
+ if (existsSync(path.join(os.homedir(), ".factory"))) {
100
+ return {
101
+ type: "droid",
102
+ confidence: "low",
103
+ configPath: path.join(os.homedir(), ".factory", "settings.json"),
104
+ };
105
+ }
89
106
  return detected;
90
107
  }
91
108
  /**
@@ -137,8 +154,9 @@ const OLD_GUARD_SCRIPTS = [
137
154
  /**
138
155
  * Install hooks to project-level Claude Code settings (.claude/settings.json)
139
156
  * AC: @enhanced-setup ac-2 - all hook entries present
157
+ * AC: @project-config ac-hooks-section — respects per-hook enable/disable from config
140
158
  */
141
- async function installClaudeCodeHooks(projectDir, dryRun = false) {
159
+ async function installClaudeCodeHooks(projectDir, dryRun = false, hooksPrefs) {
142
160
  const configPath = path.join(projectDir, ".claude", "settings.json");
143
161
  const configDir = path.dirname(configPath);
144
162
  const hooksDir = path.join(projectDir, ".claude", "hooks");
@@ -165,48 +183,89 @@ async function installClaudeCodeHooks(projectDir, dryRun = false) {
165
183
  }
166
184
  // Get or create hooks object
167
185
  const hooks = config.hooks || {};
168
- // Install UserPromptSubmit hook (spec-first reminder)
186
+ // AC: @project-config ac-hooks-section — prompt-check independently controllable
187
+ // Default: enabled (lightweight spec-first reminder)
188
+ const promptCheckEnabled = hooksPrefs?.prompt_check ?? true;
169
189
  const promptCheckCommand = "kspec session prompt-check";
170
190
  const existingPromptHooks = hooks.UserPromptSubmit;
171
191
  const promptAlreadyInstalled = existingPromptHooks?.some((entry) => entry.hooks?.some((hook) => hook.command?.includes("session prompt-check")));
172
- if (!promptAlreadyInstalled) {
173
- hooks.UserPromptSubmit = [
174
- ...(existingPromptHooks || []),
175
- {
176
- hooks: [
177
- {
178
- type: "command",
179
- command: promptCheckCommand,
180
- },
181
- ],
182
- },
183
- ];
184
- result.promptCheck = true;
192
+ if (promptCheckEnabled) {
193
+ if (!promptAlreadyInstalled) {
194
+ hooks.UserPromptSubmit = [
195
+ ...(existingPromptHooks || []),
196
+ {
197
+ hooks: [
198
+ {
199
+ type: "command",
200
+ command: promptCheckCommand,
201
+ },
202
+ ],
203
+ },
204
+ ];
205
+ result.promptCheck = true;
206
+ }
207
+ else {
208
+ result.promptCheck = true; // Already configured
209
+ }
185
210
  }
186
211
  else {
187
- result.promptCheck = true; // Already configured
212
+ // AC: @project-config ac-hooks-section remove if disabled and previously installed
213
+ if (promptAlreadyInstalled) {
214
+ const filtered = (existingPromptHooks || []).map((entry) => ({
215
+ ...entry,
216
+ hooks: entry.hooks?.filter((hook) => !hook.command?.includes("session prompt-check")),
217
+ })).filter((entry) => entry.hooks && entry.hooks.length > 0);
218
+ if (filtered.length > 0) {
219
+ hooks.UserPromptSubmit = filtered;
220
+ }
221
+ else {
222
+ delete hooks.UserPromptSubmit;
223
+ }
224
+ }
225
+ result.promptCheck = false;
188
226
  }
189
- // Install Stop hook (checkpoint)
227
+ // AC: @project-config ac-hooks-section checkpoint independently controllable
228
+ // Default: disabled (dispatch handles task lifecycle)
229
+ const checkpointEnabled = hooksPrefs?.checkpoint ?? false;
190
230
  const stopHookCommand = "kspec session checkpoint --json";
191
231
  const existingStopHooks = hooks.Stop;
192
232
  const stopAlreadyInstalled = existingStopHooks?.some((entry) => entry.hooks?.some((hook) => hook.command?.includes("session checkpoint")));
193
- if (!stopAlreadyInstalled) {
194
- hooks.Stop = [
195
- ...(existingStopHooks || []),
196
- {
197
- matcher: "",
198
- hooks: [
199
- {
200
- type: "command",
201
- command: stopHookCommand,
202
- },
203
- ],
204
- },
205
- ];
206
- result.stop = true;
233
+ if (checkpointEnabled) {
234
+ // AC: @project-config ac-hooks-section install when enabled
235
+ if (!stopAlreadyInstalled) {
236
+ hooks.Stop = [
237
+ ...(existingStopHooks || []),
238
+ {
239
+ matcher: "",
240
+ hooks: [
241
+ {
242
+ type: "command",
243
+ command: stopHookCommand,
244
+ },
245
+ ],
246
+ },
247
+ ];
248
+ result.stop = true;
249
+ }
250
+ else {
251
+ result.stop = true; // Already configured
252
+ }
207
253
  }
208
254
  else {
209
- result.stop = true; // Already configured
255
+ // AC: @project-config ac-hooks-section remove if disabled and previously installed
256
+ if (stopAlreadyInstalled) {
257
+ const filtered = (existingStopHooks || []).map((entry) => ({
258
+ ...entry,
259
+ hooks: entry.hooks?.filter((hook) => !hook.command?.includes("session checkpoint")),
260
+ })).filter((entry) => entry.hooks && entry.hooks.length > 0);
261
+ if (filtered.length > 0) {
262
+ hooks.Stop = filtered;
263
+ }
264
+ else {
265
+ delete hooks.Stop;
266
+ }
267
+ }
268
+ result.stop = false;
210
269
  }
211
270
  // AC: @enhanced-setup ac-2 - Install PreToolUse hooks with guards
212
271
  // AC: @native-guard-commands ac-setup-native - use native kspec guard worktree
@@ -352,6 +411,8 @@ function getDefaultAuthor(agentType) {
352
411
  return "@gemini";
353
412
  case "codex-cli":
354
413
  return "@codex";
414
+ case "droid":
415
+ return "@droid";
355
416
  case "aider":
356
417
  return "@aider";
357
418
  case "opencode":
@@ -391,19 +452,30 @@ async function ensureWorktree(autoWorktree) {
391
452
  // Not in a git repo, skip worktree check
392
453
  return true;
393
454
  }
394
- const status = await getShadowStatus(projectRoot);
455
+ const { config } = await loadProjectConfig(projectRoot, projectRoot);
456
+ const shadowOptions = {
457
+ branchName: config.shadow.branch,
458
+ directory: config.shadow.directory,
459
+ remote: config.shadow.remote?.value,
460
+ remoteType: config.shadow.remote?.type,
461
+ };
462
+ const branchName = shadowOptions.branchName || SHADOW_BRANCH_NAME;
463
+ const worktreeDir = shadowOptions.directory || SHADOW_WORKTREE_DIR;
464
+ const status = await getShadowStatus(projectRoot, shadowOptions);
465
+ const remoteHasShadow = await remoteShadowBranchExists(projectRoot, shadowOptions);
466
+ const recoverableShadow = status.branchExists || remoteHasShadow;
395
467
  // AC: worktree-already-exists - if already valid, skip
396
468
  if (status.healthy) {
397
469
  return true;
398
470
  }
399
- // AC: detect-existing-repo - branch exists but worktree doesn't
400
- if (status.branchExists && !status.worktreeExists) {
471
+ // AC: detect-existing-repo - existing shadow state but missing/unhealthy worktree
472
+ if (recoverableShadow && (!status.worktreeExists || !status.worktreeLinked)) {
401
473
  // AC: auto-worktree-flag - auto-create if flag set
402
474
  if (autoWorktree) {
403
- console.log(`Detected ${SHADOW_BRANCH_NAME} branch without .kspec worktree. Creating...`);
404
- const result = await repairShadow(projectRoot);
475
+ console.log(`Detected ${branchName} shadow state without a healthy ${worktreeDir} worktree. Creating...`);
476
+ const result = await repairShadow(projectRoot, shadowOptions);
405
477
  if (result.success) {
406
- success("Created .kspec worktree");
478
+ success(`Created ${worktreeDir} worktree`);
407
479
  return true;
408
480
  }
409
481
  else {
@@ -412,12 +484,12 @@ async function ensureWorktree(autoWorktree) {
412
484
  }
413
485
  }
414
486
  // AC: detect-existing-repo - prompt user
415
- const shouldCreate = await promptYesNo(`${SHADOW_BRANCH_NAME} branch exists but .kspec worktree is missing. Create it? (y/N)`);
487
+ const shouldCreate = await promptYesNo(`${branchName} shadow state exists but ${worktreeDir} worktree is missing or unhealthy. Create it? (y/N)`);
416
488
  if (shouldCreate) {
417
- console.log("Creating .kspec worktree...");
418
- const result = await repairShadow(projectRoot);
489
+ console.log(`Creating ${worktreeDir} worktree...`);
490
+ const result = await repairShadow(projectRoot, shadowOptions);
419
491
  if (result.success) {
420
- success("Created .kspec worktree");
492
+ success(`Created ${worktreeDir} worktree`);
421
493
  return true;
422
494
  }
423
495
  else {
@@ -474,6 +546,13 @@ function printManualInstructions(agentType) {
474
546
  console.log(`set = { KSPEC_AUTHOR = "${author}" }`);
475
547
  console.log("```");
476
548
  break;
549
+ case "droid":
550
+ console.log("Add to .factory/settings.json:");
551
+ console.log("```json");
552
+ console.log(JSON.stringify({ env: { KSPEC_AUTHOR: author } }, null, 2));
553
+ console.log("```");
554
+ console.log("\nDroid reads project environment variables from the env section of .factory/settings.json.");
555
+ break;
477
556
  case "opencode":
478
557
  console.log("Add to ~/.config/opencode/opencode.json:");
479
558
  console.log("```json");
@@ -494,210 +573,6 @@ function printManualInstructions(agentType) {
494
573
  console.log("\nOr add to your shell profile (~/.bashrc, ~/.zshrc, etc.)");
495
574
  }
496
575
  }
497
- /**
498
- * Check the current setup status
499
- * AC: @enhanced-setup ac-7, ac-8
500
- */
501
- async function getSetupStatus(projectDir, agentOverride) {
502
- const detected = agentOverride
503
- ? buildDetectedAgent(agentOverride)
504
- : detectAgent();
505
- const configPath = path.join(projectDir, ".claude", "settings.json");
506
- const hooksDir = path.join(projectDir, ".claude", "hooks");
507
- const agentsMdPath = path.join(projectDir, "kspec-agents.md");
508
- const hashPath = path.join(projectDir, ".kspec", ".kspec-agents-hash");
509
- const skillsDir = path.join(projectDir, ".claude", "skills");
510
- // Check hooks
511
- const hooks = {
512
- promptCheck: false,
513
- stop: false,
514
- preToolUse: false,
515
- guardsPresent: [],
516
- };
517
- try {
518
- const configContent = await fs.readFile(configPath, "utf-8");
519
- const config = JSON.parse(configContent);
520
- const hooksConfig = config.hooks || {};
521
- // Check UserPromptSubmit
522
- const promptHooks = hooksConfig.UserPromptSubmit;
523
- hooks.promptCheck = promptHooks?.some((entry) => entry.hooks?.some((h) => h.command?.includes("prompt-check"))) ?? false;
524
- // Check Stop
525
- const stopHooks = hooksConfig.Stop;
526
- hooks.stop = stopHooks?.some((entry) => entry.hooks?.some((h) => h.command?.includes("checkpoint"))) ?? false;
527
- // Check PreToolUse — look for native kspec guard worktree command
528
- const preToolUseHooks = hooksConfig.PreToolUse;
529
- hooks.preToolUse = preToolUseHooks?.some((entry) => entry.hooks?.some((h) => h.command === NATIVE_GUARD_COMMAND || h.command?.includes(".claude/hooks/"))) ?? false;
530
- // Check for native guard command
531
- if (preToolUseHooks?.some((entry) => entry.hooks?.some((h) => h.command === NATIVE_GUARD_COMMAND))) {
532
- hooks.guardsPresent.push("kspec guard worktree");
533
- }
534
- // Check for legacy bash scripts still present
535
- if (preToolUseHooks?.some((entry) => entry.hooks?.some((h) => OLD_GUARD_SCRIPTS.some((name) => h.command?.includes(name))))) {
536
- hooks.guardsPresent.push("legacy:bash-scripts");
537
- }
538
- }
539
- catch (err) {
540
- debugLog("Failed to read hooks config for status", err);
541
- }
542
- // Check for legacy guard script files on disk
543
- try {
544
- const guardFiles = await fs.readdir(hooksDir);
545
- for (const name of OLD_GUARD_SCRIPTS) {
546
- if (guardFiles.includes(name)) {
547
- hooks.guardsPresent.push(`legacy-file:${name}`);
548
- }
549
- }
550
- }
551
- catch (err) {
552
- debugLog("Hooks dir doesn't exist", err);
553
- }
554
- // Check skills
555
- const skills = {
556
- total: 0,
557
- rendered: 0,
558
- drifted: 0,
559
- };
560
- // Helper to scan a directory for skill subdirs with kspec-managed SKILL.md
561
- async function scanForSkills(baseDir) {
562
- try {
563
- const dirs = await fs.readdir(baseDir, { withFileTypes: true });
564
- for (const dir of dirs) {
565
- if (dir.isDirectory()) {
566
- const skillMdPath = path.join(baseDir, dir.name, "SKILL.md");
567
- try {
568
- const content = await fs.readFile(skillMdPath, "utf-8");
569
- if (content.includes("<!-- kspec-managed -->")) {
570
- skills.total++;
571
- skills.rendered++;
572
- }
573
- }
574
- catch (_noSkillMd) {
575
- // No SKILL.md
576
- }
577
- }
578
- }
579
- }
580
- catch (_notReadable) {
581
- // Directory doesn't exist
582
- }
583
- }
584
- // Scan .claude/skills/ (project/local skills)
585
- await scanForSkills(skillsDir);
586
- // Check plugin marketplace health
587
- // AC: @enhanced-setup ac-7, ac-8
588
- const plugin = {
589
- marketplaceRegistered: false,
590
- marketplaceHealthy: false,
591
- pluginEnabled: false,
592
- };
593
- try {
594
- const { checkMarketplaceHealth } = await import("../../lib/claude-plugin-registry.js");
595
- const health = await checkMarketplaceHealth();
596
- plugin.marketplaceRegistered = health.status !== "missing";
597
- plugin.marketplaceHealthy = health.status === "healthy";
598
- plugin.registeredPath = health.registeredPath;
599
- plugin.healthMessage = health.message;
600
- }
601
- catch (err) {
602
- debugLog("Could not check marketplace health", err);
603
- plugin.healthMessage = "Health check unavailable";
604
- }
605
- // Check if plugin is enabled in project settings
606
- try {
607
- const configContent = await fs.readFile(configPath, "utf-8");
608
- const config = JSON.parse(configContent);
609
- plugin.pluginEnabled = config.enabledPlugins?.["kspec@kspec-plugins"] === true;
610
- }
611
- catch (err) {
612
- debugLog("Could not check plugin enablement", err);
613
- }
614
- // Check agents.md
615
- const agentsMd = {
616
- exists: false,
617
- status: "missing",
618
- };
619
- try {
620
- await fs.access(agentsMdPath);
621
- agentsMd.exists = true;
622
- try {
623
- const hashContent = await fs.readFile(hashPath, "utf-8");
624
- const hashData = JSON.parse(hashContent);
625
- agentsMd.generatedAt = hashData.generatedAt;
626
- // AC: @cross-platform-and-version-robustness ac-4
627
- // Compare stored hash against current meta to detect staleness
628
- try {
629
- const { initContext, loadMetaContext } = await import("../../parser/index.js");
630
- const { computeMetaHash, loadTemplateSections, getPackageRoot } = await import("./agents.js");
631
- const ctx = await initContext();
632
- if (ctx.manifestPath) {
633
- const metaCtx = await loadMetaContext(ctx);
634
- let templateSections = [];
635
- try {
636
- templateSections = await loadTemplateSections(getPackageRoot());
637
- }
638
- catch (err) {
639
- debugLog("Templates not available for staleness check", err);
640
- }
641
- const currentHash = computeMetaHash(metaCtx.skills, metaCtx.conventions, metaCtx.workflows, templateSections);
642
- agentsMd.status = hashData.metaHash === currentHash ? "current" : "stale";
643
- }
644
- else {
645
- // AC: @doctor-command ac-staleness-unknown — no manifest means we can't determine staleness
646
- agentsMd.status = "unknown";
647
- }
648
- }
649
- catch (err) {
650
- // AC: @doctor-command ac-staleness-unknown — hash computation failed
651
- debugLog("Could not compute meta hash for staleness check", err);
652
- agentsMd.status = "unknown";
653
- }
654
- }
655
- catch (err) {
656
- debugLog("Hash file missing or invalid, marking stale", err);
657
- agentsMd.status = "stale";
658
- }
659
- }
660
- catch (err) {
661
- debugLog("kspec-agents.md doesn't exist", err);
662
- }
663
- // Check seeding state
664
- const seeding = {
665
- permissionsSeeded: false,
666
- memorySeeded: false,
667
- };
668
- try {
669
- const configContent = await fs.readFile(path.join(projectDir, ".claude", "settings.json"), "utf-8");
670
- const config = JSON.parse(configContent);
671
- seeding.permissionsSeeded = !!config.permissions;
672
- }
673
- catch (err) {
674
- debugLog("Could not check permissions seeding state", err);
675
- }
676
- if (detected.type === "claude-code") {
677
- try {
678
- const { claudeCodeMemoryWriter } = await import("./setup-seeding.js");
679
- const memoryExists = await claudeCodeMemoryWriter.exists(projectDir);
680
- seeding.memorySeeded = memoryExists;
681
- if (memoryExists) {
682
- seeding.memoryPath = claudeCodeMemoryWriter.getMemoryPath(projectDir);
683
- }
684
- }
685
- catch (err) {
686
- debugLog("Could not check memory seeding state", err);
687
- }
688
- }
689
- return {
690
- agent: {
691
- detected: detected.type,
692
- confidence: detected.confidence,
693
- },
694
- hooks,
695
- skills,
696
- plugin,
697
- agentsMd,
698
- seeding,
699
- };
700
- }
701
576
  /**
702
577
  * Render skills using the platform renderer registry
703
578
  * AC: @setup-pipeline-unification ac-2 - uses getRenderer/getAllRenderers, not legacy renderClaudeCodeSkill
@@ -761,6 +636,12 @@ async function renderSkillsForSetup(projectDir, dryRun) {
761
636
  return { rendered: 0, skipped: 0, pluginProvided: 0, skillIds: [] };
762
637
  }
763
638
  }
639
+ function getHookInstallSkipMessage(agentType) {
640
+ if (agentType === "droid") {
641
+ return "droid hooks are not yet supported; skipping .factory/settings.json hook installation";
642
+ }
643
+ return `not applicable for ${agentType}`;
644
+ }
764
645
  /**
765
646
  * Ensure built-in worker and reviewer agent definitions exist in the project meta.
766
647
  *
@@ -1069,8 +950,15 @@ export async function runSetupPipeline(projectDir, options) {
1069
950
  }
1070
951
  // Step 3: Install hooks (Claude Code only)
1071
952
  // AC: @init-setup-integration ac-3 - hooks present
953
+ // AC: @project-config ac-hooks-section — read config to determine hook preferences
1072
954
  if (detected.type === "claude-code" && installHooksFlag) {
1073
- const hooksResult = await installClaudeCodeHooks(projectDir, dryRun);
955
+ // Load project config to get hooks preferences
956
+ const { config: projectConfig } = await loadProjectConfig(projectDir, projectDir);
957
+ const hooksPrefs = {
958
+ checkpoint: projectConfig.hooks.checkpoint,
959
+ prompt_check: projectConfig.hooks.prompt_check,
960
+ };
961
+ const hooksResult = await installClaudeCodeHooks(projectDir, dryRun, hooksPrefs);
1074
962
  const installedHooks = [];
1075
963
  if (hooksResult.promptCheck)
1076
964
  installedHooks.push("UserPromptSubmit");
@@ -1100,7 +988,7 @@ export async function runSetupPipeline(projectDir, options) {
1100
988
  steps.push({
1101
989
  name: "Install hooks",
1102
990
  status: "skipped",
1103
- message: `not applicable for ${detected.type}`,
991
+ message: getHookInstallSkipMessage(detected.type),
1104
992
  });
1105
993
  }
1106
994
  // Step 3a: Ensure artifacts directory exists
@@ -1123,6 +1011,108 @@ export async function runSetupPipeline(projectDir, options) {
1123
1011
  message: artifactsCreated ? "created .kspec/artifacts/" : "already exists",
1124
1012
  });
1125
1013
  }
1014
+ // Step 3a-ii: Ensure sessions directory and gitignore entries
1015
+ // AC: @session-storage-modes ac-gitignore, ac-sessions-dir-autocreate
1016
+ // AC: @session-legacy-migration ac-shadow-gitignore
1017
+ {
1018
+ const actions = [];
1019
+ // Create .kspec-sessions/ directory
1020
+ const sessionsDirPath = path.join(projectDir, SESSIONS_WORKTREE_DIR);
1021
+ let sessionsCreated = false;
1022
+ try {
1023
+ await fs.access(sessionsDirPath);
1024
+ }
1025
+ catch (_e) {
1026
+ if (!dryRun) {
1027
+ await fs.mkdir(sessionsDirPath, { recursive: true });
1028
+ }
1029
+ sessionsCreated = true;
1030
+ }
1031
+ if (sessionsCreated) {
1032
+ actions.push(`${dryRun ? "create" : "created"} ${SESSIONS_WORKTREE_DIR}/`);
1033
+ }
1034
+ // Add .kspec-sessions/ to root .gitignore
1035
+ if (dryRun) {
1036
+ const rootNeeded = await needsSessionsGitignore(projectDir);
1037
+ if (rootNeeded) {
1038
+ actions.push(`add ${SESSIONS_WORKTREE_DIR}/ to .gitignore`);
1039
+ }
1040
+ }
1041
+ else {
1042
+ const rootAdded = await ensureSessionsGitignore(projectDir);
1043
+ if (rootAdded) {
1044
+ actions.push(`added ${SESSIONS_WORKTREE_DIR}/ to .gitignore`);
1045
+ }
1046
+ }
1047
+ // Add sessions/ to .kspec/.gitignore
1048
+ if (dryRun) {
1049
+ const shadowNeeded = await needsShadowSessionsGitignore(projectDir);
1050
+ if (shadowNeeded) {
1051
+ actions.push("add sessions/ to .kspec/.gitignore");
1052
+ }
1053
+ }
1054
+ else {
1055
+ const shadowAdded = await ensureShadowSessionsGitignore(projectDir);
1056
+ if (shadowAdded) {
1057
+ actions.push("added sessions/ to .kspec/.gitignore");
1058
+ }
1059
+ }
1060
+ steps.push({
1061
+ name: "Ensure sessions directory",
1062
+ status: actions.length > 0 ? "done" : "skipped",
1063
+ message: actions.length > 0 ? actions.join(", ") : "already configured",
1064
+ });
1065
+ }
1066
+ // Step 3a-iii: Initialize session branch worktree if sessions.storage is "branch"
1067
+ // AC: @session-branch-worktree ac-init
1068
+ {
1069
+ try {
1070
+ const { initContext } = await import("../../parser/index.js");
1071
+ const ctx = await initContext();
1072
+ const sessionStorage = ctx.manifest?.sessions?.storage;
1073
+ if (sessionStorage === "branch") {
1074
+ const { initializeSessionBranch, getSessionBranchStatus } = await import("../../parser/session-branch.js");
1075
+ const sessionBranchName = ctx.manifest?.sessions?.branch || "kspec-sessions";
1076
+ const sessionStatus = await getSessionBranchStatus(projectDir, sessionBranchName);
1077
+ if (sessionStatus.healthy) {
1078
+ steps.push({
1079
+ name: "Session branch worktree",
1080
+ status: "skipped",
1081
+ message: "already initialized",
1082
+ });
1083
+ }
1084
+ else if (dryRun) {
1085
+ steps.push({
1086
+ name: "Session branch worktree",
1087
+ status: "done",
1088
+ message: `create orphan branch "${sessionBranchName}" with worktree at ${SESSIONS_WORKTREE_DIR}/`,
1089
+ });
1090
+ }
1091
+ else {
1092
+ const sessionResult = await initializeSessionBranch(projectDir, sessionBranchName);
1093
+ if (sessionResult.success) {
1094
+ steps.push({
1095
+ name: "Session branch worktree",
1096
+ status: "done",
1097
+ message: sessionResult.alreadyExists
1098
+ ? "already initialized"
1099
+ : `created branch "${sessionBranchName}" with worktree at ${SESSIONS_WORKTREE_DIR}/`,
1100
+ });
1101
+ }
1102
+ else {
1103
+ steps.push({
1104
+ name: "Session branch worktree",
1105
+ status: "failed",
1106
+ message: sessionResult.error || "unknown error",
1107
+ });
1108
+ }
1109
+ }
1110
+ }
1111
+ }
1112
+ catch {
1113
+ // Session branch init is optional — don't block setup
1114
+ }
1115
+ }
1126
1116
  // Step 3b: Seed permissions (Claude Code only)
1127
1117
  // AC: @new-project-bootstrapping ac-1
1128
1118
  {
@@ -1252,6 +1242,9 @@ export async function runSetupPipeline(projectDir, options) {
1252
1242
  authorInstalled = true;
1253
1243
  }
1254
1244
  break;
1245
+ case "droid":
1246
+ authorInstalled = false;
1247
+ break;
1255
1248
  case "aider":
1256
1249
  if (!dryRun) {
1257
1250
  authorInstalled = await installAiderConfig(author);
@@ -1270,6 +1263,21 @@ export async function runSetupPipeline(projectDir, options) {
1270
1263
  message: `KSPEC_AUTHOR="${author}"`,
1271
1264
  });
1272
1265
  }
1266
+ else if (detected.type === "droid") {
1267
+ steps.push({
1268
+ name: "Configure author",
1269
+ status: "skipped",
1270
+ message: "add KSPEC_AUTHOR to the .factory/settings.json env section",
1271
+ });
1272
+ }
1273
+ else if (detected.type === "unknown") {
1274
+ // AC: @cmd-setup ac-1 - show manual instructions for unknown agents
1275
+ steps.push({
1276
+ name: "Configure author",
1277
+ status: "skipped",
1278
+ message: `no auto-config for unknown agent — set KSPEC_AUTHOR manually`,
1279
+ });
1280
+ }
1273
1281
  }
1274
1282
  }
1275
1283
  // Output summary
@@ -1326,7 +1334,7 @@ export function registerSetupCommand(program) {
1326
1334
  program
1327
1335
  .command("setup")
1328
1336
  .description("Configure agent environment for kspec (orchestrated pipeline)")
1329
- .option("--agent <type>", "Explicit agent type override (claude-code|cline|cursor|windsurf|unknown)")
1337
+ .option("--agent <type>", "Explicit agent type override (claude-code|cline|droid|cursor|windsurf|unknown)")
1330
1338
  .option("--dry-run", "Show what would be done without making changes")
1331
1339
  .option("--author <author>", "Custom author string (default: auto-detected based on agent)")
1332
1340
  .option("--no-hooks", "Skip installing hooks")
@@ -1342,18 +1350,34 @@ export function registerSetupCommand(program) {
1342
1350
  : undefined;
1343
1351
  // AC: @enhanced-setup ac-7, ac-8 - --status mode
1344
1352
  if (options.status) {
1345
- const status = await getSetupStatus(projectDir, agentOverride);
1353
+ const status = await getSharedSetupStatus(projectDir, {
1354
+ agentOverride,
1355
+ });
1346
1356
  output(status, () => {
1347
1357
  console.log(chalk.bold("kspec Setup Status\n"));
1348
1358
  // Agent detection
1349
1359
  console.log(chalk.gray("Agent:"));
1350
1360
  console.log(` Detected: ${status.agent.detected} (${status.agent.confidence} confidence)`);
1361
+ if (status.agent.configPath) {
1362
+ console.log(` Config: ${status.agent.configPath}`);
1363
+ }
1351
1364
  console.log();
1352
1365
  // Hooks status
1353
1366
  console.log(chalk.gray("Hooks:"));
1354
- console.log(` UserPromptSubmit: ${status.hooks.promptCheck ? chalk.green("✓") : chalk.red("✗")}`);
1355
- console.log(` Stop: ${status.hooks.stop ? chalk.green("✓") : chalk.red("✗")}`);
1356
- console.log(` PreToolUse: ${status.hooks.preToolUse ? chalk.green("✓") : chalk.red("✗")}`);
1367
+ if (status.hooks.supported) {
1368
+ console.log(` UserPromptSubmit: ${status.hooks.promptCheck ? chalk.green("✓") : chalk.red("✗")}`);
1369
+ console.log(` Stop: ${status.hooks.stop ? chalk.green("✓") : chalk.red("✗")}`);
1370
+ console.log(` PreToolUse: ${status.hooks.preToolUse ? chalk.green("✓") : chalk.red("✗")}`);
1371
+ }
1372
+ else {
1373
+ const unsupported = chalk.yellow("unsupported");
1374
+ console.log(` UserPromptSubmit: ${unsupported}`);
1375
+ console.log(` Stop: ${unsupported}`);
1376
+ console.log(` PreToolUse: ${unsupported}`);
1377
+ if (status.agent.detected === "droid") {
1378
+ console.log(" Note: droid hooks are not yet supported");
1379
+ }
1380
+ }
1357
1381
  if (status.hooks.guardsPresent.length > 0) {
1358
1382
  console.log(` Guards: ${status.hooks.guardsPresent.join(", ")}`);
1359
1383
  }
@@ -1419,10 +1443,9 @@ export function registerSetupCommand(program) {
1419
1443
  ? buildDetectedAgent(agentOverride)
1420
1444
  : detectAgent();
1421
1445
  const dryRun = options.dryRun || false;
1446
+ // AC: @cmd-setup ac-1 - proceed with setup even when no agent is detected
1422
1447
  if (detected.type === "unknown") {
1423
- warn("Could not auto-detect agent environment");
1424
- printManualInstructions("unknown");
1425
- return;
1448
+ warn("Could not auto-detect agent environment — proceeding with core setup steps");
1426
1449
  }
1427
1450
  // AC: @setup-pipeline-unification ac-3 - delegate to runSetupPipeline()
1428
1451
  // One code path for both 'kspec setup' and 'kspec init --setup'
@@ -1478,6 +1501,13 @@ export function registerSetupCommand(program) {
1478
1501
  console.log(chalk.green("Setup complete."));
1479
1502
  console.log(chalk.gray("Restart your agent session for changes to take effect."));
1480
1503
  }
1504
+ const configureAuthorStep = result.steps.find((step) => step.name === "Configure author");
1505
+ const needsManualInstructions = configureAuthorStep?.status === "skipped" &&
1506
+ !configureAuthorStep.message?.includes("already set") &&
1507
+ (detected.type === "unknown" || detected.type === "droid");
1508
+ if (needsManualInstructions) {
1509
+ printManualInstructions(detected.type);
1510
+ }
1481
1511
  });
1482
1512
  }
1483
1513
  catch (err) {