discovery-plans.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /**
  2. * Thin adapter — delegates all discovery-plan business logic to
  3. * `src/always-on/web/DiscoveryPlanService.ts`.
  4. *
  5. * This file only wires the service's dependency injection and
  6. * re-exports the public API surface consumed by routes and slash
  7. * commands.
  8. */
  9. import { isSessionActiveViaGateway as isClaudeSDKSessionActive, getPilotDeckGateway } from './pilotdeck-bridge.js';
  10. import {
  11. extractProjectDirectory,
  12. getProjectCronJobsOverview,
  13. getSessions,
  14. } from './projects.js';
  15. import { appendAlwaysOnRunEvent } from './services/always-on-run-history.js';
  16. import {
  17. appendAlwaysOnRunLog,
  18. appendAlwaysOnRunLogEvent,
  19. formatAlwaysOnPlanLogLine,
  20. } from './services/always-on-run-logs.js';
  21. import { resolvePilotHome, createProjectId } from './utils/pilotPaths.js';
  22. import { DiscoveryPlanService } from '../../src/always-on/web/DiscoveryPlanService.js';
  23. import { buildDiscoveryContext } from '../../src/always-on/web/DiscoveryPlanContext.js';
  24. import {
  25. applyWorktreeToProject,
  26. disposeWorkspace as disposeWorkspaceImpl,
  27. } from '../../src/always-on/workspace/WorkspaceApply.js';
  28. // ---------------------------------------------------------------------------
  29. // Wire dependencies for the service
  30. // ---------------------------------------------------------------------------
  31. function getService() {
  32. return new DiscoveryPlanService({
  33. pilotHome: resolvePilotHome(),
  34. createProjectId,
  35. paths: { extractProjectDirectory },
  36. sessions: { getSessions },
  37. activity: { isSessionActive: isClaudeSDKSessionActive },
  38. events: {
  39. appendRunEvent: appendAlwaysOnRunEvent,
  40. appendRunLog: appendAlwaysOnRunLog,
  41. appendRunLogEvent: appendAlwaysOnRunLogEvent,
  42. formatLogLine: formatAlwaysOnPlanLogLine,
  43. },
  44. workspace: {
  45. applyWorktreeChanges: applyWorktreeToProject,
  46. disposeWorkspace: disposeWorkspaceImpl,
  47. },
  48. });
  49. }
  50. // ---------------------------------------------------------------------------
  51. // Public API
  52. // ---------------------------------------------------------------------------
  53. export async function getProjectDiscoveryContext(projectName) {
  54. const projectRoot = await extractProjectDirectory(projectName);
  55. return buildDiscoveryContext({
  56. projectName,
  57. projectRoot,
  58. getProjectCronJobsOverview,
  59. getSessions,
  60. extractProjectDirectory,
  61. });
  62. }
  63. export async function getProjectDiscoveryPlansOverview(projectName) {
  64. return getService().getPlansOverview(projectName);
  65. }
  66. export async function rerunDiscoveryPlan(projectName, planId) {
  67. const projectRoot = await extractProjectDirectory(projectName);
  68. const gw = await getPilotDeckGateway();
  69. const result = await gw.alwaysOnRerunPlan({
  70. projectKey: projectRoot,
  71. planId,
  72. projectName,
  73. });
  74. if (result.error) {
  75. const err = new Error(result.error.message);
  76. err.code = result.error.code;
  77. throw err;
  78. }
  79. return { runId: result.runId };
  80. }
  81. export async function getProjectDiscoveryPlanReport(projectName, planId) {
  82. return getService().readReport(projectName, planId);
  83. }
  84. export async function getProjectWorkCycles(projectName) {
  85. return getService().getCyclesOverview(projectName);
  86. }
  87. export async function archiveWorkCycle(projectName, cycleId) {
  88. return getService().archiveCycle(projectName, cycleId);
  89. }
  90. export async function applyWorkCycle(projectName, cycleId) {
  91. const result = await getService().queueCycleApply(projectName, cycleId);
  92. const gw = await getPilotDeckGateway();
  93. let applyResult;
  94. try {
  95. applyResult = await gw.alwaysOnApply({
  96. projectKey: result.projectRoot,
  97. workCycleId: cycleId,
  98. projectName,
  99. });
  100. } catch (err) {
  101. await getService().updateCycleExecution(projectName, cycleId, {
  102. status: 'failed',
  103. });
  104. return {
  105. cycle: result.cycle,
  106. error: { code: 'apply_error', message: (err && err.message) || 'Apply failed' },
  107. };
  108. }
  109. if (applyResult.error) {
  110. await getService().updateCycleExecution(projectName, cycleId, {
  111. status: 'failed',
  112. });
  113. return { cycle: result.cycle, error: applyResult.error };
  114. }
  115. const finalResult = await getService().updateCycleExecution(projectName, cycleId, {
  116. status: 'completed',
  117. executionSessionId: applyResult.sessionKey,
  118. });
  119. return {
  120. cycle: finalResult.cycle,
  121. sessionKey: applyResult.sessionKey,
  122. };
  123. }