@codyswann/lisa 4.80.2 → 4.81.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/all/copy-contents/gitignore +5 -0
- package/dist/cli/doctor-session-manager-trust.d.ts +62 -0
- package/dist/cli/doctor-session-manager-trust.d.ts.map +1 -0
- package/dist/cli/doctor-session-manager-trust.js +174 -0
- package/dist/cli/doctor-session-manager-trust.js.map +1 -0
- package/dist/cli/doctor-session-manager.d.ts +35 -0
- package/dist/cli/doctor-session-manager.d.ts.map +1 -0
- package/dist/cli/doctor-session-manager.js +209 -0
- package/dist/cli/doctor-session-manager.js.map +1 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +3 -0
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/lisa-test-run-bootstrap.js +28 -0
- package/dist/cli/lisa-test-run-bootstrap.js.map +1 -1
- package/dist/cli/session-manager-config-merge.d.ts +25 -0
- package/dist/cli/session-manager-config-merge.d.ts.map +1 -0
- package/dist/cli/session-manager-config-merge.js +54 -0
- package/dist/cli/session-manager-config-merge.js.map +1 -0
- package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +257 -12
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/package.json +4 -4
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-automation-status/SKILL.md +10 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-implement/SKILL.md +17 -2
- package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/validate-config.mjs +377 -5
- package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/SKILL.md +287 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/agents/openai.yaml +4 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/references/runbook-template.md +66 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/capacity.mjs +186 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/cli-cycle.mjs +262 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/cli-manager.mjs +308 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/cli-queue.mjs +148 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/cli-runtime.mjs +326 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/cli-usage.mjs +114 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/cli-workers.mjs +295 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/config.mjs +265 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/isolation.mjs +130 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/launch.mjs +234 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/ledger.mjs +445 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/reconcile.mjs +134 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/session-manager.mjs +274 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/state-dir.mjs +112 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/telegram-route.mjs +210 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/token.mjs +191 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/worker-launch.mjs +92 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/workers.mjs +406 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-session-manager/SKILL.md +158 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-session-manager/agents/openai.yaml +4 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-tear-down-automations/SKILL.md +10 -0
- package/plugins/lisa/commands/implement.md +2 -2
- package/plugins/lisa/commands/session-manager.md +7 -0
- package/plugins/lisa/commands/setup/session-manager.md +6 -0
- package/plugins/lisa/rules/reference/automation-runbook-contract.md +14 -0
- package/plugins/lisa/rules/reference/config-resolution.md +58 -0
- package/plugins/lisa/scripts/automation-status-claude-adapter.mjs +4 -1
- package/plugins/lisa/scripts/automation-status-codex-adapter.mjs +4 -1
- package/plugins/lisa/scripts/automation-status-expected-fleet.mjs +98 -0
- package/plugins/lisa/scripts/automation-status-run-history.mjs +29 -7
- package/plugins/lisa/scripts/ready-queue-order.mjs +352 -0
- package/plugins/lisa/skills/lisa-automation-status/SKILL.md +10 -0
- package/plugins/lisa/skills/lisa-implement/SKILL.md +17 -2
- package/plugins/lisa/skills/lisa-secrets-access/scripts/validate-config.mjs +377 -5
- package/plugins/lisa/skills/lisa-session-manager/SKILL.md +285 -0
- package/plugins/lisa/skills/lisa-session-manager/agents/openai.yaml +4 -0
- package/plugins/lisa/skills/lisa-session-manager/references/runbook-template.md +66 -0
- package/plugins/lisa/skills/lisa-session-manager/scripts/capacity.mjs +186 -0
- package/plugins/lisa/skills/lisa-session-manager/scripts/cli-cycle.mjs +262 -0
- package/plugins/lisa/skills/lisa-session-manager/scripts/cli-manager.mjs +308 -0
- package/plugins/lisa/skills/lisa-session-manager/scripts/cli-queue.mjs +148 -0
- package/plugins/lisa/skills/lisa-session-manager/scripts/cli-runtime.mjs +326 -0
- package/plugins/lisa/skills/lisa-session-manager/scripts/cli-usage.mjs +114 -0
- package/plugins/lisa/skills/lisa-session-manager/scripts/cli-workers.mjs +295 -0
- package/plugins/lisa/skills/lisa-session-manager/scripts/config.mjs +265 -0
- package/plugins/lisa/skills/lisa-session-manager/scripts/isolation.mjs +130 -0
- package/plugins/lisa/skills/lisa-session-manager/scripts/launch.mjs +234 -0
- package/plugins/lisa/skills/lisa-session-manager/scripts/ledger.mjs +445 -0
- package/plugins/lisa/skills/lisa-session-manager/scripts/reconcile.mjs +134 -0
- package/plugins/lisa/skills/lisa-session-manager/scripts/session-manager.mjs +274 -0
- package/plugins/lisa/skills/lisa-session-manager/scripts/state-dir.mjs +112 -0
- package/plugins/lisa/skills/lisa-session-manager/scripts/telegram-route.mjs +210 -0
- package/plugins/lisa/skills/lisa-session-manager/scripts/token.mjs +191 -0
- package/plugins/lisa/skills/lisa-session-manager/scripts/worker-launch.mjs +92 -0
- package/plugins/lisa/skills/lisa-session-manager/scripts/workers.mjs +406 -0
- package/plugins/lisa/skills/lisa-setup-session-manager/SKILL.md +156 -0
- package/plugins/lisa/skills/lisa-setup-session-manager/agents/openai.yaml +4 -0
- package/plugins/lisa/skills/lisa-tear-down-automations/SKILL.md +10 -0
- package/plugins/lisa-agy/commands/lisa/implement.md +2 -2
- package/plugins/lisa-agy/commands/lisa/session-manager.md +7 -0
- package/plugins/lisa-agy/commands/lisa/setup/session-manager.md +6 -0
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/scripts/automation-status-claude-adapter.mjs +4 -1
- package/plugins/lisa-agy/scripts/automation-status-codex-adapter.mjs +4 -1
- package/plugins/lisa-agy/scripts/automation-status-expected-fleet.mjs +98 -0
- package/plugins/lisa-agy/scripts/automation-status-run-history.mjs +29 -7
- package/plugins/lisa-agy/scripts/ready-queue-order.mjs +352 -0
- package/plugins/lisa-agy/skills/lisa-automation-status/SKILL.md +10 -0
- package/plugins/lisa-agy/skills/lisa-implement/SKILL.md +17 -2
- package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/validate-config.mjs +377 -5
- package/plugins/lisa-agy/skills/lisa-session-manager/SKILL.md +285 -0
- package/plugins/lisa-agy/skills/lisa-session-manager/references/runbook-template.md +66 -0
- package/plugins/lisa-agy/skills/lisa-session-manager/scripts/capacity.mjs +186 -0
- package/plugins/lisa-agy/skills/lisa-session-manager/scripts/cli-cycle.mjs +262 -0
- package/plugins/lisa-agy/skills/lisa-session-manager/scripts/cli-manager.mjs +308 -0
- package/plugins/lisa-agy/skills/lisa-session-manager/scripts/cli-queue.mjs +148 -0
- package/plugins/lisa-agy/skills/lisa-session-manager/scripts/cli-runtime.mjs +326 -0
- package/plugins/lisa-agy/skills/lisa-session-manager/scripts/cli-usage.mjs +114 -0
- package/plugins/lisa-agy/skills/lisa-session-manager/scripts/cli-workers.mjs +295 -0
- package/plugins/lisa-agy/skills/lisa-session-manager/scripts/config.mjs +265 -0
- package/plugins/lisa-agy/skills/lisa-session-manager/scripts/isolation.mjs +130 -0
- package/plugins/lisa-agy/skills/lisa-session-manager/scripts/launch.mjs +234 -0
- package/plugins/lisa-agy/skills/lisa-session-manager/scripts/ledger.mjs +445 -0
- package/plugins/lisa-agy/skills/lisa-session-manager/scripts/reconcile.mjs +134 -0
- package/plugins/lisa-agy/skills/lisa-session-manager/scripts/session-manager.mjs +274 -0
- package/plugins/lisa-agy/skills/lisa-session-manager/scripts/state-dir.mjs +112 -0
- package/plugins/lisa-agy/skills/lisa-session-manager/scripts/telegram-route.mjs +210 -0
- package/plugins/lisa-agy/skills/lisa-session-manager/scripts/token.mjs +191 -0
- package/plugins/lisa-agy/skills/lisa-session-manager/scripts/worker-launch.mjs +92 -0
- package/plugins/lisa-agy/skills/lisa-session-manager/scripts/workers.mjs +406 -0
- package/plugins/lisa-agy/skills/lisa-setup-session-manager/SKILL.md +156 -0
- package/plugins/lisa-agy/skills/lisa-tear-down-automations/SKILL.md +10 -0
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/commands/lisa/implement.md +2 -2
- package/plugins/lisa-copilot/commands/lisa/session-manager.md +7 -0
- package/plugins/lisa-copilot/commands/lisa/setup/session-manager.md +6 -0
- package/plugins/lisa-copilot/rules/reference/automation-runbook-contract.md +14 -0
- package/plugins/lisa-copilot/rules/reference/config-resolution.md +58 -0
- package/plugins/lisa-copilot/scripts/automation-status-claude-adapter.mjs +4 -1
- package/plugins/lisa-copilot/scripts/automation-status-codex-adapter.mjs +4 -1
- package/plugins/lisa-copilot/scripts/automation-status-expected-fleet.mjs +98 -0
- package/plugins/lisa-copilot/scripts/automation-status-run-history.mjs +29 -7
- package/plugins/lisa-copilot/scripts/ready-queue-order.mjs +352 -0
- package/plugins/lisa-copilot/skills/lisa-automation-status/SKILL.md +10 -0
- package/plugins/lisa-copilot/skills/lisa-implement/SKILL.md +17 -2
- package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/validate-config.mjs +377 -5
- package/plugins/lisa-copilot/skills/lisa-session-manager/SKILL.md +285 -0
- package/plugins/lisa-copilot/skills/lisa-session-manager/references/runbook-template.md +66 -0
- package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/capacity.mjs +186 -0
- package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/cli-cycle.mjs +262 -0
- package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/cli-manager.mjs +308 -0
- package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/cli-queue.mjs +148 -0
- package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/cli-runtime.mjs +326 -0
- package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/cli-usage.mjs +114 -0
- package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/cli-workers.mjs +295 -0
- package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/config.mjs +265 -0
- package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/isolation.mjs +130 -0
- package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/launch.mjs +234 -0
- package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/ledger.mjs +445 -0
- package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/reconcile.mjs +134 -0
- package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/session-manager.mjs +274 -0
- package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/state-dir.mjs +112 -0
- package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/telegram-route.mjs +210 -0
- package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/token.mjs +191 -0
- package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/worker-launch.mjs +92 -0
- package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/workers.mjs +406 -0
- package/plugins/lisa-copilot/skills/lisa-setup-session-manager/SKILL.md +156 -0
- package/plugins/lisa-copilot/skills/lisa-tear-down-automations/SKILL.md +10 -0
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/commands/lisa/implement.md +2 -2
- package/plugins/lisa-cursor/commands/lisa/session-manager.md +7 -0
- package/plugins/lisa-cursor/commands/lisa/setup/session-manager.md +6 -0
- package/plugins/lisa-cursor/rules/automation-runbook-contract-reference.mdc +14 -0
- package/plugins/lisa-cursor/rules/config-resolution-reference.mdc +58 -0
- package/plugins/lisa-cursor/scripts/automation-status-claude-adapter.mjs +4 -1
- package/plugins/lisa-cursor/scripts/automation-status-codex-adapter.mjs +4 -1
- package/plugins/lisa-cursor/scripts/automation-status-expected-fleet.mjs +98 -0
- package/plugins/lisa-cursor/scripts/automation-status-run-history.mjs +29 -7
- package/plugins/lisa-cursor/scripts/ready-queue-order.mjs +352 -0
- package/plugins/lisa-cursor/skills/lisa-automation-status/SKILL.md +10 -0
- package/plugins/lisa-cursor/skills/lisa-implement/SKILL.md +17 -2
- package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/validate-config.mjs +377 -5
- package/plugins/lisa-cursor/skills/lisa-session-manager/SKILL.md +285 -0
- package/plugins/lisa-cursor/skills/lisa-session-manager/references/runbook-template.md +66 -0
- package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/capacity.mjs +186 -0
- package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/cli-cycle.mjs +262 -0
- package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/cli-manager.mjs +308 -0
- package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/cli-queue.mjs +148 -0
- package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/cli-runtime.mjs +326 -0
- package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/cli-usage.mjs +114 -0
- package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/cli-workers.mjs +295 -0
- package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/config.mjs +265 -0
- package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/isolation.mjs +130 -0
- package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/launch.mjs +234 -0
- package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/ledger.mjs +445 -0
- package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/reconcile.mjs +134 -0
- package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/session-manager.mjs +274 -0
- package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/state-dir.mjs +112 -0
- package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/telegram-route.mjs +210 -0
- package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/token.mjs +191 -0
- package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/worker-launch.mjs +92 -0
- package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/workers.mjs +406 -0
- package/plugins/lisa-cursor/skills/lisa-setup-session-manager/SKILL.md +156 -0
- package/plugins/lisa-cursor/skills/lisa-tear-down-automations/SKILL.md +10 -0
- package/plugins/lisa-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-devin/rules/reference/automation-runbook-contract.md +14 -0
- package/plugins/lisa-devin/rules/reference/config-resolution.md +58 -0
- package/plugins/lisa-devin/scripts/automation-status-claude-adapter.mjs +4 -1
- package/plugins/lisa-devin/scripts/automation-status-codex-adapter.mjs +4 -1
- package/plugins/lisa-devin/scripts/automation-status-expected-fleet.mjs +98 -0
- package/plugins/lisa-devin/scripts/automation-status-run-history.mjs +29 -7
- package/plugins/lisa-devin/scripts/ready-queue-order.mjs +352 -0
- package/plugins/lisa-devin/skills/lisa-automation-status/SKILL.md +10 -0
- package/plugins/lisa-devin/skills/lisa-implement/SKILL.md +17 -2
- package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/validate-config.mjs +377 -5
- package/plugins/lisa-devin/skills/lisa-session-manager/SKILL.md +285 -0
- package/plugins/lisa-devin/skills/lisa-session-manager/references/runbook-template.md +66 -0
- package/plugins/lisa-devin/skills/lisa-session-manager/scripts/capacity.mjs +186 -0
- package/plugins/lisa-devin/skills/lisa-session-manager/scripts/cli-cycle.mjs +262 -0
- package/plugins/lisa-devin/skills/lisa-session-manager/scripts/cli-manager.mjs +308 -0
- package/plugins/lisa-devin/skills/lisa-session-manager/scripts/cli-queue.mjs +148 -0
- package/plugins/lisa-devin/skills/lisa-session-manager/scripts/cli-runtime.mjs +326 -0
- package/plugins/lisa-devin/skills/lisa-session-manager/scripts/cli-usage.mjs +114 -0
- package/plugins/lisa-devin/skills/lisa-session-manager/scripts/cli-workers.mjs +295 -0
- package/plugins/lisa-devin/skills/lisa-session-manager/scripts/config.mjs +265 -0
- package/plugins/lisa-devin/skills/lisa-session-manager/scripts/isolation.mjs +130 -0
- package/plugins/lisa-devin/skills/lisa-session-manager/scripts/launch.mjs +234 -0
- package/plugins/lisa-devin/skills/lisa-session-manager/scripts/ledger.mjs +445 -0
- package/plugins/lisa-devin/skills/lisa-session-manager/scripts/reconcile.mjs +134 -0
- package/plugins/lisa-devin/skills/lisa-session-manager/scripts/session-manager.mjs +274 -0
- package/plugins/lisa-devin/skills/lisa-session-manager/scripts/state-dir.mjs +112 -0
- package/plugins/lisa-devin/skills/lisa-session-manager/scripts/telegram-route.mjs +210 -0
- package/plugins/lisa-devin/skills/lisa-session-manager/scripts/token.mjs +191 -0
- package/plugins/lisa-devin/skills/lisa-session-manager/scripts/worker-launch.mjs +92 -0
- package/plugins/lisa-devin/skills/lisa-session-manager/scripts/workers.mjs +406 -0
- package/plugins/lisa-devin/skills/lisa-setup-session-manager/SKILL.md +156 -0
- package/plugins/lisa-devin/skills/lisa-tear-down-automations/SKILL.md +10 -0
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/src/base/commands/implement.md +2 -2
- package/plugins/src/base/commands/session-manager.md +7 -0
- package/plugins/src/base/commands/setup/session-manager.md +6 -0
- package/plugins/src/base/rules/reference/automation-runbook-contract.md +14 -0
- package/plugins/src/base/rules/reference/config-resolution.md +58 -0
- package/plugins/src/base/scripts/automation-status-claude-adapter.mjs +4 -1
- package/plugins/src/base/scripts/automation-status-codex-adapter.mjs +4 -1
- package/plugins/src/base/scripts/automation-status-expected-fleet.mjs +98 -0
- package/plugins/src/base/scripts/automation-status-run-history.mjs +29 -7
- package/plugins/src/base/scripts/ready-queue-order.mjs +352 -0
- package/plugins/src/base/skills/lisa-automation-status/SKILL.md +10 -0
- package/plugins/src/base/skills/lisa-implement/SKILL.md +17 -2
- package/plugins/src/base/skills/lisa-secrets-access/scripts/validate-config.mjs +377 -5
- package/plugins/src/base/skills/lisa-session-manager/SKILL.md +285 -0
- package/plugins/src/base/skills/lisa-session-manager/references/runbook-template.md +66 -0
- package/plugins/src/base/skills/lisa-session-manager/scripts/capacity.mjs +186 -0
- package/plugins/src/base/skills/lisa-session-manager/scripts/cli-cycle.mjs +262 -0
- package/plugins/src/base/skills/lisa-session-manager/scripts/cli-manager.mjs +308 -0
- package/plugins/src/base/skills/lisa-session-manager/scripts/cli-queue.mjs +148 -0
- package/plugins/src/base/skills/lisa-session-manager/scripts/cli-runtime.mjs +326 -0
- package/plugins/src/base/skills/lisa-session-manager/scripts/cli-usage.mjs +114 -0
- package/plugins/src/base/skills/lisa-session-manager/scripts/cli-workers.mjs +295 -0
- package/plugins/src/base/skills/lisa-session-manager/scripts/config.mjs +265 -0
- package/plugins/src/base/skills/lisa-session-manager/scripts/isolation.mjs +130 -0
- package/plugins/src/base/skills/lisa-session-manager/scripts/launch.mjs +234 -0
- package/plugins/src/base/skills/lisa-session-manager/scripts/ledger.mjs +445 -0
- package/plugins/src/base/skills/lisa-session-manager/scripts/reconcile.mjs +134 -0
- package/plugins/src/base/skills/lisa-session-manager/scripts/session-manager.mjs +274 -0
- package/plugins/src/base/skills/lisa-session-manager/scripts/state-dir.mjs +112 -0
- package/plugins/src/base/skills/lisa-session-manager/scripts/telegram-route.mjs +210 -0
- package/plugins/src/base/skills/lisa-session-manager/scripts/token.mjs +191 -0
- package/plugins/src/base/skills/lisa-session-manager/scripts/worker-launch.mjs +92 -0
- package/plugins/src/base/skills/lisa-session-manager/scripts/workers.mjs +406 -0
- package/plugins/src/base/skills/lisa-setup-session-manager/SKILL.md +156 -0
- package/plugins/src/base/skills/lisa-tear-down-automations/SKILL.md +10 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-cycle subcommands of the session-manager CLI: ledger, route,
|
|
3
|
+
* blocked-plan and record-cycle (`queue` lives in cli-queue.mjs).
|
|
4
|
+
*
|
|
5
|
+
* Every piece of untrusted text these commands take (a worker's question, a
|
|
6
|
+
* Telegram message, a finish reason, the cycle summary, an item's body and
|
|
7
|
+
* comments) arrives on stdin or in a file, never in argv.
|
|
8
|
+
* @module session-manager/cli-cycle
|
|
9
|
+
*/
|
|
10
|
+
import {
|
|
11
|
+
AUTOMATION_RUN_OUTCOMES,
|
|
12
|
+
recordAutomationRun,
|
|
13
|
+
} from "../../../scripts/automation-run-record.mjs";
|
|
14
|
+
import {
|
|
15
|
+
CliError,
|
|
16
|
+
EXIT,
|
|
17
|
+
asSetupErrorAsync,
|
|
18
|
+
humanNeededLabel,
|
|
19
|
+
intFlag,
|
|
20
|
+
loadProject,
|
|
21
|
+
requirePositional,
|
|
22
|
+
stdinText,
|
|
23
|
+
} from "./cli-runtime.mjs";
|
|
24
|
+
import { parseJson, readJsonFile } from "./cli-queue.mjs";
|
|
25
|
+
import {
|
|
26
|
+
clearPendingQuestion,
|
|
27
|
+
readLedger,
|
|
28
|
+
recordFinish,
|
|
29
|
+
recordSpawn,
|
|
30
|
+
setControl,
|
|
31
|
+
setPendingQuestion,
|
|
32
|
+
} from "./ledger.mjs";
|
|
33
|
+
import { planBlockedRelease } from "./reconcile.mjs";
|
|
34
|
+
import { formatAnswer, routeInbound } from "./telegram-route.mjs";
|
|
35
|
+
|
|
36
|
+
/** The automation loop id every cycle records under. */
|
|
37
|
+
const LOOP_ID = "session-manager";
|
|
38
|
+
|
|
39
|
+
/** The runbook the automation-runbook contract requires for this loop. */
|
|
40
|
+
const RUNBOOK = ".lisa/automations/session-manager.runbook.md";
|
|
41
|
+
/**
|
|
42
|
+
* Parse `--paused true|false`.
|
|
43
|
+
* @param {string | undefined} value - Flag value
|
|
44
|
+
* @returns {boolean | undefined} Parsed value
|
|
45
|
+
*/
|
|
46
|
+
function pausedFlag(value) {
|
|
47
|
+
if (value === undefined) return undefined;
|
|
48
|
+
if (value !== "true" && value !== "false") {
|
|
49
|
+
throw new CliError("--paused must be true or false.", 2);
|
|
50
|
+
}
|
|
51
|
+
return value === "true";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Parse a flag where `none` clears the value.
|
|
56
|
+
* @param {string | undefined} value - Flag value
|
|
57
|
+
* @param {(value: string) => unknown} parse - Parser for a real value
|
|
58
|
+
* @returns {unknown} Parsed value, null for `none`, undefined when absent
|
|
59
|
+
*/
|
|
60
|
+
function clearable(value, parse) {
|
|
61
|
+
if (value === undefined) return undefined;
|
|
62
|
+
return value === "none" ? null : parse(value);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* With `--sender <name>`, refuse (exit 2) unless the ledger holds `ref` for
|
|
67
|
+
* exactly that worker. The manager passes the cross-session sender of a
|
|
68
|
+
* worker's report, so one worker can never finish or question another
|
|
69
|
+
* worker's item; the manager's own calls (stall, operator stop, repo-routing
|
|
70
|
+
* questions) omit the flag.
|
|
71
|
+
* @param {object} ctx - CLI context
|
|
72
|
+
* @param {string} ref - Ref the report names
|
|
73
|
+
* @returns {Promise<void>}
|
|
74
|
+
*/
|
|
75
|
+
async function assertSender(ctx, ref) {
|
|
76
|
+
const sender = ctx.values.sender;
|
|
77
|
+
if (sender === undefined) return;
|
|
78
|
+
const items = (await readLedger(ctx.root)).items;
|
|
79
|
+
const worker = Object.hasOwn(items, ref) ? items[ref].worker : null;
|
|
80
|
+
if (worker !== sender) {
|
|
81
|
+
throw new CliError(
|
|
82
|
+
`${sender} is not the worker for ${ref} (the ledger has ` +
|
|
83
|
+
`${worker ?? "no worker"}); ignoring its message.`,
|
|
84
|
+
2
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** One handler per `ledger <action>`. */
|
|
90
|
+
const LEDGER_ACTIONS = {
|
|
91
|
+
async get(ctx) {
|
|
92
|
+
const ledger = await readLedger(ctx.root);
|
|
93
|
+
const [ref] = ctx.positionals;
|
|
94
|
+
if (!ref) return ledger;
|
|
95
|
+
if (!Object.hasOwn(ledger.items, ref)) {
|
|
96
|
+
throw new CliError(`${ref} is not in the ledger.`, 2);
|
|
97
|
+
}
|
|
98
|
+
return ledger.items[ref];
|
|
99
|
+
},
|
|
100
|
+
"record-spawn": ctx =>
|
|
101
|
+
recordSpawn(ctx.root, {
|
|
102
|
+
ref: requirePositional(ctx, "ref"),
|
|
103
|
+
worker: requireValue(ctx, "worker"),
|
|
104
|
+
sessionId: ctx.values["session-id"] ?? null,
|
|
105
|
+
repo: ctx.values.repo ?? ".",
|
|
106
|
+
}),
|
|
107
|
+
async "set-question"(ctx) {
|
|
108
|
+
const ref = requirePositional(ctx, "ref");
|
|
109
|
+
await assertSender(ctx, ref);
|
|
110
|
+
return setPendingQuestion(ctx.root, {
|
|
111
|
+
ref,
|
|
112
|
+
text: stdinText(ctx, "question"),
|
|
113
|
+
telegramMessageId:
|
|
114
|
+
intFlag(ctx.values["telegram-message-id"], "--telegram-message-id") ??
|
|
115
|
+
null,
|
|
116
|
+
});
|
|
117
|
+
},
|
|
118
|
+
"clear-question": ctx =>
|
|
119
|
+
clearPendingQuestion(ctx.root, { ref: requirePositional(ctx, "ref") }),
|
|
120
|
+
async finish(ctx) {
|
|
121
|
+
const status = ctx.values.status;
|
|
122
|
+
if (status !== "DONE" && status !== "FAILED") {
|
|
123
|
+
throw new CliError("--status must be DONE or FAILED.", 2);
|
|
124
|
+
}
|
|
125
|
+
const ref = requirePositional(ctx, "ref");
|
|
126
|
+
await assertSender(ctx, ref);
|
|
127
|
+
return recordFinish(ctx.root, {
|
|
128
|
+
ref,
|
|
129
|
+
status,
|
|
130
|
+
reason: stdinText(ctx, "reason", { required: false }),
|
|
131
|
+
});
|
|
132
|
+
},
|
|
133
|
+
control: ctx =>
|
|
134
|
+
setControl(
|
|
135
|
+
ctx.root,
|
|
136
|
+
Object.fromEntries(
|
|
137
|
+
Object.entries({
|
|
138
|
+
paused: pausedFlag(ctx.values.paused),
|
|
139
|
+
maxWorkers: clearable(ctx.values["max-workers"], value =>
|
|
140
|
+
intFlag(value, "--max-workers")
|
|
141
|
+
),
|
|
142
|
+
me: clearable(ctx.values.me, value => value),
|
|
143
|
+
}).filter(([, value]) => value !== undefined)
|
|
144
|
+
)
|
|
145
|
+
),
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
/** Ledger actions the CLI accepts, for usage and argv specs. */
|
|
149
|
+
export const LEDGER_ACTION_NAMES = Object.keys(LEDGER_ACTIONS);
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* A required flag value, or exit 2.
|
|
153
|
+
* @param {object} ctx - CLI context
|
|
154
|
+
* @param {string} flag - Flag name without dashes
|
|
155
|
+
* @returns {string} Value
|
|
156
|
+
*/
|
|
157
|
+
function requireValue(ctx, flag) {
|
|
158
|
+
const value = ctx.values[flag];
|
|
159
|
+
if (!value) throw new CliError(`Missing --${flag}.`, 2);
|
|
160
|
+
return value;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* `ledger <action>`: read or update the manager's ledger.
|
|
165
|
+
* @param {object} ctx - CLI context; `ctx.action` is the ledger action
|
|
166
|
+
* @returns {Promise<{ json: unknown }>} The item, control or whole ledger
|
|
167
|
+
*/
|
|
168
|
+
export async function ledger(ctx) {
|
|
169
|
+
const handler = LEDGER_ACTIONS[ctx.action];
|
|
170
|
+
return { json: await asSetupErrorAsync(() => handler(ctx)) };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* `route [--reply-to <id>] [--owner <name>]`: decide what one Telegram message
|
|
175
|
+
* (on stdin) is: an answer for a worker, an operator command, or ambiguous.
|
|
176
|
+
* @param {object} ctx - CLI context
|
|
177
|
+
* @returns {Promise<{ json: object }>} Route, plus `message` for an answer
|
|
178
|
+
* when `--owner` is given
|
|
179
|
+
*/
|
|
180
|
+
export async function route(ctx) {
|
|
181
|
+
const text = stdinText(ctx, "message", { required: false });
|
|
182
|
+
const routed = routeInbound({
|
|
183
|
+
text,
|
|
184
|
+
replyToMessageId: intFlag(ctx.values["reply-to"], "--reply-to") ?? null,
|
|
185
|
+
ledger: await readLedger(ctx.root),
|
|
186
|
+
});
|
|
187
|
+
const owner = ctx.values.owner;
|
|
188
|
+
if (routed.kind === "answer" && owner) {
|
|
189
|
+
return { json: { ...routed, message: formatAnswer(owner, routed.body) } };
|
|
190
|
+
}
|
|
191
|
+
return { json: routed };
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* `blocked-plan [--input <file>] [--ref <ref>]`: plan one Blocked item from
|
|
196
|
+
* its JSON (stdin, or the file). `--ref` fills in the ledger's pending
|
|
197
|
+
* question when the input does not carry one.
|
|
198
|
+
*
|
|
199
|
+
* Who may release a human hold comes from `sessionManager.trustedAuthorIds`
|
|
200
|
+
* only. Any `trustedHumanActorIds` in the input is discarded: the input is
|
|
201
|
+
* assembled from the item's own (untrusted) body and comments, so a list
|
|
202
|
+
* carried beside them would let the item's text vouch for itself.
|
|
203
|
+
* @param {object} ctx - CLI context
|
|
204
|
+
* @returns {Promise<{ json: object }>} `{action,reason,edges,gate}`
|
|
205
|
+
*/
|
|
206
|
+
export async function blockedPlan(ctx) {
|
|
207
|
+
const input = ctx.values.input
|
|
208
|
+
? readJsonFile(ctx.values.input)
|
|
209
|
+
: parseJson(stdinText(ctx, "item JSON"), "stdin");
|
|
210
|
+
const ref = ctx.values.ref;
|
|
211
|
+
const pendingQuestion =
|
|
212
|
+
input.pendingQuestion ??
|
|
213
|
+
(ref ? (await readLedger(ctx.root)).items[ref]?.pendingQuestion : null);
|
|
214
|
+
const project = loadProject(ctx.root);
|
|
215
|
+
const trustedHumanActorIds = project.config?.trustedAuthorIds ?? [];
|
|
216
|
+
return {
|
|
217
|
+
json: planBlockedRelease({
|
|
218
|
+
...input,
|
|
219
|
+
// The configured label, so a Jira `Human Needed` hold is still a hold.
|
|
220
|
+
humanNeededLabel:
|
|
221
|
+
input.humanNeededLabel ?? humanNeededLabel(project, undefined),
|
|
222
|
+
pendingQuestion,
|
|
223
|
+
trustedHumanActorIds,
|
|
224
|
+
}),
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* `record-cycle --outcome <o> [--ref <url>]... [--run-id <id>]`: record this
|
|
230
|
+
* cycle's run outcome, with the one-line summary on stdin.
|
|
231
|
+
* @param {object} ctx - CLI context
|
|
232
|
+
* @returns {Promise<{ json: object }>} What was recorded
|
|
233
|
+
*/
|
|
234
|
+
export async function recordCycle(ctx) {
|
|
235
|
+
const outcome = ctx.values.outcome;
|
|
236
|
+
if (!AUTOMATION_RUN_OUTCOMES.includes(outcome)) {
|
|
237
|
+
throw new CliError(
|
|
238
|
+
`--outcome must be one of: ${AUTOMATION_RUN_OUTCOMES.join(", ")}.`,
|
|
239
|
+
EXIT.SETUP
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
const result = await asSetupErrorAsync(() =>
|
|
243
|
+
recordAutomationRun({
|
|
244
|
+
projectRoot: ctx.root,
|
|
245
|
+
loopId: LOOP_ID,
|
|
246
|
+
runbook: RUNBOOK,
|
|
247
|
+
outcome,
|
|
248
|
+
summary: stdinText(ctx, "cycle summary"),
|
|
249
|
+
refs: ctx.values.ref ?? [],
|
|
250
|
+
...(ctx.values["run-id"] ? { runId: ctx.values["run-id"] } : {}),
|
|
251
|
+
})
|
|
252
|
+
);
|
|
253
|
+
return {
|
|
254
|
+
json: {
|
|
255
|
+
path: result.path,
|
|
256
|
+
appended: result.appended,
|
|
257
|
+
loop_id: result.record.loop_id,
|
|
258
|
+
outcome: result.record.outcome,
|
|
259
|
+
run_id: result.record.run_id,
|
|
260
|
+
},
|
|
261
|
+
};
|
|
262
|
+
}
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manager and setup subcommands of the session-manager CLI: start, stop,
|
|
3
|
+
* status, repo-dir, validate, init-config and store-token.
|
|
4
|
+
*
|
|
5
|
+
* `start` hosts the manager in tmux. It refuses (exit 2) unless the bot
|
|
6
|
+
* token file exists with owner-only permissions in the project's own state
|
|
7
|
+
* dir, and it treats an existing tmux session started in this root as
|
|
8
|
+
* "already running" rather than starting a second poller on the same bot. A
|
|
9
|
+
* session of that name started in another root is another project's manager,
|
|
10
|
+
* so both `start` and `stop` refuse it (exit 2). `stop` kills only the
|
|
11
|
+
* manager's tmux session: workers hold claimed work and keep running.
|
|
12
|
+
* @module session-manager/cli-manager
|
|
13
|
+
*/
|
|
14
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
15
|
+
import path from "node:path";
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
CliError,
|
|
19
|
+
EXIT,
|
|
20
|
+
GLOBAL_CONFIG_FILE,
|
|
21
|
+
asSetupError,
|
|
22
|
+
asSetupErrorAsync,
|
|
23
|
+
intFlag,
|
|
24
|
+
listAgents,
|
|
25
|
+
loadProject,
|
|
26
|
+
mustRun,
|
|
27
|
+
requireConfig,
|
|
28
|
+
requireLisaRepo,
|
|
29
|
+
run,
|
|
30
|
+
} from "./cli-runtime.mjs";
|
|
31
|
+
import { buildDefaultBlock, detectRepos, resolveRepoDir } from "./config.mjs";
|
|
32
|
+
import {
|
|
33
|
+
defaultProjectSlug,
|
|
34
|
+
probeOwnSession,
|
|
35
|
+
sessionSurvives,
|
|
36
|
+
} from "./isolation.mjs";
|
|
37
|
+
import {
|
|
38
|
+
assertTokenPresent,
|
|
39
|
+
buildForegroundCommand,
|
|
40
|
+
buildHasSession,
|
|
41
|
+
buildManagerLaunch,
|
|
42
|
+
buildStopManager,
|
|
43
|
+
resolveStateDir,
|
|
44
|
+
storeToken as storeTokenFile,
|
|
45
|
+
} from "./launch.mjs";
|
|
46
|
+
import { readLedger } from "./ledger.mjs";
|
|
47
|
+
import { parseWorkerName, scrubWorkerEnv } from "./workers.mjs";
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The configured state dir, resolved (exit 2 for the shared default dir).
|
|
51
|
+
* @param {object} ctx - CLI context
|
|
52
|
+
* @param {object} config - Resolved block
|
|
53
|
+
* @returns {string} Absolute state dir
|
|
54
|
+
*/
|
|
55
|
+
function stateDirOf(ctx, config) {
|
|
56
|
+
return asSetupError(() =>
|
|
57
|
+
resolveStateDir(config.notify?.stateDir, {
|
|
58
|
+
env: ctx.env,
|
|
59
|
+
homedir: ctx.homedir,
|
|
60
|
+
})
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** How long a new manager session must survive before `start` says so. */
|
|
65
|
+
const DEFAULT_SETTLE_MS = 3000;
|
|
66
|
+
|
|
67
|
+
/** Upper bound for `--settle-ms`, so `start` always returns promptly. */
|
|
68
|
+
const MAX_SETTLE_MS = 60_000;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* `--settle-ms`, defaulted and bounded, or exit 2.
|
|
72
|
+
* @param {object} ctx - CLI context
|
|
73
|
+
* @returns {number} Milliseconds
|
|
74
|
+
*/
|
|
75
|
+
function settleMsOf(ctx) {
|
|
76
|
+
const value = intFlag(ctx.values["settle-ms"], "--settle-ms");
|
|
77
|
+
if (value !== undefined && value > MAX_SETTLE_MS) {
|
|
78
|
+
throw new CliError(
|
|
79
|
+
`--settle-ms must be at most ${MAX_SETTLE_MS}.`,
|
|
80
|
+
EXIT.SETUP
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
return value ?? DEFAULT_SETTLE_MS;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* `start [--settle-ms <n>]`: host the manager in a detached tmux session,
|
|
88
|
+
* and report `started` only once the session has survived the settle window
|
|
89
|
+
* (claude can exit at once on a bad argv; tmux then closes the session).
|
|
90
|
+
* @param {object} ctx - CLI context
|
|
91
|
+
* @returns {Promise<{ json: object }>} `{status,name,...}`
|
|
92
|
+
*/
|
|
93
|
+
export async function start(ctx) {
|
|
94
|
+
const settleMs = settleMsOf(ctx);
|
|
95
|
+
const config = requireConfig(ctx);
|
|
96
|
+
const stateDir = stateDirOf(ctx, config);
|
|
97
|
+
// tmux gets the scrubbed env: if this call starts the tmux server, its
|
|
98
|
+
// global environment must not carry a TELEGRAM_* value into other sessions.
|
|
99
|
+
const env = scrubWorkerEnv(ctx.env);
|
|
100
|
+
const session = probeOwnSession(ctx, config.name, env);
|
|
101
|
+
if (session.missing) throw new CliError("tmux is not on PATH.", EXIT.SETUP);
|
|
102
|
+
if (session.running) {
|
|
103
|
+
return { json: { status: "already-running", name: config.name } };
|
|
104
|
+
}
|
|
105
|
+
asSetupError(() => assertTokenPresent(stateDir));
|
|
106
|
+
const argv = asSetupError(() =>
|
|
107
|
+
buildManagerLaunch({
|
|
108
|
+
name: config.name,
|
|
109
|
+
root: ctx.root,
|
|
110
|
+
stateDir,
|
|
111
|
+
scriptsDir: ctx.scriptsDir,
|
|
112
|
+
interval: config.interval,
|
|
113
|
+
})
|
|
114
|
+
);
|
|
115
|
+
mustRun("tmux", argv, { env, cwd: ctx.root });
|
|
116
|
+
if (!(await sessionSurvives(config.name, env, settleMs))) {
|
|
117
|
+
const foreground = buildForegroundCommand(argv);
|
|
118
|
+
throw new CliError(
|
|
119
|
+
`The manager's tmux session "${config.name}" exited within ` +
|
|
120
|
+
`${settleMs} ms of starting, so the manager is not running. Run the ` +
|
|
121
|
+
`launch in the foreground to see claude's error:\n ${foreground}`,
|
|
122
|
+
EXIT.SETUP
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
json: {
|
|
127
|
+
status: "started",
|
|
128
|
+
name: config.name,
|
|
129
|
+
stateDir,
|
|
130
|
+
attach: `tmux attach -t ${config.name}`,
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* `stop`: kill the manager's tmux session only, and only when it was started
|
|
137
|
+
* in this root (exit 2 for another project's session of the same name).
|
|
138
|
+
* @param {object} ctx - CLI context
|
|
139
|
+
* @returns {{ json: object }} `{status:"stopped"|"not-running",name}`
|
|
140
|
+
*/
|
|
141
|
+
export function stop(ctx) {
|
|
142
|
+
const config = requireConfig(ctx);
|
|
143
|
+
const env = scrubWorkerEnv(ctx.env);
|
|
144
|
+
if (!probeOwnSession(ctx, config.name, env).running) {
|
|
145
|
+
return { json: { status: "not-running", name: config.name } };
|
|
146
|
+
}
|
|
147
|
+
const result = run("tmux", buildStopManager(config.name), { env });
|
|
148
|
+
const stopped = result.status === 0;
|
|
149
|
+
return {
|
|
150
|
+
json: { status: stopped ? "stopped" : "not-running", name: config.name },
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* `repo-dir [--repo <key>] [--raw]`: the directory a claim or worker for this
|
|
156
|
+
* repo key must run in.
|
|
157
|
+
* @param {object} ctx - CLI context
|
|
158
|
+
* @returns {{ json?: object, text?: string }} JSON, or the bare path
|
|
159
|
+
*/
|
|
160
|
+
export function repoDir(ctx) {
|
|
161
|
+
const config = requireConfig(ctx);
|
|
162
|
+
const key = ctx.values.repo;
|
|
163
|
+
const dir = requireLisaRepo(
|
|
164
|
+
asSetupError(() => resolveRepoDir(config, key, ctx.root))
|
|
165
|
+
);
|
|
166
|
+
if (ctx.values.raw) return { text: `${dir}\n` };
|
|
167
|
+
return { json: { repo: key ?? ".", dir } };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Problems `validateSessionManager` cannot see: they need the filesystem.
|
|
172
|
+
* @param {object} ctx - CLI context
|
|
173
|
+
* @param {object} config - Resolved block
|
|
174
|
+
* @returns {string[]} Problems
|
|
175
|
+
*/
|
|
176
|
+
function environmentProblems(ctx, config) {
|
|
177
|
+
const problems = Object.keys(config.repos?.entries ?? {}).flatMap(key => {
|
|
178
|
+
try {
|
|
179
|
+
requireLisaRepo(resolveRepoDir(config, key, ctx.root));
|
|
180
|
+
return [];
|
|
181
|
+
} catch (error) {
|
|
182
|
+
return [`sessionManager.repos.entries.${key}: ${error.message}`];
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
if (typeof config.notify?.stateDir === "string") {
|
|
186
|
+
try {
|
|
187
|
+
stateDirOf(ctx, config);
|
|
188
|
+
} catch (error) {
|
|
189
|
+
problems.push(`sessionManager.notify.stateDir: ${error.message}`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return problems;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* `validate`: every problem with the block, exit 2 when there is any.
|
|
197
|
+
* @param {object} ctx - CLI context
|
|
198
|
+
* @returns {{ json: object, exitCode: number }} `{valid,errors}`
|
|
199
|
+
*/
|
|
200
|
+
export function validate(ctx) {
|
|
201
|
+
const project = loadProject(ctx.root);
|
|
202
|
+
const errors = project.config
|
|
203
|
+
? [...project.errors, ...environmentProblems(ctx, project.config)]
|
|
204
|
+
: [`No sessionManager block in ${GLOBAL_CONFIG_FILE}.`];
|
|
205
|
+
return {
|
|
206
|
+
json: { valid: errors.length === 0, errors },
|
|
207
|
+
exitCode: errors.length === 0 ? EXIT.OK : EXIT.SETUP,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* `init-config [--slug <slug>] [--write]`: the default block for this
|
|
213
|
+
* project, written to `.lisa.config.json` only with `--write` and only when
|
|
214
|
+
* no block exists. Non-secret fields only; the token never goes here.
|
|
215
|
+
* @param {object} ctx - CLI context
|
|
216
|
+
* @returns {{ json: object }} `{written,block,...}`
|
|
217
|
+
*/
|
|
218
|
+
export function initConfig(ctx) {
|
|
219
|
+
const { global } = loadProject(ctx.root);
|
|
220
|
+
if (global?.sessionManager) {
|
|
221
|
+
return {
|
|
222
|
+
json: { written: false, reason: "exists", block: global.sessionManager },
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
const slug =
|
|
226
|
+
ctx.values.slug ?? defaultProjectSlug(ctx.root, global?.github?.repo);
|
|
227
|
+
const block = asSetupError(() =>
|
|
228
|
+
buildDefaultBlock({
|
|
229
|
+
projectSlug: slug,
|
|
230
|
+
detectedRepos: detectRepos(ctx.root),
|
|
231
|
+
})
|
|
232
|
+
);
|
|
233
|
+
if (!ctx.values.write) return { json: { written: false, block } };
|
|
234
|
+
|
|
235
|
+
const file = path.join(ctx.root, GLOBAL_CONFIG_FILE);
|
|
236
|
+
if (!existsSync(file)) {
|
|
237
|
+
throw new CliError(
|
|
238
|
+
`${file} does not exist; set up Lisa in this project first.`,
|
|
239
|
+
EXIT.SETUP
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
const current = JSON.parse(readFileSync(file, "utf8"));
|
|
243
|
+
writeFileSync(
|
|
244
|
+
file,
|
|
245
|
+
`${JSON.stringify({ ...current, sessionManager: block }, null, 2)}\n`
|
|
246
|
+
);
|
|
247
|
+
return { json: { written: true, path: file, block } };
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* `store-token [--replace]`: prompt for the bot token on the operator's
|
|
252
|
+
* terminal and write `<stateDir>/.env`. An existing token is kept (exit 2)
|
|
253
|
+
* unless `--replace` is given. With no TTY it prints the command the operator
|
|
254
|
+
* must run themselves and exits 0 with `stored:false`.
|
|
255
|
+
* @param {object} ctx - CLI context
|
|
256
|
+
* @returns {Promise<{ json: object, exitCode: number }>} Outcome
|
|
257
|
+
*/
|
|
258
|
+
export async function storeToken(ctx) {
|
|
259
|
+
const config = requireConfig(ctx);
|
|
260
|
+
const result = await asSetupErrorAsync(() =>
|
|
261
|
+
storeTokenFile({
|
|
262
|
+
stateDir: config.notify?.stateDir,
|
|
263
|
+
scriptsDir: ctx.scriptsDir,
|
|
264
|
+
projectRoot: ctx.root,
|
|
265
|
+
replace: ctx.values.replace === true,
|
|
266
|
+
env: ctx.env,
|
|
267
|
+
homedir: ctx.homedir,
|
|
268
|
+
})
|
|
269
|
+
);
|
|
270
|
+
const refused = result.stored === false && result.reason !== "no-tty";
|
|
271
|
+
return { json: result, exitCode: refused ? EXIT.SETUP : EXIT.OK };
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* `status`: is the manager's tmux session up, and what does the ledger say
|
|
276
|
+
* about each worker it dispatched.
|
|
277
|
+
* @param {object} ctx - CLI context
|
|
278
|
+
* @returns {Promise<{ json: object }>} `{manager,control,workers,untracked}`
|
|
279
|
+
*/
|
|
280
|
+
export async function status(ctx) {
|
|
281
|
+
const config = requireConfig(ctx);
|
|
282
|
+
const tmux = run("tmux", buildHasSession(config.name), { env: ctx.env });
|
|
283
|
+
const agents = listAgents(ctx, { all: true });
|
|
284
|
+
const ledger = await readLedger(ctx.root);
|
|
285
|
+
const liveNames = new Set(
|
|
286
|
+
agents.filter(agent => agent.active).map(agent => agent.name)
|
|
287
|
+
);
|
|
288
|
+
const tracked = new Set(Object.values(ledger.items).map(i => i.worker));
|
|
289
|
+
return {
|
|
290
|
+
json: {
|
|
291
|
+
manager: { name: config.name, running: tmux.status === 0 },
|
|
292
|
+
control: ledger.control,
|
|
293
|
+
workers: Object.entries(ledger.items).map(([ref, item]) => ({
|
|
294
|
+
ref,
|
|
295
|
+
worker: item.worker ?? null,
|
|
296
|
+
sessionId: item.sessionId ?? null,
|
|
297
|
+
repo: item.repo ?? null,
|
|
298
|
+
status: item.status ?? null,
|
|
299
|
+
attempts: item.attempts ?? 0,
|
|
300
|
+
pendingQuestion: Boolean(item.pendingQuestion),
|
|
301
|
+
live: liveNames.has(item.worker),
|
|
302
|
+
})),
|
|
303
|
+
untracked: [...liveNames]
|
|
304
|
+
.filter(name => parseWorkerName(name) !== null && !tracked.has(name))
|
|
305
|
+
.sort(),
|
|
306
|
+
},
|
|
307
|
+
};
|
|
308
|
+
}
|