@straiffi/archon 1.4.7 → 1.4.8

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.
Files changed (79) hide show
  1. package/dist/client/assets/GitHubActionsDialog-ln1X9xDf.js +1 -0
  2. package/dist/client/assets/{TestsDialog-CcSvemLJ.js → TestsDialog-Cp3Da2W0.js} +1 -1
  3. package/dist/client/assets/{architectureDiagram-3BPJPVTR-DJjMJGQa.js → architectureDiagram-3BPJPVTR-CFEtd9pl.js} +1 -1
  4. package/dist/client/assets/{blockDiagram-GPEHLZMM-D7qr0WKZ.js → blockDiagram-GPEHLZMM-9UsBOlSn.js} +1 -1
  5. package/dist/client/assets/{c4Diagram-AAUBKEIU-Dtpwhh8J.js → c4Diagram-AAUBKEIU--TsvWn6X.js} +1 -1
  6. package/dist/client/assets/channel-BjRPoR7Z.js +1 -0
  7. package/dist/client/assets/{chunk-2J33WTMH-BImOu1wB.js → chunk-2J33WTMH-B3FphDWz.js} +1 -1
  8. package/dist/client/assets/{chunk-3OPIFGDE-WBqy9pqS.js → chunk-3OPIFGDE-CLbUIPKK.js} +1 -1
  9. package/dist/client/assets/{chunk-5ZQYHXKU-gzwfOytX.js → chunk-5ZQYHXKU-CUHKY5eH.js} +1 -1
  10. package/dist/client/assets/{chunk-727SXJPM-DZRDmsY-.js → chunk-727SXJPM-DfKJ4Ud0.js} +1 -1
  11. package/dist/client/assets/{chunk-AQP2D5EJ-BNsOD4b1.js → chunk-AQP2D5EJ-B0oLVoZs.js} +1 -1
  12. package/dist/client/assets/{chunk-CSCIHK7Q-Be5NZf-h.js → chunk-CSCIHK7Q-Czl8GWBW.js} +1 -1
  13. package/dist/client/assets/{chunk-KSCS5N6A-t3G5p-H3.js → chunk-KSCS5N6A-pOOnuun_.js} +1 -1
  14. package/dist/client/assets/{chunk-L5ZTLDWV-08eeTRtA.js → chunk-L5ZTLDWV-DzRVeTqf.js} +1 -1
  15. package/dist/client/assets/{chunk-LZXEDZCA-BhEnRZZ3.js → chunk-LZXEDZCA-MVhzvLVp.js} +2 -2
  16. package/dist/client/assets/{chunk-ND2GUHAM-n8aRhp2g.js → chunk-ND2GUHAM-BeNiy3nE.js} +1 -1
  17. package/dist/client/assets/{chunk-NZK2D7GU-BzDdHd-c.js → chunk-NZK2D7GU-CnENvQ9d.js} +1 -1
  18. package/dist/client/assets/{chunk-O5CBEL6O-B4hb9RKU.js → chunk-O5CBEL6O-CkqDMX_f.js} +1 -1
  19. package/dist/client/assets/{chunk-WU5MYG2G-95dAWX8f.js → chunk-WU5MYG2G-sJ18xVVM.js} +1 -1
  20. package/dist/client/assets/classDiagram-4FO5ZUOK-BjzBLL5f.js +1 -0
  21. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-BDLW6NLv.js +1 -0
  22. package/dist/client/assets/{dagre-BM42HDAG-BrFwfUb5.js → dagre-BM42HDAG-BWnmF2aL.js} +1 -1
  23. package/dist/client/assets/{diagram-2AECGRRQ-C-spx6S1.js → diagram-2AECGRRQ-CASRQI5Y.js} +1 -1
  24. package/dist/client/assets/{diagram-5GNKFQAL-CTGmw6IF.js → diagram-5GNKFQAL-CY8fXRrV.js} +1 -1
  25. package/dist/client/assets/{diagram-KO2AKTUF-CGR_6C8P.js → diagram-KO2AKTUF-vtm-gqIm.js} +1 -1
  26. package/dist/client/assets/{diagram-LMA3HP47-Biu8iKKN.js → diagram-LMA3HP47-Ck-iA5q1.js} +1 -1
  27. package/dist/client/assets/{diagram-OG6HWLK6-CgPqxTkQ.js → diagram-OG6HWLK6-ALBEY2Nn.js} +1 -1
  28. package/dist/client/assets/{erDiagram-TEJ5UH35-Dvb5W4CZ.js → erDiagram-TEJ5UH35-BAHPzYR7.js} +1 -1
  29. package/dist/client/assets/{flowDiagram-I6XJVG4X-tU7PIdFt.js → flowDiagram-I6XJVG4X-pUYj1KCo.js} +1 -1
  30. package/dist/client/assets/{ganttDiagram-6RSMTGT7-Cxn3Y-uw.js → ganttDiagram-6RSMTGT7-zw-EKZcX.js} +1 -1
  31. package/dist/client/assets/{gitGraphDiagram-PVQCEYII-C3ODPbCH.js → gitGraphDiagram-PVQCEYII-DmPxQKXO.js} +1 -1
  32. package/dist/client/assets/index-BokL1E46.css +2 -0
  33. package/dist/client/assets/index-WeECH1eZ.js +260 -0
  34. package/dist/client/assets/{infoDiagram-5YYISTIA-DI-gw2Xm.js → infoDiagram-5YYISTIA-D0zuFK8l.js} +1 -1
  35. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-Boo7JuBN.js → ishikawaDiagram-YF4QCWOH-BoNe_Ie6.js} +1 -1
  36. package/dist/client/assets/{journeyDiagram-JHISSGLW-N9__o75J.js → journeyDiagram-JHISSGLW-ByAP1uL0.js} +1 -1
  37. package/dist/client/assets/{kanban-definition-UN3LZRKU-BbtqdHL3.js → kanban-definition-UN3LZRKU-CGXOqdl0.js} +1 -1
  38. package/dist/client/assets/{line-MwEcOq8D.js → line-BZ3JWBtG.js} +1 -1
  39. package/dist/client/assets/{mermaid-parser.core-C_-_i9ct.js → mermaid-parser.core-DuHIifHL.js} +1 -1
  40. package/dist/client/assets/{mermaid.core-jFmh7tic.js → mermaid.core-Co8EqKSU.js} +3 -3
  41. package/dist/client/assets/{mindmap-definition-RKZ34NQL-cAM3OmtA.js → mindmap-definition-RKZ34NQL-Cv3-5Q_b.js} +1 -1
  42. package/dist/client/assets/{pieDiagram-4H26LBE5-B7wO_tA6.js → pieDiagram-4H26LBE5-DziVyTJT.js} +1 -1
  43. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-41IRD1HZ.js → quadrantDiagram-W4KKPZXB-DjNtV4An.js} +1 -1
  44. package/dist/client/assets/{requirementDiagram-4Y6WPE33-CRp-2G5Y.js → requirementDiagram-4Y6WPE33-Cs3npD-z.js} +1 -1
  45. package/dist/client/assets/{sankeyDiagram-5OEKKPKP-C2jxwbv9.js → sankeyDiagram-5OEKKPKP-DxepDJwc.js} +1 -1
  46. package/dist/client/assets/{sequenceDiagram-3UESZ5HK-C0ifwFNY.js → sequenceDiagram-3UESZ5HK-DIPg-NEj.js} +1 -1
  47. package/dist/client/assets/{stateDiagram-AJRCARHV-DtkDso6_.js → stateDiagram-AJRCARHV-DUA-Ko9b.js} +1 -1
  48. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-D6OlcyEp.js +1 -0
  49. package/dist/client/assets/{timeline-definition-PNZ67QCA-DwL2DqkA.js → timeline-definition-PNZ67QCA-wvi8pREg.js} +1 -1
  50. package/dist/client/assets/{vennDiagram-CIIHVFJN-Cd1A1glE.js → vennDiagram-CIIHVFJN-CabtIweB.js} +1 -1
  51. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-DpWpjU7R.js → wardleyDiagram-YWT4CUSO-BiOWydTY.js} +1 -1
  52. package/dist/client/assets/{xychartDiagram-2RQKCTM6-BROvAGf_.js → xychartDiagram-2RQKCTM6-sWfRgDRl.js} +1 -1
  53. package/dist/client/index.html +2 -2
  54. package/dist/server/db.js +50 -9
  55. package/dist/server/db.js.map +1 -1
  56. package/dist/server/index.js +218 -5
  57. package/dist/server/index.js.map +1 -1
  58. package/dist/server/lib/attachments.js +36 -26
  59. package/dist/server/lib/attachments.js.map +1 -1
  60. package/dist/server/lib/chats.js +2 -2
  61. package/dist/server/lib/chats.js.map +1 -1
  62. package/dist/server/lib/integrations/github-issues.js +107 -12
  63. package/dist/server/lib/integrations/github-issues.js.map +1 -1
  64. package/dist/server/lib/integrations/importedIssueImages.js +210 -0
  65. package/dist/server/lib/integrations/importedIssueImages.js.map +1 -0
  66. package/dist/server/lib/integrations/jira.js +132 -21
  67. package/dist/server/lib/integrations/jira.js.map +1 -1
  68. package/dist/server/lib/specOperations.js +9 -4
  69. package/dist/server/lib/specOperations.js.map +1 -1
  70. package/dist/server/lib/specs.js +2 -7
  71. package/dist/server/lib/specs.js.map +1 -1
  72. package/package.json +1 -1
  73. package/dist/client/assets/GitHubActionsDialog-B0yRjwYQ.js +0 -1
  74. package/dist/client/assets/channel-JBvp4GqN.js +0 -1
  75. package/dist/client/assets/classDiagram-4FO5ZUOK-vGoYHbZF.js +0 -1
  76. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-DuL6ksKg.js +0 -1
  77. package/dist/client/assets/index--HKq89za.css +0 -2
  78. package/dist/client/assets/index-QYW4Cu-e.js +0 -260
  79. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-CpWls-En.js +0 -1
