@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.
- package/.dockerignore +54 -0
- package/.eslintignore +11 -0
- package/.eslintrc.json +95 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +53 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +53 -0
- package/.github/ISSUE_TEMPLATE/security.md +51 -0
- package/.github/PULL_REQUEST_TEMPLATE/default.md +71 -0
- package/.github/dependabot.yml +38 -0
- package/.github/skills/dependency-cache-optimization/SKILL.md +526 -0
- package/.github/skills/docker-image-management/SKILL.md +532 -0
- package/.github/skills/frontend-design/SKILL.md +782 -0
- package/.github/skills/prompt-engineering/SKILL.md +360 -0
- package/.github/skills/quality-gate-config/SKILL.md +591 -0
- package/.github/skills/result-report-analysis/SKILL.md +576 -0
- package/.github/skills/test-automation/SKILL.md +593 -0
- package/.github/skills/workflow-diagnosis/SKILL.md +468 -0
- package/.github/workflows/build-docker-image.yml +453 -0
- package/.github/workflows/release.yml +68 -0
- package/.releaserc.json +135 -0
- package/CHANGELOG.md +117 -0
- package/CLAUDE.md +336 -0
- package/CONTRIBUTING.md +339 -0
- package/Dockerfile +217 -0
- package/README.md +1527 -0
- package/STYLE.md +521 -0
- package/add-js-extensions.d.ts +9 -0
- package/add-js-extensions.d.ts.map +1 -0
- package/add-js-extensions.js.map +1 -0
- package/dist/add-js-extensions.d.ts +9 -0
- package/dist/add-js-extensions.d.ts.map +1 -0
- package/dist/add-js-extensions.js +52 -0
- package/dist/add-js-extensions.js.map +1 -0
- package/dist/ansi-colors.d.ts +26 -0
- package/dist/ansi-colors.d.ts.map +1 -0
- package/dist/ansi-colors.js +51 -0
- package/dist/ansi-colors.js.map +1 -0
- package/dist/cli/BaseCommand.d.ts +18 -0
- package/dist/cli/BaseCommand.d.ts.map +1 -0
- package/dist/cli/BaseCommand.js +31 -0
- package/dist/cli/BaseCommand.js.map +1 -0
- package/dist/cli/KasekiCLI.d.ts +30 -0
- package/dist/cli/KasekiCLI.d.ts.map +1 -0
- package/dist/cli/KasekiCLI.js +134 -0
- package/dist/cli/KasekiCLI.js.map +1 -0
- package/dist/cli/commands/ConfigCommand.d.ts +13 -0
- package/dist/cli/commands/ConfigCommand.d.ts.map +1 -0
- package/dist/cli/commands/ConfigCommand.js +131 -0
- package/dist/cli/commands/ConfigCommand.js.map +1 -0
- package/dist/cli/commands/DoctorCommand.d.ts +45 -0
- package/dist/cli/commands/DoctorCommand.d.ts.map +1 -0
- package/dist/cli/commands/DoctorCommand.js +309 -0
- package/dist/cli/commands/DoctorCommand.js.map +1 -0
- package/dist/cli/commands/ListCommand.d.ts +9 -0
- package/dist/cli/commands/ListCommand.d.ts.map +1 -0
- package/dist/cli/commands/ListCommand.js +81 -0
- package/dist/cli/commands/ListCommand.js.map +1 -0
- package/dist/cli/commands/ReportCommand.d.ts +9 -0
- package/dist/cli/commands/ReportCommand.d.ts.map +1 -0
- package/dist/cli/commands/ReportCommand.js +98 -0
- package/dist/cli/commands/ReportCommand.js.map +1 -0
- package/dist/cli/commands/RunCommand.d.ts +13 -0
- package/dist/cli/commands/RunCommand.d.ts.map +1 -0
- package/dist/cli/commands/RunCommand.js +191 -0
- package/dist/cli/commands/RunCommand.js.map +1 -0
- package/dist/cli/commands/SecretsCommand.d.ts +9 -0
- package/dist/cli/commands/SecretsCommand.d.ts.map +1 -0
- package/dist/cli/commands/SecretsCommand.js +109 -0
- package/dist/cli/commands/SecretsCommand.js.map +1 -0
- package/dist/cli/commands/ServeCommand.d.ts +9 -0
- package/dist/cli/commands/ServeCommand.d.ts.map +1 -0
- package/dist/cli/commands/ServeCommand.js +50 -0
- package/dist/cli/commands/ServeCommand.js.map +1 -0
- package/dist/cli/commands/SetupCommand.d.ts +42 -0
- package/dist/cli/commands/SetupCommand.d.ts.map +1 -0
- package/dist/cli/commands/SetupCommand.js +249 -0
- package/dist/cli/commands/SetupCommand.js.map +1 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +130 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/ConfigManager.d.ts +395 -0
- package/dist/config/ConfigManager.d.ts.map +1 -0
- package/dist/config/ConfigManager.js +446 -0
- package/dist/config/ConfigManager.js.map +1 -0
- package/dist/docker/DockerManager.d.ts +69 -0
- package/dist/docker/DockerManager.d.ts.map +1 -0
- package/dist/docker/DockerManager.js +266 -0
- package/dist/docker/DockerManager.js.map +1 -0
- package/dist/event-aggregator.d.ts +71 -0
- package/dist/event-aggregator.d.ts.map +1 -0
- package/dist/event-aggregator.js +95 -0
- package/dist/event-aggregator.js.map +1 -0
- package/dist/github-app-token.d.ts +16 -0
- package/dist/github-app-token.d.ts.map +1 -0
- package/dist/github-app-token.js +148 -0
- package/dist/github-app-token.js.map +1 -0
- package/dist/idempotency-store.d.ts +61 -0
- package/dist/idempotency-store.d.ts.map +1 -0
- package/dist/idempotency-store.js +321 -0
- package/dist/idempotency-store.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/instance/InstanceManager.d.ts +81 -0
- package/dist/instance/InstanceManager.d.ts.map +1 -0
- package/dist/instance/InstanceManager.js +220 -0
- package/dist/instance/InstanceManager.js.map +1 -0
- package/dist/instance-metadata-reader.d.ts +48 -0
- package/dist/instance-metadata-reader.d.ts.map +1 -0
- package/dist/instance-metadata-reader.js +94 -0
- package/dist/instance-metadata-reader.js.map +1 -0
- package/dist/instance-state-derivation.d.ts +42 -0
- package/dist/instance-state-derivation.d.ts.map +1 -0
- package/dist/instance-state-derivation.js +133 -0
- package/dist/instance-state-derivation.js.map +1 -0
- package/dist/job-scheduler.d.ts +124 -0
- package/dist/job-scheduler.d.ts.map +1 -0
- package/dist/job-scheduler.js +992 -0
- package/dist/job-scheduler.js.map +1 -0
- package/dist/kaseki-api-client.d.ts +89 -0
- package/dist/kaseki-api-client.d.ts.map +1 -0
- package/dist/kaseki-api-client.js +405 -0
- package/dist/kaseki-api-client.js.map +1 -0
- package/dist/kaseki-api-config.d.ts +34 -0
- package/dist/kaseki-api-config.d.ts.map +1 -0
- package/dist/kaseki-api-config.js +113 -0
- package/dist/kaseki-api-config.js.map +1 -0
- package/dist/kaseki-api-routes.d.ts +13 -0
- package/dist/kaseki-api-routes.d.ts.map +1 -0
- package/dist/kaseki-api-routes.js +559 -0
- package/dist/kaseki-api-routes.js.map +1 -0
- package/dist/kaseki-api-service-wrapper.d.ts +43 -0
- package/dist/kaseki-api-service-wrapper.d.ts.map +1 -0
- package/dist/kaseki-api-service-wrapper.js +150 -0
- package/dist/kaseki-api-service-wrapper.js.map +1 -0
- package/dist/kaseki-api-service.d.ts +16 -0
- package/dist/kaseki-api-service.d.ts.map +1 -0
- package/dist/kaseki-api-service.js +143 -0
- package/dist/kaseki-api-service.js.map +1 -0
- package/dist/kaseki-api-types.d.ts +440 -0
- package/dist/kaseki-api-types.d.ts.map +1 -0
- package/dist/kaseki-api-types.js +64 -0
- package/dist/kaseki-api-types.js.map +1 -0
- package/dist/kaseki-cli-lib.d.ts +219 -0
- package/dist/kaseki-cli-lib.d.ts.map +1 -0
- package/dist/kaseki-cli-lib.js +523 -0
- package/dist/kaseki-cli-lib.js.map +1 -0
- package/dist/kaseki-cli.d.ts +38 -0
- package/dist/kaseki-cli.d.ts.map +1 -0
- package/dist/kaseki-cli.js +559 -0
- package/dist/kaseki-cli.js.map +1 -0
- package/dist/kaseki-report.d.ts +3 -0
- package/dist/kaseki-report.d.ts.map +1 -0
- package/dist/kaseki-report.js +140 -0
- package/dist/kaseki-report.js.map +1 -0
- package/dist/lib/subprocess-helpers.d.ts +98 -0
- package/dist/lib/subprocess-helpers.d.ts.map +1 -0
- package/dist/lib/subprocess-helpers.js +136 -0
- package/dist/lib/subprocess-helpers.js.map +1 -0
- package/dist/logger.d.ts +39 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +79 -0
- package/dist/logger.js.map +1 -0
- package/dist/metrics.d.ts +19 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +59 -0
- package/dist/metrics.js.map +1 -0
- package/dist/middleware/job-lookup.d.ts +27 -0
- package/dist/middleware/job-lookup.d.ts.map +1 -0
- package/dist/middleware/job-lookup.js +28 -0
- package/dist/middleware/job-lookup.js.map +1 -0
- package/dist/pi-event-filter.d.ts +3 -0
- package/dist/pi-event-filter.d.ts.map +1 -0
- package/dist/pi-event-filter.js +126 -0
- package/dist/pi-event-filter.js.map +1 -0
- package/dist/pi-progress-stream.d.ts +3 -0
- package/dist/pi-progress-stream.d.ts.map +1 -0
- package/dist/pi-progress-stream.js +205 -0
- package/dist/pi-progress-stream.js.map +1 -0
- package/dist/pi-progress-summarizer.d.ts +61 -0
- package/dist/pi-progress-summarizer.d.ts.map +1 -0
- package/dist/pi-progress-summarizer.js +246 -0
- package/dist/pi-progress-summarizer.js.map +1 -0
- package/dist/pre-flight-validator.d.ts +72 -0
- package/dist/pre-flight-validator.d.ts.map +1 -0
- package/dist/pre-flight-validator.js +513 -0
- package/dist/pre-flight-validator.js.map +1 -0
- package/dist/progress-stream-utils.d.ts +3 -0
- package/dist/progress-stream-utils.d.ts.map +1 -0
- package/dist/progress-stream-utils.js +15 -0
- package/dist/progress-stream-utils.js.map +1 -0
- package/dist/result-cache.d.ts +52 -0
- package/dist/result-cache.d.ts.map +1 -0
- package/dist/result-cache.js +134 -0
- package/dist/result-cache.js.map +1 -0
- package/dist/routes/artifact-routes.d.ts +10 -0
- package/dist/routes/artifact-routes.d.ts.map +1 -0
- package/dist/routes/artifact-routes.js +126 -0
- package/dist/routes/artifact-routes.js.map +1 -0
- package/dist/routes/log-routes.d.ts +8 -0
- package/dist/routes/log-routes.d.ts.map +1 -0
- package/dist/routes/log-routes.js +345 -0
- package/dist/routes/log-routes.js.map +1 -0
- package/dist/routes/status-routes.d.ts +8 -0
- package/dist/routes/status-routes.d.ts.map +1 -0
- package/dist/routes/status-routes.js +82 -0
- package/dist/routes/status-routes.js.map +1 -0
- package/dist/routes/webhook-routes.d.ts +6 -0
- package/dist/routes/webhook-routes.d.ts.map +1 -0
- package/dist/routes/webhook-routes.js +86 -0
- package/dist/routes/webhook-routes.js.map +1 -0
- package/dist/run-artifact-metadata-cache.d.ts +42 -0
- package/dist/run-artifact-metadata-cache.d.ts.map +1 -0
- package/dist/run-artifact-metadata-cache.js +139 -0
- package/dist/run-artifact-metadata-cache.js.map +1 -0
- package/dist/secret-value-cache.d.ts +13 -0
- package/dist/secret-value-cache.d.ts.map +1 -0
- package/dist/secret-value-cache.js +44 -0
- package/dist/secret-value-cache.js.map +1 -0
- package/dist/secrets/SecretsManager.d.ts +80 -0
- package/dist/secrets/SecretsManager.d.ts.map +1 -0
- package/dist/secrets/SecretsManager.js +306 -0
- package/dist/secrets/SecretsManager.js.map +1 -0
- package/dist/test-utils.d.ts +55 -0
- package/dist/test-utils.d.ts.map +1 -0
- package/dist/test-utils.js +48 -0
- package/dist/test-utils.js.map +1 -0
- package/dist/timestamp-tracker.d.ts +75 -0
- package/dist/timestamp-tracker.d.ts.map +1 -0
- package/dist/timestamp-tracker.js +121 -0
- package/dist/timestamp-tracker.js.map +1 -0
- package/dist/utils/failure-artifact-writer.d.ts +29 -0
- package/dist/utils/failure-artifact-writer.d.ts.map +1 -0
- package/dist/utils/failure-artifact-writer.js +157 -0
- package/dist/utils/failure-artifact-writer.js.map +1 -0
- package/dist/utils/file-helpers.d.ts +41 -0
- package/dist/utils/file-helpers.d.ts.map +1 -0
- package/dist/utils/file-helpers.js +143 -0
- package/dist/utils/file-helpers.js.map +1 -0
- package/dist/utils/http-client-factory.d.ts +46 -0
- package/dist/utils/http-client-factory.d.ts.map +1 -0
- package/dist/utils/http-client-factory.js +114 -0
- package/dist/utils/http-client-factory.js.map +1 -0
- package/dist/utils/progress-normalizer.d.ts +13 -0
- package/dist/utils/progress-normalizer.d.ts.map +1 -0
- package/dist/utils/progress-normalizer.js +57 -0
- package/dist/utils/progress-normalizer.js.map +1 -0
- package/dist/utils/response-helpers.d.ts +34 -0
- package/dist/utils/response-helpers.d.ts.map +1 -0
- package/dist/utils/response-helpers.js +78 -0
- package/dist/utils/response-helpers.js.map +1 -0
- package/dist/utils/route-helpers.d.ts +17 -0
- package/dist/utils/route-helpers.d.ts.map +1 -0
- package/dist/utils/route-helpers.js +22 -0
- package/dist/utils/route-helpers.js.map +1 -0
- package/dist/utils/status-response-builder.d.ts +23 -0
- package/dist/utils/status-response-builder.d.ts.map +1 -0
- package/dist/utils/status-response-builder.js +144 -0
- package/dist/utils/status-response-builder.js.map +1 -0
- package/dist/utils/type-guards.d.ts +37 -0
- package/dist/utils/type-guards.d.ts.map +1 -0
- package/dist/utils/type-guards.js +45 -0
- package/dist/utils/type-guards.js.map +1 -0
- package/dist/utils/utf8-helpers.d.ts +32 -0
- package/dist/utils/utf8-helpers.d.ts.map +1 -0
- package/dist/utils/utf8-helpers.js +97 -0
- package/dist/utils/utf8-helpers.js.map +1 -0
- package/dist/utils/webhook-event-builder.d.ts +26 -0
- package/dist/utils/webhook-event-builder.d.ts.map +1 -0
- package/dist/utils/webhook-event-builder.js +77 -0
- package/dist/utils/webhook-event-builder.js.map +1 -0
- package/dist/webhook-manager.d.ts +56 -0
- package/dist/webhook-manager.d.ts.map +1 -0
- package/dist/webhook-manager.js +359 -0
- package/dist/webhook-manager.js.map +1 -0
- package/docker/workspace-cache/package-lock.json +13 -0
- package/docker/workspace-cache/package.json +7 -0
- package/docker-compose.yml +53 -0
- package/docs/API.md +708 -0
- package/docs/BACKLOG.md +19 -0
- package/docs/BUILD_STRATEGY.md +404 -0
- package/docs/CLI.md +569 -0
- package/docs/DEPLOYMENT.md +521 -0
- package/docs/DEVELOPMENT.md +459 -0
- package/docs/DOCKER_SETUP.md +522 -0
- package/docs/ENHANCED_PROGRESS_LOGS.md +264 -0
- package/docs/IMPLEMENTATION_SUMMARY.md +549 -0
- package/docs/INTEGRATION_EXAMPLE.md +217 -0
- package/docs/NPM_SETUP.md +468 -0
- package/docs/PHASE1-4_IMPLEMENTATION.md +302 -0
- package/docs/PHASE1_COMPLETION.md +192 -0
- package/docs/PHASE2_COMPLETION.md +134 -0
- package/docs/PHASE6_MIGRATION.md +392 -0
- package/docs/PRINTF_SAFETY_FIX.md +282 -0
- package/docs/QUALITY_GATES.md +369 -0
- package/docs/SETUP_GUIDE.md +482 -0
- package/docs/TASK_PROMPT_TEMPLATES.md +533 -0
- package/docs/VALIDATION_FIX.md +139 -0
- package/docs/VERIFICATION_CHECKLIST.md +335 -0
- package/docs/repo-maturity.md +760 -0
- package/fix-tests.d.ts +9 -0
- package/fix-tests.d.ts.map +1 -0
- package/fix-tests.js.map +1 -0
- package/fix-tests.ts +53 -0
- package/jest.config.ts +31 -0
- package/kaseki +183 -0
- package/kaseki-agent.sh +1961 -0
- package/ops/logrotate/kaseki +10 -0
- package/package.json +83 -0
- package/perf/README.md +54 -0
- package/perf/pi-event-filter.benchmark.test.ts +98 -0
- package/run-kaseki-json.test.sh +106 -0
- package/run-kaseki.sh +990 -0
- package/scripts/allowlist-helper.sh +56 -0
- package/scripts/cleanup-kaseki.sh +168 -0
- package/scripts/deploy-pi-template.sh +293 -0
- package/scripts/docker-entrypoint.sh +71 -0
- package/scripts/dry-run-allowlist.sh +161 -0
- package/scripts/kaseki-activate.sh +396 -0
- package/scripts/kaseki-api.service +62 -0
- package/scripts/kaseki-container-entrypoint-wrapper.sh +119 -0
- package/scripts/kaseki-container-setup-remote.sh +172 -0
- package/scripts/kaseki-container-setup.sh +193 -0
- package/scripts/kaseki-healthcheck.sh +95 -0
- package/scripts/kaseki-install.sh +50 -0
- package/scripts/kaseki-maturity-score.sh +291 -0
- package/scripts/kaseki-performance-metrics.sh +122 -0
- package/scripts/kaseki-preflight.sh +270 -0
- package/scripts/kaseki-setup.sh +265 -0
- package/scripts/pi-setup-remote.sh +213 -0
- package/scripts/setup-github-labels.sh +42 -0
- package/scripts/suggest-allowlist.sh +68 -0
- package/scripts/templates/MULTI_HOST_DISTRIBUTED.md +337 -0
- package/scripts/templates/REST_API_SERVICE.md +490 -0
- package/scripts/templates/SINGLE_HOST_CLI.md +194 -0
- package/scripts/test-github-app.sh +248 -0
- package/src/add-js-extensions.ts +61 -0
- package/src/ansi-colors.test.ts +62 -0
- package/src/ansi-colors.ts +67 -0
- package/src/cli/BaseCommand.ts +40 -0
- package/src/cli/KasekiCLI.ts +154 -0
- package/src/cli/commands/ConfigCommand.ts +145 -0
- package/src/cli/commands/DoctorCommand.ts +329 -0
- package/src/cli/commands/ListCommand.ts +105 -0
- package/src/cli/commands/ReportCommand.ts +110 -0
- package/src/cli/commands/RunCommand.ts +218 -0
- package/src/cli/commands/SecretsCommand.ts +120 -0
- package/src/cli/commands/ServeCommand.ts +62 -0
- package/src/cli/commands/SetupCommand.ts +301 -0
- package/src/cli.ts +138 -0
- package/src/config/ConfigManager.ts +476 -0
- package/src/docker/DockerManager.ts +319 -0
- package/src/docker-entrypoint-packaging.test.ts +33 -0
- package/src/event-aggregator.test.ts +117 -0
- package/src/event-aggregator.ts +126 -0
- package/src/github-app-token.ts +215 -0
- package/src/idempotency-store.test.ts +117 -0
- package/src/idempotency-store.ts +385 -0
- package/src/index.ts +89 -0
- package/src/instance/InstanceManager.ts +285 -0
- package/src/instance-metadata-reader.test.ts +190 -0
- package/src/instance-metadata-reader.ts +129 -0
- package/src/instance-state-derivation.test.ts +263 -0
- package/src/instance-state-derivation.ts +148 -0
- package/src/job-scheduler.test.ts +1236 -0
- package/src/job-scheduler.ts +1117 -0
- package/src/kaseki-api-client.ts +488 -0
- package/src/kaseki-api-config.test.ts +315 -0
- package/src/kaseki-api-config.ts +175 -0
- package/src/kaseki-api-routes.test.ts +1615 -0
- package/src/kaseki-api-routes.ts +643 -0
- package/src/kaseki-api-service-wrapper.ts +188 -0
- package/src/kaseki-api-service.test.ts +418 -0
- package/src/kaseki-api-service.ts +192 -0
- package/src/kaseki-api-types.ts +320 -0
- package/src/kaseki-cli-lib.test.ts +552 -0
- package/src/kaseki-cli-lib.ts +760 -0
- package/src/kaseki-cli.ts +682 -0
- package/src/kaseki-report.test.ts +118 -0
- package/src/kaseki-report.ts +192 -0
- package/src/lib/subprocess-helpers.ts +177 -0
- package/src/logger.ts +114 -0
- package/src/metrics.ts +66 -0
- package/src/middleware/job-lookup.test.ts +113 -0
- package/src/middleware/job-lookup.ts +45 -0
- package/src/pi-event-filter.test.ts +183 -0
- package/src/pi-event-filter.ts +183 -0
- package/src/pi-progress-stream.ts +287 -0
- package/src/pi-progress-summarizer.test.ts +302 -0
- package/src/pi-progress-summarizer.ts +287 -0
- package/src/pre-flight-validator.test.ts +512 -0
- package/src/pre-flight-validator.ts +618 -0
- package/src/progress-stream-utils.test.ts +35 -0
- package/src/progress-stream-utils.ts +14 -0
- package/src/result-cache.test.ts +195 -0
- package/src/result-cache.ts +181 -0
- package/src/routes/artifact-routes.ts +169 -0
- package/src/routes/log-routes.ts +391 -0
- package/src/routes/status-routes.ts +92 -0
- package/src/routes/webhook-routes.ts +97 -0
- package/src/run-artifact-metadata-cache.test.ts +80 -0
- package/src/run-artifact-metadata-cache.ts +184 -0
- package/src/secret-value-cache.test.ts +66 -0
- package/src/secret-value-cache.ts +55 -0
- package/src/secrets/SecretsManager.ts +343 -0
- package/src/test-utils.ts +81 -0
- package/src/timestamp-tracker.test.ts +134 -0
- package/src/timestamp-tracker.ts +132 -0
- package/src/utils/failure-artifact-writer.ts +187 -0
- package/src/utils/file-helpers.test.ts +235 -0
- package/src/utils/file-helpers.ts +150 -0
- package/src/utils/http-client-factory.test.ts +245 -0
- package/src/utils/http-client-factory.ts +157 -0
- package/src/utils/progress-normalizer.test.ts +442 -0
- package/src/utils/progress-normalizer.ts +68 -0
- package/src/utils/response-helpers.test.ts +122 -0
- package/src/utils/response-helpers.ts +101 -0
- package/src/utils/route-helpers.ts +30 -0
- package/src/utils/status-response-builder.ts +159 -0
- package/src/utils/type-guards.ts +52 -0
- package/src/utils/utf8-helpers.ts +102 -0
- package/src/utils/webhook-event-builder.test.ts +143 -0
- package/src/utils/webhook-event-builder.ts +87 -0
- package/src/webhook-manager.test.ts +152 -0
- package/src/webhook-manager.ts +445 -0
- package/templates/allowlist-api-route.txt +7 -0
- package/templates/allowlist-comprehensive.txt +8 -0
- package/templates/allowlist-parser-fix.txt +6 -0
- package/templates/allowlist-ui-component.txt +9 -0
- package/templates/allowlist-utility.txt +9 -0
- package/test/actual-model-metadata.test.sh +102 -0
- package/test/dry-run.test.sh +131 -0
- package/test/fixtures/kaseki-report-exit-codes/metadata-exit-0.json +1 -0
- package/test/fixtures/kaseki-report-exit-codes/metadata-exit-1.json +1 -0
- package/test/fixtures/kaseki-report-exit-codes/metadata-exit-invalid.json +1 -0
- package/test/fixtures/kaseki-report-exit-codes/metadata-exit-str-0.json +1 -0
- package/test/fixtures/kaseki-report-exit-codes/metadata-exit-str-1.json +1 -0
- package/test/kaseki-api.integration.test.sh +165 -0
- package/test/pi-event-filter-failure.test.sh +83 -0
- package/test/printf-safety-focused.test.sh +99 -0
- package/test/printf-safety-results/results/restoration.jsonl +10 -0
- package/test/printf-safety-results/results/test.jsonl +0 -0
- package/test/printf-safety.test.sh +297 -0
- package/test/validation-fix.test.sh +79 -0
- package/test/validation-integration.test.sh +109 -0
- package/tests/allowlist-glob.test.sh +61 -0
- package/tests/dependency-cache-key.test.sh +48 -0
- package/tests/dependency-restore-mode.test.sh +48 -0
- package/tests/doctor-template-parity.test.sh +95 -0
- package/tests/github-operations.test.sh +142 -0
- package/tests/npm-install-flags.test.sh +58 -0
- package/tests/quality-gates.test.sh +178 -0
- package/tests/repo-memory.test.sh +103 -0
- package/tests/restore-disallowed-changes.test.sh +80 -0
- package/tests/validation-missing-npm-scripts.test.sh +93 -0
- package/tests/validation-strict-mode.test.sh +118 -0
- package/tsconfig.changed.json +7 -0
- 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
|
+
}
|