@cyanautomation/kaseki-agent 1.4.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 (459) hide show
  1. package/.dockerignore +54 -0
  2. package/.eslintignore +11 -0
  3. package/.eslintrc.json +95 -0
  4. package/.github/ISSUE_TEMPLATE/bug_report.md +53 -0
  5. package/.github/ISSUE_TEMPLATE/feature_request.md +53 -0
  6. package/.github/ISSUE_TEMPLATE/security.md +51 -0
  7. package/.github/PULL_REQUEST_TEMPLATE/default.md +71 -0
  8. package/.github/dependabot.yml +38 -0
  9. package/.github/skills/dependency-cache-optimization/SKILL.md +526 -0
  10. package/.github/skills/docker-image-management/SKILL.md +532 -0
  11. package/.github/skills/frontend-design/SKILL.md +782 -0
  12. package/.github/skills/prompt-engineering/SKILL.md +360 -0
  13. package/.github/skills/quality-gate-config/SKILL.md +591 -0
  14. package/.github/skills/result-report-analysis/SKILL.md +576 -0
  15. package/.github/skills/test-automation/SKILL.md +593 -0
  16. package/.github/skills/workflow-diagnosis/SKILL.md +468 -0
  17. package/.github/workflows/build-docker-image.yml +453 -0
  18. package/.github/workflows/release.yml +68 -0
  19. package/.releaserc.json +135 -0
  20. package/CHANGELOG.md +117 -0
  21. package/CLAUDE.md +336 -0
  22. package/CONTRIBUTING.md +339 -0
  23. package/Dockerfile +217 -0
  24. package/README.md +1527 -0
  25. package/STYLE.md +521 -0
  26. package/add-js-extensions.d.ts +9 -0
  27. package/add-js-extensions.d.ts.map +1 -0
  28. package/add-js-extensions.js.map +1 -0
  29. package/dist/add-js-extensions.d.ts +9 -0
  30. package/dist/add-js-extensions.d.ts.map +1 -0
  31. package/dist/add-js-extensions.js +52 -0
  32. package/dist/add-js-extensions.js.map +1 -0
  33. package/dist/ansi-colors.d.ts +26 -0
  34. package/dist/ansi-colors.d.ts.map +1 -0
  35. package/dist/ansi-colors.js +51 -0
  36. package/dist/ansi-colors.js.map +1 -0
  37. package/dist/cli/BaseCommand.d.ts +18 -0
  38. package/dist/cli/BaseCommand.d.ts.map +1 -0
  39. package/dist/cli/BaseCommand.js +31 -0
  40. package/dist/cli/BaseCommand.js.map +1 -0
  41. package/dist/cli/KasekiCLI.d.ts +30 -0
  42. package/dist/cli/KasekiCLI.d.ts.map +1 -0
  43. package/dist/cli/KasekiCLI.js +134 -0
  44. package/dist/cli/KasekiCLI.js.map +1 -0
  45. package/dist/cli/commands/ConfigCommand.d.ts +13 -0
  46. package/dist/cli/commands/ConfigCommand.d.ts.map +1 -0
  47. package/dist/cli/commands/ConfigCommand.js +131 -0
  48. package/dist/cli/commands/ConfigCommand.js.map +1 -0
  49. package/dist/cli/commands/DoctorCommand.d.ts +45 -0
  50. package/dist/cli/commands/DoctorCommand.d.ts.map +1 -0
  51. package/dist/cli/commands/DoctorCommand.js +309 -0
  52. package/dist/cli/commands/DoctorCommand.js.map +1 -0
  53. package/dist/cli/commands/ListCommand.d.ts +9 -0
  54. package/dist/cli/commands/ListCommand.d.ts.map +1 -0
  55. package/dist/cli/commands/ListCommand.js +81 -0
  56. package/dist/cli/commands/ListCommand.js.map +1 -0
  57. package/dist/cli/commands/ReportCommand.d.ts +9 -0
  58. package/dist/cli/commands/ReportCommand.d.ts.map +1 -0
  59. package/dist/cli/commands/ReportCommand.js +98 -0
  60. package/dist/cli/commands/ReportCommand.js.map +1 -0
  61. package/dist/cli/commands/RunCommand.d.ts +13 -0
  62. package/dist/cli/commands/RunCommand.d.ts.map +1 -0
  63. package/dist/cli/commands/RunCommand.js +191 -0
  64. package/dist/cli/commands/RunCommand.js.map +1 -0
  65. package/dist/cli/commands/SecretsCommand.d.ts +9 -0
  66. package/dist/cli/commands/SecretsCommand.d.ts.map +1 -0
  67. package/dist/cli/commands/SecretsCommand.js +109 -0
  68. package/dist/cli/commands/SecretsCommand.js.map +1 -0
  69. package/dist/cli/commands/ServeCommand.d.ts +9 -0
  70. package/dist/cli/commands/ServeCommand.d.ts.map +1 -0
  71. package/dist/cli/commands/ServeCommand.js +50 -0
  72. package/dist/cli/commands/ServeCommand.js.map +1 -0
  73. package/dist/cli/commands/SetupCommand.d.ts +42 -0
  74. package/dist/cli/commands/SetupCommand.d.ts.map +1 -0
  75. package/dist/cli/commands/SetupCommand.js +249 -0
  76. package/dist/cli/commands/SetupCommand.js.map +1 -0
  77. package/dist/cli.d.ts +9 -0
  78. package/dist/cli.d.ts.map +1 -0
  79. package/dist/cli.js +130 -0
  80. package/dist/cli.js.map +1 -0
  81. package/dist/config/ConfigManager.d.ts +395 -0
  82. package/dist/config/ConfigManager.d.ts.map +1 -0
  83. package/dist/config/ConfigManager.js +446 -0
  84. package/dist/config/ConfigManager.js.map +1 -0
  85. package/dist/docker/DockerManager.d.ts +69 -0
  86. package/dist/docker/DockerManager.d.ts.map +1 -0
  87. package/dist/docker/DockerManager.js +266 -0
  88. package/dist/docker/DockerManager.js.map +1 -0
  89. package/dist/event-aggregator.d.ts +71 -0
  90. package/dist/event-aggregator.d.ts.map +1 -0
  91. package/dist/event-aggregator.js +95 -0
  92. package/dist/event-aggregator.js.map +1 -0
  93. package/dist/github-app-token.d.ts +16 -0
  94. package/dist/github-app-token.d.ts.map +1 -0
  95. package/dist/github-app-token.js +148 -0
  96. package/dist/github-app-token.js.map +1 -0
  97. package/dist/idempotency-store.d.ts +61 -0
  98. package/dist/idempotency-store.d.ts.map +1 -0
  99. package/dist/idempotency-store.js +321 -0
  100. package/dist/idempotency-store.js.map +1 -0
  101. package/dist/index.d.ts +25 -0
  102. package/dist/index.d.ts.map +1 -0
  103. package/dist/index.js +31 -0
  104. package/dist/index.js.map +1 -0
  105. package/dist/instance/InstanceManager.d.ts +81 -0
  106. package/dist/instance/InstanceManager.d.ts.map +1 -0
  107. package/dist/instance/InstanceManager.js +220 -0
  108. package/dist/instance/InstanceManager.js.map +1 -0
  109. package/dist/instance-metadata-reader.d.ts +48 -0
  110. package/dist/instance-metadata-reader.d.ts.map +1 -0
  111. package/dist/instance-metadata-reader.js +94 -0
  112. package/dist/instance-metadata-reader.js.map +1 -0
  113. package/dist/instance-state-derivation.d.ts +42 -0
  114. package/dist/instance-state-derivation.d.ts.map +1 -0
  115. package/dist/instance-state-derivation.js +133 -0
  116. package/dist/instance-state-derivation.js.map +1 -0
  117. package/dist/job-scheduler.d.ts +124 -0
  118. package/dist/job-scheduler.d.ts.map +1 -0
  119. package/dist/job-scheduler.js +992 -0
  120. package/dist/job-scheduler.js.map +1 -0
  121. package/dist/kaseki-api-client.d.ts +89 -0
  122. package/dist/kaseki-api-client.d.ts.map +1 -0
  123. package/dist/kaseki-api-client.js +405 -0
  124. package/dist/kaseki-api-client.js.map +1 -0
  125. package/dist/kaseki-api-config.d.ts +34 -0
  126. package/dist/kaseki-api-config.d.ts.map +1 -0
  127. package/dist/kaseki-api-config.js +113 -0
  128. package/dist/kaseki-api-config.js.map +1 -0
  129. package/dist/kaseki-api-routes.d.ts +13 -0
  130. package/dist/kaseki-api-routes.d.ts.map +1 -0
  131. package/dist/kaseki-api-routes.js +559 -0
  132. package/dist/kaseki-api-routes.js.map +1 -0
  133. package/dist/kaseki-api-service-wrapper.d.ts +43 -0
  134. package/dist/kaseki-api-service-wrapper.d.ts.map +1 -0
  135. package/dist/kaseki-api-service-wrapper.js +150 -0
  136. package/dist/kaseki-api-service-wrapper.js.map +1 -0
  137. package/dist/kaseki-api-service.d.ts +16 -0
  138. package/dist/kaseki-api-service.d.ts.map +1 -0
  139. package/dist/kaseki-api-service.js +143 -0
  140. package/dist/kaseki-api-service.js.map +1 -0
  141. package/dist/kaseki-api-types.d.ts +440 -0
  142. package/dist/kaseki-api-types.d.ts.map +1 -0
  143. package/dist/kaseki-api-types.js +64 -0
  144. package/dist/kaseki-api-types.js.map +1 -0
  145. package/dist/kaseki-cli-lib.d.ts +219 -0
  146. package/dist/kaseki-cli-lib.d.ts.map +1 -0
  147. package/dist/kaseki-cli-lib.js +523 -0
  148. package/dist/kaseki-cli-lib.js.map +1 -0
  149. package/dist/kaseki-cli.d.ts +38 -0
  150. package/dist/kaseki-cli.d.ts.map +1 -0
  151. package/dist/kaseki-cli.js +559 -0
  152. package/dist/kaseki-cli.js.map +1 -0
  153. package/dist/kaseki-report.d.ts +3 -0
  154. package/dist/kaseki-report.d.ts.map +1 -0
  155. package/dist/kaseki-report.js +140 -0
  156. package/dist/kaseki-report.js.map +1 -0
  157. package/dist/lib/subprocess-helpers.d.ts +98 -0
  158. package/dist/lib/subprocess-helpers.d.ts.map +1 -0
  159. package/dist/lib/subprocess-helpers.js +136 -0
  160. package/dist/lib/subprocess-helpers.js.map +1 -0
  161. package/dist/logger.d.ts +39 -0
  162. package/dist/logger.d.ts.map +1 -0
  163. package/dist/logger.js +79 -0
  164. package/dist/logger.js.map +1 -0
  165. package/dist/metrics.d.ts +19 -0
  166. package/dist/metrics.d.ts.map +1 -0
  167. package/dist/metrics.js +59 -0
  168. package/dist/metrics.js.map +1 -0
  169. package/dist/middleware/job-lookup.d.ts +27 -0
  170. package/dist/middleware/job-lookup.d.ts.map +1 -0
  171. package/dist/middleware/job-lookup.js +28 -0
  172. package/dist/middleware/job-lookup.js.map +1 -0
  173. package/dist/pi-event-filter.d.ts +3 -0
  174. package/dist/pi-event-filter.d.ts.map +1 -0
  175. package/dist/pi-event-filter.js +126 -0
  176. package/dist/pi-event-filter.js.map +1 -0
  177. package/dist/pi-progress-stream.d.ts +3 -0
  178. package/dist/pi-progress-stream.d.ts.map +1 -0
  179. package/dist/pi-progress-stream.js +205 -0
  180. package/dist/pi-progress-stream.js.map +1 -0
  181. package/dist/pi-progress-summarizer.d.ts +61 -0
  182. package/dist/pi-progress-summarizer.d.ts.map +1 -0
  183. package/dist/pi-progress-summarizer.js +246 -0
  184. package/dist/pi-progress-summarizer.js.map +1 -0
  185. package/dist/pre-flight-validator.d.ts +72 -0
  186. package/dist/pre-flight-validator.d.ts.map +1 -0
  187. package/dist/pre-flight-validator.js +513 -0
  188. package/dist/pre-flight-validator.js.map +1 -0
  189. package/dist/progress-stream-utils.d.ts +3 -0
  190. package/dist/progress-stream-utils.d.ts.map +1 -0
  191. package/dist/progress-stream-utils.js +15 -0
  192. package/dist/progress-stream-utils.js.map +1 -0
  193. package/dist/result-cache.d.ts +52 -0
  194. package/dist/result-cache.d.ts.map +1 -0
  195. package/dist/result-cache.js +134 -0
  196. package/dist/result-cache.js.map +1 -0
  197. package/dist/routes/artifact-routes.d.ts +10 -0
  198. package/dist/routes/artifact-routes.d.ts.map +1 -0
  199. package/dist/routes/artifact-routes.js +126 -0
  200. package/dist/routes/artifact-routes.js.map +1 -0
  201. package/dist/routes/log-routes.d.ts +8 -0
  202. package/dist/routes/log-routes.d.ts.map +1 -0
  203. package/dist/routes/log-routes.js +345 -0
  204. package/dist/routes/log-routes.js.map +1 -0
  205. package/dist/routes/status-routes.d.ts +8 -0
  206. package/dist/routes/status-routes.d.ts.map +1 -0
  207. package/dist/routes/status-routes.js +82 -0
  208. package/dist/routes/status-routes.js.map +1 -0
  209. package/dist/routes/webhook-routes.d.ts +6 -0
  210. package/dist/routes/webhook-routes.d.ts.map +1 -0
  211. package/dist/routes/webhook-routes.js +86 -0
  212. package/dist/routes/webhook-routes.js.map +1 -0
  213. package/dist/run-artifact-metadata-cache.d.ts +42 -0
  214. package/dist/run-artifact-metadata-cache.d.ts.map +1 -0
  215. package/dist/run-artifact-metadata-cache.js +139 -0
  216. package/dist/run-artifact-metadata-cache.js.map +1 -0
  217. package/dist/secret-value-cache.d.ts +13 -0
  218. package/dist/secret-value-cache.d.ts.map +1 -0
  219. package/dist/secret-value-cache.js +44 -0
  220. package/dist/secret-value-cache.js.map +1 -0
  221. package/dist/secrets/SecretsManager.d.ts +80 -0
  222. package/dist/secrets/SecretsManager.d.ts.map +1 -0
  223. package/dist/secrets/SecretsManager.js +306 -0
  224. package/dist/secrets/SecretsManager.js.map +1 -0
  225. package/dist/test-utils.d.ts +55 -0
  226. package/dist/test-utils.d.ts.map +1 -0
  227. package/dist/test-utils.js +48 -0
  228. package/dist/test-utils.js.map +1 -0
  229. package/dist/timestamp-tracker.d.ts +75 -0
  230. package/dist/timestamp-tracker.d.ts.map +1 -0
  231. package/dist/timestamp-tracker.js +121 -0
  232. package/dist/timestamp-tracker.js.map +1 -0
  233. package/dist/utils/failure-artifact-writer.d.ts +29 -0
  234. package/dist/utils/failure-artifact-writer.d.ts.map +1 -0
  235. package/dist/utils/failure-artifact-writer.js +157 -0
  236. package/dist/utils/failure-artifact-writer.js.map +1 -0
  237. package/dist/utils/file-helpers.d.ts +41 -0
  238. package/dist/utils/file-helpers.d.ts.map +1 -0
  239. package/dist/utils/file-helpers.js +143 -0
  240. package/dist/utils/file-helpers.js.map +1 -0
  241. package/dist/utils/http-client-factory.d.ts +46 -0
  242. package/dist/utils/http-client-factory.d.ts.map +1 -0
  243. package/dist/utils/http-client-factory.js +114 -0
  244. package/dist/utils/http-client-factory.js.map +1 -0
  245. package/dist/utils/progress-normalizer.d.ts +13 -0
  246. package/dist/utils/progress-normalizer.d.ts.map +1 -0
  247. package/dist/utils/progress-normalizer.js +57 -0
  248. package/dist/utils/progress-normalizer.js.map +1 -0
  249. package/dist/utils/response-helpers.d.ts +34 -0
  250. package/dist/utils/response-helpers.d.ts.map +1 -0
  251. package/dist/utils/response-helpers.js +78 -0
  252. package/dist/utils/response-helpers.js.map +1 -0
  253. package/dist/utils/route-helpers.d.ts +17 -0
  254. package/dist/utils/route-helpers.d.ts.map +1 -0
  255. package/dist/utils/route-helpers.js +22 -0
  256. package/dist/utils/route-helpers.js.map +1 -0
  257. package/dist/utils/status-response-builder.d.ts +23 -0
  258. package/dist/utils/status-response-builder.d.ts.map +1 -0
  259. package/dist/utils/status-response-builder.js +144 -0
  260. package/dist/utils/status-response-builder.js.map +1 -0
  261. package/dist/utils/type-guards.d.ts +37 -0
  262. package/dist/utils/type-guards.d.ts.map +1 -0
  263. package/dist/utils/type-guards.js +45 -0
  264. package/dist/utils/type-guards.js.map +1 -0
  265. package/dist/utils/utf8-helpers.d.ts +32 -0
  266. package/dist/utils/utf8-helpers.d.ts.map +1 -0
  267. package/dist/utils/utf8-helpers.js +97 -0
  268. package/dist/utils/utf8-helpers.js.map +1 -0
  269. package/dist/utils/webhook-event-builder.d.ts +26 -0
  270. package/dist/utils/webhook-event-builder.d.ts.map +1 -0
  271. package/dist/utils/webhook-event-builder.js +77 -0
  272. package/dist/utils/webhook-event-builder.js.map +1 -0
  273. package/dist/webhook-manager.d.ts +56 -0
  274. package/dist/webhook-manager.d.ts.map +1 -0
  275. package/dist/webhook-manager.js +359 -0
  276. package/dist/webhook-manager.js.map +1 -0
  277. package/docker/workspace-cache/package-lock.json +13 -0
  278. package/docker/workspace-cache/package.json +7 -0
  279. package/docker-compose.yml +53 -0
  280. package/docs/API.md +708 -0
  281. package/docs/BACKLOG.md +19 -0
  282. package/docs/BUILD_STRATEGY.md +404 -0
  283. package/docs/CLI.md +569 -0
  284. package/docs/DEPLOYMENT.md +521 -0
  285. package/docs/DEVELOPMENT.md +459 -0
  286. package/docs/DOCKER_SETUP.md +522 -0
  287. package/docs/ENHANCED_PROGRESS_LOGS.md +264 -0
  288. package/docs/IMPLEMENTATION_SUMMARY.md +549 -0
  289. package/docs/INTEGRATION_EXAMPLE.md +217 -0
  290. package/docs/NPM_SETUP.md +468 -0
  291. package/docs/PHASE1-4_IMPLEMENTATION.md +302 -0
  292. package/docs/PHASE1_COMPLETION.md +192 -0
  293. package/docs/PHASE2_COMPLETION.md +134 -0
  294. package/docs/PHASE6_MIGRATION.md +392 -0
  295. package/docs/PRINTF_SAFETY_FIX.md +282 -0
  296. package/docs/QUALITY_GATES.md +369 -0
  297. package/docs/SETUP_GUIDE.md +482 -0
  298. package/docs/TASK_PROMPT_TEMPLATES.md +533 -0
  299. package/docs/VALIDATION_FIX.md +139 -0
  300. package/docs/VERIFICATION_CHECKLIST.md +335 -0
  301. package/docs/repo-maturity.md +760 -0
  302. package/fix-tests.d.ts +9 -0
  303. package/fix-tests.d.ts.map +1 -0
  304. package/fix-tests.js.map +1 -0
  305. package/fix-tests.ts +53 -0
  306. package/jest.config.ts +31 -0
  307. package/kaseki +183 -0
  308. package/kaseki-agent.sh +1961 -0
  309. package/ops/logrotate/kaseki +10 -0
  310. package/package.json +83 -0
  311. package/perf/README.md +54 -0
  312. package/perf/pi-event-filter.benchmark.test.ts +98 -0
  313. package/run-kaseki-json.test.sh +106 -0
  314. package/run-kaseki.sh +990 -0
  315. package/scripts/allowlist-helper.sh +56 -0
  316. package/scripts/cleanup-kaseki.sh +168 -0
  317. package/scripts/deploy-pi-template.sh +293 -0
  318. package/scripts/docker-entrypoint.sh +71 -0
  319. package/scripts/dry-run-allowlist.sh +161 -0
  320. package/scripts/kaseki-activate.sh +396 -0
  321. package/scripts/kaseki-api.service +62 -0
  322. package/scripts/kaseki-container-entrypoint-wrapper.sh +119 -0
  323. package/scripts/kaseki-container-setup-remote.sh +172 -0
  324. package/scripts/kaseki-container-setup.sh +193 -0
  325. package/scripts/kaseki-healthcheck.sh +95 -0
  326. package/scripts/kaseki-install.sh +50 -0
  327. package/scripts/kaseki-maturity-score.sh +291 -0
  328. package/scripts/kaseki-performance-metrics.sh +122 -0
  329. package/scripts/kaseki-preflight.sh +270 -0
  330. package/scripts/kaseki-setup.sh +265 -0
  331. package/scripts/pi-setup-remote.sh +213 -0
  332. package/scripts/setup-github-labels.sh +42 -0
  333. package/scripts/suggest-allowlist.sh +68 -0
  334. package/scripts/templates/MULTI_HOST_DISTRIBUTED.md +337 -0
  335. package/scripts/templates/REST_API_SERVICE.md +490 -0
  336. package/scripts/templates/SINGLE_HOST_CLI.md +194 -0
  337. package/scripts/test-github-app.sh +248 -0
  338. package/src/add-js-extensions.ts +61 -0
  339. package/src/ansi-colors.test.ts +62 -0
  340. package/src/ansi-colors.ts +67 -0
  341. package/src/cli/BaseCommand.ts +40 -0
  342. package/src/cli/KasekiCLI.ts +154 -0
  343. package/src/cli/commands/ConfigCommand.ts +145 -0
  344. package/src/cli/commands/DoctorCommand.ts +329 -0
  345. package/src/cli/commands/ListCommand.ts +105 -0
  346. package/src/cli/commands/ReportCommand.ts +110 -0
  347. package/src/cli/commands/RunCommand.ts +218 -0
  348. package/src/cli/commands/SecretsCommand.ts +120 -0
  349. package/src/cli/commands/ServeCommand.ts +62 -0
  350. package/src/cli/commands/SetupCommand.ts +301 -0
  351. package/src/cli.ts +138 -0
  352. package/src/config/ConfigManager.ts +476 -0
  353. package/src/docker/DockerManager.ts +319 -0
  354. package/src/docker-entrypoint-packaging.test.ts +33 -0
  355. package/src/event-aggregator.test.ts +117 -0
  356. package/src/event-aggregator.ts +126 -0
  357. package/src/github-app-token.ts +215 -0
  358. package/src/idempotency-store.test.ts +117 -0
  359. package/src/idempotency-store.ts +385 -0
  360. package/src/index.ts +89 -0
  361. package/src/instance/InstanceManager.ts +285 -0
  362. package/src/instance-metadata-reader.test.ts +190 -0
  363. package/src/instance-metadata-reader.ts +129 -0
  364. package/src/instance-state-derivation.test.ts +263 -0
  365. package/src/instance-state-derivation.ts +148 -0
  366. package/src/job-scheduler.test.ts +1236 -0
  367. package/src/job-scheduler.ts +1117 -0
  368. package/src/kaseki-api-client.ts +488 -0
  369. package/src/kaseki-api-config.test.ts +315 -0
  370. package/src/kaseki-api-config.ts +175 -0
  371. package/src/kaseki-api-routes.test.ts +1615 -0
  372. package/src/kaseki-api-routes.ts +643 -0
  373. package/src/kaseki-api-service-wrapper.ts +188 -0
  374. package/src/kaseki-api-service.test.ts +418 -0
  375. package/src/kaseki-api-service.ts +192 -0
  376. package/src/kaseki-api-types.ts +320 -0
  377. package/src/kaseki-cli-lib.test.ts +552 -0
  378. package/src/kaseki-cli-lib.ts +760 -0
  379. package/src/kaseki-cli.ts +682 -0
  380. package/src/kaseki-report.test.ts +118 -0
  381. package/src/kaseki-report.ts +192 -0
  382. package/src/lib/subprocess-helpers.ts +177 -0
  383. package/src/logger.ts +114 -0
  384. package/src/metrics.ts +66 -0
  385. package/src/middleware/job-lookup.test.ts +113 -0
  386. package/src/middleware/job-lookup.ts +45 -0
  387. package/src/pi-event-filter.test.ts +183 -0
  388. package/src/pi-event-filter.ts +183 -0
  389. package/src/pi-progress-stream.ts +287 -0
  390. package/src/pi-progress-summarizer.test.ts +302 -0
  391. package/src/pi-progress-summarizer.ts +287 -0
  392. package/src/pre-flight-validator.test.ts +512 -0
  393. package/src/pre-flight-validator.ts +618 -0
  394. package/src/progress-stream-utils.test.ts +35 -0
  395. package/src/progress-stream-utils.ts +14 -0
  396. package/src/result-cache.test.ts +195 -0
  397. package/src/result-cache.ts +181 -0
  398. package/src/routes/artifact-routes.ts +169 -0
  399. package/src/routes/log-routes.ts +391 -0
  400. package/src/routes/status-routes.ts +92 -0
  401. package/src/routes/webhook-routes.ts +97 -0
  402. package/src/run-artifact-metadata-cache.test.ts +80 -0
  403. package/src/run-artifact-metadata-cache.ts +184 -0
  404. package/src/secret-value-cache.test.ts +66 -0
  405. package/src/secret-value-cache.ts +55 -0
  406. package/src/secrets/SecretsManager.ts +343 -0
  407. package/src/test-utils.ts +81 -0
  408. package/src/timestamp-tracker.test.ts +134 -0
  409. package/src/timestamp-tracker.ts +132 -0
  410. package/src/utils/failure-artifact-writer.ts +187 -0
  411. package/src/utils/file-helpers.test.ts +235 -0
  412. package/src/utils/file-helpers.ts +150 -0
  413. package/src/utils/http-client-factory.test.ts +245 -0
  414. package/src/utils/http-client-factory.ts +157 -0
  415. package/src/utils/progress-normalizer.test.ts +442 -0
  416. package/src/utils/progress-normalizer.ts +68 -0
  417. package/src/utils/response-helpers.test.ts +122 -0
  418. package/src/utils/response-helpers.ts +101 -0
  419. package/src/utils/route-helpers.ts +30 -0
  420. package/src/utils/status-response-builder.ts +159 -0
  421. package/src/utils/type-guards.ts +52 -0
  422. package/src/utils/utf8-helpers.ts +102 -0
  423. package/src/utils/webhook-event-builder.test.ts +143 -0
  424. package/src/utils/webhook-event-builder.ts +87 -0
  425. package/src/webhook-manager.test.ts +152 -0
  426. package/src/webhook-manager.ts +445 -0
  427. package/templates/allowlist-api-route.txt +7 -0
  428. package/templates/allowlist-comprehensive.txt +8 -0
  429. package/templates/allowlist-parser-fix.txt +6 -0
  430. package/templates/allowlist-ui-component.txt +9 -0
  431. package/templates/allowlist-utility.txt +9 -0
  432. package/test/actual-model-metadata.test.sh +102 -0
  433. package/test/dry-run.test.sh +131 -0
  434. package/test/fixtures/kaseki-report-exit-codes/metadata-exit-0.json +1 -0
  435. package/test/fixtures/kaseki-report-exit-codes/metadata-exit-1.json +1 -0
  436. package/test/fixtures/kaseki-report-exit-codes/metadata-exit-invalid.json +1 -0
  437. package/test/fixtures/kaseki-report-exit-codes/metadata-exit-str-0.json +1 -0
  438. package/test/fixtures/kaseki-report-exit-codes/metadata-exit-str-1.json +1 -0
  439. package/test/kaseki-api.integration.test.sh +165 -0
  440. package/test/pi-event-filter-failure.test.sh +83 -0
  441. package/test/printf-safety-focused.test.sh +99 -0
  442. package/test/printf-safety-results/results/restoration.jsonl +10 -0
  443. package/test/printf-safety-results/results/test.jsonl +0 -0
  444. package/test/printf-safety.test.sh +297 -0
  445. package/test/validation-fix.test.sh +79 -0
  446. package/test/validation-integration.test.sh +109 -0
  447. package/tests/allowlist-glob.test.sh +61 -0
  448. package/tests/dependency-cache-key.test.sh +48 -0
  449. package/tests/dependency-restore-mode.test.sh +48 -0
  450. package/tests/doctor-template-parity.test.sh +95 -0
  451. package/tests/github-operations.test.sh +142 -0
  452. package/tests/npm-install-flags.test.sh +58 -0
  453. package/tests/quality-gates.test.sh +178 -0
  454. package/tests/repo-memory.test.sh +103 -0
  455. package/tests/restore-disallowed-changes.test.sh +80 -0
  456. package/tests/validation-missing-npm-scripts.test.sh +93 -0
  457. package/tests/validation-strict-mode.test.sh +118 -0
  458. package/tsconfig.changed.json +7 -0
  459. package/tsconfig.json +39 -0