@@ -10,7 +10,7 @@ import { adjectives, animals, uniqueNamesGenerator } from 'unique-names-generato
10
10
  import db from './db.js';
11
11
  import { deleteChatSession, getChatSession, listChatSessions, updateChatSessionMode } from './lib/chats.js';
12
12
  import { deleteSpecSession, getCreatedTicketIdsForSnapshot, getSpecSession, getSpecSnapshot, listSpecSessions } from './lib/specs.js';
13
- import { createChatAttachment, createSpecAttachment, deleteChatAttachment, deleteSpecSessionAttachment, getChatAttachmentById, getChatAttachmentForSession, getChatAttachmentLinkedMessageId, getSpecAttachmentForSession, getSpecAttachmentLinkedMessageId, MAX_CHAT_ATTACHMENTS_PER_TURN, MAX_CHAT_ATTACHMENT_SIZE_BYTES, MAX_SPEC_ATTACHMENTS_PER_TURN, MAX_SPEC_ATTACHMENT_SIZE_BYTES, readChatAttachmentContent, readSpecAttachmentContent, validateImageAttachment, } from './lib/attachments.js';
13
+ import { createChatAttachment, createSpecAttachment, getAttachmentById, deleteChatAttachment, deleteSpecSessionAttachment, getChatAttachmentForSession, getChatAttachmentLinkedMessageId, getSpecAttachmentForSession, getSpecAttachmentLinkedMessageId, MAX_CHAT_ATTACHMENTS_PER_TURN, MAX_CHAT_ATTACHMENT_SIZE_BYTES, MAX_SPEC_ATTACHMENTS_PER_TURN, MAX_SPEC_ATTACHMENT_SIZE_BYTES, readChatAttachmentContent, readSpecAttachmentContent, validateImageAttachment, } from './lib/attachments.js';
14
14
  import { createProjectChatSession, resolveChatMode, resolveChatTool, stopProjectChatSessionResponse, submitProjectChatSessionMessage, } from './lib/chatOperations.js';
