@kindgi/cli 0.0.0-bootstrap.0 → 0.1.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 (516) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +738 -1
  3. package/dist/build/apt.d.ts +16 -0
  4. package/dist/build/apt.d.ts.map +1 -0
  5. package/dist/build/apt.js +50 -0
  6. package/dist/build/apt.js.map +1 -0
  7. package/dist/build/bundle.d.ts +48 -0
  8. package/dist/build/bundle.d.ts.map +1 -0
  9. package/dist/build/bundle.js +125 -0
  10. package/dist/build/bundle.js.map +1 -0
  11. package/dist/build/containerfile.d.ts +27 -0
  12. package/dist/build/containerfile.d.ts.map +1 -0
  13. package/dist/build/containerfile.js +197 -0
  14. package/dist/build/containerfile.js.map +1 -0
  15. package/dist/build/context-files.d.ts +24 -0
  16. package/dist/build/context-files.d.ts.map +1 -0
  17. package/dist/build/context-files.js +99 -0
  18. package/dist/build/context-files.js.map +1 -0
  19. package/dist/build/defaults.d.ts +66 -0
  20. package/dist/build/defaults.d.ts.map +1 -0
  21. package/dist/build/defaults.js +597 -0
  22. package/dist/build/defaults.js.map +1 -0
  23. package/dist/build/envelope.d.ts +72 -0
  24. package/dist/build/envelope.d.ts.map +1 -0
  25. package/dist/build/envelope.js +76 -0
  26. package/dist/build/envelope.js.map +1 -0
  27. package/dist/build/host-install.d.ts +100 -0
  28. package/dist/build/host-install.d.ts.map +1 -0
  29. package/dist/build/host-install.js +443 -0
  30. package/dist/build/host-install.js.map +1 -0
  31. package/dist/build/image-config.d.ts +32 -0
  32. package/dist/build/image-config.d.ts.map +1 -0
  33. package/dist/build/image-config.js +129 -0
  34. package/dist/build/image-config.js.map +1 -0
  35. package/dist/build/integrity.d.ts +51 -0
  36. package/dist/build/integrity.d.ts.map +1 -0
  37. package/dist/build/integrity.js +75 -0
  38. package/dist/build/integrity.js.map +1 -0
  39. package/dist/build/node-image.d.ts +18 -0
  40. package/dist/build/node-image.d.ts.map +1 -0
  41. package/dist/build/node-image.js +46 -0
  42. package/dist/build/node-image.js.map +1 -0
  43. package/dist/build/pack-root.d.ts +69 -0
  44. package/dist/build/pack-root.d.ts.map +1 -0
  45. package/dist/build/pack-root.js +102 -0
  46. package/dist/build/pack-root.js.map +1 -0
  47. package/dist/build/poetry-requirements.d.ts +5 -0
  48. package/dist/build/poetry-requirements.d.ts.map +1 -0
  49. package/dist/build/poetry-requirements.js +8 -0
  50. package/dist/build/poetry-requirements.js.map +1 -0
  51. package/dist/build/python-image.d.ts +40 -0
  52. package/dist/build/python-image.d.ts.map +1 -0
  53. package/dist/build/python-image.js +197 -0
  54. package/dist/build/python-image.js.map +1 -0
  55. package/dist/build/runners.d.ts +259 -0
  56. package/dist/build/runners.d.ts.map +1 -0
  57. package/dist/build/runners.js +4 -0
  58. package/dist/build/runners.js.map +1 -0
  59. package/dist/build/version-specifier.d.ts +2 -0
  60. package/dist/build/version-specifier.d.ts.map +1 -0
  61. package/dist/build/version-specifier.js +70 -0
  62. package/dist/build/version-specifier.js.map +1 -0
  63. package/dist/cli-package.d.ts +15 -0
  64. package/dist/cli-package.d.ts.map +1 -0
  65. package/dist/cli-package.js +37 -0
  66. package/dist/cli-package.js.map +1 -0
  67. package/dist/cli.d.ts +3 -0
  68. package/dist/cli.d.ts.map +1 -0
  69. package/dist/cli.js +26 -0
  70. package/dist/cli.js.map +1 -0
  71. package/dist/commands/adapters.d.ts +3 -0
  72. package/dist/commands/adapters.d.ts.map +1 -0
  73. package/dist/commands/adapters.js +148 -0
  74. package/dist/commands/adapters.js.map +1 -0
  75. package/dist/commands/agents.d.ts +3 -0
  76. package/dist/commands/agents.d.ts.map +1 -0
  77. package/dist/commands/agents.js +82 -0
  78. package/dist/commands/agents.js.map +1 -0
  79. package/dist/commands/approvals.d.ts +3 -0
  80. package/dist/commands/approvals.d.ts.map +1 -0
  81. package/dist/commands/approvals.js +92 -0
  82. package/dist/commands/approvals.js.map +1 -0
  83. package/dist/commands/artifacts.d.ts +3 -0
  84. package/dist/commands/artifacts.d.ts.map +1 -0
  85. package/dist/commands/artifacts.js +87 -0
  86. package/dist/commands/artifacts.js.map +1 -0
  87. package/dist/commands/auth.d.ts +25 -0
  88. package/dist/commands/auth.d.ts.map +1 -0
  89. package/dist/commands/auth.js +283 -0
  90. package/dist/commands/auth.js.map +1 -0
  91. package/dist/commands/build.d.ts +46 -0
  92. package/dist/commands/build.d.ts.map +1 -0
  93. package/dist/commands/build.js +902 -0
  94. package/dist/commands/build.js.map +1 -0
  95. package/dist/commands/capabilities.d.ts +3 -0
  96. package/dist/commands/capabilities.d.ts.map +1 -0
  97. package/dist/commands/capabilities.js +38 -0
  98. package/dist/commands/capabilities.js.map +1 -0
  99. package/dist/commands/conversations.d.ts +3 -0
  100. package/dist/commands/conversations.d.ts.map +1 -0
  101. package/dist/commands/conversations.js +75 -0
  102. package/dist/commands/conversations.js.map +1 -0
  103. package/dist/commands/deploy.d.ts +7 -0
  104. package/dist/commands/deploy.d.ts.map +1 -0
  105. package/dist/commands/deploy.js +697 -0
  106. package/dist/commands/deploy.js.map +1 -0
  107. package/dist/commands/dev.d.ts +43 -0
  108. package/dist/commands/dev.d.ts.map +1 -0
  109. package/dist/commands/dev.js +1110 -0
  110. package/dist/commands/dev.js.map +1 -0
  111. package/dist/commands/env.d.ts +27 -0
  112. package/dist/commands/env.d.ts.map +1 -0
  113. package/dist/commands/env.js +816 -0
  114. package/dist/commands/env.js.map +1 -0
  115. package/dist/commands/feedback.d.ts +33 -0
  116. package/dist/commands/feedback.d.ts.map +1 -0
  117. package/dist/commands/feedback.js +374 -0
  118. package/dist/commands/feedback.js.map +1 -0
  119. package/dist/commands/flows.d.ts +3 -0
  120. package/dist/commands/flows.d.ts.map +1 -0
  121. package/dist/commands/flows.js +60 -0
  122. package/dist/commands/flows.js.map +1 -0
  123. package/dist/commands/guardrails.d.ts +3 -0
  124. package/dist/commands/guardrails.d.ts.map +1 -0
  125. package/dist/commands/guardrails.js +89 -0
  126. package/dist/commands/guardrails.js.map +1 -0
  127. package/dist/commands/health.d.ts +8 -0
  128. package/dist/commands/health.d.ts.map +1 -0
  129. package/dist/commands/health.js +40 -0
  130. package/dist/commands/health.js.map +1 -0
  131. package/dist/commands/helpers.d.ts +48 -0
  132. package/dist/commands/helpers.d.ts.map +1 -0
  133. package/dist/commands/helpers.js +110 -0
  134. package/dist/commands/helpers.js.map +1 -0
  135. package/dist/commands/index.d.ts +7 -0
  136. package/dist/commands/index.d.ts.map +1 -0
  137. package/dist/commands/index.js +90 -0
  138. package/dist/commands/index.js.map +1 -0
  139. package/dist/commands/init.d.ts +46 -0
  140. package/dist/commands/init.d.ts.map +1 -0
  141. package/dist/commands/init.js +454 -0
  142. package/dist/commands/init.js.map +1 -0
  143. package/dist/commands/key.d.ts +3 -0
  144. package/dist/commands/key.d.ts.map +1 -0
  145. package/dist/commands/key.js +322 -0
  146. package/dist/commands/key.js.map +1 -0
  147. package/dist/commands/mcp.d.ts +43 -0
  148. package/dist/commands/mcp.d.ts.map +1 -0
  149. package/dist/commands/mcp.js +433 -0
  150. package/dist/commands/mcp.js.map +1 -0
  151. package/dist/commands/memory.d.ts +3 -0
  152. package/dist/commands/memory.d.ts.map +1 -0
  153. package/dist/commands/memory.js +82 -0
  154. package/dist/commands/memory.js.map +1 -0
  155. package/dist/commands/observations.d.ts +3 -0
  156. package/dist/commands/observations.d.ts.map +1 -0
  157. package/dist/commands/observations.js +27 -0
  158. package/dist/commands/observations.js.map +1 -0
  159. package/dist/commands/proposals.d.ts +3 -0
  160. package/dist/commands/proposals.d.ts.map +1 -0
  161. package/dist/commands/proposals.js +116 -0
  162. package/dist/commands/proposals.js.map +1 -0
  163. package/dist/commands/provenance.d.ts +3 -0
  164. package/dist/commands/provenance.d.ts.map +1 -0
  165. package/dist/commands/provenance.js +53 -0
  166. package/dist/commands/provenance.js.map +1 -0
  167. package/dist/commands/providers.d.ts +3 -0
  168. package/dist/commands/providers.d.ts.map +1 -0
  169. package/dist/commands/providers.js +212 -0
  170. package/dist/commands/providers.js.map +1 -0
  171. package/dist/commands/reviewers.d.ts +3 -0
  172. package/dist/commands/reviewers.d.ts.map +1 -0
  173. package/dist/commands/reviewers.js +78 -0
  174. package/dist/commands/reviewers.js.map +1 -0
  175. package/dist/commands/runs.d.ts +3 -0
  176. package/dist/commands/runs.d.ts.map +1 -0
  177. package/dist/commands/runs.js +223 -0
  178. package/dist/commands/runs.js.map +1 -0
  179. package/dist/commands/secrets.d.ts +18 -0
  180. package/dist/commands/secrets.d.ts.map +1 -0
  181. package/dist/commands/secrets.js +702 -0
  182. package/dist/commands/secrets.js.map +1 -0
  183. package/dist/commands/skills.d.ts +64 -0
  184. package/dist/commands/skills.d.ts.map +1 -0
  185. package/dist/commands/skills.js +430 -0
  186. package/dist/commands/skills.js.map +1 -0
  187. package/dist/commands/test.d.ts +5 -0
  188. package/dist/commands/test.d.ts.map +1 -0
  189. package/dist/commands/test.js +181 -0
  190. package/dist/commands/test.js.map +1 -0
  191. package/dist/commands/tokens.d.ts +3 -0
  192. package/dist/commands/tokens.d.ts.map +1 -0
  193. package/dist/commands/tokens.js +33 -0
  194. package/dist/commands/tokens.js.map +1 -0
  195. package/dist/commands/tools.d.ts +3 -0
  196. package/dist/commands/tools.d.ts.map +1 -0
  197. package/dist/commands/tools.js +162 -0
  198. package/dist/commands/tools.js.map +1 -0
  199. package/dist/commands/types.d.ts +54 -0
  200. package/dist/commands/types.d.ts.map +1 -0
  201. package/dist/commands/types.js +4 -0
  202. package/dist/commands/types.js.map +1 -0
  203. package/dist/commands/unwired.d.ts +22 -0
  204. package/dist/commands/unwired.d.ts.map +1 -0
  205. package/dist/commands/unwired.js +52 -0
  206. package/dist/commands/unwired.js.map +1 -0
  207. package/dist/commands/version.d.ts +8 -0
  208. package/dist/commands/version.d.ts.map +1 -0
  209. package/dist/commands/version.js +41 -0
  210. package/dist/commands/version.js.map +1 -0
  211. package/dist/config.d.ts +42 -0
  212. package/dist/config.d.ts.map +1 -0
  213. package/dist/config.js +83 -0
  214. package/dist/config.js.map +1 -0
  215. package/dist/context.d.ts +162 -0
  216. package/dist/context.d.ts.map +1 -0
  217. package/dist/context.js +45 -0
  218. package/dist/context.js.map +1 -0
  219. package/dist/deploy/defaults.d.ts +14 -0
  220. package/dist/deploy/defaults.d.ts.map +1 -0
  221. package/dist/deploy/defaults.js +37 -0
  222. package/dist/deploy/defaults.js.map +1 -0
  223. package/dist/deploy/envelope-loader.d.ts +24 -0
  224. package/dist/deploy/envelope-loader.d.ts.map +1 -0
  225. package/dist/deploy/envelope-loader.js +141 -0
  226. package/dist/deploy/envelope-loader.js.map +1 -0
  227. package/dist/deploy/post.d.ts +48 -0
  228. package/dist/deploy/post.d.ts.map +1 -0
  229. package/dist/deploy/post.js +210 -0
  230. package/dist/deploy/post.js.map +1 -0
  231. package/dist/deploy/response.d.ts +42 -0
  232. package/dist/deploy/response.d.ts.map +1 -0
  233. package/dist/deploy/response.js +128 -0
  234. package/dist/deploy/response.js.map +1 -0
  235. package/dist/deploy/runners.d.ts +218 -0
  236. package/dist/deploy/runners.d.ts.map +1 -0
  237. package/dist/deploy/runners.js +4 -0
  238. package/dist/deploy/runners.js.map +1 -0
  239. package/dist/dev/bundler.d.ts +10 -0
  240. package/dist/dev/bundler.d.ts.map +1 -0
  241. package/dist/dev/bundler.js +235 -0
  242. package/dist/dev/bundler.js.map +1 -0
  243. package/dist/dev/defaults.d.ts +140 -0
  244. package/dist/dev/defaults.d.ts.map +1 -0
  245. package/dist/dev/defaults.js +709 -0
  246. package/dist/dev/defaults.js.map +1 -0
  247. package/dist/dev/dev-only-imports.d.ts +15 -0
  248. package/dist/dev/dev-only-imports.d.ts.map +1 -0
  249. package/dist/dev/dev-only-imports.js +57 -0
  250. package/dist/dev/dev-only-imports.js.map +1 -0
  251. package/dist/dev/docker-compose.dev.yml +68 -0
  252. package/dist/dev/index-child.d.ts +2 -0
  253. package/dist/dev/index-child.d.ts.map +1 -0
  254. package/dist/dev/index-child.js +53 -0
  255. package/dist/dev/index-child.js.map +1 -0
  256. package/dist/dev/pack-code.d.ts +36 -0
  257. package/dist/dev/pack-code.d.ts.map +1 -0
  258. package/dist/dev/pack-code.js +129 -0
  259. package/dist/dev/pack-code.js.map +1 -0
  260. package/dist/dev/pack-env.d.ts +13 -0
  261. package/dist/dev/pack-env.d.ts.map +1 -0
  262. package/dist/dev/pack-env.js +36 -0
  263. package/dist/dev/pack-env.js.map +1 -0
  264. package/dist/dev/pack-service.d.ts +40 -0
  265. package/dist/dev/pack-service.d.ts.map +1 -0
  266. package/dist/dev/pack-service.js +189 -0
  267. package/dist/dev/pack-service.js.map +1 -0
  268. package/dist/dev/paths.d.ts +22 -0
  269. package/dist/dev/paths.d.ts.map +1 -0
  270. package/dist/dev/paths.js +35 -0
  271. package/dist/dev/paths.js.map +1 -0
  272. package/dist/dev/postgres-container.d.ts +77 -0
  273. package/dist/dev/postgres-container.d.ts.map +1 -0
  274. package/dist/dev/postgres-container.js +346 -0
  275. package/dist/dev/postgres-container.js.map +1 -0
  276. package/dist/dev/python-builder.d.ts +16 -0
  277. package/dist/dev/python-builder.d.ts.map +1 -0
  278. package/dist/dev/python-builder.js +122 -0
  279. package/dist/dev/python-builder.js.map +1 -0
  280. package/dist/dev/register.d.ts +71 -0
  281. package/dist/dev/register.d.ts.map +1 -0
  282. package/dist/dev/register.js +54 -0
  283. package/dist/dev/register.js.map +1 -0
  284. package/dist/dev/runners.d.ts +312 -0
  285. package/dist/dev/runners.d.ts.map +1 -0
  286. package/dist/dev/runners.js +4 -0
  287. package/dist/dev/runners.js.map +1 -0
  288. package/dist/dev/runtime-container.d.ts +71 -0
  289. package/dist/dev/runtime-container.d.ts.map +1 -0
  290. package/dist/dev/runtime-container.js +173 -0
  291. package/dist/dev/runtime-container.js.map +1 -0
  292. package/dist/dev/runtime-env.d.ts +62 -0
  293. package/dist/dev/runtime-env.d.ts.map +1 -0
  294. package/dist/dev/runtime-env.js +100 -0
  295. package/dist/dev/runtime-env.js.map +1 -0
  296. package/dist/dev/runtime-image.d.ts +26 -0
  297. package/dist/dev/runtime-image.d.ts.map +1 -0
  298. package/dist/dev/runtime-image.js +44 -0
  299. package/dist/dev/runtime-image.js.map +1 -0
  300. package/dist/dev/runtime-registry.d.ts +73 -0
  301. package/dist/dev/runtime-registry.d.ts.map +1 -0
  302. package/dist/dev/runtime-registry.js +111 -0
  303. package/dist/dev/runtime-registry.js.map +1 -0
  304. package/dist/env/defaults.d.ts +3 -0
  305. package/dist/env/defaults.d.ts.map +1 -0
  306. package/dist/env/defaults.js +22 -0
  307. package/dist/env/defaults.js.map +1 -0
  308. package/dist/env/pack-env-plan.d.ts +70 -0
  309. package/dist/env/pack-env-plan.d.ts.map +1 -0
  310. package/dist/env/pack-env-plan.js +236 -0
  311. package/dist/env/pack-env-plan.js.map +1 -0
  312. package/dist/env/parser.d.ts +9 -0
  313. package/dist/env/parser.d.ts.map +1 -0
  314. package/dist/env/parser.js +11 -0
  315. package/dist/env/parser.js.map +1 -0
  316. package/dist/env/project-env.d.ts +34 -0
  317. package/dist/env/project-env.d.ts.map +1 -0
  318. package/dist/env/project-env.js +45 -0
  319. package/dist/env/project-env.js.map +1 -0
  320. package/dist/env/runners.d.ts +22 -0
  321. package/dist/env/runners.d.ts.map +1 -0
  322. package/dist/env/runners.js +4 -0
  323. package/dist/env/runners.js.map +1 -0
  324. package/dist/env/writer.d.ts +7 -0
  325. package/dist/env/writer.d.ts.map +1 -0
  326. package/dist/env/writer.js +9 -0
  327. package/dist/env/writer.js.map +1 -0
  328. package/dist/errors.d.ts +31 -0
  329. package/dist/errors.d.ts.map +1 -0
  330. package/dist/errors.js +111 -0
  331. package/dist/errors.js.map +1 -0
  332. package/dist/help.d.ts +5 -0
  333. package/dist/help.d.ts.map +1 -0
  334. package/dist/help.js +61 -0
  335. package/dist/help.js.map +1 -0
  336. package/dist/index.d.ts +13 -0
  337. package/dist/index.d.ts.map +1 -0
  338. package/dist/index.js +13 -0
  339. package/dist/index.js.map +1 -0
  340. package/dist/init/augment-scaffolder.d.ts +86 -0
  341. package/dist/init/augment-scaffolder.d.ts.map +1 -0
  342. package/dist/init/augment-scaffolder.js +538 -0
  343. package/dist/init/augment-scaffolder.js.map +1 -0
  344. package/dist/init/dependency-specs.d.ts +58 -0
  345. package/dist/init/dependency-specs.d.ts.map +1 -0
  346. package/dist/init/dependency-specs.js +153 -0
  347. package/dist/init/dependency-specs.js.map +1 -0
  348. package/dist/init/gitignore-patcher.d.ts +23 -0
  349. package/dist/init/gitignore-patcher.d.ts.map +1 -0
  350. package/dist/init/gitignore-patcher.js +103 -0
  351. package/dist/init/gitignore-patcher.js.map +1 -0
  352. package/dist/init/mode-detect.d.ts +34 -0
  353. package/dist/init/mode-detect.d.ts.map +1 -0
  354. package/dist/init/mode-detect.js +115 -0
  355. package/dist/init/mode-detect.js.map +1 -0
  356. package/dist/init/package-json-patcher.d.ts +36 -0
  357. package/dist/init/package-json-patcher.d.ts.map +1 -0
  358. package/dist/init/package-json-patcher.js +128 -0
  359. package/dist/init/package-json-patcher.js.map +1 -0
  360. package/dist/init/pnpm-workspace-patcher.d.ts +55 -0
  361. package/dist/init/pnpm-workspace-patcher.d.ts.map +1 -0
  362. package/dist/init/pnpm-workspace-patcher.js +248 -0
  363. package/dist/init/pnpm-workspace-patcher.js.map +1 -0
  364. package/dist/init/pyproject-patcher.d.ts +56 -0
  365. package/dist/init/pyproject-patcher.d.ts.map +1 -0
  366. package/dist/init/pyproject-patcher.js +324 -0
  367. package/dist/init/pyproject-patcher.js.map +1 -0
  368. package/dist/init/python-augment.d.ts +22 -0
  369. package/dist/init/python-augment.d.ts.map +1 -0
  370. package/dist/init/python-augment.js +300 -0
  371. package/dist/init/python-augment.js.map +1 -0
  372. package/dist/init/template-files.d.ts +18 -0
  373. package/dist/init/template-files.d.ts.map +1 -0
  374. package/dist/init/template-files.js +53 -0
  375. package/dist/init/template-files.js.map +1 -0
  376. package/dist/key/defaults.d.ts +3 -0
  377. package/dist/key/defaults.d.ts.map +1 -0
  378. package/dist/key/defaults.js +60 -0
  379. package/dist/key/defaults.js.map +1 -0
  380. package/dist/key/fingerprint.d.ts +6 -0
  381. package/dist/key/fingerprint.d.ts.map +1 -0
  382. package/dist/key/fingerprint.js +25 -0
  383. package/dist/key/fingerprint.js.map +1 -0
  384. package/dist/key/paths.d.ts +30 -0
  385. package/dist/key/paths.d.ts.map +1 -0
  386. package/dist/key/paths.js +51 -0
  387. package/dist/key/paths.js.map +1 -0
  388. package/dist/key/runners.d.ts +60 -0
  389. package/dist/key/runners.d.ts.map +1 -0
  390. package/dist/key/runners.js +4 -0
  391. package/dist/key/runners.js.map +1 -0
  392. package/dist/main.d.ts +113 -0
  393. package/dist/main.d.ts.map +1 -0
  394. package/dist/main.js +199 -0
  395. package/dist/main.js.map +1 -0
  396. package/dist/mcp/launcher.d.ts +143 -0
  397. package/dist/mcp/launcher.d.ts.map +1 -0
  398. package/dist/mcp/launcher.js +393 -0
  399. package/dist/mcp/launcher.js.map +1 -0
  400. package/dist/mcp/preset-loader.d.ts +29 -0
  401. package/dist/mcp/preset-loader.d.ts.map +1 -0
  402. package/dist/mcp/preset-loader.js +217 -0
  403. package/dist/mcp/preset-loader.js.map +1 -0
  404. package/dist/mcp/preset-types.d.ts +71 -0
  405. package/dist/mcp/preset-types.d.ts.map +1 -0
  406. package/dist/mcp/preset-types.js +4 -0
  407. package/dist/mcp/preset-types.js.map +1 -0
  408. package/dist/mcp/presets/README.md +68 -0
  409. package/dist/mcp/presets/postgres.json +15 -0
  410. package/dist/output.d.ts +26 -0
  411. package/dist/output.d.ts.map +1 -0
  412. package/dist/output.js +46 -0
  413. package/dist/output.js.map +1 -0
  414. package/dist/pack-config.d.ts +37 -0
  415. package/dist/pack-config.d.ts.map +1 -0
  416. package/dist/pack-config.js +65 -0
  417. package/dist/pack-config.js.map +1 -0
  418. package/dist/package-manager.d.ts +33 -0
  419. package/dist/package-manager.d.ts.map +1 -0
  420. package/dist/package-manager.js +129 -0
  421. package/dist/package-manager.js.map +1 -0
  422. package/dist/parse.d.ts +88 -0
  423. package/dist/parse.d.ts.map +1 -0
  424. package/dist/parse.js +100 -0
  425. package/dist/parse.js.map +1 -0
  426. package/dist/providers/preset-loader.d.ts +47 -0
  427. package/dist/providers/preset-loader.d.ts.map +1 -0
  428. package/dist/providers/preset-loader.js +107 -0
  429. package/dist/providers/preset-loader.js.map +1 -0
  430. package/dist/providers/presets/anthropic.json +47 -0
  431. package/dist/providers/presets/gemini.json +40 -0
  432. package/dist/reference.d.ts +28 -0
  433. package/dist/reference.d.ts.map +1 -0
  434. package/dist/reference.js +52 -0
  435. package/dist/reference.js.map +1 -0
  436. package/dist/sdk-package.d.ts +9 -0
  437. package/dist/sdk-package.d.ts.map +1 -0
  438. package/dist/sdk-package.js +20 -0
  439. package/dist/sdk-package.js.map +1 -0
  440. package/dist/sdk-skills/kindgi-authoring-agents/SKILL.md +252 -0
  441. package/dist/sdk-skills/kindgi-authoring-flows/SKILL.md +302 -0
  442. package/dist/sdk-skills/kindgi-authoring-guardrails/SKILL.md +297 -0
  443. package/dist/sdk-skills/kindgi-authoring-mcp-servers/SKILL.md +289 -0
  444. package/dist/sdk-skills/kindgi-authoring-providers/SKILL.md +705 -0
  445. package/dist/sdk-skills/kindgi-authoring-tools/SKILL.md +298 -0
  446. package/dist/sdk-skills/kindgi-framework-feedback/SKILL.md +211 -0
  447. package/dist/sdk-skills/kindgi-getting-started/SKILL.md +189 -0
  448. package/dist/sdk-skills/kindgi-python-authoring-agents/SKILL.md +205 -0
  449. package/dist/sdk-skills/kindgi-python-authoring-flows/SKILL.md +325 -0
  450. package/dist/sdk-skills/kindgi-python-authoring-guardrails/SKILL.md +176 -0
  451. package/dist/sdk-skills/kindgi-python-authoring-tools/SKILL.md +305 -0
  452. package/dist/sdk-skills/kindgi-python-getting-started/SKILL.md +242 -0
  453. package/dist/stop-signal.d.ts +15 -0
  454. package/dist/stop-signal.d.ts.map +1 -0
  455. package/dist/stop-signal.js +16 -0
  456. package/dist/stop-signal.js.map +1 -0
  457. package/dist/templates/minimal/.nvmrc +1 -0
  458. package/dist/templates/minimal/AGENTS.md +23 -0
  459. package/dist/templates/minimal/README.md.tmpl +69 -0
  460. package/dist/templates/minimal/agents/.gitkeep +0 -0
  461. package/dist/templates/minimal/flows/.gitkeep +0 -0
  462. package/dist/templates/minimal/gitignore +8 -0
  463. package/dist/templates/minimal/guardrails/.gitkeep +0 -0
  464. package/dist/templates/minimal/kindgi.config.ts.tmpl +44 -0
  465. package/dist/templates/minimal/package.json.tmpl +25 -0
  466. package/dist/templates/minimal/pnpm-workspace.yaml +8 -0
  467. package/dist/templates/minimal/tools/.gitkeep +0 -0
  468. package/dist/templates/minimal/tsconfig.json.tmpl +27 -0
  469. package/dist/templates/minimal/vitest.config.ts.tmpl +14 -0
  470. package/dist/templates/python/AGENTS.md +30 -0
  471. package/dist/templates/python/README.md.tmpl +56 -0
  472. package/dist/templates/python/agents/echo_agent.py.tmpl +23 -0
  473. package/dist/templates/python/flows/echo_flow.py.tmpl +17 -0
  474. package/dist/templates/python/gitignore +9 -0
  475. package/dist/templates/python/guardrails/response_not_empty.py.tmpl +27 -0
  476. package/dist/templates/python/pyproject.toml.tmpl +42 -0
  477. package/dist/templates/python/tests/test_tools.py.tmpl +22 -0
  478. package/dist/templates/python/tools/echo.py.tmpl +27 -0
  479. package/dist/templates/python/tools/greet.py.tmpl +20 -0
  480. package/dist/templates/sample/.nvmrc +1 -0
  481. package/dist/templates/sample/AGENTS.md +23 -0
  482. package/dist/templates/sample/README.md.tmpl +85 -0
  483. package/dist/templates/sample/agents/echo-agent/index.ts.tmpl +34 -0
  484. package/dist/templates/sample/flows/echo-flow/index.ts.tmpl +59 -0
  485. package/dist/templates/sample/gitignore +8 -0
  486. package/dist/templates/sample/guardrails/response-not-empty/index.ts.tmpl +58 -0
  487. package/dist/templates/sample/kindgi.config.ts.tmpl +41 -0
  488. package/dist/templates/sample/package.json.tmpl +25 -0
  489. package/dist/templates/sample/pnpm-workspace.yaml +8 -0
  490. package/dist/templates/sample/tools/echo/index.test.ts.tmpl +31 -0
  491. package/dist/templates/sample/tools/echo/index.ts.tmpl +37 -0
  492. package/dist/templates/sample/tools/fetch-httpbin/index.ts.tmpl +60 -0
  493. package/dist/templates/sample/tools/greet/index.ts.tmpl +35 -0
  494. package/dist/templates/sample/tsconfig.json.tmpl +27 -0
  495. package/dist/templates/sample/vitest.config.ts.tmpl +14 -0
  496. package/dist/terminal-input.d.ts +17 -0
  497. package/dist/terminal-input.d.ts.map +1 -0
  498. package/dist/terminal-input.js +88 -0
  499. package/dist/terminal-input.js.map +1 -0
  500. package/dist/test/defaults.d.ts +3 -0
  501. package/dist/test/defaults.d.ts.map +1 -0
  502. package/dist/test/defaults.js +104 -0
  503. package/dist/test/defaults.js.map +1 -0
  504. package/dist/test/runners.d.ts +60 -0
  505. package/dist/test/runners.d.ts.map +1 -0
  506. package/dist/test/runners.js +4 -0
  507. package/dist/test/runners.js.map +1 -0
  508. package/dist/version-info.d.ts +9 -0
  509. package/dist/version-info.d.ts.map +1 -0
  510. package/dist/version-info.js +27 -0
  511. package/dist/version-info.js.map +1 -0
  512. package/dist/write-fully.d.ts +13 -0
  513. package/dist/write-fully.d.ts.map +1 -0
  514. package/dist/write-fully.js +17 -0
  515. package/dist/write-fully.js.map +1 -0
  516. package/package.json +63 -4
