@kindgi/cli 0.1.11-rc.0 → 0.2.0-rc.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 (350) hide show
  1. package/README.md +77 -33
  2. package/dist/build/containerfile.d.ts +2 -0
  3. package/dist/build/containerfile.d.ts.map +1 -1
  4. package/dist/build/containerfile.js +14 -3
  5. package/dist/build/containerfile.js.map +1 -1
  6. package/dist/build/defaults.d.ts +2 -0
  7. package/dist/build/defaults.d.ts.map +1 -1
  8. package/dist/build/defaults.js +8 -0
  9. package/dist/build/defaults.js.map +1 -1
  10. package/dist/build/hosted.d.ts +2 -9
  11. package/dist/build/hosted.d.ts.map +1 -1
  12. package/dist/build/hosted.js +4 -2
  13. package/dist/build/hosted.js.map +1 -1
  14. package/dist/build/pack-blocks.d.ts +51 -0
  15. package/dist/build/pack-blocks.d.ts.map +1 -0
  16. package/dist/build/pack-blocks.js +98 -0
  17. package/dist/build/pack-blocks.js.map +1 -0
  18. package/dist/build/runners.d.ts +5 -1
  19. package/dist/build/runners.d.ts.map +1 -1
  20. package/dist/cli.js +4 -0
  21. package/dist/cli.js.map +1 -1
  22. package/dist/commands/adapters.d.ts.map +1 -1
  23. package/dist/commands/adapters.js +12 -6
  24. package/dist/commands/adapters.js.map +1 -1
  25. package/dist/commands/agents.js +8 -8
  26. package/dist/commands/agents.js.map +1 -1
  27. package/dist/commands/auth.d.ts.map +1 -1
  28. package/dist/commands/auth.js +155 -39
  29. package/dist/commands/auth.js.map +1 -1
  30. package/dist/commands/blocks.d.ts.map +1 -1
  31. package/dist/commands/blocks.js +1 -1
  32. package/dist/commands/blocks.js.map +1 -1
  33. package/dist/commands/build.d.ts +17 -6
  34. package/dist/commands/build.d.ts.map +1 -1
  35. package/dist/commands/build.js +136 -89
  36. package/dist/commands/build.js.map +1 -1
  37. package/dist/commands/connection-apps.d.ts +3 -0
  38. package/dist/commands/connection-apps.d.ts.map +1 -0
  39. package/dist/commands/connection-apps.js +239 -0
  40. package/dist/commands/connection-apps.js.map +1 -0
  41. package/dist/commands/connections.d.ts +44 -0
  42. package/dist/commands/connections.d.ts.map +1 -0
  43. package/dist/commands/connections.js +385 -0
  44. package/dist/commands/connections.js.map +1 -0
  45. package/dist/commands/conversations.js +1 -1
  46. package/dist/commands/conversations.js.map +1 -1
  47. package/dist/commands/deploy.d.ts.map +1 -1
  48. package/dist/commands/deploy.js +178 -97
  49. package/dist/commands/deploy.js.map +1 -1
  50. package/dist/commands/dev.d.ts +10 -0
  51. package/dist/commands/dev.d.ts.map +1 -1
  52. package/dist/commands/dev.js +177 -87
  53. package/dist/commands/dev.js.map +1 -1
  54. package/dist/commands/doctor.js +7 -7
  55. package/dist/commands/doctor.js.map +1 -1
  56. package/dist/commands/env-scoped.d.ts.map +1 -1
  57. package/dist/commands/env-scoped.js +37 -22
  58. package/dist/commands/env-scoped.js.map +1 -1
  59. package/dist/commands/env.d.ts.map +1 -1
  60. package/dist/commands/env.js +35 -22
  61. package/dist/commands/env.js.map +1 -1
  62. package/dist/commands/eval-runs.js +6 -6
  63. package/dist/commands/eval-runs.js.map +1 -1
  64. package/dist/commands/eval-suites.js +9 -9
  65. package/dist/commands/eval-suites.js.map +1 -1
  66. package/dist/commands/exports.d.ts.map +1 -1
  67. package/dist/commands/exports.js +35 -9
  68. package/dist/commands/exports.js.map +1 -1
  69. package/dist/commands/feedback.d.ts.map +1 -1
  70. package/dist/commands/feedback.js +4 -3
  71. package/dist/commands/feedback.js.map +1 -1
  72. package/dist/commands/gate-policies.d.ts.map +1 -1
  73. package/dist/commands/gate-policies.js +7 -7
  74. package/dist/commands/gate-policies.js.map +1 -1
  75. package/dist/commands/helpers.d.ts +33 -0
  76. package/dist/commands/helpers.d.ts.map +1 -1
  77. package/dist/commands/helpers.js +49 -0
  78. package/dist/commands/helpers.js.map +1 -1
  79. package/dist/commands/index.d.ts.map +1 -1
  80. package/dist/commands/index.js +10 -0
  81. package/dist/commands/index.js.map +1 -1
  82. package/dist/commands/init.d.ts +1 -1
  83. package/dist/commands/init.d.ts.map +1 -1
  84. package/dist/commands/init.js +57 -45
  85. package/dist/commands/init.js.map +1 -1
  86. package/dist/commands/judge-classes.js +4 -4
  87. package/dist/commands/judge-classes.js.map +1 -1
  88. package/dist/commands/judging-queue.d.ts +3 -0
  89. package/dist/commands/judging-queue.d.ts.map +1 -0
  90. package/dist/commands/judging-queue.js +105 -0
  91. package/dist/commands/judging-queue.js.map +1 -0
  92. package/dist/commands/judging-rules.d.ts +3 -0
  93. package/dist/commands/judging-rules.d.ts.map +1 -0
  94. package/dist/commands/judging-rules.js +351 -0
  95. package/dist/commands/judging-rules.js.map +1 -0
  96. package/dist/commands/judgments.d.ts.map +1 -1
  97. package/dist/commands/judgments.js +78 -36
  98. package/dist/commands/judgments.js.map +1 -1
  99. package/dist/commands/key.d.ts.map +1 -1
  100. package/dist/commands/key.js +107 -9
  101. package/dist/commands/key.js.map +1 -1
  102. package/dist/commands/license.d.ts.map +1 -1
  103. package/dist/commands/license.js +67 -15
  104. package/dist/commands/license.js.map +1 -1
  105. package/dist/commands/mail-triggers.d.ts +3 -0
  106. package/dist/commands/mail-triggers.d.ts.map +1 -0
  107. package/dist/commands/mail-triggers.js +290 -0
  108. package/dist/commands/mail-triggers.js.map +1 -0
  109. package/dist/commands/mcp.d.ts.map +1 -1
  110. package/dist/commands/mcp.js +4 -4
  111. package/dist/commands/mcp.js.map +1 -1
  112. package/dist/commands/people.js +8 -14
  113. package/dist/commands/people.js.map +1 -1
  114. package/dist/commands/promote.js +1 -1
  115. package/dist/commands/promote.js.map +1 -1
  116. package/dist/commands/proposals.d.ts.map +1 -1
  117. package/dist/commands/proposals.js +83 -30
  118. package/dist/commands/proposals.js.map +1 -1
  119. package/dist/commands/run-waits.d.ts +68 -19
  120. package/dist/commands/run-waits.d.ts.map +1 -1
  121. package/dist/commands/run-waits.js +82 -8
  122. package/dist/commands/run-waits.js.map +1 -1
  123. package/dist/commands/runs.d.ts.map +1 -1
  124. package/dist/commands/runs.js +70 -30
  125. package/dist/commands/runs.js.map +1 -1
  126. package/dist/commands/schedules.d.ts.map +1 -1
  127. package/dist/commands/schedules.js +44 -20
  128. package/dist/commands/schedules.js.map +1 -1
  129. package/dist/commands/secrets-copy.d.ts.map +1 -1
  130. package/dist/commands/secrets-copy.js +20 -12
  131. package/dist/commands/secrets-copy.js.map +1 -1
  132. package/dist/commands/secrets.d.ts.map +1 -1
  133. package/dist/commands/secrets.js +13 -8
  134. package/dist/commands/secrets.js.map +1 -1
  135. package/dist/commands/service-accounts.d.ts.map +1 -1
  136. package/dist/commands/service-accounts.js +4 -2
  137. package/dist/commands/service-accounts.js.map +1 -1
  138. package/dist/commands/sign-in.js +2 -2
  139. package/dist/commands/sign-in.js.map +1 -1
  140. package/dist/commands/sites.d.ts.map +1 -1
  141. package/dist/commands/sites.js +13 -6
  142. package/dist/commands/sites.js.map +1 -1
  143. package/dist/commands/skills.d.ts +54 -3
  144. package/dist/commands/skills.d.ts.map +1 -1
  145. package/dist/commands/skills.js +169 -38
  146. package/dist/commands/skills.js.map +1 -1
  147. package/dist/commands/tokens.d.ts.map +1 -1
  148. package/dist/commands/tokens.js +9 -1
  149. package/dist/commands/tokens.js.map +1 -1
  150. package/dist/commands/upgrade.d.ts.map +1 -1
  151. package/dist/commands/upgrade.js +9 -8
  152. package/dist/commands/upgrade.js.map +1 -1
  153. package/dist/commands/webhooks.d.ts.map +1 -1
  154. package/dist/commands/webhooks.js +72 -33
  155. package/dist/commands/webhooks.js.map +1 -1
  156. package/dist/config.d.ts +6 -0
  157. package/dist/config.d.ts.map +1 -1
  158. package/dist/config.js +18 -3
  159. package/dist/config.js.map +1 -1
  160. package/dist/context.d.ts +12 -0
  161. package/dist/context.d.ts.map +1 -1
  162. package/dist/context.js +2 -0
  163. package/dist/context.js.map +1 -1
  164. package/dist/deploy/pack-blocks-gate.d.ts +12 -0
  165. package/dist/deploy/pack-blocks-gate.d.ts.map +1 -0
  166. package/dist/deploy/pack-blocks-gate.js +34 -0
  167. package/dist/deploy/pack-blocks-gate.js.map +1 -0
  168. package/dist/deploy/post.d.ts +9 -0
  169. package/dist/deploy/post.d.ts.map +1 -1
  170. package/dist/deploy/post.js +20 -3
  171. package/dist/deploy/post.js.map +1 -1
  172. package/dist/dev/defaults.d.ts.map +1 -1
  173. package/dist/dev/defaults.js +8 -1
  174. package/dist/dev/defaults.js.map +1 -1
  175. package/dist/dev/dev-only-imports.d.ts +7 -4
  176. package/dist/dev/dev-only-imports.d.ts.map +1 -1
  177. package/dist/dev/dev-only-imports.js +5 -5
  178. package/dist/dev/dev-only-imports.js.map +1 -1
  179. package/dist/dev/log-view.d.ts +4 -4
  180. package/dist/dev/log-view.d.ts.map +1 -1
  181. package/dist/dev/log-view.js +4 -4
  182. package/dist/dev/log-view.js.map +1 -1
  183. package/dist/dev/pack-service.d.ts +7 -1
  184. package/dist/dev/pack-service.d.ts.map +1 -1
  185. package/dist/dev/pack-service.js +36 -3
  186. package/dist/dev/pack-service.js.map +1 -1
  187. package/dist/dev/preview-expiry.d.ts +6 -7
  188. package/dist/dev/preview-expiry.d.ts.map +1 -1
  189. package/dist/dev/preview-expiry.js +7 -8
  190. package/dist/dev/preview-expiry.js.map +1 -1
  191. package/dist/dev/providers.d.ts +2 -1
  192. package/dist/dev/providers.d.ts.map +1 -1
  193. package/dist/dev/providers.js +28 -12
  194. package/dist/dev/providers.js.map +1 -1
  195. package/dist/dev/runners.d.ts +19 -0
  196. package/dist/dev/runners.d.ts.map +1 -1
  197. package/dist/dev/runtime-container.d.ts.map +1 -1
  198. package/dist/dev/runtime-container.js +2 -2
  199. package/dist/dev/runtime-container.js.map +1 -1
  200. package/dist/dev/runtime-env.d.ts +2 -1
  201. package/dist/dev/runtime-env.d.ts.map +1 -1
  202. package/dist/dev/runtime-env.js +5 -5
  203. package/dist/dev/runtime-env.js.map +1 -1
  204. package/dist/dev/runtime-image.d.ts +2 -2
  205. package/dist/dev/runtime-image.d.ts.map +1 -1
  206. package/dist/dev/runtime-image.js +2 -2
  207. package/dist/dev/runtime-image.js.map +1 -1
  208. package/dist/dev/runtime-registry.d.ts +8 -10
  209. package/dist/dev/runtime-registry.d.ts.map +1 -1
  210. package/dist/dev/runtime-registry.js +27 -27
  211. package/dist/dev/runtime-registry.js.map +1 -1
  212. package/dist/dev/sandbox/index.js +1 -1
  213. package/dist/dev/sandbox/notices.d.ts +2 -0
  214. package/dist/dev/sandbox/notices.d.ts.map +1 -1
  215. package/dist/dev/sandbox/notices.js +5 -2
  216. package/dist/dev/sandbox/notices.js.map +1 -1
  217. package/dist/env/defaults.d.ts.map +1 -1
  218. package/dist/env/defaults.js +3 -1
  219. package/dist/env/defaults.js.map +1 -1
  220. package/dist/env/pack-env-plan.d.ts +4 -0
  221. package/dist/env/pack-env-plan.d.ts.map +1 -1
  222. package/dist/env/pack-env-plan.js +8 -2
  223. package/dist/env/pack-env-plan.js.map +1 -1
  224. package/dist/exports/create.d.ts +2 -0
  225. package/dist/exports/create.d.ts.map +1 -1
  226. package/dist/exports/create.js +10 -2
  227. package/dist/exports/create.js.map +1 -1
  228. package/dist/exports/plan.d.ts.map +1 -1
  229. package/dist/exports/plan.js +32 -0
  230. package/dist/exports/plan.js.map +1 -1
  231. package/dist/feedback/store.d.ts.map +1 -1
  232. package/dist/feedback/store.js +8 -19
  233. package/dist/feedback/store.js.map +1 -1
  234. package/dist/help.d.ts +6 -0
  235. package/dist/help.d.ts.map +1 -1
  236. package/dist/help.js +35 -1
  237. package/dist/help.js.map +1 -1
  238. package/dist/init/agent-access.d.ts +3 -2
  239. package/dist/init/agent-access.d.ts.map +1 -1
  240. package/dist/init/agent-access.js +5 -1
  241. package/dist/init/agent-access.js.map +1 -1
  242. package/dist/init/augment-scaffolder.d.ts +7 -0
  243. package/dist/init/augment-scaffolder.d.ts.map +1 -1
  244. package/dist/init/augment-scaffolder.js +15 -14
  245. package/dist/init/augment-scaffolder.js.map +1 -1
  246. package/dist/init/dependency-specs.d.ts +1 -0
  247. package/dist/init/dependency-specs.d.ts.map +1 -1
  248. package/dist/init/dependency-specs.js +27 -7
  249. package/dist/init/dependency-specs.js.map +1 -1
  250. package/dist/init/java-augment.d.ts +3 -0
  251. package/dist/init/java-augment.d.ts.map +1 -1
  252. package/dist/init/java-augment.js +16 -15
  253. package/dist/init/java-augment.js.map +1 -1
  254. package/dist/init/python-augment.d.ts +3 -0
  255. package/dist/init/python-augment.d.ts.map +1 -1
  256. package/dist/init/python-augment.js +15 -14
  257. package/dist/init/python-augment.js.map +1 -1
  258. package/dist/init/scala-augment.d.ts +8 -1
  259. package/dist/init/scala-augment.d.ts.map +1 -1
  260. package/dist/init/scala-augment.js +32 -17
  261. package/dist/init/scala-augment.js.map +1 -1
  262. package/dist/key/defaults.d.ts.map +1 -1
  263. package/dist/key/defaults.js +6 -1
  264. package/dist/key/defaults.js.map +1 -1
  265. package/dist/key/runners.d.ts +4 -1
  266. package/dist/key/runners.d.ts.map +1 -1
  267. package/dist/license/renew.d.ts +6 -0
  268. package/dist/license/renew.d.ts.map +1 -1
  269. package/dist/license/renew.js +8 -5
  270. package/dist/license/renew.js.map +1 -1
  271. package/dist/main.d.ts +10 -0
  272. package/dist/main.d.ts.map +1 -1
  273. package/dist/main.js +19 -5
  274. package/dist/main.js.map +1 -1
  275. package/dist/output.d.ts +6 -0
  276. package/dist/output.d.ts.map +1 -1
  277. package/dist/output.js +8 -0
  278. package/dist/output.js.map +1 -1
  279. package/dist/parse.d.ts +1 -1
  280. package/dist/parse.d.ts.map +1 -1
  281. package/dist/parse.js +1 -1
  282. package/dist/parse.js.map +1 -1
  283. package/dist/private-file.d.ts +23 -0
  284. package/dist/private-file.d.ts.map +1 -0
  285. package/dist/private-file.js +65 -0
  286. package/dist/private-file.js.map +1 -0
  287. package/dist/progress-head.d.ts +13 -0
  288. package/dist/progress-head.d.ts.map +1 -0
  289. package/dist/progress-head.js +30 -0
  290. package/dist/progress-head.js.map +1 -0
  291. package/dist/progress-lines.d.ts +29 -0
  292. package/dist/progress-lines.d.ts.map +1 -0
  293. package/dist/progress-lines.js +35 -0
  294. package/dist/progress-lines.js.map +1 -0
  295. package/dist/sdk-skills/kindgi-authoring-agents/SKILL.md +6 -6
  296. package/dist/sdk-skills/kindgi-authoring-flows/SKILL.md +1 -1
  297. package/dist/sdk-skills/kindgi-authoring-guardrails/SKILL.md +2 -2
  298. package/dist/sdk-skills/kindgi-authoring-mcp-servers/SKILL.md +1 -1
  299. package/dist/sdk-skills/kindgi-authoring-providers/SKILL.md +13 -3
  300. package/dist/sdk-skills/kindgi-authoring-tools/SKILL.md +47 -9
  301. package/dist/sdk-skills/kindgi-fix-corrections/SKILL.md +262 -0
  302. package/dist/sdk-skills/kindgi-framework-feedback/SKILL.md +1 -1
  303. package/dist/sdk-skills/kindgi-getting-started/SKILL.md +46 -9
  304. package/dist/sdk-skills/kindgi-java-authoring-agents/SKILL.md +5 -5
  305. package/dist/sdk-skills/kindgi-java-authoring-flows/SKILL.md +1 -1
  306. package/dist/sdk-skills/kindgi-java-authoring-guardrails/SKILL.md +1 -1
  307. package/dist/sdk-skills/kindgi-java-authoring-tools/SKILL.md +101 -11
  308. package/dist/sdk-skills/kindgi-java-getting-started/SKILL.md +41 -9
  309. package/dist/sdk-skills/kindgi-python-authoring-agents/SKILL.md +4 -4
  310. package/dist/sdk-skills/kindgi-python-authoring-flows/SKILL.md +1 -1
  311. package/dist/sdk-skills/kindgi-python-authoring-guardrails/SKILL.md +1 -1
  312. package/dist/sdk-skills/kindgi-python-authoring-tools/SKILL.md +53 -10
  313. package/dist/sdk-skills/kindgi-python-getting-started/SKILL.md +42 -11
  314. package/dist/sdk-skills/kindgi-scala-authoring-agents/SKILL.md +5 -5
  315. package/dist/sdk-skills/kindgi-scala-authoring-flows/SKILL.md +1 -1
  316. package/dist/sdk-skills/kindgi-scala-authoring-guardrails/SKILL.md +1 -1
  317. package/dist/sdk-skills/kindgi-scala-authoring-tools/SKILL.md +92 -9
  318. package/dist/sdk-skills/kindgi-scala-getting-started/SKILL.md +41 -9
  319. package/dist/sdk-skills/kindgi-using/SKILL.md +63 -21
  320. package/dist/templates/drupal/AGENTS.md +2 -1
  321. package/dist/templates/follow-up/.nvmrc +1 -0
  322. package/dist/templates/follow-up/AGENTS.md +83 -0
  323. package/dist/templates/follow-up/README.md.tmpl +111 -0
  324. package/dist/templates/follow-up/agents/follow-up/index.test.ts.tmpl +26 -0
  325. package/dist/templates/follow-up/agents/follow-up/index.ts.tmpl +53 -0
  326. package/dist/templates/follow-up/gitignore +8 -0
  327. package/dist/templates/follow-up/kindgi.config.ts.tmpl +45 -0
  328. package/dist/templates/follow-up/package.json.tmpl +30 -0
  329. package/dist/templates/follow-up/pnpm-workspace.yaml +9 -0
  330. package/dist/templates/follow-up/tools/gmail-send/index.test.ts.tmpl +60 -0
  331. package/dist/templates/follow-up/tools/gmail-send/index.ts.tmpl +14 -0
  332. package/dist/templates/follow-up/tsconfig.json.tmpl +27 -0
  333. package/dist/templates/follow-up/vitest.config.ts.tmpl +14 -0
  334. package/dist/templates/java/AGENTS.md +2 -1
  335. package/dist/templates/minimal/AGENTS.md +2 -1
  336. package/dist/templates/python/AGENTS.md +2 -1
  337. package/dist/templates/sample/AGENTS.md +2 -1
  338. package/dist/templates/scala/AGENTS.md +2 -1
  339. package/dist/templates/woocommerce/AGENTS.md +12 -3
  340. package/dist/templates/woocommerce/README.md.tmpl +29 -5
  341. package/dist/templates/woocommerce/agents/store-agent/index.test.ts.tmpl +38 -7
  342. package/dist/templates/woocommerce/agents/store-agent/index.ts.tmpl +7 -12
  343. package/dist/templates/woocommerce/blocks/store-agent-prompt.json.tmpl +10 -0
  344. package/dist/templates/woocommerce/blocks/store-agent-prompt.liquid.tmpl +7 -0
  345. package/dist/templates/woocommerce/kindgi.config.ts.tmpl +1 -0
  346. package/dist/value-target.d.ts +4 -2
  347. package/dist/value-target.d.ts.map +1 -1
  348. package/dist/value-target.js +8 -5
  349. package/dist/value-target.js.map +1 -1
  350. package/package.json +13 -13
