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,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server version + drift detection for the dashboard banner.
|
|
3
|
+
*
|
|
4
|
+
* Computed agent-side (inside the container) from what the harness can reach:
|
|
5
|
+
* - core.current — baked at build time as LASTLIGHT_GIT_SHA (Dockerfile ARG).
|
|
6
|
+
* - core.latest — `git ls-remote` of the public core repo (agent has GitHub
|
|
7
|
+
* egress). Best-effort; null on failure.
|
|
8
|
+
* - overlay.current — `git rev-parse HEAD` in the read-only-mounted overlay
|
|
9
|
+
* checkout (its .git is readable).
|
|
10
|
+
* - overlay.latest — best-effort `git ls-remote`; often null in-container
|
|
11
|
+
* (the private overlay's deploy key isn't present), shown as
|
|
12
|
+
* "unknown" rather than implying drift.
|
|
13
|
+
*
|
|
14
|
+
* `behind` is only true when BOTH SHAs are known and differ — so an unreachable
|
|
15
|
+
* remote never produces a false "update available". The authoritative drift
|
|
16
|
+
* view is `lastlight server status` on the host (full git access); this is the
|
|
17
|
+
* in-dashboard nudge.
|
|
18
|
+
*/
|
|
19
|
+
import { execFile } from "node:child_process";
|
|
20
|
+
import { promisify } from "node:util";
|
|
21
|
+
import { readFileSync } from "node:fs";
|
|
22
|
+
import { resolve } from "node:path";
|
|
23
|
+
const exec = promisify(execFile);
|
|
24
|
+
const CORE_REMOTE = "https://github.com/cliftonc/lastlight";
|
|
25
|
+
/** Overlay checkout path inside the container (LASTLIGHT_OVERLAY_DIR mount). */
|
|
26
|
+
function overlayDir() {
|
|
27
|
+
return process.env.LASTLIGHT_OVERLAY_DIR || "/app/instance";
|
|
28
|
+
}
|
|
29
|
+
/** Capture trimmed stdout with a short timeout; null instead of throwing. */
|
|
30
|
+
async function softCapture(cmd, args) {
|
|
31
|
+
try {
|
|
32
|
+
const { stdout } = await exec(cmd, args, { timeout: 8000 });
|
|
33
|
+
return stdout.trim() || null;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** First column of `git ls-remote … <ref>` — the SHA, or null. */
|
|
40
|
+
function lsRemoteSha(stdout) {
|
|
41
|
+
if (!stdout)
|
|
42
|
+
return null;
|
|
43
|
+
const first = stdout.split(/\s+/)[0];
|
|
44
|
+
return /^[0-9a-f]{7,40}$/i.test(first) ? first : null;
|
|
45
|
+
}
|
|
46
|
+
function compare(current, latest) {
|
|
47
|
+
return { current, latest, behind: !!current && !!latest && current !== latest };
|
|
48
|
+
}
|
|
49
|
+
function readPackageVersion() {
|
|
50
|
+
try {
|
|
51
|
+
const pkg = JSON.parse(readFileSync(resolve("package.json"), "utf8"));
|
|
52
|
+
return pkg.version ?? null;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/** Compute core + overlay version drift for `GET /admin/api/server/info`. */
|
|
59
|
+
export async function getServerVersion() {
|
|
60
|
+
const ov = overlayDir();
|
|
61
|
+
const [coreLatest, overlayCurrent, overlayLatest] = await Promise.all([
|
|
62
|
+
softCapture("git", ["ls-remote", CORE_REMOTE, "HEAD"]),
|
|
63
|
+
softCapture("git", ["-C", ov, "rev-parse", "HEAD"]),
|
|
64
|
+
softCapture("git", ["-C", ov, "ls-remote", "origin", "HEAD"]),
|
|
65
|
+
]);
|
|
66
|
+
return {
|
|
67
|
+
core: compare(process.env.LASTLIGHT_GIT_SHA || null, lsRemoteSha(coreLatest)),
|
|
68
|
+
overlay: compare(overlayCurrent, lsRemoteSha(overlayLatest)),
|
|
69
|
+
packageVersion: readPackageVersion(),
|
|
70
|
+
buildDate: process.env.LASTLIGHT_BUILD_DATE || null,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/admin/version.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAEjC,MAAM,WAAW,GAAG,uCAAuC,CAAC;AAC5D,gFAAgF;AAChF,SAAS,UAAU;IACjB,OAAO,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,eAAe,CAAC;AAC9D,CAAC;AAiBD,6EAA6E;AAC7E,KAAK,UAAU,WAAW,CAAC,GAAW,EAAE,IAAc;IACpD,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5D,OAAO,MAAM,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,kEAAkE;AAClE,SAAS,WAAW,CAAC,MAAqB;IACxC,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACrC,OAAO,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACxD,CAAC;AAED,SAAS,OAAO,CAAC,OAAsB,EAAE,MAAqB;IAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;AAClF,CAAC;AAED,SAAS,kBAAkB;IACzB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC,CAAyB,CAAC;QAC9F,OAAO,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,6EAA6E;AAC7E,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,MAAM,EAAE,GAAG,UAAU,EAAE,CAAC;IACxB,MAAM,CAAC,UAAU,EAAE,cAAc,EAAE,aAAa,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACpE,WAAW,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;QACtD,WAAW,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;QACnD,WAAW,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;KAC9D,CAAC,CAAC;IACH,OAAO;QACL,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,IAAI,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC;QAC7E,OAAO,EAAE,OAAO,CAAC,cAAc,EAAE,WAAW,CAAC,aAAa,CAAC,CAAC;QAC5D,cAAc,EAAE,kBAAkB,EAAE;QACpC,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,IAAI;KACpD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
+
// Mock execFile so getServerVersion's git calls return controllable output.
|
|
3
|
+
// promisify(execFile) calls execFile(file, args, opts, cb) — invoke cb here.
|
|
4
|
+
const execFileMock = vi.hoisted(() => vi.fn());
|
|
5
|
+
vi.mock("node:child_process", () => ({ execFile: execFileMock }));
|
|
6
|
+
import { getServerVersion } from "./version.js";
|
|
7
|
+
const OV = "/tmp/test-overlay";
|
|
8
|
+
let responses;
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
process.env.LASTLIGHT_OVERLAY_DIR = OV;
|
|
11
|
+
responses = {};
|
|
12
|
+
execFileMock.mockImplementation((_file, args, opts, cb) => {
|
|
13
|
+
const callback = (typeof opts === "function" ? opts : cb);
|
|
14
|
+
const r = responses[args.join(" ")];
|
|
15
|
+
if (r instanceof Error)
|
|
16
|
+
callback(r);
|
|
17
|
+
else
|
|
18
|
+
callback(null, { stdout: r ?? "", stderr: "" });
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
delete process.env.LASTLIGHT_GIT_SHA;
|
|
23
|
+
delete process.env.LASTLIGHT_OVERLAY_DIR;
|
|
24
|
+
vi.restoreAllMocks();
|
|
25
|
+
});
|
|
26
|
+
const coreLsRemote = "ls-remote https://github.com/cliftonc/lastlight HEAD";
|
|
27
|
+
const overlayRevParse = `-C ${OV} rev-parse HEAD`;
|
|
28
|
+
const overlayLsRemote = `-C ${OV} ls-remote origin HEAD`;
|
|
29
|
+
describe("getServerVersion", () => {
|
|
30
|
+
it("flags core behind when current SHA differs from remote", async () => {
|
|
31
|
+
process.env.LASTLIGHT_GIT_SHA = "aaaa1111aaaa1111";
|
|
32
|
+
responses[coreLsRemote] = "bbbb2222bbbb2222\tHEAD";
|
|
33
|
+
responses[overlayRevParse] = "cccc3333";
|
|
34
|
+
responses[overlayLsRemote] = "cccc3333\tHEAD";
|
|
35
|
+
const v = await getServerVersion();
|
|
36
|
+
expect(v.core.current).toBe("aaaa1111aaaa1111");
|
|
37
|
+
expect(v.core.latest).toBe("bbbb2222bbbb2222");
|
|
38
|
+
expect(v.core.behind).toBe(true);
|
|
39
|
+
expect(v.overlay.behind).toBe(false); // equal SHAs
|
|
40
|
+
});
|
|
41
|
+
it("is not behind when current matches remote", async () => {
|
|
42
|
+
process.env.LASTLIGHT_GIT_SHA = "deadbeefdeadbeef";
|
|
43
|
+
responses[coreLsRemote] = "deadbeefdeadbeef\tHEAD";
|
|
44
|
+
responses[overlayRevParse] = "1111";
|
|
45
|
+
responses[overlayLsRemote] = "1111\tHEAD";
|
|
46
|
+
const v = await getServerVersion();
|
|
47
|
+
expect(v.core.behind).toBe(false);
|
|
48
|
+
});
|
|
49
|
+
it("treats an unreachable remote as unknown, never behind", async () => {
|
|
50
|
+
process.env.LASTLIGHT_GIT_SHA = "aaaa1111";
|
|
51
|
+
responses[coreLsRemote] = new Error("network down");
|
|
52
|
+
responses[overlayRevParse] = "2222";
|
|
53
|
+
responses[overlayLsRemote] = new Error("no auth");
|
|
54
|
+
const v = await getServerVersion();
|
|
55
|
+
expect(v.core.current).toBe("aaaa1111");
|
|
56
|
+
expect(v.core.latest).toBeNull();
|
|
57
|
+
expect(v.core.behind).toBe(false);
|
|
58
|
+
expect(v.overlay.current).toBe("2222");
|
|
59
|
+
expect(v.overlay.latest).toBeNull();
|
|
60
|
+
expect(v.overlay.behind).toBe(false);
|
|
61
|
+
});
|
|
62
|
+
it("reports core.current null when the SHA wasn't baked", async () => {
|
|
63
|
+
responses[coreLsRemote] = "abcd1234\tHEAD";
|
|
64
|
+
responses[overlayRevParse] = "3333";
|
|
65
|
+
responses[overlayLsRemote] = "3333\tHEAD";
|
|
66
|
+
const v = await getServerVersion();
|
|
67
|
+
expect(v.core.current).toBeNull();
|
|
68
|
+
expect(v.core.behind).toBe(false); // unknown current → not behind
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
//# sourceMappingURL=version.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.test.js","sourceRoot":"","sources":["../../src/admin/version.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export interface CliConfig {
|
|
2
|
+
/** Base URL of the Last Light instance, e.g. https://ll.example.com */
|
|
3
|
+
url: string;
|
|
4
|
+
/** Bearer token minted by the instance (7-day TTL). */
|
|
5
|
+
token: string;
|
|
6
|
+
/** ISO timestamp the token was saved — informational. */
|
|
7
|
+
savedAt: string;
|
|
8
|
+
/**
|
|
9
|
+
* Working directory for the host-local `lastlight server` lifecycle commands
|
|
10
|
+
* (start/stop/restart/update). A full git checkout of the lastlight repo plus
|
|
11
|
+
* the `instance/` overlay + the `docker-compose.override.yml` symlink — the
|
|
12
|
+
* docker build context. Written by `lastlight server setup`. Distinct from
|
|
13
|
+
* `url`/`token`, which target a *remote* instance over HTTP.
|
|
14
|
+
*/
|
|
15
|
+
serverHome?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare const DEFAULT_URL = "http://localhost:8644";
|
|
18
|
+
/** Default working directory for `lastlight server` when nothing else is set. */
|
|
19
|
+
export declare function defaultServerHome(): string;
|
|
20
|
+
/** `~/.lastlight` — the CLI config directory. */
|
|
21
|
+
export declare function configDir(): string;
|
|
22
|
+
/** `~/.lastlight/config.json` — the saved-credentials file. */
|
|
23
|
+
export declare function configPath(): string;
|
|
24
|
+
/** Load the saved credentials, or null if none / unreadable. */
|
|
25
|
+
export declare function loadConfig(): CliConfig | null;
|
|
26
|
+
/**
|
|
27
|
+
* Persist `{ url, token }` (stamping `savedAt`), preserving any other fields
|
|
28
|
+
* (e.g. `serverHome`) already in the file.
|
|
29
|
+
*/
|
|
30
|
+
export declare function saveConfig(cfg: {
|
|
31
|
+
url: string;
|
|
32
|
+
token: string;
|
|
33
|
+
}): CliConfig;
|
|
34
|
+
/** Persist the `serverHome` working directory, preserving credentials. */
|
|
35
|
+
export declare function saveServerHome(home: string): void;
|
|
36
|
+
/**
|
|
37
|
+
* Resolve the working directory for `lastlight server` lifecycle commands.
|
|
38
|
+
* Precedence: explicit override (`--home`) → `LASTLIGHT_HOME` env → saved
|
|
39
|
+
* `serverHome` → built-in default (`~/lastlight`).
|
|
40
|
+
*/
|
|
41
|
+
export declare function resolveServerHome(override?: string): string;
|
|
42
|
+
/** Remove the saved config (logout). No-op if it doesn't exist. */
|
|
43
|
+
export declare function clearConfig(): void;
|
|
44
|
+
/**
|
|
45
|
+
* Resolve the effective instance URL + token the CLI should use for a command.
|
|
46
|
+
* Precedence: explicit override (`--url`/`--token`) → env → saved file →
|
|
47
|
+
* built-in default URL (with no token).
|
|
48
|
+
*/
|
|
49
|
+
export declare function resolveTarget(override?: {
|
|
50
|
+
url?: string;
|
|
51
|
+
token?: string;
|
|
52
|
+
}): {
|
|
53
|
+
url: string;
|
|
54
|
+
token: string;
|
|
55
|
+
};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persisted CLI config — `~/.lastlight/config.json`.
|
|
3
|
+
*
|
|
4
|
+
* Stores the instance URL and bearer token that `lastlight login` obtains, so
|
|
5
|
+
* every subsequent command runs against the same remote instance without
|
|
6
|
+
* re-authenticating. The file holds a credential, so it is written mode 0600
|
|
7
|
+
* inside a 0700 directory.
|
|
8
|
+
*
|
|
9
|
+
* Env vars (`LASTLIGHT_URL` / `LASTLIGHT_TOKEN`) always take precedence over
|
|
10
|
+
* the file — see `resolveTarget()` — so CI/scripts can override without
|
|
11
|
+
* touching disk.
|
|
12
|
+
*/
|
|
13
|
+
import fs from "node:fs";
|
|
14
|
+
import os from "node:os";
|
|
15
|
+
import path from "node:path";
|
|
16
|
+
export const DEFAULT_URL = "http://localhost:8644";
|
|
17
|
+
/** Default working directory for `lastlight server` when nothing else is set. */
|
|
18
|
+
export function defaultServerHome() {
|
|
19
|
+
return path.join(os.homedir(), "lastlight");
|
|
20
|
+
}
|
|
21
|
+
/** `~/.lastlight` — the CLI config directory. */
|
|
22
|
+
export function configDir() {
|
|
23
|
+
return path.join(os.homedir(), ".lastlight");
|
|
24
|
+
}
|
|
25
|
+
/** `~/.lastlight/config.json` — the saved-credentials file. */
|
|
26
|
+
export function configPath() {
|
|
27
|
+
return path.join(configDir(), "config.json");
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Read the raw config object (any subset of fields), or null if none /
|
|
31
|
+
* unreadable. Unlike `loadConfig`, this does not require `url`/`token` — it is
|
|
32
|
+
* used when the only persisted field might be `serverHome`.
|
|
33
|
+
*/
|
|
34
|
+
function readRaw() {
|
|
35
|
+
try {
|
|
36
|
+
return JSON.parse(fs.readFileSync(configPath(), "utf8"));
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** Load the saved credentials, or null if none / unreadable. */
|
|
43
|
+
export function loadConfig() {
|
|
44
|
+
const parsed = readRaw();
|
|
45
|
+
if (parsed && typeof parsed.url === "string" && typeof parsed.token === "string") {
|
|
46
|
+
return {
|
|
47
|
+
url: parsed.url,
|
|
48
|
+
token: parsed.token,
|
|
49
|
+
savedAt: parsed.savedAt ?? "",
|
|
50
|
+
serverHome: typeof parsed.serverHome === "string" ? parsed.serverHome : undefined,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
/** Merge `patch` into the on-disk config and persist it (mode 0600 / dir 0700). */
|
|
56
|
+
function writeMerged(patch) {
|
|
57
|
+
const dir = configDir();
|
|
58
|
+
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
59
|
+
const merged = { ...(readRaw() ?? {}), ...patch };
|
|
60
|
+
fs.writeFileSync(configPath(), JSON.stringify(merged, null, 2) + "\n", { mode: 0o600 });
|
|
61
|
+
// mkdir/writeFile honour `mode` only on creation; enforce on existing files too.
|
|
62
|
+
try {
|
|
63
|
+
fs.chmodSync(configPath(), 0o600);
|
|
64
|
+
fs.chmodSync(dir, 0o700);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
/* best-effort — non-POSIX filesystems may reject chmod */
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Persist `{ url, token }` (stamping `savedAt`), preserving any other fields
|
|
72
|
+
* (e.g. `serverHome`) already in the file.
|
|
73
|
+
*/
|
|
74
|
+
export function saveConfig(cfg) {
|
|
75
|
+
writeMerged({ url: cfg.url, token: cfg.token, savedAt: new Date().toISOString() });
|
|
76
|
+
return loadConfig();
|
|
77
|
+
}
|
|
78
|
+
/** Persist the `serverHome` working directory, preserving credentials. */
|
|
79
|
+
export function saveServerHome(home) {
|
|
80
|
+
writeMerged({ serverHome: home });
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Resolve the working directory for `lastlight server` lifecycle commands.
|
|
84
|
+
* Precedence: explicit override (`--home`) → `LASTLIGHT_HOME` env → saved
|
|
85
|
+
* `serverHome` → built-in default (`~/lastlight`).
|
|
86
|
+
*/
|
|
87
|
+
export function resolveServerHome(override) {
|
|
88
|
+
return (override ||
|
|
89
|
+
process.env.LASTLIGHT_HOME ||
|
|
90
|
+
readRaw()?.serverHome ||
|
|
91
|
+
defaultServerHome());
|
|
92
|
+
}
|
|
93
|
+
/** Remove the saved config (logout). No-op if it doesn't exist. */
|
|
94
|
+
export function clearConfig() {
|
|
95
|
+
try {
|
|
96
|
+
fs.rmSync(configPath());
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
/* already gone */
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Resolve the effective instance URL + token the CLI should use for a command.
|
|
104
|
+
* Precedence: explicit override (`--url`/`--token`) → env → saved file →
|
|
105
|
+
* built-in default URL (with no token).
|
|
106
|
+
*/
|
|
107
|
+
export function resolveTarget(override) {
|
|
108
|
+
const saved = loadConfig();
|
|
109
|
+
const url = override?.url ||
|
|
110
|
+
process.env.LASTLIGHT_URL ||
|
|
111
|
+
saved?.url ||
|
|
112
|
+
DEFAULT_URL;
|
|
113
|
+
const token = override?.token ||
|
|
114
|
+
process.env.LASTLIGHT_TOKEN ||
|
|
115
|
+
saved?.token ||
|
|
116
|
+
"";
|
|
117
|
+
return { url: url.replace(/\/+$/, ""), token };
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=cli-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-config.js","sourceRoot":"","sources":["../src/cli-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { loadConfig, saveConfig, clearConfig, resolveTarget, saveServerHome, resolveServerHome, defaultServerHome, configPath, DEFAULT_URL, } from "./cli-config.js";
|
|
6
|
+
let tmpHome;
|
|
7
|
+
let origHome;
|
|
8
|
+
let origUrl;
|
|
9
|
+
let origToken;
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), "ll-cli-"));
|
|
12
|
+
origHome = process.env.HOME;
|
|
13
|
+
origUrl = process.env.LASTLIGHT_URL;
|
|
14
|
+
origToken = process.env.LASTLIGHT_TOKEN;
|
|
15
|
+
process.env.HOME = tmpHome;
|
|
16
|
+
delete process.env.LASTLIGHT_URL;
|
|
17
|
+
delete process.env.LASTLIGHT_TOKEN;
|
|
18
|
+
});
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
if (origHome === undefined)
|
|
21
|
+
delete process.env.HOME;
|
|
22
|
+
else
|
|
23
|
+
process.env.HOME = origHome;
|
|
24
|
+
if (origUrl === undefined)
|
|
25
|
+
delete process.env.LASTLIGHT_URL;
|
|
26
|
+
else
|
|
27
|
+
process.env.LASTLIGHT_URL = origUrl;
|
|
28
|
+
if (origToken === undefined)
|
|
29
|
+
delete process.env.LASTLIGHT_TOKEN;
|
|
30
|
+
else
|
|
31
|
+
process.env.LASTLIGHT_TOKEN = origToken;
|
|
32
|
+
fs.rmSync(tmpHome, { recursive: true, force: true });
|
|
33
|
+
});
|
|
34
|
+
describe("cli-config", () => {
|
|
35
|
+
it("round-trips save → load", () => {
|
|
36
|
+
expect(loadConfig()).toBeNull();
|
|
37
|
+
saveConfig({ url: "https://ll.example.com", token: "tok-123" });
|
|
38
|
+
const cfg = loadConfig();
|
|
39
|
+
expect(cfg?.url).toBe("https://ll.example.com");
|
|
40
|
+
expect(cfg?.token).toBe("tok-123");
|
|
41
|
+
expect(cfg?.savedAt).toBeTruthy();
|
|
42
|
+
});
|
|
43
|
+
it("writes the config file mode 0600", () => {
|
|
44
|
+
saveConfig({ url: "https://x", token: "t" });
|
|
45
|
+
const mode = fs.statSync(configPath()).mode & 0o777;
|
|
46
|
+
expect(mode).toBe(0o600);
|
|
47
|
+
});
|
|
48
|
+
it("clearConfig removes the file", () => {
|
|
49
|
+
saveConfig({ url: "https://x", token: "t" });
|
|
50
|
+
clearConfig();
|
|
51
|
+
expect(loadConfig()).toBeNull();
|
|
52
|
+
expect(() => clearConfig()).not.toThrow(); // idempotent
|
|
53
|
+
});
|
|
54
|
+
it("env vars override the saved file", () => {
|
|
55
|
+
saveConfig({ url: "https://saved", token: "saved-tok" });
|
|
56
|
+
process.env.LASTLIGHT_URL = "https://env";
|
|
57
|
+
process.env.LASTLIGHT_TOKEN = "env-tok";
|
|
58
|
+
const t = resolveTarget();
|
|
59
|
+
expect(t.url).toBe("https://env");
|
|
60
|
+
expect(t.token).toBe("env-tok");
|
|
61
|
+
});
|
|
62
|
+
it("explicit override beats env and file", () => {
|
|
63
|
+
process.env.LASTLIGHT_URL = "https://env";
|
|
64
|
+
const t = resolveTarget({ url: "https://flag", token: "flag-tok" });
|
|
65
|
+
expect(t.url).toBe("https://flag");
|
|
66
|
+
expect(t.token).toBe("flag-tok");
|
|
67
|
+
});
|
|
68
|
+
it("saveServerHome persists without clobbering credentials", () => {
|
|
69
|
+
saveConfig({ url: "https://ll.example.com", token: "tok-123" });
|
|
70
|
+
saveServerHome("/home/lastlight/lastlight");
|
|
71
|
+
const cfg = loadConfig();
|
|
72
|
+
expect(cfg?.token).toBe("tok-123"); // creds preserved
|
|
73
|
+
expect(cfg?.serverHome).toBe("/home/lastlight/lastlight");
|
|
74
|
+
});
|
|
75
|
+
it("resolveServerHome: --home > LASTLIGHT_HOME > saved > default", () => {
|
|
76
|
+
expect(resolveServerHome()).toBe(defaultServerHome());
|
|
77
|
+
saveServerHome("/saved/home");
|
|
78
|
+
expect(resolveServerHome()).toBe("/saved/home");
|
|
79
|
+
process.env.LASTLIGHT_HOME = "/env/home";
|
|
80
|
+
expect(resolveServerHome()).toBe("/env/home");
|
|
81
|
+
expect(resolveServerHome("/flag/home")).toBe("/flag/home");
|
|
82
|
+
delete process.env.LASTLIGHT_HOME;
|
|
83
|
+
});
|
|
84
|
+
it("falls back to the default URL and trims trailing slashes", () => {
|
|
85
|
+
const t = resolveTarget();
|
|
86
|
+
expect(t.url).toBe(DEFAULT_URL);
|
|
87
|
+
expect(t.token).toBe("");
|
|
88
|
+
saveConfig({ url: "https://ll.example.com/", token: "t" });
|
|
89
|
+
expect(resolveTarget().url).toBe("https://ll.example.com");
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
//# sourceMappingURL=cli-config.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-config.test.js","sourceRoot":"","sources":["../src/cli-config.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Render an array of records as an aligned text table. */
|
|
2
|
+
export declare function table(rows: Array<Record<string, string>>, columns: Array<{
|
|
3
|
+
key: string;
|
|
4
|
+
header: string;
|
|
5
|
+
}>): string;
|
|
6
|
+
/** "3m ago" / "2h ago" / "5d ago" from an ISO timestamp or unix-seconds number. */
|
|
7
|
+
export declare function age(input: string | number | null | undefined): string;
|
|
8
|
+
/** Color a workflow-run / execution status string. */
|
|
9
|
+
export declare function colorStatus(status: string | null | undefined): string;
|
|
10
|
+
/** ✓ / ✗ for a boolean-ish success value. */
|
|
11
|
+
export declare function checkmark(success: boolean | undefined): string;
|
|
12
|
+
/**
|
|
13
|
+
* Follow a server-sent-events endpoint, invoking `onEvent` for each `data:`
|
|
14
|
+
* payload until the stream closes or the process is interrupted. Uses the
|
|
15
|
+
* global `fetch` ReadableStream — no EventSource polyfill or extra dependency.
|
|
16
|
+
* The token is passed as a `?token=` query param (the server's auth middleware
|
|
17
|
+
* accepts it there for SSE, which can't set headers).
|
|
18
|
+
*/
|
|
19
|
+
export declare function followSSE(url: string, token: string, onEvent: (data: string) => void): Promise<void>;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Presentation helpers for the `lastlight` CLI — plain tables, relative ages,
|
|
3
|
+
* status coloring, and a dependency-free SSE follower. All human formatting is
|
|
4
|
+
* skipped when the caller passes `--json` (the command prints raw JSON itself).
|
|
5
|
+
*/
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
/** Render an array of records as an aligned text table. */
|
|
8
|
+
export function table(rows, columns) {
|
|
9
|
+
if (rows.length === 0)
|
|
10
|
+
return chalk.dim("(none)");
|
|
11
|
+
const widths = columns.map((col) => Math.max(col.header.length, ...rows.map((r) => stripAnsi(r[col.key] ?? "").length)));
|
|
12
|
+
const pad = (s, w) => s + " ".repeat(Math.max(0, w - stripAnsi(s).length));
|
|
13
|
+
const headerLine = columns.map((c, i) => chalk.bold(pad(c.header, widths[i]))).join(" ");
|
|
14
|
+
const body = rows.map((r) => columns.map((c, i) => pad(r[c.key] ?? "", widths[i])).join(" "));
|
|
15
|
+
return [headerLine, ...body].join("\n");
|
|
16
|
+
}
|
|
17
|
+
const ANSI = /\[[0-9;]*m/g;
|
|
18
|
+
function stripAnsi(s) {
|
|
19
|
+
return s.replace(ANSI, "");
|
|
20
|
+
}
|
|
21
|
+
/** "3m ago" / "2h ago" / "5d ago" from an ISO timestamp or unix-seconds number. */
|
|
22
|
+
export function age(input) {
|
|
23
|
+
if (input === null || input === undefined || input === "")
|
|
24
|
+
return "";
|
|
25
|
+
const ms = typeof input === "number" ? input * 1000 : Date.parse(input);
|
|
26
|
+
if (Number.isNaN(ms))
|
|
27
|
+
return String(input);
|
|
28
|
+
const diff = Date.now() - ms;
|
|
29
|
+
const sec = Math.round(diff / 1000);
|
|
30
|
+
if (sec < 60)
|
|
31
|
+
return `${sec}s ago`;
|
|
32
|
+
const min = Math.round(sec / 60);
|
|
33
|
+
if (min < 60)
|
|
34
|
+
return `${min}m ago`;
|
|
35
|
+
const hr = Math.round(min / 60);
|
|
36
|
+
if (hr < 48)
|
|
37
|
+
return `${hr}h ago`;
|
|
38
|
+
return `${Math.round(hr / 24)}d ago`;
|
|
39
|
+
}
|
|
40
|
+
/** Color a workflow-run / execution status string. */
|
|
41
|
+
export function colorStatus(status) {
|
|
42
|
+
const s = (status ?? "").toLowerCase();
|
|
43
|
+
switch (s) {
|
|
44
|
+
case "succeeded":
|
|
45
|
+
case "success":
|
|
46
|
+
case "approved":
|
|
47
|
+
return chalk.green(status);
|
|
48
|
+
case "failed":
|
|
49
|
+
case "error":
|
|
50
|
+
case "rejected":
|
|
51
|
+
return chalk.red(status);
|
|
52
|
+
case "running":
|
|
53
|
+
case "paused":
|
|
54
|
+
case "pending":
|
|
55
|
+
return chalk.yellow(status);
|
|
56
|
+
case "cancelled":
|
|
57
|
+
return chalk.dim(status);
|
|
58
|
+
default:
|
|
59
|
+
return status ?? "";
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/** ✓ / ✗ for a boolean-ish success value. */
|
|
63
|
+
export function checkmark(success) {
|
|
64
|
+
if (success === undefined)
|
|
65
|
+
return chalk.yellow("…");
|
|
66
|
+
return success ? chalk.green("✓") : chalk.red("✗");
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Follow a server-sent-events endpoint, invoking `onEvent` for each `data:`
|
|
70
|
+
* payload until the stream closes or the process is interrupted. Uses the
|
|
71
|
+
* global `fetch` ReadableStream — no EventSource polyfill or extra dependency.
|
|
72
|
+
* The token is passed as a `?token=` query param (the server's auth middleware
|
|
73
|
+
* accepts it there for SSE, which can't set headers).
|
|
74
|
+
*/
|
|
75
|
+
export async function followSSE(url, token, onEvent) {
|
|
76
|
+
const u = new URL(url);
|
|
77
|
+
if (token)
|
|
78
|
+
u.searchParams.set("token", token);
|
|
79
|
+
const res = await fetch(u, { headers: { Accept: "text/event-stream" } });
|
|
80
|
+
if (!res.ok || !res.body) {
|
|
81
|
+
throw new Error(`stream failed: ${res.status} ${res.statusText}`);
|
|
82
|
+
}
|
|
83
|
+
const reader = res.body.getReader();
|
|
84
|
+
const decoder = new TextDecoder();
|
|
85
|
+
let buffer = "";
|
|
86
|
+
for (;;) {
|
|
87
|
+
const { done, value } = await reader.read();
|
|
88
|
+
if (done)
|
|
89
|
+
break;
|
|
90
|
+
buffer += decoder.decode(value, { stream: true });
|
|
91
|
+
// SSE frames are separated by a blank line; each frame may have multiple
|
|
92
|
+
// `data:` lines that concatenate into one payload.
|
|
93
|
+
let sep;
|
|
94
|
+
while ((sep = buffer.indexOf("\n\n")) !== -1) {
|
|
95
|
+
const frame = buffer.slice(0, sep);
|
|
96
|
+
buffer = buffer.slice(sep + 2);
|
|
97
|
+
const data = frame
|
|
98
|
+
.split("\n")
|
|
99
|
+
.filter((l) => l.startsWith("data:"))
|
|
100
|
+
.map((l) => l.slice(5).replace(/^ /, ""))
|
|
101
|
+
.join("\n");
|
|
102
|
+
if (data)
|
|
103
|
+
onEvent(data);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=cli-format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-format.js","sourceRoot":"","sources":["../src/cli-format.ts"],"names":[],"mappings":"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"}
|