15
15
  import { createProjectSpecSession, deleteProjectSpecSession, stopProjectSpecSessionResponse, submitProjectSpecSessionMessage, updateProjectSpecSessionMode, } from './lib/specOperations.js';
16
16
  import { buildProjectSpecReviewRevisionDraft, getProjectSpecReviewFindings, startProjectSpecReview, stopProjectSpecReview, } from './lib/specReviewOperations.js';
@@ -49,8 +49,9 @@ import { shutdownRealtimeServer } from './lib/shutdown.js';
49
49
  import { resolveClientBuildPaths, shouldServeClientApp, STATIC_CLIENT_DIRECTORY_OPTIONS, STATIC_CLIENT_INDEX_OPTIONS, } from './lib/staticClient.js';
50
50
  import { deleteIntegrationConnection, getGitHubConnectionConfig, getJiraConnectionConfig, listIntegrationConnections, upsertIntegrationConnection, } from './lib/integrations/index.js';
51
51
  import { createGitHubPullRequest, createOrFindGitHubPullRequest, findOpenGitHubPullRequest, findOpenGitHubPullRequestByHeadBranch, getGitHubPullRequestComments, getGitHubPullRequestReviews, getGitHubPullRequest, GitHubApiError, hasGitHubRemoteBranch, resolveGitHubRepository, validateGitHubConnection, } from './lib/integrations/github.js';