@@ -25,7 +25,7 @@
25
25
  */
26
26
  import { lstat, mkdir, readFile, readlink, realpath, stat, writeFile } from 'node:fs/promises';
27
27
  import { basename, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
28
- import { findKindgiConfig, resolveDiscovery, resolvePackEnv, } from '@kindgi/handler-runtime';
28
+ import { codePatterns, findKindgiConfig, resolveDiscovery, resolvePackEnv, } from '@kindgi/handler-runtime';
29
29
  import { hostedApiAddress } from '../api-address.js';
30
30
  import { checkAptPackages } from '../build/apt.js';
31
31
  import { PACK_SERVICE_COMMAND } from '../build/containerfile.js';
@@ -37,6 +37,7 @@ import { readImageConfig } from '../build/image-config.js';
37
37
  import { checkIntegrity } from '../build/integrity.js';
38
38
  import { DEFAULT_JAVA_BUILD_IMAGE_REF, DEFAULT_JAVA_RUNTIME_IMAGE_REF, JAVA_PACK_SERVICE_COMMAND, collectJavaContextFiles, } from '../build/java-image.js';
39
39
  import { nodeBaseImageFor } from '../build/node-image.js';
40
+ import { checkPackBlocks, packIndexerName } from '../build/pack-blocks.js';
40
41
  import { resolvePackRoots } from '../build/pack-root.js';
41
42
  import { DEFAULT_PYTHON_BASE_IMAGE_REF, DEFAULT_UV_IMAGE_REF, PYTHON_LOCKFILES, PYTHON_PACK_SERVICE_COMMAND, collectPythonContextFiles, } from '../build/python-image.js';
42
43
  import { DEFAULT_SCALA_BUILD_IMAGE_REF, SCALA_PACK_SERVICE_COMMAND, collectScalaContextFiles, } from '../build/scala-image.js';
@@ -44,7 +45,9 @@ import { resolvePackJava, resolvePackPython, resolvePackScala } from '../dev/pac
44
45
  import { renderJson } from '../output.js';
45
46
  import { loadPackConfig } from '../pack-config.js';
46
47
  import { isPackageVersion } from '../package-manager.js';
48
+ import { progressLines } from '../progress-lines.js';
47
49
  import { isWait, sendWaitingOutRateLimits } from '../rate-limit-wait.js';
50
+ import { CLI_VERSION } from '../version-info.js';
48
51
  import { timeFlagValue } from './helpers.js';
49
52
  /**
50
53
  * The project (id or slug) a pack config names for an environment, or
@@ -148,9 +151,13 @@ export const buildCommand = {
148
151
  },
149
152
  path: { type: 'string', description: 'The pack root. Default: the current directory.' },
150
153
  },
151
- run: async (ctx) => runBuild(ctx),
154
+ run: async (ctx) => runBuild(ctx, progressLines(ctx.progress, ctx.globals.format === 'quiet')),
152
155
  };
153
- export async function runBuild(ctx) {
156
+ /**
157
+ * `kindgi build`. `out` is where its lines go: the command's own, or
158
+ * `kindgi deploy`'s, for its inline build.
159
+ */
160
+ export async function runBuild(ctx, out) {
154
161
  const runners = ctx.buildRunners;
155
162
  if (runners === undefined) {
156
163
  return {
@@ -165,11 +172,8 @@ export async function runBuild(ctx) {
165
172
  return parsed;
166
173
  const args = parsed.args;
167
174
  if (args.local)
168
- return runLocalBuild(ctx, runners, args);
169
- const banner = [];
170
- const lines = (s) => {
171
- banner.push(s);
172
- };
175
+ return runLocalBuild(ctx, runners, args, out);
176
+ const lines = out.line;
173
177
  lines('');
174
178
  lines(` Environment: ${args.envName}`);
175
179
  lines(` Build: ${args.hosted ? `hosted (${args.endpoint})` : args.endpoint}`);
@@ -181,16 +185,16 @@ export async function runBuild(ctx) {
181
185
  // ---- 1. Local indexer pass ------------------------------------------
182
186
  const expectedIndexPath = join(args.outDir, 'expected-index.json');
183
187
  await mkdir(args.outDir, { recursive: true });
184
- const prepared = await prepareTarball(ctx, runners, args, expectedIndexPath, lines);
188
+ const prepared = await prepareTarball(ctx, runners, args, expectedIndexPath, out);
185
189
  if (prepared.kind === 'error')
186
- return prepared;
190
+ return withBanner(prepared, out);
187
191
  const { tarball, tarballHash, counts } = prepared;
188
192
  lines('');
189
193
  // ---- 6. POST /v1/build + SSE stream ---------------------------------
190
194
  if (args.hosted) {
191
195
  const tooLarge = hostedUploadTooLarge(tarball.bytes.length);
192
196
  if (tooLarge !== undefined)
193
- return failure(tooLarge);
197
+ return withBanner(failure(tooLarge), out);
194
198
  }
195
199
  const packId = args.config.pack?.id;
196
200
  lines(' Uploading to build service');
@@ -225,7 +229,7 @@ export async function runBuild(ctx) {
225
229
  : undefined);
226
230
  if ('thrown' in sent) {
227
231
  if (sent.thrown instanceof BuildServiceRefusal) {
228
- return failure(describeBuildRefusal(sent.thrown));
232
+ return withBanner(failure(describeBuildRefusal(sent.thrown)), out);
229
233
  }
230
234
  throw sent.thrown;
231
235
  }
@@ -257,19 +261,19 @@ export async function runBuild(ctx) {
257
261
  }
258
262
  catch (err) {
259
263
  if (err instanceof BuildServiceRefusal) {
260
- return failure(describeBuildRefusal(err));
264
+ return withBanner(failure(describeBuildRefusal(err)), out);
261
265
  }
262
- return failure(`${err.message}\n`);
266
+ return withBanner(failure(`${err.message}\n`), out);
263
267
  }
264
268
  }
265
269
  if (terminal.status === 'failed') {
266
- return failure(`Build failed: [${terminal.error?.code ?? 'unknown'}] ${terminal.error?.message ?? 'no message'}\n`);
270
+ return withBanner(failure(`Build failed: [${terminal.error?.code ?? 'unknown'}] ${terminal.error?.message ?? 'no message'}\n`), out);
267
271
  }
268
272
  if (terminal.imageRef === undefined ||
269
273
  terminal.imageDigest === undefined ||
270
274
  terminal.indexJson === undefined ||
271
275
  terminal.indexHash === undefined) {
272
- return failure('Build terminal payload missing required fields (imageRef / imageDigest / indexJson / indexHash).\n');
276
+ return withBanner(failure('Build terminal payload missing required fields (imageRef / imageDigest / indexJson / indexHash).\n'), out);
273
277
  }
274
278
  lines(` ✓ Build complete (${terminal.imageRef})`);
275
279
  for (const line of closureSummary(captured))
@@ -281,14 +285,14 @@ export async function runBuild(ctx) {
281
285
  let serverBytes;
282
286
  lines(' Verifying build output');
283
287
  if (args.skipIntegrityGate) {
284
- lines(' ⚠ Integrity gate SKIPPED — --skip-integrity-gate. Signature will attest to');
285
- lines(' the server-reported hash without local re-verification. NOT RECOMMENDED.');
288
+ out.problem(' ⚠ Integrity gate SKIPPED — --skip-integrity-gate. Signature will attest to');
289
+ out.problem(' the server-reported hash without local re-verification. NOT RECOMMENDED.');
286
290
  }
287
291
  else {
288
292
  if (args.skipImagePull || runners.pullImageIndex === undefined) {
289
- lines(' ⚠ Image pull SKIPPED — hash-only comparison. Byte-diff path unavailable');
290
- lines(' (requires Docker). CI environments where this is expected can safely');
291
- lines(' omit --skip-image-pull warnings.');
293
+ out.problem(' ⚠ Image pull SKIPPED — hash-only comparison. Byte-diff path unavailable');
294
+ out.problem(' (requires Docker). CI environments where this is expected can safely');
295
+ out.problem(' omit --skip-image-pull warnings.');
292
296
  }
293
297
  else {
294
298
  try {
@@ -301,8 +305,8 @@ export async function runBuild(ctx) {
301
305
  serverBytes = pulled.bytes;
302
306
  }
303
307
  catch (err) {
304
- lines(` ⚠ docker pull failed: ${err.message}`);
305
- lines(' Falling back to hash-only comparison.');
308
+ out.problem(` ⚠ docker pull failed: ${err.message}`);
309
+ out.problem(' Falling back to hash-only comparison.');
306
310
  }
307
311
  }
308
312
  const check = checkIntegrity({
@@ -312,7 +316,7 @@ export async function runBuild(ctx) {
312
316
  ...(serverBytes !== undefined && { serverBytes }),
313
317
  });
314
318
  if (!check.ok) {
315
- return failure(`Integrity gate FAILED — refusing to sign.\n\n${check.reason ?? 'unknown reason'}\n`);
319
+ return withBanner(failure(`Integrity gate FAILED — refusing to sign.\n\n${check.reason ?? 'unknown reason'}\n`), out);
316
320
  }
317
321
  lines(` ✓ indexHash matches local indexer output (${terminal.indexHash.slice(0, 14)}…)`);
318
322
  if (serverBytes !== undefined) {
@@ -321,7 +325,7 @@ export async function runBuild(ctx) {
321
325
  }
322
326
  lines('');
323
327
  // ---- 8. Sign + 9. emit deploy-envelope.json ------------------------------
324
- const written = await signAndWriteEnvelope(runners, args, lines, {
328
+ const written = await signAndWriteEnvelope(runners, args, out, {
325
329
  imageRef: terminal.imageRef,
326
330
  imageDigest: terminal.imageDigest,
327
331
  index: terminal.indexJson,
@@ -329,7 +333,7 @@ export async function runBuild(ctx) {
329
333
  ...(terminal.buildLogsUrl !== undefined && { buildLogsUrl: terminal.buildLogsUrl }),
330
334
  });
331
335
  if (written.kind === 'error')
332
- return written;
336
+ return withBanner(written, out);
333
337
  const { envelopePath, signature } = written;
334
338
  const summary = {
335
339
  envName: args.envName,
@@ -349,10 +353,7 @@ export async function runBuild(ctx) {
349
353
  imagePullSkipped: args.skipImagePull || runners.pullImageIndex === undefined,
350
354
  };
351
355
  const rendered = renderJson(summary, ctx.globals.format);
352
- return {
353
- kind: 'ok',
354
- rendered: { stdout: rendered.stdout, stderr: `${banner.join('\n')}\n` },
355
- };
356
+ return { kind: 'ok', rendered: { stdout: rendered.stdout, stderr: out.kept() } };
356
357
  }
357
358
  // ---------------------------------------------------------------------
358
359
  // --local: build with this machine's Docker
@@ -367,14 +368,11 @@ export async function runBuild(ctx) {
367
368
  * `--push`, the image goes to the registry, and is signed into an
368
369
  * envelope for `kindgi deploy`.
369
370
  */
370
- async function runLocalBuild(ctx, runners, args) {
371
+ async function runLocalBuild(ctx, runners, args, out) {
371
372
  if (runners.dockerBuild === undefined || runners.pullImageIndex === undefined) {
372
373
  return failure('kindgi build --local needs Docker runners; rebuild the CLI.\n');
373
374
  }
374
- const banner = [];
375
- const lines = (s) => {
376
- banner.push(s);
377
- };
375
+ const lines = out.line;
378
376
  const pushTo = args.pushRepository;
379
377
  lines('');
380
378
  lines(pushTo !== undefined
@@ -385,9 +383,9 @@ async function runLocalBuild(ctx, runners, args) {
385
383
  lines(` Output: ${args.outDir}`);
386
384
  const expectedIndexPath = join(args.outDir, 'expected-index.json');
387
385
  await mkdir(args.outDir, { recursive: true });
388
- const context = await preparePackContext(ctx, runners, args, expectedIndexPath, lines);
386
+ const context = await preparePackContext(ctx, runners, args, expectedIndexPath, out);
389
387
  if (context.kind === 'error')
390
- return withBanner(context, banner);
388
+ return withBanner(context, out);
391
389
  const expectedBytes = new Uint8Array(await readFile(expectedIndexPath));
392
390
  const packId = JSON.parse(new TextDecoder().decode(expectedBytes))
393
391
  .packId;
@@ -408,11 +406,11 @@ async function runLocalBuild(ctx, runners, args) {
408
406
  },
409
407
  });
410
408
  if (built.kind === 'err')
411
- return withBanner(failure(`Image build failed: ${built.message}\n`), banner);
409
+ return withBanner(failure(`Image build failed: ${built.message}\n`), out);
412
410
  for (const line of closureSummary(buildLog))
413
411
  lines(line);
414
412
  if (pushTo !== undefined && built.digest === undefined) {
415
- return withBanner(failure(`The push of ${tag} reported no digest.\n`), banner);
413
+ return withBanner(failure(`The push of ${tag} reported no digest.\n`), out);
416
414
  }
417
415
  // Pushed: the image is the registry's, by digest; loaded: the local tag.
418
416
  const imageRef = pushTo !== undefined ? `${pushTo}@${built.digest}` : tag;
@@ -436,19 +434,19 @@ async function runLocalBuild(ctx, runners, args) {
436
434
  serverBytes: pulled.bytes,
437
435
  });
438
436
  if (!check.ok) {
439
- return withBanner(failure(`Integrity gate FAILED: the image's index isn't the local one.\n\n${check.reason ?? ''}\n`), banner);
437
+ return withBanner(failure(`Integrity gate FAILED: the image's index isn't the local one.\n\n${check.reason ?? ''}\n`), out);
440
438
  }
441
439
  lines(' ✓ /app/index.json in the image matches the local index byte for byte');
442
440
  lines('');
443
441
  if (pushTo !== undefined && built.digest !== undefined) {
444
- const written = await signAndWriteEnvelope(runners, args, lines, {
442
+ const written = await signAndWriteEnvelope(runners, args, out, {
445
443
  imageRef,
446
444
  imageDigest: built.digest,
447
445
  index: JSON.parse(new TextDecoder().decode(expectedBytes)),
448
446
  indexHash: expectedHash,
449
447
  });
450
448
  if (written.kind === 'error')
451
- return withBanner(written, banner);
449
+ return withBanner(written, out);
452
450
  const rendered = renderJson({
453
451
  envName: args.envName,
454
452
  envelopePath: written.envelopePath,
@@ -463,7 +461,7 @@ async function runLocalBuild(ctx, runners, args) {
463
461
  ...(written.signature !== undefined && { signerKeyId: written.signature.keyId }),
464
462
  local: true,
465
463
  }, ctx.globals.format);
466
- return { kind: 'ok', rendered: { stdout: rendered.stdout, stderr: `${banner.join('\n')}\n` } };
464
+ return { kind: 'ok', rendered: { stdout: rendered.stdout, stderr: out.kept() } };
467
465
  }
468
466
  lines(' Run it:');
469
467
  lines(` docker run --rm -p 8080:8080 -e KINDGI_PACK_SERVICE_TOKEN=<token> --env-file <the pack's env> ${tag}`);
@@ -485,18 +483,19 @@ async function runLocalBuild(ctx, runners, args) {
485
483
  indexCounts: context.counts,
486
484
  local: true,
487
485
  }, ctx.globals.format);
488
- return { kind: 'ok', rendered: { stdout: rendered.stdout, stderr: `${banner.join('\n')}\n` } };
486
+ return { kind: 'ok', rendered: { stdout: rendered.stdout, stderr: out.kept() } };
489
487
  }
490
488
  /**
491
489
  * Sign the image (Ed25519 over imageDigest, artifactVersion, indexHash,
492
490
  * tenantId, publishedAt) and write `deploy-envelope.json` for
493
491
  * `kindgi deploy`: the build service's path and `--local --push` alike.
494
492
  */
495
- async function signAndWriteEnvelope(runners, args, lines, image) {
493
+ async function signAndWriteEnvelope(runners, args, out, image) {
494
+ const lines = out.line;
496
495
  let signature;
497
496
  if (args.skipSign) {
498
- lines(' ⚠ Signing SKIPPED — --skip-sign. Emitted envelope is unsigned; deploy will refuse');
499
- lines(' it. Use only for CI that signs elsewhere.');
497
+ out.problem(' ⚠ Signing SKIPPED — --skip-sign. Emitted envelope is unsigned; deploy will refuse');
498
+ out.problem(' it. Use only for CI that signs elsewhere.');
500
499
  }
501
500
  else if (args.signingKeyPath === undefined) {
502
501
  return failure(noSigningKey(undefined));
@@ -535,17 +534,17 @@ async function signAndWriteEnvelope(runners, args, lines, image) {
535
534
  lines('');
536
535
  return { kind: 'ok', envelopePath, signature };
537
536
  }
538
- /** A failure that still shows what the build did up to it. */
539
- function withBanner(result, banner) {
540
- return { ...result, stderr: `${banner.join('\n')}\n${result.stderr}` };
537
+ /** A failure that still shows what the build did up to it (the lines kept, when not streamed). */
538
+ function withBanner(result, out) {
539
+ return { ...result, stderr: `${out.kept()}${result.stderr}` };
541
540
  }
542
541
  /** The pack's image context, by the pack's language. */
543
- function preparePackContext(ctx, runners, args, expectedIndexPath, lines) {
542
+ function preparePackContext(ctx, runners, args, expectedIndexPath, out) {
544
543
  if (args.language === 'java' || args.language === 'scala')
545
- return prepareJvmContext(ctx, runners, args, args.language, expectedIndexPath, lines);
544
+ return prepareJvmContext(ctx, runners, args, args.language, expectedIndexPath, out);
546
545
  return args.language === 'python'
547
- ? preparePythonContext(ctx, runners, args, expectedIndexPath, lines)
548
- : prepareNodeContext(runners, args, expectedIndexPath, lines);
546
+ ? preparePythonContext(ctx, runners, args, expectedIndexPath, out)
547
+ : prepareNodeContext(runners, args, expectedIndexPath, out);
549
548
  }
550
549
  /**
551
550
  * A pnpm install with no `packageManager` gets the host's pnpm version:
@@ -580,7 +579,8 @@ async function withHostPnpm(runners, install) {
580
579
  * base image, the bundles, the local index over them, the Containerfile,
581
580
  * and the build context (`<out>/context`).
582
581
  */
583
- async function prepareNodeContext(runners, args, expectedIndexPath, lines) {
582
+ async function prepareNodeContext(runners, args, expectedIndexPath, out) {
583
+ const lines = out.line;
584
584
  const hostInstall = await resolveHostInstall(args.packDir);
585
585
  if (hostInstall.kind === 'err')
586
586
  return failure(`${hostInstall.message}\n`);
@@ -643,7 +643,8 @@ async function prepareNodeContext(runners, args, expectedIndexPath, lines) {
643
643
  const dependencies = dependenciesStep(image, bundle.computedImports, args.packDir);
644
644
  if (dependencies.kind === 'refuse')
645
645
  return failure(dependencies.message);
646
- lines(dependencies.lines.join('\n'));
646
+ lines(dependencies.mode);
647
+ warn(out, dependencies.warnings);
647
648
  // Only what the pack loads: the install cut down to it, or the full one trimmed after, and why.
648
649
  let imageInstall = install;
649
650
  let trimmedBecause;
@@ -677,9 +678,12 @@ async function prepareNodeContext(runners, args, expectedIndexPath, lines) {
677
678
  .map((e) => ` [${e.code}] ${e.message}`)
678
679
  .join('\n')}\n`);
679
680
  }
681
+ const blocks = await checkBuildBlocks(args, localIndex.counts, expectedIndexPath);
682
+ if (blocks.kind === 'err')
683
+ return failure(`${blocks.message}\n`);
680
684
  lines(` ✓ ${localIndex.counts.tools} tools, ${localIndex.counts.guardrails} guardrails, ` +
681
- `${localIndex.counts.agents} agents, ${localIndex.counts.flows} flows indexed`);
682
- printIndexWarnings(localIndex, lines);
685
+ `${localIndex.counts.agents} agents, ${localIndex.counts.flows} flows${blocksCounted(localIndex.counts)} indexed`);
686
+ printIndexWarnings(localIndex, out.problem);
683
687
  // ---- 3. Containerfile + context --------------------------------------
684
688
  const containerfilePath = join(args.outDir, 'Containerfile');
685
689
  await runners.writeContainerfile({
@@ -691,6 +695,7 @@ async function prepareNodeContext(runners, args, expectedIndexPath, lines) {
691
695
  install: imageInstall,
692
696
  image,
693
697
  hasIncludes: includeFiles.files.length > 0,
698
+ hasBlocks: blocks.files.length > 0,
694
699
  });
695
700
  const contextDir = join(args.outDir, 'context');
696
701
  await runners.writeContext({
@@ -701,14 +706,16 @@ async function prepareNodeContext(runners, args, expectedIndexPath, lines) {
701
706
  containerfilePath,
702
707
  includes: includeFiles.files,
703
708
  extensionFiles: image.contextFiles,
709
+ blockFiles: blocks.files,
704
710
  });
705
- lines(` ✓ Context: ${imageInstall.files.length} install file(s), the bundles${includeFiles.files.length > 0 ? `, ${includeFiles.files.length} bundle.include file(s)` : ''}; no pack source`);
711
+ lines(` ✓ Context: ${imageInstall.files.length} install file(s), the bundles${includeFiles.files.length > 0 ? `, ${includeFiles.files.length} bundle.include file(s)` : ''}${blocks.files.length > 0 ? `, ${blocks.files.length} block file(s) for the indexer` : ''}; no pack source`);
706
712
  if (install.secrets.length > 0) {
707
713
  lines(` ✓ ${install.secrets.map((s) => s.file).join(', ')}: read by the install as a build secret, never in the image`);
708
714
  }
709
715
  lines(installLine(imageInstall, image.steps, trimmedBecause));
710
716
  for (const line of skippedScriptLines(install.skippedScripts))
711
717
  lines(line);
718
+ warn(out, patchPackageWarnings(install.skippedScripts));
712
719
  const secrets = install.secrets.map((secret) => ({
713
720
  id: secret.id,
714
721
  src: join(install.root, secret.file),
@@ -737,30 +744,34 @@ export function installLine(install, steps, trimmedBecause) {
737
744
  ? ` ✓ Install: ${what}`
738
745
  : ` ✓ Install: ${what}, then trimmed to what the pack loads\n It downloads the app's whole install first, since ${trimmedBecause}.`;
739
746
  }
740
- /**
741
- * What the image leaves out of the app's own install scripts, and what
742
- * to do when one of them is something the image needs: `patch-package`
743
- * (pnpm's own patches are applied by the install).
744
- */
747
+ /** What the image leaves out of the app's own install scripts. */
745
748
  export function skippedScriptLines(skipped) {
746
749
  if (skipped.length === 0)
747
750
  return [];
748
- const where = (s) => s.manifest === 'package.json' ? s.name : `${s.manifest} ${s.name}`;
749
- const lines = [
750
- ` ✓ The app's own install scripts don't run in the image: ${skipped.map((s) => `${where(s)} (\`${s.command}\`)`).join(', ')}`,
751
+ return [
752
+ ` ✓ The app's own install scripts don't run in the image: ${skipped.map((s) => `${scriptWhere(s)} (\`${s.command}\`)`).join(', ')}`,
751
753
  ];
752
- for (const s of skipped.filter((s) => /\bpatch-package\b/.test(s.command))) {
753
- lines.push(` ⚠ ${where(s)} runs patch-package, so its patches aren't applied in the image. Apply them with a build step: defineBuildExtension({ name: 'patch-package', contextFiles: [<each file in patches/>], postInstall: [{ bin: 'patch-package' }] }) in image.extensions (@kindgi/sdk/build). With pnpm, pnpm patch applies them in the install itself.`);
754
- }
755
- return lines;
754
+ }
755
+ /**
756
+ * What to do when a skipped script is something the image needs:
757
+ * `patch-package` (pnpm's own patches are applied by the install). A
758
+ * warning each, after `skippedScriptLines`.
759
+ */
760
+ export function patchPackageWarnings(skipped) {
761
+ return skipped
762
+ .filter((s) => /\bpatch-package\b/.test(s.command))
763
+ .map((s) => ` ⚠ ${scriptWhere(s)} runs patch-package, so its patches aren't applied in the image. Apply them with a build step: defineBuildExtension({ name: 'patch-package', contextFiles: [<each file in patches/>], postInstall: [{ bin: 'patch-package' }] }) in image.extensions (@kindgi/sdk/build). With pnpm, pnpm patch applies them in the install itself.`);
764
+ }
765
+ function scriptWhere(s) {
766
+ return s.manifest === 'package.json' ? s.name : `${s.manifest} ${s.name}`;
756
767
  }
757
768
  /** A pack's context, tarred for the build service. */
758
- async function prepareTarball(ctx, runners, args, expectedIndexPath, lines) {
759
- const context = await preparePackContext(ctx, runners, args, expectedIndexPath, lines);
769
+ async function prepareTarball(ctx, runners, args, expectedIndexPath, out) {
770
+ const context = await preparePackContext(ctx, runners, args, expectedIndexPath, out);
760
771
  if (context.kind === 'error')
761
772
  return context;
762
773
  if (context.secrets.length > 0) {
763
- lines(` ⚠ The build service gets no build secrets: an install that needs ${context.secrets.map((s) => s.file).join(', ')} (a private registry) fails there. \`kindgi build --local\` passes them.`);
774
+ out.problem(` ⚠ The build service gets no build secrets: an install that needs ${context.secrets.map((s) => s.file).join(', ')} (a private registry) fails there. \`kindgi build --local\` passes them.`);
764
775
  }
765
776
  const tarballPath = join(args.outDir, 'pack.tgz');
766
777
  const tarball = await runners.tarPack({
@@ -768,7 +779,7 @@ async function prepareTarball(ctx, runners, args, expectedIndexPath, lines) {
768
779
  outputPath: tarballPath,
769
780
  });
770
781
  const tarballHash = await sha256Hex(tarball.bytes);
771
- lines(` ✓ Emitted ${tarballPath} (${humanBytes(tarball.size)}, ${tarballHash.slice(0, 14)}…)`);
782
+ out.line(` ✓ Emitted ${tarballPath} (${humanBytes(tarball.size)}, ${tarballHash.slice(0, 14)}…)`);
772
783
  return { kind: 'ok', tarball, tarballHash, counts: context.counts };
773
784
  }
774
785
  /**
@@ -776,7 +787,8 @@ async function prepareTarball(ctx, runners, args, expectedIndexPath, lines) {
776
787
  * Containerfile (`build/python-image.ts`), the pack root as the context
777
788
  * (`<out>/context`).
778
789
  */
779
- async function preparePythonContext(ctx, runners, args, expectedIndexPath, lines) {
790
+ async function preparePythonContext(ctx, runners, args, expectedIndexPath, out) {
791
+ const lines = out.line;
780
792
  const python = runners.python;
781
793
  if (python === undefined)
782
794
  return failure('This CLI cannot build Python packs (no Python build runners).\n');
@@ -805,10 +817,13 @@ async function preparePythonContext(ctx, runners, args, expectedIndexPath, lines
805
817
  .map((e) => ` [${e.code}] ${e.message}`)
806
818
  .join('\n')}\n`);
807
819
  }
820
+ const blocks = await checkBuildBlocks(args, localIndex.counts, expectedIndexPath);
821
+ if (blocks.kind === 'err')
822
+ return failure(`${blocks.message}\n`);
808
823
  lines(` Indexing (Python — ${interpreter.value.join(' ')})`);
809
824
  lines(` ✓ ${localIndex.counts.tools} tools, ${localIndex.counts.guardrails} guardrails, ` +
810
- `${localIndex.counts.agents} agents, ${localIndex.counts.flows} flows discovered`);
811
- printIndexWarnings(localIndex, lines);
825
+ `${localIndex.counts.agents} agents, ${localIndex.counts.flows} flows${blocksCounted(localIndex.counts)} discovered`);
826
+ printIndexWarnings(localIndex, out.problem);
812
827
  const packFiles = await collectPythonContextFiles(args.packDir);
813
828
  if (packFiles.kind === 'error')
814
829
  return failure(`${packFiles.message}\n`);
@@ -848,7 +863,8 @@ async function preparePythonContext(ctx, runners, args, expectedIndexPath, lines
848
863
  * (`build/java-image.ts`, `build/scala-image.ts`), the pack root as the
849
864
  * context (`<out>/context`).
850
865
  */
851
- async function prepareJvmContext(ctx, runners, args, language, expectedIndexPath, lines) {
866
+ async function prepareJvmContext(ctx, runners, args, language, expectedIndexPath, out) {
867
+ const lines = out.line;
852
868
  const java = runners.jvm;
853
869
  const name = language === 'java' ? 'Java' : 'Scala';
854
870
  if (java === undefined)
@@ -894,11 +910,14 @@ async function prepareJvmContext(ctx, runners, args, language, expectedIndexPath
894
910
  ...(declared.value?.required ?? []),
895
911
  ...(declared.value?.optional ?? []),
896
912
  ].sort();
913
+ const blocks = await checkBuildBlocks(args, localIndex.counts, expectedIndexPath);
914
+ if (blocks.kind === 'err')
915
+ return failure(`${blocks.message}\n`);
897
916
  const tool = code.language === 'java' ? code.maven : code.sbt;
898
917
  lines(` Indexing (${name} — ${code.javaHome ?? code.java}; ${tool.join(' ')})`);
899
918
  lines(` ✓ ${localIndex.counts.tools} tools, ${localIndex.counts.guardrails} guardrails, ` +
900
- `${localIndex.counts.agents} agents, ${localIndex.counts.flows} flows discovered`);
901
- printIndexWarnings(localIndex, lines);
919
+ `${localIndex.counts.agents} agents, ${localIndex.counts.flows} flows${blocksCounted(localIndex.counts)} discovered`);
920
+ printIndexWarnings(localIndex, out.problem);
902
921
  const packFiles = language === 'java'
903
922
  ? await collectJavaContextFiles(args.packDir)
904
923
  : await collectScalaContextFiles(args.packDir);
@@ -1307,12 +1326,35 @@ function renderExternalsSummary(externals) {
1307
1326
  * esbuild bundler to walk. Handles both shapes:
1308
1327
  *
1309
1328
  * discovery: { tools: 'tools/**\/*.ts', ... } → ['tools', ...]
1310
- * discovery: { tools: 'kindgi/tools/** The config's discovery patterns with defaults filled in — what the indexer uses. */
1329
+ * discovery: { tools: 'kindgi/tools/**
1330
+ * The config's code discovery patterns with defaults filled in — the
1331
+ * files the indexer loads, and so the bundler's entries. Not the blocks
1332
+ * pattern: blocks are data, read from the pack's files.
1333
+ */
1311
1334
  export function discoveryPatternsOf(config) {
1335
+ return codePatterns(discoveryOf(config));
1336
+ }
1337
+ /** The config's discovery with the defaults for the pack's language filled in. */
1338
+ function discoveryOf(config, language) {
1312
1339
  const discovery = config.discovery;
1313
- return Object.values(resolveDiscovery(typeof discovery === 'object' && discovery !== null
1340
+ return resolveDiscovery(typeof discovery === 'object' && discovery !== null
1314
1341
  ? discovery
1315
- : undefined));
1342
+ : undefined, language);
1343
+ }
1344
+ /** The pack's blocks after its local index (`checkPackBlocks`), in every language. */
1345
+ function checkBuildBlocks(args, counts, indexPath) {
1346
+ return checkPackBlocks({
1347
+ packDir: args.packDir,
1348
+ pattern: discoveryOf(args.config, args.language).blocks,
1349
+ indexPath,
1350
+ blocksCounted: counts.blocks !== undefined,
1351
+ indexer: packIndexerName(args.language),
1352
+ release: CLI_VERSION,
1353
+ });
1354
+ }
1355
+ /** `, 2 blocks` for the indexed line, when the pack has any. */
1356
+ function blocksCounted(counts) {
1357
+ return counts.blocks !== undefined && counts.blocks > 0 ? `, ${counts.blocks} blocks` : '';
1316
1358
  }
1317
1359
  /**
1318
1360
  * An unpinned build's artifact version and publish time, from one clock
@@ -1353,10 +1395,15 @@ async function isFile(path) {
1353
1395
  return false;
1354
1396
  }
1355
1397
  }
1398
+ /** Each of `warnings`, a line each: said under `--quiet` too. */
1399
+ function warn(out, warnings) {
1400
+ for (const w of warnings)
1401
+ out.problem(w);
1402
+ }
1356
1403
  /** The indexer's warnings, a line each: what the pack should change, though it builds as it is. */
1357
- function printIndexWarnings(result, lines) {
1404
+ function printIndexWarnings(result, problem) {
1358
1405
  for (const w of result.warnings ?? [])
1359
- lines(` ⚠ ${w.message}`);
1406
+ problem(` ⚠ ${w.message}`);
1360
1407
  }
1361
1408
  /** The image's dependencies, as the build says them (`image.dependencies`). */
1362
1409
  function renderDependenciesMode(image) {
@@ -1366,13 +1413,13 @@ function renderDependenciesMode(image) {
1366
1413
  const kept = [...image.keep, ...image.keepIfInstalled];
1367
1414
  return ` ✓ Dependencies: only what the pack loads (image.dependencies: 'loaded')${kept.length > 0 ? `, and ${kept.join(', ')}` : ''}`;
1368
1415
  }
1369
- /** The image's dependencies, said, and with `'loaded'` the computed-import check. */
1416
+ /** The image's dependencies, said, and with `'loaded'` the computed-import check's warnings. */
1370
1417
  function dependenciesStep(image, computed, packDir) {
1371
1418
  const mode = renderDependenciesMode(image);
1372
1419
  if (image.dependencies === 'all')
1373
- return { kind: 'ok', lines: [mode] };
1420
+ return { kind: 'ok', mode, warnings: [] };
1374
1421
  const check = computedImportsCheck(computed ?? [], image.keep, packDir);
1375
- return check.kind === 'refuse' ? check : { kind: 'ok', lines: [mode, ...check.lines] };
1422
+ return check.kind === 'refuse' ? check : { kind: 'ok', mode, warnings: check.lines };
1376
1423
  }
1377
1424
  /**
1378
1425
  * With `'loaded'`: a computed `require(x)` / `import(x)` in the pack's