neondeck 1.0.0-beta.10
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/CHANGELOG.md +76 -0
- package/DEVELOPMENT.md +304 -0
- package/LICENSE +21 -0
- package/README.md +129 -0
- package/SOUL.md +8 -0
- package/bin/neondeck.mjs +27 -0
- package/config/dashboard.json +224 -0
- package/config/dashboard.schema.json +247 -0
- package/dist/SOUL.md +8 -0
- package/dist/assets/app-CnXGMuTl.js +3878 -0
- package/dist/assets/app-CnXGMuTl.js.map +1 -0
- package/dist/assets/autopilot-B8lfWyA1.js +68813 -0
- package/dist/assets/autopilot-B8lfWyA1.js.map +1 -0
- package/dist/assets/briefing-BT8h9XXT.js +52 -0
- package/dist/assets/briefing-BT8h9XXT.js.map +1 -0
- package/dist/assets/briefing-VMdQPEGc.js +2 -0
- package/dist/assets/briefings-DuApznpN.js +1596 -0
- package/dist/assets/briefings-DuApznpN.js.map +1 -0
- package/dist/assets/command-run-CnPOA8iY.js +20 -0
- package/dist/assets/command-run-CnPOA8iY.js.map +1 -0
- package/dist/assets/command-run-Smpq7waT.js +2 -0
- package/dist/assets/display-assistant-CKU4YJlc.js +392 -0
- package/dist/assets/display-assistant-CKU4YJlc.js.map +1 -0
- package/dist/assets/fix-pr-ci-Ce2SIcyf.js +46 -0
- package/dist/assets/fix-pr-ci-Ce2SIcyf.js.map +1 -0
- package/dist/assets/fix-pr-ci-P3dLxmbx.js +2 -0
- package/dist/assets/migrations/20260710061339_neondeck_pre_1_0_baseline/migration.sql +748 -0
- package/dist/assets/migrations/20260710061339_neondeck_pre_1_0_baseline/snapshot.json +7126 -0
- package/dist/assets/migrations/20260711171708_conversational_briefings/migration.sql +35 -0
- package/dist/assets/migrations/20260711171708_conversational_briefings/snapshot.json +7458 -0
- package/dist/assets/migrations/20260714191624_worktree_lock_revocation/migration.sql +1 -0
- package/dist/assets/migrations/20260714191624_worktree_lock_revocation/snapshot.json +7468 -0
- package/dist/assets/migrations/20260714213018_pr_reviews/migration.sql +34 -0
- package/dist/assets/migrations/20260714213018_pr_reviews/snapshot.json +7809 -0
- package/dist/assets/pr-reviews-BtJ5cm5P.js +521 -0
- package/dist/assets/pr-reviews-BtJ5cm5P.js.map +1 -0
- package/dist/assets/prepare-pr-worktree-B0qMZMRP.js +2 -0
- package/dist/assets/prepare-pr-worktree-C7SmiaTp.js +17 -0
- package/dist/assets/prepare-pr-worktree-C7SmiaTp.js.map +1 -0
- package/dist/assets/push-pr-autofix-CsMbrnXR.js +17 -0
- package/dist/assets/push-pr-autofix-CsMbrnXR.js.map +1 -0
- package/dist/assets/push-pr-autofix-njuM6ej2.js +2 -0
- package/dist/assets/review-pr-for-human-CEciM46A.js +2 -0
- package/dist/assets/review-pr-for-human-TPiQNRWV.js +790 -0
- package/dist/assets/review-pr-for-human-TPiQNRWV.js.map +1 -0
- package/dist/assets/safety-BQC7exnI.js +1931 -0
- package/dist/assets/safety-BQC7exnI.js.map +1 -0
- package/dist/assets/scheduled-agent-instruction-BbxwCKbU.js +2 -0
- package/dist/assets/scheduled-agent-instruction-C58itQyU.js +22 -0
- package/dist/assets/scheduled-agent-instruction-C58itQyU.js.map +1 -0
- package/dist/assets/scheduler-tick-B2S9jCYS.js +90 -0
- package/dist/assets/scheduler-tick-B2S9jCYS.js.map +1 -0
- package/dist/assets/scheduler-workflow-CnI0tWbg.js +21 -0
- package/dist/assets/scheduler-workflow-CnI0tWbg.js.map +1 -0
- package/dist/assets/skills/github-gh/SKILL.md +56 -0
- package/dist/assets/skills/neon-ci-fix/SKILL.md +15 -0
- package/dist/assets/skills/neon-docs-fix/SKILL.md +15 -0
- package/dist/assets/skills/neon-issue-triage/SKILL.md +13 -0
- package/dist/assets/skills/neon-pr-review/SKILL.md +19 -0
- package/dist/assets/skills/neondeck/SKILL.md +127 -0
- package/dist/assets/skills/neondeck-handoff/SKILL.md +31 -0
- package/dist/assets/triage-pr-event-CBje6df5.js +2 -0
- package/dist/assets/triage-pr-event-IgC-IrNs.js +17 -0
- package/dist/assets/triage-pr-event-IgC-IrNs.js.map +1 -0
- package/dist/assets/verify-then-push-pr-autofix-C5Dpomtd.js +75 -0
- package/dist/assets/verify-then-push-pr-autofix-C5Dpomtd.js.map +1 -0
- package/dist/assets/verify-then-push-pr-autofix-oZ0-wa7L.js +2 -0
- package/dist/config/dashboard.json +224 -0
- package/dist/config/dashboard.schema.json +247 -0
- package/dist/server.mjs +583 -0
- package/dist/server.mjs.map +1 -0
- package/dist/skills/github-gh/SKILL.md +56 -0
- package/dist/skills/neon-ci-fix/SKILL.md +15 -0
- package/dist/skills/neon-docs-fix/SKILL.md +15 -0
- package/dist/skills/neon-issue-triage/SKILL.md +13 -0
- package/dist/skills/neon-pr-review/SKILL.md +19 -0
- package/dist/skills/neondeck/SKILL.md +127 -0
- package/dist/skills/neondeck-handoff/SKILL.md +31 -0
- package/drizzle.config.ts +7 -0
- package/package.json +156 -0
- package/shared/patch-anchors.ts +78 -0
- package/shared/report-document.ts +91 -0
- package/src/agents/busywork-workflow.ts +24 -0
- package/src/agents/display-assistant.ts +137 -0
- package/src/agents/pr-review-assistant.ts +25 -0
- package/src/agents/scheduler-workflow.ts +20 -0
- package/src/agents/support/tools.ts +346 -0
- package/src/app.ts +1 -0
- package/src/cli/index.ts +560 -0
- package/src/cli/learning.ts +44 -0
- package/src/cli/mcp.ts +496 -0
- package/src/cli/modules.ts +107 -0
- package/src/cli/onboarding.ts +666 -0
- package/src/cli/options.ts +102 -0
- package/src/cli/output.ts +399 -0
- package/src/cli/preapprovals.ts +204 -0
- package/src/cli/prompts.ts +108 -0
- package/src/cli/types.ts +59 -0
- package/src/db.ts +41 -0
- package/src/desktop/open.ts +698 -0
- package/src/desktop/service.ts +863 -0
- package/src/domains/mcp/actions.ts +420 -0
- package/src/domains/mcp/config.ts +501 -0
- package/src/domains/mcp/format.ts +35 -0
- package/src/domains/mcp/gate.ts +188 -0
- package/src/domains/mcp/index.ts +9 -0
- package/src/domains/mcp/instructions.ts +18 -0
- package/src/domains/mcp/oauth.ts +1063 -0
- package/src/domains/mcp/policy.ts +15 -0
- package/src/domains/mcp/registry.ts +461 -0
- package/src/domains/mcp/schemas.ts +171 -0
- package/src/domains/mcp/stdio.ts +451 -0
- package/src/domains/mcp/store.ts +905 -0
- package/src/domains/mcp/tools.ts +119 -0
- package/src/lib/action-result.ts +51 -0
- package/src/lib/exec.ts +118 -0
- package/src/lib/git.ts +20 -0
- package/src/lib/report-html.ts +193 -0
- package/src/lib/sqlite.ts +51 -0
- package/src/lib/valibot.ts +33 -0
- package/src/modules/app-state/index.ts +4 -0
- package/src/modules/app-state/notification-events.ts +44 -0
- package/src/modules/app-state/notifications.ts +259 -0
- package/src/modules/app-state/types.ts +42 -0
- package/src/modules/app-state/workflow-summaries.ts +201 -0
- package/src/modules/autonomous-audit/index.ts +225 -0
- package/src/modules/autopilot/actions.ts +186 -0
- package/src/modules/autopilot/admissions.ts +865 -0
- package/src/modules/autopilot/approvals.ts +59 -0
- package/src/modules/autopilot/ci-fix-run.ts +1332 -0
- package/src/modules/autopilot/ci-fix.ts +718 -0
- package/src/modules/autopilot/comments.ts +426 -0
- package/src/modules/autopilot/fixtures.ts +344 -0
- package/src/modules/autopilot/github-facts.ts +306 -0
- package/src/modules/autopilot/index.ts +64 -0
- package/src/modules/autopilot/notifications.ts +271 -0
- package/src/modules/autopilot/push-support.ts +260 -0
- package/src/modules/autopilot/push.ts +670 -0
- package/src/modules/autopilot/recovery.ts +656 -0
- package/src/modules/autopilot/review-feedback.ts +649 -0
- package/src/modules/autopilot/review-support.ts +524 -0
- package/src/modules/autopilot/revision-run.ts +445 -0
- package/src/modules/autopilot/schemas.ts +485 -0
- package/src/modules/autopilot/state-mappers.ts +517 -0
- package/src/modules/autopilot/state-schemas.ts +450 -0
- package/src/modules/autopilot/state-store.ts +183 -0
- package/src/modules/autopilot/state.ts +255 -0
- package/src/modules/autopilot/triage-support.ts +234 -0
- package/src/modules/autopilot/triage.ts +156 -0
- package/src/modules/autopilot/utils.ts +145 -0
- package/src/modules/autopilot/worktree.ts +637 -0
- package/src/modules/autopilot-policy/config.ts +101 -0
- package/src/modules/autopilot-policy/index.ts +4 -0
- package/src/modules/autopilot-policy/risk.ts +359 -0
- package/src/modules/autopilot-policy/schemas.ts +229 -0
- package/src/modules/autopilot-policy/service.ts +272 -0
- package/src/modules/briefings/actions.ts +80 -0
- package/src/modules/briefings/index.ts +5 -0
- package/src/modules/briefings/schemas.ts +125 -0
- package/src/modules/briefings/service.ts +642 -0
- package/src/modules/briefings/snapshot.ts +291 -0
- package/src/modules/briefings/store.ts +644 -0
- package/src/modules/commands/actions.ts +112 -0
- package/src/modules/commands/handlers/index.ts +3 -0
- package/src/modules/commands/handlers/misc.ts +367 -0
- package/src/modules/commands/handlers/queue.ts +710 -0
- package/src/modules/commands/handlers/repo.ts +339 -0
- package/src/modules/commands/index.ts +5 -0
- package/src/modules/commands/registry.ts +157 -0
- package/src/modules/commands/runner.ts +152 -0
- package/src/modules/commands/schemas.ts +109 -0
- package/src/modules/commands/summaries.ts +108 -0
- package/src/modules/commands/utils.ts +113 -0
- package/src/modules/config/actions.ts +253 -0
- package/src/modules/config/events.ts +80 -0
- package/src/modules/config/files.ts +9 -0
- package/src/modules/config/history.ts +74 -0
- package/src/modules/config/index.ts +9 -0
- package/src/modules/config/mutations/dashboard.ts +333 -0
- package/src/modules/config/mutations/execution.ts +89 -0
- package/src/modules/config/mutations/models.ts +467 -0
- package/src/modules/config/mutations/providers.ts +163 -0
- package/src/modules/config/mutations/repos.ts +663 -0
- package/src/modules/config/read.ts +130 -0
- package/src/modules/config/result.ts +66 -0
- package/src/modules/config/schemas.ts +180 -0
- package/src/modules/docs-drift/index.ts +1 -0
- package/src/modules/docs-drift/service.ts +863 -0
- package/src/modules/execution/actions.ts +35 -0
- package/src/modules/execution/approvals.ts +322 -0
- package/src/modules/execution/exedev/checkouts.ts +356 -0
- package/src/modules/execution/exedev/context.ts +286 -0
- package/src/modules/execution/index.ts +7 -0
- package/src/modules/execution/policy.ts +102 -0
- package/src/modules/execution/run.ts +589 -0
- package/src/modules/execution/schemas.ts +116 -0
- package/src/modules/execution/scope.ts +137 -0
- package/src/modules/execution/store.ts +320 -0
- package/src/modules/execution/utils.ts +105 -0
- package/src/modules/execution-policy/index.ts +424 -0
- package/src/modules/flue/execution-context.ts +40 -0
- package/src/modules/flue/index.ts +2 -0
- package/src/modules/flue/origin.ts +7 -0
- package/src/modules/github/actions.ts +334 -0
- package/src/modules/github/checks.ts +484 -0
- package/src/modules/github/client.ts +110 -0
- package/src/modules/github/comments.ts +204 -0
- package/src/modules/github/errors.ts +50 -0
- package/src/modules/github/index.ts +93 -0
- package/src/modules/github/issues.ts +116 -0
- package/src/modules/github/pr-file-cache.ts +264 -0
- package/src/modules/github/pull-requests.ts +411 -0
- package/src/modules/github/queue.ts +350 -0
- package/src/modules/github/reviews.ts +1446 -0
- package/src/modules/github/schemas.ts +794 -0
- package/src/modules/github/state-truncation.ts +31 -0
- package/src/modules/handoff/index.ts +2 -0
- package/src/modules/handoff/schemas.ts +61 -0
- package/src/modules/handoff/service.ts +587 -0
- package/src/modules/hygiene/index.ts +1 -0
- package/src/modules/hygiene/service.ts +513 -0
- package/src/modules/kilo/actions.ts +229 -0
- package/src/modules/kilo/ci-fix-run-reconcile.ts +299 -0
- package/src/modules/kilo/docs-drift-boundary.ts +178 -0
- package/src/modules/kilo/index.ts +8 -0
- package/src/modules/kilo/notifications.ts +295 -0
- package/src/modules/kilo/process.ts +637 -0
- package/src/modules/kilo/results/actions.ts +66 -0
- package/src/modules/kilo/results/gates.ts +227 -0
- package/src/modules/kilo/results/index.ts +23 -0
- package/src/modules/kilo/results/schemas.ts +112 -0
- package/src/modules/kilo/results/service.ts +512 -0
- package/src/modules/kilo/results/state.ts +508 -0
- package/src/modules/kilo/results/verify.ts +328 -0
- package/src/modules/kilo/revision-reconcile.ts +187 -0
- package/src/modules/kilo/runtime-facts.ts +128 -0
- package/src/modules/kilo/schemas.ts +265 -0
- package/src/modules/kilo/service.ts +714 -0
- package/src/modules/kilo/sessions-adapters.ts +343 -0
- package/src/modules/kilo/sessions.ts +446 -0
- package/src/modules/kilo/store.ts +689 -0
- package/src/modules/kilo/utils.ts +166 -0
- package/src/modules/learning/automation-health.ts +441 -0
- package/src/modules/learning/automation-memory.ts +179 -0
- package/src/modules/learning/index.ts +6 -0
- package/src/modules/learning/observability.ts +616 -0
- package/src/modules/learning/operator.ts +404 -0
- package/src/modules/learning/reviews/agents.ts +33 -0
- package/src/modules/learning/reviews/complete.ts +321 -0
- package/src/modules/learning/reviews/context.ts +145 -0
- package/src/modules/learning/reviews/events.ts +306 -0
- package/src/modules/learning/reviews/index.ts +6 -0
- package/src/modules/learning/reviews/pr-cadence.ts +157 -0
- package/src/modules/learning/reviews/pr-context.ts +749 -0
- package/src/modules/learning/reviews/prepare.ts +387 -0
- package/src/modules/learning/reviews/schemas.ts +184 -0
- package/src/modules/learning/reviews/store.ts +405 -0
- package/src/modules/learning/skill-patches/actions.ts +86 -0
- package/src/modules/learning/skill-patches/index.ts +3 -0
- package/src/modules/learning/skill-patches/schemas.ts +60 -0
- package/src/modules/learning/skill-patches/service.ts +571 -0
- package/src/modules/learning/skill-patches/support.ts +417 -0
- package/src/modules/memory/actions.ts +183 -0
- package/src/modules/memory/candidates.ts +525 -0
- package/src/modules/memory/events.ts +2 -0
- package/src/modules/memory/index.ts +6 -0
- package/src/modules/memory/prompt.ts +214 -0
- package/src/modules/memory/schemas.ts +170 -0
- package/src/modules/memory/service.ts +578 -0
- package/src/modules/memory/store.ts +489 -0
- package/src/modules/pr-events/actions.ts +191 -0
- package/src/modules/pr-events/index.ts +46 -0
- package/src/modules/pr-events/schemas.ts +186 -0
- package/src/modules/pr-events/service.ts +1414 -0
- package/src/modules/pr-events/target.ts +222 -0
- package/src/modules/pr-events/utils.ts +85 -0
- package/src/modules/pr-events/watermarks.ts +308 -0
- package/src/modules/pr-local-diffs/index.ts +334 -0
- package/src/modules/pr-review-assist/actions.ts +239 -0
- package/src/modules/pr-review-assist/index.ts +3 -0
- package/src/modules/pr-review-assist/schemas.ts +86 -0
- package/src/modules/pr-review-assist/service.ts +706 -0
- package/src/modules/pr-reviews/events.ts +39 -0
- package/src/modules/pr-reviews/index.ts +4 -0
- package/src/modules/pr-reviews/service.ts +655 -0
- package/src/modules/pr-reviews/store.ts +186 -0
- package/src/modules/pr-reviews/types.ts +48 -0
- package/src/modules/prepared-diffs/actions.ts +132 -0
- package/src/modules/prepared-diffs/index.ts +53 -0
- package/src/modules/prepared-diffs/schemas.ts +255 -0
- package/src/modules/prepared-diffs/service.ts +791 -0
- package/src/modules/prepared-diffs/store.ts +678 -0
- package/src/modules/repo-guardrails/config.ts +61 -0
- package/src/modules/repo-guardrails/index.ts +162 -0
- package/src/modules/repo-guardrails/risk.ts +2 -0
- package/src/modules/reports/index.ts +1 -0
- package/src/modules/reports/service.ts +337 -0
- package/src/modules/repos/index.ts +3 -0
- package/src/modules/repos/model-discovery.ts +233 -0
- package/src/modules/repos/providers.ts +194 -0
- package/src/modules/repos/registry.ts +232 -0
- package/src/modules/runtime/agent-config.ts +167 -0
- package/src/modules/runtime/doctor.ts +528 -0
- package/src/modules/runtime/env.ts +123 -0
- package/src/modules/runtime/index.ts +12 -0
- package/src/modules/runtime/local-api-auth.ts +43 -0
- package/src/modules/runtime/metrics.ts +211 -0
- package/src/modules/runtime/skills-actions.ts +141 -0
- package/src/modules/runtime/skills.ts +689 -0
- package/src/modules/runtime/soul.ts +68 -0
- package/src/modules/runtime/status-database.ts +252 -0
- package/src/modules/runtime/status-schema.ts +149 -0
- package/src/modules/runtime/status.ts +481 -0
- package/src/modules/runtime/subagents.ts +37 -0
- package/src/modules/runtime/utility-model.ts +47 -0
- package/src/modules/safety/index.ts +3 -0
- package/src/modules/safety/policy-entries.ts +2528 -0
- package/src/modules/safety/schemas.ts +63 -0
- package/src/modules/safety/service.ts +58 -0
- package/src/modules/safety/tools.ts +15 -0
- package/src/modules/scheduled-tasks/actions.ts +113 -0
- package/src/modules/scheduled-tasks/dispatch.ts +107 -0
- package/src/modules/scheduled-tasks/index.ts +6 -0
- package/src/modules/scheduled-tasks/schemas.ts +91 -0
- package/src/modules/scheduled-tasks/service.ts +296 -0
- package/src/modules/scheduled-tasks/store.ts +814 -0
- package/src/modules/scheduled-tasks/triggers.ts +87 -0
- package/src/modules/scheduler/actions.ts +37 -0
- package/src/modules/scheduler/dispatch.ts +192 -0
- package/src/modules/scheduler/index.ts +4 -0
- package/src/modules/scheduler/lease.ts +247 -0
- package/src/modules/scheduler/pr-watch-event-deltas.ts +367 -0
- package/src/modules/scheduler/pr-watch-events.ts +834 -0
- package/src/modules/scheduler/schemas.ts +79 -0
- package/src/modules/scheduler/service.ts +228 -0
- package/src/modules/scheduler/utils.ts +106 -0
- package/src/modules/scheduler/workflow-invocation.ts +48 -0
- package/src/modules/sessions/actions.ts +213 -0
- package/src/modules/sessions/active-session.ts +46 -0
- package/src/modules/sessions/activity.ts +122 -0
- package/src/modules/sessions/agent-context.ts +152 -0
- package/src/modules/sessions/approval-nudges.ts +156 -0
- package/src/modules/sessions/events.ts +57 -0
- package/src/modules/sessions/index.ts +12 -0
- package/src/modules/sessions/queries.ts +252 -0
- package/src/modules/sessions/references.ts +113 -0
- package/src/modules/sessions/repo-context.ts +131 -0
- package/src/modules/sessions/schemas.ts +285 -0
- package/src/modules/sessions/service.ts +845 -0
- package/src/modules/sessions/store.ts +560 -0
- package/src/modules/sessions/summaries.ts +129 -0
- package/src/modules/sessions/utils.ts +18 -0
- package/src/modules/watches/actions.ts +115 -0
- package/src/modules/watches/index.ts +6 -0
- package/src/modules/watches/polling.ts +245 -0
- package/src/modules/watches/references.ts +293 -0
- package/src/modules/watches/schemas.ts +156 -0
- package/src/modules/watches/service.ts +557 -0
- package/src/modules/watches/store.ts +398 -0
- package/src/modules/watches/utils.ts +51 -0
- package/src/modules/worktree-verification/index.ts +256 -0
- package/src/modules/worktrees/access.ts +129 -0
- package/src/modules/worktrees/actions.ts +108 -0
- package/src/modules/worktrees/cleanup.ts +98 -0
- package/src/modules/worktrees/ensure-pr-worktree.ts +63 -0
- package/src/modules/worktrees/errors.ts +38 -0
- package/src/modules/worktrees/git.ts +48 -0
- package/src/modules/worktrees/index.ts +7 -0
- package/src/modules/worktrees/locks.ts +231 -0
- package/src/modules/worktrees/paths.ts +209 -0
- package/src/modules/worktrees/push-target.ts +39 -0
- package/src/modules/worktrees/queries.ts +31 -0
- package/src/modules/worktrees/schemas.ts +237 -0
- package/src/modules/worktrees/service.ts +680 -0
- package/src/modules/worktrees/store.ts +415 -0
- package/src/repo-edit/actions.ts +509 -0
- package/src/repo-edit/audit.ts +180 -0
- package/src/repo-edit/fuzzy-replace.ts +256 -0
- package/src/repo-edit/git.ts +830 -0
- package/src/repo-edit/index.ts +4 -0
- package/src/repo-edit/locks.ts +27 -0
- package/src/repo-edit/patch-parser.ts +212 -0
- package/src/repo-edit/patch-service.ts +572 -0
- package/src/repo-edit/path-safety.ts +299 -0
- package/src/repo-edit/schemas.ts +239 -0
- package/src/repo-edit/service.ts +488 -0
- package/src/repo-edit/support.ts +459 -0
- package/src/runtime-home/app-db/index.ts +74 -0
- package/src/runtime-home/app-db/migrate.ts +491 -0
- package/src/runtime-home/app-db/migrations/20260710061339_neondeck_pre_1_0_baseline/migration.sql +748 -0
- package/src/runtime-home/app-db/migrations/20260710061339_neondeck_pre_1_0_baseline/snapshot.json +7126 -0
- package/src/runtime-home/app-db/migrations/20260711171708_conversational_briefings/migration.sql +35 -0
- package/src/runtime-home/app-db/migrations/20260711171708_conversational_briefings/snapshot.json +7458 -0
- package/src/runtime-home/app-db/migrations/20260714191624_worktree_lock_revocation/migration.sql +1 -0
- package/src/runtime-home/app-db/migrations/20260714191624_worktree_lock_revocation/snapshot.json +7468 -0
- package/src/runtime-home/app-db/migrations/20260714213018_pr_reviews/migration.sql +34 -0
- package/src/runtime-home/app-db/migrations/20260714213018_pr_reviews/snapshot.json +7809 -0
- package/src/runtime-home/app-db/reconcile.ts +155 -0
- package/src/runtime-home/app-db/schema.ts +1209 -0
- package/src/runtime-home/bootstrap.ts +177 -0
- package/src/runtime-home/dashboard-migrations.ts +101 -0
- package/src/runtime-home/defaults.ts +54 -0
- package/src/runtime-home/files.ts +193 -0
- package/src/runtime-home/guardrails.ts +77 -0
- package/src/runtime-home/index.ts +71 -0
- package/src/runtime-home/paths.ts +75 -0
- package/src/runtime-home/schemas.ts +520 -0
- package/src/sandboxes/exedev.ts +676 -0
- package/src/server/app.ts +5 -0
- package/src/server/autopilot-push-dispatch.ts +326 -0
- package/src/server/create-app.ts +160 -0
- package/src/server/events/event-stream.ts +109 -0
- package/src/server/http.ts +56 -0
- package/src/server/learning-hooks.ts +489 -0
- package/src/server/middleware.ts +81 -0
- package/src/server/routes/autopilot.ts +318 -0
- package/src/server/routes/briefings.ts +34 -0
- package/src/server/routes/commands.ts +12 -0
- package/src/server/routes/config.ts +124 -0
- package/src/server/routes/execution.ts +71 -0
- package/src/server/routes/github.ts +559 -0
- package/src/server/routes/handoff.ts +69 -0
- package/src/server/routes/kilo.ts +179 -0
- package/src/server/routes/learning.ts +384 -0
- package/src/server/routes/mcp.ts +301 -0
- package/src/server/routes/memory.ts +99 -0
- package/src/server/routes/metrics.ts +12 -0
- package/src/server/routes/notifications.ts +48 -0
- package/src/server/routes/repo-edit.ts +115 -0
- package/src/server/routes/reports.ts +128 -0
- package/src/server/routes/repos.ts +50 -0
- package/src/server/routes/reviews.ts +257 -0
- package/src/server/routes/runtime.ts +48 -0
- package/src/server/routes/safety.ts +13 -0
- package/src/server/routes/scheduled-tasks.ts +60 -0
- package/src/server/routes/scheduler.ts +13 -0
- package/src/server/routes/sessions.ts +229 -0
- package/src/server/routes/skills.ts +103 -0
- package/src/server/routes/watches.ts +81 -0
- package/src/server/routes/workflows.ts +21 -0
- package/src/server/routes/worktrees.ts +64 -0
- package/src/server/scheduler-workflow.ts +541 -0
- package/src/server/serve.ts +100 -0
- package/src/setup.ts +162 -0
- package/src/skills/github-gh/SKILL.md +56 -0
- package/src/skills/neon-ci-fix/SKILL.md +15 -0
- package/src/skills/neon-docs-fix/SKILL.md +15 -0
- package/src/skills/neon-issue-triage/SKILL.md +13 -0
- package/src/skills/neon-pr-review/SKILL.md +19 -0
- package/src/skills/neondeck/SKILL.md +127 -0
- package/src/skills/neondeck-handoff/SKILL.md +31 -0
- package/src/workflows/briefing.ts +50 -0
- package/src/workflows/command-run.ts +15 -0
- package/src/workflows/comment-pr-autofix-result.ts +10 -0
- package/src/workflows/curate_learning_store.ts +37 -0
- package/src/workflows/dev-doctor.ts +10 -0
- package/src/workflows/fix-pr-ci-failure.ts +10 -0
- package/src/workflows/fix-pr-ci.ts +15 -0
- package/src/workflows/fix-pr-review-feedback.ts +10 -0
- package/src/workflows/handoff_to_kilo.ts +10 -0
- package/src/workflows/prepare-pr-worktree.ts +10 -0
- package/src/workflows/promote_kilo_result.ts +10 -0
- package/src/workflows/push-pr-autofix.ts +10 -0
- package/src/workflows/reconcile_kilo_task.ts +10 -0
- package/src/workflows/review-pr-for-human.ts +15 -0
- package/src/workflows/review_conversation_for_learning.ts +37 -0
- package/src/workflows/review_kilo_result.ts +10 -0
- package/src/workflows/review_pr_batch_for_learning.ts +37 -0
- package/src/workflows/scheduled-agent-instruction.ts +16 -0
- package/src/workflows/scheduler-tick.ts +10 -0
- package/src/workflows/summarize_kilo_session.ts +25 -0
- package/src/workflows/triage-pr-event.ts +10 -0
- package/src/workflows/verify-pr-worktree.ts +10 -0
- package/src/workflows/verify-then-push-pr-autofix.ts +82 -0
- package/src/workflows/verify_kilo_result.ts +10 -0
- package/src/workflows/watch-pr.ts +10 -0
- package/web/dist/assets/GitHubPrReview-Bf8PXCaq.js +3 -0
- package/web/dist/assets/MultiFileView-CFYStqTV.js +2970 -0
- package/web/dist/assets/PrReviewPopoutPage-CZN1CV82.js +1 -0
- package/web/dist/assets/abap-CLvhMVsD.js +1 -0
- package/web/dist/assets/actionscript-3--17pq3dv.js +1 -0
- package/web/dist/assets/ada-C5qYipkI.js +1 -0
- package/web/dist/assets/andromeeda-vGVdxbeo.js +1 -0
- package/web/dist/assets/angular-html-BVBpGdXr.js +1 -0
- package/web/dist/assets/angular-ts-BfdufMKP.js +1 -0
- package/web/dist/assets/apache-U0d_L8uA.js +1 -0
- package/web/dist/assets/apex-VAyPSnFM.js +1 -0
- package/web/dist/assets/apl-DWBSSoBH.js +1 -0
- package/web/dist/assets/applescript-CCn79oCD.js +1 -0
- package/web/dist/assets/ara-4CJ0cIlV.js +1 -0
- package/web/dist/assets/asciidoc-DE70LPWp.js +1 -0
- package/web/dist/assets/asm-Cmm7eHzH.js +1 -0
- package/web/dist/assets/astro-3LtMP0Sq.js +1 -0
- package/web/dist/assets/aurora-x-CDeNXAV0.js +1 -0
- package/web/dist/assets/awk-BWXHIvNe.js +1 -0
- package/web/dist/assets/ayu-dark-DluEY0Gj.js +1 -0
- package/web/dist/assets/ayu-light-C3h-C4tm.js +1 -0
- package/web/dist/assets/ayu-mirage-Bqwy1Gya.js +1 -0
- package/web/dist/assets/ballerina-B7ZEbQpA.js +1 -0
- package/web/dist/assets/bat-Bo4NYOV-.js +1 -0
- package/web/dist/assets/beancount-D-usSTwE.js +1 -0
- package/web/dist/assets/berry-DKpUyyne.js +1 -0
- package/web/dist/assets/bibtex-Ci_nEsc7.js +1 -0
- package/web/dist/assets/bicep-CUHmPFLl.js +1 -0
- package/web/dist/assets/bird2-C6vDhewU.js +1 -0
- package/web/dist/assets/blade-llJRbbtR.js +1 -0
- package/web/dist/assets/bsl-BkkzgIyY.js +1 -0
- package/web/dist/assets/c-Wt1voDr2.js +1 -0
- package/web/dist/assets/c3-BFHwR3_K.js +1 -0
- package/web/dist/assets/cadence-CQ2zXKGN.js +1 -0
- package/web/dist/assets/cairo-DLTphjLi.js +1 -0
- package/web/dist/assets/catppuccin-frappe-3VR1Za6u.js +1 -0
- package/web/dist/assets/catppuccin-latte-DwIHMF0Q.js +1 -0
- package/web/dist/assets/catppuccin-macchiato-DYnBP6_5.js +1 -0
- package/web/dist/assets/catppuccin-mocha-DYhrFGRu.js +1 -0
- package/web/dist/assets/ccount-CMHa3wy6.js +1 -0
- package/web/dist/assets/clarity-SemFz856.js +1 -0
- package/web/dist/assets/clojure-DqKBuwfJ.js +1 -0
- package/web/dist/assets/cmake-Bj61d0ZC.js +1 -0
- package/web/dist/assets/cobol-x_HIyl2P.js +1 -0
- package/web/dist/assets/codeowners-C8r90Shi.js +1 -0
- package/web/dist/assets/codeql-oeQT6MSM.js +1 -0
- package/web/dist/assets/coffee-CThvmt4R.js +1 -0
- package/web/dist/assets/common-lisp-Cv5bFMCO.js +1 -0
- package/web/dist/assets/coq-BrsZFFmf.js +1 -0
- package/web/dist/assets/cpp-NtAeskI3.js +1 -0
- package/web/dist/assets/crystal-DNu_sX0G.js +1 -0
- package/web/dist/assets/csharp-oqKa8noW.js +1 -0
- package/web/dist/assets/css-DJp_X0uY.js +1 -0
- package/web/dist/assets/csv-Dx-8-gkx.js +1 -0
- package/web/dist/assets/cue-CE9AQfxI.js +1 -0
- package/web/dist/assets/cypher-ClKdZ_lG.js +1 -0
- package/web/dist/assets/d-qD-0Kul2.js +1 -0
- package/web/dist/assets/dark-plus-Cs2F2srj.js +1 -0
- package/web/dist/assets/dart-CnvKMtbv.js +1 -0
- package/web/dist/assets/dax-BkyTk9wS.js +1 -0
- package/web/dist/assets/desktop-Dlh5hvp9.js +1 -0
- package/web/dist/assets/diff-woXpYk--.js +1 -0
- package/web/dist/assets/docker-IyjqRm3v.js +1 -0
- package/web/dist/assets/dotenv-_5a1GRtc.js +1 -0
- package/web/dist/assets/dracula-BHWKrbxM.js +1 -0
- package/web/dist/assets/dracula-soft-5eyTD99u.js +1 -0
- package/web/dist/assets/dream-maker-DW3nJb8Q.js +1 -0
- package/web/dist/assets/edge-ozw5tpLl.js +1 -0
- package/web/dist/assets/elixir-VhA6FeZt.js +1 -0
- package/web/dist/assets/elm-dREJmIFz.js +1 -0
- package/web/dist/assets/emacs-lisp-B4R74twV.js +1 -0
- package/web/dist/assets/erb-CIg6G69l.js +1 -0
- package/web/dist/assets/erlang-Cphh6RMH.js +1 -0
- package/web/dist/assets/everforest-dark-sB-x3p7T.js +1 -0
- package/web/dist/assets/everforest-light-Df2xbC6M.js +1 -0
- package/web/dist/assets/fennel-DQxkIbk2.js +1 -0
- package/web/dist/assets/fish-BJitypiv.js +1 -0
- package/web/dist/assets/fluent-C03EYrpw.js +1 -0
- package/web/dist/assets/fortran-fixed-form-DEKoE2YW.js +1 -0
- package/web/dist/assets/fortran-free-form-CYNrtFtB.js +1 -0
- package/web/dist/assets/fsharp-D13ZGOAj.js +1 -0
- package/web/dist/assets/gdresource-C0sCabJj.js +1 -0
- package/web/dist/assets/gdscript-Cp2uCuqX.js +1 -0
- package/web/dist/assets/gdshader-CBce3t8t.js +1 -0
- package/web/dist/assets/genie-CV2tkWYe.js +1 -0
- package/web/dist/assets/gherkin-DExj1W_8.js +1 -0
- package/web/dist/assets/git-commit-BSykSTBG.js +1 -0
- package/web/dist/assets/git-rebase-B44mJPta.js +1 -0
- package/web/dist/assets/github-dark-C-LZuMrd.js +1 -0
- package/web/dist/assets/github-dark-default-DXG-b-1a.js +1 -0
- package/web/dist/assets/github-dark-dimmed-Bx1FflLF.js +1 -0
- package/web/dist/assets/github-dark-high-contrast-B_tTalzw.js +1 -0
- package/web/dist/assets/github-light-EUqPIrTm.js +1 -0
- package/web/dist/assets/github-light-default-BXViO-2h.js +1 -0
- package/web/dist/assets/github-light-high-contrast-B68TUdTA.js +1 -0
- package/web/dist/assets/gleam-CSRkHgEL.js +1 -0
- package/web/dist/assets/glimmer-js-vH_gHG0-.js +1 -0
- package/web/dist/assets/glimmer-ts--abOzSAQ.js +1 -0
- package/web/dist/assets/glsl-Dv5r7kPw.js +1 -0
- package/web/dist/assets/gn-ilITqXS6.js +1 -0
- package/web/dist/assets/gnuplot-7GGW24-e.js +1 -0
- package/web/dist/assets/go-rLFTqkRN.js +1 -0
- package/web/dist/assets/graphql-CB4jsw2E.js +1 -0
- package/web/dist/assets/groovy-CacY0gHj.js +1 -0
- package/web/dist/assets/gruvbox-dark-hard-C820rvS2.js +1 -0
- package/web/dist/assets/gruvbox-dark-medium-BPjhmG05.js +1 -0
- package/web/dist/assets/gruvbox-dark-soft-MrdJrrXF.js +1 -0
- package/web/dist/assets/gruvbox-light-hard-BC_s9l72.js +1 -0
- package/web/dist/assets/gruvbox-light-medium-BAWPOn9u.js +1 -0
- package/web/dist/assets/gruvbox-light-soft-BSMLrYjP.js +1 -0
- package/web/dist/assets/hack-DvEYX148.js +1 -0
- package/web/dist/assets/haml-zE6W3STP.js +1 -0
- package/web/dist/assets/handlebars-CzBR2SDs.js +1 -0
- package/web/dist/assets/haskell-D8IpX4py.js +1 -0
- package/web/dist/assets/haxe-OTjmBuCE.js +1 -0
- package/web/dist/assets/hcl-Dh228itO.js +1 -0
- package/web/dist/assets/hjson-CxZEssPk.js +1 -0
- package/web/dist/assets/hlsl-Cvrh5tZx.js +1 -0
- package/web/dist/assets/horizon-CE9ld1lL.js +1 -0
- package/web/dist/assets/horizon-bright-DSNQnXHK.js +1 -0
- package/web/dist/assets/houston-CsvMBhTu.js +1 -0
- package/web/dist/assets/html-C8UlPnhE.js +1 -0
- package/web/dist/assets/html-derivative-CY6NRz-J.js +1 -0
- package/web/dist/assets/http-Cyd7bS_S.js +1 -0
- package/web/dist/assets/hurl-CWPsiEpf.js +1 -0
- package/web/dist/assets/hxml-B0Qn7Nwc.js +1 -0
- package/web/dist/assets/hy-CZbG8q4J.js +1 -0
- package/web/dist/assets/imba-DsUTQ-LC.js +1 -0
- package/web/dist/assets/index-BTjK1c82.js +44 -0
- package/web/dist/assets/index-D0kg2-9O.css +2 -0
- package/web/dist/assets/ini-B5eOa1yu.js +1 -0
- package/web/dist/assets/java-CGc3VwQr.js +1 -0
- package/web/dist/assets/javascript-CUt1pgmJ.js +1 -0
- package/web/dist/assets/jinja-CD-Z-FLd.js +1 -0
- package/web/dist/assets/jison-imPNup1l.js +1 -0
- package/web/dist/assets/json-Bg9ijW3F.js +1 -0
- package/web/dist/assets/json5-BR5RXkoi.js +1 -0
- package/web/dist/assets/jsonc-CYpm1nAK.js +1 -0
- package/web/dist/assets/jsonl-CmCQp5Yx.js +1 -0
- package/web/dist/assets/jsonnet-CJTPZ8u_.js +1 -0
- package/web/dist/assets/jssm-DXw9l8Rf.js +1 -0
- package/web/dist/assets/jsx-CY6oMTks.js +1 -0
- package/web/dist/assets/julia-Dc3O-irA.js +1 -0
- package/web/dist/assets/just-BhOq_Kbv.js +1 -0
- package/web/dist/assets/kanagawa-dragon-CXtmUGW6.js +1 -0
- package/web/dist/assets/kanagawa-lotus-BN08jTvb.js +1 -0
- package/web/dist/assets/kanagawa-wave-CTweb8Dz.js +1 -0
- package/web/dist/assets/kdl-CsD5j6eV.js +1 -0
- package/web/dist/assets/kilo-CvN-tXHs.js +1 -0
- package/web/dist/assets/kotlin-DhhofPvG.js +1 -0
- package/web/dist/assets/kusto-C7mF5XQf.js +1 -0
- package/web/dist/assets/laserwave-C_8bwKvT.js +1 -0
- package/web/dist/assets/latex-Cu4Y1d5w.js +1 -0
- package/web/dist/assets/lean-CewbzKMR.js +1 -0
- package/web/dist/assets/less-DVTAwKKz.js +1 -0
- package/web/dist/assets/light-plus-DVQuIRkW.js +1 -0
- package/web/dist/assets/liquid-CvXMrjlQ.js +1 -0
- package/web/dist/assets/llvm-Cm23YOpf.js +1 -0
- package/web/dist/assets/log-BNLmms1o.js +1 -0
- package/web/dist/assets/logo-Cluzi2Zq.js +1 -0
- package/web/dist/assets/lua-BjLEUjKY.js +1 -0
- package/web/dist/assets/luau-FMPmPwt6.js +1 -0
- package/web/dist/assets/make-Dixweg8N.js +1 -0
- package/web/dist/assets/markdown-BYOwaDjH.js +1 -0
- package/web/dist/assets/marko-DvhNOisQ.js +1 -0
- package/web/dist/assets/material-theme-Bm3Qr25_.js +1 -0
- package/web/dist/assets/material-theme-darker-2IIEA8gg.js +1 -0
- package/web/dist/assets/material-theme-lighter-uhdI0v04.js +1 -0
- package/web/dist/assets/material-theme-ocean-CHQ94UKr.js +1 -0
- package/web/dist/assets/material-theme-palenight-B5W6OYN7.js +1 -0
- package/web/dist/assets/matlab-D7qyCx1q.js +1 -0
- package/web/dist/assets/mdc-Bm9TpL1X.js +1 -0
- package/web/dist/assets/mdx-DQZ5AkYe.js +1 -0
- package/web/dist/assets/mermaid-Bk4SNUv9.js +1 -0
- package/web/dist/assets/min-dark-BSWPekZh.js +1 -0
- package/web/dist/assets/min-light-DDpmG2fV.js +1 -0
- package/web/dist/assets/mipsasm-BMqwQI7S.js +1 -0
- package/web/dist/assets/mojo-BgCJLMeH.js +1 -0
- package/web/dist/assets/monokai-CdkpiU2Y.js +1 -0
- package/web/dist/assets/moonbit-CaWjb8XO.js +1 -0
- package/web/dist/assets/move-B1IS1UjX.js +1 -0
- package/web/dist/assets/narrat-_X_XdTYD.js +1 -0
- package/web/dist/assets/nextflow-BJtWHP5T.js +1 -0
- package/web/dist/assets/nextflow-groovy-DJMQeKeT.js +1 -0
- package/web/dist/assets/nginx-Bhc82uuv.js +1 -0
- package/web/dist/assets/night-owl-DhmEMT88.js +1 -0
- package/web/dist/assets/night-owl-light-eJ-hLW7d.js +1 -0
- package/web/dist/assets/nim-DXTVBFnF.js +1 -0
- package/web/dist/assets/nix-IvuFDN5E.js +1 -0
- package/web/dist/assets/nord-Cb4Vim4T.js +1 -0
- package/web/dist/assets/nushell-DcLAeLz5.js +1 -0
- package/web/dist/assets/objective-c-D1A_Heim.js +1 -0
- package/web/dist/assets/objective-cpp-BsSzOQcm.js +1 -0
- package/web/dist/assets/ocaml-O90oeIOV.js +1 -0
- package/web/dist/assets/odin-B1RWQWA5.js +1 -0
- package/web/dist/assets/one-dark-pro-CLwyXe_n.js +1 -0
- package/web/dist/assets/one-light-D7Lr4KcI.js +1 -0
- package/web/dist/assets/openscad-BUDT5pXO.js +1 -0
- package/web/dist/assets/pascal-4ZHwLPI5.js +1 -0
- package/web/dist/assets/perl-C7veXV9z.js +1 -0
- package/web/dist/assets/php-BRiuMnnr.js +1 -0
- package/web/dist/assets/pierre-dark-CpLgRqie.js +1 -0
- package/web/dist/assets/pierre-dark-protanopia-deuteranopia-B35FxJx-.js +1 -0
- package/web/dist/assets/pierre-dark-soft-kZQmAZld.js +1 -0
- package/web/dist/assets/pierre-dark-tritanopia-CpjhbsIL.js +1 -0
- package/web/dist/assets/pierre-dark-vibrant-CpQYzh95.js +1 -0
- package/web/dist/assets/pierre-light-CoaEpmwp.js +1 -0
- package/web/dist/assets/pierre-light-protanopia-deuteranopia-0fSaH845.js +1 -0
- package/web/dist/assets/pierre-light-soft-lWLdNTOI.js +1 -0
- package/web/dist/assets/pierre-light-tritanopia-CEbqgOJL.js +1 -0
- package/web/dist/assets/pierre-light-vibrant-D80Fkn33.js +1 -0
- package/web/dist/assets/pkl-ot-7Btpt.js +1 -0
- package/web/dist/assets/plastic-DQwYfKfQ.js +1 -0
- package/web/dist/assets/plsql-DGHpHOYJ.js +1 -0
- package/web/dist/assets/po-BiJDBrnU.js +1 -0
- package/web/dist/assets/poimandres-DRFjx7u4.js +1 -0
- package/web/dist/assets/polar-C7UOKdEL.js +1 -0
- package/web/dist/assets/postcss-BXeXVLqQ.js +1 -0
- package/web/dist/assets/powerquery-DNMTfnFr.js +1 -0
- package/web/dist/assets/powershell-DshXNtvi.js +1 -0
- package/web/dist/assets/prisma-BsRQq5mF.js +1 -0
- package/web/dist/assets/prolog-iXnhIJG7.js +1 -0
- package/web/dist/assets/proto-DB4EqR-F.js +1 -0
- package/web/dist/assets/pug-C5hz5LQ7.js +1 -0
- package/web/dist/assets/puppet-CDv2pdJW.js +1 -0
- package/web/dist/assets/purescript-9MfHhQsQ.js +1 -0
- package/web/dist/assets/python-gzcpVVnB.js +1 -0
- package/web/dist/assets/qml-BdUV3aTS.js +1 -0
- package/web/dist/assets/qmldir-DCQb3MpD.js +1 -0
- package/web/dist/assets/qss-Fe1Jh2GI.js +1 -0
- package/web/dist/assets/r-8R7vtdQc.js +1 -0
- package/web/dist/assets/racket-DcIDlBhZ.js +1 -0
- package/web/dist/assets/raku-B3gFvitq.js +1 -0
- package/web/dist/assets/razor-DRL52XO2.js +1 -0
- package/web/dist/assets/red-CJ3rzSJv.js +1 -0
- package/web/dist/assets/reg-CRGYupPL.js +1 -0
- package/web/dist/assets/regexp-Omp9DhTb.js +1 -0
- package/web/dist/assets/rel-BtDbiS_P.js +1 -0
- package/web/dist/assets/reviews-CUXp47M8.js +1 -0
- package/web/dist/assets/riscv-Ckw8ddFX.js +1 -0
- package/web/dist/assets/rolldown-runtime-QTnfLwEv.js +1 -0
- package/web/dist/assets/ron-VUp2lXgN.js +1 -0
- package/web/dist/assets/rose-pine-BthvhNj6.js +1 -0
- package/web/dist/assets/rose-pine-dawn-Dg85fqjY.js +1 -0
- package/web/dist/assets/rose-pine-moon-hon4tzzS.js +1 -0
- package/web/dist/assets/rosmsg-CAekHB0j.js +1 -0
- package/web/dist/assets/rst-BHX71KW9.js +1 -0
- package/web/dist/assets/ruby-B--HzjGU.js +1 -0
- package/web/dist/assets/rust-Cfkwpbl8.js +1 -0
- package/web/dist/assets/sas-DrLaYOK_.js +1 -0
- package/web/dist/assets/sass-DXrisJhu.js +1 -0
- package/web/dist/assets/scala-DKOlJaKm.js +1 -0
- package/web/dist/assets/scheme-DQCgrYNe.js +1 -0
- package/web/dist/assets/scss-DdSxiZKl.js +1 -0
- package/web/dist/assets/sdbl-bTVj8UrX.js +1 -0
- package/web/dist/assets/shaderlab-TOUzSsQk.js +1 -0
- package/web/dist/assets/shellscript-DwcUjJBL.js +1 -0
- package/web/dist/assets/shellsession-CPZkydE6.js +1 -0
- package/web/dist/assets/slack-dark-DnToyrRv.js +1 -0
- package/web/dist/assets/slack-ochin-B2OO5cIa.js +1 -0
- package/web/dist/assets/smalltalk-B16xEiuN.js +1 -0
- package/web/dist/assets/snazzy-light-4G7pJPwS.js +1 -0
- package/web/dist/assets/solarized-dark-DV17i1UV.js +1 -0
- package/web/dist/assets/solarized-light-DSh2HLQt.js +1 -0
- package/web/dist/assets/solidity-CKzVLygQ.js +1 -0
- package/web/dist/assets/soy-Br5FhD7c.js +1 -0
- package/web/dist/assets/sparql-D_iOobhT.js +1 -0
- package/web/dist/assets/splunk-BC2Px7Mm.js +1 -0
- package/web/dist/assets/sql-DNssxck8.js +1 -0
- package/web/dist/assets/ssh-config-BgfXC-Er.js +1 -0
- package/web/dist/assets/stata-DXn1tqOr.js +1 -0
- package/web/dist/assets/stylus-B6D30XZt.js +1 -0
- package/web/dist/assets/surfaces-Dlg1xLbg.js +1 -0
- package/web/dist/assets/surrealql-IeLNQw0f.js +1 -0
- package/web/dist/assets/svelte-DOdLCIlh.js +1 -0
- package/web/dist/assets/swift-DonLKvLd.js +1 -0
- package/web/dist/assets/synthwave-84-nFMaYfgc.js +1 -0
- package/web/dist/assets/system-verilog-DJ5XKQeo.js +1 -0
- package/web/dist/assets/systemd-BxMlprV5.js +1 -0
- package/web/dist/assets/talonscript-CohzipZa.js +1 -0
- package/web/dist/assets/tasl-DMoTqEGO.js +1 -0
- package/web/dist/assets/tcl-CZd0xW_V.js +1 -0
- package/web/dist/assets/templ-CIwIngms.js +1 -0
- package/web/dist/assets/terraform-DswuEJGm.js +1 -0
- package/web/dist/assets/tex-D8QMumu5.js +1 -0
- package/web/dist/assets/tokyo-night-oM2G3aXe.js +1 -0
- package/web/dist/assets/toml-CcmNWLt0.js +1 -0
- package/web/dist/assets/ts-tags-BMVY4q-l.js +1 -0
- package/web/dist/assets/tsv-sltzmVWM.js +1 -0
- package/web/dist/assets/tsx-5Eka4NBX.js +1 -0
- package/web/dist/assets/turtle-ByJddavk.js +1 -0
- package/web/dist/assets/twig-C8o_5mgw.js +1 -0
- package/web/dist/assets/typescript-DOu2WMV5.js +1 -0
- package/web/dist/assets/typespec-BRdr0IET.js +1 -0
- package/web/dist/assets/typst-DI99ib-x.js +1 -0
- package/web/dist/assets/v-DETTlOr0.js +1 -0
- package/web/dist/assets/vala-zf12oZj6.js +1 -0
- package/web/dist/assets/vb-Djn5o6TS.js +1 -0
- package/web/dist/assets/verilog-CiiDBU1e.js +1 -0
- package/web/dist/assets/vesper-DdrHHSXu.js +1 -0
- package/web/dist/assets/vhdl-BroJfC0k.js +1 -0
- package/web/dist/assets/viml-DvXPmvsu.js +1 -0
- package/web/dist/assets/vitesse-black-fwtXNY1n.js +1 -0
- package/web/dist/assets/vitesse-dark-BZCL-v6S.js +1 -0
- package/web/dist/assets/vitesse-light-VbXTXTou.js +1 -0
- package/web/dist/assets/vue-BU18DNDL.js +1 -0
- package/web/dist/assets/vue-html-BeluIYX0.js +1 -0
- package/web/dist/assets/vue-vine-DGUAbOCX.js +1 -0
- package/web/dist/assets/vyper-CgoNMtux.js +1 -0
- package/web/dist/assets/wasm-BnjxR4X6.js +1 -0
- package/web/dist/assets/wasm-ByWQv1Qj.js +1 -0
- package/web/dist/assets/wenyan-C8pVoKbM.js +1 -0
- package/web/dist/assets/wgsl-BsKzXJz4.js +1 -0
- package/web/dist/assets/wikitext-ClFFjSW2.js +1 -0
- package/web/dist/assets/wit-DdvCle-K.js +1 -0
- package/web/dist/assets/wolfram-DLL8P-h_.js +1 -0
- package/web/dist/assets/worker-05jVtNwz.js +160 -0
- package/web/dist/assets/xml-DIqSwXR3.js +1 -0
- package/web/dist/assets/xsl-Ct_-YIAy.js +1 -0
- package/web/dist/assets/yaml-DTtCYNlS.js +1 -0
- package/web/dist/assets/zenscript-BnlCZFoB.js +1 -0
- package/web/dist/assets/zig-CMLA9XwU.js +1 -0
- package/web/dist/icons/neondeck-icon-192.png +0 -0
- package/web/dist/icons/neondeck-icon-512.png +0 -0
- package/web/dist/icons/neondeck-icon.svg +41 -0
- package/web/dist/icons/neondeck-maskable-512.png +0 -0
- package/web/dist/index.html +27 -0
- package/web/dist/manifest.webmanifest +28 -0
|
@@ -0,0 +1,1596 @@
|
|
|
1
|
+
import { Bn as listScheduledTasks, Ci as readChatSession, Di as createChatSession, Ea as listNotifications, Fi as updateChatSessionCommandEvent, Hn as readScheduledTask, Ja as runtimePaths, Kn as nextOccurrence, Li as publishSessionEvent, O as createCiFailureDossierReport, Ta as addNotification, Va as ensureRuntimeHome, Xa as asJsonValue, Ya as openDb, ea as readRepoRegistrySnapshot, gi as fetchGitHubLogin, ia as listWorktrees, o as readAutopilotState, oi as fetchPullRequestQueue, pa as listPreparedDiffs, qn as validateAutomationTrigger, yn as listPrWatchRecords } from "./autopilot-B8lfWyA1.js";
|
|
2
|
+
import { l as startPrReview } from "./pr-reviews-BtJ5cm5P.js";
|
|
3
|
+
import { defineAction, dispatch } from "@flue/runtime";
|
|
4
|
+
import { randomUUID } from "node:crypto";
|
|
5
|
+
import * as v from "valibot";
|
|
6
|
+
//#region src/modules/briefings/schemas.ts
|
|
7
|
+
var defaultBriefingProfileId = "morning";
|
|
8
|
+
var defaultBriefingInstructions = "Summarize what needs my attention today. Prioritize review requests, failing checks, blocked automation, and time-sensitive follow-up. Keep the briefing concise and distinguish observed facts from inference.";
|
|
9
|
+
var defaultBriefingSchedule = "0 8 * * 1-5";
|
|
10
|
+
var nonEmptyStringSchema = v.pipe(v.string(), v.trim(), v.minLength(1));
|
|
11
|
+
var timezoneSchema = v.pipe(nonEmptyStringSchema, v.check((value) => {
|
|
12
|
+
try {
|
|
13
|
+
new Intl.DateTimeFormat("en-US", { timeZone: value });
|
|
14
|
+
return true;
|
|
15
|
+
} catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}, "Timezone must be a valid IANA timezone."));
|
|
19
|
+
var briefingProfileUpdateSchema = v.object({
|
|
20
|
+
id: v.optional(v.pipe(nonEmptyStringSchema, v.maxLength(64))),
|
|
21
|
+
name: v.optional(v.pipe(nonEmptyStringSchema, v.maxLength(96))),
|
|
22
|
+
enabled: v.optional(v.boolean()),
|
|
23
|
+
instructions: v.optional(v.pipe(nonEmptyStringSchema, v.maxLength(8e3))),
|
|
24
|
+
schedule: v.optional(v.pipe(nonEmptyStringSchema, v.maxLength(160))),
|
|
25
|
+
timezone: v.optional(timezoneSchema)
|
|
26
|
+
});
|
|
27
|
+
var briefingRunNowSchema = v.object({
|
|
28
|
+
profileId: v.optional(v.pipe(nonEmptyStringSchema, v.maxLength(64))),
|
|
29
|
+
sessionId: v.optional(nonEmptyStringSchema),
|
|
30
|
+
commandEventId: v.optional(nonEmptyStringSchema),
|
|
31
|
+
trigger: v.optional(v.picklist(["manual", "dashboard"]))
|
|
32
|
+
});
|
|
33
|
+
var briefingWorkflowInputSchema = v.object({
|
|
34
|
+
profileId: v.optional(v.pipe(nonEmptyStringSchema, v.maxLength(64))),
|
|
35
|
+
taskId: v.optional(nonEmptyStringSchema),
|
|
36
|
+
sessionId: v.optional(nonEmptyStringSchema),
|
|
37
|
+
commandEventId: v.optional(nonEmptyStringSchema),
|
|
38
|
+
trigger: v.optional(v.picklist([
|
|
39
|
+
"manual",
|
|
40
|
+
"scheduled",
|
|
41
|
+
"dashboard"
|
|
42
|
+
]))
|
|
43
|
+
});
|
|
44
|
+
var briefingSnapshotSchema = v.object({
|
|
45
|
+
version: v.literal(1),
|
|
46
|
+
collectedAt: nonEmptyStringSchema,
|
|
47
|
+
byteSize: v.pipe(v.number(), v.integer(), v.minValue(0)),
|
|
48
|
+
truncated: v.boolean(),
|
|
49
|
+
sources: v.record(v.string(), v.object({
|
|
50
|
+
status: v.picklist([
|
|
51
|
+
"ok",
|
|
52
|
+
"partial",
|
|
53
|
+
"unavailable"
|
|
54
|
+
]),
|
|
55
|
+
fetchedAt: nonEmptyStringSchema,
|
|
56
|
+
truncated: v.boolean(),
|
|
57
|
+
error: v.optional(v.string()),
|
|
58
|
+
data: v.nullable(v.unknown())
|
|
59
|
+
}))
|
|
60
|
+
});
|
|
61
|
+
//#endregion
|
|
62
|
+
//#region src/modules/commands/summaries.ts
|
|
63
|
+
function compactCommandSummary(result) {
|
|
64
|
+
if (result.command === "review-queue" && result.data && typeof result.data === "object") {
|
|
65
|
+
const data = result.data;
|
|
66
|
+
return {
|
|
67
|
+
ok: result.ok,
|
|
68
|
+
command: result.command,
|
|
69
|
+
input: result.input,
|
|
70
|
+
status: result.status,
|
|
71
|
+
message: result.message,
|
|
72
|
+
fetchedAt: data.fetchedAt,
|
|
73
|
+
login: data.login,
|
|
74
|
+
repos: data.repos,
|
|
75
|
+
count: data.count,
|
|
76
|
+
truncated: data.truncated,
|
|
77
|
+
issues: data.issues,
|
|
78
|
+
triage: data.triage,
|
|
79
|
+
topActions: data.topActions
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
function completedCommand(command, input, message, data) {
|
|
85
|
+
return {
|
|
86
|
+
ok: true,
|
|
87
|
+
command,
|
|
88
|
+
input,
|
|
89
|
+
status: "completed",
|
|
90
|
+
message,
|
|
91
|
+
data: asJsonValue(data)
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function runningCommand(command, input, message, data) {
|
|
95
|
+
return {
|
|
96
|
+
ok: true,
|
|
97
|
+
command,
|
|
98
|
+
input,
|
|
99
|
+
status: "running",
|
|
100
|
+
message,
|
|
101
|
+
data: asJsonValue(data)
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function needsConfigCommand(command, input, message, details) {
|
|
105
|
+
return {
|
|
106
|
+
ok: false,
|
|
107
|
+
command,
|
|
108
|
+
input,
|
|
109
|
+
status: "needs-config",
|
|
110
|
+
message,
|
|
111
|
+
...details.errors ? { errors: details.errors } : {},
|
|
112
|
+
...details.requires ? { requires: details.requires } : {}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function failedCommand(command, input, message, details = {}) {
|
|
116
|
+
return {
|
|
117
|
+
ok: false,
|
|
118
|
+
command,
|
|
119
|
+
input,
|
|
120
|
+
status: "failed",
|
|
121
|
+
message,
|
|
122
|
+
...details.errors ? { errors: details.errors } : {},
|
|
123
|
+
...details.requires ? { requires: details.requires } : {},
|
|
124
|
+
...details.data ? { data: asJsonValue(details.data) } : {}
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
//#endregion
|
|
128
|
+
//#region src/modules/commands/utils.ts
|
|
129
|
+
var allThinkingLevels = [
|
|
130
|
+
"off",
|
|
131
|
+
"minimal",
|
|
132
|
+
"low",
|
|
133
|
+
"medium",
|
|
134
|
+
"high",
|
|
135
|
+
"xhigh"
|
|
136
|
+
];
|
|
137
|
+
function supportedReasoningLevelsForModel(model) {
|
|
138
|
+
const specifier = parseModelSpecifier(model);
|
|
139
|
+
if (!specifier) return ["off"];
|
|
140
|
+
if (specifier.provider === "openai") return isOpenAiReasoningModel(specifier.model) ? allThinkingLevels : ["off"];
|
|
141
|
+
if (specifier.provider === "anthropic") return isAnthropicReasoningModel(specifier.model) ? allThinkingLevels : ["off"];
|
|
142
|
+
if (specifier.provider === "kilocode") return isKilocodeReasoningModel(specifier.model) ? allThinkingLevels : ["off"];
|
|
143
|
+
return ["off"];
|
|
144
|
+
}
|
|
145
|
+
function parseModelSpecifier(model) {
|
|
146
|
+
const slash = model.indexOf("/");
|
|
147
|
+
if (slash <= 0 || slash === model.length - 1) return null;
|
|
148
|
+
return {
|
|
149
|
+
provider: model.slice(0, slash),
|
|
150
|
+
model: model.slice(slash + 1)
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
function isOpenAiReasoningModel(model) {
|
|
154
|
+
return /^(gpt-5|o[1-9])(?:[.-]|$)/i.test(model);
|
|
155
|
+
}
|
|
156
|
+
function isAnthropicReasoningModel(model) {
|
|
157
|
+
return /^claude-(?:.*-4|3-7)(?:[.-]|$)/i.test(model);
|
|
158
|
+
}
|
|
159
|
+
function isKilocodeReasoningModel(model) {
|
|
160
|
+
const nested = parseModelSpecifier(model);
|
|
161
|
+
if (nested?.provider === "openai") return isOpenAiReasoningModel(nested.model);
|
|
162
|
+
if (nested?.provider === "anthropic") return isAnthropicReasoningModel(nested.model);
|
|
163
|
+
return /^kilo-auto(?:\/|$)/i.test(model) || isOpenAiReasoningModel(model) || isAnthropicReasoningModel(model) || /(?:^|\/)(deepseek-r1|qwen.*thinking|.*reasoning.*)(?:[/:.-]|$)/i.test(model);
|
|
164
|
+
}
|
|
165
|
+
function formatList(values) {
|
|
166
|
+
if (values.length === 0) return "no";
|
|
167
|
+
if (values.length === 1) return values[0] ?? "";
|
|
168
|
+
return `${values.slice(0, -1).join(", ")} or ${values.at(-1)}`;
|
|
169
|
+
}
|
|
170
|
+
function isMemoryScope(value) {
|
|
171
|
+
return value === "user" || value === "local" || value === "project";
|
|
172
|
+
}
|
|
173
|
+
function isActiveMemoryScope(value) {
|
|
174
|
+
return value === "user" || value === "local" || value === "project";
|
|
175
|
+
}
|
|
176
|
+
function parseMemoryValue(raw) {
|
|
177
|
+
try {
|
|
178
|
+
return JSON.parse(raw);
|
|
179
|
+
} catch {
|
|
180
|
+
return raw;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function readStringArrayProperty(value, key) {
|
|
184
|
+
if (!value || typeof value !== "object" || !(key in value)) return void 0;
|
|
185
|
+
const property = value[key];
|
|
186
|
+
if (!Array.isArray(property)) return void 0;
|
|
187
|
+
return property.filter((item) => typeof item === "string");
|
|
188
|
+
}
|
|
189
|
+
function errorMessage(error) {
|
|
190
|
+
return error instanceof Error ? error.message : String(error);
|
|
191
|
+
}
|
|
192
|
+
//#endregion
|
|
193
|
+
//#region src/modules/commands/handlers/queue.ts
|
|
194
|
+
async function reviewQueueCommand(command, paths, dependencies) {
|
|
195
|
+
const queue = await readReviewQueue(paths, dependencies);
|
|
196
|
+
if (!queue.ok) return needsConfigCommand(command.name, command.raw, queue.message, {
|
|
197
|
+
requires: queue.requires,
|
|
198
|
+
errors: queue.errors
|
|
199
|
+
});
|
|
200
|
+
const watches = await listPrWatchRecords(paths);
|
|
201
|
+
const triage = triageReviewQueue(queue.queue, watches);
|
|
202
|
+
return completedCommand(command.name, command.raw, reviewQueueMessage(triage), {
|
|
203
|
+
fetchedAt: queue.queue.fetchedAt,
|
|
204
|
+
login: queue.queue.login,
|
|
205
|
+
repos: queue.queue.repos,
|
|
206
|
+
count: queue.queue.items.length,
|
|
207
|
+
truncated: queue.queue.truncated,
|
|
208
|
+
issues: queue.queue.issues,
|
|
209
|
+
items: queue.queue.items,
|
|
210
|
+
triage,
|
|
211
|
+
topActions: triage.topActions
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
async function reviewPrCommand(command, paths, dependencies) {
|
|
215
|
+
const ref = command.args.join(" ").trim();
|
|
216
|
+
if (!ref) return failedCommand(command.name, command.raw, "/review-pr requires a PR reference.", { requires: ["ref"] });
|
|
217
|
+
const { review, reviewId, runId } = await (dependencies.startPrReview ?? startPrReview)({
|
|
218
|
+
ref,
|
|
219
|
+
origin: "chat"
|
|
220
|
+
}, paths, dependencies.invokeReviewPrWorkflow ? { invokeWorkflow: (input) => dependencies.invokeReviewPrWorkflow({
|
|
221
|
+
ref: input.ref,
|
|
222
|
+
reviewId: input.reviewId,
|
|
223
|
+
attemptId: input.attemptId
|
|
224
|
+
}) } : void 0);
|
|
225
|
+
return runningCommand(command.name, command.raw, `Reviewing ${review.repoFullName}#${review.prNumber}.`, {
|
|
226
|
+
workflow: "review-pr-for-human",
|
|
227
|
+
reviewId,
|
|
228
|
+
runId,
|
|
229
|
+
ref: review.ref,
|
|
230
|
+
queued: true,
|
|
231
|
+
reviewUrl: review.reviewUrl,
|
|
232
|
+
trustBoundary: review.trustBoundary,
|
|
233
|
+
assistantBrief: "Track the durable review record. It will transition to ready with report links and local draft counts; the human reviewer owns edits and submission."
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
async function fixCiCommand(command, paths, dependencies) {
|
|
237
|
+
const explicitRef = command.args.join(" ").trim();
|
|
238
|
+
if (explicitRef) {
|
|
239
|
+
const parsed = parsePullRequestRef(explicitRef);
|
|
240
|
+
if (!parsed) return failedCommand(command.name, command.raw, "Expected a PR reference like repo#123, owner/repo#123, or a GitHub pull request URL.", { requires: ["pr"] });
|
|
241
|
+
return queueFixCiWorkflow(command, `${parsed.repo}#${parsed.number}`, dependencies);
|
|
242
|
+
}
|
|
243
|
+
const queue = await readReviewQueue(paths, dependencies);
|
|
244
|
+
if (!queue.ok) return needsConfigCommand(command.name, command.raw, queue.message, {
|
|
245
|
+
requires: queue.requires,
|
|
246
|
+
errors: queue.errors
|
|
247
|
+
});
|
|
248
|
+
const selected = selectPullRequest(queue.queue, command.args, { prefer: isCiFixCandidate });
|
|
249
|
+
if (!selected.ok) return failedCommand(command.name, command.raw, selected.message, {
|
|
250
|
+
requires: selected.requires,
|
|
251
|
+
data: { available: summarizePullRequests(queue.queue.items).slice(0, 10) }
|
|
252
|
+
});
|
|
253
|
+
if (!isCiFixCandidate(selected.item)) return failedCommand(command.name, command.raw, `${selected.item.repo}#${selected.item.number} does not have failing or unknown CI checks.`, {
|
|
254
|
+
requires: ["failingChecks"],
|
|
255
|
+
data: { pr: summarizePullRequests([selected.item])[0] }
|
|
256
|
+
});
|
|
257
|
+
return queueFixCiWorkflow(command, `${selected.item.repo}#${selected.item.number}`, dependencies);
|
|
258
|
+
}
|
|
259
|
+
async function queueFixCiWorkflow(command, ref, dependencies) {
|
|
260
|
+
const { runId } = await (dependencies.invokeFixCiWorkflow ?? invokeFixCiWorkflow)({ ref });
|
|
261
|
+
return completedCommand(command.name, command.raw, `Queued CI fix workflow ${runId} for ${ref}.`, {
|
|
262
|
+
workflow: "fix-pr-ci",
|
|
263
|
+
runId,
|
|
264
|
+
ref,
|
|
265
|
+
queued: true,
|
|
266
|
+
reportUrlHint: "/reports",
|
|
267
|
+
trustBoundary: "The workflow can create local reports, a managed local worktree, a Kilo task, and a prepared diff only; it does not push, comment, or submit a GitHub review.",
|
|
268
|
+
assistantBrief: "Track the returned workflow run id. The dossier report is local; any code changes must pass through the prepared-diff review loop."
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
async function invokeFixCiWorkflow(input) {
|
|
272
|
+
const { invoke } = await import("@flue/runtime");
|
|
273
|
+
return invoke((await import("./fix-pr-ci-P3dLxmbx.js")).default, { input });
|
|
274
|
+
}
|
|
275
|
+
async function explainCiCommand(command, paths, dependencies) {
|
|
276
|
+
const options = parseExplainCiArgs(command.args);
|
|
277
|
+
const queue = await readReviewQueue(paths, dependencies);
|
|
278
|
+
if (!queue.ok) return needsConfigCommand(command.name, command.raw, queue.message, {
|
|
279
|
+
requires: queue.requires,
|
|
280
|
+
errors: queue.errors
|
|
281
|
+
});
|
|
282
|
+
const selected = selectPullRequest(queue.queue, options.args, { prefer: (item) => item.checks?.status === "failure" || item.checkError !== void 0 || item.checks?.status === "pending" });
|
|
283
|
+
if (!selected.ok) return failedCommand(command.name, command.raw, selected.message, {
|
|
284
|
+
requires: selected.requires,
|
|
285
|
+
data: { available: summarizePullRequests(queue.queue.items).slice(0, 10) }
|
|
286
|
+
});
|
|
287
|
+
const pr = selected.item;
|
|
288
|
+
const explanation = ciExplanation(pr);
|
|
289
|
+
if (options.report) {
|
|
290
|
+
const report = await (dependencies.createCiFailureDossierReport ?? createCiFailureDossierReport)({
|
|
291
|
+
ref: `${pr.repo}#${pr.number}`,
|
|
292
|
+
reportOnly: true
|
|
293
|
+
}, paths);
|
|
294
|
+
if (!report.ok) {
|
|
295
|
+
const requires = "requires" in report ? report.requires : void 0;
|
|
296
|
+
const errors = "errors" in report ? report.errors : void 0;
|
|
297
|
+
return requires?.includes("GITHUB_TOKEN") ? needsConfigCommand(command.name, command.raw, report.message, {
|
|
298
|
+
requires,
|
|
299
|
+
errors
|
|
300
|
+
}) : failedCommand(command.name, command.raw, report.message, {
|
|
301
|
+
requires,
|
|
302
|
+
errors
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
if (!("report" in report)) return failedCommand(command.name, command.raw, "CI dossier report writer did not return a report record.", { requires: ["report"] });
|
|
306
|
+
return completedCommand(command.name, command.raw, `${explanation.message} Created CI dossier report ${report.report.id}.`, {
|
|
307
|
+
pr: summarizePullRequests([pr])[0],
|
|
308
|
+
checks: pr.checks,
|
|
309
|
+
checkError: pr.checkError,
|
|
310
|
+
explanation,
|
|
311
|
+
report: {
|
|
312
|
+
id: report.report.id,
|
|
313
|
+
kind: report.report.kind,
|
|
314
|
+
title: report.report.title,
|
|
315
|
+
url: `/reports/${report.report.id}`
|
|
316
|
+
},
|
|
317
|
+
assistantBrief: "Use the deterministic CI dossier report and queue facts first. Separate observed facts from likely next debugging steps."
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
return completedCommand(command.name, command.raw, explanation.message, {
|
|
321
|
+
pr: summarizePullRequests([pr])[0],
|
|
322
|
+
checks: pr.checks,
|
|
323
|
+
checkError: pr.checkError,
|
|
324
|
+
explanation,
|
|
325
|
+
assistantBrief: "Use these deterministic CI/check facts first. Separate observed facts from likely next debugging steps."
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
function parseExplainCiArgs(args) {
|
|
329
|
+
return {
|
|
330
|
+
report: args.includes("--report"),
|
|
331
|
+
args: args.filter((arg) => arg !== "--report")
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
async function summarizePrCommand(command, paths, dependencies) {
|
|
335
|
+
const queue = await readReviewQueue(paths, dependencies);
|
|
336
|
+
if (!queue.ok) return needsConfigCommand(command.name, command.raw, queue.message, {
|
|
337
|
+
requires: queue.requires,
|
|
338
|
+
errors: queue.errors
|
|
339
|
+
});
|
|
340
|
+
const selected = selectPullRequest(queue.queue, command.args);
|
|
341
|
+
if (!selected.ok) return failedCommand(command.name, command.raw, selected.message, {
|
|
342
|
+
requires: selected.requires,
|
|
343
|
+
data: { available: summarizePullRequests(queue.queue.items).slice(0, 10) }
|
|
344
|
+
});
|
|
345
|
+
const pr = selected.item;
|
|
346
|
+
const summary = {
|
|
347
|
+
headline: `${pr.repo}#${pr.number}: ${pr.title}`,
|
|
348
|
+
state: pr.state,
|
|
349
|
+
author: pr.author,
|
|
350
|
+
relations: pr.relations,
|
|
351
|
+
labels: pr.labels,
|
|
352
|
+
comments: pr.comments,
|
|
353
|
+
ageDays: pr.ageDays,
|
|
354
|
+
stale: pr.stale,
|
|
355
|
+
baseRef: pr.baseRef,
|
|
356
|
+
headSha: pr.headSha,
|
|
357
|
+
checks: pr.checks?.status ?? "unknown",
|
|
358
|
+
url: pr.url
|
|
359
|
+
};
|
|
360
|
+
return completedCommand(command.name, command.raw, `Summarized ${pr.repo}#${pr.number}.`, {
|
|
361
|
+
pr: summarizePullRequests([pr])[0],
|
|
362
|
+
summary,
|
|
363
|
+
assistantBrief: "Summarize the PR from these deterministic facts. Do not invent diff contents that were not fetched."
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
function triageReviewQueue(queue, watches) {
|
|
367
|
+
const authored = queue.items.filter((item) => item.relations.includes("authored"));
|
|
368
|
+
const assigned = queue.items.filter((item) => item.relations.includes("assigned"));
|
|
369
|
+
const requestedReviews = queue.items.filter((item) => item.relations.includes("review-requested"));
|
|
370
|
+
const failedChecks = queue.items.filter((item) => item.checks?.status === "failure");
|
|
371
|
+
const checkErrors = queue.items.filter((item) => item.checkError);
|
|
372
|
+
const stalePrs = queue.items.filter((item) => item.stale);
|
|
373
|
+
const activeWatches = watches.filter((watch) => [
|
|
374
|
+
"watching",
|
|
375
|
+
"merged",
|
|
376
|
+
"attention-needed"
|
|
377
|
+
].includes(watch.status));
|
|
378
|
+
const watchedPrs = queue.items.filter((item) => activeWatches.some((watch) => watch.repoFullName === item.repo && watch.prNumber === item.number));
|
|
379
|
+
return {
|
|
380
|
+
summary: {
|
|
381
|
+
authored: authored.length,
|
|
382
|
+
assigned: assigned.length,
|
|
383
|
+
requestedReviews: requestedReviews.length,
|
|
384
|
+
failedChecks: failedChecks.length,
|
|
385
|
+
checkErrors: checkErrors.length,
|
|
386
|
+
stale: stalePrs.length,
|
|
387
|
+
activeWatches: activeWatches.length,
|
|
388
|
+
watchedPrs: watchedPrs.length,
|
|
389
|
+
truncated: queue.truncated,
|
|
390
|
+
issues: queue.issues.length
|
|
391
|
+
},
|
|
392
|
+
authored: summarizePullRequests(authored),
|
|
393
|
+
assigned: summarizePullRequests(assigned),
|
|
394
|
+
requestedReviews: summarizePullRequests(requestedReviews),
|
|
395
|
+
failedChecks: summarizePullRequests(failedChecks),
|
|
396
|
+
checkErrors: summarizePullRequests(checkErrors),
|
|
397
|
+
stalePrs: summarizePullRequests(stalePrs),
|
|
398
|
+
issues: summarizeQueueIssues(queue.issues),
|
|
399
|
+
activeWatches: activeWatches.map((watch) => ({
|
|
400
|
+
id: watch.id,
|
|
401
|
+
repo: watch.repoFullName,
|
|
402
|
+
number: watch.prNumber,
|
|
403
|
+
status: watch.status,
|
|
404
|
+
desiredTerminalState: watch.desiredTerminalState,
|
|
405
|
+
url: watch.url,
|
|
406
|
+
updatedAt: watch.updatedAt
|
|
407
|
+
})),
|
|
408
|
+
topActions: rankReviewQueueActions(queue.items, activeWatches, failedChecks, checkErrors, requestedReviews, assigned, stalePrs, authored).slice(0, 3)
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
function summarizePullRequests(items) {
|
|
412
|
+
return items.map((item) => ({
|
|
413
|
+
repo: item.repo,
|
|
414
|
+
number: item.number,
|
|
415
|
+
title: item.title,
|
|
416
|
+
url: item.url,
|
|
417
|
+
author: item.author,
|
|
418
|
+
relations: item.relations,
|
|
419
|
+
checks: item.checks?.status ?? "unknown",
|
|
420
|
+
checkError: item.checkError,
|
|
421
|
+
stale: item.stale,
|
|
422
|
+
ageDays: item.ageDays,
|
|
423
|
+
updatedAt: item.updatedAt
|
|
424
|
+
}));
|
|
425
|
+
}
|
|
426
|
+
function summarizeQueueIssues(issues) {
|
|
427
|
+
return issues.map((issue) => ({
|
|
428
|
+
type: issue.type,
|
|
429
|
+
message: issue.message,
|
|
430
|
+
query: issue.query,
|
|
431
|
+
repo: issue.repo,
|
|
432
|
+
number: issue.number
|
|
433
|
+
}));
|
|
434
|
+
}
|
|
435
|
+
function rankReviewQueueActions(items, watches, failedChecks, checkErrors, requestedReviews, assigned, stalePrs, authored) {
|
|
436
|
+
const actions = [];
|
|
437
|
+
for (const item of failedChecks) actions.push(prAction(item, "Fix failing checks", "urgent"));
|
|
438
|
+
for (const item of checkErrors) actions.push(prAction(item, "Investigate unknown CI status", "urgent"));
|
|
439
|
+
for (const watch of watches.filter((item) => item.status === "attention-needed")) actions.push({
|
|
440
|
+
title: `Resolve watch ${watch.id}`,
|
|
441
|
+
reason: `Watch is ${watch.status}.`,
|
|
442
|
+
priority: "urgent",
|
|
443
|
+
url: watch.url,
|
|
444
|
+
repo: watch.repoFullName,
|
|
445
|
+
number: watch.prNumber
|
|
446
|
+
});
|
|
447
|
+
for (const item of requestedReviews) actions.push(prAction(item, "Review requested PR", "high"));
|
|
448
|
+
for (const item of assigned) actions.push(prAction(item, "Move assigned PR forward", "high"));
|
|
449
|
+
for (const item of stalePrs) actions.push(prAction(item, "Refresh stale PR", "medium"));
|
|
450
|
+
for (const item of authored) actions.push(prAction(item, "Advance authored PR", "medium"));
|
|
451
|
+
for (const item of items) actions.push(prAction(item, "Inspect open PR", "low"));
|
|
452
|
+
return dedupeActions(actions);
|
|
453
|
+
}
|
|
454
|
+
function prAction(item, reason, priority) {
|
|
455
|
+
return {
|
|
456
|
+
title: `${reason}: ${item.repo}#${item.number}`,
|
|
457
|
+
reason: item.checks?.status === "failure" ? `${item.checks.failed} checks failed.` : item.checkError ? `GitHub enrichment failed: ${item.checkError}` : reason,
|
|
458
|
+
priority,
|
|
459
|
+
url: item.url,
|
|
460
|
+
repo: item.repo,
|
|
461
|
+
number: item.number
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
function dedupeActions(actions) {
|
|
465
|
+
const seen = /* @__PURE__ */ new Set();
|
|
466
|
+
return actions.filter((action) => {
|
|
467
|
+
const key = action.repo && action.number ? `${action.repo}#${action.number}` : `${action.title}:${action.reason}`;
|
|
468
|
+
if (seen.has(key)) return false;
|
|
469
|
+
seen.add(key);
|
|
470
|
+
return true;
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
function isCiFixCandidate(item) {
|
|
474
|
+
return item.checks?.status === "failure" || item.checkError !== void 0;
|
|
475
|
+
}
|
|
476
|
+
function reviewQueueMessage(triage) {
|
|
477
|
+
const { summary } = triage;
|
|
478
|
+
const partial = summary.truncated || summary.issues > 0;
|
|
479
|
+
return `Triaged ${summary.authored + summary.assigned + summary.requestedReviews} user-related PR signal${summary.authored + summary.assigned + summary.requestedReviews === 1 ? "" : "s"}: ${summary.requestedReviews} review request${summary.requestedReviews === 1 ? "" : "s"}, ${summary.failedChecks} failing check set${summary.failedChecks === 1 ? "" : "s"}, ${summary.checkErrors} unknown check state${summary.checkErrors === 1 ? "" : "s"}, ${summary.stale} stale PR${summary.stale === 1 ? "" : "s"}.${partial ? " Results are partial; inspect queue issues." : ""}`;
|
|
480
|
+
}
|
|
481
|
+
function selectPullRequest(queue, args, options = {}) {
|
|
482
|
+
const ref = args.join(" ").trim();
|
|
483
|
+
if (ref) {
|
|
484
|
+
const parsed = parsePullRequestRef(ref);
|
|
485
|
+
if (!parsed) return {
|
|
486
|
+
ok: false,
|
|
487
|
+
message: "Expected a PR reference like repo#123, owner/repo#123, or a GitHub pull request URL.",
|
|
488
|
+
requires: ["pr"]
|
|
489
|
+
};
|
|
490
|
+
const match = queue.items.find((item) => item.number === parsed.number && (item.repo.toLowerCase() === parsed.repo.toLowerCase() || item.repo.split("/").at(1)?.toLowerCase() === parsed.repo.toLowerCase()));
|
|
491
|
+
if (!match) return {
|
|
492
|
+
ok: false,
|
|
493
|
+
message: `PR ${parsed.repo}#${parsed.number} was not found in the current review queue.`,
|
|
494
|
+
requires: ["queuedPr"]
|
|
495
|
+
};
|
|
496
|
+
return {
|
|
497
|
+
ok: true,
|
|
498
|
+
item: match
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
const item = (options.prefer ? queue.items.find(options.prefer) : void 0) ?? queue.items[0];
|
|
502
|
+
if (!item) return {
|
|
503
|
+
ok: false,
|
|
504
|
+
message: "No pull requests are available in the current review queue.",
|
|
505
|
+
requires: ["pr"]
|
|
506
|
+
};
|
|
507
|
+
return {
|
|
508
|
+
ok: true,
|
|
509
|
+
item
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
function parsePullRequestRef(ref) {
|
|
513
|
+
const url = ref.match(/github\.com\/([^/\s]+)\/([^/\s]+)\/pull\/(\d+)/i);
|
|
514
|
+
if (url) return {
|
|
515
|
+
repo: `${url[1]}/${url[2].replace(/\.git$/, "")}`,
|
|
516
|
+
number: Number(url[3])
|
|
517
|
+
};
|
|
518
|
+
const hash = ref.match(/^([A-Za-z0-9_.-]+(?:\/[A-Za-z0-9_.-]+)?)#(\d+)$/);
|
|
519
|
+
if (!hash) return void 0;
|
|
520
|
+
return {
|
|
521
|
+
repo: hash[1],
|
|
522
|
+
number: Number(hash[2])
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
function ciExplanation(pr) {
|
|
526
|
+
if (pr.checkError) return {
|
|
527
|
+
status: "unknown",
|
|
528
|
+
message: `GitHub check status for ${pr.repo}#${pr.number} could not be enriched.`,
|
|
529
|
+
facts: [`Enrichment error: ${pr.checkError}`],
|
|
530
|
+
nextActions: ["Open the PR checks page in GitHub.", "Retry after confirming the token can read checks."]
|
|
531
|
+
};
|
|
532
|
+
if (!pr.checks) return {
|
|
533
|
+
status: "unknown",
|
|
534
|
+
message: `${pr.repo}#${pr.number} has no check summary in the queue.`,
|
|
535
|
+
facts: ["No check runs or commit statuses were available."],
|
|
536
|
+
nextActions: ["Confirm the PR head SHA and configured repository access."]
|
|
537
|
+
};
|
|
538
|
+
const facts = [
|
|
539
|
+
`${pr.checks.total} total check signal${pr.checks.total === 1 ? "" : "s"}.`,
|
|
540
|
+
`${pr.checks.failed} failed, ${pr.checks.pending} pending, ${pr.checks.successful} successful.`,
|
|
541
|
+
`${pr.checks.statusContexts ?? 0} legacy status context${pr.checks.statusContexts === 1 ? "" : "s"}.`
|
|
542
|
+
];
|
|
543
|
+
const nextActions = pr.checks.status === "failure" ? [
|
|
544
|
+
"Open the failing GitHub checks and inspect the first failed job log.",
|
|
545
|
+
"Run the matching local validation command if the repo exposes one.",
|
|
546
|
+
"After fixing, rerun failed checks or push an update."
|
|
547
|
+
] : pr.checks.status === "pending" ? ["Wait for pending checks or inspect queued jobs for capacity issues."] : pr.checks.status === "success" ? ["No CI action is needed unless review feedback remains."] : ["Confirm whether this repo is expected to publish checks."];
|
|
548
|
+
return {
|
|
549
|
+
status: pr.checks.status,
|
|
550
|
+
message: `${pr.repo}#${pr.number} CI is ${pr.checks.status}.`,
|
|
551
|
+
facts,
|
|
552
|
+
nextActions
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
async function readReviewQueue(paths, dependencies) {
|
|
556
|
+
const token = process.env.GITHUB_TOKEN;
|
|
557
|
+
if (!token) return {
|
|
558
|
+
ok: false,
|
|
559
|
+
message: "GITHUB_TOKEN is not configured.",
|
|
560
|
+
requires: ["GITHUB_TOKEN"]
|
|
561
|
+
};
|
|
562
|
+
try {
|
|
563
|
+
const registry = await readRepoRegistrySnapshot(paths);
|
|
564
|
+
const fetchLogin = dependencies.fetchGitHubLogin ?? fetchGitHubLogin;
|
|
565
|
+
return {
|
|
566
|
+
ok: true,
|
|
567
|
+
queue: await (dependencies.fetchPullRequestQueue ?? fetchPullRequestQueue)({
|
|
568
|
+
token,
|
|
569
|
+
login: process.env.GITHUB_LOGIN ?? await fetchLogin(token),
|
|
570
|
+
repos: registry.repos
|
|
571
|
+
})
|
|
572
|
+
};
|
|
573
|
+
} catch (error) {
|
|
574
|
+
return {
|
|
575
|
+
ok: false,
|
|
576
|
+
message: "Could not fetch GitHub review queue.",
|
|
577
|
+
errors: [errorMessage(error)]
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
//#endregion
|
|
582
|
+
//#region src/modules/hygiene/service.ts
|
|
583
|
+
async function readHygieneSummary(paths) {
|
|
584
|
+
const [worktrees, preparedDiffs, watches] = await Promise.all([
|
|
585
|
+
listWorktrees(paths),
|
|
586
|
+
listPreparedDiffs({}, paths),
|
|
587
|
+
listPrWatchRecords(paths)
|
|
588
|
+
]);
|
|
589
|
+
const unusedApprovals = countUnusedExecutionApprovals(paths);
|
|
590
|
+
return {
|
|
591
|
+
worktreeCleanupCandidates: worktrees.worktrees.filter((worktree) => [
|
|
592
|
+
"cleanup-pending",
|
|
593
|
+
"failed",
|
|
594
|
+
"needs-sync"
|
|
595
|
+
].includes(worktree.lifecycleStatus)).length,
|
|
596
|
+
stalledPreparedDiffs: (preparedDiffs.preparedDiffs ?? []).filter((diff) => [
|
|
597
|
+
"prepared",
|
|
598
|
+
"revision-requested",
|
|
599
|
+
"push-approved"
|
|
600
|
+
].includes(diff.status)).length,
|
|
601
|
+
closedOrMergedWatches: watches.filter((watch) => ["closed", "merged"].includes(watch.status)).length,
|
|
602
|
+
unusedExecutionApprovals: unusedApprovals
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
function countUnusedExecutionApprovals(paths) {
|
|
606
|
+
const database = openDb(paths.neondeckDatabase, { readOnly: true });
|
|
607
|
+
try {
|
|
608
|
+
const row = database.prepare(`
|
|
609
|
+
SELECT COUNT(*) AS count
|
|
610
|
+
FROM execution_approvals
|
|
611
|
+
WHERE status = 'approved'
|
|
612
|
+
AND used_at IS NULL;
|
|
613
|
+
`).get();
|
|
614
|
+
return typeof row?.count === "number" ? row.count : 0;
|
|
615
|
+
} finally {
|
|
616
|
+
database.close();
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
//#endregion
|
|
620
|
+
//#region src/modules/briefings/snapshot.ts
|
|
621
|
+
var collectionLimit = 40;
|
|
622
|
+
var snapshotByteLimit = 96e3;
|
|
623
|
+
async function collectBriefingSnapshot(paths, dependencies = {}) {
|
|
624
|
+
const collectedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
625
|
+
const [repos, reviewQueue, watches, tasks, notifications, hygiene, autopilot] = await Promise.all([
|
|
626
|
+
capture("repos", async () => {
|
|
627
|
+
return boundedList((await (dependencies.readRepos ?? readRepoRegistrySnapshot)(paths)).repos.map((repo) => ({
|
|
628
|
+
id: repo.id,
|
|
629
|
+
fullName: `${repo.github.owner}/${repo.github.name}`,
|
|
630
|
+
localPath: repo.path
|
|
631
|
+
})));
|
|
632
|
+
}),
|
|
633
|
+
capture("reviewQueue", async () => {
|
|
634
|
+
const result = await readReviewQueue(paths, dependencies);
|
|
635
|
+
if (!result.ok) return {
|
|
636
|
+
data: {
|
|
637
|
+
available: false,
|
|
638
|
+
message: result.message,
|
|
639
|
+
requires: result.requires ?? [],
|
|
640
|
+
errors: result.errors ?? []
|
|
641
|
+
},
|
|
642
|
+
partial: true
|
|
643
|
+
};
|
|
644
|
+
const items = result.queue.items.map((item) => ({
|
|
645
|
+
repo: item.repo,
|
|
646
|
+
number: item.number,
|
|
647
|
+
title: item.title,
|
|
648
|
+
url: item.url,
|
|
649
|
+
author: item.author,
|
|
650
|
+
checks: item.checks,
|
|
651
|
+
updatedAt: item.updatedAt
|
|
652
|
+
}));
|
|
653
|
+
return {
|
|
654
|
+
...boundedList(items),
|
|
655
|
+
data: {
|
|
656
|
+
...boundedList(items).data,
|
|
657
|
+
issues: result.queue.issues.slice(0, 12),
|
|
658
|
+
fetchedAt: result.queue.fetchedAt
|
|
659
|
+
},
|
|
660
|
+
partial: result.queue.truncated || result.queue.issues.length > 0
|
|
661
|
+
};
|
|
662
|
+
}),
|
|
663
|
+
capture("watches", async () => {
|
|
664
|
+
return boundedList((await (dependencies.readWatches ?? listPrWatchRecords)(paths)).map((watch) => ({
|
|
665
|
+
id: watch.id,
|
|
666
|
+
repoId: watch.repoId,
|
|
667
|
+
prNumber: watch.prNumber,
|
|
668
|
+
title: watch.title,
|
|
669
|
+
status: watch.status,
|
|
670
|
+
url: watch.url,
|
|
671
|
+
lastCheckedAt: watch.lastCheckedAt
|
|
672
|
+
})));
|
|
673
|
+
}),
|
|
674
|
+
capture("scheduledTasks", async () => {
|
|
675
|
+
return boundedList((await (dependencies.readTasks ?? listScheduledTasks)(paths)).map((task) => ({
|
|
676
|
+
id: task.id,
|
|
677
|
+
kind: task.spec.kind,
|
|
678
|
+
enabled: task.enabled,
|
|
679
|
+
nextRunAt: task.nextRunAt,
|
|
680
|
+
lastRunAt: task.lastRunAt
|
|
681
|
+
})));
|
|
682
|
+
}),
|
|
683
|
+
capture("notifications", async () => {
|
|
684
|
+
return boundedList((await (dependencies.readNotifications ?? listNotifications)(paths)).filter((notification) => !notification.readAt).map((notification) => ({
|
|
685
|
+
id: notification.id,
|
|
686
|
+
level: notification.level,
|
|
687
|
+
title: notification.title,
|
|
688
|
+
message: notification.message,
|
|
689
|
+
source: notification.source,
|
|
690
|
+
createdAt: notification.createdAt
|
|
691
|
+
})));
|
|
692
|
+
}),
|
|
693
|
+
capture("hygiene", async () => ({ data: await (dependencies.readHygiene ?? readHygieneSummary)(paths) })),
|
|
694
|
+
capture("autopilot", async () => {
|
|
695
|
+
const state = await (dependencies.readAutopilot ?? readAutopilotState)(paths);
|
|
696
|
+
return {
|
|
697
|
+
data: {
|
|
698
|
+
summary: state.summary,
|
|
699
|
+
queue: state.queue.slice(0, collectionLimit),
|
|
700
|
+
preparedDiffs: state.preparedDiffs.slice(0, collectionLimit),
|
|
701
|
+
pendingApprovals: state.pendingApprovals.slice(0, collectionLimit),
|
|
702
|
+
runningChecks: state.runningChecks.slice(0, collectionLimit)
|
|
703
|
+
},
|
|
704
|
+
truncated: state.queue.length > collectionLimit || state.preparedDiffs.length > collectionLimit || state.pendingApprovals.length > collectionLimit || state.runningChecks.length > collectionLimit
|
|
705
|
+
};
|
|
706
|
+
})
|
|
707
|
+
]);
|
|
708
|
+
const sources = {
|
|
709
|
+
repos,
|
|
710
|
+
reviewQueue,
|
|
711
|
+
watches,
|
|
712
|
+
scheduledTasks: tasks,
|
|
713
|
+
notifications,
|
|
714
|
+
hygiene,
|
|
715
|
+
autopilot
|
|
716
|
+
};
|
|
717
|
+
const sizedInitial = withByteSize({
|
|
718
|
+
version: 1,
|
|
719
|
+
collectedAt,
|
|
720
|
+
byteSize: 0,
|
|
721
|
+
truncated: Object.values(sources).some((source) => source.truncated),
|
|
722
|
+
sources
|
|
723
|
+
});
|
|
724
|
+
if (sizedInitial.byteSize <= snapshotByteLimit) return sizedInitial;
|
|
725
|
+
const compactSources = Object.fromEntries(Object.entries(sources).map(([name, source]) => [name, {
|
|
726
|
+
...source,
|
|
727
|
+
status: source.status === "unavailable" ? "unavailable" : "partial",
|
|
728
|
+
truncated: true,
|
|
729
|
+
...source.error ? { error: truncateText(source.error, 1e3) } : {},
|
|
730
|
+
data: asJsonValue(compactData(source.data))
|
|
731
|
+
}]));
|
|
732
|
+
const compact = {
|
|
733
|
+
version: 1,
|
|
734
|
+
collectedAt,
|
|
735
|
+
byteSize: 0,
|
|
736
|
+
truncated: true,
|
|
737
|
+
sources: compactSources
|
|
738
|
+
};
|
|
739
|
+
const sizedCompact = withByteSize(compact);
|
|
740
|
+
if (sizedCompact.byteSize <= snapshotByteLimit) return sizedCompact;
|
|
741
|
+
return withByteSize({
|
|
742
|
+
...compact,
|
|
743
|
+
sources: Object.fromEntries(Object.entries(compactSources).map(([name, source]) => [name, {
|
|
744
|
+
...source,
|
|
745
|
+
data: null,
|
|
746
|
+
error: source.error ? truncateText(source.error, 300) : void 0
|
|
747
|
+
}]))
|
|
748
|
+
});
|
|
749
|
+
}
|
|
750
|
+
async function capture(_name, read) {
|
|
751
|
+
const fetchedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
752
|
+
try {
|
|
753
|
+
const result = await read();
|
|
754
|
+
return {
|
|
755
|
+
status: result.partial || result.truncated ? "partial" : "ok",
|
|
756
|
+
fetchedAt,
|
|
757
|
+
truncated: Boolean(result.truncated),
|
|
758
|
+
data: asJsonValue(result.data)
|
|
759
|
+
};
|
|
760
|
+
} catch (error) {
|
|
761
|
+
return {
|
|
762
|
+
status: "unavailable",
|
|
763
|
+
fetchedAt,
|
|
764
|
+
truncated: false,
|
|
765
|
+
error: truncateText(error instanceof Error ? error.message : String(error), 1e3),
|
|
766
|
+
data: null
|
|
767
|
+
};
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
function withByteSize(snapshot) {
|
|
771
|
+
let candidate = snapshot;
|
|
772
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
773
|
+
const byteSize = Buffer.byteLength(JSON.stringify(candidate), "utf8");
|
|
774
|
+
if (byteSize === candidate.byteSize) return candidate;
|
|
775
|
+
candidate = {
|
|
776
|
+
...candidate,
|
|
777
|
+
byteSize
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
return candidate;
|
|
781
|
+
}
|
|
782
|
+
function truncateText(value, limit) {
|
|
783
|
+
return value.length > limit ? `${value.slice(0, limit - 3)}...` : value;
|
|
784
|
+
}
|
|
785
|
+
function boundedList(items) {
|
|
786
|
+
return {
|
|
787
|
+
data: {
|
|
788
|
+
total: items.length,
|
|
789
|
+
items: items.slice(0, collectionLimit)
|
|
790
|
+
},
|
|
791
|
+
truncated: items.length > collectionLimit
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
function compactData(data, depth = 0) {
|
|
795
|
+
if (typeof data === "string") return data.length > 300 ? `${data.slice(0, 297)}...` : data;
|
|
796
|
+
if (data === null || typeof data === "number" || typeof data === "boolean" || data === void 0) return data ?? null;
|
|
797
|
+
if (depth >= 3) return Array.isArray(data) ? {
|
|
798
|
+
total: data.length,
|
|
799
|
+
truncated: true
|
|
800
|
+
} : { truncated: true };
|
|
801
|
+
if (Array.isArray(data)) return data.slice(0, 3).map((value) => compactData(value, depth + 1));
|
|
802
|
+
if (typeof data !== "object") return String(data);
|
|
803
|
+
return Object.fromEntries(Object.entries(data).slice(0, 3).map(([key, value]) => [key, compactData(value, depth + 1)]));
|
|
804
|
+
}
|
|
805
|
+
//#endregion
|
|
806
|
+
//#region src/modules/briefings/store.ts
|
|
807
|
+
var nullableString = v.nullable(v.string());
|
|
808
|
+
var persistedProfileSchema = v.object({
|
|
809
|
+
id: v.string(),
|
|
810
|
+
name: v.string(),
|
|
811
|
+
enabled: v.number(),
|
|
812
|
+
instructions: v.string(),
|
|
813
|
+
instructions_version: v.number(),
|
|
814
|
+
schedule: v.string(),
|
|
815
|
+
timezone: v.string(),
|
|
816
|
+
session_id: nullableString,
|
|
817
|
+
created_at: v.string(),
|
|
818
|
+
updated_at: v.string()
|
|
819
|
+
});
|
|
820
|
+
var persistedRunSchema = v.object({
|
|
821
|
+
id: v.string(),
|
|
822
|
+
profile_id: nullableString,
|
|
823
|
+
trigger: v.picklist([
|
|
824
|
+
"manual",
|
|
825
|
+
"scheduled",
|
|
826
|
+
"dashboard"
|
|
827
|
+
]),
|
|
828
|
+
snapshot_json: v.string(),
|
|
829
|
+
instructions: v.string(),
|
|
830
|
+
instructions_version: v.number(),
|
|
831
|
+
session_id: v.string(),
|
|
832
|
+
command_event_id: nullableString,
|
|
833
|
+
dispatch_id: nullableString,
|
|
834
|
+
workflow_run_id: nullableString,
|
|
835
|
+
status: v.picklist([
|
|
836
|
+
"queued",
|
|
837
|
+
"ready",
|
|
838
|
+
"failed"
|
|
839
|
+
]),
|
|
840
|
+
error: nullableString,
|
|
841
|
+
queued_at: v.string(),
|
|
842
|
+
completed_at: nullableString,
|
|
843
|
+
created_at: v.string(),
|
|
844
|
+
updated_at: v.string()
|
|
845
|
+
});
|
|
846
|
+
var persistedRunMetadataSchema = v.omit(persistedRunSchema, ["snapshot_json", "instructions"]);
|
|
847
|
+
var persistedBriefingTaskSchema = v.object({
|
|
848
|
+
kind: v.string(),
|
|
849
|
+
trigger_json: v.string(),
|
|
850
|
+
next_run_at: nullableString,
|
|
851
|
+
claim_id: nullableString,
|
|
852
|
+
claim_expires_at: nullableString,
|
|
853
|
+
last_run_at: nullableString,
|
|
854
|
+
created_at: v.string()
|
|
855
|
+
});
|
|
856
|
+
async function readBriefingProfile(id = defaultBriefingProfileId, paths = runtimePaths()) {
|
|
857
|
+
await ensureRuntimeHome(paths);
|
|
858
|
+
const database = openDb(paths.neondeckDatabase);
|
|
859
|
+
try {
|
|
860
|
+
const row = database.prepare("SELECT * FROM briefing_profiles WHERE id = ?;").get(id);
|
|
861
|
+
if (row) return readProfileRow(row, false);
|
|
862
|
+
} finally {
|
|
863
|
+
database.close();
|
|
864
|
+
}
|
|
865
|
+
const compatibleTask = await readScheduledTask(`briefing:${id}`, paths);
|
|
866
|
+
const timezone = compatibleTask?.trigger.kind === "cron" ? compatibleTask.trigger.timezone : Intl.DateTimeFormat().resolvedOptions().timeZone ?? "UTC";
|
|
867
|
+
if (!compatibleTask) return (await writeBriefingProfileAndTask({
|
|
868
|
+
id,
|
|
869
|
+
name: id === "morning" ? "Morning Briefing" : id,
|
|
870
|
+
enabled: true,
|
|
871
|
+
instructions: defaultBriefingInstructions,
|
|
872
|
+
instructionsVersion: 1,
|
|
873
|
+
schedule: defaultBriefingSchedule,
|
|
874
|
+
timezone,
|
|
875
|
+
sessionId: null
|
|
876
|
+
}, paths)).profile;
|
|
877
|
+
const cron = compatibleTask?.trigger.kind === "cron" ? compatibleTask.trigger : void 0;
|
|
878
|
+
return {
|
|
879
|
+
id,
|
|
880
|
+
name: id === "morning" ? "Morning Briefing" : id,
|
|
881
|
+
enabled: compatibleTask.enabled,
|
|
882
|
+
instructions: defaultBriefingInstructions,
|
|
883
|
+
instructionsVersion: 1,
|
|
884
|
+
schedule: cron?.expression ?? "0 8 * * 1-5",
|
|
885
|
+
timezone,
|
|
886
|
+
sessionId: null,
|
|
887
|
+
compatibility: true,
|
|
888
|
+
createdAt: null,
|
|
889
|
+
updatedAt: compatibleTask?.updatedAt ?? null
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
async function writeBriefingProfileAndTask(profile, paths = runtimePaths()) {
|
|
893
|
+
await ensureRuntimeHome(paths);
|
|
894
|
+
const triggerResult = validateAutomationTrigger({
|
|
895
|
+
kind: "cron",
|
|
896
|
+
expression: profile.schedule,
|
|
897
|
+
timezone: profile.timezone
|
|
898
|
+
});
|
|
899
|
+
if (!triggerResult.ok) throw new Error(triggerResult.message);
|
|
900
|
+
const trigger = triggerResult.trigger;
|
|
901
|
+
const taskId = `briefing:${profile.id}`;
|
|
902
|
+
const spec = {
|
|
903
|
+
kind: "run-briefing",
|
|
904
|
+
briefingId: profile.id
|
|
905
|
+
};
|
|
906
|
+
const database = openDb(paths.neondeckDatabase);
|
|
907
|
+
const now = /* @__PURE__ */ new Date();
|
|
908
|
+
const nowIso = now.toISOString();
|
|
909
|
+
try {
|
|
910
|
+
database.exec("BEGIN IMMEDIATE;");
|
|
911
|
+
const beforeProfile = database.prepare("SELECT * FROM briefing_profiles WHERE id = ?;").get(profile.id);
|
|
912
|
+
const beforeTaskRow = database.prepare("SELECT * FROM scheduled_tasks WHERE id = ?;").get(taskId);
|
|
913
|
+
const beforeTask = beforeTaskRow ? parsePersisted(persistedBriefingTaskSchema, beforeTaskRow, "briefing scheduled task") : void 0;
|
|
914
|
+
if (beforeTask && beforeTask.kind !== "run-briefing") throw new Error(`Scheduled task "${taskId}" cannot be replaced with a briefing task.`);
|
|
915
|
+
const triggerJson = JSON.stringify(asJsonValue(trigger));
|
|
916
|
+
const nextRunAt = beforeTask && beforeTask.trigger_json === triggerJson ? beforeTask.next_run_at : nextOccurrence(trigger, now);
|
|
917
|
+
database.prepare(`INSERT INTO scheduled_tasks (
|
|
918
|
+
id, kind, trigger_json, payload_json, enabled, next_run_at,
|
|
919
|
+
claim_id, claim_expires_at, last_run_at, created_at, updated_at
|
|
920
|
+
) VALUES (?, 'run-briefing', ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
921
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
922
|
+
kind = excluded.kind,
|
|
923
|
+
trigger_json = excluded.trigger_json,
|
|
924
|
+
payload_json = excluded.payload_json,
|
|
925
|
+
enabled = excluded.enabled,
|
|
926
|
+
next_run_at = excluded.next_run_at,
|
|
927
|
+
updated_at = excluded.updated_at;`).run(taskId, triggerJson, JSON.stringify(asJsonValue(spec)), profile.enabled ? 1 : 0, nextRunAt, beforeTask?.claim_id ?? null, beforeTask?.claim_expires_at ?? null, beforeTask?.last_run_at ?? null, beforeTask?.created_at ?? nowIso, nowIso);
|
|
928
|
+
database.prepare(`INSERT INTO briefing_profiles (
|
|
929
|
+
id, name, enabled, instructions, instructions_version, schedule,
|
|
930
|
+
timezone, session_id, created_at, updated_at
|
|
931
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
932
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
933
|
+
name = excluded.name,
|
|
934
|
+
enabled = excluded.enabled,
|
|
935
|
+
instructions = excluded.instructions,
|
|
936
|
+
instructions_version = excluded.instructions_version,
|
|
937
|
+
schedule = excluded.schedule,
|
|
938
|
+
timezone = excluded.timezone,
|
|
939
|
+
session_id = excluded.session_id,
|
|
940
|
+
updated_at = excluded.updated_at;`).run(profile.id, profile.name, profile.enabled ? 1 : 0, profile.instructions, profile.instructionsVersion, profile.schedule, profile.timezone, profile.sessionId, nowIso, nowIso);
|
|
941
|
+
const afterProfile = database.prepare("SELECT * FROM briefing_profiles WHERE id = ?;").get(profile.id);
|
|
942
|
+
database.prepare(`INSERT INTO config_history (
|
|
943
|
+
action, file, target, before_json, after_json, changed_at
|
|
944
|
+
) VALUES ('briefing_profile_update', 'briefing_profiles', ?, ?, ?, ?);`).run(profile.id, beforeProfile ? JSON.stringify(readProfileRow(beforeProfile, false)) : null, JSON.stringify(readProfileRow(afterProfile, false)), nowIso);
|
|
945
|
+
database.exec("COMMIT;");
|
|
946
|
+
return {
|
|
947
|
+
profile: readProfileRow(afterProfile, false),
|
|
948
|
+
task: {
|
|
949
|
+
id: taskId,
|
|
950
|
+
spec,
|
|
951
|
+
trigger,
|
|
952
|
+
enabled: profile.enabled,
|
|
953
|
+
nextRunAt,
|
|
954
|
+
claimId: beforeTask?.claim_id ?? null,
|
|
955
|
+
claimExpiresAt: beforeTask?.claim_expires_at ?? null,
|
|
956
|
+
lastRunAt: beforeTask?.last_run_at ?? null,
|
|
957
|
+
createdAt: beforeTask?.created_at ?? nowIso,
|
|
958
|
+
updatedAt: nowIso
|
|
959
|
+
}
|
|
960
|
+
};
|
|
961
|
+
} catch (error) {
|
|
962
|
+
database.exec("ROLLBACK;");
|
|
963
|
+
throw error;
|
|
964
|
+
} finally {
|
|
965
|
+
database.close();
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
async function setBriefingProfileSession(id, sessionId, paths = runtimePaths()) {
|
|
969
|
+
await ensureRuntimeHome(paths);
|
|
970
|
+
const database = openDb(paths.neondeckDatabase);
|
|
971
|
+
try {
|
|
972
|
+
database.prepare("UPDATE briefing_profiles SET session_id = ?, updated_at = ? WHERE id = ?;").run(sessionId, (/* @__PURE__ */ new Date()).toISOString(), id);
|
|
973
|
+
} finally {
|
|
974
|
+
database.close();
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
async function createBriefingRun(input, paths = runtimePaths()) {
|
|
978
|
+
await ensureRuntimeHome(paths);
|
|
979
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
980
|
+
const id = `briefing:${now.replace(/\D/g, "").slice(0, 14)}:${randomUUID().slice(0, 8)}`;
|
|
981
|
+
const database = openDb(paths.neondeckDatabase);
|
|
982
|
+
try {
|
|
983
|
+
database.prepare(`INSERT INTO briefing_runs (
|
|
984
|
+
id, profile_id, trigger, snapshot_json, instructions,
|
|
985
|
+
instructions_version, session_id, command_event_id, dispatch_id,
|
|
986
|
+
workflow_run_id, status, error, queued_at, completed_at, created_at,
|
|
987
|
+
updated_at
|
|
988
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, NULL, NULL, 'queued', NULL, ?, NULL, ?, ?);`).run(id, input.profileId, input.trigger, JSON.stringify(input.snapshot), input.instructions, input.instructionsVersion, input.sessionId, input.commandEventId ?? null, now, now, now);
|
|
989
|
+
return readBriefingRun(id, paths);
|
|
990
|
+
} finally {
|
|
991
|
+
database.close();
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
async function attachBriefingDispatch(id, dispatchId, paths = runtimePaths()) {
|
|
995
|
+
const database = openDb(paths.neondeckDatabase);
|
|
996
|
+
try {
|
|
997
|
+
database.prepare("UPDATE briefing_runs SET dispatch_id = ?, updated_at = ? WHERE id = ?;").run(dispatchId, (/* @__PURE__ */ new Date()).toISOString(), id);
|
|
998
|
+
} finally {
|
|
999
|
+
database.close();
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
async function attachBriefingWorkflowRun(id, workflowRunId, paths = runtimePaths()) {
|
|
1003
|
+
const database = openDb(paths.neondeckDatabase);
|
|
1004
|
+
try {
|
|
1005
|
+
database.prepare("UPDATE briefing_runs SET workflow_run_id = ?, updated_at = ? WHERE id = ?;").run(workflowRunId, (/* @__PURE__ */ new Date()).toISOString(), id);
|
|
1006
|
+
} finally {
|
|
1007
|
+
database.close();
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
async function settleBriefingRun(dispatchId, status, error, paths = runtimePaths()) {
|
|
1011
|
+
await ensureRuntimeHome(paths);
|
|
1012
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1013
|
+
const database = openDb(paths.neondeckDatabase);
|
|
1014
|
+
try {
|
|
1015
|
+
const update = database.prepare(`UPDATE briefing_runs
|
|
1016
|
+
SET status = ?, error = ?, completed_at = ?, updated_at = ?
|
|
1017
|
+
WHERE dispatch_id = ? AND status = 'queued';`).run(status, error, now, now, dispatchId);
|
|
1018
|
+
const row = database.prepare("SELECT * FROM briefing_runs WHERE dispatch_id = ?;").get(dispatchId);
|
|
1019
|
+
return {
|
|
1020
|
+
changed: update.changes === 1,
|
|
1021
|
+
run: row ? readRunRow(row) : null
|
|
1022
|
+
};
|
|
1023
|
+
} finally {
|
|
1024
|
+
database.close();
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
async function failBriefingRunBeforeDispatch(id, error, paths = runtimePaths()) {
|
|
1028
|
+
const database = openDb(paths.neondeckDatabase);
|
|
1029
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1030
|
+
try {
|
|
1031
|
+
database.prepare(`UPDATE briefing_runs SET status = 'failed', error = ?, completed_at = ?, updated_at = ? WHERE id = ?;`).run(error, now, now, id);
|
|
1032
|
+
} finally {
|
|
1033
|
+
database.close();
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
async function readBriefingRun(id, paths = runtimePaths()) {
|
|
1037
|
+
await ensureRuntimeHome(paths);
|
|
1038
|
+
const database = openDb(paths.neondeckDatabase);
|
|
1039
|
+
try {
|
|
1040
|
+
const row = database.prepare("SELECT * FROM briefing_runs WHERE id = ?;").get(id);
|
|
1041
|
+
return row ? readRunRow(row) : null;
|
|
1042
|
+
} finally {
|
|
1043
|
+
database.close();
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
async function readBriefingRunByDispatch(dispatchId, paths = runtimePaths()) {
|
|
1047
|
+
await ensureRuntimeHome(paths);
|
|
1048
|
+
const database = openDb(paths.neondeckDatabase);
|
|
1049
|
+
try {
|
|
1050
|
+
const row = database.prepare("SELECT * FROM briefing_runs WHERE dispatch_id = ?;").get(dispatchId);
|
|
1051
|
+
return row ? readRunRow(row) : null;
|
|
1052
|
+
} finally {
|
|
1053
|
+
database.close();
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
async function listBriefingRunMetadata(paths = runtimePaths(), limit = 20) {
|
|
1057
|
+
await ensureRuntimeHome(paths);
|
|
1058
|
+
const database = openDb(paths.neondeckDatabase);
|
|
1059
|
+
try {
|
|
1060
|
+
return database.prepare(`SELECT
|
|
1061
|
+
id, profile_id, trigger, instructions_version, session_id,
|
|
1062
|
+
command_event_id, dispatch_id, workflow_run_id, status, error,
|
|
1063
|
+
queued_at, completed_at, created_at, updated_at,
|
|
1064
|
+
json_extract(snapshot_json, '$.version') AS snapshot_version,
|
|
1065
|
+
json_extract(snapshot_json, '$.collectedAt') AS snapshot_collected_at,
|
|
1066
|
+
json_extract(snapshot_json, '$.byteSize') AS snapshot_byte_size,
|
|
1067
|
+
json_extract(snapshot_json, '$.truncated') AS snapshot_truncated
|
|
1068
|
+
FROM briefing_runs
|
|
1069
|
+
ORDER BY created_at DESC
|
|
1070
|
+
LIMIT ?;`).all(limit).map(readRunMetadataRow);
|
|
1071
|
+
} finally {
|
|
1072
|
+
database.close();
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
function readProfileRow(row, compatibility) {
|
|
1076
|
+
const value = parsePersisted(persistedProfileSchema, row, "briefing profile");
|
|
1077
|
+
return {
|
|
1078
|
+
id: value.id,
|
|
1079
|
+
name: value.name,
|
|
1080
|
+
enabled: value.enabled === 1,
|
|
1081
|
+
instructions: value.instructions,
|
|
1082
|
+
instructionsVersion: value.instructions_version,
|
|
1083
|
+
schedule: value.schedule,
|
|
1084
|
+
timezone: value.timezone,
|
|
1085
|
+
sessionId: value.session_id,
|
|
1086
|
+
compatibility,
|
|
1087
|
+
createdAt: value.created_at,
|
|
1088
|
+
updatedAt: value.updated_at
|
|
1089
|
+
};
|
|
1090
|
+
}
|
|
1091
|
+
function readRunRow(row) {
|
|
1092
|
+
const value = parsePersisted(persistedRunSchema, row, "briefing run");
|
|
1093
|
+
let snapshot;
|
|
1094
|
+
try {
|
|
1095
|
+
snapshot = v.parse(briefingSnapshotSchema, JSON.parse(value.snapshot_json));
|
|
1096
|
+
} catch (error) {
|
|
1097
|
+
throw new Error(`Invalid persisted briefing snapshot for ${value.id}.`, { cause: error });
|
|
1098
|
+
}
|
|
1099
|
+
return {
|
|
1100
|
+
id: value.id,
|
|
1101
|
+
profileId: value.profile_id,
|
|
1102
|
+
trigger: value.trigger,
|
|
1103
|
+
snapshot,
|
|
1104
|
+
instructions: value.instructions,
|
|
1105
|
+
instructionsVersion: value.instructions_version,
|
|
1106
|
+
sessionId: value.session_id,
|
|
1107
|
+
commandEventId: value.command_event_id,
|
|
1108
|
+
dispatchId: value.dispatch_id,
|
|
1109
|
+
workflowRunId: value.workflow_run_id,
|
|
1110
|
+
status: value.status,
|
|
1111
|
+
error: value.error,
|
|
1112
|
+
queuedAt: value.queued_at,
|
|
1113
|
+
completedAt: value.completed_at,
|
|
1114
|
+
createdAt: value.created_at,
|
|
1115
|
+
updatedAt: value.updated_at
|
|
1116
|
+
};
|
|
1117
|
+
}
|
|
1118
|
+
function readRunMetadataRow(row) {
|
|
1119
|
+
const value = parsePersisted(v.object({
|
|
1120
|
+
...persistedRunMetadataSchema.entries,
|
|
1121
|
+
snapshot_version: v.literal(1),
|
|
1122
|
+
snapshot_collected_at: v.string(),
|
|
1123
|
+
snapshot_byte_size: v.number(),
|
|
1124
|
+
snapshot_truncated: v.number()
|
|
1125
|
+
}), row, "briefing run metadata");
|
|
1126
|
+
return {
|
|
1127
|
+
id: value.id,
|
|
1128
|
+
profileId: value.profile_id,
|
|
1129
|
+
trigger: value.trigger,
|
|
1130
|
+
instructionsVersion: value.instructions_version,
|
|
1131
|
+
sessionId: value.session_id,
|
|
1132
|
+
commandEventId: value.command_event_id,
|
|
1133
|
+
dispatchId: value.dispatch_id,
|
|
1134
|
+
workflowRunId: value.workflow_run_id,
|
|
1135
|
+
status: value.status,
|
|
1136
|
+
error: value.error,
|
|
1137
|
+
queuedAt: value.queued_at,
|
|
1138
|
+
completedAt: value.completed_at,
|
|
1139
|
+
createdAt: value.created_at,
|
|
1140
|
+
updatedAt: value.updated_at,
|
|
1141
|
+
snapshot: {
|
|
1142
|
+
version: 1,
|
|
1143
|
+
collectedAt: value.snapshot_collected_at,
|
|
1144
|
+
byteSize: value.snapshot_byte_size,
|
|
1145
|
+
truncated: value.snapshot_truncated === 1
|
|
1146
|
+
}
|
|
1147
|
+
};
|
|
1148
|
+
}
|
|
1149
|
+
function parsePersisted(schema, value, label) {
|
|
1150
|
+
try {
|
|
1151
|
+
return v.parse(schema, value);
|
|
1152
|
+
} catch (error) {
|
|
1153
|
+
throw new Error(`Invalid persisted ${label}.`, { cause: error });
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
//#endregion
|
|
1157
|
+
//#region src/modules/briefings/service.ts
|
|
1158
|
+
var pendingBriefingTerminals = /* @__PURE__ */ new Map();
|
|
1159
|
+
var pendingTerminalTtlMs = 3e4;
|
|
1160
|
+
async function readBriefingState(paths = runtimePaths()) {
|
|
1161
|
+
const profile = await readBriefingProfile(defaultBriefingProfileId, paths);
|
|
1162
|
+
const [runs, notifications, linkedSession] = await Promise.all([
|
|
1163
|
+
listBriefingRunMetadata(paths),
|
|
1164
|
+
listNotifications(paths),
|
|
1165
|
+
profile.sessionId ? readChatSession({
|
|
1166
|
+
id: profile.sessionId,
|
|
1167
|
+
reason: "briefing-state-read"
|
|
1168
|
+
}, paths) : null
|
|
1169
|
+
]);
|
|
1170
|
+
const session = linkedSession && "session" in linkedSession ? linkedSession.session : null;
|
|
1171
|
+
return {
|
|
1172
|
+
ok: true,
|
|
1173
|
+
action: "briefing_state_read",
|
|
1174
|
+
changed: false,
|
|
1175
|
+
profile,
|
|
1176
|
+
latestRun: runs[0] ?? null,
|
|
1177
|
+
runs,
|
|
1178
|
+
sessionStaleReasons: session?.staleReasons ?? [],
|
|
1179
|
+
unreadCount: notifications.filter((notification) => notification.source === "briefing" && !notification.readAt).length,
|
|
1180
|
+
fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1181
|
+
};
|
|
1182
|
+
}
|
|
1183
|
+
async function rotateBriefingSession(rawInput, paths = runtimePaths()) {
|
|
1184
|
+
const parsed = v.safeParse(v.object({ id: v.optional(v.string()) }), rawInput);
|
|
1185
|
+
if (!parsed.success) return {
|
|
1186
|
+
ok: false,
|
|
1187
|
+
action: "briefing_session_rotate",
|
|
1188
|
+
changed: false,
|
|
1189
|
+
message: "Invalid briefing session rotation request."
|
|
1190
|
+
};
|
|
1191
|
+
const profile = await readBriefingProfile(parsed.output.id ?? "morning", paths);
|
|
1192
|
+
if (profile.compatibility) await writeBriefingProfileAndTask({
|
|
1193
|
+
id: profile.id,
|
|
1194
|
+
name: profile.name,
|
|
1195
|
+
enabled: profile.enabled,
|
|
1196
|
+
instructions: profile.instructions,
|
|
1197
|
+
instructionsVersion: profile.instructionsVersion,
|
|
1198
|
+
schedule: profile.schedule,
|
|
1199
|
+
timezone: profile.timezone,
|
|
1200
|
+
sessionId: null
|
|
1201
|
+
}, paths);
|
|
1202
|
+
const created = await createChatSession({
|
|
1203
|
+
title: profile.name,
|
|
1204
|
+
kind: "briefing",
|
|
1205
|
+
linkedTaskId: `briefing:${profile.id}:rotation:${Date.now()}`,
|
|
1206
|
+
activate: false,
|
|
1207
|
+
surface: "dashboard",
|
|
1208
|
+
reason: "explicit-briefing-session-rotation",
|
|
1209
|
+
uiMetadata: { briefingProfileId: profile.id }
|
|
1210
|
+
}, paths);
|
|
1211
|
+
if (!("session" in created)) return {
|
|
1212
|
+
ok: false,
|
|
1213
|
+
action: "briefing_session_rotate",
|
|
1214
|
+
changed: false,
|
|
1215
|
+
message: "A fresh briefing conversation could not be created."
|
|
1216
|
+
};
|
|
1217
|
+
await setBriefingProfileSession(profile.id, created.session.id, paths);
|
|
1218
|
+
return {
|
|
1219
|
+
ok: true,
|
|
1220
|
+
action: "briefing_session_rotate",
|
|
1221
|
+
changed: true,
|
|
1222
|
+
message: "Started a fresh briefing conversation.",
|
|
1223
|
+
profile: await readBriefingProfile(profile.id, paths),
|
|
1224
|
+
session: created.session
|
|
1225
|
+
};
|
|
1226
|
+
}
|
|
1227
|
+
async function readBriefingRunDetails(id, paths = runtimePaths()) {
|
|
1228
|
+
const run = await readBriefingRun(id, paths);
|
|
1229
|
+
if (!run) return {
|
|
1230
|
+
ok: false,
|
|
1231
|
+
action: "briefing_run_read",
|
|
1232
|
+
changed: false,
|
|
1233
|
+
message: `Briefing run "${id}" was not found.`
|
|
1234
|
+
};
|
|
1235
|
+
return {
|
|
1236
|
+
ok: true,
|
|
1237
|
+
action: "briefing_run_read",
|
|
1238
|
+
changed: false,
|
|
1239
|
+
message: `Read briefing run "${id}".`,
|
|
1240
|
+
run
|
|
1241
|
+
};
|
|
1242
|
+
}
|
|
1243
|
+
async function updateBriefingProfile(rawInput, paths = runtimePaths()) {
|
|
1244
|
+
const parsed = v.safeParse(briefingProfileUpdateSchema, rawInput);
|
|
1245
|
+
if (!parsed.success) return {
|
|
1246
|
+
ok: false,
|
|
1247
|
+
action: "briefing_profile_update",
|
|
1248
|
+
changed: false,
|
|
1249
|
+
message: "Invalid briefing profile.",
|
|
1250
|
+
errors: [v.summarize(parsed.issues)]
|
|
1251
|
+
};
|
|
1252
|
+
const id = parsed.output.id ?? "morning";
|
|
1253
|
+
const current = await readBriefingProfile(id, paths);
|
|
1254
|
+
const instructions = parsed.output.instructions ?? current.instructions;
|
|
1255
|
+
const desired = {
|
|
1256
|
+
id,
|
|
1257
|
+
name: parsed.output.name ?? current.name,
|
|
1258
|
+
enabled: parsed.output.enabled ?? current.enabled,
|
|
1259
|
+
instructions,
|
|
1260
|
+
instructionsVersion: instructions === current.instructions ? current.instructionsVersion : current.instructionsVersion + 1,
|
|
1261
|
+
schedule: parsed.output.schedule ?? current.schedule,
|
|
1262
|
+
timezone: parsed.output.timezone ?? current.timezone,
|
|
1263
|
+
sessionId: current.sessionId
|
|
1264
|
+
};
|
|
1265
|
+
try {
|
|
1266
|
+
const updated = await writeBriefingProfileAndTask(desired, paths);
|
|
1267
|
+
return {
|
|
1268
|
+
ok: true,
|
|
1269
|
+
action: "briefing_profile_update",
|
|
1270
|
+
changed: true,
|
|
1271
|
+
message: "Updated the morning briefing profile and schedule.",
|
|
1272
|
+
profile: updated.profile,
|
|
1273
|
+
task: updated.task
|
|
1274
|
+
};
|
|
1275
|
+
} catch (error) {
|
|
1276
|
+
return {
|
|
1277
|
+
ok: false,
|
|
1278
|
+
action: "briefing_profile_update",
|
|
1279
|
+
changed: false,
|
|
1280
|
+
message: `The briefing profile was not changed: ${error instanceof Error ? error.message : String(error)}`
|
|
1281
|
+
};
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
async function runBriefingNow(rawInput, paths = runtimePaths(), dependencies = {}) {
|
|
1285
|
+
const parsed = v.safeParse(briefingRunNowSchema, rawInput);
|
|
1286
|
+
if (!parsed.success) return {
|
|
1287
|
+
ok: false,
|
|
1288
|
+
action: "briefing_run",
|
|
1289
|
+
changed: false,
|
|
1290
|
+
message: "Invalid briefing run request.",
|
|
1291
|
+
errors: [v.summarize(parsed.issues)]
|
|
1292
|
+
};
|
|
1293
|
+
try {
|
|
1294
|
+
const input = {
|
|
1295
|
+
profileId: parsed.output.profileId ?? "morning",
|
|
1296
|
+
sessionId: parsed.output.sessionId,
|
|
1297
|
+
commandEventId: parsed.output.commandEventId,
|
|
1298
|
+
trigger: parsed.output.trigger ?? "dashboard"
|
|
1299
|
+
};
|
|
1300
|
+
const { runId } = await (dependencies.invokeWorkflow ?? invokeBriefingWorkflow)(input);
|
|
1301
|
+
return {
|
|
1302
|
+
ok: true,
|
|
1303
|
+
action: "briefing_run",
|
|
1304
|
+
changed: true,
|
|
1305
|
+
message: `Briefing workflow ${runId} queued.`,
|
|
1306
|
+
workflowRunId: runId
|
|
1307
|
+
};
|
|
1308
|
+
} catch (error) {
|
|
1309
|
+
return {
|
|
1310
|
+
ok: false,
|
|
1311
|
+
action: "briefing_run",
|
|
1312
|
+
changed: false,
|
|
1313
|
+
message: error instanceof Error ? error.message : String(error)
|
|
1314
|
+
};
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
async function invokeBriefingWorkflow(input) {
|
|
1318
|
+
const { invoke } = await import("@flue/runtime");
|
|
1319
|
+
return invoke((await import("./briefing-VMdQPEGc.js")).default, { input });
|
|
1320
|
+
}
|
|
1321
|
+
async function admitBriefing(input, paths = runtimePaths(), dependencies = {}) {
|
|
1322
|
+
const profile = await readBriefingProfile(input.profileId, paths);
|
|
1323
|
+
const sessionId = input.sessionId ? await validateRequestedBriefingSession(input.sessionId, paths) : await resolveScheduledBriefingSession(profile, paths);
|
|
1324
|
+
const snapshot = await collectBriefingSnapshot(paths, dependencies);
|
|
1325
|
+
const run = await createBriefingRun({
|
|
1326
|
+
profileId: profile.id,
|
|
1327
|
+
trigger: input.trigger,
|
|
1328
|
+
snapshot,
|
|
1329
|
+
instructions: profile.instructions,
|
|
1330
|
+
instructionsVersion: profile.instructionsVersion,
|
|
1331
|
+
sessionId,
|
|
1332
|
+
commandEventId: input.commandEventId
|
|
1333
|
+
}, paths);
|
|
1334
|
+
if (!run) throw new Error("Briefing run could not be persisted.");
|
|
1335
|
+
try {
|
|
1336
|
+
const receipt = await (dependencies.dispatchAgent ?? dispatch)({
|
|
1337
|
+
agent: "display-assistant",
|
|
1338
|
+
id: sessionId,
|
|
1339
|
+
input: composeBriefingInput(run, profile)
|
|
1340
|
+
});
|
|
1341
|
+
await attachBriefingDispatch(run.id, receipt.dispatchId, paths);
|
|
1342
|
+
await reconcilePendingBriefingTerminal(receipt.dispatchId, paths);
|
|
1343
|
+
return {
|
|
1344
|
+
...run,
|
|
1345
|
+
dispatchId: receipt.dispatchId
|
|
1346
|
+
};
|
|
1347
|
+
} catch (error) {
|
|
1348
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1349
|
+
await failBriefingRunBeforeDispatch(run.id, message, paths);
|
|
1350
|
+
await addNotification({
|
|
1351
|
+
level: "attention",
|
|
1352
|
+
title: "Morning briefing failed",
|
|
1353
|
+
message: "Neon could not start the briefing conversation.",
|
|
1354
|
+
source: "briefing",
|
|
1355
|
+
sourceId: run.id,
|
|
1356
|
+
data: {
|
|
1357
|
+
runId: run.id,
|
|
1358
|
+
sessionId,
|
|
1359
|
+
error: message
|
|
1360
|
+
}
|
|
1361
|
+
}, paths);
|
|
1362
|
+
throw error;
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
async function settleBriefingObservation(event, paths = runtimePaths()) {
|
|
1366
|
+
if (!event.dispatchId) return null;
|
|
1367
|
+
const observation = event;
|
|
1368
|
+
if (observation.taskId || observation.parentSession) return null;
|
|
1369
|
+
if (typeof observation.agentName === "string" && observation.agentName !== "display-assistant") return null;
|
|
1370
|
+
if (event.type === "operation" && (event.operationKind !== "prompt" || !event.isError)) return null;
|
|
1371
|
+
const failed = event.type === "operation" ? event.isError : event.type === "submission_settled" ? event.outcome !== "completed" : false;
|
|
1372
|
+
const error = failed ? briefingObservationError(event) : null;
|
|
1373
|
+
const instanceId = typeof observation.instanceId === "string" ? observation.instanceId : "";
|
|
1374
|
+
let correlated = await readBriefingRunByDispatch(event.dispatchId, paths);
|
|
1375
|
+
if (!correlated) {
|
|
1376
|
+
const runId = briefingRunIdFromObservation(observation);
|
|
1377
|
+
if (runId) {
|
|
1378
|
+
const candidate = await readBriefingRun(runId, paths);
|
|
1379
|
+
if (candidate?.status === "queued" && (!instanceId || candidate.sessionId === instanceId)) {
|
|
1380
|
+
await attachBriefingDispatch(runId, event.dispatchId, paths);
|
|
1381
|
+
correlated = await readBriefingRunByDispatch(event.dispatchId, paths);
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
if (!correlated) {
|
|
1386
|
+
rememberPendingBriefingTerminal(paths, event.dispatchId, {
|
|
1387
|
+
failed,
|
|
1388
|
+
error,
|
|
1389
|
+
instanceId,
|
|
1390
|
+
recordedAt: Date.now()
|
|
1391
|
+
});
|
|
1392
|
+
return null;
|
|
1393
|
+
}
|
|
1394
|
+
if (instanceId && correlated.sessionId !== instanceId) return null;
|
|
1395
|
+
return finalizeBriefingTerminal(event.dispatchId, {
|
|
1396
|
+
failed,
|
|
1397
|
+
error,
|
|
1398
|
+
instanceId,
|
|
1399
|
+
recordedAt: Date.now()
|
|
1400
|
+
}, paths);
|
|
1401
|
+
}
|
|
1402
|
+
async function finalizeBriefingTerminal(dispatchId, terminal, paths) {
|
|
1403
|
+
const { failed, error } = terminal;
|
|
1404
|
+
const settled = await settleBriefingRun(dispatchId, failed ? "failed" : "ready", error, paths);
|
|
1405
|
+
if (!settled.changed || !settled.run) return settled.run;
|
|
1406
|
+
const run = settled.run;
|
|
1407
|
+
if (run.commandEventId) await updateChatSessionCommandEvent({
|
|
1408
|
+
sessionId: run.sessionId,
|
|
1409
|
+
eventId: run.commandEventId,
|
|
1410
|
+
status: failed ? "failed" : "completed",
|
|
1411
|
+
result: null,
|
|
1412
|
+
reason: "briefing-submission-settled"
|
|
1413
|
+
}, paths);
|
|
1414
|
+
await addNotification({
|
|
1415
|
+
level: failed ? "attention" : "ready",
|
|
1416
|
+
title: failed ? "Morning briefing failed" : "Morning briefing ready",
|
|
1417
|
+
message: failed ? "Neon could not complete the briefing. Open the conversation for context." : "Neon has added today's briefing to your Morning Briefing conversation.",
|
|
1418
|
+
source: "briefing",
|
|
1419
|
+
sourceId: run.id,
|
|
1420
|
+
data: {
|
|
1421
|
+
runId: run.id,
|
|
1422
|
+
sessionId: run.sessionId
|
|
1423
|
+
}
|
|
1424
|
+
}, paths);
|
|
1425
|
+
const sessionResult = await readChatSession({
|
|
1426
|
+
id: run.sessionId,
|
|
1427
|
+
reason: "briefing-submission-settled"
|
|
1428
|
+
}, paths);
|
|
1429
|
+
if ("session" in sessionResult && sessionResult.session) publishSessionEvent("updated", sessionResult.session, null);
|
|
1430
|
+
return run;
|
|
1431
|
+
}
|
|
1432
|
+
function briefingObservationError(event) {
|
|
1433
|
+
if (event.type === "submission_settled") return event.error?.message ?? `Briefing submission ${event.outcome}.`;
|
|
1434
|
+
if (event.type === "operation") {
|
|
1435
|
+
if (event.error instanceof Error) return event.error.message;
|
|
1436
|
+
if (typeof event.error === "string") return event.error;
|
|
1437
|
+
return event.errorInfo?.message ?? "Briefing model operation failed.";
|
|
1438
|
+
}
|
|
1439
|
+
return null;
|
|
1440
|
+
}
|
|
1441
|
+
async function linkBriefingWorkflowObservation(event, paths = runtimePaths()) {
|
|
1442
|
+
if (!("result" in event) || !event.result || typeof event.result !== "object") return;
|
|
1443
|
+
const briefingRunId = event.result.briefingRunId;
|
|
1444
|
+
if (typeof briefingRunId === "string") await attachBriefingWorkflowRun(briefingRunId, event.runId, paths);
|
|
1445
|
+
}
|
|
1446
|
+
function composeBriefingInput(run, profile) {
|
|
1447
|
+
const triggerLabel = run.trigger === "scheduled" ? "scheduled morning" : "manual";
|
|
1448
|
+
return [
|
|
1449
|
+
`[NEONDECK_INTERNAL_BRIEFING_INPUT v1 trigger=${run.trigger} run=${run.id}]`,
|
|
1450
|
+
`Prepare the ${triggerLabel} briefing for ${run.snapshot.collectedAt}.`,
|
|
1451
|
+
`Briefing snapshot id: ${run.id}.`,
|
|
1452
|
+
"Neondeck fact snapshot:",
|
|
1453
|
+
JSON.stringify(run.snapshot, null, 2),
|
|
1454
|
+
"User briefing instructions:",
|
|
1455
|
+
profile.instructions,
|
|
1456
|
+
"Respond to the user normally in this conversation. Use any configured MCP tools relevant to their instructions; do not assume a named external source was consulted unless you actually used it. If a deterministic or MCP source is unavailable, needs login, is denied, or awaits approval, explain that naturally and continue with the useful context you do have. Distinguish observed facts from inference. This briefing is informational; do not mutate external systems or auto-approve tool calls."
|
|
1457
|
+
].join("\n\n");
|
|
1458
|
+
}
|
|
1459
|
+
function briefingRunIdFromObservation(observation) {
|
|
1460
|
+
const agentInput = observation.agentInput;
|
|
1461
|
+
if (!agentInput || typeof agentInput !== "object") return null;
|
|
1462
|
+
const raw = agentInput.text;
|
|
1463
|
+
if (typeof raw !== "string") return null;
|
|
1464
|
+
let text = raw;
|
|
1465
|
+
if (raw.startsWith("\"")) try {
|
|
1466
|
+
const decoded = JSON.parse(raw);
|
|
1467
|
+
if (typeof decoded === "string") text = decoded;
|
|
1468
|
+
} catch {
|
|
1469
|
+
return null;
|
|
1470
|
+
}
|
|
1471
|
+
return text.match(/\[NEONDECK_INTERNAL_BRIEFING_INPUT v1 trigger=\w+ run=([^\]\s]+)\]/)?.[1] ?? null;
|
|
1472
|
+
}
|
|
1473
|
+
function pendingTerminalKey(paths, dispatchId) {
|
|
1474
|
+
return `${paths.home}:${dispatchId}`;
|
|
1475
|
+
}
|
|
1476
|
+
function rememberPendingBriefingTerminal(paths, dispatchId, terminal) {
|
|
1477
|
+
const cutoff = Date.now() - pendingTerminalTtlMs;
|
|
1478
|
+
for (const [key, value] of pendingBriefingTerminals) if (value.recordedAt < cutoff) pendingBriefingTerminals.delete(key);
|
|
1479
|
+
if (pendingBriefingTerminals.size >= 100) {
|
|
1480
|
+
const oldest = pendingBriefingTerminals.keys().next().value;
|
|
1481
|
+
if (oldest) pendingBriefingTerminals.delete(oldest);
|
|
1482
|
+
}
|
|
1483
|
+
pendingBriefingTerminals.set(pendingTerminalKey(paths, dispatchId), terminal);
|
|
1484
|
+
}
|
|
1485
|
+
async function reconcilePendingBriefingTerminal(dispatchId, paths) {
|
|
1486
|
+
const key = pendingTerminalKey(paths, dispatchId);
|
|
1487
|
+
const terminal = pendingBriefingTerminals.get(key);
|
|
1488
|
+
if (!terminal) return;
|
|
1489
|
+
pendingBriefingTerminals.delete(key);
|
|
1490
|
+
if (Date.now() - terminal.recordedAt > pendingTerminalTtlMs) return;
|
|
1491
|
+
const run = await readBriefingRunByDispatch(dispatchId, paths);
|
|
1492
|
+
if (!run || terminal.instanceId && run.sessionId !== terminal.instanceId) return;
|
|
1493
|
+
await finalizeBriefingTerminal(dispatchId, terminal, paths);
|
|
1494
|
+
}
|
|
1495
|
+
async function resolveScheduledBriefingSession(profile, paths) {
|
|
1496
|
+
if (profile.sessionId) {
|
|
1497
|
+
const existing = await readChatSession({
|
|
1498
|
+
id: profile.sessionId,
|
|
1499
|
+
reason: "scheduled-briefing-reuse"
|
|
1500
|
+
}, paths);
|
|
1501
|
+
if ("session" in existing && !existing.session.archivedAt) {
|
|
1502
|
+
if (existing.session.staleReasons.length > 0) throw new Error("The briefing conversation context is stale. Start a fresh briefing conversation before running again.");
|
|
1503
|
+
return profile.sessionId;
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
if (profile.compatibility) await writeBriefingProfileAndTask({
|
|
1507
|
+
id: profile.id,
|
|
1508
|
+
name: profile.name,
|
|
1509
|
+
enabled: profile.enabled,
|
|
1510
|
+
instructions: profile.instructions,
|
|
1511
|
+
instructionsVersion: profile.instructionsVersion,
|
|
1512
|
+
schedule: profile.schedule,
|
|
1513
|
+
timezone: profile.timezone,
|
|
1514
|
+
sessionId: null
|
|
1515
|
+
}, paths);
|
|
1516
|
+
const created = await createChatSession({
|
|
1517
|
+
title: profile.name,
|
|
1518
|
+
kind: "briefing",
|
|
1519
|
+
linkedTaskId: `briefing:${profile.id}`,
|
|
1520
|
+
activate: false,
|
|
1521
|
+
surface: "dashboard",
|
|
1522
|
+
reason: "scheduled-briefing-session",
|
|
1523
|
+
uiMetadata: { briefingProfileId: profile.id }
|
|
1524
|
+
}, paths);
|
|
1525
|
+
if (!("session" in created)) throw new Error("Briefing session could not be created.");
|
|
1526
|
+
if (created.session.staleReasons.length > 0) throw new Error("The briefing conversation context is stale. Start a fresh briefing conversation before running again.");
|
|
1527
|
+
await setBriefingProfileSession(profile.id, created.session.id, paths);
|
|
1528
|
+
return created.session.id;
|
|
1529
|
+
}
|
|
1530
|
+
async function validateRequestedBriefingSession(sessionId, paths) {
|
|
1531
|
+
const result = await readChatSession({
|
|
1532
|
+
id: sessionId,
|
|
1533
|
+
reason: "manual-briefing-admission"
|
|
1534
|
+
}, paths);
|
|
1535
|
+
if (!("session" in result) || result.session.archivedAt || result.session.agentName !== "display-assistant" || result.session.staleReasons.length > 0) throw new Error("Manual briefings require an active display-assistant chat session.");
|
|
1536
|
+
return result.session.id;
|
|
1537
|
+
}
|
|
1538
|
+
//#endregion
|
|
1539
|
+
//#region src/modules/briefings/actions.ts
|
|
1540
|
+
var outputSchema = v.looseObject({
|
|
1541
|
+
ok: v.boolean(),
|
|
1542
|
+
action: v.string(),
|
|
1543
|
+
changed: v.boolean(),
|
|
1544
|
+
message: v.optional(v.string())
|
|
1545
|
+
});
|
|
1546
|
+
var neondeckBriefingActions = [
|
|
1547
|
+
defineAction({
|
|
1548
|
+
name: "neondeck_briefing_profile_read",
|
|
1549
|
+
description: "Read the typed morning briefing profile, its durable conversation link, and recent operational run metadata.",
|
|
1550
|
+
input: v.object({}),
|
|
1551
|
+
output: outputSchema,
|
|
1552
|
+
async run() {
|
|
1553
|
+
return readBriefingState();
|
|
1554
|
+
}
|
|
1555
|
+
}),
|
|
1556
|
+
defineAction({
|
|
1557
|
+
name: "neondeck_briefing_profile_update",
|
|
1558
|
+
description: "Update the enabled state, cron schedule, timezone, title, or user-authored instructions for the morning briefing profile.",
|
|
1559
|
+
input: briefingProfileUpdateSchema,
|
|
1560
|
+
output: outputSchema,
|
|
1561
|
+
async run({ input }) {
|
|
1562
|
+
return updateBriefingProfile(input);
|
|
1563
|
+
}
|
|
1564
|
+
}),
|
|
1565
|
+
defineAction({
|
|
1566
|
+
name: "neondeck_briefing_run_read",
|
|
1567
|
+
description: "Read one exact persisted deterministic briefing snapshot and its operational dispatch metadata. This never reads or parses the assistant transcript.",
|
|
1568
|
+
input: v.object({ id: v.pipe(v.string(), v.minLength(1)) }),
|
|
1569
|
+
output: outputSchema,
|
|
1570
|
+
async run({ input }) {
|
|
1571
|
+
return readBriefingRunDetails(input.id);
|
|
1572
|
+
}
|
|
1573
|
+
}),
|
|
1574
|
+
defineAction({
|
|
1575
|
+
name: "neondeck_briefing_run_now",
|
|
1576
|
+
description: "Queue an informational briefing in its persistent briefing conversation. All configured display-assistant MCP tools remain available under their normal auth and approval controls.",
|
|
1577
|
+
input: briefingRunNowSchema,
|
|
1578
|
+
output: outputSchema,
|
|
1579
|
+
async run({ input }) {
|
|
1580
|
+
return runBriefingNow(input);
|
|
1581
|
+
}
|
|
1582
|
+
}),
|
|
1583
|
+
defineAction({
|
|
1584
|
+
name: "neondeck_briefing_session_rotate",
|
|
1585
|
+
description: "Explicitly start a fresh durable briefing conversation when its captured model, SOUL, memory, skill, or provider context is stale. The old transcript remains preserved.",
|
|
1586
|
+
input: v.object({ id: v.optional(v.string()) }),
|
|
1587
|
+
output: outputSchema,
|
|
1588
|
+
async run({ input }) {
|
|
1589
|
+
return rotateBriefingSession(input);
|
|
1590
|
+
}
|
|
1591
|
+
})
|
|
1592
|
+
];
|
|
1593
|
+
//#endregion
|
|
1594
|
+
export { completedCommand as C, compactCommandSummary as S, briefingWorkflowInputSchema as T, isActiveMemoryScope as _, readBriefingState as a, readStringArrayProperty as b, settleBriefingObservation as c, explainCiCommand as d, fixCiCommand as f, formatList as g, summarizePrCommand as h, readBriefingRunDetails as i, updateBriefingProfile as l, reviewQueueCommand as m, admitBriefing as n, rotateBriefingSession as o, reviewPrCommand as p, linkBriefingWorkflowObservation as r, runBriefingNow as s, neondeckBriefingActions as t, collectBriefingSnapshot as u, isMemoryScope as v, failedCommand as w, supportedReasoningLevelsForModel as x, parseMemoryValue as y };
|
|
1595
|
+
|
|
1596
|
+
//# sourceMappingURL=briefings-DuApznpN.js.map
|