lastlight 0.1.8 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +265 -118
- package/agent-context/rules.md +62 -9
- package/agent-context/security.md +69 -0
- package/config/default.yaml +89 -0
- package/deploy/.env.production.example +20 -2
- package/deploy/entrypoint.sh +16 -17
- package/deploy/native/README.md +160 -0
- package/deploy/native/install.sh +110 -0
- package/deploy/native/lastlight.env.example +95 -0
- package/deploy/native/lastlight.service +50 -0
- package/deploy/sandbox-entrypoint.sh +59 -42
- package/dist/admin/auth.d.ts +1 -1
- package/dist/admin/auth.js +3 -1
- package/dist/admin/auth.js.map +1 -1
- package/dist/admin/chat-session-reader.d.ts +11 -14
- package/dist/admin/chat-session-reader.js +27 -51
- package/dist/admin/chat-session-reader.js.map +1 -1
- package/dist/admin/docker.d.ts +37 -0
- package/dist/admin/docker.js +86 -1
- package/dist/admin/docker.js.map +1 -1
- package/dist/admin/index.js +38 -3
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/log-search.test.d.ts +1 -0
- package/dist/admin/log-search.test.js +78 -0
- package/dist/admin/log-search.test.js.map +1 -0
- package/dist/admin/routes.d.ts +52 -3
- package/dist/admin/routes.js +780 -63
- package/dist/admin/routes.js.map +1 -1
- package/dist/admin/routes.test.js +680 -14
- package/dist/admin/routes.test.js.map +1 -1
- package/dist/admin/server-logs.test.d.ts +1 -0
- package/dist/admin/server-logs.test.js +58 -0
- package/dist/admin/server-logs.test.js.map +1 -0
- package/dist/admin/sessions.d.ts +26 -39
- package/dist/admin/sessions.js +86 -310
- package/dist/admin/sessions.js.map +1 -1
- package/dist/admin/sessions.test.d.ts +1 -0
- package/dist/admin/sessions.test.js +78 -0
- package/dist/admin/sessions.test.js.map +1 -0
- package/dist/admin/version.d.ts +15 -0
- package/dist/admin/version.js +73 -0
- package/dist/admin/version.js.map +1 -0
- package/dist/admin/version.test.d.ts +1 -0
- package/dist/admin/version.test.js +71 -0
- package/dist/admin/version.test.js.map +1 -0
- package/dist/cli-config.d.ts +55 -0
- package/dist/cli-config.js +119 -0
- package/dist/cli-config.js.map +1 -0
- package/dist/cli-config.test.d.ts +1 -0
- package/dist/cli-config.test.js +92 -0
- package/dist/cli-config.test.js.map +1 -0
- package/dist/cli-format.d.ts +19 -0
- package/dist/cli-format.js +107 -0
- package/dist/cli-format.js.map +1 -0
- package/dist/cli-server.d.ts +73 -0
- package/dist/cli-server.js +347 -0
- package/dist/cli-server.js.map +1 -0
- package/dist/cli-server.test.d.ts +1 -0
- package/dist/cli-server.test.js +38 -0
- package/dist/cli-server.test.js.map +1 -0
- package/dist/cli-timeline.d.ts +35 -0
- package/dist/cli-timeline.js +373 -0
- package/dist/cli-timeline.js.map +1 -0
- package/dist/cli-timeline.test.d.ts +1 -0
- package/dist/cli-timeline.test.js +104 -0
- package/dist/cli-timeline.test.js.map +1 -0
- package/dist/cli.d.ts +0 -19
- package/dist/cli.js +910 -194
- package/dist/cli.js.map +1 -1
- package/dist/config-overlay.test.d.ts +1 -0
- package/dist/config-overlay.test.js +112 -0
- package/dist/config-overlay.test.js.map +1 -0
- package/dist/config-resolve.d.ts +28 -0
- package/dist/config-resolve.js +47 -0
- package/dist/config-resolve.js.map +1 -0
- package/dist/config-resolve.test.d.ts +1 -0
- package/dist/config-resolve.test.js +68 -0
- package/dist/config-resolve.test.js.map +1 -0
- package/dist/config.d.ts +62 -49
- package/dist/config.js +452 -76
- package/dist/config.js.map +1 -1
- package/dist/config.test.js +201 -32
- package/dist/config.test.js.map +1 -1
- package/dist/connectors/github-webhook.js +83 -5
- package/dist/connectors/github-webhook.js.map +1 -1
- package/dist/connectors/github-webhook.test.d.ts +1 -0
- package/dist/connectors/github-webhook.test.js +156 -0
- package/dist/connectors/github-webhook.test.js.map +1 -0
- package/dist/connectors/messaging/session-manager.d.ts +18 -0
- package/dist/connectors/messaging/session-manager.js +83 -2
- package/dist/connectors/messaging/session-manager.js.map +1 -1
- package/dist/connectors/messaging/session-manager.test.d.ts +1 -0
- package/dist/connectors/messaging/session-manager.test.js +144 -0
- package/dist/connectors/messaging/session-manager.test.js.map +1 -0
- package/dist/connectors/slack/connector.d.ts +9 -0
- package/dist/connectors/slack/connector.js +15 -0
- package/dist/connectors/slack/connector.js.map +1 -1
- package/dist/connectors/slack/mrkdwn.js +81 -0
- package/dist/connectors/slack/mrkdwn.js.map +1 -1
- package/dist/connectors/slack/mrkdwn.test.js +49 -0
- package/dist/connectors/slack/mrkdwn.test.js.map +1 -1
- package/dist/connectors/types.d.ts +1 -1
- package/dist/cron/fanout.d.ts +33 -0
- package/dist/cron/fanout.js +55 -0
- package/dist/cron/fanout.js.map +1 -0
- package/dist/cron/fanout.test.d.ts +1 -0
- package/dist/cron/fanout.test.js +73 -0
- package/dist/cron/fanout.test.js.map +1 -0
- package/dist/cron/jobs.d.ts +5 -0
- package/dist/cron/jobs.js +10 -3
- package/dist/cron/jobs.js.map +1 -1
- package/dist/cron/scheduler.d.ts +12 -0
- package/dist/cron/scheduler.js +27 -1
- package/dist/cron/scheduler.js.map +1 -1
- package/dist/engine/agent-executor.d.ts +158 -0
- package/dist/engine/agent-executor.js +1140 -0
- package/dist/engine/agent-executor.js.map +1 -0
- package/dist/engine/agent-executor.test.d.ts +1 -0
- package/dist/engine/agent-executor.test.js +395 -0
- package/dist/engine/agent-executor.test.js.map +1 -0
- package/dist/engine/chat-runner.d.ts +123 -0
- package/dist/engine/chat-runner.js +379 -0
- package/dist/engine/chat-runner.js.map +1 -0
- package/dist/engine/chat-runner.test.d.ts +1 -0
- package/dist/engine/chat-runner.test.js +104 -0
- package/dist/engine/chat-runner.test.js.map +1 -0
- package/dist/engine/chat-skills.d.ts +45 -0
- package/dist/engine/chat-skills.js +184 -0
- package/dist/engine/chat-skills.js.map +1 -0
- package/dist/engine/chat-skills.test.d.ts +1 -0
- package/dist/engine/chat-skills.test.js +20 -0
- package/dist/engine/chat-skills.test.js.map +1 -0
- package/dist/engine/chat.d.ts +20 -23
- package/dist/engine/chat.js +251 -155
- package/dist/engine/chat.js.map +1 -1
- package/dist/engine/chat.test.d.ts +1 -0
- package/dist/engine/chat.test.js +42 -0
- package/dist/engine/chat.test.js.map +1 -0
- package/dist/engine/classifier.d.ts +35 -2
- package/dist/engine/classifier.js +170 -31
- package/dist/engine/classifier.js.map +1 -1
- package/dist/engine/classifier.test.d.ts +1 -0
- package/dist/engine/classifier.test.js +115 -0
- package/dist/engine/classifier.test.js.map +1 -0
- package/dist/engine/dispatcher.d.ts +60 -0
- package/dist/engine/dispatcher.js +601 -0
- package/dist/engine/dispatcher.js.map +1 -0
- package/dist/engine/dispatcher.test.d.ts +1 -0
- package/dist/engine/dispatcher.test.js +511 -0
- package/dist/engine/dispatcher.test.js.map +1 -0
- package/dist/engine/event-shim.d.ts +117 -0
- package/dist/engine/event-shim.js +435 -0
- package/dist/engine/event-shim.js.map +1 -0
- package/dist/engine/event-shim.test.d.ts +1 -0
- package/dist/engine/event-shim.test.js +194 -0
- package/dist/engine/event-shim.test.js.map +1 -0
- package/dist/engine/git-auth.d.ts +13 -17
- package/dist/engine/git-auth.js +99 -42
- package/dist/engine/git-auth.js.map +1 -1
- package/dist/engine/git-auth.test.d.ts +1 -0
- package/dist/engine/git-auth.test.js +117 -0
- package/dist/engine/git-auth.test.js.map +1 -0
- package/dist/engine/github-app-client.d.ts +7 -0
- package/dist/engine/github-app-client.js +16 -0
- package/dist/engine/github-app-client.js.map +1 -0
- package/dist/engine/github-app-client.test.d.ts +1 -0
- package/dist/engine/github-app-client.test.js +44 -0
- package/dist/engine/github-app-client.test.js.map +1 -0
- package/dist/engine/github-tools.d.ts +12 -0
- package/dist/engine/github-tools.js +261 -0
- package/dist/engine/github-tools.js.map +1 -0
- package/dist/engine/github.d.ts +1027 -43
- package/dist/engine/github.js +153 -14
- package/dist/engine/github.js.map +1 -1
- package/dist/engine/llm.d.ts +47 -0
- package/dist/engine/llm.js +221 -0
- package/dist/engine/llm.js.map +1 -0
- package/dist/engine/llm.test.d.ts +1 -0
- package/dist/engine/llm.test.js +189 -0
- package/dist/engine/llm.test.js.map +1 -0
- package/dist/engine/profiles.d.ts +249 -0
- package/dist/engine/profiles.js +42 -0
- package/dist/engine/profiles.js.map +1 -0
- package/dist/engine/router.d.ts +12 -6
- package/dist/engine/router.js +339 -81
- package/dist/engine/router.js.map +1 -1
- package/dist/engine/router.test.js +428 -78
- package/dist/engine/router.test.js.map +1 -1
- package/dist/engine/screen.d.ts +41 -0
- package/dist/engine/screen.js +93 -0
- package/dist/engine/screen.js.map +1 -0
- package/dist/engine/screen.test.d.ts +1 -0
- package/dist/engine/screen.test.js +82 -0
- package/dist/engine/screen.test.js.map +1 -0
- package/dist/index.js +423 -437
- package/dist/index.js.map +1 -1
- package/dist/managed-repos.d.ts +7 -9
- package/dist/managed-repos.js +12 -15
- package/dist/managed-repos.js.map +1 -1
- package/dist/managed-repos.test.js +24 -19
- package/dist/managed-repos.test.js.map +1 -1
- package/dist/notify/index.d.ts +15 -0
- package/dist/notify/index.js +6 -0
- package/dist/notify/index.js.map +1 -0
- package/dist/notify/model.d.ts +57 -0
- package/dist/notify/model.js +89 -0
- package/dist/notify/model.js.map +1 -0
- package/dist/notify/model.test.d.ts +1 -0
- package/dist/notify/model.test.js +109 -0
- package/dist/notify/model.test.js.map +1 -0
- package/dist/notify/notifier.d.ts +17 -0
- package/dist/notify/notifier.js +87 -0
- package/dist/notify/notifier.js.map +1 -0
- package/dist/notify/notifier.test.d.ts +1 -0
- package/dist/notify/notifier.test.js +100 -0
- package/dist/notify/notifier.test.js.map +1 -0
- package/dist/notify/render.d.ts +21 -0
- package/dist/notify/render.js +59 -0
- package/dist/notify/render.js.map +1 -0
- package/dist/notify/render.test.d.ts +1 -0
- package/dist/notify/render.test.js +65 -0
- package/dist/notify/render.test.js.map +1 -0
- package/dist/notify/transports/github.d.ts +26 -0
- package/dist/notify/transports/github.js +26 -0
- package/dist/notify/transports/github.js.map +1 -0
- package/dist/notify/transports/slack.d.ts +26 -0
- package/dist/notify/transports/slack.js +28 -0
- package/dist/notify/transports/slack.js.map +1 -0
- package/dist/notify/transports.test.d.ts +1 -0
- package/dist/notify/transports.test.js +71 -0
- package/dist/notify/transports.test.js.map +1 -0
- package/dist/notify/types.d.ts +95 -0
- package/dist/notify/types.js +16 -0
- package/dist/notify/types.js.map +1 -0
- package/dist/sandbox/docker-compose.test.d.ts +1 -0
- package/dist/sandbox/docker-compose.test.js +128 -0
- package/dist/sandbox/docker-compose.test.js.map +1 -0
- package/dist/sandbox/docker.d.ts +97 -9
- package/dist/sandbox/docker.js +192 -41
- package/dist/sandbox/docker.js.map +1 -1
- package/dist/sandbox/docker.test.d.ts +1 -0
- package/dist/sandbox/docker.test.js +137 -0
- package/dist/sandbox/docker.test.js.map +1 -0
- package/dist/sandbox/egress-allowlist.d.ts +69 -0
- package/dist/sandbox/egress-allowlist.js +164 -0
- package/dist/sandbox/egress-allowlist.js.map +1 -0
- package/dist/sandbox/egress-allowlist.test.d.ts +1 -0
- package/dist/sandbox/egress-allowlist.test.js +65 -0
- package/dist/sandbox/egress-allowlist.test.js.map +1 -0
- package/dist/sandbox/egress-firewall-config.d.ts +127 -0
- package/dist/sandbox/egress-firewall-config.js +434 -0
- package/dist/sandbox/egress-firewall-config.js.map +1 -0
- package/dist/sandbox/egress-firewall-config.test.d.ts +1 -0
- package/dist/sandbox/egress-firewall-config.test.js +244 -0
- package/dist/sandbox/egress-firewall-config.test.js.map +1 -0
- package/dist/sandbox/images.d.ts +23 -0
- package/dist/sandbox/images.js +55 -0
- package/dist/sandbox/images.js.map +1 -0
- package/dist/sandbox/index.d.ts +82 -3
- package/dist/sandbox/index.js +223 -93
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sandbox/index.test.d.ts +1 -0
- package/dist/sandbox/index.test.js +157 -0
- package/dist/sandbox/index.test.js.map +1 -0
- package/dist/session-log.d.ts +63 -0
- package/dist/session-log.js +290 -0
- package/dist/session-log.js.map +1 -0
- package/dist/session-log.test.d.ts +1 -0
- package/dist/session-log.test.js +85 -0
- package/dist/session-log.test.js.map +1 -0
- package/dist/setup.d.ts +31 -12
- package/dist/setup.js +516 -174
- package/dist/setup.js.map +1 -1
- package/dist/setup.test.js +138 -6
- package/dist/setup.test.js.map +1 -1
- package/dist/state/approval-store.d.ts +86 -0
- package/dist/state/approval-store.js +140 -0
- package/dist/state/approval-store.js.map +1 -0
- package/dist/state/build-assets.d.ts +50 -0
- package/dist/state/build-assets.js +154 -0
- package/dist/state/build-assets.js.map +1 -0
- package/dist/state/build-assets.test.d.ts +1 -0
- package/dist/state/build-assets.test.js +106 -0
- package/dist/state/build-assets.test.js.map +1 -0
- package/dist/state/db.d.ts +65 -333
- package/dist/state/db.js +112 -835
- package/dist/state/db.js.map +1 -1
- package/dist/state/db.test.js +127 -91
- package/dist/state/db.test.js.map +1 -1
- package/dist/state/execution-store.d.ts +257 -0
- package/dist/state/execution-store.js +527 -0
- package/dist/state/execution-store.js.map +1 -0
- package/dist/state/migrate.d.ts +15 -0
- package/dist/state/migrate.js +175 -0
- package/dist/state/migrate.js.map +1 -0
- package/dist/state/workflow-run-store.d.ts +195 -0
- package/dist/state/workflow-run-store.js +363 -0
- package/dist/state/workflow-run-store.js.map +1 -0
- package/dist/state/workflow-run-store.test.d.ts +1 -0
- package/dist/state/workflow-run-store.test.js +264 -0
- package/dist/state/workflow-run-store.test.js.map +1 -0
- package/dist/telemetry/index.d.ts +38 -0
- package/dist/telemetry/index.js +253 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/telemetry/index.test.d.ts +1 -0
- package/dist/telemetry/index.test.js +73 -0
- package/dist/telemetry/index.test.js.map +1 -0
- package/dist/telemetry/pi-events.d.ts +12 -0
- package/dist/telemetry/pi-events.js +134 -0
- package/dist/telemetry/pi-events.js.map +1 -0
- package/dist/telemetry/pi-events.test.d.ts +1 -0
- package/dist/telemetry/pi-events.test.js +69 -0
- package/dist/telemetry/pi-events.test.js.map +1 -0
- package/dist/workflows/dag.d.ts +13 -1
- package/dist/workflows/dag.js +7 -3
- package/dist/workflows/dag.js.map +1 -1
- package/dist/workflows/dag.test.js +22 -0
- package/dist/workflows/dag.test.js.map +1 -1
- package/dist/workflows/golden-build.test.d.ts +1 -0
- package/dist/workflows/golden-build.test.js +45 -0
- package/dist/workflows/golden-build.test.js.map +1 -0
- package/dist/workflows/loader-overlay.test.d.ts +1 -0
- package/dist/workflows/loader-overlay.test.js +101 -0
- package/dist/workflows/loader-overlay.test.js.map +1 -0
- package/dist/workflows/loader.d.ts +36 -11
- package/dist/workflows/loader.js +311 -87
- package/dist/workflows/loader.js.map +1 -1
- package/dist/workflows/loader.test.js +114 -10
- package/dist/workflows/loader.test.js.map +1 -1
- package/dist/workflows/loop-eval.js +2 -0
- package/dist/workflows/loop-eval.js.map +1 -1
- package/dist/workflows/loop-eval.test.js +14 -0
- package/dist/workflows/loop-eval.test.js.map +1 -1
- package/dist/workflows/phase-executor.d.ts +145 -0
- package/dist/workflows/phase-executor.js +691 -0
- package/dist/workflows/phase-executor.js.map +1 -0
- package/dist/workflows/phase-executor.test.d.ts +1 -0
- package/dist/workflows/phase-executor.test.js +434 -0
- package/dist/workflows/phase-executor.test.js.map +1 -0
- package/dist/workflows/phase-ref.d.ts +44 -0
- package/dist/workflows/phase-ref.js +78 -0
- package/dist/workflows/phase-ref.js.map +1 -0
- package/dist/workflows/phase-ref.test.d.ts +1 -0
- package/dist/workflows/phase-ref.test.js +24 -0
- package/dist/workflows/phase-ref.test.js.map +1 -0
- package/dist/workflows/resume.d.ts +5 -11
- package/dist/workflows/resume.js +88 -7
- package/dist/workflows/resume.js.map +1 -1
- package/dist/workflows/runner.d.ts +34 -27
- package/dist/workflows/runner.js +252 -930
- package/dist/workflows/runner.js.map +1 -1
- package/dist/workflows/runner.test.js +346 -35
- package/dist/workflows/runner.test.js.map +1 -1
- package/dist/workflows/schema.d.ts +52 -10
- package/dist/workflows/schema.js +147 -7
- package/dist/workflows/schema.js.map +1 -1
- package/dist/workflows/simple.d.ts +67 -3
- package/dist/workflows/simple.js +248 -87
- package/dist/workflows/simple.js.map +1 -1
- package/dist/workflows/simple.test.d.ts +1 -0
- package/dist/workflows/simple.test.js +107 -0
- package/dist/workflows/simple.test.js.map +1 -0
- package/dist/workflows/templates.d.ts +29 -0
- package/dist/workflows/templates.js +42 -4
- package/dist/workflows/templates.js.map +1 -1
- package/dist/workflows/templates.test.js +103 -0
- package/dist/workflows/templates.test.js.map +1 -1
- package/dist/workflows/triggers.d.ts +21 -0
- package/dist/workflows/triggers.js +44 -0
- package/dist/workflows/triggers.js.map +1 -0
- package/dist/workflows/verdict.d.ts +19 -0
- package/dist/workflows/verdict.js +30 -0
- package/dist/workflows/verdict.js.map +1 -0
- package/dist/workflows/verdict.test.d.ts +1 -0
- package/dist/workflows/verdict.test.js +44 -0
- package/dist/workflows/verdict.test.js.map +1 -0
- package/dist/worktree/manager.d.ts +1 -1
- package/dist/worktree/manager.js +14 -14
- package/dist/worktree/manager.js.map +1 -1
- package/dist/worktree/manager.test.d.ts +1 -0
- package/dist/worktree/manager.test.js +87 -0
- package/dist/worktree/manager.test.js.map +1 -0
- package/docker-compose.yml +206 -5
- package/package.json +19 -7
- package/sandbox.Dockerfile +97 -18
- package/skills/README.md +40 -0
- package/skills/browser-qa/SKILL.md +193 -0
- package/skills/browser-qa/scripts/agent-browser.mjs +380 -0
- package/skills/building/SKILL.md +95 -0
- package/skills/chat/SKILL.md +30 -11
- package/skills/code-review/SKILL.md +59 -0
- package/skills/debug-production/SKILL.md +108 -0
- package/skills/demo/SKILL.md +194 -0
- package/skills/demo/scripts/compose-demo.sh +205 -0
- package/skills/issue-answer/SKILL.md +90 -0
- package/skills/issue-comment/SKILL.md +38 -24
- package/skills/issue-triage/SKILL.md +103 -37
- package/skills/issue-triage/references/AGENT-BRIEF.md +61 -0
- package/skills/pr-comment/SKILL.md +64 -0
- package/skills/pr-review/SKILL.md +65 -49
- package/skills/qa-test/SKILL.md +97 -0
- package/skills/repo-health/SKILL.md +48 -45
- package/skills/security-feedback/SKILL.md +173 -0
- package/skills/security-feedback/references/templates.md +77 -0
- package/skills/security-review/SKILL.md +213 -0
- package/skills/security-review/references/issue-format.md +302 -0
- package/skills/verify/SKILL.md +118 -0
- package/workflows/answer.yaml +37 -0
- package/workflows/build.yaml +32 -22
- package/workflows/cron-security.yaml +6 -0
- package/workflows/demo.yaml +55 -0
- package/workflows/explore.yaml +9 -0
- package/workflows/pr-comment.yaml +16 -0
- package/workflows/pr-fix.yaml +3 -0
- package/workflows/pr-review.yaml +4 -1
- package/workflows/prompts/answer.md +67 -0
- package/workflows/prompts/architect.md +24 -7
- package/workflows/prompts/demo.md +100 -0
- package/workflows/prompts/executor.md +29 -20
- package/workflows/prompts/explore-ask.md +51 -22
- package/workflows/prompts/explore-publish.md +2 -2
- package/workflows/prompts/explore-read.md +24 -10
- package/workflows/prompts/explore-synthesize.md +15 -8
- package/workflows/prompts/fix.md +9 -10
- package/workflows/prompts/guardrails.md +26 -8
- package/workflows/prompts/pr-fix.md +6 -7
- package/workflows/prompts/pr.md +11 -10
- package/workflows/prompts/qa-browser.md +95 -0
- package/workflows/prompts/qa-synth.md +44 -0
- package/workflows/prompts/qa-test.md +60 -0
- package/workflows/prompts/re-reviewer.md +8 -9
- package/workflows/prompts/reviewer.md +10 -9
- package/workflows/prompts/verify-browser.md +93 -0
- package/workflows/prompts/verify-synth.md +44 -0
- package/workflows/prompts/verify.md +63 -0
- package/workflows/qa-test.yaml +87 -0
- package/workflows/security-feedback.yaml +25 -0
- package/workflows/security-review.yaml +29 -0
- package/workflows/verify.yaml +85 -0
- package/deploy/mcp-config.tmpl.json +0 -14
- package/dist/cron/rate-limits.d.ts +0 -26
- package/dist/cron/rate-limits.js +0 -193
- package/dist/cron/rate-limits.js.map +0 -1
- package/dist/engine/executor.d.ts +0 -75
- package/dist/engine/executor.js +0 -292
- package/dist/engine/executor.js.map +0 -1
- package/mcp-github-app/package.json +0 -18
- package/mcp-github-app/src/auth.js +0 -66
- package/mcp-github-app/src/github.js +0 -371
- package/mcp-github-app/src/index.js +0 -534
- package/skills/devops/webhook-subscriptions/SKILL.md +0 -180
- package/skills/github/DESCRIPTION.md +0 -3
- package/skills/github/codebase-inspection/SKILL.md +0 -115
- package/skills/github/github-auth/SKILL.md +0 -54
- package/skills/github/github-auth/scripts/gh-env.sh +0 -66
- package/skills/github/github-code-review/SKILL.md +0 -480
- package/skills/github/github-code-review/references/review-output-template.md +0 -74
- package/skills/github/github-issues/SKILL.md +0 -369
- package/skills/github/github-issues/templates/bug-report.md +0 -35
- package/skills/github/github-issues/templates/feature-request.md +0 -31
- package/skills/github/github-pr-workflow/SKILL.md +0 -395
- package/skills/github/github-pr-workflow/references/ci-troubleshooting.md +0 -183
- package/skills/github/github-pr-workflow/references/conventional-commits.md +0 -71
- package/skills/github/github-pr-workflow/templates/pr-body-bugfix.md +0 -35
- package/skills/github/github-pr-workflow/templates/pr-body-feature.md +0 -33
- package/skills/github/github-repo-management/SKILL.md +0 -515
- package/skills/github/github-repo-management/references/github-api-cheatsheet.md +0 -161
- package/skills/github-orchestrator/SKILL.md +0 -103
- package/skills/mcp/DESCRIPTION.md +0 -3
- package/skills/mcp/mcporter/SKILL.md +0 -122
- package/skills/mcp/native-mcp/SKILL.md +0 -356
- package/skills/software-development/architect/SKILL.md +0 -154
- package/skills/software-development/assure-guardrails/SKILL.md +0 -239
- package/skills/software-development/plan/SKILL.md +0 -64
- package/skills/software-development/requesting-code-review/SKILL.md +0 -291
- package/skills/software-development/subagent-driven-development/SKILL.md +0 -433
- package/skills/software-development/systematic-debugging/SKILL.md +0 -366
- package/skills/software-development/test-driven-development/SKILL.md +0 -342
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
You are running the **browser-QA pass** of a verify run — driving the claim's
|
|
2
|
+
behaviour in a **real headless browser** and capturing **screenshot evidence**.
|
|
3
|
+
A text-evidence verify already ran and posted its verdict; your job is to add
|
|
4
|
+
visual proof (or to settle a claim that can only be shown in a rendered UI).
|
|
5
|
+
Read the `browser-qa` skill for the driver contract and the `verify` skill for
|
|
6
|
+
the investigator rules, then follow them. The `building` skill installs and runs
|
|
7
|
+
the repo.
|
|
8
|
+
|
|
9
|
+
**Stay in the browser.** Do **not** read, quote, or analyse the repo's source
|
|
10
|
+
code — the text pass already covered the code. Your evidence is strictly what
|
|
11
|
+
the browser shows: the driver's extracted text, assertion results, console
|
|
12
|
+
errors, and the screenshots. No `index.html`/CSS walkthroughs, no "from the
|
|
13
|
+
checked-in code" observations.
|
|
14
|
+
|
|
15
|
+
## The claim to test
|
|
16
|
+
|
|
17
|
+
{{#if commentBody}}
|
|
18
|
+
**Claim / request:**
|
|
19
|
+
{{commentBody}}
|
|
20
|
+
{{/if}}
|
|
21
|
+
{{#if issueTitle}}**Issue/PR title:** {{issueTitle}}{{/if}}
|
|
22
|
+
{{#if issueBody}}
|
|
23
|
+
**Issue/PR body:**
|
|
24
|
+
{{issueBody}}
|
|
25
|
+
{{/if}}
|
|
26
|
+
|
|
27
|
+
Target repo: **{{owner}}/{{repo}}**
|
|
28
|
+
{{#if issueNumber}}Target issue/PR: **#{{issueNumber}}**{{/if}}
|
|
29
|
+
|
|
30
|
+
If the claim is purely about non-UI behaviour (a CLI, an API response, a pure
|
|
31
|
+
function) the text pass already covered it — keep this pass short: note that the
|
|
32
|
+
claim isn't UI-shaped and that no browser evidence was needed. Spend the effort
|
|
33
|
+
where a rendered UI is the only place the claim shows.
|
|
34
|
+
|
|
35
|
+
## First: confirm the browser is available
|
|
36
|
+
|
|
37
|
+
Run the driver's probe before anything else:
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
node <browser-qa skill dir>/scripts/agent-browser.mjs doctor
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
(The `browser-qa` skill is staged into this phase's skill bundle — find its
|
|
44
|
+
absolute path from the available-skills catalogue.) If `doctor` exits non-zero,
|
|
45
|
+
the browser toolchain isn't present: say so plainly and stop — do not fake
|
|
46
|
+
screenshots. This phase only runs on the docker QA image, so `doctor` should
|
|
47
|
+
pass.
|
|
48
|
+
|
|
49
|
+
## Workspace + run the app
|
|
50
|
+
|
|
51
|
+
You are already inside the **{{repo}}** repo at branch {{branch}} — the harness
|
|
52
|
+
pre-cloned it and your cwd is the repo root (no `cd`). For a PR claim, check out
|
|
53
|
+
the PR head. Follow the `building` skill to install and start the app's
|
|
54
|
+
dev-server in the background; wait until it's listening on `localhost`.
|
|
55
|
+
|
|
56
|
+
## Drive the UI and capture evidence
|
|
57
|
+
|
|
58
|
+
Author a `flow.json` (shape documented in the `browser-qa` skill), then run
|
|
59
|
+
`agent-browser.mjs run flow.json --base-url http://localhost:<port>
|
|
60
|
+
--out-dir {{issueDir}}`. Save every screenshot under **`{{issueDir}}/`** — the
|
|
61
|
+
harness harvests that directory. Parse the JSON report (extracted text,
|
|
62
|
+
assertion results, console errors) — that, not the images, is what you reason
|
|
63
|
+
over. For a before/after regression claim, capture both states.
|
|
64
|
+
|
|
65
|
+
## How your report is delivered — read carefully
|
|
66
|
+
|
|
67
|
+
Your **final message is the report**, and the harness posts it for you{{#if issueNumber}} as
|
|
68
|
+
a comment on **#{{issueNumber}}**{{/if}}{{#if !issueNumber}} back into the thread this request came from{{/if}}.
|
|
69
|
+
Title it clearly as the **browser-QA evidence** so it reads as a supplement to
|
|
70
|
+
the text verdict, not a competing one. Use the `verify` report shape
|
|
71
|
+
(Environment / Evidence / **Conclusion: CONFIRMED | REFUTED | INCONCLUSIVE**).
|
|
72
|
+
|
|
73
|
+
**Keep it tight** — a one-line environment summary, the evidence (screenshots +
|
|
74
|
+
the key assertion/text/console results), and a one-sentence conclusion. No
|
|
75
|
+
per-step narration, no code analysis, no long Coverage prose; a short
|
|
76
|
+
"what was / wasn't exercised" is enough.
|
|
77
|
+
|
|
78
|
+
**Embed each screenshot inline** so it renders in the comment.
|
|
79
|
+
{{#if artifactBaseUrl}}Every PNG you saved to `<name>.png` is served publicly at
|
|
80
|
+
`{{artifactBaseUrl}}/<name>.png`. Write a **raw Markdown image** for each one
|
|
81
|
+
under Evidence — `!` then `[caption]` then the URL in parentheses — on its own
|
|
82
|
+
line. Do **NOT** wrap it in backticks or a code fence; inside a code span it
|
|
83
|
+
shows as literal text instead of rendering. For example, a screenshot saved as
|
|
84
|
+
`home.png` becomes a line reading: an exclamation mark, `[Home]`, then
|
|
85
|
+
`({{artifactBaseUrl}}/home.png)` with no spaces and no backticks.{{/if}}{{#if !artifactBaseUrl}}No
|
|
86
|
+
public URL is configured, so reference each screenshot by filename (e.g.
|
|
87
|
+
`after-login.png`) and note it's in the run's Artifacts view.{{/if}}
|
|
88
|
+
|
|
89
|
+
**Do NOT post it yourself** with `github_add_issue_comment` — that would
|
|
90
|
+
double-post. Never fabricate a screenshot or a pass; a clearly-evidenced
|
|
91
|
+
**REFUTED** is a real finding. If screenshots couldn't be persisted (no
|
|
92
|
+
server-mode build assets), still report what the DOM/text evidence showed and
|
|
93
|
+
say the images weren't retained.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
You are writing the **single final verdict** for a verify run. Two passes have
|
|
2
|
+
already run: a text-evidence verification and (sometimes) a browser-QA pass.
|
|
3
|
+
Your job is to **synthesize them into one concise comment** — the reader sees
|
|
4
|
+
only your output, not the individual passes.
|
|
5
|
+
|
|
6
|
+
This is a **pure writing task**. Do **not** run commands, install anything, read
|
|
7
|
+
repo files, or start a server — everything you need is below. Do **not** post a
|
|
8
|
+
comment yourself (`github_add_issue_comment`); your final message *is* the
|
|
9
|
+
comment, delivered by the harness.
|
|
10
|
+
|
|
11
|
+
## The claim
|
|
12
|
+
|
|
13
|
+
{{#if commentBody}}{{commentBody}}{{/if}}{{#if issueTitle}} (issue/PR: {{issueTitle}}){{/if}}
|
|
14
|
+
|
|
15
|
+
## Text-verification report
|
|
16
|
+
|
|
17
|
+
{{verifyResult}}
|
|
18
|
+
|
|
19
|
+
{{#if verifyBrowserResult}}
|
|
20
|
+
## Browser-QA report (real headless browser + screenshots)
|
|
21
|
+
|
|
22
|
+
{{verifyBrowserResult}}
|
|
23
|
+
{{/if}}
|
|
24
|
+
|
|
25
|
+
## Write the verdict
|
|
26
|
+
|
|
27
|
+
Produce a tight Markdown comment:
|
|
28
|
+
|
|
29
|
+
- **Lead with the conclusion** on its own line: **CONFIRMED**, **REFUTED**, or
|
|
30
|
+
**INCONCLUSIVE**. If the two passes disagree, reconcile them and say why the
|
|
31
|
+
combined evidence lands where it does (browser evidence is decisive for
|
|
32
|
+
rendered-UI behaviour; text evidence for everything else).
|
|
33
|
+
- One short paragraph of the **key evidence** that settles it — the decisive
|
|
34
|
+
commands/output and assertion results, not a replay of both reports.
|
|
35
|
+
{{#if verifyBrowserResult}}- **Embed the browser screenshots inline** exactly as they appear in the
|
|
36
|
+
browser-QA report above (the `` image
|
|
37
|
+
Markdown) so they render in this comment. Keep them; don't turn them into
|
|
38
|
+
plain links or drop them.{{/if}}
|
|
39
|
+
- A one-line **coverage** note: what was exercised, and anything notable that
|
|
40
|
+
wasn't.
|
|
41
|
+
|
|
42
|
+
Keep it short and decisive — no per-step narration, no restating both reports in
|
|
43
|
+
full. If a pass reported a failure or a REFUTED, surface it plainly; don't bury
|
|
44
|
+
it under the other pass.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
You are **verifying a claim** — testing whether a stated behaviour is actually
|
|
2
|
+
true and reporting the evidence. Read the `verify` skill for the full procedure
|
|
3
|
+
and investigator rules, then follow it. It uses the `building` skill for
|
|
4
|
+
installing and running the repo. This prompt gives you the claim and how your
|
|
5
|
+
report is delivered.
|
|
6
|
+
|
|
7
|
+
## The claim to test
|
|
8
|
+
|
|
9
|
+
{{#if commentBody}}
|
|
10
|
+
**Claim / request:**
|
|
11
|
+
{{commentBody}}
|
|
12
|
+
{{/if}}
|
|
13
|
+
{{#if issueTitle}}**Issue/PR title:** {{issueTitle}}{{/if}}
|
|
14
|
+
{{#if issueBody}}
|
|
15
|
+
**Issue/PR body:**
|
|
16
|
+
{{issueBody}}
|
|
17
|
+
{{/if}}
|
|
18
|
+
|
|
19
|
+
Target repo: **{{owner}}/{{repo}}**
|
|
20
|
+
{{#if issueNumber}}Target issue/PR: **#{{issueNumber}}**{{/if}}
|
|
21
|
+
|
|
22
|
+
If no explicit claim is given and this is a PR, read the PR description + diff
|
|
23
|
+
and pick the single most important, most testable claim it makes — and say which
|
|
24
|
+
claim you chose.
|
|
25
|
+
|
|
26
|
+
## Workspace
|
|
27
|
+
|
|
28
|
+
You are already inside the **{{repo}}** repo at branch {{branch}} — the harness
|
|
29
|
+
pre-cloned it and your cwd is the repo root. Git is configured; no clone, no
|
|
30
|
+
`cd`. For a PR claim, check out the PR head (see the `pr-review`/`building`
|
|
31
|
+
workspace notes); for a before/after claim, `git fetch` the base ref too.
|
|
32
|
+
|
|
33
|
+
## First — is this even a text-checkable claim?
|
|
34
|
+
|
|
35
|
+
You have **bash, file read, and the github tools** — no browser, no
|
|
36
|
+
screenshots, no video. Before doing any setup, judge whether the claim is
|
|
37
|
+
**purely about a rendered UI** (visual layout, mobile rendering, a click/render
|
|
38
|
+
flow that only shows in a browser). If it is, **do not install/build/guess** —
|
|
39
|
+
a dedicated browser-QA pass runs after you and owns it. Say in one line that the
|
|
40
|
+
claim is UI-shaped and defer it to the browser pass, conclude **INCONCLUSIVE
|
|
41
|
+
(UI-only — deferred to browser QA)**, and stop. Spend your effort only on claims
|
|
42
|
+
bash can actually settle.
|
|
43
|
+
|
|
44
|
+
## Evidence — what you can and can't capture
|
|
45
|
+
|
|
46
|
+
For a text-checkable claim, prove it with test output, command stdout/stderr,
|
|
47
|
+
exit codes, `curl` against a dev-server you start, and log/file excerpts.
|
|
48
|
+
|
|
49
|
+
## How your report is delivered — read carefully
|
|
50
|
+
|
|
51
|
+
Your **final message is the report**, and the harness posts it for you:
|
|
52
|
+
{{#if issueNumber}}
|
|
53
|
+
- as a comment on **#{{issueNumber}}**.
|
|
54
|
+
{{/if}}
|
|
55
|
+
{{#if !issueNumber}}
|
|
56
|
+
- back into the thread this request came from.
|
|
57
|
+
{{/if}}
|
|
58
|
+
|
|
59
|
+
Make your final message the complete report in the shape the `verify` skill
|
|
60
|
+
defines (Environment / Evidence / **Conclusion: CONFIRMED | REFUTED |
|
|
61
|
+
INCONCLUSIVE**). **Do NOT post it yourself** with `github_add_issue_comment` —
|
|
62
|
+
that would double-post. The only acceptable result that contradicts the claim is
|
|
63
|
+
a clearly-evidenced **REFUTED**; surface it, don't bury it.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
kind: qa-test
|
|
2
|
+
name: qa-test
|
|
3
|
+
description: |
|
|
4
|
+
Run an automated QA flow against a repo's CLI or locally-served app and report
|
|
5
|
+
step-level pass/fail with evidence. It installs and runs the code in the
|
|
6
|
+
sandbox, exercises a flow (CLI invocations or curl against a dev-server),
|
|
7
|
+
optionally drives the UI in a real browser, then posts a single per-step QA
|
|
8
|
+
report. Does not modify code.
|
|
9
|
+
|
|
10
|
+
Delivery is a single in-place status comment (`status_checklist`): the run
|
|
11
|
+
shows its phases ticking off, then a final `synthesize` phase folds the text
|
|
12
|
+
report and (when it ran) the browser evidence into ONE combined report,
|
|
13
|
+
delivered as the comment's footer via `final_message`. No comment-per-phase.
|
|
14
|
+
Posted on the originating issue/PR for GitHub runs, or into the Slack thread
|
|
15
|
+
for Slack runs. The agents therefore do NOT post anything themselves.
|
|
16
|
+
|
|
17
|
+
When the host runs the docker backend with the browser-QA image built, the
|
|
18
|
+
gated `qa_browser` phase drives a real headless Chromium against the
|
|
19
|
+
locally-served app and captures step-level screenshot evidence; everywhere
|
|
20
|
+
else it is silently skipped (graceful degradation) and the text report stands
|
|
21
|
+
alone. The synthesis runs either way.
|
|
22
|
+
|
|
23
|
+
Triggered by:
|
|
24
|
+
- a `@last-light qa-test <target> [-- steps]` comment on an issue/PR
|
|
25
|
+
- manual CLI: tsx src/cli.ts qa-test owner/repo#N -- "<steps>"
|
|
26
|
+
|
|
27
|
+
status_checklist: true
|
|
28
|
+
final_message: "{{synthesisResult}}"
|
|
29
|
+
|
|
30
|
+
phases:
|
|
31
|
+
- name: phase_0
|
|
32
|
+
label: Context
|
|
33
|
+
type: context
|
|
34
|
+
depends_on: []
|
|
35
|
+
|
|
36
|
+
- name: qa_test
|
|
37
|
+
label: QA Test
|
|
38
|
+
depends_on: [phase_0]
|
|
39
|
+
prompt: prompts/qa-test.md
|
|
40
|
+
# qa-test: the flow procedure + report shape (primary).
|
|
41
|
+
# building: install + run the repo to exercise the flow.
|
|
42
|
+
skills: [qa-test, building]
|
|
43
|
+
model: "{{models.qa-test}}"
|
|
44
|
+
variant: "{{variants.qa-test}}"
|
|
45
|
+
output_var: qaResult
|
|
46
|
+
messages:
|
|
47
|
+
on_start: "Running the QA flow — installing, running, and exercising each step..."
|
|
48
|
+
on_success: "Text QA flow complete."
|
|
49
|
+
on_failure: "I couldn't complete the QA run — see the logs for details."
|
|
50
|
+
|
|
51
|
+
# Browser-QA pass (Tier B). Gated to the docker backend AND the enriched
|
|
52
|
+
# `lastlight-sandbox-qa:latest` image (Playwright + Chromium). On gondolin, or
|
|
53
|
+
# a docker host without that image, the scheduler silently skips this phase.
|
|
54
|
+
# It is terminal (nothing depends on it) — `synthesize` depends only on
|
|
55
|
+
# `qa_test`, so it still runs (after this phase, by declaration order) and
|
|
56
|
+
# folds in `qaBrowserResult` only when this phase actually produced it.
|
|
57
|
+
- name: qa_browser
|
|
58
|
+
label: QA Test (browser)
|
|
59
|
+
depends_on: [qa_test]
|
|
60
|
+
prompt: prompts/qa-browser.md
|
|
61
|
+
skills: [qa-test, building, browser-qa]
|
|
62
|
+
model: "{{models.qa-test}}"
|
|
63
|
+
variant: "{{variants.qa-test}}"
|
|
64
|
+
requires_sandbox: docker
|
|
65
|
+
sandbox_image: qa
|
|
66
|
+
output_var: qaBrowserResult
|
|
67
|
+
messages:
|
|
68
|
+
on_start: "Browser QA available — driving the UI and capturing screenshots..."
|
|
69
|
+
on_success: "Browser QA complete — screenshots captured."
|
|
70
|
+
on_skipped_done: "Browser QA unavailable on this host — text report stands."
|
|
71
|
+
|
|
72
|
+
# Synthesis. Depends only on `qa_test` (always runs after the gated browser
|
|
73
|
+
# phase by declaration order, and never skips when that phase is gated out).
|
|
74
|
+
# Reads the prior reports from phaseOutputs and writes ONE combined report;
|
|
75
|
+
# its output (`synthesisResult`) becomes the comment footer via the
|
|
76
|
+
# workflow-level `final_message`. Pure composition — no skills, no repo work.
|
|
77
|
+
- name: synthesize
|
|
78
|
+
label: Summary
|
|
79
|
+
depends_on: [qa_test]
|
|
80
|
+
prompt: prompts/qa-synth.md
|
|
81
|
+
model: "{{models.qa-test}}"
|
|
82
|
+
variant: "{{variants.qa-test}}"
|
|
83
|
+
output_var: synthesisResult
|
|
84
|
+
messages:
|
|
85
|
+
on_start: "Synthesizing the final report..."
|
|
86
|
+
on_success: "Report posted below."
|
|
87
|
+
on_failure: "I couldn't synthesize the final report — see the logs."
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
kind: health
|
|
2
|
+
name: security-feedback
|
|
3
|
+
description: |
|
|
4
|
+
Process maintainer feedback on a security-labelled issue (usually a
|
|
5
|
+
per-run scan summary). Classifies the comment and acts:
|
|
6
|
+
|
|
7
|
+
- create-issues — break selected findings out into individual issues
|
|
8
|
+
that can later be fed to the `build` skill (the primary flow)
|
|
9
|
+
- accept-risk / false-positive — update SECURITY.md via PR to
|
|
10
|
+
suppress the finding in future scans
|
|
11
|
+
- reopen — ask the maintainer to re-run `@last-light security-review`
|
|
12
|
+
- discuss / ignore — reply conversationally or do nothing
|
|
13
|
+
|
|
14
|
+
The scan-summary issue grammar is defined in
|
|
15
|
+
`skills/security-review/SKILL.md § Issue format`; this skill's parser
|
|
16
|
+
mirrors it (version-checked on entry).
|
|
17
|
+
|
|
18
|
+
Triggered by:
|
|
19
|
+
- @last-light mention on issues labelled "security"
|
|
20
|
+
|
|
21
|
+
phases:
|
|
22
|
+
- name: feedback
|
|
23
|
+
label: Security feedback
|
|
24
|
+
skill: security-feedback
|
|
25
|
+
model: "{{models.security}}"
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
kind: health
|
|
2
|
+
name: security-review
|
|
3
|
+
description: |
|
|
4
|
+
Scan the target repository for security issues using open-source tools
|
|
5
|
+
(npm audit, semgrep, gitleaks) plus AI code review. Files ONE summary
|
|
6
|
+
issue per run (Renovate-style) containing a GitHub task list of every
|
|
7
|
+
finding grouped by Critical / High / Medium / Low. Honours SECURITY.md
|
|
8
|
+
for known false positives and accepted risks.
|
|
9
|
+
|
|
10
|
+
Maintainers break findings out into individual issues by commenting on
|
|
11
|
+
the summary issue (see the `security-feedback` skill — which handles
|
|
12
|
+
`@last-light create issues for the criticals`, per-item accept-risk /
|
|
13
|
+
false-positive commands, and conversational follow-ups).
|
|
14
|
+
|
|
15
|
+
Each invocation scans exactly ONE repo. The weekly cron fans out into
|
|
16
|
+
one independent run per managed repo.
|
|
17
|
+
|
|
18
|
+
Triggered by:
|
|
19
|
+
- weekly cron (Monday 10:00, fans out over every managed repo)
|
|
20
|
+
- manual CLI: tsx src/cli.ts security owner/repo
|
|
21
|
+
- @last-light security-review in a GitHub comment
|
|
22
|
+
- Slack: "security review cliftonc/repo"
|
|
23
|
+
|
|
24
|
+
phases:
|
|
25
|
+
- name: scan
|
|
26
|
+
label: Security scan
|
|
27
|
+
skill: security-review
|
|
28
|
+
model: "{{models.security}}"
|
|
29
|
+
variant: "{{variants.security}}"
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
kind: verify
|
|
2
|
+
name: verify
|
|
3
|
+
description: |
|
|
4
|
+
Verify a behaviour claim against a repo or PR and report whether the evidence
|
|
5
|
+
confirms or refutes it. It installs and runs the code in the sandbox, captures
|
|
6
|
+
bash/text evidence, optionally drives the UI in a real browser, then posts a
|
|
7
|
+
single CONFIRMED / REFUTED / INCONCLUSIVE verdict. Does not modify code.
|
|
8
|
+
|
|
9
|
+
Delivery is a single in-place status comment (`status_checklist`): the run
|
|
10
|
+
shows its phases ticking off, then a final `synthesize` phase folds the text
|
|
11
|
+
verdict and (when it ran) the browser evidence into ONE combined verdict,
|
|
12
|
+
delivered as the comment's footer via `final_message`. No comment-per-phase.
|
|
13
|
+
Posted on the originating issue/PR for GitHub runs, or into the Slack thread
|
|
14
|
+
for Slack runs. The agents therefore do NOT post anything themselves.
|
|
15
|
+
|
|
16
|
+
When the host runs the docker backend with the browser-QA image built, the
|
|
17
|
+
gated `verify_browser` phase drives the UI in a real headless Chromium and
|
|
18
|
+
captures screenshot evidence; everywhere else it is silently skipped (graceful
|
|
19
|
+
degradation) and the text verdict stands alone. The synthesis runs either way.
|
|
20
|
+
|
|
21
|
+
Triggered by:
|
|
22
|
+
- a `@last-light verify <claim>` comment on an issue/PR
|
|
23
|
+
- manual CLI: tsx src/cli.ts verify owner/repo#N -- "<claim>"
|
|
24
|
+
|
|
25
|
+
status_checklist: true
|
|
26
|
+
final_message: "{{synthesisResult}}"
|
|
27
|
+
|
|
28
|
+
phases:
|
|
29
|
+
- name: phase_0
|
|
30
|
+
label: Context
|
|
31
|
+
type: context
|
|
32
|
+
depends_on: []
|
|
33
|
+
|
|
34
|
+
- name: verify
|
|
35
|
+
label: Verify
|
|
36
|
+
depends_on: [phase_0]
|
|
37
|
+
prompt: prompts/verify.md
|
|
38
|
+
# verify: the investigator procedure + report shape (primary).
|
|
39
|
+
# building: install + run the repo to capture evidence.
|
|
40
|
+
skills: [verify, building]
|
|
41
|
+
model: "{{models.verify}}"
|
|
42
|
+
variant: "{{variants.verify}}"
|
|
43
|
+
output_var: verifyResult
|
|
44
|
+
messages:
|
|
45
|
+
on_start: "Verifying the claim — installing, running, and capturing evidence..."
|
|
46
|
+
on_success: "Text verification complete."
|
|
47
|
+
on_failure: "I couldn't complete the verification — see the logs for details."
|
|
48
|
+
|
|
49
|
+
# Browser-QA pass (Tier B). Gated to the docker backend AND the enriched
|
|
50
|
+
# `lastlight-sandbox-qa:latest` image (Playwright + Chromium). On gondolin, or
|
|
51
|
+
# a docker host without that image, the scheduler silently skips this phase.
|
|
52
|
+
# It is terminal (nothing depends on it) — `synthesize` depends only on
|
|
53
|
+
# `verify`, so it still runs (after this phase, by declaration order) and
|
|
54
|
+
# folds in `verifyBrowserResult` only when this phase actually produced it.
|
|
55
|
+
- name: verify_browser
|
|
56
|
+
label: Verify (browser)
|
|
57
|
+
depends_on: [verify]
|
|
58
|
+
prompt: prompts/verify-browser.md
|
|
59
|
+
skills: [verify, building, browser-qa]
|
|
60
|
+
model: "{{models.verify}}"
|
|
61
|
+
variant: "{{variants.verify}}"
|
|
62
|
+
requires_sandbox: docker
|
|
63
|
+
sandbox_image: qa
|
|
64
|
+
output_var: verifyBrowserResult
|
|
65
|
+
messages:
|
|
66
|
+
on_start: "Browser QA available — driving the UI and capturing screenshots..."
|
|
67
|
+
on_success: "Browser QA complete — screenshots captured."
|
|
68
|
+
on_skipped_done: "Browser QA unavailable on this host — text verdict stands."
|
|
69
|
+
|
|
70
|
+
# Synthesis. Depends only on `verify` (always runs after the gated browser
|
|
71
|
+
# phase by declaration order, and never skips when that phase is gated out).
|
|
72
|
+
# Reads the prior reports from phaseOutputs and writes ONE concise combined
|
|
73
|
+
# verdict; its output (`synthesisResult`) becomes the comment footer via the
|
|
74
|
+
# workflow-level `final_message`. Pure composition — no skills, no repo work.
|
|
75
|
+
- name: synthesize
|
|
76
|
+
label: Summary
|
|
77
|
+
depends_on: [verify]
|
|
78
|
+
prompt: prompts/verify-synth.md
|
|
79
|
+
model: "{{models.verify}}"
|
|
80
|
+
variant: "{{variants.verify}}"
|
|
81
|
+
output_var: synthesisResult
|
|
82
|
+
messages:
|
|
83
|
+
on_start: "Synthesizing the final verdict..."
|
|
84
|
+
on_success: "Verdict posted below."
|
|
85
|
+
on_failure: "I couldn't synthesize the final verdict — see the logs."
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"mcpServers": {
|
|
3
|
-
"github": {
|
|
4
|
-
"command": "node",
|
|
5
|
-
"args": ["/app/mcp-github-app/src/index.js"],
|
|
6
|
-
"env": {
|
|
7
|
-
"GITHUB_APP_ID": "${GITHUB_APP_ID}",
|
|
8
|
-
"GITHUB_APP_PRIVATE_KEY_PATH": "${GITHUB_APP_PRIVATE_KEY_PATH}",
|
|
9
|
-
"GITHUB_APP_INSTALLATION_ID": "${GITHUB_APP_INSTALLATION_ID}",
|
|
10
|
-
"GITHUB_TOKEN": "${GITHUB_TOKEN}"
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { StateDb } from "../state/db.js";
|
|
2
|
-
/** Component name used for the host claude CLI auth state in system_status. */
|
|
3
|
-
export declare const HOST_CLAUDE_AUTH_COMPONENT = "host-claude-auth";
|
|
4
|
-
/**
|
|
5
|
-
* Optional notifier — called once when the auth state transitions to degraded.
|
|
6
|
-
* Pass a SlackConnector's `sendToDeliveryChannel` (or any other channel).
|
|
7
|
-
*/
|
|
8
|
-
export type AdminNotifier = (text: string) => Promise<void>;
|
|
9
|
-
/**
|
|
10
|
-
* Check Claude usage limits by making a minimal Agent SDK call
|
|
11
|
-
* and parsing the stream-json output for rate_limit_event and usage data.
|
|
12
|
-
*
|
|
13
|
-
* Works with Claude subscriptions (no API key needed).
|
|
14
|
-
*
|
|
15
|
-
* Behavior:
|
|
16
|
-
* - If the host claude CLI returns "Not logged in" / authentication_failed,
|
|
17
|
-
* marks `system_status.host-claude-auth` as `degraded`, notifies the admin
|
|
18
|
-
* on the first transition, and halts subsequent runs until cleared.
|
|
19
|
-
* - The capacity check creates a JSONL session file as a side effect — we
|
|
20
|
-
* delete it after parsing so it doesn't pollute the dashboard Sessions list.
|
|
21
|
-
*/
|
|
22
|
-
export interface CheckApiUsageOptions {
|
|
23
|
-
/** Bypass the auth-degraded early return — used by manual rechecks. */
|
|
24
|
-
force?: boolean;
|
|
25
|
-
}
|
|
26
|
-
export declare function checkApiUsage(db: StateDb, notifyAdmin?: AdminNotifier, opts?: CheckApiUsageOptions): Promise<void>;
|
package/dist/cron/rate-limits.js
DELETED
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
/** Component name used for the host claude CLI auth state in system_status. */
|
|
2
|
-
export const HOST_CLAUDE_AUTH_COMPONENT = "host-claude-auth";
|
|
3
|
-
export async function checkApiUsage(db, notifyAdmin, opts = {}) {
|
|
4
|
-
// Halt early if we're already in a degraded state — operator must clear it
|
|
5
|
-
// (e.g. after `claude /login` + recheck) before this cron resumes.
|
|
6
|
-
// The recheck endpoint passes force:true to bypass this.
|
|
7
|
-
const existing = db.getSystemStatus(HOST_CLAUDE_AUTH_COMPONENT);
|
|
8
|
-
if (!opts.force && existing?.state === "degraded") {
|
|
9
|
-
console.log(`[usage] Skipping capacity check — host claude auth is degraded since ${existing.since}. Run claude /login on the host and trigger a recheck to resume.`);
|
|
10
|
-
return;
|
|
11
|
-
}
|
|
12
|
-
const now = new Date().toISOString();
|
|
13
|
-
let capacityCheckSessionId = "";
|
|
14
|
-
let authFailed = false;
|
|
15
|
-
let authFailureReason = "";
|
|
16
|
-
// ── Capacity & rate limit check via claude CLI ──
|
|
17
|
-
try {
|
|
18
|
-
const { execFile } = await import("child_process");
|
|
19
|
-
const { promisify } = await import("util");
|
|
20
|
-
const exec = promisify(execFile);
|
|
21
|
-
let stdout = "";
|
|
22
|
-
try {
|
|
23
|
-
// NOTE: do NOT pass --bare here. --bare disables OAuth credential
|
|
24
|
-
// reading and requires ANTHROPIC_API_KEY, which we don't have on this
|
|
25
|
-
// host (we authenticate via `claude /login` to a Claude subscription).
|
|
26
|
-
const result = await exec("claude", [
|
|
27
|
-
"--print", "reply with just: ok",
|
|
28
|
-
"--output-format", "stream-json",
|
|
29
|
-
"--verbose",
|
|
30
|
-
"--max-turns", "1",
|
|
31
|
-
"--model", process.env.CLAUDE_MODEL || "claude-sonnet-4-6",
|
|
32
|
-
], {
|
|
33
|
-
timeout: 30_000,
|
|
34
|
-
env: { ...process.env, HOME: process.env.HOME || "/home/lastlight" },
|
|
35
|
-
});
|
|
36
|
-
stdout = result.stdout;
|
|
37
|
-
}
|
|
38
|
-
catch (execErr) {
|
|
39
|
-
// Non-zero exit (e.g. auth_failed) — claude still emits stream-json on stdout
|
|
40
|
-
stdout = execErr.stdout?.toString() || "";
|
|
41
|
-
if (!stdout) {
|
|
42
|
-
// No output at all — propagate the underlying failure
|
|
43
|
-
throw execErr;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
// Parse each JSON line from the stream output
|
|
47
|
-
for (const line of stdout.split("\n")) {
|
|
48
|
-
if (!line.startsWith("{"))
|
|
49
|
-
continue;
|
|
50
|
-
try {
|
|
51
|
-
const msg = JSON.parse(line);
|
|
52
|
-
// Capture session id so we can delete the JSONL file afterwards
|
|
53
|
-
if (msg.type === "system" && msg.subtype === "init" && msg.session_id) {
|
|
54
|
-
capacityCheckSessionId = msg.session_id;
|
|
55
|
-
}
|
|
56
|
-
// Detect "Not logged in" — claude emits a synthetic assistant message
|
|
57
|
-
// with error: "authentication_failed" when the host CLI has no creds.
|
|
58
|
-
if (msg.type === "assistant" && msg.error === "authentication_failed") {
|
|
59
|
-
authFailed = true;
|
|
60
|
-
const text = msg.message?.content?.[0]?.text || "Not logged in";
|
|
61
|
-
authFailureReason = text;
|
|
62
|
-
}
|
|
63
|
-
// Rate limit info from subscription
|
|
64
|
-
if (msg.type === "rate_limit_event" && msg.rate_limit_info) {
|
|
65
|
-
const info = msg.rate_limit_info;
|
|
66
|
-
db.updateRateLimit("subscription:status", info.status === "allowed" ? 1 : 0, now);
|
|
67
|
-
db.updateRateLimit("subscription:type", 0, info.rateLimitType || "unknown");
|
|
68
|
-
if (info.resetsAt) {
|
|
69
|
-
db.updateRateLimit("subscription:resets_at", info.resetsAt, new Date(info.resetsAt * 1000).toISOString());
|
|
70
|
-
}
|
|
71
|
-
if (info.overageStatus) {
|
|
72
|
-
db.updateRateLimit("subscription:overage_status", info.overageStatus === "allowed" ? 1 : 0, now);
|
|
73
|
-
}
|
|
74
|
-
if (info.overageResetsAt) {
|
|
75
|
-
db.updateRateLimit("subscription:overage_resets_at", info.overageResetsAt, new Date(info.overageResetsAt * 1000).toISOString());
|
|
76
|
-
}
|
|
77
|
-
db.updateRateLimit("subscription:using_overage", info.isUsingOverage ? 1 : 0, now);
|
|
78
|
-
console.log(`[usage] Subscription: ${info.status}, type=${info.rateLimitType}, overage=${info.isUsingOverage ? "yes" : "no"} (${info.overageStatus})`);
|
|
79
|
-
}
|
|
80
|
-
// Result with cost and usage breakdown
|
|
81
|
-
if (msg.type === "result") {
|
|
82
|
-
if (msg.total_cost_usd !== undefined) {
|
|
83
|
-
// Store as cents to keep as integer
|
|
84
|
-
db.updateRateLimit("usage:last_check_cost_cents", Math.round(msg.total_cost_usd * 100), now);
|
|
85
|
-
}
|
|
86
|
-
if (msg.usage) {
|
|
87
|
-
db.updateRateLimit("usage:last_check_input_tokens", msg.usage.input_tokens || 0, now);
|
|
88
|
-
db.updateRateLimit("usage:last_check_output_tokens", msg.usage.output_tokens || 0, now);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
catch { /* skip unparseable lines */ }
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
catch (err) {
|
|
96
|
-
// The capacity check is best-effort — log and continue. Cleanup + status
|
|
97
|
-
// handling below should still run regardless of the failure mode.
|
|
98
|
-
db.updateRateLimit("subscription:status", 0, now);
|
|
99
|
-
console.warn(`[usage] Capacity check failed: ${err.message}`);
|
|
100
|
-
}
|
|
101
|
-
// If the call surfaced an auth failure, mark the component degraded and
|
|
102
|
-
// notify the admin once on transition. Subsequent runs early-return above.
|
|
103
|
-
if (authFailed) {
|
|
104
|
-
const transitioned = db.setSystemStatus(HOST_CLAUDE_AUTH_COMPONENT, "degraded", authFailureReason || "Host claude CLI is not logged in");
|
|
105
|
-
if (transitioned) {
|
|
106
|
-
console.error(`[usage] Host claude auth is now DEGRADED: ${authFailureReason}`);
|
|
107
|
-
if (notifyAdmin) {
|
|
108
|
-
const msg = `:rotating_light: *Last Light: host claude CLI auth degraded*\n` +
|
|
109
|
-
`Reason: ${authFailureReason}\n` +
|
|
110
|
-
`Action: run \`docker exec -it --user lastlight lastlight-agent-1 claude /login\` and then trigger a recheck.\n` +
|
|
111
|
-
`The capacity-check cron is now halted to prevent log spam.`;
|
|
112
|
-
try {
|
|
113
|
-
await notifyAdmin(msg);
|
|
114
|
-
}
|
|
115
|
-
catch (notifyErr) {
|
|
116
|
-
console.error(`[usage] Failed to notify admin: ${notifyErr.message}`);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
else {
|
|
122
|
-
// Successful run — clear any prior degraded state
|
|
123
|
-
const existing = db.getSystemStatus(HOST_CLAUDE_AUTH_COMPONENT);
|
|
124
|
-
if (existing && existing.state !== "ok") {
|
|
125
|
-
db.setSystemStatus(HOST_CLAUDE_AUTH_COMPONENT, "ok");
|
|
126
|
-
console.log(`[usage] Host claude auth recovered — state cleared`);
|
|
127
|
-
if (notifyAdmin) {
|
|
128
|
-
try {
|
|
129
|
-
await notifyAdmin(`:white_check_mark: Last Light: host claude CLI auth recovered. Capacity-check cron resuming normal operation.`);
|
|
130
|
-
}
|
|
131
|
-
catch { /* non-fatal */ }
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
else if (!existing) {
|
|
135
|
-
// First-ever successful run — initialize the state
|
|
136
|
-
db.setSystemStatus(HOST_CLAUDE_AUTH_COMPONENT, "ok");
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
// Run JSONL cleanup regardless of outcome (try/finally semantics).
|
|
140
|
-
{
|
|
141
|
-
// Delete the session JSONL file the capacity check created so it doesn't
|
|
142
|
-
// pollute the dashboard Sessions list. Best-effort — ignore failures.
|
|
143
|
-
if (capacityCheckSessionId) {
|
|
144
|
-
try {
|
|
145
|
-
const { unlink } = await import("fs/promises");
|
|
146
|
-
const { join } = await import("path");
|
|
147
|
-
const home = process.env.HOME || "/home/lastlight";
|
|
148
|
-
// claude encodes the project's cwd as the directory name, replacing
|
|
149
|
-
// path separators with dashes. e.g. /app -> -app
|
|
150
|
-
const projectDir = process.cwd().replace(/\//g, "-");
|
|
151
|
-
const sessionFile = join(home, ".claude", "projects", projectDir, `${capacityCheckSessionId}.jsonl`);
|
|
152
|
-
await unlink(sessionFile);
|
|
153
|
-
}
|
|
154
|
-
catch {
|
|
155
|
-
/* file may not exist or claude may not have written it — ignore */
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
// ── Usage stats from our own execution records ──
|
|
160
|
-
try {
|
|
161
|
-
const stats = computeUsageStats(db);
|
|
162
|
-
db.updateRateLimit("usage:executions_1h", stats.lastHour, now);
|
|
163
|
-
db.updateRateLimit("usage:executions_24h", stats.last24h, now);
|
|
164
|
-
db.updateRateLimit("usage:turns_1h", stats.turnsLastHour, now);
|
|
165
|
-
db.updateRateLimit("usage:turns_24h", stats.turnsLast24h, now);
|
|
166
|
-
console.log(`[usage] Last 1h: ${stats.lastHour} executions, ${stats.turnsLastHour} turns | ` +
|
|
167
|
-
`24h: ${stats.last24h} executions, ${stats.turnsLast24h} turns`);
|
|
168
|
-
}
|
|
169
|
-
catch (err) {
|
|
170
|
-
console.error(`[usage] Stats computation failed: ${err.message}`);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
function computeUsageStats(db) {
|
|
174
|
-
const now = Date.now();
|
|
175
|
-
const oneHourAgo = new Date(now - 60 * 60 * 1000).toISOString();
|
|
176
|
-
const oneDayAgo = new Date(now - 24 * 60 * 60 * 1000).toISOString();
|
|
177
|
-
const raw = db.database;
|
|
178
|
-
const h1 = raw.prepare(`
|
|
179
|
-
SELECT COUNT(*) as count, COALESCE(SUM(turns), 0) as turns
|
|
180
|
-
FROM executions WHERE started_at >= ?
|
|
181
|
-
`).get(oneHourAgo);
|
|
182
|
-
const h24 = raw.prepare(`
|
|
183
|
-
SELECT COUNT(*) as count, COALESCE(SUM(turns), 0) as turns
|
|
184
|
-
FROM executions WHERE started_at >= ?
|
|
185
|
-
`).get(oneDayAgo);
|
|
186
|
-
return {
|
|
187
|
-
lastHour: h1.count,
|
|
188
|
-
turnsLastHour: h1.turns,
|
|
189
|
-
last24h: h24.count,
|
|
190
|
-
turnsLast24h: h24.turns,
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
//# sourceMappingURL=rate-limits.js.map
|