@@ -0,0 +1,248 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
5
+ HELPER="$ROOT_DIR/dist/github-app-token.js"
6
+ RUNNER="$ROOT_DIR/run-kaseki.sh"
7
+
8
+ if [ ! -x "$HELPER" ]; then
9
+ if command -v npx >/dev/null 2>&1; then
10
+ npx --yes tsc "$ROOT_DIR/src/github-app-token.ts" --outDir "$ROOT_DIR/dist" --target es2020 --module commonjs --esModuleInterop >/dev/null 2>&1 || true
11
+ chmod +x "$HELPER" 2>/dev/null || true
12
+ fi
13
+ fi
14
+
15
+ if [ ! -x "$HELPER" ]; then
16
+ echo "Expected executable helper at $HELPER" >&2
17
+ exit 1
18
+ fi
19
+
20
+ TMP_DIR="$(mktemp -d)"
21
+ trap 'rm -rf "$TMP_DIR"' EXIT
22
+
23
+ assert_token_error_contract() {
24
+ local expected_exit="$1"
25
+ local expected_substring="$2"
26
+ shift 2
27
+
28
+ local stdout_file="$TMP_DIR/token.stdout"
29
+ local stderr_file="$TMP_DIR/token.stderr"
30
+
31
+ set +e
32
+ node "$HELPER" "$@" >"$stdout_file" 2>"$stderr_file"
33
+ local status=$?
34
+ set -e
35
+
36
+ if [ "$status" -ne "$expected_exit" ]; then
37
+ echo "Unexpected helper exit code. expected=$expected_exit got=$status args=[$*]" >&2
38
+ exit 1
39
+ fi
40
+
41
+ if [ "$expected_substring" = "Usage:" ]; then
42
+ if ! grep -q "Usage:" "$stderr_file"; then
43
+ echo "Expected usage message in stderr for args=[$*]" >&2
44
+ exit 1
45
+ fi
46
+ if [ -s "$stdout_file" ]; then
47
+ echo "Expected empty stdout for usage errors" >&2
48
+ exit 1
49
+ fi
50
+ return
51
+ fi
52
+
53
+ node --input-type=commonjs - "$stdout_file" "$expected_substring" <<'NODEEOF'
54
+ const fs = require('node:fs');
55
+ const stdoutPath = process.argv[2];
56
+ const expected = process.argv[3];
57
+ const raw = fs.readFileSync(stdoutPath, 'utf8').trim();
58
+ if (!raw) throw new Error('expected JSON output on stdout');
59
+ let parsed;
60
+ try { parsed = JSON.parse(raw); } catch (err) { throw new Error('invalid JSON output: ' + err.message); }
61
+ if (!parsed.error || typeof parsed.error !== 'string') throw new Error('missing string error field');
62
+ if (!parsed.error.includes(expected)) throw new Error('error field missing expected substring: ' + expected);
63
+ NODEEOF
64
+ }
65
+
66
+ echo "Test 1: helper arg validation + structured failures"
67
+ assert_token_error_contract 1 "Usage:"
68
+ assert_token_error_contract 1 "Usage:" "123" "missing.pem" "owner"
69
+ assert_token_error_contract 1 "ENOENT" "123" "$TMP_DIR/does-not-exist.pem" "owner" "repo"
70
+
71
+ MOCK_KEY="$TMP_DIR/mock-key.pem"
72
+ openssl genrsa -out "$MOCK_KEY" 2048 >/dev/null 2>&1
73
+
74
+ run_helper_with_https_mock() {
75
+ local fixture="$1"
76
+ local stdout_file="$TMP_DIR/mock-${fixture}.stdout"
77
+ local stderr_file="$TMP_DIR/mock-${fixture}.stderr"
78
+
79
+ set +e
80
+ NODE_OPTIONS="--require $TMP_DIR/mock-https.js" MOCK_GITHUB_FIXTURE="$fixture" \
81
+ node "$HELPER" "123" "$MOCK_KEY" "octo" "hello" >"$stdout_file" 2>"$stderr_file"
82
+ local status=$?
83
+ set -e
84
+
85
+ echo "$status" > "$TMP_DIR/mock-${fixture}.status"
86
+ }
87
+
88
+ cat > "$TMP_DIR/mock-https.js" <<'EOF_JS'
89
+ const https = require('node:https');
90
+ const { EventEmitter } = require('node:events');
91
+
92
+ const fixture = process.env.MOCK_GITHUB_FIXTURE;
93
+ const original = https.request;
94
+
95
+ https.request = (options, cb) => {
96
+ const req = new EventEmitter();
97
+ req.end = () => {
98
+ const res = new EventEmitter();
99
+ res.statusCode = 500;
100
+ let body = '{"error":"unconfigured fixture"}';
101
+
102
+ if (fixture === 'success-installation') {
103
+ if (options.path.endsWith('/installation')) {
104
+ res.statusCode = 200;
105
+ body = JSON.stringify({ id: 777 });
106
+ } else if (options.path.includes('/access_tokens')) {
107
+ res.statusCode = 201;
108
+ body = JSON.stringify({ token: 'ghu_fixture_token', expires_at: '2026-06-01T00:00:00Z' });
109
+ }
110
+ } else if (fixture === 'installation-failure' && options.path.endsWith('/installation')) {
111
+ res.statusCode = 404;
112
+ body = JSON.stringify({ message: 'Not Found' });
113
+ } else if (fixture === 'token-failure') {
114
+ if (options.path.endsWith('/installation')) {
115
+ res.statusCode = 200;
116
+ body = JSON.stringify({ id: 777 });
117
+ } else if (options.path.includes('/access_tokens')) {
118
+ res.statusCode = 403;
119
+ body = JSON.stringify({ message: 'Forbidden' });
120
+ }
121
+ }
122
+
123
+ process.nextTick(() => {
124
+ cb(res);
125
+ res.emit('data', Buffer.from(body));
126
+ res.emit('end');
127
+ });
128
+ };
129
+ req.on = (...args) => EventEmitter.prototype.on.apply(req, args);
130
+ req.write = () => {};
131
+ return req;
132
+ };
133
+
134
+ process.on('exit', () => { https.request = original; });
135
+ EOF_JS
136
+
137
+ echo "Test 2: helper token-generation flow with stubbed GitHub API"
138
+ run_helper_with_https_mock success-installation
139
+ [ "$(cat "$TMP_DIR/mock-success-installation.status")" -eq 0 ] || { echo "Expected success fixture to exit 0" >&2; exit 1; }
140
+ node --input-type=commonjs -e '
141
+ const fs = require("node:fs");
142
+ const out = JSON.parse(fs.readFileSync(process.argv[1], "utf8"));
143
+ if (out.token !== "ghu_fixture_token") throw new Error("token mismatch");
144
+ if (out.expires_at !== "2026-06-01T00:00:00Z") throw new Error("expires_at mismatch");
145
+ ' "$TMP_DIR/mock-success-installation.stdout"
146
+
147
+ run_helper_with_https_mock installation-failure
148
+ [ "$(cat "$TMP_DIR/mock-installation-failure.status")" -eq 1 ] || { echo "Expected installation failure exit 1" >&2; exit 1; }
149
+ node --input-type=commonjs -e 'const f=require("node:fs"); const out=JSON.parse(f.readFileSync(process.argv[1],"utf8")); if (!out.error.includes("Failed to get installation ID")) throw new Error("missing installation error");' "$TMP_DIR/mock-installation-failure.stdout"
150
+
151
+ run_helper_with_https_mock token-failure
152
+ [ "$(cat "$TMP_DIR/mock-token-failure.status")" -eq 1 ] || { echo "Expected token failure exit 1" >&2; exit 1; }
153
+ node --input-type=commonjs -e 'const f=require("node:fs"); const out=JSON.parse(f.readFileSync(process.argv[1],"utf8")); if (!out.error.includes("Failed to get access token")) throw new Error("missing token error");' "$TMP_DIR/mock-token-failure.stdout"
154
+
155
+ echo "Test 3/4: run-kaseki metadata + credential artifact handling"
156
+ DOCKER_BIN="$TMP_DIR/docker"
157
+ cat > "$DOCKER_BIN" <<'EOF_DOCKER'
158
+ #!/usr/bin/env bash
159
+ set -euo pipefail
160
+ if [ "$1" = "run" ]; then
161
+ result_dir=""
162
+ while [ "$#" -gt 0 ]; do
163
+ if [ "$1" = "-v" ]; then
164
+ shift
165
+ case "$1" in
166
+ *:/results) result_dir="${1%%:/results}" ;;
167
+ *:/results:*) result_dir="${1%%:/results:*}" ;;
168
+ esac
169
+ fi
170
+ shift || true
171
+ done
172
+ [ -n "$result_dir" ] || { echo "missing results mount" >&2; exit 1; }
173
+ mkdir -p "$result_dir"
174
+ cat > "$result_dir/metadata.json" <<'META'
175
+ {
176
+ "github_pr_url": "https://github.com/octo/hello/pull/42",
177
+ "github_push_exit_code": 0,
178
+ "github_pr_exit_code": 1
179
+ }
180
+ META
181
+ touch "$result_dir/stdout.log" "$result_dir/stderr.log" "$result_dir/progress.log" "$result_dir/progress.jsonl" "$result_dir/quality.log" "$result_dir/secret-scan.log" "$result_dir/git-push.log"
182
+ exit 0
183
+ fi
184
+ exit 0
185
+ EOF_DOCKER
186
+ chmod +x "$DOCKER_BIN"
187
+
188
+ KASEKI_ROOT="$TMP_DIR/kaseki-root"
189
+ mkdir -p "$KASEKI_ROOT"
190
+ HOST_KEY_FILE="$TMP_DIR/github-app.pem"
191
+ printf '%s\n' 'PRIVATEKEY' > "$HOST_KEY_FILE"
192
+ HOST_APP_ID_FILE="$TMP_DIR/github-app-id"
193
+ HOST_CLIENT_ID_FILE="$TMP_DIR/github-app-client-id"
194
+ printf '%s\n' '1' > "$HOST_APP_ID_FILE"
195
+ printf '%s\n' 'abc' > "$HOST_CLIENT_ID_FILE"
196
+
197
+ mkdir -p "$TMP_DIR/scripts"
198
+ cat > "$TMP_DIR/scripts/kaseki-preflight.sh" <<'EOF_PREFLIGHT'
199
+ #!/usr/bin/env bash
200
+ exit 0
201
+ EOF_PREFLIGHT
202
+ chmod +x "$TMP_DIR/scripts/kaseki-preflight.sh"
203
+
204
+ set +e
205
+ env PATH="$TMP_DIR:/usr/bin:/bin" \
206
+ KASEKI_ROOT="$KASEKI_ROOT" \
207
+ OPENROUTER_API_KEY="dummy" \
208
+ GITHUB_APP_ID_FILE="$HOST_APP_ID_FILE" \
209
+ GITHUB_APP_CLIENT_ID_FILE="$HOST_CLIENT_ID_FILE" \
210
+ GITHUB_APP_PRIVATE_KEY_FILE="$HOST_KEY_FILE" \
211
+ "$RUNNER" >"$TMP_DIR/run.stdout" 2>"$TMP_DIR/run.stderr"
212
+ run_status=$?
213
+ set -e
214
+
215
+ if [ "$run_status" -ne 0 ]; then
216
+ echo "Expected run-kaseki.sh to exit 0, got $run_status" >&2
217
+ cat "$TMP_DIR/run.stderr" >&2 || true
218
+ exit 1
219
+ fi
220
+
221
+ result_dir="$KASEKI_ROOT/kaseki-results/kaseki-1"
222
+ [ -d "$result_dir" ] || { echo "Expected result dir" >&2; exit 1; }
223
+
224
+ node --input-type=commonjs -e '
225
+ const fs = require("node:fs");
226
+ const path = require("node:path");
227
+ const dir = process.argv[1];
228
+ const jsonFiles = fs.readdirSync(dir).filter((name) => name.endsWith(".json"));
229
+ let found = false;
230
+ for (const file of jsonFiles) {
231
+ let data;
232
+ try { data = JSON.parse(fs.readFileSync(path.join(dir, file), "utf8")); } catch { continue; }
233
+ if (Object.prototype.hasOwnProperty.call(data, "github_pr_url") &&
234
+ Object.prototype.hasOwnProperty.call(data, "github_push_exit_code") &&
235
+ Object.prototype.hasOwnProperty.call(data, "github_pr_exit_code")) {
236
+ found = true;
237
+ break;
238
+ }
239
+ }
240
+ if (!found) throw new Error("no JSON artifact includes github_pr_url/github_push_exit_code/github_pr_exit_code");
241
+ ' "$result_dir"
242
+
243
+ if ! grep -q "workspace_removed=" "$result_dir/cleanup.log"; then
244
+ echo "Expected cleanup.log to include workspace removal status" >&2
245
+ exit 1
246
+ fi
247
+
248
+ echo "All behavior-focused GitHub App tests passed"
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * add-js-extensions.ts
4
+ *
5
+ * Post-compilation script to add .js extensions to local imports in ES modules.
6
+ * This is required for proper ES module resolution in Node.js.
7
+ */
8
+
9
+ import fs from 'fs';
10
+ import path from 'path';
11
+ import { fileURLToPath } from 'url';
12
+
13
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
14
+ const distDir = __dirname;
15
+
16
+ function addJsExtensions(filePath: string): void {
17
+ let content = fs.readFileSync(filePath, 'utf8');
18
+
19
+ // Match imports/exports from relative paths without extensions
20
+ // Pattern: from './path', from '../path', from '../../path', etc.
21
+ // But not: from './path.js' or from 'npm-package' or from 'npm-package/subpath'
22
+ content = content.replace(
23
+ /from\s+['"](\.[.]*[/\\][^'"]*?)['"](?!\.js\b)/g,
24
+ (match: string, importPath: string) => {
25
+ // Skip if already has .js extension
26
+ if (importPath.endsWith('.js')) {
27
+ return match;
28
+ }
29
+ // Add .js extension to relative imports
30
+ return `from '${importPath}.js'`;
31
+ },
32
+ );
33
+
34
+ fs.writeFileSync(filePath, content, 'utf8');
35
+ }
36
+
37
+ function processDirectory(dir: string): void {
38
+ const files = fs.readdirSync(dir);
39
+
40
+ for (const file of files) {
41
+ const filePath = path.join(dir, file);
42
+ const stat = fs.statSync(filePath);
43
+
44
+ if (stat.isDirectory()) {
45
+ processDirectory(filePath);
46
+ } else if (file.endsWith('.js')) {
47
+ addJsExtensions(filePath);
48
+ }
49
+ }
50
+ }
51
+
52
+ try {
53
+ if (fs.existsSync(distDir)) {
54
+ processDirectory(distDir);
55
+ console.log('✓ Added .js extensions to imports in dist/');
56
+ }
57
+ } catch (error) {
58
+ const err = error as Error;
59
+ console.error('Error adding .js extensions:', err.message);
60
+ process.exit(1);
61
+ }
@@ -0,0 +1,62 @@
1
+ import { describe, it, expect } from '@jest/globals';
2
+ import { ANSI_COLORS, stripAnsi } from '../src/ansi-colors';
3
+
4
+ describe('ansi-colors', () => {
5
+ describe('ANSI_COLORS', () => {
6
+ it('exports color constants', () => {
7
+ // Colors might be empty strings if not a TTY, but should exist
8
+ expect(ANSI_COLORS).toHaveProperty('RED');
9
+ expect(ANSI_COLORS).toHaveProperty('YELLOW');
10
+ expect(ANSI_COLORS).toHaveProperty('GREEN');
11
+ expect(ANSI_COLORS).toHaveProperty('BLUE');
12
+ expect(ANSI_COLORS).toHaveProperty('RESET');
13
+ });
14
+
15
+ it('exports formatting codes', () => {
16
+ expect(ANSI_COLORS).toHaveProperty('BOLD');
17
+ expect(ANSI_COLORS).toHaveProperty('DIM');
18
+ });
19
+
20
+ it('color codes are strings (possibly empty)', () => {
21
+ expect(typeof ANSI_COLORS.RED).toBe('string');
22
+ expect(typeof ANSI_COLORS.YELLOW).toBe('string');
23
+ expect(typeof ANSI_COLORS.RESET).toBe('string');
24
+ });
25
+ });
26
+
27
+ describe('stripAnsi', () => {
28
+ it('removes red color codes', () => {
29
+ const text = `${ANSI_COLORS.RED}error message${ANSI_COLORS.RESET}`;
30
+ const stripped = stripAnsi(text);
31
+ expect(stripped).toBe('error message');
32
+ });
33
+
34
+ it('removes multiple color codes', () => {
35
+ const text = `${ANSI_COLORS.YELLOW}warn${ANSI_COLORS.RESET} and ${ANSI_COLORS.RED}error${ANSI_COLORS.RESET}`;
36
+ const stripped = stripAnsi(text);
37
+ expect(stripped).toBe('warn and error');
38
+ });
39
+
40
+ it('handles text without color codes', () => {
41
+ const text = 'plain text';
42
+ expect(stripAnsi(text)).toBe('plain text');
43
+ });
44
+
45
+ it('removes bold and dim codes', () => {
46
+ const text = `${ANSI_COLORS.BOLD}bold${ANSI_COLORS.RESET} ${ANSI_COLORS.DIM}dim${ANSI_COLORS.RESET}`;
47
+ const stripped = stripAnsi(text);
48
+ expect(stripped).toBe('bold dim');
49
+ });
50
+
51
+ it('handles empty string', () => {
52
+ expect(stripAnsi('')).toBe('');
53
+ });
54
+
55
+ it('removes all ANSI escape sequences', () => {
56
+ // Test with raw ANSI codes
57
+ const text = '\x1b[31mred\x1b[0m \x1b[33myellow\x1b[0m';
58
+ const stripped = stripAnsi(text);
59
+ expect(stripped).toBe('red yellow');
60
+ });
61
+ });
62
+ });
@@ -0,0 +1,67 @@
1
+ /**
2
+ * ANSI Color codes for terminal output
3
+ * Only applied when outputting to a TTY
4
+ */
5
+
6
+ export interface AnsiColorSet {
7
+ RED: string;
8
+ YELLOW: string;
9
+ GREEN: string;
10
+ BLUE: string;
11
+ CYAN: string;
12
+ MAGENTA: string;
13
+ WHITE: string;
14
+ RESET: string;
15
+ BOLD: string;
16
+ DIM: string;
17
+ }
18
+
19
+ /**
20
+ * Check if output should be colored (not piped, is TTY)
21
+ */
22
+ function shouldUseColor(): boolean {
23
+ // Check if stdout is a TTY and TERM is not 'dumb'
24
+ const isTTY = process.stdout?.isTTY ?? false;
25
+ const notDumb = process.env.TERM !== 'dumb';
26
+ const noColorEnv = process.env.NO_COLOR;
27
+
28
+ return isTTY && notDumb && !noColorEnv;
29
+ }
30
+
31
+ /**
32
+ * ANSI color codes
33
+ * Only include actual colors if output is to a TTY
34
+ */
35
+ export const ANSI_COLORS: AnsiColorSet = shouldUseColor()
36
+ ? {
37
+ RED: '\x1b[31m',
38
+ YELLOW: '\x1b[33m',
39
+ GREEN: '\x1b[32m',
40
+ BLUE: '\x1b[34m',
41
+ CYAN: '\x1b[36m',
42
+ MAGENTA: '\x1b[35m',
43
+ WHITE: '\x1b[37m',
44
+ RESET: '\x1b[0m',
45
+ BOLD: '\x1b[1m',
46
+ DIM: '\x1b[2m',
47
+ }
48
+ : {
49
+ RED: '',
50
+ YELLOW: '',
51
+ GREEN: '',
52
+ BLUE: '',
53
+ CYAN: '',
54
+ MAGENTA: '',
55
+ WHITE: '',
56
+ RESET: '',
57
+ BOLD: '',
58
+ DIM: '',
59
+ };
60
+
61
+ /**
62
+ * Strip ANSI codes from a string
63
+ */
64
+ export function stripAnsi(text: string): string {
65
+ // eslint-disable-next-line no-control-regex
66
+ return text.replace(/\x1b\[[0-9;]*m/g, '');
67
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Base class for all CLI commands
3
+ */
4
+
5
+ import { ConfigManager } from '../config/ConfigManager';
6
+
7
+ export abstract class BaseCommand {
8
+ protected configManager: ConfigManager;
9
+
10
+ constructor(configManager: ConfigManager) {
11
+ this.configManager = configManager;
12
+ }
13
+
14
+ abstract execute(args: string[]): Promise<number>;
15
+
16
+ /**
17
+ * Parse simple arguments
18
+ * Handles: command arg1 arg2 --flag --key=value
19
+ */
20
+ protected parseArgs(args: string[]): {
21
+ positional: string[];
22
+ flags: Map<string, string | boolean>;
23
+ } {
24
+ const positional: string[] = [];
25
+ const flags = new Map<string, string | boolean>();
26
+
27
+ for (const arg of args) {
28
+ if (arg.startsWith('--')) {
29
+ const [key, value] = arg.substring(2).split('=');
30
+ flags.set(key, value || true);
31
+ } else if (arg.startsWith('-') && arg.length === 2) {
32
+ flags.set(arg.substring(1), true);
33
+ } else {
34
+ positional.push(arg);
35
+ }
36
+ }
37
+
38
+ return { positional, flags };
39
+ }
40
+ }
@@ -0,0 +1,154 @@
1
+ /**
2
+ * KasekiCLI - Main command router
3
+ *
4
+ * Dispatches CLI subcommands to their respective handlers
5
+ */
6
+
7
+ import { createLogger } from '../logger';
8
+ import { ConfigManager } from '../config/ConfigManager';
9
+
10
+ const logger = createLogger('kaseki-cli');
11
+
12
+ export interface CLICommand {
13
+ name: string;
14
+ description: string;
15
+ execute(args: string[]): Promise<number>;
16
+ }
17
+
18
+ export class KasekiCLI {
19
+ private configManager: ConfigManager;
20
+ private commands: Map<string, CLICommand>;
21
+
22
+ constructor(configManager: ConfigManager) {
23
+ this.configManager = configManager;
24
+ this.commands = new Map();
25
+ this.registerCommands();
26
+ }
27
+
28
+ /**
29
+ * Register all available commands
30
+ * These will be lazily loaded when needed
31
+ */
32
+ private registerCommands(): void {
33
+ // Commands will be loaded dynamically to avoid circular dependencies
34
+ // and reduce startup time
35
+ this.commands.set('setup', {
36
+ name: 'setup',
37
+ description: 'Interactive setup wizard (first-time configuration)',
38
+ execute: async (args) => {
39
+ const { SetupCommand } = await import('./commands/SetupCommand');
40
+ const cmd = new SetupCommand(this.configManager);
41
+ return cmd.execute(args);
42
+ },
43
+ });
44
+
45
+ this.commands.set('run', {
46
+ name: 'run',
47
+ description: 'Run kaseki agent on target repository',
48
+ execute: async (args) => {
49
+ const { RunCommand } = await import('./commands/RunCommand');
50
+ const cmd = new RunCommand(this.configManager);
51
+ return cmd.execute(args);
52
+ },
53
+ });
54
+
55
+ this.commands.set('doctor', {
56
+ name: 'doctor',
57
+ description: 'Health checks and dependency validation',
58
+ execute: async (args) => {
59
+ const { DoctorCommand } = await import('./commands/DoctorCommand');
60
+ const cmd = new DoctorCommand(this.configManager);
61
+ return cmd.execute(args);
62
+ },
63
+ });
64
+
65
+ this.commands.set('serve', {
66
+ name: 'serve',
67
+ description: 'Start REST API service for async execution',
68
+ execute: async (args) => {
69
+ const { ServeCommand } = await import('./commands/ServeCommand');
70
+ const cmd = new ServeCommand(this.configManager);
71
+ return cmd.execute(args);
72
+ },
73
+ });
74
+
75
+ this.commands.set('config', {
76
+ name: 'config',
77
+ description: 'Manage configuration',
78
+ execute: async (args) => {
79
+ const { ConfigCommand } = await import('./commands/ConfigCommand');
80
+ const cmd = new ConfigCommand(this.configManager);
81
+ return cmd.execute(args);
82
+ },
83
+ });
84
+
85
+ this.commands.set('list', {
86
+ name: 'list',
87
+ description: 'List all kaseki instances',
88
+ execute: async (args) => {
89
+ const { ListCommand } = await import('./commands/ListCommand');
90
+ const cmd = new ListCommand(this.configManager);
91
+ return cmd.execute(args);
92
+ },
93
+ });
94
+
95
+ this.commands.set('report', {
96
+ name: 'report',
97
+ description: 'Generate report for completed instance',
98
+ execute: async (args) => {
99
+ const { ReportCommand } = await import('./commands/ReportCommand');
100
+ const cmd = new ReportCommand(this.configManager);
101
+ return cmd.execute(args);
102
+ },
103
+ });
104
+
105
+ this.commands.set('secrets', {
106
+ name: 'secrets',
107
+ description: 'Manage stored secrets (keyring/file)',
108
+ execute: async (args) => {
109
+ const { SecretsCommand } = await import('./commands/SecretsCommand');
110
+ const cmd = new SecretsCommand(this.configManager);
111
+ return cmd.execute(args);
112
+ },
113
+ });
114
+ }
115
+
116
+ /**
117
+ * Dispatch to appropriate subcommand
118
+ */
119
+ async dispatch(subcommand: string | undefined, args: string[]): Promise<number> {
120
+ if (!subcommand) {
121
+ console.error('No command specified');
122
+ return 1;
123
+ }
124
+
125
+ const command = this.commands.get(subcommand);
126
+ if (!command) {
127
+ console.error(`Unknown command: ${subcommand}`);
128
+ console.error('\nRun \'kaseki-agent --help\' for available commands');
129
+ return 1;
130
+ }
131
+
132
+ try {
133
+ logger.debug(`Executing command: ${subcommand}`);
134
+ return await command.execute(args);
135
+ } catch (error) {
136
+ if (error instanceof Error) {
137
+ logger.error(`Command failed: ${error.message}`);
138
+ if (process.env.DEBUG === '1') {
139
+ console.error(error.stack);
140
+ }
141
+ } else {
142
+ logger.error('Unknown error in command execution');
143
+ }
144
+ return 1;
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Get list of available commands
150
+ */
151
+ getCommands(): CLICommand[] {
152
+ return Array.from(this.commands.values());
153
+ }
154
+ }