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