lastlight 0.1.15 → 0.2.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/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 +377 -432
- 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 +30 -1
- package/dist/setup.js +241 -25
- 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 -9
- 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,380 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// agent-browser.mjs — bundled headless-browser driver for Tier B browser QA.
|
|
3
|
+
//
|
|
4
|
+
// CONTRACT
|
|
5
|
+
// --------
|
|
6
|
+
// Runs inside the `lastlight-sandbox-qa:latest` docker image, which bakes in
|
|
7
|
+
// Playwright + Chromium at PLAYWRIGHT_BROWSERS_PATH=/opt/playwright-browsers and
|
|
8
|
+
// makes the global `playwright` package resolvable via NODE_PATH. The calling
|
|
9
|
+
// agent has bash + file tools but NO vision: it reasons over this CLI's JSON
|
|
10
|
+
// stdout (extracted text, assertion results, console errors). The PNG
|
|
11
|
+
// screenshots are human evidence only — the agent never "sees" them.
|
|
12
|
+
//
|
|
13
|
+
// Subcommands:
|
|
14
|
+
// doctor
|
|
15
|
+
// Runtime probe. Launches headless Chromium (--no-sandbox), opens
|
|
16
|
+
// about:blank, closes. On success prints {"ok":true,"chromium":"<version>"}
|
|
17
|
+
// and exits 0; on ANY failure prints {"ok":false,"error":"..."} and exits 1.
|
|
18
|
+
// The skill runs this first to decide browser-vs-text.
|
|
19
|
+
//
|
|
20
|
+
// run <flow.json> [--base-url URL] [--out-dir DIR] [--record-dir DIR]
|
|
21
|
+
// Executes a FLOW in ONE Chromium session (state preserved across steps) and
|
|
22
|
+
// prints a single JSON report.
|
|
23
|
+
//
|
|
24
|
+
// With --record-dir DIR (or `"record": true` in the flow), the whole session
|
|
25
|
+
// is screen-recorded via Playwright's native recordVideo and saved to
|
|
26
|
+
// <record-dir>/session.webm (default: the out-dir). The saved path is
|
|
27
|
+
// reported as `video` in the JSON. Used by the `/demo` workflow, which then
|
|
28
|
+
// composites the raw webm into a titled mp4 with compose-demo.sh.
|
|
29
|
+
//
|
|
30
|
+
// Flow shape:
|
|
31
|
+
// { "baseUrl": "http://localhost:3000",
|
|
32
|
+
// "viewport": {"width":1280,"height":800},
|
|
33
|
+
// "steps": [
|
|
34
|
+
// {"name":"home", "goto":"/"},
|
|
35
|
+
// {"click":"text=Login"},
|
|
36
|
+
// {"fill":["#email","a@b.com"]},
|
|
37
|
+
// {"type":["#search","hello"]},
|
|
38
|
+
// {"press":"Enter"},
|
|
39
|
+
// {"waitFor":"#dashboard"},
|
|
40
|
+
// {"assertText":"Welcome"},
|
|
41
|
+
// {"text":"h1"},
|
|
42
|
+
// {"screenshot":"after-login"}
|
|
43
|
+
// ] }
|
|
44
|
+
// A step may combine an action plus a trailing `screenshot`.
|
|
45
|
+
//
|
|
46
|
+
// Per-step semantics:
|
|
47
|
+
// - A step error (selector not found, assertion fail, timeout) is recorded
|
|
48
|
+
// {ok:false} and the run CONTINUES (best-effort QA) — EXCEPT a `goto`
|
|
49
|
+
// that throws is FATAL: remaining steps are marked skipped.
|
|
50
|
+
// - assertText passes if the text is visible anywhere on the page; on miss
|
|
51
|
+
// the step is {ok:false} but the run continues.
|
|
52
|
+
// - text extracts a selector's textContent into the step result.
|
|
53
|
+
// - screenshot writes <out-dir>/<basename>.png (full page).
|
|
54
|
+
//
|
|
55
|
+
// Final stdout: one JSON object
|
|
56
|
+
// { ok, baseUrl, steps:[{index,action,ok,ms,text?,screenshot?,error?}],
|
|
57
|
+
// consoleErrors:[...], screenshots:[paths] }
|
|
58
|
+
// Exit 0 even when steps failed (the agent reads the JSON to judge). Exit
|
|
59
|
+
// non-zero only on a FATAL harness error (bad flow file, launch failure).
|
|
60
|
+
//
|
|
61
|
+
// Dependency-free apart from playwright.
|
|
62
|
+
|
|
63
|
+
import { readFileSync, mkdirSync } from 'node:fs';
|
|
64
|
+
import { resolve, join } from 'node:path';
|
|
65
|
+
import { createRequire } from 'node:module';
|
|
66
|
+
|
|
67
|
+
// This file is ESM (.mjs); playwright is a CJS package. createRequire gives us
|
|
68
|
+
// a `require` that resolves an absolute package-dir path (see loadPlaywright).
|
|
69
|
+
const require = createRequire(import.meta.url);
|
|
70
|
+
|
|
71
|
+
const WAIT_TIMEOUT = 10_000; // sane default for waitFor / assertText probes
|
|
72
|
+
|
|
73
|
+
function emit(obj) {
|
|
74
|
+
process.stdout.write(JSON.stringify(obj) + '\n');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function loadPlaywright() {
|
|
78
|
+
// Resolve playwright via CJS `require`: it handles an absolute package-dir
|
|
79
|
+
// path ($LASTLIGHT_PLAYWRIGHT, baked into the QA image) by reading the
|
|
80
|
+
// package.json `main` — which ESM `import()` of a directory does NOT do — and
|
|
81
|
+
// it honours NODE_PATH for the bare-specifier fallback. playwright ships a CJS
|
|
82
|
+
// entry, so `require` returns { chromium, … } directly.
|
|
83
|
+
const candidates = [process.env.LASTLIGHT_PLAYWRIGHT, 'playwright'].filter(Boolean);
|
|
84
|
+
for (const spec of candidates) {
|
|
85
|
+
try {
|
|
86
|
+
return require(spec);
|
|
87
|
+
} catch {
|
|
88
|
+
// try the next candidate
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
emit({
|
|
92
|
+
ok: false,
|
|
93
|
+
error:
|
|
94
|
+
'playwright not available — browser QA needs the lastlight-sandbox-qa image',
|
|
95
|
+
});
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function doctor() {
|
|
100
|
+
const { chromium } = await loadPlaywright();
|
|
101
|
+
let browser;
|
|
102
|
+
try {
|
|
103
|
+
browser = await chromium.launch({ headless: true, args: ['--no-sandbox'] });
|
|
104
|
+
const page = await browser.newPage();
|
|
105
|
+
await page.goto('about:blank');
|
|
106
|
+
const version = browser.version();
|
|
107
|
+
await page.close();
|
|
108
|
+
emit({ ok: true, chromium: version });
|
|
109
|
+
process.exit(0);
|
|
110
|
+
} catch (err) {
|
|
111
|
+
emit({ ok: false, error: String(err && err.message ? err.message : err) });
|
|
112
|
+
process.exit(1);
|
|
113
|
+
} finally {
|
|
114
|
+
if (browser) await browser.close().catch(() => {});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Resolve a goto target against the base URL. Absolute URLs pass through.
|
|
119
|
+
function resolveUrl(target, baseUrl) {
|
|
120
|
+
if (/^https?:\/\//i.test(target)) return target;
|
|
121
|
+
if (!baseUrl) return target;
|
|
122
|
+
return baseUrl.replace(/\/+$/, '') + '/' + String(target).replace(/^\/+/, '');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Returns the action name for a step (for reporting) — first recognized key.
|
|
126
|
+
function actionOf(step) {
|
|
127
|
+
for (const k of [
|
|
128
|
+
'goto',
|
|
129
|
+
'click',
|
|
130
|
+
'fill',
|
|
131
|
+
'type',
|
|
132
|
+
'press',
|
|
133
|
+
'waitFor',
|
|
134
|
+
'assertText',
|
|
135
|
+
'text',
|
|
136
|
+
]) {
|
|
137
|
+
if (k in step) return k;
|
|
138
|
+
}
|
|
139
|
+
if ('screenshot' in step) return 'screenshot';
|
|
140
|
+
return 'noop';
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async function execStep(page, step, baseUrl, outDir, screenshots) {
|
|
144
|
+
const result = {};
|
|
145
|
+
let fatal = false;
|
|
146
|
+
|
|
147
|
+
if ('goto' in step) {
|
|
148
|
+
// Navigation failure is FATAL.
|
|
149
|
+
try {
|
|
150
|
+
await page.goto(resolveUrl(step.goto, baseUrl), {
|
|
151
|
+
waitUntil: 'load',
|
|
152
|
+
timeout: WAIT_TIMEOUT * 3,
|
|
153
|
+
});
|
|
154
|
+
} catch (err) {
|
|
155
|
+
throw Object.assign(new Error(`goto failed: ${err.message}`), {
|
|
156
|
+
fatal: true,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
} else if ('click' in step) {
|
|
160
|
+
await page.click(step.click, { timeout: WAIT_TIMEOUT });
|
|
161
|
+
} else if ('fill' in step) {
|
|
162
|
+
const [sel, val] = step.fill;
|
|
163
|
+
await page.fill(sel, val, { timeout: WAIT_TIMEOUT });
|
|
164
|
+
} else if ('type' in step) {
|
|
165
|
+
const [sel, val] = step.type;
|
|
166
|
+
await page.locator(sel).first().pressSequentially(val, {
|
|
167
|
+
timeout: WAIT_TIMEOUT,
|
|
168
|
+
});
|
|
169
|
+
} else if ('press' in step) {
|
|
170
|
+
await page.keyboard.press(step.press);
|
|
171
|
+
} else if ('waitFor' in step) {
|
|
172
|
+
await page.locator(step.waitFor).first().waitFor({
|
|
173
|
+
state: 'visible',
|
|
174
|
+
timeout: WAIT_TIMEOUT,
|
|
175
|
+
});
|
|
176
|
+
} else if ('assertText' in step) {
|
|
177
|
+
// Pass if visible anywhere on the page; miss => step fails, run continues.
|
|
178
|
+
try {
|
|
179
|
+
await page
|
|
180
|
+
.getByText(step.assertText, { exact: false })
|
|
181
|
+
.first()
|
|
182
|
+
.waitFor({ state: 'visible', timeout: WAIT_TIMEOUT });
|
|
183
|
+
} catch {
|
|
184
|
+
throw new Error(`assertText not found: ${JSON.stringify(step.assertText)}`);
|
|
185
|
+
}
|
|
186
|
+
} else if ('text' in step) {
|
|
187
|
+
const txt = await page
|
|
188
|
+
.locator(step.text)
|
|
189
|
+
.first()
|
|
190
|
+
.textContent({ timeout: WAIT_TIMEOUT });
|
|
191
|
+
result.text = txt == null ? '' : txt.trim();
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// A trailing screenshot can ride along with any action (or stand alone).
|
|
195
|
+
if ('screenshot' in step) {
|
|
196
|
+
const base = String(step.screenshot).replace(/[^a-zA-Z0-9._-]/g, '_');
|
|
197
|
+
const path = join(outDir, `${base}.png`);
|
|
198
|
+
await page.screenshot({ path, fullPage: true });
|
|
199
|
+
result.screenshot = path;
|
|
200
|
+
screenshots.push(path);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return { result, fatal };
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
async function run(flowPath, baseUrlArg, outDirArg, recordDirArg) {
|
|
207
|
+
let flow;
|
|
208
|
+
try {
|
|
209
|
+
flow = JSON.parse(readFileSync(resolve(flowPath), 'utf8'));
|
|
210
|
+
} catch (err) {
|
|
211
|
+
emit({ ok: false, error: `cannot read flow file: ${err.message}` });
|
|
212
|
+
process.exit(1);
|
|
213
|
+
}
|
|
214
|
+
if (!flow || !Array.isArray(flow.steps)) {
|
|
215
|
+
emit({ ok: false, error: 'flow file must have a "steps" array' });
|
|
216
|
+
process.exit(1);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const baseUrl = baseUrlArg || flow.baseUrl || '';
|
|
220
|
+
const outDir = resolve(outDirArg || process.cwd());
|
|
221
|
+
// Record the session when --record-dir is passed OR the flow opts in with
|
|
222
|
+
// `"record": true`. The .webm lands in the record dir (default: out-dir).
|
|
223
|
+
const doRecord = !!recordDirArg || flow.record === true;
|
|
224
|
+
const videoDir = resolve(recordDirArg || outDir);
|
|
225
|
+
try {
|
|
226
|
+
mkdirSync(outDir, { recursive: true });
|
|
227
|
+
} catch {
|
|
228
|
+
/* best effort */
|
|
229
|
+
}
|
|
230
|
+
if (doRecord) {
|
|
231
|
+
try {
|
|
232
|
+
mkdirSync(videoDir, { recursive: true });
|
|
233
|
+
} catch {
|
|
234
|
+
/* best effort */
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const viewport = flow.viewport || { width: 1280, height: 800 };
|
|
239
|
+
const { chromium } = await loadPlaywright();
|
|
240
|
+
let browser;
|
|
241
|
+
const steps = [];
|
|
242
|
+
const screenshots = [];
|
|
243
|
+
const consoleErrors = [];
|
|
244
|
+
let videoPath = null;
|
|
245
|
+
|
|
246
|
+
try {
|
|
247
|
+
browser = await chromium.launch({ headless: true, args: ['--no-sandbox'] });
|
|
248
|
+
} catch (err) {
|
|
249
|
+
emit({
|
|
250
|
+
ok: false,
|
|
251
|
+
error: `browser launch failed: ${err && err.message ? err.message : err}`,
|
|
252
|
+
});
|
|
253
|
+
process.exit(1);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
try {
|
|
257
|
+
const context = await browser.newContext({
|
|
258
|
+
viewport,
|
|
259
|
+
// Playwright records video per-context; the size matches the viewport so
|
|
260
|
+
// the clip isn't letterboxed. The .webm is flushed on context.close().
|
|
261
|
+
...(doRecord ? { recordVideo: { dir: videoDir, size: viewport } } : {}),
|
|
262
|
+
});
|
|
263
|
+
const page = await context.newPage();
|
|
264
|
+
|
|
265
|
+
page.on('console', (msg) => {
|
|
266
|
+
if (msg.type() === 'error') consoleErrors.push(msg.text());
|
|
267
|
+
});
|
|
268
|
+
page.on('pageerror', (err) => {
|
|
269
|
+
consoleErrors.push(String(err && err.message ? err.message : err));
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
let fatalHit = false;
|
|
273
|
+
for (let i = 0; i < flow.steps.length; i++) {
|
|
274
|
+
const step = flow.steps[i];
|
|
275
|
+
const action = actionOf(step);
|
|
276
|
+
|
|
277
|
+
if (fatalHit) {
|
|
278
|
+
steps.push({ index: i, action, ok: false, ms: 0, error: 'skipped (prior fatal step)' });
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const started = Date.now();
|
|
283
|
+
try {
|
|
284
|
+
const { result } = await execStep(page, step, baseUrl, outDir, screenshots);
|
|
285
|
+
steps.push({ index: i, action, ok: true, ms: Date.now() - started, ...result });
|
|
286
|
+
} catch (err) {
|
|
287
|
+
const entry = {
|
|
288
|
+
index: i,
|
|
289
|
+
action,
|
|
290
|
+
ok: false,
|
|
291
|
+
ms: Date.now() - started,
|
|
292
|
+
error: String(err && err.message ? err.message : err),
|
|
293
|
+
};
|
|
294
|
+
steps.push(entry);
|
|
295
|
+
if (err && err.fatal) fatalHit = true; // navigation failure: skip the rest
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Finalize a recording (if any) BEFORE emitting: saving the video requires
|
|
300
|
+
// the context to close, which flushes the .webm to disk. A save failure is a
|
|
301
|
+
// reported finding, not a fatal run error.
|
|
302
|
+
if (doRecord) {
|
|
303
|
+
const video = page.video();
|
|
304
|
+
await context.close();
|
|
305
|
+
if (video) {
|
|
306
|
+
const target = join(videoDir, 'session.webm');
|
|
307
|
+
try {
|
|
308
|
+
await video.saveAs(target);
|
|
309
|
+
videoPath = target;
|
|
310
|
+
await video.delete().catch(() => {});
|
|
311
|
+
} catch (err) {
|
|
312
|
+
consoleErrors.push(
|
|
313
|
+
`video save failed: ${err && err.message ? err.message : err}`,
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
emit({
|
|
320
|
+
ok: steps.every((s) => s.ok),
|
|
321
|
+
baseUrl,
|
|
322
|
+
steps,
|
|
323
|
+
consoleErrors,
|
|
324
|
+
screenshots,
|
|
325
|
+
...(videoPath ? { video: videoPath } : {}),
|
|
326
|
+
});
|
|
327
|
+
process.exit(0);
|
|
328
|
+
} catch (err) {
|
|
329
|
+
// Unexpected harness error mid-run — still emit a JSON object.
|
|
330
|
+
emit({
|
|
331
|
+
ok: false,
|
|
332
|
+
error: String(err && err.message ? err.message : err),
|
|
333
|
+
baseUrl,
|
|
334
|
+
steps,
|
|
335
|
+
consoleErrors,
|
|
336
|
+
screenshots,
|
|
337
|
+
...(videoPath ? { video: videoPath } : {}),
|
|
338
|
+
});
|
|
339
|
+
process.exit(1);
|
|
340
|
+
} finally {
|
|
341
|
+
if (browser) await browser.close().catch(() => {});
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
async function main() {
|
|
346
|
+
const [cmd, ...rest] = process.argv.slice(2);
|
|
347
|
+
|
|
348
|
+
if (cmd === 'doctor') {
|
|
349
|
+
await doctor();
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (cmd === 'run') {
|
|
354
|
+
const positional = [];
|
|
355
|
+
let baseUrl;
|
|
356
|
+
let outDir;
|
|
357
|
+
let recordDir;
|
|
358
|
+
for (let i = 0; i < rest.length; i++) {
|
|
359
|
+
const a = rest[i];
|
|
360
|
+
if (a === '--base-url') baseUrl = rest[++i];
|
|
361
|
+
else if (a === '--out-dir') outDir = rest[++i];
|
|
362
|
+
else if (a === '--record-dir') recordDir = rest[++i];
|
|
363
|
+
else positional.push(a);
|
|
364
|
+
}
|
|
365
|
+
if (!positional[0]) {
|
|
366
|
+
emit({ ok: false, error: 'usage: agent-browser.mjs run <flow.json> [--base-url URL] [--out-dir DIR] [--record-dir DIR]' });
|
|
367
|
+
process.exit(1);
|
|
368
|
+
}
|
|
369
|
+
await run(positional[0], baseUrl, outDir, recordDir);
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
emit({ ok: false, error: 'usage: agent-browser.mjs <doctor|run> ...' });
|
|
374
|
+
process.exit(1);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
main().catch((err) => {
|
|
378
|
+
emit({ ok: false, error: String(err && err.message ? err.message : err) });
|
|
379
|
+
process.exit(1);
|
|
380
|
+
});
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: building
|
|
3
|
+
description: Install dependencies and run the test/lint/typecheck gate for a change inside the sandbox — package-manager detection, install-first, and (when implementing) TDD discipline. Use when implementing, fixing, or verifying code in a pre-cloned repo.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
tags: [build, test, sandbox]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Building
|
|
9
|
+
|
|
10
|
+
How to install, build, test, and gate a change in the sandbox. The same
|
|
11
|
+
discipline whether you're implementing a feature, fixing review feedback, or
|
|
12
|
+
verifying someone else's PR.
|
|
13
|
+
|
|
14
|
+
## Workspace & git
|
|
15
|
+
|
|
16
|
+
The harness pre-cloned the repo; your cwd is the repo root (or a `<repo>/`
|
|
17
|
+
subdirectory — check with `ls -la`). Git is configured for clone/push/pull/fetch.
|
|
18
|
+
If auth fails after ~1 hour, call the `github_refresh_git_auth` MCP tool. Suppress
|
|
19
|
+
noise where it helps: `git clone --quiet`, `git push --quiet`, `CI=true`.
|
|
20
|
+
|
|
21
|
+
## Install-first
|
|
22
|
+
|
|
23
|
+
`node_modules` (and any other dependency dir) is **always** absent on arrival —
|
|
24
|
+
by design, not a blocker. **Installing is the first step, not a reason to skip
|
|
25
|
+
verification.** Detect the package manager from the lockfile and use the
|
|
26
|
+
frozen/CI variant:
|
|
27
|
+
|
|
28
|
+
- `package-lock.json` → `npm ci`
|
|
29
|
+
- `pnpm-lock.yaml` → `corepack pnpm install --frozen-lockfile`
|
|
30
|
+
- `yarn.lock` → `corepack yarn install --frozen-lockfile`
|
|
31
|
+
|
|
32
|
+
Node is available via `fnm` + `corepack`; the egress allowlist permits the public
|
|
33
|
+
package registries, so install works. For a monorepo, install at the root, then
|
|
34
|
+
operate on the changed package. For non-Node repos, use the ecosystem's
|
|
35
|
+
equivalent (`pip install`, `cargo build`, `go mod download`, …) read from the
|
|
36
|
+
project's manifest.
|
|
37
|
+
|
|
38
|
+
The **only** acceptable "couldn't verify" is when the install or build command
|
|
39
|
+
*itself* fails — quote the exact command and error, and scope your work to what
|
|
40
|
+
you could check. Never cite "deps aren't installed" as the reason: you install them.
|
|
41
|
+
|
|
42
|
+
**If the repo's only test path needs an external service that won't run in the
|
|
43
|
+
sandbox** (a live database, a cloud API, a running daemon), do **not** report
|
|
44
|
+
that verification "could not run." Add a focused unit or CLI test project that
|
|
45
|
+
exercises your change against in-memory fixtures or fakes, run *that*, and paste
|
|
46
|
+
its output. A change you couldn't execute even once is unverified — building a
|
|
47
|
+
runnable path is part of the work, not an optional extra.
|
|
48
|
+
|
|
49
|
+
## The gate
|
|
50
|
+
|
|
51
|
+
While iterating, run **only the tests covering the files you touched** — not the
|
|
52
|
+
whole suite on every edit. Then, **once before committing or claiming done, run
|
|
53
|
+
the full gate and require all of it to pass:**
|
|
54
|
+
|
|
55
|
+
1. Full test command — zero failures.
|
|
56
|
+
2. Lint command (if present) — fix all errors.
|
|
57
|
+
3. Typecheck command (if present) — fix all errors.
|
|
58
|
+
|
|
59
|
+
If any step fails, fix it and re-run only what failed until clean. Do not commit
|
|
60
|
+
or report done until the full suite, lint, and typecheck all pass. Cite the
|
|
61
|
+
actual command output — static reasoning is not verification.
|
|
62
|
+
|
|
63
|
+
## TDD (when implementing)
|
|
64
|
+
|
|
65
|
+
When you are *writing* code (not just verifying a PR): write the **failing test
|
|
66
|
+
first**, watch it go red, then implement until it goes green, then refactor.
|
|
67
|
+
Test behaviour through the public interface, not implementation details. The red
|
|
68
|
+
test is the proof the test can fail — a test that was never red proves nothing.
|
|
69
|
+
|
|
70
|
+
## Decomposition budget (when implementing)
|
|
71
|
+
|
|
72
|
+
The gate passing is necessary, not sufficient — a green test does not excuse an
|
|
73
|
+
unmaintainable function. Before you commit, decompose:
|
|
74
|
+
|
|
75
|
+
- Keep each function under **roughly 15 cyclomatic complexity** (branches +
|
|
76
|
+
loops + boolean operators). If you're past that, extract helpers.
|
|
77
|
+
- One function = one responsibility. A function that **parses, validates, and
|
|
78
|
+
emits is three functions** — split it before committing, not "later."
|
|
79
|
+
- The refactor step of red-green-refactor is where this happens. Don't skip it
|
|
80
|
+
because the tests already pass.
|
|
81
|
+
|
|
82
|
+
## Type safety — no compiler-silencing assertions
|
|
83
|
+
|
|
84
|
+
The gate requires `tsc` (or the project's typechecker) to pass — but passing it
|
|
85
|
+
by *suppressing* it is a regression, not a fix. **Never** use `as any`, an
|
|
86
|
+
unchecked `as`-cast, `@ts-ignore`/`@ts-expect-error`, `# type: ignore`, or the
|
|
87
|
+
equivalent to:
|
|
88
|
+
|
|
89
|
+
- silence a compiler error instead of fixing the underlying type, or
|
|
90
|
+
- bypass a validator/guard the same code path defines (e.g. casting past a Zod
|
|
91
|
+
schema, a runtime type guard, or a parse function so the value skips the very
|
|
92
|
+
check that file exists to enforce).
|
|
93
|
+
|
|
94
|
+
If the types genuinely can't express something, narrow with a real type guard or
|
|
95
|
+
fix the type — don't assert your way past it.
|
package/skills/chat/SKILL.md
CHANGED
|
@@ -1,17 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: chat
|
|
3
|
+
description: Conversational assistant for messaging-platform threads (Slack, Discord). Answer questions about repos, PRs, and issues, explain code, and guide users to natural-language triggers (e.g. "build owner/repo#N", "triage owner/repo", "review PRs on owner/repo", "status").
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# Chat
|
|
2
7
|
|
|
3
|
-
|
|
8
|
+
You are answering in a messaging thread (Slack, Discord). The conversation is
|
|
9
|
+
the job — answer the question that was asked, don't expand it into a report.
|
|
10
|
+
|
|
11
|
+
## What you do
|
|
12
|
+
|
|
13
|
+
- Answer questions about repositories, issues, pull requests, and code.
|
|
14
|
+
- Explain how the bot's workflows behave.
|
|
15
|
+
- Report status on running work when asked.
|
|
16
|
+
|
|
17
|
+
## What you don't do
|
|
18
|
+
|
|
19
|
+
Chat is **read-and-explain only**. You don't review PRs, triage issues, run
|
|
20
|
+
builds, or change anything. When the user wants an *action*, name the
|
|
21
|
+
natural-language trigger and stop:
|
|
4
22
|
|
|
5
|
-
|
|
23
|
+
- code changes → `build owner/repo#N`
|
|
24
|
+
- issue triage → `triage owner/repo`
|
|
25
|
+
- PR review → `review PRs on owner/repo`
|
|
26
|
+
- security scan → `security review owner/repo`
|
|
27
|
+
- running-task status → `status`
|
|
6
28
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
- Provide status on running tasks when asked
|
|
10
|
-
- Suggest commands for actions: `/build`, `/triage`, `/review`, `/status`
|
|
29
|
+
Phrase triggers as natural language — never with a leading `/`, which Slack
|
|
30
|
+
intercepts before it reaches Last Light.
|
|
11
31
|
|
|
12
|
-
##
|
|
32
|
+
## Style
|
|
13
33
|
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
- If the user wants to trigger an action, guide them to the appropriate slash command
|
|
34
|
+
- Concise — messaging panes are narrow. A few sentences beats a wall of text.
|
|
35
|
+
- Markdown sparingly: bold for emphasis, fenced blocks for code.
|
|
36
|
+
- Lead with the answer. Cite `path:line` when pointing at code.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: code-review
|
|
3
|
+
description: The shared rubric for reviewing a code change — finding tiers (Critical/Important/Suggestions/Nits) and what to check (correctness, security, edge cases, regression risk, test coverage). Use when reviewing a PR or a branch diff.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
tags: [review, code-quality]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Code Review
|
|
9
|
+
|
|
10
|
+
The shared rubric for assessing a code change. Used both by a PR review and by
|
|
11
|
+
the build cycle's branch-diff reviewer — the *procedure* differs (where the diff
|
|
12
|
+
comes from, how the verdict is recorded), but the rubric below is the same.
|
|
13
|
+
|
|
14
|
+
Review the change **in full context** — read each changed file, not just the
|
|
15
|
+
hunk. For a large change (>300 lines or >5 files): trace data flow through
|
|
16
|
+
modified functions, check callers of anything whose signature or behaviour
|
|
17
|
+
changed for regression risk, and check that tests cover the actual risk areas,
|
|
18
|
+
not just the happy path.
|
|
19
|
+
|
|
20
|
+
## Finding tiers
|
|
21
|
+
|
|
22
|
+
Categorise every finding into exactly one tier:
|
|
23
|
+
|
|
24
|
+
- **Critical** — security issues, data loss, breaking changes, silent
|
|
25
|
+
data-dropping (see Correctness below). Blocks merge.
|
|
26
|
+
- **Important** — missing tests, performance problems, type errors, **avoidable
|
|
27
|
+
duplication**, **excessive complexity**, **compiler-silencing assertions**.
|
|
28
|
+
Should fix.
|
|
29
|
+
- **Suggestions** — clarity, naming, minor DRY tidy-ups. Nice to have.
|
|
30
|
+
- **Nits** — style, formatting. Optional.
|
|
31
|
+
|
|
32
|
+
## What to check
|
|
33
|
+
|
|
34
|
+
- **Correctness** — does it do what it claims? Logic errors, off-by-one, wrong
|
|
35
|
+
conditions, mishandled async. **A silent default or a dropped output for an
|
|
36
|
+
input the code doesn't support is a correctness bug, not graceful handling** —
|
|
37
|
+
flag any unsupported case that is silently defaulted, skipped, or omitted
|
|
38
|
+
instead of warned-and-skipped or warned-and-surfaced.
|
|
39
|
+
- **Edge cases** — empty/null inputs, boundaries, error paths, concurrency.
|
|
40
|
+
- **Security** — injection, auth/authorization, secret handling, untrusted input.
|
|
41
|
+
- **Complexity** — flag functions past ~15 cyclomatic complexity or that mix
|
|
42
|
+
parse/validate/emit responsibilities; ask for helper extraction. This is an
|
|
43
|
+
**Important** finding, not a nit.
|
|
44
|
+
- **Duplication** — flag avoidable duplicated logic (two or more clone groups of
|
|
45
|
+
the same code/branching). DRY is **should-fix** here, not merely "nice to have."
|
|
46
|
+
- **Type safety** — flag `as any`, unchecked `as`-casts, or `@ts-ignore` used to
|
|
47
|
+
silence the compiler or to bypass a validator the same code path defines.
|
|
48
|
+
- **Regression risk** — existing callers of changed functions; behaviour changes
|
|
49
|
+
that ripple.
|
|
50
|
+
- **Test coverage** — do the tests exercise the real risk, or just the happy path?
|
|
51
|
+
- **Fit** — does it match the codebase's existing patterns and conventions?
|
|
52
|
+
|
|
53
|
+
## Calibration
|
|
54
|
+
|
|
55
|
+
- Don't nitpick generated files (lockfiles, compiled assets).
|
|
56
|
+
- Don't repeat what linters/CI already catch.
|
|
57
|
+
- Don't block over style preferences alone.
|
|
58
|
+
- Read the room: if a human reviewer already approved, lower the bar for blocking
|
|
59
|
+
— prefer a comment over requesting changes on non-critical findings.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: debug-production
|
|
3
|
+
description: Debug a running Last Light instance (usually production) via the `lastlight` CLI instead of SSH. Use when investigating a failed/stuck workflow, a bad agent run, a phase error, or "why didn't the bot do X" — anything that previously meant SSHing in to read SQLite or session logs.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
tags: [ops, debugging, cli]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Debug a Last Light instance via the CLI
|
|
9
|
+
|
|
10
|
+
Read a running instance's state over its admin API with the `lastlight` CLI —
|
|
11
|
+
no SSH, no poking SQLite or jsonl files on the box. Every command takes
|
|
12
|
+
`--json` for machine-parseable output; prefer it when you need to extract
|
|
13
|
+
fields.
|
|
14
|
+
|
|
15
|
+
## 0. Connect
|
|
16
|
+
|
|
17
|
+
The CLI talks to whatever instance you logged into (saved in
|
|
18
|
+
`~/.lastlight/config.json`). Confirm you're pointed at the right one and the
|
|
19
|
+
token is valid:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
lastlight status # instance URL, server health, token validity
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
If the token is missing/expired, authenticate (the prod instance URL lives in
|
|
26
|
+
local agent memory — see the "Last Light production server" note):
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
lastlight login https://<instance> # browser handoff (password/Slack/GitHub)
|
|
30
|
+
lastlight login https://<instance> --password # headless fallback
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
For one-off targeting without saving, pass `--url` / `--token` on any command,
|
|
34
|
+
or set `LASTLIGHT_URL` / `LASTLIGHT_TOKEN` (env wins over the saved config).
|
|
35
|
+
|
|
36
|
+
## 1. Find the broken run
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
lastlight workflow list --status failed # recent failures
|
|
40
|
+
lastlight workflow list --status active # running + paused now
|
|
41
|
+
lastlight workflow list --workflow pr-review --limit 50
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Copy the run `ID` from the table.
|
|
45
|
+
|
|
46
|
+
## 2. Inspect the run's phases
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
lastlight workflow log <run-id> # run header + per-phase table (✓/✗, duration, session id, error)
|
|
50
|
+
lastlight workflow log <run-id> --follow # then tail the current phase live
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The phase table shows which phase failed, its error snippet, and the `SESSION`
|
|
54
|
+
id you need for the transcript.
|
|
55
|
+
|
|
56
|
+
## 3. Read / tail the agent transcript
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
lastlight session list # recent sandbox sessions (TYPE, MODEL, LIVE)
|
|
60
|
+
lastlight session log <session-id> # full transcript
|
|
61
|
+
lastlight session log <session-id> --follow # live tail (SSE) of an in-flight phase
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## 4. Search across runs
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
lastlight logs search "ECONNREFUSED" # errors ledger (default)
|
|
68
|
+
lastlight logs search "rate limit" --scope all # errors + transcript content
|
|
69
|
+
lastlight logs search "could not clone" --scope messages --limit 20
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`--scope errors` (default) matches the executions ledger (error/skill/repo);
|
|
73
|
+
`messages` greps recent session transcripts; `all` does both.
|
|
74
|
+
|
|
75
|
+
## 5. Raw server / docker logs
|
|
76
|
+
|
|
77
|
+
When the workflow + session views aren't enough — a crash before any session
|
|
78
|
+
was written, a sidecar misbehaving, harness boot errors — read the actual
|
|
79
|
+
container logs (`docker logs`) over the API:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
lastlight server list # the lastlight-* containers + status
|
|
83
|
+
lastlight server logs # the agent harness (default), last 200 lines
|
|
84
|
+
lastlight server logs --tail 500 --since 10m
|
|
85
|
+
lastlight server logs --follow # live tail (Ctrl-C to stop)
|
|
86
|
+
lastlight server logs coredns-strict # a specific sidecar by service or container name
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## 6. Approvals & health
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
lastlight approvals list # paused gates waiting on a human
|
|
93
|
+
lastlight approvals approve <id> --reason "looks good"
|
|
94
|
+
lastlight approvals reject <id> --reason "wrong approach"
|
|
95
|
+
|
|
96
|
+
lastlight stats # totals + per-skill success/fail
|
|
97
|
+
lastlight stats --daily 14 # last 14 days of cost/tokens
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Tips
|
|
101
|
+
|
|
102
|
+
- Add `--json` to any command to pipe into `jq` (e.g.
|
|
103
|
+
`lastlight workflow list --status failed --json | jq -r '.workflowRuns[].id'`).
|
|
104
|
+
- Triage flow: `workflow list --status failed` → `workflow log <id>` → grab the
|
|
105
|
+
failed phase's session → `session log <session-id>` → if it's a recurring
|
|
106
|
+
symptom, `logs search "<error text>"` to see how often it happens.
|
|
107
|
+
- These are read-only except `approvals approve/reject` and the trigger
|
|
108
|
+
commands (`build`/`triage`/`review`/…) — debugging never mutates the box.
|