@@ -0,0 +1,1110 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+ /**
4
+ * `kindgi dev` — the local development loop.
5
+ *
6
+ * One command, everything on the laptop. Runs the Kindgi runtime as a
7
+ * container (`dev/runtime-container.ts`; or attaches to one you run,
8
+ * `--runtime-url`), discovers the pack's primitives via
9
+ * `@kindgi/handler-runtime.runIndexer`, runs the pack's code in a local
10
+ * pack service (the same process a deployment runs, as a child),
11
+ * registers each primitive into the runtime via the SDK, watches the
12
+ * four discovery folders (`tools/`, `guardrails/`, `agents/`, `flows/`)
13
+ * and the env files, and re-indexes, restarts the pack service and
14
+ * re-registers on change.
15
+ *
16
+ * v1 constraints:
17
+ * - Docker required for the runtime (unless `--runtime-url`), and
18
+ * Postgres: `kindgi dev` starts a bundled `docker-compose.dev.yml`
19
+ * (Postgres) with `docker compose`, or the same container with plain
20
+ * `docker` when compose isn't available, shared by every `kindgi dev`
21
+ * on the machine and left running; or set `--database-url` /
22
+ * `KINDGI_DATABASE_URL`.
23
+ * - `--watch` defaults ON. `--no-watch` runs a single boot + register
24
+ * cycle then exits — useful for smoke tests + CI.
25
+ * - A watch tick re-indexes and reloads the pack. The runtime serves
26
+ * the primitives from the pack's index on disk, so nothing is
27
+ * registered over HTTP.
28
+ *
29
+ * Every side effect (server boot, indexer run, filesystem watch)
30
+ * flows through `ctx.devRunners` so tests can substitute fixtures
31
+ * without booting Postgres or hitting the filesystem.
32
+ */
33
+ import { randomBytes, randomUUID } from 'node:crypto';
34
+ import { existsSync } from 'node:fs';
35
+ import { chmod, readFile, unlink, writeFile } from 'node:fs/promises';
36
+ import { isAbsolute, join, resolve } from 'node:path';
37
+ import { discoveryRoots, findKindgiConfig, packLanguage, resolveDiscovery, } from '@kindgi/handler-runtime';
38
+ import { LOCAL_ENV_NAME, displayEnvPath, packValues, readPackEnv, runtimeValues, } from '@kindgi/secrets-dotenv';
39
+ import { CORS_ORIGINS_VAR, PUBLIC_TOKEN_KEY_PATH_VAR, parseCorsOrigins } from '@kindgi/env-schema';
40
+ import { createDevOnlyImportsCheck } from '../dev/dev-only-imports.js';
41
+ import { resolvePackCode } from '../dev/pack-code.js';
42
+ import { devPackEnv, devPackEnvFiles } from '../dev/pack-env.js';
43
+ import { createPackRefresher, describePackEvent } from '../dev/pack-service.js';
44
+ import { registerFromIndex } from '../dev/register.js';
45
+ import { DEFAULT_RUNTIME_IMAGE } from '../dev/runtime-image.js';
46
+ import { describeEnvDiagnostics, loadLocalEnvSettings } from '../env/project-env.js';
47
+ import { renderJson } from '../output.js';
48
+ import { binDisplay, detectBinRunner } from '../package-manager.js';
49
+ import { defaultSdkSkillsRoot } from './init.js';
50
+ import { detectSkillDrift } from './skills.js';
51
+ export const devCommand = {
52
+ kind: 'leaf',
53
+ name: 'dev',
54
+ description: 'Run the Kindgi runtime as a container + hot-reload the pack under cwd.',
55
+ usage: 'kindgi dev [--port <n>] [--database-url <url>] [--tenant <id>] [--dev-token <token>] [--no-watch] [--path <dir>] [--reset] [--recreate-services] [--runtime-image <ref> | --runtime-url <url>]',
56
+ optionSpec: {
57
+ port: {
58
+ type: 'string',
59
+ description: "The port the runtime's API is reached on, on `127.0.0.1`. Default: `4000`. Not used with `--runtime-url`.",
60
+ },
61
+ // The Kindgi runtime image to run (default: the one this CLI release pins).
62
+ 'runtime-image': {
63
+ type: 'string',
64
+ description: 'The runtime image to run. Default: the one this CLI release pins.',
65
+ },
66
+ // A runtime you run yourself (e.g. from source) instead of the image.
67
+ 'runtime-url': {
68
+ type: 'string',
69
+ description: "Use a runtime you run yourself, at this origin, instead of starting the container. Start it with the pack's `.kindgi/dev/runtime.env`.",
70
+ },
71
+ 'database-url': {
72
+ type: 'string',
73
+ description: "The Postgres to use. Default: `KINDGI_DATABASE_URL` (the shell's, then the env files'), else the bundled Postgres.",
74
+ },
75
+ tenant: {
76
+ type: 'string',
77
+ description: "Pin the tenant. Default: the previous run's (from `.kindgirc.json`), else a new one.",
78
+ },
79
+ // Named `dev-token` to avoid clobbering the global `--token`
80
+ // (which is the caller's bearer token to a remote API). In dev
81
+ // mode, we CREATE a token for the freshly-booted api-server; this
82
+ // flag lets the caller pin it.
83
+ 'dev-token': {
84
+ type: 'string',
85
+ description: "Pin the API token. Default: the previous run's (from `.kindgirc.json`), else a new one.",
86
+ },
87
+ watch: {
88
+ type: 'boolean',
89
+ description: 'Re-index and reload the pack on every save. On by default; `--no-watch` turns it off.',
90
+ },
91
+ 'no-watch': {
92
+ type: 'boolean',
93
+ description: 'Start, index and register once, then exit. For smoke tests and CI.',
94
+ },
95
+ path: {
96
+ type: 'string',
97
+ description: 'The pack root, with a `kindgi.config.ts` (or `.mts`) or a `pyproject.toml` with `[tool.kindgi]`. Default: the current directory.',
98
+ },
99
+ // --reset: a fresh start for this pack only — a new tenant and token
100
+ // (it removes .kindgirc.json). The shared services and their data,
101
+ // which every kindgi dev on the machine uses, are never touched.
102
+ reset: {
103
+ type: 'boolean',
104
+ description: 'Start this pack fresh: removes `.kindgirc.json`, so the run gets a new tenant and token. The shared Postgres is left alone.',
105
+ },
106
+ // --recreate-services: let `docker compose` recreate the shared
107
+ // Postgres if its definition changed. Default: an existing container
108
+ // is reused as it is, so no other kindgi dev loses its database.
109
+ // Without compose it's always reused, and the output says so.
110
+ 'recreate-services': {
111
+ type: 'boolean',
112
+ description: 'Let `docker compose` recreate the bundled Postgres if its definition changed (needs compose). By default an existing container is reused.',
113
+ },
114
+ },
115
+ run: async (ctx) => runDev(ctx),
116
+ };
117
+ /** The API's default port on `127.0.0.1`. */
118
+ export const DEFAULT_DEV_PORT = 4000;
119
+ /** Default debounce for the watcher's re-index tick. */
120
+ export const DEFAULT_WATCH_DEBOUNCE_MS = 200;
121
+ /**
122
+ * Render the "manual KINDGI_DATABASE_URL required" hint shown when
123
+ * (a) the caller passed neither `--database-url` nor `KINDGI_DATABASE_URL`
124
+ * AND (b) the auto-start path is not viable (docker isn't installed or
125
+ * doesn't answer, or the runner isn't wired). Includes the auto-start reason
126
+ * so the user knows what to fix.
127
+ */
128
+ /**
129
+ * Live progress writer. Bypasses the command's buffered stdout/stderr
130
+ * return path so the developer sees phases as they happen — critical
131
+ * during the first-run docker-compose bring-up (image pulls,
132
+ * healthcheck waits) which can take 30–90s. Tests don't hit this
133
+ * path (the `startServices` runner is unwired in DevRunners fixtures)
134
+ * so nothing to intercept.
135
+ */
136
+ function emitProgress(msg) {
137
+ process.stderr.write(`${stoppingLineOpen ? '\n' : ''} ${msg}\n`);
138
+ stoppingLineOpen = false;
139
+ }
140
+ /**
141
+ * Shutdown is one line: "Stopping kindgi dev..." the moment the signal
142
+ * arrives, finished with "stopped." once the runtime and the pack service
143
+ * are down. A progress line in between (a save still being loaded) starts
144
+ * on its own line.
145
+ */
146
+ let stoppingLineOpen = false;
147
+ function beginStoppingLine() {
148
+ process.stderr.write(' Stopping kindgi dev...');
149
+ stoppingLineOpen = true;
150
+ }
151
+ function endStoppingLine(stopped) {
152
+ if (stoppingLineOpen)
153
+ process.stderr.write(stopped ? ' stopped.\n' : '\n');
154
+ else if (stopped)
155
+ process.stderr.write(' kindgi dev stopped.\n');
156
+ stoppingLineOpen = false;
157
+ }
158
+ /**
159
+ * Run an async work function while emitting a heartbeat every
160
+ * `intervalMs` so the user sees the seconds ticking during long
161
+ * operations (docker pulls, healthcheck waits). The heartbeat clears
162
+ * as soon as the work resolves or rejects.
163
+ */
164
+ async function withHeartbeat(label, intervalMs, work) {
165
+ const started = Date.now();
166
+ const tick = setInterval(() => {
167
+ const elapsed = Math.round((Date.now() - started) / 1000);
168
+ process.stderr.write(` ⋯ ${label} (${elapsed}s elapsed)\n`);
169
+ }, intervalMs);
170
+ try {
171
+ return await work();
172
+ }
173
+ finally {
174
+ clearInterval(tick);
175
+ }
176
+ }
177
+ function renderMissingDbHint(reason) {
178
+ return `kindgi dev needs Postgres, and couldn't start the bundled one: ${reason}\n\nOptions:\n 1. Install Docker (Docker Desktop, or Docker Engine on Linux) and make sure it runs: kindgi dev then starts the bundled Postgres itself, with \`docker compose\` when it's there and plain \`docker\` otherwise.\n 2. Use your own Postgres (16, with pgvector): pass --database-url=<url>, or set KINDGI_DATABASE_URL.\n`;
179
+ }
180
+ export async function runDev(ctx) {
181
+ const parsed = resolveDevArgs(ctx);
182
+ if (parsed.kind === 'error')
183
+ return parsed;
184
+ const args = parsed.args;
185
+ const runners = pickRunners(ctx);
186
+ if (runners.kind === 'error')
187
+ return runners;
188
+ const dev = runners.runners;
189
+ // Confirm the pack has a kindgi.config.ts (or one of its
190
+ // accepted extensions). Failing loud here beats a cryptic
191
+ // config-not-found from the indexer.
192
+ const configFile = await findKindgiConfig(args.packDir);
193
+ if (configFile === undefined) {
194
+ return {
195
+ kind: 'error',
196
+ stderr: `kindgi dev could not find a kindgi.config.ts (or a pyproject.toml with a [tool.kindgi] table) at ${args.packDir}.\nRun \`kindgi init <pack-name>\` to scaffold a pack, or pass --path=<dir> to point at an existing one.\n`,
197
+ exitCode: 1,
198
+ };
199
+ }
200
+ // The project's env files — Kindgi runtime config (`KINDGI_*`) for
201
+ // this process, everything else for the pack's agents via the dev
202
+ // secret binding.
203
+ const projectEnv = await loadDevProjectEnv(ctx, args.packDir);
204
+ if (projectEnv.kind === 'error')
205
+ return projectEnv;
206
+ const publicRunTokens = await resolveDevPublicRunTokens(ctx.env, projectEnv.runtime);
207
+ if (publicRunTokens.kind === 'error')
208
+ return publicRunTokens;
209
+ // `--reset` starts this pack fresh: without `.kindgirc.json` the boot
210
+ // below makes a new tenant and token, so the pack sees none of its
211
+ // earlier data. Other packs, and the shared services, are untouched.
212
+ if (args.reset) {
213
+ try {
214
+ await unlink(join(args.packDir, '.kindgirc.json'));
215
+ emitProgress('🧹 --reset: removed .kindgirc.json (fresh token + tenant this boot)');
216
+ }
217
+ catch (err) {
218
+ if (err.code !== 'ENOENT') {
219
+ emitProgress(` --reset: could not remove .kindgirc.json: ${err.message}`);
220
+ }
221
+ }
222
+ }
223
+ // Resolve the database URL. Precedence:
224
+ // 1. --database-url, then KINDGI_DATABASE_URL from the shell
225
+ // (resolved into args.databaseUrl at resolveDevArgs time).
226
+ // 2. KINDGI_DATABASE_URL from the project's env files.
227
+ // 3. Auto-start the bundled Postgres via
228
+ // `dev.startServices` when it's wired AND docker is available
229
+ // (`docker compose`, else plain `docker`).
230
+ // 4. Loud error with the manual quick-start hint.
231
+ let databaseUrl = args.databaseUrl ?? projectEnv.runtime.KINDGI_DATABASE_URL;
232
+ if (args.databaseUrl === undefined && databaseUrl !== undefined) {
233
+ emitProgress('using KINDGI_DATABASE_URL from the env files');
234
+ }
235
+ let servicesHandle;
236
+ if (databaseUrl === undefined) {
237
+ if (dev.startServices === undefined) {
238
+ return {
239
+ kind: 'error',
240
+ stderr: renderMissingDbHint('start-services runner not wired'),
241
+ exitCode: 1,
242
+ };
243
+ }
244
+ if (args.recreateServices) {
245
+ emitProgress('⚠ --recreate-services: the shared Postgres may be recreated; every kindgi dev on this machine using it reconnects');
246
+ }
247
+ emitProgress('Starting Postgres...');
248
+ emitProgress(' first-run image pull can take 30-90s; cached boots are ~5-10s');
249
+ const outcome = await withHeartbeat('still starting services', 5000, () => dev.startServices({ recreate: args.recreateServices }));
250
+ if (outcome.kind === 'unavailable') {
251
+ return {
252
+ kind: 'error',
253
+ stderr: renderMissingDbHint(outcome.reason),
254
+ exitCode: 1,
255
+ };
256
+ }
257
+ if (outcome.kind === 'error') {
258
+ return {
259
+ kind: 'error',
260
+ stderr: `kindgi dev auto-started bundled services but the boot failed:\n ${outcome.message}\n\nFalling back to manual KINDGI_DATABASE_URL is your escape hatch — set KINDGI_DATABASE_URL then re-run.\n`,
261
+ exitCode: 1,
262
+ };
263
+ }
264
+ servicesHandle = outcome.handle;
265
+ databaseUrl = outcome.handle.databaseUrl;
266
+ emitProgress(outcome.handle.startedWith === 'docker'
267
+ ? "✓ Postgres: started with docker (docker compose isn't available)"
268
+ : '✓ Postgres: started with docker compose');
269
+ for (const note of outcome.handle.notes ?? [])
270
+ emitProgress(`⚠ ${note}`);
271
+ }
272
+ // Resolve the tenant and the bearer token BEFORE booting, so the
273
+ // server seeds the same ones across `kindgi dev` runs: the pack's
274
+ // registered primitives and providers stay with the tenant, and the
275
+ // console, curl bookmarks and anything else holding the printed token
276
+ // keep working. Each one, highest first:
277
+ // 1. Its flag (`--tenant`, `--dev-token`).
278
+ // 2. The previous boot's, from `.kindgirc.json` in the pack dir.
279
+ // 3. Server-generated on this boot (the very first one, or after
280
+ // `--reset`, which already deleted the file), then persisted.
281
+ // Per field: `--dev-token` alone keeps the previous tenant.
282
+ const kindgircPath = join(args.packDir, '.kindgirc.json');
283
+ const persisted = await readPersistedRc(kindgircPath);
284
+ // Start the runtime. A failed start is the loudest error path, so
285
+ // we tear down auto-started services (if any) before returning. The
286
+ // first boot (or the first after `--reset`) makes the tenant, token and
287
+ // user here; they're persisted after the runtime serves.
288
+ const effectiveTenantId = args.tenantId ?? persisted.tenantId ?? randomUUID();
289
+ const effectiveToken = args.token ?? persisted.token ?? generateDevToken();
290
+ // The user the token resolves to comes back with the tenant it
291
+ // belongs to: what is keyed to the user (a reviewer registration)
292
+ // survives restarts.
293
+ const effectiveUserId = (effectiveTenantId === persisted.tenantId ? persisted.userId : undefined) ?? randomUUID();
294
+ // The pack's code is bundled and runs in a local pack service. It
295
+ // starts once the pack is bundled and indexed; the api-server gets
296
+ // its transport now.
297
+ const packEnv = () => devPackEnv({
298
+ packDir: args.packDir,
299
+ ...(projectEnv.localEnvFiles !== undefined && { localEnvFiles: projectEnv.localEnvFiles }),
300
+ hostEnv: ctx.env,
301
+ });
302
+ const code = await resolveDevPackCode(dev, projectEnv.language, args.packDir, projectEnv.config, packEnv);
303
+ if (code.kind === 'error') {
304
+ return code;
305
+ }
306
+ // A Node pack's imports that `kindgi build` would refuse (in
307
+ // devDependencies only): a warning here, on boot and when the set
308
+ // changes on a save.
309
+ const devOnly = code.value.language === 'node' ? createDevOnlyImportsCheck(args.packDir) : undefined;
310
+ const packOptions = {
311
+ packDir: args.packDir,
312
+ code: code.value,
313
+ env: packEnv,
314
+ onLog: (line) => emitProgress(` [pack] ${line}`),
315
+ onEvent: (event) => {
316
+ const line = describePackEvent(event);
317
+ if (line !== undefined)
318
+ emitProgress(line);
319
+ },
320
+ };
321
+ // The front listens for the whole session; children come and go behind
322
+ // it. It keeps the previous session's port, so a runtime started with
323
+ // its URL (`--runtime-url`) keeps reaching it.
324
+ let pack = dev.createPackService({
325
+ ...packOptions,
326
+ ...(persisted.packServicePort !== undefined && { port: persisted.packServicePort }),
327
+ ...(persisted.packServiceToken !== undefined && { token: persisted.packServiceToken }),
328
+ });
329
+ let packFront;
330
+ try {
331
+ packFront = await pack.listen();
332
+ }
333
+ catch (err) {
334
+ if (persisted.packServicePort === undefined)
335
+ throw err;
336
+ emitProgress(` the pack service's port ${persisted.packServicePort} is taken: using another one${args.runtimeUrl !== undefined ? ' (restart your runtime with the new runtime.env)' : ''}`);
337
+ await pack.close().catch(() => undefined);
338
+ pack = dev.createPackService(packOptions);
339
+ packFront = await pack.listen();
340
+ }
341
+ const builder = dev.createPackBuilder({
342
+ packDir: args.packDir,
343
+ patterns: projectEnv.discoveryPatterns,
344
+ ...(configFile.format === 'module' && { configPath: configFile.path }),
345
+ code: code.value,
346
+ env: packEnv,
347
+ });
348
+ const refresher = createPackRefresher({
349
+ dev,
350
+ pack,
351
+ builder,
352
+ packDir: args.packDir,
353
+ env: packEnv,
354
+ code: code.value,
355
+ ...(devOnly !== undefined && {
356
+ onBuild: async (build) => {
357
+ if (build.externals === undefined)
358
+ return;
359
+ for (const line of await devOnly.check(build.externals))
360
+ emitProgress(` ${line}`);
361
+ },
362
+ }),
363
+ });
364
+ // Bundle, index and start the pack's code before the runtime: it reads
365
+ // that index, and calls that pack service, from its first request.
366
+ emitProgress('Bundling + indexing the pack...');
367
+ const bootIndex = await refresher.refresh();
368
+ emitProgress(args.runtimeUrl !== undefined
369
+ ? `Using the Kindgi runtime at ${args.runtimeUrl}...`
370
+ : `Starting the Kindgi runtime (${args.runtimeImage})...`);
371
+ let server;
372
+ try {
373
+ server = await withHeartbeat('still starting the runtime', 3000, () => dev.startApiServer({
374
+ port: args.port,
375
+ databaseUrl,
376
+ tenantId: effectiveTenantId,
377
+ token: effectiveToken,
378
+ userId: effectiveUserId,
379
+ packDir: args.packDir,
380
+ ...(projectEnv.localEnvFiles !== undefined && {
381
+ localEnvFiles: projectEnv.localEnvFiles,
382
+ }),
383
+ hostEnv: ctx.env,
384
+ packService: { url: packFront.url, token: pack.token },
385
+ ...(publicRunTokens.keyPath !== undefined && {
386
+ publicRunTokenKeyPath: publicRunTokens.keyPath,
387
+ }),
388
+ ...(publicRunTokens.corsOrigins.length > 0 && {
389
+ corsOrigins: publicRunTokens.corsOrigins,
390
+ }),
391
+ runtimeImage: args.runtimeImage,
392
+ ...(args.runtimeUrl !== undefined && { runtimeUrl: args.runtimeUrl }),
393
+ onLog: (line) => emitProgress(` [runtime] ${line}`),
394
+ onProgress: emitProgress,
395
+ }));
396
+ }
397
+ catch (err) {
398
+ await pack.close().catch(() => undefined);
399
+ return {
400
+ kind: 'error',
401
+ stderr: `kindgi dev couldn't start the Kindgi runtime: ${err.message}\n`,
402
+ exitCode: 1,
403
+ };
404
+ }
405
+ emitProgress(`✓ the Kindgi runtime is serving at ${server.baseUrl}`);
406
+ const client = ctx.clientFor(server.baseUrl, server.token);
407
+ // Boot-time register, from the index built above.
408
+ emitProgress('Registering primitives...');
409
+ const bootReport = bootIndex.kind === 'ok'
410
+ ? await registerFromIndex({
411
+ index: bootIndex.index,
412
+ apiUrl: server.baseUrl,
413
+ token: server.token,
414
+ client,
415
+ fetchImpl: ctx.fetch,
416
+ projectId: server.defaultProjectId,
417
+ packDir: args.packDir,
418
+ })
419
+ : emptyReport();
420
+ emitBootIndex(bootIndex, bootReport, discoveryRoots(projectEnv.discoveryPatterns));
421
+ // Hints run the project's own kindgi through its package manager — or,
422
+ // for a Python pack (no npm project), the kindgi on PATH.
423
+ const runner = await detectBinRunner(args.packDir, code.value.language);
424
+ const kindgi = (...a) => binDisplay(runner, 'kindgi', a);
425
+ const providers = await registeredProviders(client);
426
+ const registerProviderCommand = kindgi('providers', 'register', '--preset=anthropic');
427
+ const bannerLines = renderDevBanner({
428
+ baseUrl: server.baseUrl,
429
+ tenantId: server.tenantId,
430
+ token: server.token,
431
+ providers,
432
+ registerProviderCommand,
433
+ packDir: args.packDir,
434
+ bootIndex,
435
+ bootReport,
436
+ discoveryRoots: discoveryRoots(projectEnv.discoveryPatterns),
437
+ ...(servicesHandle !== undefined && { autoStartedServices: servicesHandle.services }),
438
+ corsOrigins: publicRunTokens.corsOrigins,
439
+ });
440
+ // Write `.kindgirc.json` to the pack root so a SECOND terminal in
441
+ // the same directory (`cd <pack>; kindgi runs start ...`) picks up
442
+ // the api URL + bearer token automatically. Same file the config
443
+ // precedence in `config.ts` already reads. PERSISTS across boots by
444
+ // default — token + tenantId from the previous boot were read +
445
+ // reused above, so subsequent writes here are idempotent. The
446
+ // apiUrl gets refreshed each boot in case the port changed (--port
447
+ // flag, or the future auto-select on collision). Scaffolded
448
+ // .gitignore excludes it so it never ends up in git. Delete via
449
+ // `kindgi dev --reset` to force a fresh token + tenantId on the
450
+ // next boot.
451
+ //
452
+ // `tenantId` persistence is load-bearing after the r1
453
+ // named-volumes Postgres fix: without it, every boot creates a new
454
+ // tenant row and orphans the pack's registered primitives under old
455
+ // tenant UUIDs. Persisting keeps the "run this pack" identity
456
+ // stable across restarts.
457
+ let kindgircWritten = false;
458
+ try {
459
+ await writeFile(kindgircPath, `${JSON.stringify({
460
+ apiUrl: server.baseUrl,
461
+ token: server.token,
462
+ tenantId: server.tenantId,
463
+ userId: server.userId,
464
+ packServicePort: packFront.port,
465
+ packServiceToken: pack.token,
466
+ }, null, 2)}\n`,
467
+ // It holds the dev token and the pack service's token.
468
+ { encoding: 'utf8', mode: 0o600 });
469
+ await chmod(kindgircPath, 0o600);
470
+ kindgircWritten = true;
471
+ }
472
+ catch {
473
+ // Best effort — if the pack dir is read-only or something goes wrong,
474
+ // don't fail boot. The user can still pass --url/--token flags.
475
+ }
476
+ // Emit the "you're up, here's what to do next" block live to stderr
477
+ // so watch-mode users see it immediately. (With --no-watch, the returned
478
+ // command result also carries bannerLines, flushed on exit; watch mode
479
+ // ends with its one shutdown line, never the boot banner again.)
480
+ emitProgress('');
481
+ emitProgress('════════════════════════════════════════');
482
+ emitProgress(' ✓ Kindgi is up');
483
+ emitProgress('════════════════════════════════════════');
484
+ emitProgress(` API ${server.baseUrl}`);
485
+ if (server.consoleMounted === true) {
486
+ emitProgress(` Console ${server.baseUrl}/console/`);
487
+ }
488
+ emitProgress(` Tenant ${server.tenantId}`);
489
+ emitProgress(` Token ${server.token}`);
490
+ if (providers !== undefined) {
491
+ emitProgress(` Providers ${describeProviders(providers, registerProviderCommand)}`);
492
+ }
493
+ emitProgress(` Origins ${describeBrowserOrigins(publicRunTokens.corsOrigins)}`);
494
+ emitProgress('');
495
+ if (bootIndex.kind === 'ok' && bootIndex.counts.agents > 0) {
496
+ if (kindgircWritten) {
497
+ emitProgress(' Try it (from another terminal, cd to the pack dir first):');
498
+ }
499
+ else {
500
+ emitProgress(' Try it (auto-config write failed — pass --url + --token flags):');
501
+ }
502
+ // Suggest the first agent id from the index for a concrete
503
+ // starting-point command.
504
+ const firstAgent = bootIndex.index
505
+ ?.agents?.[0]?.id;
506
+ if (firstAgent !== undefined) {
507
+ emitProgress(` ${kindgi('runs', 'start', `--agent=${firstAgent}`, `--input='{"userMessage":"hi"}'`)}`);
508
+ emitProgress(` ${kindgi('runs', 'stream', '<run-id>')}`);
509
+ }
510
+ else {
511
+ emitProgress(` ${kindgi('runs', 'start', '--agent=<agent-id>', `--input='{"userMessage":"hi"}'`)}`);
512
+ }
513
+ emitProgress('');
514
+ }
515
+ emitProgress(' Hit a framework rough edge?');
516
+ emitProgress(` echo "…" | ${kindgi('feedback', 'write', '--kind=bug', '--title="…"', '--body-stdin')} (appends to FEEDBACK.md)`);
517
+ emitProgress('');
518
+ await emitSkillDriftHint(args.packDir, code.value.language, kindgi('skills', 'sync'));
519
+ if (args.watch) {
520
+ emitProgress(` Watching ${args.packDir}`);
521
+ emitProgress(' Ctrl+C to stop.');
522
+ emitProgress('');
523
+ }
524
+ const watchHandles = [];
525
+ let watchTicks = 0;
526
+ let lastWatchOutcome;
527
+ let lastWatchReport;
528
+ // Refresh ticks still running. Shutdown drains these so a tick never
529
+ // registers against a server that is already shutting down.
530
+ const inFlightTicks = new Set();
531
+ // Refreshes asked for while one runs collapse into one; report it once.
532
+ const reported = new WeakSet();
533
+ if (args.watch) {
534
+ const onRefresh = (build) => {
535
+ // The refresh runs asynchronously so no watcher ever blocks. Any
536
+ // failure lands in `lastWatchOutcome` / stderr; the server stays up.
537
+ const refreshed = refresher.refresh(build);
538
+ if (reported.has(refreshed))
539
+ return;
540
+ reported.add(refreshed);
541
+ const tick = (async () => {
542
+ watchTicks += 1;
543
+ const startedAt = Date.now();
544
+ const outcome = await refreshed;
545
+ lastWatchOutcome = outcome;
546
+ if (outcome.kind === 'ok') {
547
+ const report = await registerFromIndex({
548
+ index: outcome.index,
549
+ apiUrl: server.baseUrl,
550
+ token: server.token,
551
+ client,
552
+ fetchImpl: ctx.fetch,
553
+ projectId: server.defaultProjectId,
554
+ packDir: args.packDir,
555
+ });
556
+ lastWatchReport = report;
557
+ emitWatchTick({
558
+ elapsedMs: Date.now() - startedAt,
559
+ counts: outcome.counts,
560
+ fileErrors: outcome.fileErrors,
561
+ registered: report.registered.length,
562
+ failed: report.failed,
563
+ });
564
+ }
565
+ else if (outcome.code === 'discovery-empty') {
566
+ lastWatchReport = undefined;
567
+ emitProgress(' (no primitives yet)');
568
+ }
569
+ else {
570
+ lastWatchReport = undefined;
571
+ emitProgress(` ✗ refresh failed [${outcome.code}] ${outcome.message}`);
572
+ }
573
+ })();
574
+ inFlightTicks.add(tick);
575
+ void tick.finally(() => inFlightTicks.delete(tick));
576
+ };
577
+ // Code: esbuild rebuilds when any file a bundle read changes —
578
+ // shared libraries outside the discovery folders included.
579
+ await builder.watch((build) => onRefresh(build));
580
+ // A primitive file added or removed changes the entry points.
581
+ watchHandles.push(await dev.watchPack(args.packDir, () => {
582
+ void builder.syncEntries();
583
+ }, { debounceMs: DEFAULT_WATCH_DEBOUNCE_MS, patterns: projectEnv.discoveryPatterns }));
584
+ // The env files: the same code, restarted with the new environment.
585
+ watchHandles.push(await dev.watchPack(args.packDir, () => onRefresh(), {
586
+ debounceMs: DEFAULT_WATCH_DEBOUNCE_MS,
587
+ patterns: [],
588
+ files: devPackEnvFiles(args.packDir, projectEnv.localEnvFiles),
589
+ }));
590
+ }
591
+ // Watch mode: wait for the caller's abort signal (SIGINT/SIGTERM in
592
+ // production; injected AbortController.signal in tests). Non-watch
593
+ // mode: return immediately after boot registration.
594
+ if (args.watch)
595
+ await waitForAbort(ctx.stopSignal);
596
+ await stopDev({
597
+ watch: args.watch,
598
+ watchHandles,
599
+ builder,
600
+ inFlightTicks,
601
+ refresher,
602
+ server,
603
+ pack,
604
+ });
605
+ // `.kindgirc.json` is intentionally NOT deleted on exit — the
606
+ // persisted token survives so re-boots and second-terminal
607
+ // sessions keep working with the same bearer. `kindgi dev --reset`
608
+ // deletes it if you want a fresh token.
609
+ void kindgircWritten;
610
+ // The bundled services keep running: other `kindgi dev` sessions on
611
+ // this machine share them (see `StartedServicesHandle`).
612
+ // The JSON summary is for scripts that ask for it (`--json`, `--raw`):
613
+ // the boot, and in watch mode the last save's outcome — where the pack
614
+ // stood when kindgi dev stopped.
615
+ const summary = {
616
+ apiUrl: server.baseUrl,
617
+ tenantId: server.tenantId,
618
+ token: server.token,
619
+ port: server.port,
620
+ watch: args.watch,
621
+ packDir: args.packDir,
622
+ boot: summariseOutcome(bootIndex, bootReport),
623
+ // A Node pack's dev-only imports when kindgi dev stopped.
624
+ ...(devOnly !== undefined && { devOnlyImports: devOnly.current() }),
625
+ ...(args.watch && {
626
+ watchTicks,
627
+ ...(lastWatchOutcome !== undefined && {
628
+ lastWatch: summariseOutcome(lastWatchOutcome, lastWatchReport ?? emptyReport()),
629
+ }),
630
+ }),
631
+ };
632
+ const stdout = ctx.globals.formatRequested ? renderJson(summary, ctx.globals.format).stdout : '';
633
+ return {
634
+ kind: 'ok',
635
+ rendered: { stdout, stderr: args.watch ? '' : `${bannerLines.join('\n')}\n` },
636
+ };
637
+ }
638
+ /**
639
+ * Public run tokens for the browser app under development: signed with
640
+ * the key file when `KINDGI_PUBLIC_TOKEN_SIGNING_KEY_PATH` is set,
641
+ * otherwise with a key made now (tokens stop working when `kindgi dev`
642
+ * stops). `KINDGI_CORS_ORIGINS` lists the app's origins
643
+ * (`http://localhost:3000`). Both come from the shell, then the env files,
644
+ * like `KINDGI_DATABASE_URL`.
645
+ */
646
+ async function resolveDevPublicRunTokens(shell, files) {
647
+ const pick = (name) => {
648
+ const value = shell[name] ?? files[name];
649
+ return value === undefined || value.trim() === '' ? undefined : value.trim();
650
+ };
651
+ try {
652
+ const keyPath = pick(PUBLIC_TOKEN_KEY_PATH_VAR);
653
+ if (keyPath !== undefined && (!isAbsolute(keyPath) || !existsSync(keyPath))) {
654
+ throw new Error(`${PUBLIC_TOKEN_KEY_PATH_VAR} must be the absolute path of an existing key file. Got "${keyPath}".`);
655
+ }
656
+ return { kind: 'ok', keyPath, corsOrigins: parseCorsOrigins(pick(CORS_ORIGINS_VAR)) };
657
+ }
658
+ catch (err) {
659
+ return { kind: 'error', stderr: `kindgi dev: ${err.message}\n`, exitCode: 1 };
660
+ }
661
+ }
662
+ /**
663
+ * Read the project's env files for `local` and report them in the boot
664
+ * log (names and counts only — never values).
665
+ */
666
+ async function loadDevProjectEnv(ctx, packDir) {
667
+ const fail = (message) => ({
668
+ kind: 'error',
669
+ stderr: `kindgi dev: ${message}\n`,
670
+ exitCode: 1,
671
+ });
672
+ const settings = await loadLocalEnvSettings(ctx, packDir);
673
+ if (settings.kind === 'error')
674
+ return fail(settings.message);
675
+ if (settings.configProblem !== undefined) {
676
+ return fail(`could not load kindgi.config.ts at ${packDir}: ${settings.configProblem}`);
677
+ }
678
+ let env;
679
+ try {
680
+ env = await readPackEnv({
681
+ packDir,
682
+ envName: LOCAL_ENV_NAME,
683
+ ...(settings.localEnvFiles !== undefined && { localEnvFiles: settings.localEnvFiles }),
684
+ env: ctx.env,
685
+ });
686
+ }
687
+ catch (err) {
688
+ return fail(`could not read the env files: ${err.message}`);
689
+ }
690
+ const label = (paths) => paths.map((p) => displayEnvPath(packDir, p)).join(', ');
691
+ emitProgress(env.present.length === 0
692
+ ? `env files: none yet (reads ${label(env.files.read)})`
693
+ : `✓ env files: ${label(env.present)} — ${Object.keys(packValues(env.values)).length} name(s) for the pack`);
694
+ for (const line of describeEnvDiagnostics(packDir, env.diagnostics))
695
+ emitProgress(` ! ${line}`);
696
+ const discovery = settings.config?.discovery;
697
+ const language = settings.config !== undefined ? packLanguage(settings.config) : 'node';
698
+ return {
699
+ kind: 'ok',
700
+ localEnvFiles: settings.localEnvFiles,
701
+ runtime: runtimeValues(env.values),
702
+ discoveryPatterns: Object.values(resolveDiscovery(typeof discovery === 'object' && discovery !== null
703
+ ? discovery
704
+ : undefined, language)),
705
+ language,
706
+ config: settings.config,
707
+ };
708
+ }
709
+ function resolveDevArgs(ctx) {
710
+ // --port
711
+ const portRaw = ctx.options.port;
712
+ let port = DEFAULT_DEV_PORT;
713
+ if (typeof portRaw === 'string' && portRaw !== '') {
714
+ const parsedPort = Number.parseInt(portRaw, 10);
715
+ if (!Number.isFinite(parsedPort) || parsedPort < 0 || parsedPort > 65535) {
716
+ return {
717
+ kind: 'error',
718
+ stderr: `Invalid --port: ${portRaw}. Expected an integer 0..65535.\n`,
719
+ exitCode: 1,
720
+ };
721
+ }
722
+ port = parsedPort;
723
+ }
724
+ // --database-url > KINDGI_DATABASE_URL
725
+ const dbFlag = ctx.options['database-url'];
726
+ const dbEnv = getEnv(ctx, 'KINDGI_DATABASE_URL');
727
+ const databaseUrl = typeof dbFlag === 'string' && dbFlag !== ''
728
+ ? dbFlag
729
+ : typeof dbEnv === 'string' && dbEnv !== ''
730
+ ? dbEnv
731
+ : undefined;
732
+ // databaseUrl is allowed to be undefined at resolve time. `runDev`
733
+ // handles it: if `startServices` is wired AND docker is available,
734
+ // auto-start the bundled Postgres and use the container URL. If not,
735
+ // error with the manual quick-start hint.
736
+ // --tenant / --dev-token
737
+ const tenantFlag = ctx.options.tenant;
738
+ const tokenFlag = ctx.options['dev-token'];
739
+ const tenantId = typeof tenantFlag === 'string' && tenantFlag !== '' ? tenantFlag : undefined;
740
+ const token = typeof tokenFlag === 'string' && tokenFlag !== '' ? tokenFlag : undefined;
741
+ // --watch / --no-watch. Defaults ON for `kindgi dev`.
742
+ const watchOn = ctx.options.watch === true;
743
+ const watchOff = ctx.options['no-watch'] === true;
744
+ if (watchOn && watchOff) {
745
+ return {
746
+ kind: 'error',
747
+ stderr: 'Contradictory flags: --watch and --no-watch cannot both be set.\n',
748
+ exitCode: 1,
749
+ };
750
+ }
751
+ const watch = !watchOff;
752
+ // --path — pack root. Default is cwd.
753
+ const pathFlag = ctx.options.path;
754
+ const rawPath = typeof pathFlag === 'string' && pathFlag !== '' ? pathFlag : ctx.cwd;
755
+ const packDir = isAbsolute(rawPath) ? rawPath : resolve(ctx.cwd, rawPath);
756
+ // --reset — a fresh start for this pack only.
757
+ const reset = ctx.options.reset === true;
758
+ const recreateServices = ctx.options['recreate-services'] === true;
759
+ // --runtime-image / --runtime-url — which runtime: an image, or one you run.
760
+ const imageFlag = ctx.options['runtime-image'];
761
+ const urlFlag = ctx.options['runtime-url'];
762
+ const runtimeUrl = typeof urlFlag === 'string' && urlFlag !== '' ? urlFlag : undefined;
763
+ if (runtimeUrl !== undefined && typeof imageFlag === 'string' && imageFlag !== '') {
764
+ return {
765
+ kind: 'error',
766
+ stderr: '--runtime-image and --runtime-url exclude each other: an image, or a runtime you run.\n',
767
+ exitCode: 1,
768
+ };
769
+ }
770
+ if (runtimeUrl !== undefined && !/^https?:\/\/[^/]+\/?$/.test(runtimeUrl)) {
771
+ return {
772
+ kind: 'error',
773
+ stderr: `Invalid --runtime-url: ${runtimeUrl}. Expected the runtime's origin, e.g. http://127.0.0.1:4000.\n`,
774
+ exitCode: 1,
775
+ };
776
+ }
777
+ const runtimeImage = typeof imageFlag === 'string' && imageFlag !== '' ? imageFlag : DEFAULT_RUNTIME_IMAGE;
778
+ return {
779
+ kind: 'ok',
780
+ args: {
781
+ port,
782
+ databaseUrl,
783
+ tenantId,
784
+ token,
785
+ watch,
786
+ packDir,
787
+ reset,
788
+ recreateServices,
789
+ runtimeImage,
790
+ runtimeUrl,
791
+ },
792
+ };
793
+ }
794
+ function pickRunners(ctx) {
795
+ if (ctx.devRunners !== undefined)
796
+ return { kind: 'ok', runners: ctx.devRunners };
797
+ return {
798
+ kind: 'error',
799
+ stderr: 'Internal error: kindgi dev requires dev runners to be wired. ' +
800
+ 'Rebuild the CLI (`pnpm --filter @kindgi/cli build`).\n',
801
+ exitCode: 1,
802
+ };
803
+ }
804
+ /**
805
+ * Read the persisted `.kindgirc.json` if present. Returns `undefined`
806
+ * for any missing field — all missing cases fall back to
807
+ * server-generated on this boot. Called at boot so the previous run's
808
+ * token AND tenantId are reused across restarts.
809
+ *
810
+ * Persisting `tenantId` alongside `token` matters after the r1
811
+ * named-volume Postgres change: without it, `seedTenant` generates a
812
+ * fresh UUID + slug on every boot, orphaning the pack's registered
813
+ * primitives from previous boots under old tenant rows in the
814
+ * persisted DB.
815
+ */
816
+ async function readPersistedRc(kindgircPath) {
817
+ try {
818
+ const raw = await readFile(kindgircPath, 'utf8');
819
+ const parsed = JSON.parse(raw);
820
+ return {
821
+ ...(typeof parsed.packServiceToken === 'string' &&
822
+ /^[A-Za-z0-9_-]{32,}$/.test(parsed.packServiceToken) && {
823
+ packServiceToken: parsed.packServiceToken,
824
+ }),
825
+ ...(typeof parsed.packServicePort === 'number' &&
826
+ Number.isInteger(parsed.packServicePort) &&
827
+ parsed.packServicePort > 0 &&
828
+ parsed.packServicePort < 65536 && { packServicePort: parsed.packServicePort }),
829
+ ...(typeof parsed.token === 'string' && parsed.token.length > 0 && { token: parsed.token }),
830
+ ...(typeof parsed.tenantId === 'string' &&
831
+ parsed.tenantId.length > 0 && { tenantId: parsed.tenantId }),
832
+ ...(typeof parsed.userId === 'string' &&
833
+ parsed.userId.length > 0 && { userId: parsed.userId }),
834
+ };
835
+ }
836
+ catch {
837
+ return {};
838
+ }
839
+ }
840
+ /** What the boot loaded, live: the counts and failures, no primitives yet, or the indexer's error. */
841
+ function emitBootIndex(bootIndex, bootReport, roots) {
842
+ if (bootIndex.kind !== 'ok') {
843
+ // Dev stays up either way; the section says so.
844
+ for (const line of renderIndexSection({ bootIndex, bootReport, discoveryRoots: roots })) {
845
+ emitProgress(line.replace(/^ {2}/, ''));
846
+ }
847
+ return;
848
+ }
849
+ const c = bootIndex.counts;
850
+ emitProgress(`✓ loaded: ${c.tools} tools, ${c.guardrails} guardrails, ${c.agents} agents, ${c.flows} flows`);
851
+ for (const e of bootIndex.fileErrors) {
852
+ emitProgress(` ⚠ indexer: ${e.filePath ?? '?'} [${e.code}] ${e.message}`);
853
+ }
854
+ for (const f of bootReport.failed) {
855
+ emitProgress(` ⚠ ${f.kind}: ${f.id} — ${f.message ?? 'unknown reason'}`);
856
+ }
857
+ }
858
+ /**
859
+ * Stop everything `kindgi dev` started: the watchers, then the refreshes
860
+ * in flight (drained, so none registers against a server shutting down),
861
+ * the runtime and the pack service. In watch mode, on the one shutdown
862
+ * line.
863
+ */
864
+ async function stopDev(parts) {
865
+ let stopped = false;
866
+ try {
867
+ if (parts.watch) {
868
+ beginStoppingLine();
869
+ for (const handle of parts.watchHandles)
870
+ await handle.close();
871
+ }
872
+ // Nothing starts a refresh any more; drain the ones in flight.
873
+ await parts.builder.dispose();
874
+ await Promise.allSettled(parts.inFlightTicks);
875
+ await parts.refresher.idle();
876
+ await parts.server.shutdown();
877
+ await parts.pack.close();
878
+ stopped = true;
879
+ }
880
+ finally {
881
+ if (parts.watch)
882
+ endStoppingLine(stopped);
883
+ }
884
+ }
885
+ /**
886
+ * Emit a short human-readable line per watch tick so the user sees
887
+ * that a save re-indexed + reloaded the pack. Primitives come from
888
+ * disk, so they aren't "re-registered" per se — the neutral
889
+ * "loaded" verb covers both paths.
890
+ */
891
+ function emitWatchTick(input) {
892
+ const { counts, fileErrors, failed, elapsedMs, registered } = input;
893
+ const totals = `${counts.tools} tools, ${counts.guardrails} guardrails, ${counts.agents} agents, ${counts.flows} flows`;
894
+ if (fileErrors.length === 0 && failed.length === 0) {
895
+ emitProgress(` ✓ loaded ${registered} primitives (${totals}) in ${elapsedMs}ms`);
896
+ return;
897
+ }
898
+ emitProgress(` ⚠ loaded ${registered} of ${registered + failed.length} in ${elapsedMs}ms — ${totals}`);
899
+ for (const e of fileErrors) {
900
+ emitProgress(` ✗ indexer: ${e.filePath ?? '?'} [${e.code}] ${e.message}`);
901
+ }
902
+ for (const f of failed) {
903
+ emitProgress(` ✗ ${f.kind}: ${f.id} — ${f.message ?? 'unknown reason'}`);
904
+ }
905
+ }
906
+ /**
907
+ * Compare the pack's installed framework skills against the bundled
908
+ * SDK versions; print a one-liner if drift is detected. Silent when
909
+ * everything is up to date. Never fails boot — a drift-check crash
910
+ * (missing skills root, unreadable manifest) is swallowed because
911
+ * the drift check is advisory, not load-bearing.
912
+ */
913
+ async function emitSkillDriftHint(packDir, language, syncCommand) {
914
+ const skillsRoot = defaultSdkSkillsRoot();
915
+ if (skillsRoot === undefined)
916
+ return;
917
+ try {
918
+ const drift = await detectSkillDrift({ skillsRoot, targetDir: packDir, language });
919
+ const total = drift.missing.length + drift.outdated.length;
920
+ if (total === 0)
921
+ return;
922
+ const parts = [];
923
+ if (drift.outdated.length > 0)
924
+ parts.push(`${drift.outdated.length} out of date`);
925
+ if (drift.missing.length > 0)
926
+ parts.push(`${drift.missing.length} not yet installed`);
927
+ emitProgress(` ⚠ Framework skills: ${parts.join(', ')}.`);
928
+ emitProgress(` Run \`${syncCommand}\` to pull the latest.`);
929
+ emitProgress('');
930
+ }
931
+ catch {
932
+ // Advisory; never block boot on a drift-check failure.
933
+ }
934
+ }
935
+ /**
936
+ * How this pack's code runs (`dev/pack-code.ts`). For a Python pack, the
937
+ * interpreter is resolved and checked — with the pack's own environment —
938
+ * before anything boots.
939
+ */
940
+ async function resolveDevPackCode(dev, language, packDir, config, packEnv) {
941
+ const resolved = await resolvePackCode(language, packDir, config);
942
+ if (resolved.kind === 'err') {
943
+ return { kind: 'error', stderr: `kindgi dev: ${resolved.message}\n`, exitCode: 1 };
944
+ }
945
+ if (resolved.value.language === 'python') {
946
+ const checked = await dev.checkPackPython(resolved.value.python, await packEnv(), packDir);
947
+ if (checked.kind === 'err') {
948
+ return { kind: 'error', stderr: `kindgi dev: ${checked.message}\n`, exitCode: 1 };
949
+ }
950
+ emitProgress(`✓ pack code: ${checked.value}`);
951
+ }
952
+ return { kind: 'ok', value: resolved.value };
953
+ }
954
+ function getEnv(ctx, key) {
955
+ // `ctx.env` is the only source: the `kindgi` binary passes
956
+ // `process.env` (src/cli.ts), tests pass an explicit record. No
957
+ // per-key fallback to `process.env` — that made "variable unset"
958
+ // untestable whenever the host shell (or CI) exported it.
959
+ return ctx.env[key];
960
+ }
961
+ /**
962
+ * The tenant's providers for the banner; `undefined` when they can't be
963
+ * listed (the banner then leaves the line out).
964
+ */
965
+ async function registeredProviders(client) {
966
+ try {
967
+ const providers = [];
968
+ let cursor;
969
+ do {
970
+ const page = await client.providers.list({
971
+ limit: 100,
972
+ ...(cursor !== undefined && { cursor }),
973
+ });
974
+ providers.push(...page.data);
975
+ cursor = page.hasMore ? page.nextCursor : undefined;
976
+ } while (cursor !== undefined);
977
+ return providers;
978
+ }
979
+ catch {
980
+ return undefined;
981
+ }
982
+ }
983
+ /** The browser origins line: who may follow runs with public run tokens (`KINDGI_CORS_ORIGINS`). */
984
+ function describeBrowserOrigins(origins) {
985
+ return origins.length > 0
986
+ ? `${origins.join(', ')} (browsers may follow runs with public run tokens)`
987
+ : 'none (set KINDGI_CORS_ORIGINS so a browser app can follow runs)';
988
+ }
989
+ /**
990
+ * The banner's providers line: each provider with its models, fallbacks
991
+ * marked; when only fallbacks (or nothing) can answer, how to register a
992
+ * real model.
993
+ */
994
+ function describeProviders(providers, registerProviderCommand) {
995
+ if (providers.length === 0) {
996
+ return `none — agent turns fail until one is registered: ${registerProviderCommand}`;
997
+ }
998
+ const named = providers
999
+ .map((p) => p.fallback === true
1000
+ ? `${p.id} (fallback)`
1001
+ : `${p.id} (${p.models.map((m) => m.name).join(', ')})`)
1002
+ .join(' · ');
1003
+ if (providers.some((p) => p.fallback !== true))
1004
+ return named;
1005
+ return `${named} — canned replies; for a real model: ${registerProviderCommand}`;
1006
+ }
1007
+ /** The banner `kindgi dev --no-watch` prints to stderr when it exits. */
1008
+ export function renderDevBanner(inputs) {
1009
+ const lines = [];
1010
+ lines.push('');
1011
+ lines.push(' Starting Kindgi locally (dev: the runtime in a container, your code on this machine)');
1012
+ lines.push(` API server ${inputs.baseUrl}`);
1013
+ lines.push(` Tenant ${inputs.tenantId}`);
1014
+ lines.push(` Bearer token ${inputs.token}`);
1015
+ lines.push(` Pack dir ${inputs.packDir}`);
1016
+ if (inputs.providers !== undefined) {
1017
+ lines.push(` Providers ${describeProviders(inputs.providers, inputs.registerProviderCommand)}`);
1018
+ }
1019
+ if (inputs.autoStartedServices !== undefined && inputs.autoStartedServices.length > 0) {
1020
+ lines.push(` Auto-started ${inputs.autoStartedServices.join(', ')} (docker, shared by every kindgi dev; left running)`);
1021
+ }
1022
+ if (inputs.corsOrigins !== undefined) {
1023
+ lines.push(` Browser origins ${describeBrowserOrigins(inputs.corsOrigins)}`);
1024
+ }
1025
+ lines.push('');
1026
+ lines.push(...renderIndexSection(inputs));
1027
+ lines.push('');
1028
+ lines.push(' --no-watch: single boot + register cycle complete.');
1029
+ return lines;
1030
+ }
1031
+ /** The "what got indexed" part of the banner: counts + failures, an empty pack, or the indexer error. */
1032
+ function renderIndexSection(inputs) {
1033
+ const index = inputs.bootIndex;
1034
+ if (index.kind === 'ok') {
1035
+ const c = index.counts;
1036
+ const lines = [
1037
+ ` Discovering pack (${index.packId}@${index.packVersion})`,
1038
+ ` ✓ ${c.tools} tools ✓ ${c.guardrails} guardrails ✓ ${c.agents} agents ✓ ${c.flows} flows`,
1039
+ ];
1040
+ if (inputs.bootReport.failed.length > 0) {
1041
+ lines.push('', ' Registration failures:');
1042
+ for (const f of inputs.bootReport.failed) {
1043
+ lines.push(` ✗ ${f.kind} ${f.id} — ${f.message ?? 'unknown error'}`);
1044
+ }
1045
+ }
1046
+ return lines;
1047
+ }
1048
+ if (index.code === 'discovery-empty') {
1049
+ const where = (inputs.discoveryRoots ?? []).map((r) => `${r === '' ? '.' : r}/`).join(', ');
1050
+ return [
1051
+ ` No primitives yet — add a tool or agent${where === '' ? '' : ` under ${where}`}; it registers on save.`,
1052
+ ];
1053
+ }
1054
+ return [
1055
+ ` Indexer failed: [${index.code}] ${index.message}`,
1056
+ ...(index.filePath !== undefined ? [` at ${index.filePath}`] : []),
1057
+ ' Fix the pack source; kindgi dev keeps the server up regardless.',
1058
+ ];
1059
+ }
1060
+ /** The refresh found no primitive files: an empty pack, which is not an error. */
1061
+ function isEmptyPack(outcome) {
1062
+ return outcome.kind === 'err' && outcome.code === 'discovery-empty';
1063
+ }
1064
+ function summariseOutcome(outcome, report) {
1065
+ if (isEmptyPack(outcome)) {
1066
+ return {
1067
+ ok: true,
1068
+ empty: true,
1069
+ counts: { tools: 0, guardrails: 0, agents: 0, flows: 0 },
1070
+ registered: 0,
1071
+ failed: [],
1072
+ };
1073
+ }
1074
+ if (outcome.kind === 'err') {
1075
+ return {
1076
+ ok: false,
1077
+ indexerError: {
1078
+ code: outcome.code,
1079
+ message: outcome.message,
1080
+ ...(outcome.filePath !== undefined && { filePath: outcome.filePath }),
1081
+ },
1082
+ };
1083
+ }
1084
+ return {
1085
+ ok: true,
1086
+ packId: outcome.packId,
1087
+ packVersion: outcome.packVersion,
1088
+ counts: outcome.counts,
1089
+ registered: report.registered.length,
1090
+ failed: report.failed.map((f) => ({ kind: f.kind, id: f.id, message: f.message ?? null })),
1091
+ };
1092
+ }
1093
+ function emptyReport() {
1094
+ return { registered: [], failed: [] };
1095
+ }
1096
+ function waitForAbort(signal) {
1097
+ // biome-ignore lint/suspicious/noEmptyBlockStatements: wait forever when no signal
1098
+ if (signal === undefined)
1099
+ return new Promise(() => { });
1100
+ if (signal.aborted)
1101
+ return Promise.resolve();
1102
+ return new Promise((resolvePromise) => {
1103
+ signal.addEventListener('abort', () => resolvePromise(), { once: true });
1104
+ });
1105
+ }
1106
+ /** A dev token in the runtime's own format: `kgi_bt_` and 32 random bytes, URL-safe base64. */
1107
+ function generateDevToken() {
1108
+ return `kgi_bt_${randomBytes(32).toString('base64url')}`;
1109
+ }
1110
+ //# sourceMappingURL=dev.js.map