lastlight 0.15.0 → 0.16.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 +71 -692
- package/dist/cli-config.js.map +1 -0
- package/dist/cli-format.js.map +1 -0
- package/dist/{cli/cli-server.d.ts → cli-server.d.ts} +26 -1
- package/dist/{cli/cli-server.js → cli-server.js} +40 -5
- package/dist/cli-server.js.map +1 -0
- package/dist/cli-timeline.js.map +1 -0
- package/dist/{cli/cli.js → cli.js} +4 -3
- package/dist/cli.js.map +1 -0
- package/dist/{cli/fork-cli.d.ts → fork-cli.d.ts} +3 -3
- package/dist/{cli/fork-cli.js → fork-cli.js} +28 -27
- package/dist/fork-cli.js.map +1 -0
- package/dist/{cli/oauth-cli.js → oauth-cli.js} +1 -1
- package/dist/oauth-cli.js.map +1 -0
- package/dist/{cli/setup.js → setup.js} +10 -4
- package/dist/setup.js.map +1 -0
- package/dist/{cli/skills-install.d.ts → skills-install.d.ts} +6 -0
- package/dist/{cli/skills-install.js → skills-install.js} +6 -2
- package/dist/skills-install.js.map +1 -0
- package/package.json +20 -65
- package/plugins/lastlight/.claude-plugin/plugin.json +1 -1
- package/agent-context/rules.md +0 -80
- package/agent-context/security.md +0 -69
- package/agent-context/soul.md +0 -21
- package/config/default.yaml +0 -119
- package/deploy/.env.production.example +0 -100
- package/deploy/entrypoint.sh +0 -82
- package/deploy/native/README.md +0 -160
- package/deploy/native/install.sh +0 -110
- package/deploy/native/lastlight.env.example +0 -95
- package/deploy/native/lastlight.service +0 -50
- package/deploy/sandbox-entrypoint.sh +0 -93
- package/dist/admin/auth.d.ts +0 -51
- package/dist/admin/auth.js +0 -121
- package/dist/admin/auth.js.map +0 -1
- package/dist/admin/chat-session-reader.d.ts +0 -39
- package/dist/admin/chat-session-reader.js +0 -84
- package/dist/admin/chat-session-reader.js.map +0 -1
- package/dist/admin/docker.d.ts +0 -61
- package/dist/admin/docker.js +0 -187
- package/dist/admin/docker.js.map +0 -1
- package/dist/admin/index.d.ts +0 -9
- package/dist/admin/index.js +0 -59
- package/dist/admin/index.js.map +0 -1
- package/dist/admin/routes.d.ts +0 -81
- package/dist/admin/routes.js +0 -1381
- package/dist/admin/routes.js.map +0 -1
- package/dist/admin/sessions.d.ts +0 -89
- package/dist/admin/sessions.js +0 -204
- package/dist/admin/sessions.js.map +0 -1
- package/dist/admin/tail.d.ts +0 -12
- package/dist/admin/tail.js +0 -145
- package/dist/admin/tail.js.map +0 -1
- package/dist/admin/version.d.ts +0 -22
- package/dist/admin/version.js +0 -92
- package/dist/admin/version.js.map +0 -1
- package/dist/cli/cli-config.js.map +0 -1
- package/dist/cli/cli-format.js.map +0 -1
- package/dist/cli/cli-server.js.map +0 -1
- package/dist/cli/cli-timeline.js.map +0 -1
- package/dist/cli/cli.js.map +0 -1
- package/dist/cli/fork-cli.js.map +0 -1
- package/dist/cli/oauth-cli.js.map +0 -1
- package/dist/cli/setup.js.map +0 -1
- package/dist/cli/skills-install.js.map +0 -1
- package/dist/config/config-resolve.d.ts +0 -28
- package/dist/config/config-resolve.js +0 -47
- package/dist/config/config-resolve.js.map +0 -1
- package/dist/config/config.d.ts +0 -157
- package/dist/config/config.js +0 -581
- package/dist/config/config.js.map +0 -1
- package/dist/config/core-pin.d.ts +0 -16
- package/dist/config/core-pin.js +0 -85
- package/dist/config/core-pin.js.map +0 -1
- package/dist/config/overlay-assets.d.ts +0 -20
- package/dist/config/overlay-assets.js +0 -114
- package/dist/config/overlay-assets.js.map +0 -1
- package/dist/config/overlay-bootstrap.d.ts +0 -44
- package/dist/config/overlay-bootstrap.js +0 -304
- package/dist/config/overlay-bootstrap.js.map +0 -1
- package/dist/connectors/github-webhook.d.ts +0 -45
- package/dist/connectors/github-webhook.js +0 -321
- package/dist/connectors/github-webhook.js.map +0 -1
- package/dist/connectors/index.d.ts +0 -18
- package/dist/connectors/index.js +0 -41
- package/dist/connectors/index.js.map +0 -1
- package/dist/connectors/messaging/base.d.ts +0 -42
- package/dist/connectors/messaging/base.js +0 -139
- package/dist/connectors/messaging/base.js.map +0 -1
- package/dist/connectors/messaging/delivery.d.ts +0 -14
- package/dist/connectors/messaging/delivery.js +0 -38
- package/dist/connectors/messaging/delivery.js.map +0 -1
- package/dist/connectors/messaging/index.d.ts +0 -4
- package/dist/connectors/messaging/index.js +0 -4
- package/dist/connectors/messaging/index.js.map +0 -1
- package/dist/connectors/messaging/session-manager.d.ts +0 -53
- package/dist/connectors/messaging/session-manager.js +0 -255
- package/dist/connectors/messaging/session-manager.js.map +0 -1
- package/dist/connectors/messaging/types.d.ts +0 -58
- package/dist/connectors/messaging/types.js +0 -7
- package/dist/connectors/messaging/types.js.map +0 -1
- package/dist/connectors/slack/connector.d.ts +0 -100
- package/dist/connectors/slack/connector.js +0 -341
- package/dist/connectors/slack/connector.js.map +0 -1
- package/dist/connectors/slack/index.d.ts +0 -2
- package/dist/connectors/slack/index.js +0 -3
- package/dist/connectors/slack/index.js.map +0 -1
- package/dist/connectors/slack/mrkdwn.d.ts +0 -8
- package/dist/connectors/slack/mrkdwn.js +0 -123
- package/dist/connectors/slack/mrkdwn.js.map +0 -1
- package/dist/connectors/types.d.ts +0 -61
- package/dist/connectors/types.js +0 -2
- package/dist/connectors/types.js.map +0 -1
- package/dist/cron/fanout.d.ts +0 -33
- package/dist/cron/fanout.js +0 -55
- package/dist/cron/fanout.js.map +0 -1
- package/dist/cron/jobs.d.ts +0 -18
- package/dist/cron/jobs.js +0 -37
- package/dist/cron/jobs.js.map +0 -1
- package/dist/cron/scheduler.d.ts +0 -45
- package/dist/cron/scheduler.js +0 -105
- package/dist/cron/scheduler.js.map +0 -1
- package/dist/engine/agent-executor.d.ts +0 -34
- package/dist/engine/agent-executor.js +0 -246
- package/dist/engine/agent-executor.js.map +0 -1
- package/dist/engine/chat/chat-runner.d.ts +0 -132
- package/dist/engine/chat/chat-runner.js +0 -424
- package/dist/engine/chat/chat-runner.js.map +0 -1
- package/dist/engine/chat/chat-skills.d.ts +0 -45
- package/dist/engine/chat/chat-skills.js +0 -184
- package/dist/engine/chat/chat-skills.js.map +0 -1
- package/dist/engine/chat/chat.d.ts +0 -54
- package/dist/engine/chat/chat.js +0 -316
- package/dist/engine/chat/chat.js.map +0 -1
- package/dist/engine/chat/message-batcher.d.ts +0 -32
- package/dist/engine/chat/message-batcher.js +0 -109
- package/dist/engine/chat/message-batcher.js.map +0 -1
- package/dist/engine/dispatcher.d.ts +0 -73
- package/dist/engine/dispatcher.js +0 -663
- package/dist/engine/dispatcher.js.map +0 -1
- package/dist/engine/event-shim.d.ts +0 -117
- package/dist/engine/event-shim.js +0 -435
- package/dist/engine/event-shim.js.map +0 -1
- package/dist/engine/executors/orchestrator.d.ts +0 -81
- package/dist/engine/executors/orchestrator.js +0 -365
- package/dist/engine/executors/orchestrator.js.map +0 -1
- package/dist/engine/executors/shared.d.ts +0 -189
- package/dist/engine/executors/shared.js +0 -616
- package/dist/engine/executors/shared.js.map +0 -1
- package/dist/engine/github/git-auth.d.ts +0 -62
- package/dist/engine/github/git-auth.js +0 -161
- package/dist/engine/github/git-auth.js.map +0 -1
- package/dist/engine/github/github-app-client.d.ts +0 -23
- package/dist/engine/github/github-app-client.js +0 -33
- package/dist/engine/github/github-app-client.js.map +0 -1
- package/dist/engine/github/github-tools.d.ts +0 -18
- package/dist/engine/github/github-tools.js +0 -263
- package/dist/engine/github/github-tools.js.map +0 -1
- package/dist/engine/github/github.d.ts +0 -1193
- package/dist/engine/github/github.js +0 -357
- package/dist/engine/github/github.js.map +0 -1
- package/dist/engine/github/profiles.d.ts +0 -279
- package/dist/engine/github/profiles.js +0 -42
- package/dist/engine/github/profiles.js.map +0 -1
- package/dist/engine/github/review-poster.d.ts +0 -98
- package/dist/engine/github/review-poster.js +0 -177
- package/dist/engine/github/review-poster.js.map +0 -1
- package/dist/engine/llm.d.ts +0 -79
- package/dist/engine/llm.js +0 -269
- package/dist/engine/llm.js.map +0 -1
- package/dist/engine/oauth.d.ts +0 -43
- package/dist/engine/oauth.js +0 -103
- package/dist/engine/oauth.js.map +0 -1
- package/dist/engine/router.d.ts +0 -29
- package/dist/engine/router.js +0 -680
- package/dist/engine/router.js.map +0 -1
- package/dist/engine/screen/classifier.d.ts +0 -93
- package/dist/engine/screen/classifier.js +0 -215
- package/dist/engine/screen/classifier.js.map +0 -1
- package/dist/engine/screen/screen.d.ts +0 -41
- package/dist/engine/screen/screen.js +0 -93
- package/dist/engine/screen/screen.js.map +0 -1
- package/dist/evals-api.d.ts +0 -24
- package/dist/evals-api.js +0 -22
- package/dist/evals-api.js.map +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -923
- package/dist/index.js.map +0 -1
- package/dist/managed-repos.d.ts +0 -30
- package/dist/managed-repos.js +0 -72
- package/dist/managed-repos.js.map +0 -1
- package/dist/notify/index.d.ts +0 -15
- package/dist/notify/index.js +0 -6
- package/dist/notify/index.js.map +0 -1
- package/dist/notify/model.d.ts +0 -57
- package/dist/notify/model.js +0 -89
- package/dist/notify/model.js.map +0 -1
- package/dist/notify/notifier.d.ts +0 -17
- package/dist/notify/notifier.js +0 -87
- package/dist/notify/notifier.js.map +0 -1
- package/dist/notify/render.d.ts +0 -21
- package/dist/notify/render.js +0 -59
- package/dist/notify/render.js.map +0 -1
- package/dist/notify/transports/github.d.ts +0 -26
- package/dist/notify/transports/github.js +0 -26
- package/dist/notify/transports/github.js.map +0 -1
- package/dist/notify/transports/slack.d.ts +0 -26
- package/dist/notify/transports/slack.js +0 -28
- package/dist/notify/transports/slack.js.map +0 -1
- package/dist/notify/types.d.ts +0 -95
- package/dist/notify/types.js +0 -16
- package/dist/notify/types.js.map +0 -1
- package/dist/providers.d.ts +0 -125
- package/dist/providers.js +0 -279
- package/dist/providers.js.map +0 -1
- package/dist/sandbox/docker.d.ts +0 -180
- package/dist/sandbox/docker.js +0 -517
- package/dist/sandbox/docker.js.map +0 -1
- package/dist/sandbox/egress-allowlist.d.ts +0 -74
- package/dist/sandbox/egress-allowlist.js +0 -164
- package/dist/sandbox/egress-allowlist.js.map +0 -1
- package/dist/sandbox/egress-firewall-config.d.ts +0 -127
- package/dist/sandbox/egress-firewall-config.js +0 -434
- package/dist/sandbox/egress-firewall-config.js.map +0 -1
- package/dist/sandbox/images.d.ts +0 -23
- package/dist/sandbox/images.js +0 -55
- package/dist/sandbox/images.js.map +0 -1
- package/dist/sandbox/index.d.ts +0 -112
- package/dist/sandbox/index.js +0 -332
- package/dist/sandbox/index.js.map +0 -1
- package/dist/sandbox/sandbox.d.ts +0 -214
- package/dist/sandbox/sandbox.js +0 -453
- package/dist/sandbox/sandbox.js.map +0 -1
- package/dist/sandbox/smol.d.ts +0 -162
- package/dist/sandbox/smol.js +0 -485
- package/dist/sandbox/smol.js.map +0 -1
- package/dist/session-log.d.ts +0 -63
- package/dist/session-log.js +0 -290
- package/dist/session-log.js.map +0 -1
- package/dist/state/approval-store.d.ts +0 -88
- package/dist/state/approval-store.js +0 -149
- package/dist/state/approval-store.js.map +0 -1
- package/dist/state/build-assets.d.ts +0 -50
- package/dist/state/build-assets.js +0 -154
- package/dist/state/build-assets.js.map +0 -1
- package/dist/state/db.d.ts +0 -81
- package/dist/state/db.js +0 -155
- package/dist/state/db.js.map +0 -1
- package/dist/state/execution-store.d.ts +0 -257
- package/dist/state/execution-store.js +0 -527
- package/dist/state/execution-store.js.map +0 -1
- package/dist/state/migrate.d.ts +0 -15
- package/dist/state/migrate.js +0 -175
- package/dist/state/migrate.js.map +0 -1
- package/dist/state/workflow-run-store.d.ts +0 -216
- package/dist/state/workflow-run-store.js +0 -403
- package/dist/state/workflow-run-store.js.map +0 -1
- package/dist/telemetry/index.d.ts +0 -38
- package/dist/telemetry/index.js +0 -253
- package/dist/telemetry/index.js.map +0 -1
- package/dist/telemetry/pi-events.d.ts +0 -12
- package/dist/telemetry/pi-events.js +0 -134
- package/dist/telemetry/pi-events.js.map +0 -1
- package/dist/workflows/dag.d.ts +0 -37
- package/dist/workflows/dag.js +0 -118
- package/dist/workflows/dag.js.map +0 -1
- package/dist/workflows/loader.d.ts +0 -53
- package/dist/workflows/loader.js +0 -421
- package/dist/workflows/loader.js.map +0 -1
- package/dist/workflows/loop-eval.d.ts +0 -28
- package/dist/workflows/loop-eval.js +0 -74
- package/dist/workflows/loop-eval.js.map +0 -1
- package/dist/workflows/phase-executor.d.ts +0 -215
- package/dist/workflows/phase-executor.js +0 -1144
- package/dist/workflows/phase-executor.js.map +0 -1
- package/dist/workflows/phase-ref.d.ts +0 -50
- package/dist/workflows/phase-ref.js +0 -91
- package/dist/workflows/phase-ref.js.map +0 -1
- package/dist/workflows/resume.d.ts +0 -58
- package/dist/workflows/resume.js +0 -313
- package/dist/workflows/resume.js.map +0 -1
- package/dist/workflows/runner.d.ts +0 -63
- package/dist/workflows/runner.js +0 -364
- package/dist/workflows/runner.js.map +0 -1
- package/dist/workflows/schema.d.ts +0 -344
- package/dist/workflows/schema.js +0 -460
- package/dist/workflows/schema.js.map +0 -1
- package/dist/workflows/simple.d.ts +0 -90
- package/dist/workflows/simple.js +0 -393
- package/dist/workflows/simple.js.map +0 -1
- package/dist/workflows/target-policy.d.ts +0 -74
- package/dist/workflows/target-policy.js +0 -80
- package/dist/workflows/target-policy.js.map +0 -1
- package/dist/workflows/templates.d.ts +0 -88
- package/dist/workflows/templates.js +0 -127
- package/dist/workflows/templates.js.map +0 -1
- package/dist/workflows/triggers.d.ts +0 -21
- package/dist/workflows/triggers.js +0 -45
- package/dist/workflows/triggers.js.map +0 -1
- package/dist/workflows/verdict.d.ts +0 -19
- package/dist/workflows/verdict.js +0 -30
- package/dist/workflows/verdict.js.map +0 -1
- package/dist/worktree/manager.d.ts +0 -43
- package/dist/worktree/manager.js +0 -127
- package/dist/worktree/manager.js.map +0 -1
- package/docker-compose.yml +0 -274
- package/sandbox.Dockerfile +0 -68
- package/skills/README.md +0 -42
- package/skills/browser-qa/SKILL.md +0 -208
- package/skills/browser-qa/scripts/agent-browser.mjs +0 -531
- package/skills/building/SKILL.md +0 -95
- package/skills/chat/SKILL.md +0 -36
- package/skills/code-review/SKILL.md +0 -82
- package/skills/debug-production/SKILL.md +0 -108
- package/skills/demo/SKILL.md +0 -228
- package/skills/demo/scripts/compose-demo.sh +0 -243
- package/skills/issue-answer/SKILL.md +0 -91
- package/skills/issue-comment/SKILL.md +0 -49
- package/skills/issue-triage/SKILL.md +0 -149
- package/skills/issue-triage/references/AGENT-BRIEF.md +0 -65
- package/skills/pr-comment/SKILL.md +0 -64
- package/skills/pr-review/SKILL.md +0 -148
- package/skills/pr-review/references/findings-schema.md +0 -89
- package/skills/qa-test/SKILL.md +0 -97
- package/skills/repo-health/SKILL.md +0 -67
- package/skills/security-feedback/SKILL.md +0 -173
- package/skills/security-feedback/references/templates.md +0 -77
- package/skills/security-review/SKILL.md +0 -215
- package/skills/security-review/references/issue-format.md +0 -302
- package/skills/verify/SKILL.md +0 -118
- package/workflows/answer.yaml +0 -44
- package/workflows/build.yaml +0 -129
- package/workflows/cron-health.yaml +0 -6
- package/workflows/cron-review.yaml +0 -8
- package/workflows/cron-security.yaml +0 -6
- package/workflows/cron-triage.yaml +0 -8
- package/workflows/demo.yaml +0 -62
- package/workflows/examples/bash-smoke.yaml +0 -41
- package/workflows/examples/parallel-review.yaml +0 -36
- package/workflows/examples/tdd-loop.yaml +0 -17
- package/workflows/explore.yaml +0 -80
- package/workflows/issue-comment.yaml +0 -15
- package/workflows/issue-triage.yaml +0 -22
- package/workflows/pr-comment.yaml +0 -16
- package/workflows/pr-fix.yaml +0 -17
- package/workflows/pr-review.yaml +0 -50
- package/workflows/prompts/answer.md +0 -68
- package/workflows/prompts/architect.md +0 -44
- package/workflows/prompts/classifier.md +0 -60
- package/workflows/prompts/classify-adds-info.md +0 -17
- package/workflows/prompts/demo.md +0 -125
- package/workflows/prompts/executor.md +0 -42
- package/workflows/prompts/explore-ask.md +0 -99
- package/workflows/prompts/explore-publish.md +0 -31
- package/workflows/prompts/explore-read.md +0 -120
- package/workflows/prompts/explore-synthesize.md +0 -88
- package/workflows/prompts/fix.md +0 -18
- package/workflows/prompts/guardrails.md +0 -96
- package/workflows/prompts/pr-fix.md +0 -26
- package/workflows/prompts/pr.md +0 -39
- package/workflows/prompts/qa-browser.md +0 -95
- package/workflows/prompts/qa-synth.md +0 -44
- package/workflows/prompts/qa-test.md +0 -60
- package/workflows/prompts/re-reviewer.md +0 -33
- package/workflows/prompts/reviewer.md +0 -60
- package/workflows/prompts/verify-browser.md +0 -93
- package/workflows/prompts/verify-synth.md +0 -44
- package/workflows/prompts/verify.md +0 -63
- package/workflows/qa-test.yaml +0 -94
- package/workflows/repo-health.yaml +0 -15
- package/workflows/security-feedback.yaml +0 -25
- package/workflows/security-review.yaml +0 -37
- package/workflows/verify.yaml +0 -93
- /package/dist/{cli/cli-config.d.ts → cli-config.d.ts} +0 -0
- /package/dist/{cli/cli-config.js → cli-config.js} +0 -0
- /package/dist/{cli/cli-format.d.ts → cli-format.d.ts} +0 -0
- /package/dist/{cli/cli-format.js → cli-format.js} +0 -0
- /package/dist/{cli/cli-timeline.d.ts → cli-timeline.d.ts} +0 -0
- /package/dist/{cli/cli-timeline.js → cli-timeline.js} +0 -0
- /package/dist/{cli/cli.d.ts → cli.d.ts} +0 -0
- /package/dist/{cli/oauth-cli.d.ts → oauth-cli.d.ts} +0 -0
- /package/dist/{cli/setup.d.ts → setup.d.ts} +0 -0
package/deploy/entrypoint.sh
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# Last Light Docker entrypoint
|
|
3
|
-
# Links secrets, ensures state dirs, then starts the harness.
|
|
4
|
-
set -euo pipefail
|
|
5
|
-
|
|
6
|
-
# Secrets live in the consolidated deployment folder (instance/secrets). Fall
|
|
7
|
-
# back to the legacy standalone secrets/ mount for pre-migration deployments.
|
|
8
|
-
SECRETS="/app/instance/secrets"
|
|
9
|
-
[ -d "$SECRETS" ] || SECRETS="/app/secrets"
|
|
10
|
-
APP_DIR="/app"
|
|
11
|
-
STATE_DIR="${STATE_DIR:-/app/data}"
|
|
12
|
-
|
|
13
|
-
# Materialize secrets into the writable /app layer, owned by `lastlight` (mode
|
|
14
|
-
# 600). We COPY rather than symlink: the source lives on a read-only mount owned
|
|
15
|
-
# by whatever uid created it on the host (often 1000), while the harness runs as
|
|
16
|
-
# `lastlight` (uid-pinned 10001) via gosu below. A symlink would leave the
|
|
17
|
-
# unreadable 600 source in place and the harness would EACCES on it. root (this
|
|
18
|
-
# entrypoint, pre-gosu) bypasses the source perms to read+copy; the chown then
|
|
19
|
-
# hands the copy to lastlight. Same pattern as the PEM→state-volume copy below.
|
|
20
|
-
# rm -f first so a stale symlink from an older image isn't written through.
|
|
21
|
-
for f in .env; do
|
|
22
|
-
if [ -f "$SECRETS/$f" ]; then
|
|
23
|
-
rm -f "$APP_DIR/$f"
|
|
24
|
-
cp "$SECRETS/$f" "$APP_DIR/$f"
|
|
25
|
-
chown lastlight:lastlight "$APP_DIR/$f"
|
|
26
|
-
chmod 600 "$APP_DIR/$f"
|
|
27
|
-
echo "Copied $f from secrets volume"
|
|
28
|
-
fi
|
|
29
|
-
done
|
|
30
|
-
|
|
31
|
-
# GitHub App private key(s) — same copy+chown so the in-process Octokit (which
|
|
32
|
-
# also runs as lastlight) can read them.
|
|
33
|
-
for pem in "$SECRETS"/*.pem; do
|
|
34
|
-
if [ -f "$pem" ]; then
|
|
35
|
-
dest="$APP_DIR/$(basename "$pem")"
|
|
36
|
-
rm -f "$dest"
|
|
37
|
-
cp "$pem" "$dest"
|
|
38
|
-
chown lastlight:lastlight "$dest"
|
|
39
|
-
chmod 600 "$dest"
|
|
40
|
-
echo "Copied $(basename "$pem") from secrets volume"
|
|
41
|
-
fi
|
|
42
|
-
done
|
|
43
|
-
|
|
44
|
-
# Ensure state directory structure exists and is owned by lastlight.
|
|
45
|
-
# agent-sessions/ is where agentic-pi's event shim writes JSONL envelopes
|
|
46
|
-
# the dashboard reads (path is set by LASTLIGHT_SESSIONS_DIR).
|
|
47
|
-
mkdir -p "$STATE_DIR"/{logs,sandboxes,secrets,agent-sessions}
|
|
48
|
-
chown -R lastlight:lastlight "$STATE_DIR"
|
|
49
|
-
|
|
50
|
-
# Copy PEM to the data volume so sandbox containers can access it via shared
|
|
51
|
-
# volume (LASTLIGHT_SANDBOX=docker fallback path only — gondolin doesn't go
|
|
52
|
-
# through this). Owner is `lastlight` so the host harness (which exec's via
|
|
53
|
-
# gosu lastlight below) can read it for in-process GitHub API calls.
|
|
54
|
-
# Sandbox-entrypoint runs as root before switching to `agent`, so it can
|
|
55
|
-
# still read this 600 file and materialize an agent-readable copy when
|
|
56
|
-
# ALLOW_APP_PEM=1.
|
|
57
|
-
for pem in "$SECRETS"/*.pem; do
|
|
58
|
-
if [ -f "$pem" ]; then
|
|
59
|
-
cp "$pem" "$STATE_DIR/secrets/app.pem"
|
|
60
|
-
chown lastlight:lastlight "$STATE_DIR/secrets/app.pem"
|
|
61
|
-
chmod 600 "$STATE_DIR/secrets/app.pem"
|
|
62
|
-
echo "Copied PEM to data volume for sandbox access"
|
|
63
|
-
break
|
|
64
|
-
fi
|
|
65
|
-
done
|
|
66
|
-
|
|
67
|
-
# Source .env if available
|
|
68
|
-
if [ -f "$APP_DIR/.env" ]; then
|
|
69
|
-
set -a
|
|
70
|
-
# shellcheck disable=SC1091
|
|
71
|
-
source "$APP_DIR/.env"
|
|
72
|
-
set +a
|
|
73
|
-
fi
|
|
74
|
-
|
|
75
|
-
# Fix Docker socket permissions — host GID may differ from container docker group
|
|
76
|
-
if [ -S /var/run/docker.sock ]; then
|
|
77
|
-
chmod 666 /var/run/docker.sock
|
|
78
|
-
fi
|
|
79
|
-
|
|
80
|
-
echo "Starting Last Light (state: $STATE_DIR)..."
|
|
81
|
-
# Drop to non-root before exec'ing the harness.
|
|
82
|
-
exec gosu lastlight "$@"
|
package/deploy/native/README.md
DELETED
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
# Native deploy (systemd + gondolin)
|
|
2
|
-
|
|
3
|
-
Production deploy for `lastlight` as a systemd service on a KVM-capable
|
|
4
|
-
Linux host. Replaces the Docker compose deploy; the Dockerfiles in the
|
|
5
|
-
repo root are kept only for local prod-like smoke testing.
|
|
6
|
-
|
|
7
|
-
## Why native
|
|
8
|
-
|
|
9
|
-
`agentic-pi`'s gondolin sandbox needs `/dev/kvm`. Running lastlight inside
|
|
10
|
-
a container loses or complicates KVM access (Docker-in-Docker, nested
|
|
11
|
-
virt, capability juggling). On a bare-metal Linux box you get
|
|
12
|
-
near-native VM performance with no extra moving parts.
|
|
13
|
-
|
|
14
|
-
See `agentic-pi/SPIKE-gondolin.md` for the full analysis.
|
|
15
|
-
|
|
16
|
-
## First-time install
|
|
17
|
-
|
|
18
|
-
On the prod host as root:
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
# 1. Clone the repo to the canonical path.
|
|
22
|
-
git clone https://github.com/nearform/lastlight.git /opt/lastlight
|
|
23
|
-
cd /opt/lastlight
|
|
24
|
-
|
|
25
|
-
# 2. (Optional) Drop the GitHub App PEM in place before the install runs,
|
|
26
|
-
# so install.sh locks it down. Otherwise place it later and re-run.
|
|
27
|
-
install -m 0600 -o root /path/to/your-app.pem /etc/lastlight/app.pem
|
|
28
|
-
|
|
29
|
-
# 3. Provision system + install systemd unit.
|
|
30
|
-
sudo bash deploy/native/install.sh
|
|
31
|
-
|
|
32
|
-
# 4. install.sh scaffolds /etc/lastlight/lastlight.env from the example
|
|
33
|
-
# and refuses to (re)start the service while any CHANGE_ME placeholder
|
|
34
|
-
# remains. Edit it:
|
|
35
|
-
sudo $EDITOR /etc/lastlight/lastlight.env
|
|
36
|
-
|
|
37
|
-
# 5. Re-run install.sh to start the service.
|
|
38
|
-
sudo bash deploy/native/install.sh
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
## Re-deploying a code change
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
cd /opt/lastlight
|
|
45
|
-
sudo -u lastlight git pull
|
|
46
|
-
sudo bash deploy/native/install.sh # rebuilds + restarts the service
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
The existing `/home/lastlight/deploy.sh` on the prod host should be
|
|
50
|
-
replaced with the two lines above (or wrap them in a script).
|
|
51
|
-
|
|
52
|
-
## What's where
|
|
53
|
-
|
|
54
|
-
| Path | Purpose |
|
|
55
|
-
| --- | --- |
|
|
56
|
-
| `/opt/lastlight` | Source checkout. `node dist/index.js` runs from here. |
|
|
57
|
-
| `/etc/lastlight/lastlight.env` | systemd EnvironmentFile (mode 0640). Holds all secrets. |
|
|
58
|
-
| `/etc/lastlight/app.pem` | GitHub App private key (mode 0640). Optional but typical. |
|
|
59
|
-
| `/var/lib/lastlight/` | Persistent state — SQLite DB, session JSONLs, gondolin image cache. |
|
|
60
|
-
| `/var/lib/lastlight/lastlight.db` | Workflow runs, executions, messaging sessions. |
|
|
61
|
-
| `/var/lib/lastlight/agent-sessions/` | Dashboard's JSONL envelope store. |
|
|
62
|
-
| `/var/lib/lastlight/.cache/agentic-pi/images/` | Downloaded gondolin guest images (~89 MB each). |
|
|
63
|
-
| `/var/log/lastlight/` | LogsDirectory if anything writes to it. |
|
|
64
|
-
| `/etc/systemd/system/lastlight.service` | The unit file (installed by install.sh from `deploy/native/lastlight.service`). |
|
|
65
|
-
|
|
66
|
-
## Operations
|
|
67
|
-
|
|
68
|
-
```bash
|
|
69
|
-
# Status / logs
|
|
70
|
-
systemctl status lastlight
|
|
71
|
-
journalctl -u lastlight -f # live tail
|
|
72
|
-
journalctl -u lastlight --since '10 min ago' # recent
|
|
73
|
-
|
|
74
|
-
# Restart (e.g. after an env edit that doesn't need a rebuild)
|
|
75
|
-
sudo systemctl restart lastlight
|
|
76
|
-
|
|
77
|
-
# Stop / disable
|
|
78
|
-
sudo systemctl stop lastlight
|
|
79
|
-
sudo systemctl disable lastlight
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
## TLS / reverse proxy
|
|
83
|
-
|
|
84
|
-
The harness binds `127.0.0.1:8644` by default (PORT in the env file).
|
|
85
|
-
Front it with Caddy or nginx for TLS.
|
|
86
|
-
|
|
87
|
-
Minimal Caddy setup:
|
|
88
|
-
|
|
89
|
-
```bash
|
|
90
|
-
sudo apt-get install -y caddy
|
|
91
|
-
sudo tee /etc/caddy/Caddyfile <<'EOF'
|
|
92
|
-
your-domain.example.com {
|
|
93
|
-
reverse_proxy 127.0.0.1:8644
|
|
94
|
-
}
|
|
95
|
-
EOF
|
|
96
|
-
sudo systemctl reload caddy
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
## Migrating from the Docker compose deploy
|
|
100
|
-
|
|
101
|
-
On the old (Docker compose) box:
|
|
102
|
-
|
|
103
|
-
```bash
|
|
104
|
-
# Snapshot the persistent volume.
|
|
105
|
-
docker run --rm -v lastlight_agent-data:/data -v /tmp:/backup busybox \
|
|
106
|
-
tar czf /backup/lastlight-data.tgz -C /data .
|
|
107
|
-
scp /tmp/lastlight-data.tgz root@new-host:/tmp/
|
|
108
|
-
docker compose down
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
On the new (native) host, after running install.sh and editing the env file:
|
|
112
|
-
|
|
113
|
-
```bash
|
|
114
|
-
sudo systemctl stop lastlight
|
|
115
|
-
sudo tar xzf /tmp/lastlight-data.tgz -C /var/lib/lastlight \
|
|
116
|
-
lastlight.db lastlight.db-shm lastlight.db-wal \
|
|
117
|
-
agent-sessions secrets || true
|
|
118
|
-
# The old volume used these directory names that the new code doesn't read.
|
|
119
|
-
# Safe to skip restoring them: opencode-home/, opencode-serve/, sandboxes/,
|
|
120
|
-
# sandbox-data/, sessions/, claude-home/.
|
|
121
|
-
sudo chown -R lastlight:lastlight /var/lib/lastlight
|
|
122
|
-
sudo systemctl start lastlight
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
The DB schema is unchanged across the migration, so workflow_runs +
|
|
126
|
-
executions history carry over.
|
|
127
|
-
|
|
128
|
-
## Rollback
|
|
129
|
-
|
|
130
|
-
If the new service doesn't come up cleanly:
|
|
131
|
-
|
|
132
|
-
```bash
|
|
133
|
-
sudo systemctl stop lastlight
|
|
134
|
-
sudo systemctl disable lastlight
|
|
135
|
-
# Restore the docker stack on the same host (or fail over to the old host)
|
|
136
|
-
docker compose up -d
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
State at `/var/lib/lastlight/` and the docker `agent-data` volume are
|
|
140
|
-
independent — neither rollback step touches the other.
|
|
141
|
-
|
|
142
|
-
## Verification
|
|
143
|
-
|
|
144
|
-
After the service is up:
|
|
145
|
-
|
|
146
|
-
```bash
|
|
147
|
-
# 1. It started cleanly.
|
|
148
|
-
systemctl status lastlight # → active (running)
|
|
149
|
-
|
|
150
|
-
# 2. KVM is reachable from the service's user context.
|
|
151
|
-
sudo -u lastlight ls -l /dev/kvm
|
|
152
|
-
|
|
153
|
-
# 3. The harness is listening.
|
|
154
|
-
curl -sS http://127.0.0.1:8644/admin/ | head -5
|
|
155
|
-
|
|
156
|
-
# 4. (Optional) Trigger a real workflow via a PR comment and watch:
|
|
157
|
-
journalctl -u lastlight -f
|
|
158
|
-
# Then look in the dashboard for the executions row + a JSONL under
|
|
159
|
-
# /var/lib/lastlight/agent-sessions/projects/<slug>/
|
|
160
|
-
```
|
package/deploy/native/install.sh
DELETED
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# Idempotent provision + (re)deploy of lastlight as a systemd service on a
|
|
3
|
-
# KVM-capable Linux host. Run as root from the repo root:
|
|
4
|
-
#
|
|
5
|
-
# sudo bash deploy/native/install.sh
|
|
6
|
-
#
|
|
7
|
-
# On first run: installs system deps, creates the lastlight user, scaffolds
|
|
8
|
-
# /etc/lastlight/lastlight.env from the example, installs and starts the
|
|
9
|
-
# systemd unit. On subsequent runs: re-installs the deps that changed,
|
|
10
|
-
# rebuilds, restarts the service.
|
|
11
|
-
|
|
12
|
-
set -euo pipefail
|
|
13
|
-
|
|
14
|
-
REPO_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
15
|
-
SERVICE_NAME=lastlight
|
|
16
|
-
LASTLIGHT_USER=lastlight
|
|
17
|
-
LASTLIGHT_HOME=/var/lib/lastlight
|
|
18
|
-
ENV_DIR=/etc/lastlight
|
|
19
|
-
ENV_FILE="${ENV_DIR}/lastlight.env"
|
|
20
|
-
PEM_FILE="${ENV_DIR}/app.pem"
|
|
21
|
-
|
|
22
|
-
if [ "$(id -u)" -ne 0 ]; then
|
|
23
|
-
echo "install.sh must run as root (try: sudo $0)" >&2
|
|
24
|
-
exit 1
|
|
25
|
-
fi
|
|
26
|
-
|
|
27
|
-
# ── 1. KVM check — gondolin silently hangs without it ──────────────────────
|
|
28
|
-
if [ ! -e /dev/kvm ]; then
|
|
29
|
-
echo "ERROR: /dev/kvm not present on this host." >&2
|
|
30
|
-
echo " gondolin (lastlight's default sandbox) requires KVM. The host must" >&2
|
|
31
|
-
echo " be bare-metal Linux or a VM with nested virtualization enabled." >&2
|
|
32
|
-
echo " See agentic-pi/SPIKE-gondolin.md for the full constraint." >&2
|
|
33
|
-
exit 1
|
|
34
|
-
fi
|
|
35
|
-
|
|
36
|
-
# ── 2. System dependencies (Debian/Ubuntu) ─────────────────────────────────
|
|
37
|
-
export DEBIAN_FRONTEND=noninteractive
|
|
38
|
-
apt-get update
|
|
39
|
-
apt-get install -y --no-install-recommends \
|
|
40
|
-
curl ca-certificates git \
|
|
41
|
-
qemu-system-x86 qemu-utils \
|
|
42
|
-
python3 build-essential
|
|
43
|
-
# Use NodeSource for a current Node 22 LTS (Debian's nodejs is too old).
|
|
44
|
-
if ! command -v node >/dev/null 2>&1 || ! node -e 'process.exit(process.versions.node.split(".")[0] >= 20 ? 0 : 1)'; then
|
|
45
|
-
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
|
|
46
|
-
apt-get install -y --no-install-recommends nodejs
|
|
47
|
-
fi
|
|
48
|
-
|
|
49
|
-
# ── 3. User + group ────────────────────────────────────────────────────────
|
|
50
|
-
if ! id "$LASTLIGHT_USER" >/dev/null 2>&1; then
|
|
51
|
-
useradd --system --create-home --home-dir "$LASTLIGHT_HOME" \
|
|
52
|
-
--shell /usr/sbin/nologin "$LASTLIGHT_USER"
|
|
53
|
-
fi
|
|
54
|
-
# `kvm` group exists once qemu is installed; gate the membership add to
|
|
55
|
-
# avoid a usermod warning on hosts where it doesn't.
|
|
56
|
-
if getent group kvm >/dev/null 2>&1; then
|
|
57
|
-
usermod -aG kvm "$LASTLIGHT_USER"
|
|
58
|
-
fi
|
|
59
|
-
|
|
60
|
-
# ── 4. Repo install + build (as the lastlight user) ────────────────────────
|
|
61
|
-
chown -R "$LASTLIGHT_USER:$LASTLIGHT_USER" "$REPO_DIR"
|
|
62
|
-
sudo -u "$LASTLIGHT_USER" -H bash -c "cd '$REPO_DIR' && npm ci --no-audit --no-fund"
|
|
63
|
-
sudo -u "$LASTLIGHT_USER" -H bash -c "cd '$REPO_DIR' && npm run build && npm run build:dashboard"
|
|
64
|
-
# Prune dev deps to shrink the on-disk footprint of the deployed checkout.
|
|
65
|
-
sudo -u "$LASTLIGHT_USER" -H bash -c "cd '$REPO_DIR' && npm prune --omit=dev"
|
|
66
|
-
|
|
67
|
-
# ── 5. Env file scaffold (don't overwrite an existing config) ──────────────
|
|
68
|
-
mkdir -p "$ENV_DIR"
|
|
69
|
-
chmod 0750 "$ENV_DIR"
|
|
70
|
-
chgrp "$LASTLIGHT_USER" "$ENV_DIR"
|
|
71
|
-
if [ ! -f "$ENV_FILE" ]; then
|
|
72
|
-
install -m 0640 -o root -g "$LASTLIGHT_USER" \
|
|
73
|
-
"$REPO_DIR/deploy/native/lastlight.env.example" "$ENV_FILE"
|
|
74
|
-
echo "" >&2
|
|
75
|
-
echo " NOTE: $ENV_FILE was just created from the example template." >&2
|
|
76
|
-
echo " Edit it to fill in your GitHub App, model API keys, Slack tokens, etc." >&2
|
|
77
|
-
echo " Then re-run this script to start the service." >&2
|
|
78
|
-
echo "" >&2
|
|
79
|
-
fi
|
|
80
|
-
|
|
81
|
-
# ── 6. App PEM — referenced by GITHUB_APP_PRIVATE_KEY_PATH in the env file ─
|
|
82
|
-
# If you placed the PEM at /etc/lastlight/app.pem before running install.sh,
|
|
83
|
-
# this section locks down its permissions; otherwise it's a no-op.
|
|
84
|
-
if [ -f "$PEM_FILE" ]; then
|
|
85
|
-
chown root:"$LASTLIGHT_USER" "$PEM_FILE"
|
|
86
|
-
chmod 0640 "$PEM_FILE"
|
|
87
|
-
fi
|
|
88
|
-
|
|
89
|
-
# ── 7. systemd unit ────────────────────────────────────────────────────────
|
|
90
|
-
install -m 0644 \
|
|
91
|
-
"$REPO_DIR/deploy/native/lastlight.service" \
|
|
92
|
-
"/etc/systemd/system/${SERVICE_NAME}.service"
|
|
93
|
-
systemctl daemon-reload
|
|
94
|
-
|
|
95
|
-
# ── 8. Enable + start ──────────────────────────────────────────────────────
|
|
96
|
-
systemctl enable "${SERVICE_NAME}"
|
|
97
|
-
# Only start/restart if the env file looks configured (the example has the
|
|
98
|
-
# string CHANGE_ME everywhere a value is required).
|
|
99
|
-
if grep -q '^[A-Z].*=CHANGE_ME' "$ENV_FILE"; then
|
|
100
|
-
echo " $ENV_FILE still has CHANGE_ME placeholders — not (re)starting the service." >&2
|
|
101
|
-
echo " Fill in the values and re-run install.sh." >&2
|
|
102
|
-
exit 0
|
|
103
|
-
fi
|
|
104
|
-
systemctl restart "${SERVICE_NAME}"
|
|
105
|
-
|
|
106
|
-
# Brief status read-out so the operator sees if it started cleanly.
|
|
107
|
-
sleep 2
|
|
108
|
-
systemctl status "${SERVICE_NAME}" --no-pager -l | head -20 || true
|
|
109
|
-
echo ""
|
|
110
|
-
echo " Live logs: journalctl -u ${SERVICE_NAME} -f"
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
# ── Last Light — Native deploy env (systemd EnvironmentFile) ────────────
|
|
2
|
-
# Path on the host: /etc/lastlight/lastlight.env
|
|
3
|
-
# Mode 0640, owned by root:lastlight.
|
|
4
|
-
#
|
|
5
|
-
# Anything marked CHANGE_ME must be replaced before the service will start
|
|
6
|
-
# (install.sh refuses to start the unit while placeholders are present).
|
|
7
|
-
|
|
8
|
-
# ── GitHub App (required) ─────────────────────────────────────────────────
|
|
9
|
-
GITHUB_APP_ID=CHANGE_ME
|
|
10
|
-
GITHUB_APP_INSTALLATION_ID=CHANGE_ME
|
|
11
|
-
# PEM is read by the harness at boot. install.sh locks down permissions if
|
|
12
|
-
# you place it at /etc/lastlight/app.pem before running.
|
|
13
|
-
GITHUB_APP_PRIVATE_KEY_PATH=/etc/lastlight/app.pem
|
|
14
|
-
|
|
15
|
-
# Webhook receiver
|
|
16
|
-
WEBHOOK_SECRET=CHANGE_ME
|
|
17
|
-
# Listener port — Caddy/Nginx should reverse-proxy 443 → 127.0.0.1:PORT.
|
|
18
|
-
PORT=8644
|
|
19
|
-
|
|
20
|
-
# ── Model + provider API key ─────────────────────────────────────────────
|
|
21
|
-
# pi-ai supports anthropic/…, openai/…, openrouter/<vendor>/<model>.
|
|
22
|
-
LASTLIGHT_MODEL=anthropic/claude-sonnet-4-6
|
|
23
|
-
# Set whichever matches LASTLIGHT_MODEL (or several if LASTLIGHT_MODELS
|
|
24
|
-
# routes different phases to different providers).
|
|
25
|
-
ANTHROPIC_API_KEY=CHANGE_ME
|
|
26
|
-
# OPENAI_API_KEY=
|
|
27
|
-
# OPENROUTER_API_KEY=
|
|
28
|
-
|
|
29
|
-
# ── OpenTelemetry (optional, disabled by default) ────────────────────────
|
|
30
|
-
# LASTLIGHT_OTEL_ENABLED=false
|
|
31
|
-
# LASTLIGHT_OTEL_SERVICE_NAME=lastlight
|
|
32
|
-
# LASTLIGHT_OTEL_INCLUDE_CONTENT=false
|
|
33
|
-
# LASTLIGHT_OTEL_FORWARD_TO_SANDBOX=true
|
|
34
|
-
# LASTLIGHT_OTEL_STRICT=false
|
|
35
|
-
# OTEL_EXPORTER_OTLP_ENDPOINT=https://CHANGE_ME
|
|
36
|
-
# OTEL_EXPORTER_OTLP_HEADERS=authorization=Bearer CHANGE_ME
|
|
37
|
-
# docker backend routes sandbox telemetry through an in-network otel-collector
|
|
38
|
-
# (re-exports to the endpoint above; headers stay host-side, any port works).
|
|
39
|
-
# LASTLIGHT_OTEL_COLLECTOR_HOSTS is only used by the gondolin egress allowlist.
|
|
40
|
-
# LASTLIGHT_OTEL_COLLECTOR_HOSTS=CHANGE_ME
|
|
41
|
-
|
|
42
|
-
# Per-task model overrides (optional). JSON keyed by phase/skill name.
|
|
43
|
-
# LASTLIGHT_MODELS={"architect":"openai/gpt-5.5","triage":"anthropic/claude-haiku-4-5-20251001"}
|
|
44
|
-
|
|
45
|
-
# ── Web search (optional, explore workflow only) ─────────────────────────
|
|
46
|
-
# Set any one to enable agentic-pi's `web_search` / `web_fetch` tools for
|
|
47
|
-
# the explore workflow. Provider auto-detected from whichever key is set
|
|
48
|
-
# (Tavily > Exa > Brave). Other workflows ignore these keys.
|
|
49
|
-
# TAVILY_API_KEY=tvly-...
|
|
50
|
-
# BRAVE_SEARCH_API_KEY=BSA...
|
|
51
|
-
# EXA_API_KEY=...
|
|
52
|
-
|
|
53
|
-
# Reasoning-effort default + per-task overrides (optional).
|
|
54
|
-
# Values: off | minimal | low | medium | high | xhigh
|
|
55
|
-
# LASTLIGHT_THINKING=medium
|
|
56
|
-
# LASTLIGHT_THINKINGS={"architect":"high","reviewer":"high"}
|
|
57
|
-
|
|
58
|
-
# ── Sandbox backend ───────────────────────────────────────────────────────
|
|
59
|
-
# gondolin = agentic-pi's QEMU micro-VM (default, requires /dev/kvm).
|
|
60
|
-
# docker = sibling docker containers (requires docker socket access).
|
|
61
|
-
# none = unsandboxed in-process (dev only — agent reads/writes host fs).
|
|
62
|
-
LASTLIGHT_SANDBOX=gondolin
|
|
63
|
-
|
|
64
|
-
# ── State paths ───────────────────────────────────────────────────────────
|
|
65
|
-
# systemd's StateDirectory= grants /var/lib/lastlight with the right mode.
|
|
66
|
-
STATE_DIR=/var/lib/lastlight
|
|
67
|
-
DB_PATH=/var/lib/lastlight/lastlight.db
|
|
68
|
-
LASTLIGHT_SESSIONS_DIR=/var/lib/lastlight/agent-sessions
|
|
69
|
-
|
|
70
|
-
# ── Admin dashboard ───────────────────────────────────────────────────────
|
|
71
|
-
# HMAC secret for session tokens. Generate with: openssl rand -hex 32
|
|
72
|
-
ADMIN_SECRET=CHANGE_ME
|
|
73
|
-
# Optional: require a password for the dashboard. Leave unset to allow
|
|
74
|
-
# anyone who can reach the listener (i.e. anyone past Caddy).
|
|
75
|
-
# ADMIN_PASSWORD=
|
|
76
|
-
|
|
77
|
-
# ── Slack (optional) ──────────────────────────────────────────────────────
|
|
78
|
-
# Setting SLACK_BOT_TOKEN enables the chat skill and the Slack connector.
|
|
79
|
-
# SLACK_BOT_TOKEN=xoxb-…
|
|
80
|
-
# SLACK_APP_TOKEN=xapp-…
|
|
81
|
-
# SLACK_DELIVERY_CHANNEL=C0123456789
|
|
82
|
-
# SLACK_ALLOWED_USERS=U0123,U0456
|
|
83
|
-
|
|
84
|
-
# Slack OAuth for dashboard login (optional)
|
|
85
|
-
# SLACK_OAUTH_CLIENT_ID=
|
|
86
|
-
# SLACK_OAUTH_CLIENT_SECRET=
|
|
87
|
-
# SLACK_OAUTH_REDIRECT_URI=https://your-domain/admin/auth/slack/callback
|
|
88
|
-
# SLACK_ALLOWED_WORKSPACE=
|
|
89
|
-
|
|
90
|
-
# ── Approval gates (optional) ─────────────────────────────────────────────
|
|
91
|
-
# Comma-separated list of gate names that should pause the runner.
|
|
92
|
-
# APPROVAL_GATES=post_architect,post_reviewer
|
|
93
|
-
|
|
94
|
-
# ── Bootstrap label (optional) ────────────────────────────────────────────
|
|
95
|
-
# BOOTSTRAP_LABEL=lastlight:bootstrap
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
[Unit]
|
|
2
|
-
Description=Last Light — GitHub repository maintenance agent
|
|
3
|
-
Documentation=https://github.com/nearform/lastlight
|
|
4
|
-
After=network-online.target
|
|
5
|
-
Wants=network-online.target
|
|
6
|
-
|
|
7
|
-
[Service]
|
|
8
|
-
Type=simple
|
|
9
|
-
User=lastlight
|
|
10
|
-
Group=lastlight
|
|
11
|
-
# gondolin needs /dev/kvm — group `kvm` is the standard accessor on Debian/Ubuntu.
|
|
12
|
-
SupplementaryGroups=kvm
|
|
13
|
-
|
|
14
|
-
WorkingDirectory=/opt/lastlight
|
|
15
|
-
ExecStart=/usr/bin/node /opt/lastlight/dist/index.js
|
|
16
|
-
EnvironmentFile=/etc/lastlight/lastlight.env
|
|
17
|
-
|
|
18
|
-
# HOME drives where agentic-pi caches the gondolin guest image
|
|
19
|
-
# (~/.cache/agentic-pi/images/). Pin it to the StateDirectory so the cache
|
|
20
|
-
# survives redeploys and isn't recomputed on every restart.
|
|
21
|
-
Environment=HOME=/var/lib/lastlight
|
|
22
|
-
Environment=NODE_ENV=production
|
|
23
|
-
|
|
24
|
-
Restart=on-failure
|
|
25
|
-
RestartSec=5s
|
|
26
|
-
LimitNOFILE=65536
|
|
27
|
-
# 2 GB matches the docker-compose limit. Bursts during webhook fan-out +
|
|
28
|
-
# in-process pi-ai chat; per-task gondolin VMs have their own memory budget.
|
|
29
|
-
MemoryMax=2G
|
|
30
|
-
|
|
31
|
-
# /var/lib/lastlight created with mode 0750, owned by lastlight:lastlight
|
|
32
|
-
StateDirectory=lastlight
|
|
33
|
-
StateDirectoryMode=0750
|
|
34
|
-
LogsDirectory=lastlight
|
|
35
|
-
LogsDirectoryMode=0750
|
|
36
|
-
|
|
37
|
-
# Security hardening — the harness only writes to its state dir and logs.
|
|
38
|
-
NoNewPrivileges=true
|
|
39
|
-
PrivateTmp=true
|
|
40
|
-
ProtectSystem=strict
|
|
41
|
-
ProtectHome=true
|
|
42
|
-
ProtectKernelTunables=true
|
|
43
|
-
ProtectKernelModules=true
|
|
44
|
-
ProtectControlGroups=true
|
|
45
|
-
ReadWritePaths=/var/lib/lastlight /var/log/lastlight
|
|
46
|
-
# Explicit /dev/kvm rule — ProtectSystem=strict alone doesn't gate /dev.
|
|
47
|
-
DeviceAllow=/dev/kvm rw
|
|
48
|
-
|
|
49
|
-
[Install]
|
|
50
|
-
WantedBy=multi-user.target
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# Sandbox container entrypoint — runs as root after volumes are mounted.
|
|
3
|
-
# Used only when LASTLIGHT_SANDBOX=docker (the gondolin sandbox runs in
|
|
4
|
-
# process and doesn't go through this script). Fixes permissions, writes
|
|
5
|
-
# AGENTS.md, sets up git identity, then drops to the agent user via gosu.
|
|
6
|
-
set -euo pipefail
|
|
7
|
-
|
|
8
|
-
AGENT_HOME="/home/agent"
|
|
9
|
-
WORKSPACE="$AGENT_HOME/workspace"
|
|
10
|
-
# LASTLIGHT_WORKSPACE and LASTLIGHT_GIT_CREDENTIALS are set as image-level
|
|
11
|
-
# ENV in sandbox.Dockerfile so they're visible to every `docker exec` call
|
|
12
|
-
# the harness makes (not just the entrypoint's PID-1 tree). They show up in
|
|
13
|
-
# this shell's env via that mechanism; no export needed here.
|
|
14
|
-
|
|
15
|
-
# ── Fix workspace ownership (bind-mounts may be root-owned on macOS) ──
|
|
16
|
-
chown -R agent:agent "$WORKSPACE" 2>/dev/null || true
|
|
17
|
-
chown agent:agent "$AGENT_HOME"
|
|
18
|
-
|
|
19
|
-
# Ensure ~/.config exists and is agent-owned before any root-side mkdir
|
|
20
|
-
# below claims it (some tools write here at startup).
|
|
21
|
-
mkdir -p "$AGENT_HOME/.config"
|
|
22
|
-
chown agent:agent "$AGENT_HOME/.config"
|
|
23
|
-
|
|
24
|
-
# ── Shared package-manager cache (issue #107) ──
|
|
25
|
-
# /cache is a Docker named volume shared across every sandbox so npm / pnpm /
|
|
26
|
-
# yarn reuse already-downloaded tarballs. A freshly-created volume is root-owned,
|
|
27
|
-
# and a cache seeded by an older image (when `agent` had a different UID) leaves
|
|
28
|
-
# children owned by the wrong UID — which blocks npm/pnpm/yarn writes (e.g.
|
|
29
|
-
# /cache/npm/_logs). Self-heal: if the subdir OR any immediate child isn't
|
|
30
|
-
# agent-owned, chown -R it. The recursive pass runs only when something is
|
|
31
|
-
# actually wrong, so a warm, correctly-owned cache stays cheap.
|
|
32
|
-
if [ -d /cache ]; then
|
|
33
|
-
for sub in npm pnpm yarn uv; do
|
|
34
|
-
mkdir -p "/cache/$sub"
|
|
35
|
-
if [ -n "$(find "/cache/$sub" -maxdepth 1 ! -user agent -print -quit 2>/dev/null)" ]; then
|
|
36
|
-
chown -R agent:agent "/cache/$sub" 2>/dev/null || true
|
|
37
|
-
fi
|
|
38
|
-
done
|
|
39
|
-
fi
|
|
40
|
-
|
|
41
|
-
# ── App PEM: keep shared copy unreadable by the agent by default ──
|
|
42
|
-
if [ -f /data/secrets/app.pem ]; then
|
|
43
|
-
chmod 600 /data/secrets/app.pem 2>/dev/null || true
|
|
44
|
-
fi
|
|
45
|
-
|
|
46
|
-
# Optionally materialize an agent-readable PEM for high-trust runs only.
|
|
47
|
-
# The harness forwards GITHUB_APP_PRIVATE_KEY_PATH into the sandbox env so
|
|
48
|
-
# any tool inside that needs the App key can find it.
|
|
49
|
-
if [ "${ALLOW_APP_PEM:-0}" = "1" ] && [ -f /data/secrets/app.pem ]; then
|
|
50
|
-
cp /data/secrets/app.pem "$AGENT_HOME/.config/app.pem"
|
|
51
|
-
chown agent:agent "$AGENT_HOME/.config/app.pem"
|
|
52
|
-
chmod 600 "$AGENT_HOME/.config/app.pem"
|
|
53
|
-
export GITHUB_APP_PRIVATE_KEY_PATH="$AGENT_HOME/.config/app.pem"
|
|
54
|
-
else
|
|
55
|
-
export GITHUB_APP_PRIVATE_KEY_PATH=""
|
|
56
|
-
fi
|
|
57
|
-
|
|
58
|
-
# ── AGENTS.md — agentic-pi auto-loads this from cwd as the agent's
|
|
59
|
-
# system context (same convention as CLAUDE.md). ──
|
|
60
|
-
if [ ! -f "$WORKSPACE/AGENTS.md" ]; then
|
|
61
|
-
cat /app/agent-context/*.md > "$WORKSPACE/AGENTS.md" 2>/dev/null || true
|
|
62
|
-
fi
|
|
63
|
-
chown agent:agent "$WORKSPACE/AGENTS.md" 2>/dev/null || true
|
|
64
|
-
|
|
65
|
-
# ── Git identity and auth (system-wide so it applies regardless of exec user) ──
|
|
66
|
-
git config --system user.name "last-light[bot]"
|
|
67
|
-
git config --system user.email "last-light[bot]@users.noreply.github.com"
|
|
68
|
-
|
|
69
|
-
if [ -n "${GIT_TOKEN:-}" ]; then
|
|
70
|
-
# Reject tokens containing characters that would break the URL line in
|
|
71
|
-
# the credentials file (newline, '@', ':', '/', whitespace). Real GitHub
|
|
72
|
-
# tokens are alphanumeric + underscore — the wider charset here is
|
|
73
|
-
# defensive against future format changes.
|
|
74
|
-
if ! printf %s "$GIT_TOKEN" | grep -Eq '^[A-Za-z0-9_-]+$'; then
|
|
75
|
-
echo "ERROR: GIT_TOKEN contains characters outside [A-Za-z0-9_-]; refusing to write credentials file" >&2
|
|
76
|
-
exit 1
|
|
77
|
-
fi
|
|
78
|
-
# Write the file as the agent user (mode 600) so the helper can read it
|
|
79
|
-
# after the entrypoint drops privileges. Path is set by us above; the
|
|
80
|
-
# `store --file=<path>` value goes into git's config as argv-split (no
|
|
81
|
-
# shell), so the only constraint is no-whitespace in the path.
|
|
82
|
-
install -m 600 -o agent -g agent /dev/null "$LASTLIGHT_GIT_CREDENTIALS"
|
|
83
|
-
printf 'https://x-access-token:%s@github.com\n' "$GIT_TOKEN" > "$LASTLIGHT_GIT_CREDENTIALS"
|
|
84
|
-
chown agent:agent "$LASTLIGHT_GIT_CREDENTIALS"
|
|
85
|
-
git config --system credential.helper "store --file=$LASTLIGHT_GIT_CREDENTIALS"
|
|
86
|
-
fi
|
|
87
|
-
|
|
88
|
-
# ── Sentinel for harness waitForReady() ──
|
|
89
|
-
touch "$WORKSPACE/.ready"
|
|
90
|
-
chown agent:agent "$WORKSPACE/.ready"
|
|
91
|
-
|
|
92
|
-
# ── Drop to agent user ──
|
|
93
|
-
exec gosu agent "$@"
|
package/dist/admin/auth.d.ts
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import type { Context, Next } from "hono";
|
|
2
|
-
/**
|
|
3
|
-
* Grace window past `exp` in which a token can still be *refreshed* (but not
|
|
4
|
-
* used to authenticate a normal request). Lets an active user whose token
|
|
5
|
-
* lapsed briefly slide their session forward via the refresh route instead of
|
|
6
|
-
* being bounced back through a full login. Beyond this, they must re-login.
|
|
7
|
-
*/
|
|
8
|
-
export declare const REFRESH_GRACE_SECONDS: number;
|
|
9
|
-
export declare function createToken(secret: string, method?: "password" | "slack" | "github"): string;
|
|
10
|
-
export declare function verifyToken(token: string, secret: string): boolean;
|
|
11
|
-
/**
|
|
12
|
-
* Like `verifyToken`, but also accepts a token that expired within the last
|
|
13
|
-
* `REFRESH_GRACE_SECONDS`. Used ONLY by the refresh route so a briefly-lapsed
|
|
14
|
-
* session can be renewed. The signature must still be valid (we minted it), so
|
|
15
|
-
* this can't be forged.
|
|
16
|
-
*/
|
|
17
|
-
export declare function verifyTokenForRefresh(token: string, secret: string): boolean;
|
|
18
|
-
export interface TokenPayload {
|
|
19
|
-
exp: number;
|
|
20
|
-
method?: "password" | "slack" | "github";
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Decode a token's payload WITHOUT verifying its signature or expiry — used to
|
|
24
|
-
* carry the login `method` across a refresh. Callers that need authenticity
|
|
25
|
-
* must still gate on `verifyToken` (the refresh route runs behind
|
|
26
|
-
* `authMiddleware`, which does exactly that). Returns null if unparseable.
|
|
27
|
-
*/
|
|
28
|
-
export declare function decodeToken(token: string): TokenPayload | null;
|
|
29
|
-
/**
|
|
30
|
-
* Whether any login method is configured — an admin password OR a working OAuth
|
|
31
|
-
* provider. The single source of truth for "is auth on", shared by the admin
|
|
32
|
-
* dashboard and the `/api/*` trigger routes so they can't drift. The GitHub
|
|
33
|
-
* gate, like the OAuth route, also requires an allowed-org to be set.
|
|
34
|
-
*/
|
|
35
|
-
export declare function authIsEnabled(opts: {
|
|
36
|
-
adminPassword?: string;
|
|
37
|
-
slackOAuthClientId?: string;
|
|
38
|
-
slackOAuthClientSecret?: string;
|
|
39
|
-
githubOAuthClientId?: string;
|
|
40
|
-
githubOAuthClientSecret?: string;
|
|
41
|
-
githubAllowedOrg?: string;
|
|
42
|
-
}): boolean;
|
|
43
|
-
/**
|
|
44
|
-
* Gate the admin API. `enabled` should be true when ANY login method is
|
|
45
|
-
* configured — an admin password OR a working OAuth provider. Gating only on
|
|
46
|
-
* the password (the old behaviour) left the dashboard fully open whenever the
|
|
47
|
-
* password was cleared, even with Slack/GitHub OAuth set up.
|
|
48
|
-
*/
|
|
49
|
-
export declare function authMiddleware(enabled: boolean, secret: string): (c: Context, next: Next) => Promise<void | (Response & import("hono").TypedResponse<{
|
|
50
|
-
error: string;
|
|
51
|
-
}, 401, "json">)>;
|