52
- import { importJiraIssue, JiraApiError, validateJiraConnection } from './lib/integrations/jira.js';
53
- import { importGitHubIssue } from './lib/integrations/github-issues.js';
52
+ import { importJiraIssue, JiraApiError, prepareJiraIssueImport, validateJiraConnection } from './lib/integrations/jira.js';
53
+ import { importGitHubIssue, prepareGitHubIssueImport } from './lib/integrations/github-issues.js';
54
+ import { buildImportedIssueSessionTitle, importProviderHostedIssueImages } from './lib/integrations/importedIssueImages.js';
54
55
  import { dispatchGitHubWorkflow, getGitHubWorkflowDispatchConfig, getGitHubWorkflowRun, getGitHubWorkflowRunJobs, listGitHubWorkflows, listGitHubWorkflowRuns, } from './lib/integrations/githubActions.js';
55
56
  import { clearAllGitHubActionsSessions, getActiveTrackedRunCount, getTrackedGitHubActionsRuns, trackGitHubActionsRun, } from './lib/integrations/githubActionsSessions.js';
56
57
  import { PlanningReferenceError, resolveExternalPlanningDescription } from './lib/integrations/planning.js';
@@ -2068,7 +2069,7 @@ app.post('/projects/:id/chat-sessions/:sessionId/attachments', (req, res) => {
2068
2069
  }
2069
2070
  catch (uploadError) {
2070
2071
  for (const attachmentId of createdAttachmentIds) {
2071
- const attachment = getChatAttachmentById(attachmentId);
2072
+ const attachment = getAttachmentById(attachmentId);
2072
2073
  if (!attachment) {
2073
2074
  continue;
2074
2075
  }
@@ -2353,7 +2354,7 @@ app.post('/projects/:id/spec-sessions/:sessionId/attachments', (req, res) => {
2353
2354
  }
2354
2355
  catch (uploadError) {
2355
2356
  for (const attachmentId of createdAttachmentIds) {
2356
- const attachment = getChatAttachmentById(attachmentId);
2357
+ const attachment = getAttachmentById(attachmentId);
2357
2358
  if (!attachment) {
2358
2359
  continue;
2359
2360
  }
@@ -3580,6 +3581,76 @@ app.get('/integrations', (req, res) => {
3580
3581
  }
3581
3582
  return res.json({ connections: listIntegrationConnections(result.project.id) });
3582
3583
  });
3584
+ const NOOP_BROADCASTER = {
3585
+ emit: () => undefined,
3586
+ };
3587
+ const buildSpecImportSessionPayload = (payload, draft) => {
3588
+ return {
3589
+ tool: payload?.tool,
3590
+ mode: payload?.mode,
3591
+ model: payload?.model,
3592
+ variant: payload?.variant,
3593
+ skills: payload?.skills,
3594
+ title: buildImportedIssueSessionTitle(draft),
3595
+ external_source: draft.external_source,
3596
+ };
3597
+ };
3598
+ const prepareSpecImportResponse = async ({ projectId, payload, preparedDraft, importOptions, broadcaster, }) => {
3599
+ const draft = {
3600
+ title: preparedDraft.title,
3601
+ description: preparedDraft.description,
3602
+ external_source: preparedDraft.external_source,
3603
+ };
3604
+ const imported = await importProviderHostedIssueImages({
3605
+ ...importOptions,
3606
+ draft,
3607
+ imageCandidates: preparedDraft.image_candidates,
3608
+ });
3609
+ if (imported.importedImages.length === 0) {
3610
+ return {
3611
+ draft,
3612
+ prompt_text: imported.promptText,
3613
+ external_source: draft.external_source,
3614
+ spec_session: null,
3615
+ imported_attachments: [],
3616
+ import_notice: imported.notice,
3617
+ };
3618
+ }
3619
+ const createResult = createProjectSpecSession({
3620
+ projectId,
3621
+ payload: buildSpecImportSessionPayload(payload, draft),
3622
+ broadcaster: NOOP_BROADCASTER,
3623
+ });
3624
+ if (!createResult.ok) {
3625
+ throw new HttpError(createResult.status, createResult.error);
3626
+ }
3627
+ if (!createResult.value) {
3628
+ throw new Error('Unable to create the imported spec session.');
3629
+ }
3630
+ const specSession = createResult.value;
3631
+ try {
3632
+ const importedAttachments = imported.importedImages.map(image => createSpecAttachment({
3633
+ specSessionId: specSession.id,
3634
+ originalName: image.originalName,
3635
+ mimeType: image.mimeType,
3636
+ buffer: image.buffer,
3637
+ projectId,
3638
+ }));
3639
+ broadcaster.emit('spec-session:created', specSession);
3640
+ return {
3641
+ draft,
3642
+ prompt_text: imported.promptText,
3643
+ external_source: draft.external_source,
3644
+ spec_session: specSession,
3645
+ imported_attachments: importedAttachments,
3646
+ import_notice: imported.notice,
3647
+ };
3648
+ }
3649
+ catch (error) {
3650
+ deleteSpecSession(specSession.id);
3651
+ throw error;
3652
+ }
3653
+ };
3583
3654
  app.post('/integrations/github/connect', async (req, res) => {
3584
3655
  const result = getRequiredProject(req);
3585
3656
  if ('error' in result) {
@@ -3751,6 +3822,77 @@ app.post('/integrations/jira/resolve/issue', async (req, res) => {
3751
3822
  return res.status(500).json({ error: getErrorMessage(error) || 'Unable to import the Jira issue.' });
3752
3823
  }
3753
3824
  });
3825
+ app.post('/integrations/jira/prepare-spec-import', async (req, res) => {
3826
+ const result = getRequiredProject(req);
3827
+ if ('error' in result) {
3828
+ return res.status(400).json({ error: result.error });
3829
+ }
3830
+ const jiraConfig = getJiraConnectionConfig(result.project.id);
3831
+ if (!jiraConfig) {
3832
+ return res.status(400).json({ error: 'Jira is not connected for this project.' });
3833
+ }
3834
+ const issue = asTrimmedString(req.body?.issue);
3835
+ if (!issue) {
3836
+ return res.status(400).json({ error: 'issue is required' });
3837
+ }
3838
+ try {
3839
+ const prepared = await prepareJiraIssueImport(jiraConfig, issue);
3840
+ const response = await prepareSpecImportResponse({
3841
+ projectId: result.project.id,
3842
+ payload: req.body,
3843
+ preparedDraft: prepared,
3844
+ importOptions: { provider: 'jira', config: jiraConfig },
3845
+ broadcaster: io,
3846
+ });
3847
+ return res.json(response);
3848
+ }
3849
+ catch (error) {
3850
+ console.warn(`[integrations] jira spec import failed project=${result.project.id} issue=${issue}`, error);
3851
+ if (error instanceof JiraApiError) {
3852
+ return res.status(error.status).json({ error: error.publicMessage });
3853
+ }
3854
+ if (error instanceof HttpError) {
3855
+ return res.status(error.status).json({ error: error.message });
3856
+ }
3857
+ return res.status(500).json({ error: getErrorMessage(error) || 'Unable to prepare the Jira issue for spec import.' });
3858
+ }
3859
+ });
3860
+ app.post('/integrations/jira/prepare/spec-import', async (req, res) => {
3861
+ const result = getRequiredProject(req);
3862
+ if ('error' in result) {
3863
+ return res.status(400).json({ error: result.error });
3864
+ }
3865
+ const jiraConfig = getJiraConnectionConfig(result.project.id);
3866
+ if (!jiraConfig) {
3867
+ return res.status(400).json({ error: 'Jira is not connected for this project.' });
3868
+ }
3869
+ const issue = asTrimmedString(req.body?.issue);
3870
+ if (!issue) {
3871
+ return res.status(400).json({ error: 'issue is required' });
3872
+ }
3873
+ console.info(`[integrations] jira prepare spec import project=${result.project.id} issue=${issue}`);
3874
+ try {
3875
+ const prepared = await prepareJiraIssueImport(jiraConfig, issue);
3876
+ const response = await prepareSpecImportResponse({
3877
+ projectId: result.project.id,
3878
+ payload: req.body,
3879
+ preparedDraft: prepared,
3880
+ importOptions: { provider: 'jira', config: jiraConfig },
3881
+ broadcaster: io,
3882
+ });
3883
+ return res.json(response);
3884
+ }
3885
+ catch (error) {
3886
+ console.warn(`[integrations] jira prepare spec import failed project=${result.project.id} issue=${issue}`, error);
3887
+ if (error instanceof JiraApiError) {
3888
+ return res.status(error.status).json({ error: error.publicMessage });
3889
+ }
3890
+ if (error instanceof HttpError) {
3891
+ return res.status(error.status).json({ error: error.message });
3892
+ }
3893
+ return res.status(500).json({ error: getErrorMessage(error) || 'Unable to prepare the Jira issue for spec import.' });
3894
+ }
3895
+ });
3754
3896
  app.post('/integrations/github/resolve/issue', async (req, res) => {
3755
3897
  const result = getRequiredProject(req);
3756
3898
  if ('error' in result) {
@@ -3780,6 +3922,77 @@ app.post('/integrations/github/resolve/issue', async (req, res) => {
3780
3922
  return res.status(500).json({ error: getErrorMessage(error) || 'Unable to import the GitHub issue.' });
3781
3923
  }
3782
3924
  });
3925
+ app.post('/integrations/github/prepare-spec-import', async (req, res) => {
3926
+ const result = getRequiredProject(req);
3927
+ if ('error' in result) {
3928
+ return res.status(400).json({ error: result.error });
3929
+ }
3930
+ const githubConfig = getGitHubConnectionConfig(result.project.id);
3931
+ if (!githubConfig) {
3932
+ return res.status(400).json({ error: 'GitHub is not connected for this project.' });
3933
+ }
3934
+ const issue = asTrimmedString(req.body?.issue);
3935
+ if (!issue) {
3936
+ return res.status(400).json({ error: 'issue is required' });
3937
+ }
3938
+ try {
3939
+ const prepared = await prepareGitHubIssueImport(githubConfig, issue);
3940
+ const response = await prepareSpecImportResponse({
3941
+ projectId: result.project.id,
3942
+ payload: req.body,
3943
+ preparedDraft: prepared,
3944
+ importOptions: { provider: 'github', config: githubConfig },
3945
+ broadcaster: io,
3946
+ });
3947
+ return res.json(response);
3948
+ }
3949
+ catch (error) {
3950
+ console.warn(`[integrations] github spec import failed project=${result.project.id} issue=${issue}`, error);
3951
+ if (error instanceof GitHubApiError) {
3952
+ return res.status(error.status).json({ error: error.publicMessage });
3953
+ }
3954
+ if (error instanceof HttpError) {
3955
+ return res.status(error.status).json({ error: error.message });
3956
+ }
3957
+ return res.status(500).json({ error: getErrorMessage(error) || 'Unable to prepare the GitHub issue for spec import.' });
3958
+ }
3959
+ });
3960
+ app.post('/integrations/github/prepare/spec-import', async (req, res) => {
3961
+ const result = getRequiredProject(req);
3962
+ if ('error' in result) {
3963
+ return res.status(400).json({ error: result.error });
3964
+ }
3965
+ const githubConfig = getGitHubConnectionConfig(result.project.id);
3966
+ if (!githubConfig) {
3967
+ return res.status(400).json({ error: 'GitHub is not connected for this project.' });
3968
+ }
3969
+ const issue = asTrimmedString(req.body?.issue);
3970
+ if (!issue) {
3971
+ return res.status(400).json({ error: 'issue is required' });
3972
+ }
3973
+ console.info(`[integrations] github prepare spec import project=${result.project.id} issue=${issue}`);
3974
+ try {
3975
+ const prepared = await prepareGitHubIssueImport(githubConfig, issue);
3976
+ const response = await prepareSpecImportResponse({
3977
+ projectId: result.project.id,
3978
+ payload: req.body,
3979
+ preparedDraft: prepared,
3980
+ importOptions: { provider: 'github', config: githubConfig },
3981
+ broadcaster: io,
3982
+ });
3983
+ return res.json(response);
3984
+ }
3985
+ catch (error) {
3986
+ console.warn(`[integrations] github prepare spec import failed project=${result.project.id} issue=${issue}`, error);
3987
+ if (error instanceof GitHubApiError) {
3988
+ return res.status(error.status).json({ error: error.publicMessage });
3989
+ }
3990
+ if (error instanceof HttpError) {
3991
+ return res.status(error.status).json({ error: error.message });
3992
+ }
3993
+ return res.status(500).json({ error: getErrorMessage(error) || 'Unable to prepare the GitHub issue for spec import.' });
3994
+ }
3995
+ });
3783
3996
  app.get('/integrations/github/actions/workflows', async (req, res) => {
3784
3997
  const result = getRequiredProject(req);
3785
3998
  if ('error' in result) {