@xopcai/xopc 0.0.136 → 0.0.137

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 (120) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/xopc.extension.json +1 -1
  3. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-CER17NHM.js → agent-avatar-dicebear-BVGEvspi.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agents-Bv5R-N8Q.js → agents-Bmfl5l9o.js} +1 -1
  5. package/dist/gateway/static/root/assets/{app-management-settings-panel-B3Ap_wpX.js → app-management-settings-panel-BmdZifqk.js} +1 -1
  6. package/dist/gateway/static/root/assets/{appearance-settings-3kBO22Xd.js → appearance-settings-CI-Cony7.js} +1 -1
  7. package/dist/gateway/static/root/assets/{apps-page-BHYbGQcZ.js → apps-page-8yKgtRah.js} +1 -1
  8. package/dist/gateway/static/root/assets/{archive-plugin-D_vGeNB8.js → archive-plugin-hMye7wu9.js} +1 -1
  9. package/dist/gateway/static/root/assets/{attachment-load-hWV_8pHL.js → attachment-load-qKR5CPYj.js} +1 -1
  10. package/dist/gateway/static/root/assets/{automation-suggestion-card-DVKmVTIo.js → automation-suggestion-card-BrtqTkO2.js} +1 -1
  11. package/dist/gateway/static/root/assets/{automations-page-BCTXpOBp.js → automations-page-CTbY1_xq.js} +1 -1
  12. package/dist/gateway/static/root/assets/{binary-plugins-BuXIeSPc.js → binary-plugins-DURU6npf.js} +1 -1
  13. package/dist/gateway/static/root/assets/{block-editor-C1m0u-UU.js → block-editor-BQIHfg8Q.js} +58 -54
  14. package/dist/gateway/static/root/assets/{browser-settings-page-ChUF08V5.js → browser-settings-page-BTlEo9yH.js} +1 -1
  15. package/dist/gateway/static/root/assets/{capability-presets-api-B7WWYaEh.js → capability-presets-api-DowJXE85.js} +1 -1
  16. package/dist/gateway/static/root/assets/{capability-presets-settings-panel-D_Bh1PnA.js → capability-presets-settings-panel-CUBsiEWT.js} +1 -1
  17. package/dist/gateway/static/root/assets/{channel-recipient-api-sV06LCht.js → channel-recipient-api-BqbZNCJJ.js} +1 -1
  18. package/dist/gateway/static/root/assets/{channels-settings-BI2ChQc7.js → channels-settings-BzPicGm_.js} +1 -1
  19. package/dist/gateway/static/root/assets/channels-status-swr-BCkcagDP.js +1 -0
  20. package/dist/gateway/static/root/assets/{connectors-page-qgvEp09M.js → connectors-page-BryXzajG.js} +1 -1
  21. package/dist/gateway/static/root/assets/{desktop-pet-BxMJlvb-.js → desktop-pet-DxLTNBD2.js} +1 -1
  22. package/dist/gateway/static/root/assets/{desktop-pet-settings-DCvpDImn.js → desktop-pet-settings-D_EgKbEB.js} +1 -1
  23. package/dist/gateway/static/root/assets/{directory-picker-path-field-D1nxs9PA.js → directory-picker-path-field-DmzW9Mwg.js} +1 -1
  24. package/dist/gateway/static/root/assets/{dreaming-settings-EAWkpOgw.js → dreaming-settings-D3DNPePf.js} +1 -1
  25. package/dist/gateway/static/root/assets/{extension-debug-page-LUQ8dE8z.js → extension-debug-page-hUg0oHQR.js} +1 -1
  26. package/dist/gateway/static/root/assets/{extension-page-B_mnhoRd.js → extension-page-Bl1aQuV_.js} +1 -1
  27. package/dist/gateway/static/root/assets/{extension-settings-page-BWQsGmvW.js → extension-settings-page-BghvkAL8.js} +1 -1
  28. package/dist/gateway/static/root/assets/{fetch-BWXmBizE.js → fetch-hvbCiP2J.js} +1 -1
  29. package/dist/gateway/static/root/assets/{gateway-config-api-M9bzPASf.js → gateway-config-api-Dk4b3f7r.js} +1 -1
  30. package/dist/gateway/static/root/assets/{gateway-settings-CbgtpprN.js → gateway-settings-DKNhpqYg.js} +1 -1
  31. package/dist/gateway/static/root/assets/{gateway-startup-retry-BALL91S7.js → gateway-startup-retry-BzbrcQLJ.js} +1 -1
  32. package/dist/gateway/static/root/assets/{goal-create-dialog-CbP4t9aM.js → goal-create-dialog-Z_oEJXTZ.js} +1 -1
  33. package/dist/gateway/static/root/assets/{goal-detail-page-DlwI-MZZ.js → goal-detail-page-CIFnmZ2W.js} +1 -1
  34. package/dist/gateway/static/root/assets/{goals-config-api-BBhFVzBS.js → goals-config-api-DpQ3Hj8X.js} +1 -1
  35. package/dist/gateway/static/root/assets/{goals-page-D26r7knp.js → goals-page-BYWfLxSr.js} +1 -1
  36. package/dist/gateway/static/root/assets/{goals-settings-DdmVG_TR.js → goals-settings-DW6d-W79.js} +1 -1
  37. package/dist/gateway/static/root/assets/{heartbeat-settings-DZW2Xq-U.js → heartbeat-settings-CSGeVzW8.js} +1 -1
  38. package/dist/gateway/static/root/assets/index-B-SGXAZ7.js +262 -0
  39. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-1IWd88-T.js → keyboard-shortcuts-settings-Bh85DLbN.js} +1 -1
  40. package/dist/gateway/static/root/assets/{logs-page-DxoKJO7-.js → logs-page-BYG_JKr5.js} +1 -1
  41. package/dist/gateway/static/root/assets/{markdown-split-BtdBj32h.js → markdown-split-BLOUZPDJ.js} +1 -1
  42. package/dist/gateway/static/root/assets/{media-plugins-CpoPj3s8.js → media-plugins-vlqpbsN0.js} +1 -1
  43. package/dist/gateway/static/root/assets/messages-CD-qhazm.js +3 -0
  44. package/dist/gateway/static/root/assets/{models-hub-panel-D1Rp__dV.js → models-hub-panel-BihK16QP.js} +1 -1
  45. package/dist/gateway/static/root/assets/{notes-page-CgR1bO2W.js → notes-page-DJGOihcg.js} +1 -1
  46. package/dist/gateway/static/root/assets/{notes-workbench-ozsnmDTV.js → notes-workbench-CtdxRaAk.js} +2 -2
  47. package/dist/gateway/static/root/assets/{page-tabs-CVLqCfQB.js → page-tabs-BOKnavua.js} +1 -1
  48. package/dist/gateway/static/root/assets/{preview-open-alternatives-CKUXJk2t.js → preview-open-alternatives-07J39ZIq.js} +1 -1
  49. package/dist/gateway/static/root/assets/{project-detail-page-B4dqFAQF.js → project-detail-page-BC26Zx8C.js} +1 -1
  50. package/dist/gateway/static/root/assets/{projects-page-DlRGXv4a.js → projects-page-kQNhzpLr.js} +1 -1
  51. package/dist/gateway/static/root/assets/{remote-access-hub-rZEYQMZV.js → remote-access-hub-CN1ioJ0X.js} +1 -1
  52. package/dist/gateway/static/root/assets/{save-bar-controls-BtGni268.js → save-bar-controls-CDGmAkP7.js} +1 -1
  53. package/dist/gateway/static/root/assets/{schedule-field-BDGzKVWn.js → schedule-field-7Cvi7W5t.js} +1 -1
  54. package/dist/gateway/static/root/assets/{schema-form-DQJsKMCE.js → schema-form-xobSdD8a.js} +1 -1
  55. package/dist/gateway/static/root/assets/{sessions-page-DxGoCGU8.js → sessions-page-DEGTTMvU.js} +1 -1
  56. package/dist/gateway/static/root/assets/settings-advanced-gate-DgMxVBrX.js +1 -0
  57. package/dist/gateway/static/root/assets/{settings-collapsible-section-c8XGd4-8.js → settings-collapsible-section-CnqjZAfV.js} +1 -1
  58. package/dist/gateway/static/root/assets/{settings-form-section-By0YiDWo.js → settings-form-section-DRzUUAOA.js} +1 -1
  59. package/dist/gateway/static/root/assets/{settings-loading-skeleton-SYCPY-WM.js → settings-loading-skeleton-ke39n0bn.js} +1 -1
  60. package/dist/gateway/static/root/assets/{settings-page-D9NwvnBt.js → settings-page-BDP9GD1j.js} +1 -1
  61. package/dist/gateway/static/root/assets/{settings-page-layout-CrICyGob.js → settings-page-layout-CIf2rF-q.js} +1 -1
  62. package/dist/gateway/static/root/assets/{setup-status-panel-IjK-hDxf.js → setup-status-panel-CiiWlcKj.js} +1 -1
  63. package/dist/gateway/static/root/assets/{share-preview-page-Dfnk9M_m.js → share-preview-page-CwJ2tj2j.js} +1 -1
  64. package/dist/gateway/static/root/assets/{shares-settings-vQiRBra7.js → shares-settings-dm7VKGsi.js} +1 -1
  65. package/dist/gateway/static/root/assets/skill-reload-api-ZzOv59qM.js +1 -0
  66. package/dist/gateway/static/root/assets/{skills-page-CruV215G.js → skills-page-Bc0rxqmf.js} +1 -1
  67. package/dist/gateway/static/root/assets/{system-settings-panel-BBVbSDFD.js → system-settings-panel-1a3I3zIl.js} +1 -1
  68. package/dist/gateway/static/root/assets/{typed-models-lib-CwFayhxu.js → typed-models-lib-C3NCA3Nd.js} +1 -1
  69. package/dist/gateway/static/root/assets/{use-channel-catalog-BKtHOM50.js → use-channel-catalog-DUOMGhwc.js} +1 -1
  70. package/dist/gateway/static/root/assets/{user-profile-settings-panel-_KDWzagh.js → user-profile-settings-panel-dKptBh4U.js} +1 -1
  71. package/dist/gateway/static/root/assets/{utils-BiUjIHb4.js → utils-BqnHAm5O.js} +1 -1
  72. package/dist/gateway/static/root/assets/{voice-api-key-field-agJqlm4o.js → voice-api-key-field-D4dtA6k3.js} +1 -1
  73. package/dist/gateway/static/root/assets/{work-item-detail-page-Bdw4ATCb.js → work-item-detail-page-DpUYYeDf.js} +1 -1
  74. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-D-Dy6mTy.js → workflow-run-setup-panel-BQ8aBXA1.js} +1 -1
  75. package/dist/gateway/static/root/assets/{workflow-start-dialog-GammZ2GK.js → workflow-start-dialog-jHmIHxTR.js} +1 -1
  76. package/dist/gateway/static/root/assets/{workflows-page-Cw5zrqti.js → workflows-page-DzjPClwt.js} +1 -1
  77. package/dist/gateway/static/root/index.html +4 -4
  78. package/dist/package.js +1 -1
  79. package/dist/src/agent/session/session-inspector.d.ts +1 -0
  80. package/dist/src/agent/session/session-inspector.js +8 -2
  81. package/dist/src/agent/session/session-inspector.js.map +1 -1
  82. package/dist/src/cli/command-loaders.js +1 -0
  83. package/dist/src/cli/command-loaders.js.map +1 -1
  84. package/dist/src/cli/command-manifest.js +4 -0
  85. package/dist/src/cli/command-manifest.js.map +1 -1
  86. package/dist/src/cli/commands/resume.d.ts +1 -0
  87. package/dist/src/cli/commands/resume.js +31 -0
  88. package/dist/src/cli/commands/resume.js.map +1 -0
  89. package/dist/src/cli/commands/tui-runner.d.ts +9 -0
  90. package/dist/src/cli/commands/tui-runner.js +40 -0
  91. package/dist/src/cli/commands/tui-runner.js.map +1 -0
  92. package/dist/src/cli/commands/tui.js +4 -28
  93. package/dist/src/cli/commands/tui.js.map +1 -1
  94. package/dist/src/config/agent-profile.js +1 -1
  95. package/dist/src/gateway/agents-admin.js +1 -1
  96. package/dist/src/gateway/hono/routes/home.js +37 -2
  97. package/dist/src/gateway/hono/routes/home.js.map +1 -1
  98. package/dist/src/gateway/hono/routes/projects.js +16 -0
  99. package/dist/src/gateway/hono/routes/projects.js.map +1 -1
  100. package/dist/src/projects/project-kind.js +0 -1
  101. package/dist/src/projects/project-kind.js.map +1 -1
  102. package/dist/src/tui/tui-picker-overlay.d.ts +6 -1
  103. package/dist/src/tui/tui-picker-overlay.js +4 -1
  104. package/dist/src/tui/tui-picker-overlay.js.map +1 -1
  105. package/dist/src/tui/tui-types.d.ts +2 -0
  106. package/dist/src/tui/tui-types.js.map +1 -1
  107. package/dist/src/tui/tui.js +17 -2
  108. package/dist/src/tui/tui.js.map +1 -1
  109. package/dist/src/work-items/work-item-service.d.ts +1 -0
  110. package/dist/src/work-items/work-item-service.js +3 -0
  111. package/dist/src/work-items/work-item-service.js.map +1 -1
  112. package/dist/src/work-items/work-item-store.d.ts +1 -0
  113. package/dist/src/work-items/work-item-store.js +13 -0
  114. package/dist/src/work-items/work-item-store.js.map +1 -1
  115. package/package.json +1 -1
  116. package/dist/gateway/static/root/assets/channels-status-swr-MY4Xh4fM.js +0 -1
  117. package/dist/gateway/static/root/assets/index-DZOm5_ex.js +0 -262
  118. package/dist/gateway/static/root/assets/messages-CQ_k8RHj.js +0 -3
  119. package/dist/gateway/static/root/assets/settings-advanced-gate-4e8ZQwxr.js +0 -1
  120. package/dist/gateway/static/root/assets/skill-reload-api-BIWv778A.js +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"projects.js","names":["path","record"],"sources":["../../../../../src/gateway/hono/routes/projects.ts"],"sourcesContent":["import type { Hono } from 'hono';\nimport { readdir, readFile, realpath, stat, writeFile } from 'node:fs/promises';\nimport * as path from 'node:path';\n\nimport { ActivityService } from '../../../activity/index.js';\nimport { resolveEffectiveAgentProfile } from '../../../config/agent-profile.js';\nimport type { GoalWithDetails } from '../../../goals/index.js';\nimport { GoalService } from '../../../goals/index.js';\nimport {\n buildProjectLoopOverview,\n inferProjectKind,\n inferSuggestedProjectDefaultAgentId,\n isValidProjectAgentId,\n normalizeProjectAgentId,\n ProjectWorkspaceConflictError,\n ProjectWorkspaceMissingError,\n type Project,\n resolveProjectAgentId,\n type ProjectStatus,\n type ProjectWorkflowRunBrief,\n} from '../../../projects/index.js';\nimport { buildSessionKey } from '../../../routing/session-key.js';\nimport {\n getSqliteDatabase,\n getSessionMetadata,\n listMemoryRecords,\n loadTranscriptRowsForSession,\n type SessionMetadataSeed,\n upsertMemoryRecord,\n} from '../../../storage/sqlite/index.js';\nimport {\n buildWorkItemAgentContext,\n WorkItemService,\n WORK_ITEM_ATTACHMENT_MAX_BYTES,\n WORK_ITEM_ATTACHMENT_MAX_COUNT,\n type WorkItemPriority,\n type WorkItemStatus,\n} from '../../../work-items/index.js';\nimport { createGatewayRouteLogger } from '../lib/route-logger.js';\nimport { parseActivityIncludeRelated, parseActivityQuery } from './activity.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\nimport { FILE_SEARCH_MAX_LIMIT, fuzzySearchWorkspaceFiles } from '../../workspace-file-search.js';\n\nconst log = createGatewayRouteLogger('Projects');\n\nfunction parseProjectStatus(raw: unknown): ProjectStatus | undefined {\n return raw === 'active' || raw === 'paused' || raw === 'archived' ? raw : undefined;\n}\n\nfunction parseLimit(raw: string | undefined, fallback = 50): number | undefined {\n if (!raw) return undefined;\n const n = Number.parseInt(raw, 10);\n return Number.isFinite(n) ? Math.min(500, Math.max(1, n)) : fallback;\n}\n\nfunction isHiddenEmptyProjectChatShell(session: {\n hiddenFromSessionList?: boolean;\n messageCount?: number;\n routing?: { peerId?: string };\n customData?: Record<string, unknown>;\n}): boolean {\n return session.hiddenFromSessionList === true\n && session.messageCount === 0\n && session.customData?.genericNewChatShell !== false\n && Boolean(session.routing?.peerId?.startsWith('chat_'));\n}\n\nfunction textField(body: Record<string, unknown>, key: string): string | undefined {\n const value = body[key];\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction optionalTextField(body: Record<string, unknown>, key: string): string | null | undefined {\n if (!(key in body)) return undefined;\n const value = body[key];\n return typeof value === 'string' ? value : null;\n}\n\nfunction resolveEffectiveWorkspaceRoot(\n service: AuthenticatedRouteDeps['service'],\n project: Project,\n): string | undefined {\n const fixedRoot = project.workspaceRoot?.trim();\n if (fixedRoot) return fixedRoot;\n const agentId = resolveProjectAgentId({\n config: service.currentConfig,\n projects: service.projects,\n projectId: project.id,\n });\n return resolveEffectiveAgentProfile(service.currentConfig, agentId).resolvedWorkspacePath;\n}\n\nfunction enrichProjectWorkspace<T extends Project>(\n service: AuthenticatedRouteDeps['service'],\n project: T,\n): T {\n return {\n ...project,\n workspaceMode: project.workspaceRoot?.trim() ? 'fixed' : 'followAgent',\n effectiveWorkspaceRoot: resolveEffectiveWorkspaceRoot(service, project),\n };\n}\n\nfunction finiteNumberField(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) return value;\n if (typeof value === 'string' && value.trim()) {\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n }\n return undefined;\n}\n\nfunction collectUploadedFiles(body: Record<string, unknown>): File[] {\n const raw = body.file ?? body.files ?? body.attachments;\n const values = Array.isArray(raw) ? raw : raw ? [raw] : [];\n return values.filter((value): value is File => value instanceof File);\n}\n\nfunction validateUploadedWorkItemFiles(files: File[]): string | null {\n if (files.length > WORK_ITEM_ATTACHMENT_MAX_COUNT) {\n return `Too many attachments (max ${WORK_ITEM_ATTACHMENT_MAX_COUNT})`;\n }\n for (const file of files) {\n if (file.size > WORK_ITEM_ATTACHMENT_MAX_BYTES) {\n return `Attachment ${JSON.stringify(file.name || 'upload')} exceeds ${Math.floor(WORK_ITEM_ATTACHMENT_MAX_BYTES / (1024 * 1024))}MB limit`;\n }\n }\n return null;\n}\n\nasync function uploadedFileToBuffer(file: File): Promise<{ name: string; buffer: Buffer; mimeType: string }> {\n return {\n name: file.name || 'upload',\n buffer: Buffer.from(await file.arrayBuffer()),\n mimeType: file.type || 'application/octet-stream',\n };\n}\n\nfunction parseCsvEnum<T extends string>(raw: string | undefined, values: readonly T[]): T[] | undefined {\n if (!raw) return undefined;\n const allowed = new Set(values);\n const parsed = raw\n .split(',')\n .map((item) => item.trim())\n .filter((item): item is T => allowed.has(item as T));\n return parsed.length > 0 ? [...new Set(parsed)] : undefined;\n}\n\nfunction parseEnumValue<T extends string>(raw: unknown, values: readonly T[]): T | undefined {\n if (typeof raw !== 'string') return undefined;\n return values.includes(raw as T) ? raw as T : undefined;\n}\n\nconst WORK_ITEM_STATUSES = [\n 'backlog',\n 'todo',\n 'in_progress',\n 'blocked',\n 'needs_input',\n 'in_review',\n 'done',\n 'cancelled',\n] as const satisfies readonly WorkItemStatus[];\nconst WORK_ITEM_PRIORITIES = ['urgent', 'high', 'normal', 'low'] as const satisfies readonly WorkItemPriority[];\nconst WORK_ITEM_SUGGESTION_STATUSES = ['pending', 'applied', 'dismissed'] as const;\n\nconst SKIP_FILE_NAMES = new Set(['.git', 'node_modules']);\n\nconst PROJECT_FILE_MIME_BY_EXT: Record<string, string> = {\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n webp: 'image/webp',\n bmp: 'image/bmp',\n svg: 'image/svg+xml',\n pdf: 'application/pdf',\n docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n txt: 'text/plain',\n md: 'text/markdown',\n json: 'application/json',\n html: 'text/html',\n css: 'text/css',\n js: 'text/javascript',\n ts: 'text/typescript',\n mp3: 'audio/mpeg',\n wav: 'audio/wav',\n ogg: 'audio/ogg',\n webm: 'video/webm',\n mp4: 'video/mp4',\n mov: 'video/quicktime',\n};\n\nfunction normalizeRelativePath(raw: string | undefined): string {\n const normalized = (raw ?? '').trim().replaceAll('\\\\', '/');\n return normalized.replace(/^\\/+/, '');\n}\n\nfunction isWithinDirectory(root: string, target: string): boolean {\n const relativePath = path.relative(root, target);\n return relativePath === '' || (!relativePath.startsWith('..') && !path.isAbsolute(relativePath));\n}\n\nasync function resolveProjectWorkspaceRoot(\n service: AuthenticatedRouteDeps['service'],\n projectId: string,\n): Promise<{ ok: true; projectId: string; root: string } | { ok: false; status: number; error: string }> {\n const project = service.projects.get(projectId);\n if (!project) return { ok: false, status: 404, error: 'Project not found' };\n const workspaceRoot = resolveEffectiveWorkspaceRoot(service, project);\n if (!workspaceRoot?.trim()) {\n return { ok: false, status: 400, error: 'Project workspace root is not set' };\n }\n\n try {\n const root = await realpath(workspaceRoot);\n const rootStat = await stat(root);\n if (!rootStat.isDirectory()) {\n return { ok: false, status: 400, error: 'Project workspace root is not a directory' };\n }\n return { ok: true, projectId: project.id, root };\n } catch (err) {\n log.warn({ err, projectId: project.id, path: workspaceRoot }, 'project workspace root unavailable');\n return { ok: false, status: 404, error: 'Project workspace root is unavailable' };\n }\n}\n\nasync function resolveProjectWorkspacePath(\n service: AuthenticatedRouteDeps['service'],\n projectId: string,\n rawPath: string | undefined,\n): Promise<\n | { ok: true; projectId: string; root: string; requestedPath: string; absolutePath: string; relativePath: string }\n | { ok: false; status: number; error: string }\n> {\n const rootResult = await resolveProjectWorkspaceRoot(service, projectId);\n if (rootResult.ok === false) {\n return { ok: false, status: rootResult.status, error: rootResult.error };\n }\n\n const requestedPath = normalizeRelativePath(rawPath);\n const candidate = path.resolve(rootResult.root, requestedPath);\n if (!isWithinDirectory(rootResult.root, candidate)) {\n return { ok: false, status: 400, error: 'Path is outside project workspace' };\n }\n\n const relativePath = path.relative(rootResult.root, candidate).split(path.sep).join('/');\n return {\n ok: true,\n projectId: rootResult.projectId,\n root: rootResult.root,\n requestedPath,\n absolutePath: candidate,\n relativePath: relativePath === '.' ? '' : relativePath,\n };\n}\n\nasync function resolveExistingProjectWorkspacePath(\n service: AuthenticatedRouteDeps['service'],\n projectId: string,\n rawPath: string | undefined,\n): Promise<\n | {\n ok: true;\n projectId: string;\n root: string;\n requestedPath: string;\n absolutePath: string;\n relativePath: string;\n stat: Awaited<ReturnType<typeof stat>>;\n }\n | { ok: false; status: number; error: string }\n> {\n const resolved = await resolveProjectWorkspacePath(service, projectId, rawPath);\n if (resolved.ok === false) return resolved;\n if (!resolved.requestedPath.trim()) {\n return { ok: false, status: 400, error: 'Missing path' };\n }\n\n let realTarget: string;\n try {\n realTarget = await realpath(resolved.absolutePath);\n } catch {\n return { ok: false, status: 404, error: 'Not found' };\n }\n if (!isWithinDirectory(resolved.root, realTarget)) {\n return { ok: false, status: 400, error: 'Path is outside project workspace' };\n }\n const targetStat = await stat(realTarget);\n return {\n ...resolved,\n absolutePath: realTarget,\n stat: targetStat,\n };\n}\n\nasync function resolveProjectWorkspaceWritePath(\n service: AuthenticatedRouteDeps['service'],\n projectId: string,\n rawPath: string | undefined,\n): Promise<\n | {\n ok: true;\n projectId: string;\n root: string;\n requestedPath: string;\n absolutePath: string;\n relativePath: string;\n existingStat?: Awaited<ReturnType<typeof stat>>;\n }\n | { ok: false; status: number; error: string }\n> {\n const resolved = await resolveProjectWorkspacePath(service, projectId, rawPath);\n if (resolved.ok === false) return resolved;\n if (!resolved.requestedPath.trim()) {\n return { ok: false, status: 400, error: 'Missing path' };\n }\n\n try {\n const realTarget = await realpath(resolved.absolutePath);\n if (!isWithinDirectory(resolved.root, realTarget)) {\n return { ok: false, status: 400, error: 'Path is outside project workspace' };\n }\n return {\n ...resolved,\n absolutePath: realTarget,\n existingStat: await stat(realTarget),\n };\n } catch {\n const parentPath = path.dirname(resolved.absolutePath);\n try {\n const realParent = await realpath(parentPath);\n if (!isWithinDirectory(resolved.root, realParent)) {\n return { ok: false, status: 400, error: 'Path is outside project workspace' };\n }\n } catch {\n return { ok: false, status: 404, error: 'Parent directory not found' };\n }\n return resolved;\n }\n}\n\nfunction textFromTranscriptContent(content: unknown): string {\n if (typeof content === 'string') return content;\n if (!Array.isArray(content)) return '';\n return content\n .map((part) => {\n if (!part || typeof part !== 'object') return '';\n const record = part as Record<string, unknown>;\n return typeof record.text === 'string' ? record.text : '';\n })\n .filter(Boolean)\n .join('\\n');\n}\n\nfunction buildSessionSummaryMemoryContent(sessionKey: string, explicitSummary?: string): string {\n const summary = explicitSummary?.trim();\n if (summary) return summary;\n const rows = loadTranscriptRowsForSession(sessionKey)\n .filter((row) => {\n if (!row || typeof row !== 'object') return false;\n const record = row as unknown as Record<string, unknown>;\n const role = record.role;\n return role === 'user' || role === 'assistant' || role === 'compactionSummary' || role === 'branchSummary';\n })\n .slice(-12);\n const lines = rows\n .map((row) => {\n const record = row as unknown as Record<string, unknown>;\n const rowRole = typeof record.role === 'string' ? record.role : 'message';\n const role = rowRole === 'compactionSummary' || rowRole === 'branchSummary' ? 'summary' : rowRole;\n const text = (typeof record.summary === 'string' ? record.summary : undefined) ?? textFromTranscriptContent(record.content);\n const compact = text.trim().replace(/\\s+/g, ' ').slice(0, 280);\n return compact ? `- ${role}: ${compact}` : '';\n })\n .filter(Boolean);\n return lines.length > 0\n ? [`Session summary for ${sessionKey}:`, ...lines].join('\\n')\n : `Session summary for ${sessionKey}: no transcript content available.`;\n}\n\nfunction buildWorkItemChatSessionMetadata(params: {\n agentId: string;\n accountId: string;\n peerId: string;\n workItemId: string;\n title: string;\n updatedAt: number;\n}): SessionMetadataSeed {\n return {\n name: params.title,\n tags: ['work-item'],\n sourceChannel: 'webchat',\n sourceChatId: [params.accountId, 'direct', params.peerId].join(':'),\n sessionType: 'chat',\n hiddenFromSessionList: true,\n routing: {\n agentId: params.agentId,\n source: 'webchat',\n accountId: params.accountId,\n peerKind: 'direct',\n peerId: params.peerId,\n },\n customData: {\n genericNewChatShell: false,\n sourceBinding: {\n kind: 'work_item',\n sourceId: params.workItemId,\n version: String(params.updatedAt),\n attachedAt: Date.now(),\n },\n },\n };\n}\n\nfunction listFailedProjectWorkflowRuns(projectId: string, limit = 5): ProjectWorkflowRunBrief[] {\n const rows = getSqliteDatabase()\n .prepare(\n `SELECT run_id, definition_id, status, created_at_ms, error_message\n FROM workflow_runs\n WHERE project_id = ? AND status IN ('failed', 'timeout', 'cancelled')\n ORDER BY created_at_ms DESC\n LIMIT ?`,\n )\n .all(projectId, Math.max(1, Math.min(20, Math.floor(limit)))) as Array<{\n run_id: string;\n definition_id: string;\n status: string;\n created_at_ms: number;\n error_message: string | null;\n }>;\n return rows.map((row) => ({\n runId: row.run_id,\n definitionId: row.definition_id,\n status: row.status,\n createdAt: row.created_at_ms,\n errorMessage: row.error_message ?? undefined,\n }));\n}\n\nfunction buildProjectDigestMemoryContent(input: ReturnType<typeof buildProjectLoopOverview> & { projectName: string }): string {\n const lines = [\n `Project digest: ${input.projectName}`,\n `Status: ${input.digest.summary}`,\n input.digest.nextAction ? `Next: ${input.digest.nextAction}` : undefined,\n ].filter(Boolean) as string[];\n if (input.attentionItems.length > 0) {\n lines.push('', 'Attention:');\n for (const item of input.attentionItems.slice(0, 8)) {\n lines.push(`- ${item.kind}: ${item.title}${item.detail ? ` - ${item.detail}` : ''}`);\n }\n }\n if (input.timeline.length > 0) {\n lines.push('', 'Recent activity:');\n for (const item of input.timeline.slice(0, 8)) {\n lines.push(`- ${item.kind}: ${item.title}${item.detail ? ` - ${item.detail}` : ''}`);\n }\n }\n return lines.join('\\n');\n}\n\nfunction projectDigestMemoryRecordId(projectId: string): string {\n return `project-digest:${projectId}`;\n}\n\nexport function registerProjectsRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service } = deps;\n const activity = new ActivityService();\n const goals = new GoalService();\n const workItems = new WorkItemService();\n\n authenticated.post('/api/projects', async (c) => {\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const name = textField(body, 'name')?.trim();\n const workspaceRoot = textField(body, 'workspaceRoot')?.trim();\n if (!name && !workspaceRoot) return c.json({ ok: false, error: 'Missing name' }, 400);\n const hasDefaultAgentPatch = Object.hasOwn(body, 'defaultAgentId');\n const explicitDefaultAgentId = normalizeProjectAgentId(textField(body, 'defaultAgentId'));\n const defaultAgentId = hasDefaultAgentPatch\n ? explicitDefaultAgentId\n : inferSuggestedProjectDefaultAgentId({\n config: service.currentConfig,\n name,\n description: textField(body, 'description'),\n workspaceRoot,\n projectKind: textField(body, 'projectKind'),\n });\n if (!isValidProjectAgentId(service.currentConfig, defaultAgentId)) {\n return c.json({ ok: false, error: 'Default agent not found' }, 400);\n }\n try {\n const project = service.projects.create({\n name,\n description: textField(body, 'description'),\n defaultAgentId,\n workspaceRoot,\n createWorkspaceRoot: body.createWorkspaceRoot === true,\n projectKind: textField(body, 'projectKind'),\n brief: textField(body, 'brief'),\n instructions: textField(body, 'instructions'),\n });\n return c.json({ ok: true, project: enrichProjectWorkspace(service, project) }, 201);\n } catch (error) {\n if (error instanceof ProjectWorkspaceConflictError) {\n return c.json({ ok: false, code: 'workspace_already_bound', error: error.message, project: error.project }, 409);\n }\n if (error instanceof ProjectWorkspaceMissingError) {\n return c.json({ ok: false, code: 'workspace_root_missing', error: error.message, workspaceRoot: error.workspaceRoot }, 409);\n }\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 400);\n }\n });\n\n authenticated.get('/api/projects', async (c) => {\n const status = parseProjectStatus(c.req.query('status'));\n const result = service.projects.list({\n ...(status ? { status } : {}),\n search: c.req.query('search'),\n sortBy: c.req.query('sortBy') as 'updatedAt' | 'createdAt' | 'name' | undefined,\n sortOrder: c.req.query('sortOrder') as 'asc' | 'desc' | undefined,\n limit: parseLimit(c.req.query('limit')),\n offset: c.req.query('offset') ? Math.max(0, Number.parseInt(c.req.query('offset')!, 10) || 0) : undefined,\n });\n return c.json({ ok: true, ...result, items: result.items.map((project) => enrichProjectWorkspace(service, project)) });\n });\n\n authenticated.get('/api/projects/suggestions', async (c) => {\n const sessionKey = c.req.query('sessionKey')?.trim();\n return c.json({ ok: true, suggestions: sessionKey ? service.projects.suggestProjectsForSession(sessionKey) : [] });\n });\n\n authenticated.post('/api/projects/infer-defaults', async (c) => {\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const input = {\n name: textField(body, 'name'),\n description: textField(body, 'description'),\n workspaceRoot: textField(body, 'workspaceRoot'),\n projectKind: textField(body, 'projectKind'),\n };\n const inference = inferProjectKind(input);\n const defaultAgentId = inferSuggestedProjectDefaultAgentId({\n config: service.currentConfig,\n ...input,\n });\n return c.json({ ok: true, inference, defaultAgentId });\n });\n\n authenticated.post('/api/projects/resolve-workspace', async (c) => {\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const workspacePath = textField(body, 'workspacePath')?.trim();\n if (!workspacePath) return c.json({ ok: false, error: 'Missing workspacePath' }, 400);\n const agentId = textField(body, 'agentId')?.trim() || 'main';\n const suggestedDefaultAgentId = inferSuggestedProjectDefaultAgentId({\n config: service.currentConfig,\n workspaceRoot: workspacePath,\n projectKind: textField(body, 'projectKind'),\n });\n let match;\n try {\n match = service.projects.resolveOrCreateForWorkspacePath({\n workspacePath,\n agentId,\n defaultAgentId: suggestedDefaultAgentId,\n autoCreate: body.autoCreate !== false,\n });\n } catch (error) {\n if (error instanceof ProjectWorkspaceConflictError) {\n match = { project: error.project, reason: 'exact' as const, created: false };\n } else {\n throw error;\n }\n }\n if (!match) return c.json({ ok: true, project: null });\n\n const sessionKey = textField(body, 'sessionKey')?.trim();\n const projectDefaultAgentId = normalizeProjectAgentId(match.project.defaultAgentId);\n const shouldBindRequestedSession = !projectDefaultAgentId || projectDefaultAgentId === normalizeProjectAgentId(agentId);\n if (sessionKey && shouldBindRequestedSession) {\n const existingSession = getSessionMetadata(sessionKey);\n if (!existingSession) {\n await service.sessionIndexInstance.saveMessages(sessionKey, [], {\n metadata: {\n sourceChannel: 'tui',\n sourceChatId: `default:direct:${sessionKey}`,\n sessionType: 'chat',\n projectId: match.project.id,\n routing: {\n agentId,\n source: 'tui',\n accountId: 'default',\n peerKind: 'direct',\n peerId: sessionKey,\n },\n },\n });\n }\n service.projects.attachSession(sessionKey, match.project.id);\n }\n\n return c.json({ ok: true, ...match });\n });\n\n authenticated.get('/api/projects/:id/overview', async (c) => {\n const project = service.projects.getWithDetails(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const goalIds = service.projects.listGoalIds(project.id, parseLimit(c.req.query('goalLimit'), 100));\n const projectGoals = goalIds\n .map((id) => goals.get(id))\n .filter((goal): goal is GoalWithDetails => Boolean(goal));\n const loop = buildProjectLoopOverview({\n project,\n goals: projectGoals,\n recentWorkflowRuns: project.recentWorkflowRuns,\n failedWorkflowRuns: listFailedProjectWorkflowRuns(project.id),\n memoryRecords: listMemoryRecords({ projectId: project.id, status: 'active', limit: 5 }),\n });\n return c.json({\n ok: true,\n overview: {\n project: enrichProjectWorkspace(service, project),\n stats: {\n sessionCount: project.sessionCount,\n goalCount: project.goalCount,\n activeGoalCount: project.activeGoalCount,\n recentWorkflowRunCount: project.recentWorkflowRuns.length,\n staleGoalCount: loop.staleGoals.length,\n attentionCount: loop.attentionItems.length,\n failedWorkflowRunCount: loop.failedWorkflowRuns.length,\n },\n activeGoals: loop.activeGoals,\n blockedGoals: loop.blockedGoals,\n staleGoals: loop.staleGoals,\n nextActions: loop.nextActions,\n attentionItems: loop.attentionItems,\n timeline: loop.timeline,\n digest: loop.digest,\n failedWorkflowRuns: loop.failedWorkflowRuns,\n recentSessions: project.recentSessions,\n recentWorkflowRuns: project.recentWorkflowRuns,\n recommendedAction: loop.recommendedAction,\n },\n });\n });\n\n authenticated.get('/api/projects/:id/activity', (c) => {\n const project = service.projects.get(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const result = activity.listForProject({\n projectId: project.id,\n includeRelated: parseActivityIncludeRelated(c.req.query('includeRelated')),\n ...parseActivityQuery(c),\n });\n return c.json({ ok: true, ...result });\n });\n\n authenticated.get('/api/projects/:id/work-items', async (c) => {\n const project = service.projects.get(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const result = workItems.listProjectWorkItems(project.id, {\n status: parseCsvEnum(c.req.query('status'), WORK_ITEM_STATUSES),\n priority: parseCsvEnum(c.req.query('priority'), WORK_ITEM_PRIORITIES),\n includeArchived: c.req.query('includeArchived') === 'true',\n search: c.req.query('search'),\n sortBy: c.req.query('sortBy') as 'updatedAt' | 'createdAt' | 'priority' | 'status' | undefined,\n sortOrder: c.req.query('sortOrder') as 'asc' | 'desc' | undefined,\n limit: parseLimit(c.req.query('limit')),\n offset: c.req.query('offset') ? Math.max(0, Number.parseInt(c.req.query('offset')!, 10) || 0) : undefined,\n });\n return c.json({ ok: true, ...result });\n });\n\n authenticated.post('/api/projects/:id/work-items', async (c) => {\n const project = service.projects.get(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const contentType = c.req.header('content-type') || '';\n let body: Record<string, unknown>;\n let files: File[] = [];\n if (contentType.includes('multipart/form-data')) {\n try {\n body = await c.req.parseBody({ all: true }) as Record<string, unknown>;\n } catch {\n return c.json({ ok: false, error: 'Invalid multipart body' }, 400);\n }\n files = collectUploadedFiles(body);\n } else {\n body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n }\n const attachmentError = validateUploadedWorkItemFiles(files);\n if (attachmentError) return c.json({ ok: false, error: attachmentError }, 413);\n const title = textField(body, 'title')?.trim();\n if (!title) return c.json({ ok: false, error: 'Work item title is required' }, 400);\n const status = parseEnumValue(body.status, WORK_ITEM_STATUSES);\n const priority = parseEnumValue(body.priority, WORK_ITEM_PRIORITIES);\n const dueAt = finiteNumberField(body.dueAt);\n if (Object.hasOwn(body, 'status') && !status) return c.json({ ok: false, error: 'Invalid work item status' }, 400);\n if (Object.hasOwn(body, 'priority') && !priority) return c.json({ ok: false, error: 'Invalid work item priority' }, 400);\n if (Object.hasOwn(body, 'dueAt') && dueAt === undefined && body.dueAt !== null) return c.json({ ok: false, error: 'Invalid dueAt' }, 400);\n const uploads: Array<{ name: string; buffer: Buffer; mimeType: string }> = [];\n for (const file of files) {\n uploads.push(await uploadedFileToBuffer(file));\n }\n const item = workItems.createProjectWorkItem(project.id, {\n title,\n description: textField(body, 'description'),\n status,\n priority,\n ownerAgentId: textField(body, 'ownerAgentId') || project.defaultAgentId || undefined,\n nextAction: textField(body, 'nextAction'),\n blockedReason: textField(body, 'blockedReason'),\n dueAt,\n });\n for (const upload of uploads) {\n await workItems.addAttachment(item.id, upload);\n }\n const created = files.length > 0 ? workItems.getWorkItem(item.id) ?? item : item;\n return c.json({ ok: true, item: created }, 201);\n });\n\n authenticated.get('/api/work-items/:id', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n return c.json({ ok: true, item });\n });\n\n authenticated.get('/api/work-items/:id/attachments', async (c) => {\n const attachments = workItems.listAttachments(c.req.param('id'));\n if (!attachments) return c.json({ ok: false, error: 'Work item not found' }, 404);\n return c.json({ ok: true, attachments });\n });\n\n authenticated.post('/api/work-items/:id/attachments', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n let body: Record<string, unknown>;\n try {\n body = await c.req.parseBody({ all: true }) as Record<string, unknown>;\n } catch {\n return c.json({ ok: false, error: 'Invalid multipart body' }, 400);\n }\n const files = collectUploadedFiles(body);\n if (!files.length) return c.json({ ok: false, error: 'Missing file field' }, 400);\n const attachmentError = validateUploadedWorkItemFiles(files);\n if (attachmentError) return c.json({ ok: false, error: attachmentError }, 413);\n const attachments = [];\n for (const file of files) {\n const upload = await uploadedFileToBuffer(file);\n const attachment = await workItems.addAttachment(item.id, upload);\n if (attachment) attachments.push(attachment);\n }\n return c.json({ ok: true, attachments, item: workItems.getWorkItem(item.id) }, 201);\n });\n\n authenticated.get('/api/work-items/:id/attachments/:attachmentId/content', async (c) => {\n const result = await workItems.readAttachment(c.req.param('id'), c.req.param('attachmentId'));\n if (!result) return c.json({ ok: false, error: 'Attachment not found' }, 404);\n return new Response(result.buffer, {\n headers: {\n 'Content-Type': result.attachment.mimeType,\n 'Content-Length': String(result.attachment.size),\n 'Content-Disposition': `inline; filename=\"${encodeURIComponent(result.attachment.fileName)}\"`,\n 'Cache-Control': 'private, max-age=31536000, immutable',\n },\n });\n });\n\n authenticated.delete('/api/work-items/:id/attachments/:attachmentId', async (c) => {\n const attachment = await workItems.removeAttachment(c.req.param('id'), c.req.param('attachmentId'));\n if (!attachment) return c.json({ ok: false, error: 'Attachment not found' }, 404);\n return c.json({ ok: true, attachment, item: workItems.getWorkItem(c.req.param('id')) });\n });\n\n authenticated.patch('/api/work-items/:id', async (c) => {\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const status = Object.hasOwn(body, 'status')\n ? parseEnumValue(body.status, WORK_ITEM_STATUSES)\n : undefined;\n const priority = Object.hasOwn(body, 'priority')\n ? parseEnumValue(body.priority, WORK_ITEM_PRIORITIES)\n : undefined;\n const dueAt = Object.hasOwn(body, 'dueAt')\n ? (body.dueAt === null ? null : (typeof body.dueAt === 'number' && Number.isFinite(body.dueAt) ? body.dueAt : undefined))\n : undefined;\n const archivedAt = Object.hasOwn(body, 'archivedAt')\n ? (body.archivedAt === null ? null : (typeof body.archivedAt === 'number' && Number.isFinite(body.archivedAt) ? body.archivedAt : undefined))\n : undefined;\n if (status === undefined && Object.hasOwn(body, 'status')) return c.json({ ok: false, error: 'Invalid work item status' }, 400);\n if (priority === undefined && Object.hasOwn(body, 'priority')) return c.json({ ok: false, error: 'Invalid work item priority' }, 400);\n if (dueAt === undefined && Object.hasOwn(body, 'dueAt')) return c.json({ ok: false, error: 'Invalid dueAt' }, 400);\n if (archivedAt === undefined && Object.hasOwn(body, 'archivedAt')) return c.json({ ok: false, error: 'Invalid archivedAt' }, 400);\n\n const item = workItems.updateWorkItem(c.req.param('id'), {\n ...(Object.hasOwn(body, 'title') ? { title: textField(body, 'title') ?? '' } : {}),\n ...(Object.hasOwn(body, 'description') ? { description: optionalTextField(body, 'description') } : {}),\n ...(Object.hasOwn(body, 'status') ? { status } : {}),\n ...(Object.hasOwn(body, 'priority') ? { priority } : {}),\n ...(Object.hasOwn(body, 'ownerAgentId') ? { ownerAgentId: optionalTextField(body, 'ownerAgentId') } : {}),\n ...(Object.hasOwn(body, 'nextAction') ? { nextAction: optionalTextField(body, 'nextAction') } : {}),\n ...(Object.hasOwn(body, 'blockedReason') ? { blockedReason: optionalTextField(body, 'blockedReason') } : {}),\n ...(Object.hasOwn(body, 'dueAt') ? { dueAt } : {}),\n ...(Object.hasOwn(body, 'archivedAt') ? { archivedAt } : {}),\n });\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n return c.json({ ok: true, item });\n });\n\n authenticated.delete('/api/work-items/:id', async (c) => {\n const item = workItems.updateWorkItem(c.req.param('id'), { archivedAt: Date.now() });\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n return c.json({ ok: true, item });\n });\n\n authenticated.get('/api/work-items/:id/events', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n return c.json({ ok: true, events: workItems.listEvents(item.id) });\n });\n\n authenticated.get('/api/work-items/:id/update-suggestions', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n const status = parseEnumValue(c.req.query('status'), WORK_ITEM_SUGGESTION_STATUSES);\n if (c.req.query('status') && !status) return c.json({ ok: false, error: 'Invalid suggestion status' }, 400);\n return c.json({ ok: true, suggestions: workItems.listUpdateSuggestions(item.id, status) });\n });\n\n authenticated.post('/api/work-items/:id/update-suggestions', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const sourceKind = parseEnumValue(body.sourceKind, ['chat', 'goal', 'workflow_run', 'automation'] as const);\n const sourceId = textField(body, 'sourceId')?.trim();\n if (!sourceKind) return c.json({ ok: false, error: 'Invalid sourceKind' }, 400);\n if (!sourceId) return c.json({ ok: false, error: 'sourceId is required' }, 400);\n const patchBody = body.patch && typeof body.patch === 'object' && !Array.isArray(body.patch)\n ? body.patch as Record<string, unknown>\n : {};\n const status = Object.hasOwn(patchBody, 'status')\n ? parseEnumValue(patchBody.status, WORK_ITEM_STATUSES)\n : undefined;\n if (Object.hasOwn(patchBody, 'status') && !status) return c.json({ ok: false, error: 'Invalid work item status' }, 400);\n const confidence = typeof body.confidence === 'number' && Number.isFinite(body.confidence)\n ? Math.max(0, Math.min(1, body.confidence))\n : undefined;\n const suggestion = workItems.createUpdateSuggestion(item.id, {\n sourceKind,\n sourceId,\n patch: {\n ...(Object.hasOwn(patchBody, 'status') ? { status } : {}),\n ...(Object.hasOwn(patchBody, 'nextAction') ? { nextAction: optionalTextField(patchBody, 'nextAction') } : {}),\n ...(Object.hasOwn(patchBody, 'blockedReason') ? { blockedReason: optionalTextField(patchBody, 'blockedReason') } : {}),\n },\n progressNote: optionalTextField(body, 'progressNote') ?? undefined,\n rationale: optionalTextField(body, 'rationale') ?? undefined,\n confidence,\n });\n if (!suggestion) return c.json({ ok: false, error: 'Work item not found' }, 404);\n return c.json({ ok: true, suggestion }, 201);\n });\n\n authenticated.post('/api/work-item-update-suggestions/:id/apply', async (c) => {\n const result = workItems.applyUpdateSuggestion(c.req.param('id'));\n if (!result) return c.json({ ok: false, error: 'Suggestion not found or already resolved' }, 404);\n return c.json({ ok: true, item: result.item, suggestion: result.suggestion });\n });\n\n authenticated.post('/api/work-item-update-suggestions/:id/dismiss', async (c) => {\n const suggestion = workItems.dismissUpdateSuggestion(c.req.param('id'));\n if (!suggestion) return c.json({ ok: false, error: 'Suggestion not found or already resolved' }, 404);\n return c.json({ ok: true, suggestion });\n });\n\n authenticated.post('/api/work-items/:id/start-chat', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n const project = service.projects.get(item.projectId);\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const agentId = resolveProjectAgentId({\n config: service.currentConfig,\n projects: service.projects,\n explicitAgentId: item.ownerAgentId,\n projectId: project.id,\n });\n const peerId = `work_item_${Date.now()}`;\n const sessionKey = buildSessionKey({\n agentId,\n source: 'webchat',\n accountId: 'default',\n peerKind: 'direct',\n peerId,\n });\n await service.sessionIndexInstance.saveMessages(sessionKey, [], {\n metadata: buildWorkItemChatSessionMetadata({\n agentId,\n accountId: 'default',\n peerId,\n workItemId: item.id,\n title: item.title,\n updatedAt: item.updatedAt,\n }),\n });\n service.projects.attachSession(sessionKey, project.id);\n const session = await service.sessions.getSession(sessionKey);\n workItems.addLink(item.id, {\n kind: 'chat',\n targetId: sessionKey,\n title: session?.name || item.title,\n statusSnapshot: session?.status,\n }, 'chat_started');\n const updated = item.status === 'todo' || item.status === 'backlog'\n ? workItems.updateWorkItem(item.id, { status: 'in_progress' })\n : workItems.getWorkItem(item.id);\n return c.json({ ok: true, session, item: updated }, 201);\n });\n\n authenticated.post('/api/work-items/:id/create-goal', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n const project = service.projects.get(item.projectId);\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const attachments = await workItems.snapshotAttachmentsForGoal(item.id);\n if (!attachments) return c.json({ ok: false, error: 'Work item not found' }, 404);\n const context = await buildWorkItemAgentContext(item, { attachments, includeImages: false });\n const goal = goals.create({\n title: item.title,\n description: item.description || item.nextAction,\n priority: item.priority === 'urgent' ? 'high' : item.priority,\n agentId: item.ownerAgentId || project.defaultAgentId || undefined,\n projectId: project.id,\n source: 'api',\n config: service.currentConfig,\n });\n const goalWithContext = goals.setContextMessage({\n goalId: goal.id,\n text: context.text,\n attachments,\n }) ?? goal;\n workItems.addLink(item.id, {\n kind: 'goal',\n targetId: goal.id,\n title: goal.title,\n statusSnapshot: goal.status,\n }, 'goal_created');\n const updated = item.status === 'todo' || item.status === 'backlog'\n ? workItems.updateWorkItem(item.id, { status: 'in_progress' })\n : workItems.getWorkItem(item.id);\n return c.json({ ok: true, goal: goalWithContext, item: updated }, 201);\n });\n\n authenticated.post('/api/work-items/:id/workflows/run', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n const project = service.projects.get(item.projectId);\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n if (item.status === 'done' || item.status === 'cancelled' || item.archivedAt) {\n return c.json({ ok: false, error: 'Work item is not active' }, 409);\n }\n\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const definitionId = textField(body, 'definitionId')?.trim();\n if (!definitionId) return c.json({ ok: false, error: 'Missing definitionId' }, 400);\n\n const agentId = resolveProjectAgentId({\n config: service.currentConfig,\n projects: service.projects,\n explicitAgentId: item.ownerAgentId,\n projectId: project.id,\n });\n const goalText = textField(body, 'goal')?.trim() || item.nextAction || item.title;\n const attachments = item.attachments?.map((attachment) => ({\n id: attachment.id,\n fileName: attachment.fileName,\n type: attachment.type,\n mimeType: attachment.mimeType,\n size: attachment.size,\n }));\n const input = Object.hasOwn(body, 'input') ? body.input : {\n workItem: {\n id: item.id,\n title: item.title,\n description: item.description,\n status: item.status,\n priority: item.priority,\n nextAction: item.nextAction,\n blockedReason: item.blockedReason,\n attachments,\n },\n project: {\n id: project.id,\n name: project.name,\n description: project.description,\n brief: project.brief,\n instructions: project.instructions,\n workspaceRoot: project.workspaceRoot,\n },\n };\n const rawTokenBudget = body.tokenBudget;\n const tokenBudget = rawTokenBudget === null\n ? null\n : typeof rawTokenBudget === 'number' && Number.isFinite(rawTokenBudget)\n ? rawTokenBudget\n : undefined;\n\n const result = await service.createWorkflowRunService().startWorkflowRun({\n agentId,\n definitionId,\n projectId: project.id,\n workItemId: item.id,\n goal: goalText,\n input,\n source: { kind: 'webui' },\n concurrency: finiteNumberField(body.concurrency),\n maxSubagents: finiteNumberField(body.maxSubagents),\n tokenBudget,\n });\n if (result.ok === false) {\n return c.json({ ok: false, error: result.message, code: result.code }, result.httpStatus);\n }\n\n workItems.addLink(item.id, {\n kind: 'workflow_run',\n targetId: result.runId,\n title: goalText,\n statusSnapshot: 'queued',\n }, 'workflow_started');\n const updated = item.status === 'todo' || item.status === 'backlog'\n ? workItems.updateWorkItem(item.id, { status: 'in_progress' })\n : workItems.getWorkItem(item.id);\n return c.json({ ok: true, runId: result.runId, sessionKey: result.sessionKey, item: updated }, 202);\n });\n\n authenticated.post('/api/projects/:id/digest-memory', async (c) => {\n const project = service.projects.getWithDetails(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const goalIds = service.projects.listGoalIds(project.id, 100);\n const projectGoals = goalIds\n .map((id) => goals.get(id))\n .filter((goal): goal is GoalWithDetails => Boolean(goal));\n const loop = buildProjectLoopOverview({\n project,\n goals: projectGoals,\n recentWorkflowRuns: project.recentWorkflowRuns,\n failedWorkflowRuns: listFailedProjectWorkflowRuns(project.id),\n memoryRecords: listMemoryRecords({ projectId: project.id, status: 'active', limit: 5 }),\n });\n const record = upsertMemoryRecord({\n id: projectDigestMemoryRecordId(project.id),\n providerId: 'local',\n kind: 'daily_note',\n agentId: resolveProjectAgentId({\n config: service.currentConfig,\n projects: service.projects,\n projectId: project.id,\n }),\n workspaceId: project.workspaceRoot,\n projectId: project.id,\n content: buildProjectDigestMemoryContent({ ...loop, projectName: project.name }),\n source: {\n provider: 'project-digest',\n },\n confidence: 0.75,\n tags: ['project', 'project-digest', project.slug],\n status: 'active',\n sensitivity: 'normal',\n });\n return c.json({ ok: true, record }, 201);\n });\n\n authenticated.post('/api/projects/:id/blockers', async (c) => {\n const project = service.projects.getWithDetails(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const title = typeof body.title === 'string' ? body.title.trim() : '';\n if (!title) return c.json({ ok: false, error: 'Missing title' }, 400);\n const reason = typeof body.reason === 'string' ? body.reason.trim() : '';\n const goal = goals.create({\n title,\n description: reason || undefined,\n agentId: resolveProjectAgentId({\n config: service.currentConfig,\n projects: service.projects,\n projectId: project.id,\n }),\n priority: body.priority === 'low' || body.priority === 'normal' || body.priority === 'high' ? body.priority : 'high',\n source: 'api',\n projectId: project.id,\n });\n const blocked = goals.setStatus(goal.id, 'blocked', { reason: reason || title });\n if (reason) {\n goals.setContextMessage({ goalId: goal.id, text: reason });\n }\n return c.json({ ok: true, goal: blocked ?? goals.get(goal.id) }, 201);\n });\n\n authenticated.post('/api/projects/:id/pin', async (c) => {\n try {\n const project = service.projects.pin(c.req.param('id'));\n return c.json({ ok: true, project: enrichProjectWorkspace(service, project) });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.post('/api/projects/:id/unpin', async (c) => {\n try {\n const project = service.projects.unpin(c.req.param('id'));\n return c.json({ ok: true, project: enrichProjectWorkspace(service, project) });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.get('/api/projects/:id', async (c) => {\n const project = service.projects.getWithDetails(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n return c.json({ ok: true, project: enrichProjectWorkspace(service, project) });\n });\n\n authenticated.patch('/api/projects/:id', async (c) => {\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const status = parseProjectStatus(body.status);\n const defaultAgentPatch = optionalTextField(body, 'defaultAgentId');\n const defaultAgentId = defaultAgentPatch === undefined ? undefined : normalizeProjectAgentId(defaultAgentPatch);\n if (defaultAgentId && !isValidProjectAgentId(service.currentConfig, defaultAgentId)) {\n return c.json({ ok: false, error: 'Default agent not found' }, 400);\n }\n try {\n const project = service.projects.update(c.req.param('id'), {\n ...(textField(body, 'name') !== undefined ? { name: textField(body, 'name') } : {}),\n ...(optionalTextField(body, 'description') !== undefined ? { description: optionalTextField(body, 'description') } : {}),\n ...(status ? { status } : {}),\n ...(defaultAgentPatch !== undefined ? { defaultAgentId: defaultAgentId ?? null } : {}),\n ...(optionalTextField(body, 'workspaceRoot') !== undefined ? { workspaceRoot: optionalTextField(body, 'workspaceRoot') } : {}),\n createWorkspaceRoot: body.createWorkspaceRoot === true,\n ...(optionalTextField(body, 'brief') !== undefined ? { brief: optionalTextField(body, 'brief') } : {}),\n ...(optionalTextField(body, 'instructions') !== undefined ? { instructions: optionalTextField(body, 'instructions') } : {}),\n });\n return c.json({ ok: true, project: enrichProjectWorkspace(service, project) });\n } catch (error) {\n if (error instanceof ProjectWorkspaceConflictError) {\n return c.json({ ok: false, code: 'workspace_already_bound', error: error.message, project: error.project }, 409);\n }\n if (error instanceof ProjectWorkspaceMissingError) {\n return c.json({ ok: false, code: 'workspace_root_missing', error: error.message, workspaceRoot: error.workspaceRoot }, 409);\n }\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.delete('/api/projects/:id', async (c) => {\n service.projects.delete(c.req.param('id'));\n return c.json({ ok: true });\n });\n\n authenticated.get('/api/projects/:id/sessions', async (c) => {\n try {\n const keys = service.projects.listSessionKeys(c.req.param('id'), parseLimit(c.req.query('limit'), 100));\n const sessions = await Promise.all(keys.map((key) => service.sessions.getSession(key)));\n return c.json({\n ok: true,\n sessions: sessions.filter((session) => session && !isHiddenEmptyProjectChatShell(session)),\n });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.get('/api/projects/:id/goals', async (c) => {\n try {\n const ids = service.projects.listGoalIds(c.req.param('id'), parseLimit(c.req.query('limit'), 100));\n return c.json({ ok: true, goals: ids.map((id) => goals.get(id)).filter(Boolean) });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.get('/api/projects/:id/files', async (c) => {\n const resolved = await resolveProjectWorkspacePath(service, c.req.param('id'), c.req.query('path'));\n if (resolved.ok === false) return c.json({ ok: false, error: resolved.error }, resolved.status as 400);\n const { root, absolutePath: candidate } = resolved;\n let currentPath: string;\n try {\n currentPath = await realpath(candidate);\n if (!isWithinDirectory(root, currentPath)) {\n return c.json({ ok: false, error: 'Path is outside project workspace' }, 400);\n }\n const currentStat = await stat(currentPath);\n if (!currentStat.isDirectory()) {\n return c.json({ ok: false, error: 'Path is not a directory' }, 400);\n }\n } catch (err) {\n log.warn({ err, projectId: resolved.projectId, path: candidate }, 'project file path unavailable');\n return c.json({ ok: false, error: 'Path not found' }, 404);\n }\n\n try {\n const dirents = await readdir(currentPath, { withFileTypes: true });\n const entries = await Promise.all(dirents\n .filter((entry) => !SKIP_FILE_NAMES.has(entry.name))\n .map(async (entry) => {\n const displayPath = path.join(currentPath, entry.name);\n const absolutePath = await realpath(displayPath).catch(() => null);\n if (!absolutePath || !isWithinDirectory(root, absolutePath)) return null;\n const entryStat = await stat(absolutePath).catch(() => null);\n if (!entryStat) return null;\n const relativePath = path.relative(root, displayPath).split(path.sep).join('/');\n return {\n name: entry.name,\n path: relativePath,\n absolutePath,\n type: entryStat.isDirectory() ? 'directory' : 'file',\n size: entryStat?.isFile() ? entryStat.size : undefined,\n updatedAt: entryStat?.mtime.toISOString(),\n };\n }));\n const visibleEntries = entries.filter((entry): entry is NonNullable<typeof entry> => entry !== null);\n visibleEntries.sort((left, right) => {\n if (left.type !== right.type) return left.type === 'directory' ? -1 : 1;\n return left.name.localeCompare(right.name);\n });\n const relativeCurrentPath = path.relative(root, currentPath).split(path.sep).join('/');\n const parentRelativePath = relativeCurrentPath ? path.dirname(relativeCurrentPath).replaceAll('\\\\', '/') : null;\n return c.json({\n ok: true,\n root,\n path: relativeCurrentPath === '.' ? '' : relativeCurrentPath,\n parentPath: parentRelativePath === '.' ? '' : parentRelativePath,\n entries: visibleEntries,\n });\n } catch (err) {\n log.warn({ err, projectId: resolved.projectId, path: currentPath }, 'project file list failed');\n if ((err as NodeJS.ErrnoException)?.code === 'EACCES') {\n return c.json({ ok: false, error: 'Permission denied' }, 403);\n }\n return c.json({ ok: false, error: 'Failed to read project files' }, 500);\n }\n });\n\n /** Fuzzy filename / path search across the entire project workspace. */\n authenticated.get('/api/projects/:id/files/search', async (c) => {\n const q = typeof c.req.query('q') === 'string' ? c.req.query('q')!.trim() : '';\n const limitRaw = c.req.query('limit');\n const limit = Math.min(\n Math.max(parseInt(typeof limitRaw === 'string' ? limitRaw : '50', 10) || 50, 1),\n FILE_SEARCH_MAX_LIMIT,\n );\n const root = await resolveProjectWorkspaceRoot(service, c.req.param('id'));\n if (root.ok === false) return c.json({ ok: false, error: root.error }, root.status as 400);\n const entries = await fuzzySearchWorkspaceFiles(root.root, q, limit);\n return c.json({ ok: true, entries });\n });\n\n authenticated.get('/api/projects/:id/files/read', async (c) => {\n const resolved = await resolveExistingProjectWorkspacePath(service, c.req.param('id'), c.req.query('path'));\n if (resolved.ok === false) return c.json({ ok: false, error: { message: resolved.error } }, resolved.status as 400);\n if (!resolved.stat.isFile()) {\n return c.json({ ok: false, error: { message: 'Not a file' } }, 400);\n }\n try {\n const content = await readFile(resolved.absolutePath, 'utf-8');\n return c.json({\n ok: true,\n payload: {\n content,\n path: resolved.relativePath,\n absolutePath: resolved.absolutePath,\n mtimeMs: resolved.stat.mtimeMs,\n },\n });\n } catch {\n return c.json({ ok: false, error: { message: 'Read failed' } }, 500);\n }\n });\n\n authenticated.get('/api/projects/:id/files/raw', async (c) => {\n const resolved = await resolveExistingProjectWorkspacePath(service, c.req.param('id'), c.req.query('path'));\n if (resolved.ok === false) return c.json({ ok: false, error: { message: resolved.error } }, resolved.status as 400);\n if (!resolved.stat.isFile()) {\n return c.json({ ok: false, error: { message: 'Not a file' } }, 400);\n }\n const ext = resolved.relativePath.split('.').pop()?.toLowerCase() ?? '';\n const contentType = PROJECT_FILE_MIME_BY_EXT[ext] || 'application/octet-stream';\n try {\n const buf = await readFile(resolved.absolutePath);\n return new Response(buf, {\n headers: {\n 'Content-Type': contentType,\n 'Cache-Control': 'private, max-age=3600',\n },\n });\n } catch {\n return c.json({ ok: false, error: { message: 'Read failed' } }, 500);\n }\n });\n\n authenticated.get('/api/projects/:id/files/resolve-reference', async (c) => {\n const rawPath = typeof c.req.query('path') === 'string' ? c.req.query('path')!.trim() : '';\n if (!rawPath) {\n return c.json({ ok: false, error: { code: 'INVALID_PATH', message: 'Missing path' } }, 400);\n }\n const resolved = await resolveProjectWorkspacePath(service, c.req.param('id'), rawPath);\n if (resolved.ok === false) {\n return c.json({ ok: false, error: { code: 'PROJECT_WORKSPACE_RESOLUTION_FAILED', message: resolved.error } }, resolved.status as 400);\n }\n let st: Awaited<ReturnType<typeof stat>> | null = null;\n let absolutePath = resolved.absolutePath;\n try {\n absolutePath = await realpath(resolved.absolutePath);\n if (!isWithinDirectory(resolved.root, absolutePath)) {\n return c.json({\n ok: false,\n error: { code: 'PROJECT_WORKSPACE_RESOLUTION_FAILED', message: 'Path is outside project workspace' },\n }, 400);\n }\n st = await stat(absolutePath);\n } catch {\n st = null;\n }\n const displayName = path.basename(rawPath);\n if (!st) {\n return c.json({\n ok: true,\n payload: {\n inputPath: rawPath,\n displayName,\n scope: 'missing',\n exists: false,\n absolutePath: resolved.absolutePath,\n capabilities: ['copyPath'],\n errorCode: 'FILE_NOT_FOUND',\n },\n });\n }\n return c.json({\n ok: true,\n payload: {\n inputPath: rawPath,\n displayName,\n scope: 'workspace',\n exists: true,\n isDirectory: st.isDirectory(),\n absolutePath,\n workspaceRelativePath: resolved.relativePath,\n capabilities: st.isDirectory()\n ? ['openExternal', 'revealInFolder', 'copyPath']\n : ['preview', 'edit', 'openExternal', 'revealInFolder', 'copyPath'],\n mtimeMs: st.mtimeMs,\n },\n });\n });\n\n authenticated.put('/api/projects/:id/files/write', async (c) => {\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n return c.json({ ok: false, error: { message: 'Invalid JSON' } }, 400);\n }\n const bodyRecord = typeof body === 'object' && body !== null ? body as Record<string, unknown> : {};\n const pathRel = typeof bodyRecord.path === 'string' ? bodyRecord.path : '';\n const content = typeof bodyRecord.content === 'string' ? bodyRecord.content : '';\n if (!pathRel.trim()) {\n return c.json({ ok: false, error: { message: 'Missing path' } }, 400);\n }\n const resolved = await resolveProjectWorkspaceWritePath(service, c.req.param('id'), pathRel);\n if (resolved.ok === false) return c.json({ ok: false, error: { message: resolved.error } }, resolved.status as 400);\n if (resolved.existingStat && !resolved.existingStat.isFile()) {\n return c.json({ ok: false, error: { message: 'Not a file' } }, 400);\n }\n try {\n await writeFile(resolved.absolutePath, content, 'utf-8');\n const mtimeMs = (await stat(resolved.absolutePath).catch(() => ({ mtimeMs: Date.now() }))).mtimeMs;\n return c.json({\n ok: true,\n payload: { path: resolved.relativePath, mtimeMs },\n });\n } catch (err) {\n log.error({ err, projectId: resolved.projectId, path: resolved.absolutePath }, 'project file write failed');\n return c.json({ ok: false, error: { message: 'Write failed' } }, 500);\n }\n });\n\n authenticated.post('/api/projects/:id/sessions/:sessionKey', async (c) => {\n try {\n service.projects.attachSession(c.req.param('sessionKey'), c.req.param('id'));\n const session = await service.sessions.getSession(c.req.param('sessionKey'));\n return c.json({ ok: true, session });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.delete('/api/projects/:id/sessions/:sessionKey', async (c) => {\n try {\n const projectId = c.req.param('id');\n const sessionKey = c.req.param('sessionKey');\n if (!service.projects.get(projectId)) {\n return c.json({ ok: false, error: 'Project not found' }, 404);\n }\n const session = await service.sessions.getSession(sessionKey);\n if (!session) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n if (session.projectId !== projectId) {\n return c.json({ ok: false, error: 'Session is not attached to this project' }, 409);\n }\n service.projects.detachSession(sessionKey);\n return c.json({ ok: true });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.post('/api/projects/:id/sessions/:sessionKey/summary-memory', async (c) => {\n const projectId = c.req.param('id');\n const sessionKey = c.req.param('sessionKey');\n const project = service.projects.get(projectId);\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const session = getSessionMetadata(sessionKey);\n if (!session) return c.json({ ok: false, error: 'Session not found' }, 404);\n if (session.projectId !== projectId) {\n return c.json({ ok: false, error: 'Session is not attached to this project' }, 409);\n }\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const content = buildSessionSummaryMemoryContent(\n sessionKey,\n typeof body.summary === 'string' ? body.summary : undefined,\n );\n const record = upsertMemoryRecord({\n providerId: 'local',\n kind: 'session_summary',\n agentId: session.routing?.agentId ?? 'main',\n workspaceId: session.cwd,\n sessionKey,\n projectId,\n content,\n source: {\n provider: 'project-summary',\n sessionEntryId: sessionKey,\n },\n confidence: typeof body.confidence === 'number' ? body.confidence : 0.7,\n tags: ['project', 'session-summary', project.slug],\n status: 'active',\n sensitivity: 'normal',\n evidence: [{ sessionKey }],\n });\n return c.json({ ok: true, record }, 201);\n });\n\n authenticated.post('/api/projects/:id/goals/:goalId', async (c) => {\n try {\n service.projects.attachGoal(c.req.param('goalId'), c.req.param('id'));\n return c.json({ ok: true, goal: goals.get(c.req.param('goalId')) });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.delete('/api/projects/:id/goals/:goalId', async (c) => {\n try {\n const projectId = c.req.param('id');\n const goalId = c.req.param('goalId');\n if (!service.projects.get(projectId)) {\n return c.json({ ok: false, error: 'Project not found' }, 404);\n }\n const goal = goals.get(goalId);\n if (!goal) {\n return c.json({ ok: false, error: 'Goal not found' }, 404);\n }\n if (goal.projectId !== projectId) {\n return c.json({ ok: false, error: 'Goal is not attached to this project' }, 409);\n }\n service.projects.detachGoal(goalId);\n return c.json({ ok: true });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"projects.js","names":["path","record"],"sources":["../../../../../src/gateway/hono/routes/projects.ts"],"sourcesContent":["import type { Hono } from 'hono';\nimport { readdir, readFile, realpath, stat, writeFile } from 'node:fs/promises';\nimport * as path from 'node:path';\n\nimport { ActivityService } from '../../../activity/index.js';\nimport { resolveEffectiveAgentProfile } from '../../../config/agent-profile.js';\nimport type { GoalWithDetails } from '../../../goals/index.js';\nimport { GoalService } from '../../../goals/index.js';\nimport {\n buildProjectLoopOverview,\n inferProjectKind,\n inferSuggestedProjectDefaultAgentId,\n isValidProjectAgentId,\n normalizeProjectAgentId,\n ProjectWorkspaceConflictError,\n ProjectWorkspaceMissingError,\n type Project,\n resolveProjectAgentId,\n type ProjectStatus,\n type ProjectWorkflowRunBrief,\n} from '../../../projects/index.js';\nimport { buildSessionKey } from '../../../routing/session-key.js';\nimport {\n getSqliteDatabase,\n getSessionMetadata,\n listMemoryRecords,\n loadTranscriptRowsForSession,\n type SessionMetadataSeed,\n upsertMemoryRecord,\n} from '../../../storage/sqlite/index.js';\nimport {\n buildWorkItemAgentContext,\n WorkItemService,\n WORK_ITEM_ATTACHMENT_MAX_BYTES,\n WORK_ITEM_ATTACHMENT_MAX_COUNT,\n type WorkItemPriority,\n type WorkItemStatus,\n} from '../../../work-items/index.js';\nimport { createGatewayRouteLogger } from '../lib/route-logger.js';\nimport { parseActivityIncludeRelated, parseActivityQuery } from './activity.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\nimport { FILE_SEARCH_MAX_LIMIT, fuzzySearchWorkspaceFiles } from '../../workspace-file-search.js';\n\nconst log = createGatewayRouteLogger('Projects');\n\nfunction parseProjectStatus(raw: unknown): ProjectStatus | undefined {\n return raw === 'active' || raw === 'paused' || raw === 'archived' ? raw : undefined;\n}\n\nfunction parseLimit(raw: string | undefined, fallback = 50): number | undefined {\n if (!raw) return undefined;\n const n = Number.parseInt(raw, 10);\n return Number.isFinite(n) ? Math.min(500, Math.max(1, n)) : fallback;\n}\n\nfunction isHiddenEmptyProjectChatShell(session: {\n hiddenFromSessionList?: boolean;\n messageCount?: number;\n routing?: { peerId?: string };\n customData?: Record<string, unknown>;\n}): boolean {\n return session.hiddenFromSessionList === true\n && session.messageCount === 0\n && session.customData?.genericNewChatShell !== false\n && Boolean(session.routing?.peerId?.startsWith('chat_'));\n}\n\nfunction textField(body: Record<string, unknown>, key: string): string | undefined {\n const value = body[key];\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction optionalTextField(body: Record<string, unknown>, key: string): string | null | undefined {\n if (!(key in body)) return undefined;\n const value = body[key];\n return typeof value === 'string' ? value : null;\n}\n\nfunction resolveEffectiveWorkspaceRoot(\n service: AuthenticatedRouteDeps['service'],\n project: Project,\n): string | undefined {\n const fixedRoot = project.workspaceRoot?.trim();\n if (fixedRoot) return fixedRoot;\n const agentId = resolveProjectAgentId({\n config: service.currentConfig,\n projects: service.projects,\n projectId: project.id,\n });\n return resolveEffectiveAgentProfile(service.currentConfig, agentId).resolvedWorkspacePath;\n}\n\nfunction enrichProjectWorkspace<T extends Project>(\n service: AuthenticatedRouteDeps['service'],\n project: T,\n): T {\n return {\n ...project,\n workspaceMode: project.workspaceRoot?.trim() ? 'fixed' : 'followAgent',\n effectiveWorkspaceRoot: resolveEffectiveWorkspaceRoot(service, project),\n };\n}\n\nfunction finiteNumberField(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) return value;\n if (typeof value === 'string' && value.trim()) {\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n }\n return undefined;\n}\n\nfunction collectUploadedFiles(body: Record<string, unknown>): File[] {\n const raw = body.file ?? body.files ?? body.attachments;\n const values = Array.isArray(raw) ? raw : raw ? [raw] : [];\n return values.filter((value): value is File => value instanceof File);\n}\n\nfunction validateUploadedWorkItemFiles(files: File[]): string | null {\n if (files.length > WORK_ITEM_ATTACHMENT_MAX_COUNT) {\n return `Too many attachments (max ${WORK_ITEM_ATTACHMENT_MAX_COUNT})`;\n }\n for (const file of files) {\n if (file.size > WORK_ITEM_ATTACHMENT_MAX_BYTES) {\n return `Attachment ${JSON.stringify(file.name || 'upload')} exceeds ${Math.floor(WORK_ITEM_ATTACHMENT_MAX_BYTES / (1024 * 1024))}MB limit`;\n }\n }\n return null;\n}\n\nasync function uploadedFileToBuffer(file: File): Promise<{ name: string; buffer: Buffer; mimeType: string }> {\n return {\n name: file.name || 'upload',\n buffer: Buffer.from(await file.arrayBuffer()),\n mimeType: file.type || 'application/octet-stream',\n };\n}\n\nfunction parseCsvEnum<T extends string>(raw: string | undefined, values: readonly T[]): T[] | undefined {\n if (!raw) return undefined;\n const allowed = new Set(values);\n const parsed = raw\n .split(',')\n .map((item) => item.trim())\n .filter((item): item is T => allowed.has(item as T));\n return parsed.length > 0 ? [...new Set(parsed)] : undefined;\n}\n\nfunction parseEnumValue<T extends string>(raw: unknown, values: readonly T[]): T | undefined {\n if (typeof raw !== 'string') return undefined;\n return values.includes(raw as T) ? raw as T : undefined;\n}\n\nconst WORK_ITEM_STATUSES = [\n 'backlog',\n 'todo',\n 'in_progress',\n 'blocked',\n 'needs_input',\n 'in_review',\n 'done',\n 'cancelled',\n] as const satisfies readonly WorkItemStatus[];\nconst WORK_ITEM_PRIORITIES = ['urgent', 'high', 'normal', 'low'] as const satisfies readonly WorkItemPriority[];\nconst WORK_ITEM_SUGGESTION_STATUSES = ['pending', 'applied', 'dismissed'] as const;\n\nconst SKIP_FILE_NAMES = new Set(['.git', 'node_modules']);\n\nconst PROJECT_FILE_MIME_BY_EXT: Record<string, string> = {\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n webp: 'image/webp',\n bmp: 'image/bmp',\n svg: 'image/svg+xml',\n pdf: 'application/pdf',\n docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n txt: 'text/plain',\n md: 'text/markdown',\n json: 'application/json',\n html: 'text/html',\n css: 'text/css',\n js: 'text/javascript',\n ts: 'text/typescript',\n mp3: 'audio/mpeg',\n wav: 'audio/wav',\n ogg: 'audio/ogg',\n webm: 'video/webm',\n mp4: 'video/mp4',\n mov: 'video/quicktime',\n};\n\nfunction normalizeRelativePath(raw: string | undefined): string {\n const normalized = (raw ?? '').trim().replaceAll('\\\\', '/');\n return normalized.replace(/^\\/+/, '');\n}\n\nfunction isWithinDirectory(root: string, target: string): boolean {\n const relativePath = path.relative(root, target);\n return relativePath === '' || (!relativePath.startsWith('..') && !path.isAbsolute(relativePath));\n}\n\nasync function resolveProjectWorkspaceRoot(\n service: AuthenticatedRouteDeps['service'],\n projectId: string,\n): Promise<{ ok: true; projectId: string; root: string } | { ok: false; status: number; error: string }> {\n const project = service.projects.get(projectId);\n if (!project) return { ok: false, status: 404, error: 'Project not found' };\n const workspaceRoot = resolveEffectiveWorkspaceRoot(service, project);\n if (!workspaceRoot?.trim()) {\n return { ok: false, status: 400, error: 'Project workspace root is not set' };\n }\n\n try {\n const root = await realpath(workspaceRoot);\n const rootStat = await stat(root);\n if (!rootStat.isDirectory()) {\n return { ok: false, status: 400, error: 'Project workspace root is not a directory' };\n }\n return { ok: true, projectId: project.id, root };\n } catch (err) {\n log.warn({ err, projectId: project.id, path: workspaceRoot }, 'project workspace root unavailable');\n return { ok: false, status: 404, error: 'Project workspace root is unavailable' };\n }\n}\n\nasync function resolveProjectWorkspacePath(\n service: AuthenticatedRouteDeps['service'],\n projectId: string,\n rawPath: string | undefined,\n): Promise<\n | { ok: true; projectId: string; root: string; requestedPath: string; absolutePath: string; relativePath: string }\n | { ok: false; status: number; error: string }\n> {\n const rootResult = await resolveProjectWorkspaceRoot(service, projectId);\n if (rootResult.ok === false) {\n return { ok: false, status: rootResult.status, error: rootResult.error };\n }\n\n const requestedPath = normalizeRelativePath(rawPath);\n const candidate = path.resolve(rootResult.root, requestedPath);\n if (!isWithinDirectory(rootResult.root, candidate)) {\n return { ok: false, status: 400, error: 'Path is outside project workspace' };\n }\n\n const relativePath = path.relative(rootResult.root, candidate).split(path.sep).join('/');\n return {\n ok: true,\n projectId: rootResult.projectId,\n root: rootResult.root,\n requestedPath,\n absolutePath: candidate,\n relativePath: relativePath === '.' ? '' : relativePath,\n };\n}\n\nasync function resolveExistingProjectWorkspacePath(\n service: AuthenticatedRouteDeps['service'],\n projectId: string,\n rawPath: string | undefined,\n): Promise<\n | {\n ok: true;\n projectId: string;\n root: string;\n requestedPath: string;\n absolutePath: string;\n relativePath: string;\n stat: Awaited<ReturnType<typeof stat>>;\n }\n | { ok: false; status: number; error: string }\n> {\n const resolved = await resolveProjectWorkspacePath(service, projectId, rawPath);\n if (resolved.ok === false) return resolved;\n if (!resolved.requestedPath.trim()) {\n return { ok: false, status: 400, error: 'Missing path' };\n }\n\n let realTarget: string;\n try {\n realTarget = await realpath(resolved.absolutePath);\n } catch {\n return { ok: false, status: 404, error: 'Not found' };\n }\n if (!isWithinDirectory(resolved.root, realTarget)) {\n return { ok: false, status: 400, error: 'Path is outside project workspace' };\n }\n const targetStat = await stat(realTarget);\n return {\n ...resolved,\n absolutePath: realTarget,\n stat: targetStat,\n };\n}\n\nasync function resolveProjectWorkspaceWritePath(\n service: AuthenticatedRouteDeps['service'],\n projectId: string,\n rawPath: string | undefined,\n): Promise<\n | {\n ok: true;\n projectId: string;\n root: string;\n requestedPath: string;\n absolutePath: string;\n relativePath: string;\n existingStat?: Awaited<ReturnType<typeof stat>>;\n }\n | { ok: false; status: number; error: string }\n> {\n const resolved = await resolveProjectWorkspacePath(service, projectId, rawPath);\n if (resolved.ok === false) return resolved;\n if (!resolved.requestedPath.trim()) {\n return { ok: false, status: 400, error: 'Missing path' };\n }\n\n try {\n const realTarget = await realpath(resolved.absolutePath);\n if (!isWithinDirectory(resolved.root, realTarget)) {\n return { ok: false, status: 400, error: 'Path is outside project workspace' };\n }\n return {\n ...resolved,\n absolutePath: realTarget,\n existingStat: await stat(realTarget),\n };\n } catch {\n const parentPath = path.dirname(resolved.absolutePath);\n try {\n const realParent = await realpath(parentPath);\n if (!isWithinDirectory(resolved.root, realParent)) {\n return { ok: false, status: 400, error: 'Path is outside project workspace' };\n }\n } catch {\n return { ok: false, status: 404, error: 'Parent directory not found' };\n }\n return resolved;\n }\n}\n\nfunction textFromTranscriptContent(content: unknown): string {\n if (typeof content === 'string') return content;\n if (!Array.isArray(content)) return '';\n return content\n .map((part) => {\n if (!part || typeof part !== 'object') return '';\n const record = part as Record<string, unknown>;\n return typeof record.text === 'string' ? record.text : '';\n })\n .filter(Boolean)\n .join('\\n');\n}\n\nfunction buildSessionSummaryMemoryContent(sessionKey: string, explicitSummary?: string): string {\n const summary = explicitSummary?.trim();\n if (summary) return summary;\n const rows = loadTranscriptRowsForSession(sessionKey)\n .filter((row) => {\n if (!row || typeof row !== 'object') return false;\n const record = row as unknown as Record<string, unknown>;\n const role = record.role;\n return role === 'user' || role === 'assistant' || role === 'compactionSummary' || role === 'branchSummary';\n })\n .slice(-12);\n const lines = rows\n .map((row) => {\n const record = row as unknown as Record<string, unknown>;\n const rowRole = typeof record.role === 'string' ? record.role : 'message';\n const role = rowRole === 'compactionSummary' || rowRole === 'branchSummary' ? 'summary' : rowRole;\n const text = (typeof record.summary === 'string' ? record.summary : undefined) ?? textFromTranscriptContent(record.content);\n const compact = text.trim().replace(/\\s+/g, ' ').slice(0, 280);\n return compact ? `- ${role}: ${compact}` : '';\n })\n .filter(Boolean);\n return lines.length > 0\n ? [`Session summary for ${sessionKey}:`, ...lines].join('\\n')\n : `Session summary for ${sessionKey}: no transcript content available.`;\n}\n\nfunction buildWorkItemChatSessionMetadata(params: {\n agentId: string;\n accountId: string;\n peerId: string;\n workItemId: string;\n title: string;\n updatedAt: number;\n}): SessionMetadataSeed {\n return {\n name: params.title,\n tags: ['work-item'],\n sourceChannel: 'webchat',\n sourceChatId: [params.accountId, 'direct', params.peerId].join(':'),\n sessionType: 'chat',\n hiddenFromSessionList: true,\n routing: {\n agentId: params.agentId,\n source: 'webchat',\n accountId: params.accountId,\n peerKind: 'direct',\n peerId: params.peerId,\n },\n customData: {\n genericNewChatShell: false,\n sourceBinding: {\n kind: 'work_item',\n sourceId: params.workItemId,\n version: String(params.updatedAt),\n attachedAt: Date.now(),\n },\n },\n };\n}\n\nfunction listFailedProjectWorkflowRuns(projectId: string, limit = 5): ProjectWorkflowRunBrief[] {\n const rows = getSqliteDatabase()\n .prepare(\n `SELECT run_id, definition_id, status, created_at_ms, error_message\n FROM workflow_runs\n WHERE project_id = ? AND status IN ('failed', 'timeout', 'cancelled')\n ORDER BY created_at_ms DESC\n LIMIT ?`,\n )\n .all(projectId, Math.max(1, Math.min(20, Math.floor(limit)))) as Array<{\n run_id: string;\n definition_id: string;\n status: string;\n created_at_ms: number;\n error_message: string | null;\n }>;\n return rows.map((row) => ({\n runId: row.run_id,\n definitionId: row.definition_id,\n status: row.status,\n createdAt: row.created_at_ms,\n errorMessage: row.error_message ?? undefined,\n }));\n}\n\nfunction buildProjectDigestMemoryContent(input: ReturnType<typeof buildProjectLoopOverview> & { projectName: string }): string {\n const lines = [\n `Project digest: ${input.projectName}`,\n `Status: ${input.digest.summary}`,\n input.digest.nextAction ? `Next: ${input.digest.nextAction}` : undefined,\n ].filter(Boolean) as string[];\n if (input.attentionItems.length > 0) {\n lines.push('', 'Attention:');\n for (const item of input.attentionItems.slice(0, 8)) {\n lines.push(`- ${item.kind}: ${item.title}${item.detail ? ` - ${item.detail}` : ''}`);\n }\n }\n if (input.timeline.length > 0) {\n lines.push('', 'Recent activity:');\n for (const item of input.timeline.slice(0, 8)) {\n lines.push(`- ${item.kind}: ${item.title}${item.detail ? ` - ${item.detail}` : ''}`);\n }\n }\n return lines.join('\\n');\n}\n\nfunction projectDigestMemoryRecordId(projectId: string): string {\n return `project-digest:${projectId}`;\n}\n\nexport function registerProjectsRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service } = deps;\n const activity = new ActivityService();\n const goals = new GoalService();\n const workItems = new WorkItemService();\n\n authenticated.post('/api/projects', async (c) => {\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const name = textField(body, 'name')?.trim();\n const workspaceRoot = textField(body, 'workspaceRoot')?.trim();\n if (!name && !workspaceRoot) return c.json({ ok: false, error: 'Missing name' }, 400);\n const hasDefaultAgentPatch = Object.hasOwn(body, 'defaultAgentId');\n const explicitDefaultAgentId = normalizeProjectAgentId(textField(body, 'defaultAgentId'));\n const defaultAgentId = hasDefaultAgentPatch\n ? explicitDefaultAgentId\n : inferSuggestedProjectDefaultAgentId({\n config: service.currentConfig,\n name,\n description: textField(body, 'description'),\n workspaceRoot,\n projectKind: textField(body, 'projectKind'),\n });\n if (!isValidProjectAgentId(service.currentConfig, defaultAgentId)) {\n return c.json({ ok: false, error: 'Default agent not found' }, 400);\n }\n try {\n const project = service.projects.create({\n name,\n description: textField(body, 'description'),\n defaultAgentId,\n workspaceRoot,\n createWorkspaceRoot: body.createWorkspaceRoot === true,\n projectKind: textField(body, 'projectKind'),\n brief: textField(body, 'brief'),\n instructions: textField(body, 'instructions'),\n });\n return c.json({ ok: true, project: enrichProjectWorkspace(service, project) }, 201);\n } catch (error) {\n if (error instanceof ProjectWorkspaceConflictError) {\n return c.json({ ok: false, code: 'workspace_already_bound', error: error.message, project: error.project }, 409);\n }\n if (error instanceof ProjectWorkspaceMissingError) {\n return c.json({ ok: false, code: 'workspace_root_missing', error: error.message, workspaceRoot: error.workspaceRoot }, 409);\n }\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 400);\n }\n });\n\n authenticated.get('/api/projects', async (c) => {\n const status = parseProjectStatus(c.req.query('status'));\n const result = service.projects.list({\n ...(status ? { status } : {}),\n search: c.req.query('search'),\n sortBy: c.req.query('sortBy') as 'updatedAt' | 'createdAt' | 'name' | undefined,\n sortOrder: c.req.query('sortOrder') as 'asc' | 'desc' | undefined,\n limit: parseLimit(c.req.query('limit')),\n offset: c.req.query('offset') ? Math.max(0, Number.parseInt(c.req.query('offset')!, 10) || 0) : undefined,\n });\n return c.json({ ok: true, ...result, items: result.items.map((project) => enrichProjectWorkspace(service, project)) });\n });\n\n authenticated.get('/api/projects/suggestions', async (c) => {\n const sessionKey = c.req.query('sessionKey')?.trim();\n return c.json({ ok: true, suggestions: sessionKey ? service.projects.suggestProjectsForSession(sessionKey) : [] });\n });\n\n authenticated.post('/api/projects/infer-defaults', async (c) => {\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const input = {\n name: textField(body, 'name'),\n description: textField(body, 'description'),\n workspaceRoot: textField(body, 'workspaceRoot'),\n projectKind: textField(body, 'projectKind'),\n };\n const inference = inferProjectKind(input);\n const defaultAgentId = inferSuggestedProjectDefaultAgentId({\n config: service.currentConfig,\n ...input,\n });\n return c.json({ ok: true, inference, defaultAgentId });\n });\n\n authenticated.post('/api/projects/resolve-workspace', async (c) => {\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const workspacePath = textField(body, 'workspacePath')?.trim();\n if (!workspacePath) return c.json({ ok: false, error: 'Missing workspacePath' }, 400);\n const agentId = textField(body, 'agentId')?.trim() || 'main';\n const suggestedDefaultAgentId = inferSuggestedProjectDefaultAgentId({\n config: service.currentConfig,\n workspaceRoot: workspacePath,\n projectKind: textField(body, 'projectKind'),\n });\n let match;\n try {\n match = service.projects.resolveOrCreateForWorkspacePath({\n workspacePath,\n agentId,\n defaultAgentId: suggestedDefaultAgentId,\n autoCreate: body.autoCreate !== false,\n });\n } catch (error) {\n if (error instanceof ProjectWorkspaceConflictError) {\n match = { project: error.project, reason: 'exact' as const, created: false };\n } else {\n throw error;\n }\n }\n if (!match) return c.json({ ok: true, project: null });\n\n const sessionKey = textField(body, 'sessionKey')?.trim();\n const projectDefaultAgentId = normalizeProjectAgentId(match.project.defaultAgentId);\n const shouldBindRequestedSession = !projectDefaultAgentId || projectDefaultAgentId === normalizeProjectAgentId(agentId);\n if (sessionKey && shouldBindRequestedSession) {\n const existingSession = getSessionMetadata(sessionKey);\n if (!existingSession) {\n await service.sessionIndexInstance.saveMessages(sessionKey, [], {\n metadata: {\n sourceChannel: 'tui',\n sourceChatId: `default:direct:${sessionKey}`,\n sessionType: 'chat',\n projectId: match.project.id,\n routing: {\n agentId,\n source: 'tui',\n accountId: 'default',\n peerKind: 'direct',\n peerId: sessionKey,\n },\n },\n });\n }\n service.projects.attachSession(sessionKey, match.project.id);\n }\n\n return c.json({ ok: true, ...match });\n });\n\n authenticated.get('/api/projects/:id/overview', async (c) => {\n const project = service.projects.getWithDetails(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const goalIds = service.projects.listGoalIds(project.id, parseLimit(c.req.query('goalLimit'), 100));\n const projectGoals = goalIds\n .map((id) => goals.get(id))\n .filter((goal): goal is GoalWithDetails => Boolean(goal));\n const loop = buildProjectLoopOverview({\n project,\n goals: projectGoals,\n recentWorkflowRuns: project.recentWorkflowRuns,\n failedWorkflowRuns: listFailedProjectWorkflowRuns(project.id),\n memoryRecords: listMemoryRecords({ projectId: project.id, status: 'active', limit: 5 }),\n });\n return c.json({\n ok: true,\n overview: {\n project: enrichProjectWorkspace(service, project),\n stats: {\n sessionCount: project.sessionCount,\n goalCount: project.goalCount,\n activeGoalCount: project.activeGoalCount,\n recentWorkflowRunCount: project.recentWorkflowRuns.length,\n staleGoalCount: loop.staleGoals.length,\n attentionCount: loop.attentionItems.length,\n failedWorkflowRunCount: loop.failedWorkflowRuns.length,\n },\n activeGoals: loop.activeGoals,\n blockedGoals: loop.blockedGoals,\n staleGoals: loop.staleGoals,\n nextActions: loop.nextActions,\n attentionItems: loop.attentionItems,\n timeline: loop.timeline,\n digest: loop.digest,\n failedWorkflowRuns: loop.failedWorkflowRuns,\n recentSessions: project.recentSessions,\n recentWorkflowRuns: project.recentWorkflowRuns,\n recommendedAction: loop.recommendedAction,\n },\n });\n });\n\n authenticated.get('/api/projects/:id/activity', (c) => {\n const project = service.projects.get(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const result = activity.listForProject({\n projectId: project.id,\n includeRelated: parseActivityIncludeRelated(c.req.query('includeRelated')),\n ...parseActivityQuery(c),\n });\n return c.json({ ok: true, ...result });\n });\n\n authenticated.get('/api/projects/:id/work-items', async (c) => {\n const project = service.projects.get(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const result = workItems.listProjectWorkItems(project.id, {\n status: parseCsvEnum(c.req.query('status'), WORK_ITEM_STATUSES),\n priority: parseCsvEnum(c.req.query('priority'), WORK_ITEM_PRIORITIES),\n includeArchived: c.req.query('includeArchived') === 'true',\n search: c.req.query('search'),\n sortBy: c.req.query('sortBy') as 'updatedAt' | 'createdAt' | 'priority' | 'status' | undefined,\n sortOrder: c.req.query('sortOrder') as 'asc' | 'desc' | undefined,\n limit: parseLimit(c.req.query('limit')),\n offset: c.req.query('offset') ? Math.max(0, Number.parseInt(c.req.query('offset')!, 10) || 0) : undefined,\n });\n return c.json({ ok: true, ...result });\n });\n\n authenticated.post('/api/projects/:id/work-items', async (c) => {\n const project = service.projects.get(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const contentType = c.req.header('content-type') || '';\n let body: Record<string, unknown>;\n let files: File[] = [];\n if (contentType.includes('multipart/form-data')) {\n try {\n body = await c.req.parseBody({ all: true }) as Record<string, unknown>;\n } catch {\n return c.json({ ok: false, error: 'Invalid multipart body' }, 400);\n }\n files = collectUploadedFiles(body);\n } else {\n body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n }\n const attachmentError = validateUploadedWorkItemFiles(files);\n if (attachmentError) return c.json({ ok: false, error: attachmentError }, 413);\n const title = textField(body, 'title')?.trim();\n if (!title) return c.json({ ok: false, error: 'Work item title is required' }, 400);\n const status = parseEnumValue(body.status, WORK_ITEM_STATUSES);\n const priority = parseEnumValue(body.priority, WORK_ITEM_PRIORITIES);\n const dueAt = finiteNumberField(body.dueAt);\n if (Object.hasOwn(body, 'status') && !status) return c.json({ ok: false, error: 'Invalid work item status' }, 400);\n if (Object.hasOwn(body, 'priority') && !priority) return c.json({ ok: false, error: 'Invalid work item priority' }, 400);\n if (Object.hasOwn(body, 'dueAt') && dueAt === undefined && body.dueAt !== null) return c.json({ ok: false, error: 'Invalid dueAt' }, 400);\n const uploads: Array<{ name: string; buffer: Buffer; mimeType: string }> = [];\n for (const file of files) {\n uploads.push(await uploadedFileToBuffer(file));\n }\n const item = workItems.createProjectWorkItem(project.id, {\n title,\n description: textField(body, 'description'),\n status,\n priority,\n ownerAgentId: textField(body, 'ownerAgentId') || project.defaultAgentId || undefined,\n nextAction: textField(body, 'nextAction'),\n blockedReason: textField(body, 'blockedReason'),\n dueAt,\n });\n for (const upload of uploads) {\n await workItems.addAttachment(item.id, upload);\n }\n const created = files.length > 0 ? workItems.getWorkItem(item.id) ?? item : item;\n return c.json({ ok: true, item: created }, 201);\n });\n\n authenticated.get('/api/work-items', (c) => {\n const result = workItems.listWorkItems({\n status: parseCsvEnum(c.req.query('status'), WORK_ITEM_STATUSES),\n priority: parseCsvEnum(c.req.query('priority'), WORK_ITEM_PRIORITIES),\n includeArchived: c.req.query('includeArchived') === 'true',\n search: c.req.query('search'),\n sortBy: c.req.query('sortBy') as 'updatedAt' | 'createdAt' | 'priority' | 'status' | undefined,\n sortOrder: c.req.query('sortOrder') as 'asc' | 'desc' | undefined,\n limit: parseLimit(c.req.query('limit')),\n offset: c.req.query('offset') ? Math.max(0, Number.parseInt(c.req.query('offset')!, 10) || 0) : undefined,\n });\n return c.json({ ok: true, ...result });\n });\n\n authenticated.get('/api/work-items/:id', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n return c.json({ ok: true, item });\n });\n\n authenticated.get('/api/work-items/:id/attachments', async (c) => {\n const attachments = workItems.listAttachments(c.req.param('id'));\n if (!attachments) return c.json({ ok: false, error: 'Work item not found' }, 404);\n return c.json({ ok: true, attachments });\n });\n\n authenticated.post('/api/work-items/:id/attachments', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n let body: Record<string, unknown>;\n try {\n body = await c.req.parseBody({ all: true }) as Record<string, unknown>;\n } catch {\n return c.json({ ok: false, error: 'Invalid multipart body' }, 400);\n }\n const files = collectUploadedFiles(body);\n if (!files.length) return c.json({ ok: false, error: 'Missing file field' }, 400);\n const attachmentError = validateUploadedWorkItemFiles(files);\n if (attachmentError) return c.json({ ok: false, error: attachmentError }, 413);\n const attachments = [];\n for (const file of files) {\n const upload = await uploadedFileToBuffer(file);\n const attachment = await workItems.addAttachment(item.id, upload);\n if (attachment) attachments.push(attachment);\n }\n return c.json({ ok: true, attachments, item: workItems.getWorkItem(item.id) }, 201);\n });\n\n authenticated.get('/api/work-items/:id/attachments/:attachmentId/content', async (c) => {\n const result = await workItems.readAttachment(c.req.param('id'), c.req.param('attachmentId'));\n if (!result) return c.json({ ok: false, error: 'Attachment not found' }, 404);\n return new Response(result.buffer, {\n headers: {\n 'Content-Type': result.attachment.mimeType,\n 'Content-Length': String(result.attachment.size),\n 'Content-Disposition': `inline; filename=\"${encodeURIComponent(result.attachment.fileName)}\"`,\n 'Cache-Control': 'private, max-age=31536000, immutable',\n },\n });\n });\n\n authenticated.delete('/api/work-items/:id/attachments/:attachmentId', async (c) => {\n const attachment = await workItems.removeAttachment(c.req.param('id'), c.req.param('attachmentId'));\n if (!attachment) return c.json({ ok: false, error: 'Attachment not found' }, 404);\n return c.json({ ok: true, attachment, item: workItems.getWorkItem(c.req.param('id')) });\n });\n\n authenticated.patch('/api/work-items/:id', async (c) => {\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const status = Object.hasOwn(body, 'status')\n ? parseEnumValue(body.status, WORK_ITEM_STATUSES)\n : undefined;\n const priority = Object.hasOwn(body, 'priority')\n ? parseEnumValue(body.priority, WORK_ITEM_PRIORITIES)\n : undefined;\n const dueAt = Object.hasOwn(body, 'dueAt')\n ? (body.dueAt === null ? null : (typeof body.dueAt === 'number' && Number.isFinite(body.dueAt) ? body.dueAt : undefined))\n : undefined;\n const archivedAt = Object.hasOwn(body, 'archivedAt')\n ? (body.archivedAt === null ? null : (typeof body.archivedAt === 'number' && Number.isFinite(body.archivedAt) ? body.archivedAt : undefined))\n : undefined;\n if (status === undefined && Object.hasOwn(body, 'status')) return c.json({ ok: false, error: 'Invalid work item status' }, 400);\n if (priority === undefined && Object.hasOwn(body, 'priority')) return c.json({ ok: false, error: 'Invalid work item priority' }, 400);\n if (dueAt === undefined && Object.hasOwn(body, 'dueAt')) return c.json({ ok: false, error: 'Invalid dueAt' }, 400);\n if (archivedAt === undefined && Object.hasOwn(body, 'archivedAt')) return c.json({ ok: false, error: 'Invalid archivedAt' }, 400);\n\n const item = workItems.updateWorkItem(c.req.param('id'), {\n ...(Object.hasOwn(body, 'title') ? { title: textField(body, 'title') ?? '' } : {}),\n ...(Object.hasOwn(body, 'description') ? { description: optionalTextField(body, 'description') } : {}),\n ...(Object.hasOwn(body, 'status') ? { status } : {}),\n ...(Object.hasOwn(body, 'priority') ? { priority } : {}),\n ...(Object.hasOwn(body, 'ownerAgentId') ? { ownerAgentId: optionalTextField(body, 'ownerAgentId') } : {}),\n ...(Object.hasOwn(body, 'nextAction') ? { nextAction: optionalTextField(body, 'nextAction') } : {}),\n ...(Object.hasOwn(body, 'blockedReason') ? { blockedReason: optionalTextField(body, 'blockedReason') } : {}),\n ...(Object.hasOwn(body, 'dueAt') ? { dueAt } : {}),\n ...(Object.hasOwn(body, 'archivedAt') ? { archivedAt } : {}),\n });\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n return c.json({ ok: true, item });\n });\n\n authenticated.delete('/api/work-items/:id', async (c) => {\n const item = workItems.updateWorkItem(c.req.param('id'), { archivedAt: Date.now() });\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n return c.json({ ok: true, item });\n });\n\n authenticated.get('/api/work-items/:id/events', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n return c.json({ ok: true, events: workItems.listEvents(item.id) });\n });\n\n authenticated.get('/api/work-items/:id/update-suggestions', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n const status = parseEnumValue(c.req.query('status'), WORK_ITEM_SUGGESTION_STATUSES);\n if (c.req.query('status') && !status) return c.json({ ok: false, error: 'Invalid suggestion status' }, 400);\n return c.json({ ok: true, suggestions: workItems.listUpdateSuggestions(item.id, status) });\n });\n\n authenticated.post('/api/work-items/:id/update-suggestions', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const sourceKind = parseEnumValue(body.sourceKind, ['chat', 'goal', 'workflow_run', 'automation'] as const);\n const sourceId = textField(body, 'sourceId')?.trim();\n if (!sourceKind) return c.json({ ok: false, error: 'Invalid sourceKind' }, 400);\n if (!sourceId) return c.json({ ok: false, error: 'sourceId is required' }, 400);\n const patchBody = body.patch && typeof body.patch === 'object' && !Array.isArray(body.patch)\n ? body.patch as Record<string, unknown>\n : {};\n const status = Object.hasOwn(patchBody, 'status')\n ? parseEnumValue(patchBody.status, WORK_ITEM_STATUSES)\n : undefined;\n if (Object.hasOwn(patchBody, 'status') && !status) return c.json({ ok: false, error: 'Invalid work item status' }, 400);\n const confidence = typeof body.confidence === 'number' && Number.isFinite(body.confidence)\n ? Math.max(0, Math.min(1, body.confidence))\n : undefined;\n const suggestion = workItems.createUpdateSuggestion(item.id, {\n sourceKind,\n sourceId,\n patch: {\n ...(Object.hasOwn(patchBody, 'status') ? { status } : {}),\n ...(Object.hasOwn(patchBody, 'nextAction') ? { nextAction: optionalTextField(patchBody, 'nextAction') } : {}),\n ...(Object.hasOwn(patchBody, 'blockedReason') ? { blockedReason: optionalTextField(patchBody, 'blockedReason') } : {}),\n },\n progressNote: optionalTextField(body, 'progressNote') ?? undefined,\n rationale: optionalTextField(body, 'rationale') ?? undefined,\n confidence,\n });\n if (!suggestion) return c.json({ ok: false, error: 'Work item not found' }, 404);\n return c.json({ ok: true, suggestion }, 201);\n });\n\n authenticated.post('/api/work-item-update-suggestions/:id/apply', async (c) => {\n const result = workItems.applyUpdateSuggestion(c.req.param('id'));\n if (!result) return c.json({ ok: false, error: 'Suggestion not found or already resolved' }, 404);\n return c.json({ ok: true, item: result.item, suggestion: result.suggestion });\n });\n\n authenticated.post('/api/work-item-update-suggestions/:id/dismiss', async (c) => {\n const suggestion = workItems.dismissUpdateSuggestion(c.req.param('id'));\n if (!suggestion) return c.json({ ok: false, error: 'Suggestion not found or already resolved' }, 404);\n return c.json({ ok: true, suggestion });\n });\n\n authenticated.post('/api/work-items/:id/start-chat', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n const project = service.projects.get(item.projectId);\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const agentId = resolveProjectAgentId({\n config: service.currentConfig,\n projects: service.projects,\n explicitAgentId: item.ownerAgentId,\n projectId: project.id,\n });\n const peerId = `work_item_${Date.now()}`;\n const sessionKey = buildSessionKey({\n agentId,\n source: 'webchat',\n accountId: 'default',\n peerKind: 'direct',\n peerId,\n });\n await service.sessionIndexInstance.saveMessages(sessionKey, [], {\n metadata: buildWorkItemChatSessionMetadata({\n agentId,\n accountId: 'default',\n peerId,\n workItemId: item.id,\n title: item.title,\n updatedAt: item.updatedAt,\n }),\n });\n service.projects.attachSession(sessionKey, project.id);\n const session = await service.sessions.getSession(sessionKey);\n workItems.addLink(item.id, {\n kind: 'chat',\n targetId: sessionKey,\n title: session?.name || item.title,\n statusSnapshot: session?.status,\n }, 'chat_started');\n const updated = item.status === 'todo' || item.status === 'backlog'\n ? workItems.updateWorkItem(item.id, { status: 'in_progress' })\n : workItems.getWorkItem(item.id);\n return c.json({ ok: true, session, item: updated }, 201);\n });\n\n authenticated.post('/api/work-items/:id/create-goal', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n const project = service.projects.get(item.projectId);\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const attachments = await workItems.snapshotAttachmentsForGoal(item.id);\n if (!attachments) return c.json({ ok: false, error: 'Work item not found' }, 404);\n const context = await buildWorkItemAgentContext(item, { attachments, includeImages: false });\n const goal = goals.create({\n title: item.title,\n description: item.description || item.nextAction,\n priority: item.priority === 'urgent' ? 'high' : item.priority,\n agentId: item.ownerAgentId || project.defaultAgentId || undefined,\n projectId: project.id,\n source: 'api',\n config: service.currentConfig,\n });\n const goalWithContext = goals.setContextMessage({\n goalId: goal.id,\n text: context.text,\n attachments,\n }) ?? goal;\n workItems.addLink(item.id, {\n kind: 'goal',\n targetId: goal.id,\n title: goal.title,\n statusSnapshot: goal.status,\n }, 'goal_created');\n const updated = item.status === 'todo' || item.status === 'backlog'\n ? workItems.updateWorkItem(item.id, { status: 'in_progress' })\n : workItems.getWorkItem(item.id);\n return c.json({ ok: true, goal: goalWithContext, item: updated }, 201);\n });\n\n authenticated.post('/api/work-items/:id/workflows/run', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n const project = service.projects.get(item.projectId);\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n if (item.status === 'done' || item.status === 'cancelled' || item.archivedAt) {\n return c.json({ ok: false, error: 'Work item is not active' }, 409);\n }\n\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const definitionId = textField(body, 'definitionId')?.trim();\n if (!definitionId) return c.json({ ok: false, error: 'Missing definitionId' }, 400);\n\n const agentId = resolveProjectAgentId({\n config: service.currentConfig,\n projects: service.projects,\n explicitAgentId: item.ownerAgentId,\n projectId: project.id,\n });\n const goalText = textField(body, 'goal')?.trim() || item.nextAction || item.title;\n const attachments = item.attachments?.map((attachment) => ({\n id: attachment.id,\n fileName: attachment.fileName,\n type: attachment.type,\n mimeType: attachment.mimeType,\n size: attachment.size,\n }));\n const input = Object.hasOwn(body, 'input') ? body.input : {\n workItem: {\n id: item.id,\n title: item.title,\n description: item.description,\n status: item.status,\n priority: item.priority,\n nextAction: item.nextAction,\n blockedReason: item.blockedReason,\n attachments,\n },\n project: {\n id: project.id,\n name: project.name,\n description: project.description,\n brief: project.brief,\n instructions: project.instructions,\n workspaceRoot: project.workspaceRoot,\n },\n };\n const rawTokenBudget = body.tokenBudget;\n const tokenBudget = rawTokenBudget === null\n ? null\n : typeof rawTokenBudget === 'number' && Number.isFinite(rawTokenBudget)\n ? rawTokenBudget\n : undefined;\n\n const result = await service.createWorkflowRunService().startWorkflowRun({\n agentId,\n definitionId,\n projectId: project.id,\n workItemId: item.id,\n goal: goalText,\n input,\n source: { kind: 'webui' },\n concurrency: finiteNumberField(body.concurrency),\n maxSubagents: finiteNumberField(body.maxSubagents),\n tokenBudget,\n });\n if (result.ok === false) {\n return c.json({ ok: false, error: result.message, code: result.code }, result.httpStatus);\n }\n\n workItems.addLink(item.id, {\n kind: 'workflow_run',\n targetId: result.runId,\n title: goalText,\n statusSnapshot: 'queued',\n }, 'workflow_started');\n const updated = item.status === 'todo' || item.status === 'backlog'\n ? workItems.updateWorkItem(item.id, { status: 'in_progress' })\n : workItems.getWorkItem(item.id);\n return c.json({ ok: true, runId: result.runId, sessionKey: result.sessionKey, item: updated }, 202);\n });\n\n authenticated.post('/api/projects/:id/digest-memory', async (c) => {\n const project = service.projects.getWithDetails(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const goalIds = service.projects.listGoalIds(project.id, 100);\n const projectGoals = goalIds\n .map((id) => goals.get(id))\n .filter((goal): goal is GoalWithDetails => Boolean(goal));\n const loop = buildProjectLoopOverview({\n project,\n goals: projectGoals,\n recentWorkflowRuns: project.recentWorkflowRuns,\n failedWorkflowRuns: listFailedProjectWorkflowRuns(project.id),\n memoryRecords: listMemoryRecords({ projectId: project.id, status: 'active', limit: 5 }),\n });\n const record = upsertMemoryRecord({\n id: projectDigestMemoryRecordId(project.id),\n providerId: 'local',\n kind: 'daily_note',\n agentId: resolveProjectAgentId({\n config: service.currentConfig,\n projects: service.projects,\n projectId: project.id,\n }),\n workspaceId: project.workspaceRoot,\n projectId: project.id,\n content: buildProjectDigestMemoryContent({ ...loop, projectName: project.name }),\n source: {\n provider: 'project-digest',\n },\n confidence: 0.75,\n tags: ['project', 'project-digest', project.slug],\n status: 'active',\n sensitivity: 'normal',\n });\n return c.json({ ok: true, record }, 201);\n });\n\n authenticated.post('/api/projects/:id/blockers', async (c) => {\n const project = service.projects.getWithDetails(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const title = typeof body.title === 'string' ? body.title.trim() : '';\n if (!title) return c.json({ ok: false, error: 'Missing title' }, 400);\n const reason = typeof body.reason === 'string' ? body.reason.trim() : '';\n const goal = goals.create({\n title,\n description: reason || undefined,\n agentId: resolveProjectAgentId({\n config: service.currentConfig,\n projects: service.projects,\n projectId: project.id,\n }),\n priority: body.priority === 'low' || body.priority === 'normal' || body.priority === 'high' ? body.priority : 'high',\n source: 'api',\n projectId: project.id,\n });\n const blocked = goals.setStatus(goal.id, 'blocked', { reason: reason || title });\n if (reason) {\n goals.setContextMessage({ goalId: goal.id, text: reason });\n }\n return c.json({ ok: true, goal: blocked ?? goals.get(goal.id) }, 201);\n });\n\n authenticated.post('/api/projects/:id/pin', async (c) => {\n try {\n const project = service.projects.pin(c.req.param('id'));\n return c.json({ ok: true, project: enrichProjectWorkspace(service, project) });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.post('/api/projects/:id/unpin', async (c) => {\n try {\n const project = service.projects.unpin(c.req.param('id'));\n return c.json({ ok: true, project: enrichProjectWorkspace(service, project) });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.get('/api/projects/:id', async (c) => {\n const project = service.projects.getWithDetails(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n return c.json({ ok: true, project: enrichProjectWorkspace(service, project) });\n });\n\n authenticated.patch('/api/projects/:id', async (c) => {\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const status = parseProjectStatus(body.status);\n const defaultAgentPatch = optionalTextField(body, 'defaultAgentId');\n const defaultAgentId = defaultAgentPatch === undefined ? undefined : normalizeProjectAgentId(defaultAgentPatch);\n if (defaultAgentId && !isValidProjectAgentId(service.currentConfig, defaultAgentId)) {\n return c.json({ ok: false, error: 'Default agent not found' }, 400);\n }\n try {\n const project = service.projects.update(c.req.param('id'), {\n ...(textField(body, 'name') !== undefined ? { name: textField(body, 'name') } : {}),\n ...(optionalTextField(body, 'description') !== undefined ? { description: optionalTextField(body, 'description') } : {}),\n ...(status ? { status } : {}),\n ...(defaultAgentPatch !== undefined ? { defaultAgentId: defaultAgentId ?? null } : {}),\n ...(optionalTextField(body, 'workspaceRoot') !== undefined ? { workspaceRoot: optionalTextField(body, 'workspaceRoot') } : {}),\n createWorkspaceRoot: body.createWorkspaceRoot === true,\n ...(optionalTextField(body, 'brief') !== undefined ? { brief: optionalTextField(body, 'brief') } : {}),\n ...(optionalTextField(body, 'instructions') !== undefined ? { instructions: optionalTextField(body, 'instructions') } : {}),\n });\n return c.json({ ok: true, project: enrichProjectWorkspace(service, project) });\n } catch (error) {\n if (error instanceof ProjectWorkspaceConflictError) {\n return c.json({ ok: false, code: 'workspace_already_bound', error: error.message, project: error.project }, 409);\n }\n if (error instanceof ProjectWorkspaceMissingError) {\n return c.json({ ok: false, code: 'workspace_root_missing', error: error.message, workspaceRoot: error.workspaceRoot }, 409);\n }\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.delete('/api/projects/:id', async (c) => {\n service.projects.delete(c.req.param('id'));\n return c.json({ ok: true });\n });\n\n authenticated.get('/api/projects/:id/sessions', async (c) => {\n try {\n const keys = service.projects.listSessionKeys(c.req.param('id'), parseLimit(c.req.query('limit'), 100));\n const sessions = await Promise.all(keys.map((key) => service.sessions.getSession(key)));\n return c.json({\n ok: true,\n sessions: sessions.filter((session) => session && !isHiddenEmptyProjectChatShell(session)),\n });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.get('/api/projects/:id/goals', async (c) => {\n try {\n const ids = service.projects.listGoalIds(c.req.param('id'), parseLimit(c.req.query('limit'), 100));\n return c.json({ ok: true, goals: ids.map((id) => goals.get(id)).filter(Boolean) });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.get('/api/projects/:id/files', async (c) => {\n const resolved = await resolveProjectWorkspacePath(service, c.req.param('id'), c.req.query('path'));\n if (resolved.ok === false) return c.json({ ok: false, error: resolved.error }, resolved.status as 400);\n const { root, absolutePath: candidate } = resolved;\n let currentPath: string;\n try {\n currentPath = await realpath(candidate);\n if (!isWithinDirectory(root, currentPath)) {\n return c.json({ ok: false, error: 'Path is outside project workspace' }, 400);\n }\n const currentStat = await stat(currentPath);\n if (!currentStat.isDirectory()) {\n return c.json({ ok: false, error: 'Path is not a directory' }, 400);\n }\n } catch (err) {\n log.warn({ err, projectId: resolved.projectId, path: candidate }, 'project file path unavailable');\n return c.json({ ok: false, error: 'Path not found' }, 404);\n }\n\n try {\n const dirents = await readdir(currentPath, { withFileTypes: true });\n const entries = await Promise.all(dirents\n .filter((entry) => !SKIP_FILE_NAMES.has(entry.name))\n .map(async (entry) => {\n const displayPath = path.join(currentPath, entry.name);\n const absolutePath = await realpath(displayPath).catch(() => null);\n if (!absolutePath || !isWithinDirectory(root, absolutePath)) return null;\n const entryStat = await stat(absolutePath).catch(() => null);\n if (!entryStat) return null;\n const relativePath = path.relative(root, displayPath).split(path.sep).join('/');\n return {\n name: entry.name,\n path: relativePath,\n absolutePath,\n type: entryStat.isDirectory() ? 'directory' : 'file',\n size: entryStat?.isFile() ? entryStat.size : undefined,\n updatedAt: entryStat?.mtime.toISOString(),\n };\n }));\n const visibleEntries = entries.filter((entry): entry is NonNullable<typeof entry> => entry !== null);\n visibleEntries.sort((left, right) => {\n if (left.type !== right.type) return left.type === 'directory' ? -1 : 1;\n return left.name.localeCompare(right.name);\n });\n const relativeCurrentPath = path.relative(root, currentPath).split(path.sep).join('/');\n const parentRelativePath = relativeCurrentPath ? path.dirname(relativeCurrentPath).replaceAll('\\\\', '/') : null;\n return c.json({\n ok: true,\n root,\n path: relativeCurrentPath === '.' ? '' : relativeCurrentPath,\n parentPath: parentRelativePath === '.' ? '' : parentRelativePath,\n entries: visibleEntries,\n });\n } catch (err) {\n log.warn({ err, projectId: resolved.projectId, path: currentPath }, 'project file list failed');\n if ((err as NodeJS.ErrnoException)?.code === 'EACCES') {\n return c.json({ ok: false, error: 'Permission denied' }, 403);\n }\n return c.json({ ok: false, error: 'Failed to read project files' }, 500);\n }\n });\n\n /** Fuzzy filename / path search across the entire project workspace. */\n authenticated.get('/api/projects/:id/files/search', async (c) => {\n const q = typeof c.req.query('q') === 'string' ? c.req.query('q')!.trim() : '';\n const limitRaw = c.req.query('limit');\n const limit = Math.min(\n Math.max(parseInt(typeof limitRaw === 'string' ? limitRaw : '50', 10) || 50, 1),\n FILE_SEARCH_MAX_LIMIT,\n );\n const root = await resolveProjectWorkspaceRoot(service, c.req.param('id'));\n if (root.ok === false) return c.json({ ok: false, error: root.error }, root.status as 400);\n const entries = await fuzzySearchWorkspaceFiles(root.root, q, limit);\n return c.json({ ok: true, entries });\n });\n\n authenticated.get('/api/projects/:id/files/read', async (c) => {\n const resolved = await resolveExistingProjectWorkspacePath(service, c.req.param('id'), c.req.query('path'));\n if (resolved.ok === false) return c.json({ ok: false, error: { message: resolved.error } }, resolved.status as 400);\n if (!resolved.stat.isFile()) {\n return c.json({ ok: false, error: { message: 'Not a file' } }, 400);\n }\n try {\n const content = await readFile(resolved.absolutePath, 'utf-8');\n return c.json({\n ok: true,\n payload: {\n content,\n path: resolved.relativePath,\n absolutePath: resolved.absolutePath,\n mtimeMs: resolved.stat.mtimeMs,\n },\n });\n } catch {\n return c.json({ ok: false, error: { message: 'Read failed' } }, 500);\n }\n });\n\n authenticated.get('/api/projects/:id/files/raw', async (c) => {\n const resolved = await resolveExistingProjectWorkspacePath(service, c.req.param('id'), c.req.query('path'));\n if (resolved.ok === false) return c.json({ ok: false, error: { message: resolved.error } }, resolved.status as 400);\n if (!resolved.stat.isFile()) {\n return c.json({ ok: false, error: { message: 'Not a file' } }, 400);\n }\n const ext = resolved.relativePath.split('.').pop()?.toLowerCase() ?? '';\n const contentType = PROJECT_FILE_MIME_BY_EXT[ext] || 'application/octet-stream';\n try {\n const buf = await readFile(resolved.absolutePath);\n return new Response(buf, {\n headers: {\n 'Content-Type': contentType,\n 'Cache-Control': 'private, max-age=3600',\n },\n });\n } catch {\n return c.json({ ok: false, error: { message: 'Read failed' } }, 500);\n }\n });\n\n authenticated.get('/api/projects/:id/files/resolve-reference', async (c) => {\n const rawPath = typeof c.req.query('path') === 'string' ? c.req.query('path')!.trim() : '';\n if (!rawPath) {\n return c.json({ ok: false, error: { code: 'INVALID_PATH', message: 'Missing path' } }, 400);\n }\n const resolved = await resolveProjectWorkspacePath(service, c.req.param('id'), rawPath);\n if (resolved.ok === false) {\n return c.json({ ok: false, error: { code: 'PROJECT_WORKSPACE_RESOLUTION_FAILED', message: resolved.error } }, resolved.status as 400);\n }\n let st: Awaited<ReturnType<typeof stat>> | null = null;\n let absolutePath = resolved.absolutePath;\n try {\n absolutePath = await realpath(resolved.absolutePath);\n if (!isWithinDirectory(resolved.root, absolutePath)) {\n return c.json({\n ok: false,\n error: { code: 'PROJECT_WORKSPACE_RESOLUTION_FAILED', message: 'Path is outside project workspace' },\n }, 400);\n }\n st = await stat(absolutePath);\n } catch {\n st = null;\n }\n const displayName = path.basename(rawPath);\n if (!st) {\n return c.json({\n ok: true,\n payload: {\n inputPath: rawPath,\n displayName,\n scope: 'missing',\n exists: false,\n absolutePath: resolved.absolutePath,\n capabilities: ['copyPath'],\n errorCode: 'FILE_NOT_FOUND',\n },\n });\n }\n return c.json({\n ok: true,\n payload: {\n inputPath: rawPath,\n displayName,\n scope: 'workspace',\n exists: true,\n isDirectory: st.isDirectory(),\n absolutePath,\n workspaceRelativePath: resolved.relativePath,\n capabilities: st.isDirectory()\n ? ['openExternal', 'revealInFolder', 'copyPath']\n : ['preview', 'edit', 'openExternal', 'revealInFolder', 'copyPath'],\n mtimeMs: st.mtimeMs,\n },\n });\n });\n\n authenticated.put('/api/projects/:id/files/write', async (c) => {\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n return c.json({ ok: false, error: { message: 'Invalid JSON' } }, 400);\n }\n const bodyRecord = typeof body === 'object' && body !== null ? body as Record<string, unknown> : {};\n const pathRel = typeof bodyRecord.path === 'string' ? bodyRecord.path : '';\n const content = typeof bodyRecord.content === 'string' ? bodyRecord.content : '';\n if (!pathRel.trim()) {\n return c.json({ ok: false, error: { message: 'Missing path' } }, 400);\n }\n const resolved = await resolveProjectWorkspaceWritePath(service, c.req.param('id'), pathRel);\n if (resolved.ok === false) return c.json({ ok: false, error: { message: resolved.error } }, resolved.status as 400);\n if (resolved.existingStat && !resolved.existingStat.isFile()) {\n return c.json({ ok: false, error: { message: 'Not a file' } }, 400);\n }\n try {\n await writeFile(resolved.absolutePath, content, 'utf-8');\n const mtimeMs = (await stat(resolved.absolutePath).catch(() => ({ mtimeMs: Date.now() }))).mtimeMs;\n return c.json({\n ok: true,\n payload: { path: resolved.relativePath, mtimeMs },\n });\n } catch (err) {\n log.error({ err, projectId: resolved.projectId, path: resolved.absolutePath }, 'project file write failed');\n return c.json({ ok: false, error: { message: 'Write failed' } }, 500);\n }\n });\n\n authenticated.post('/api/projects/:id/sessions/:sessionKey', async (c) => {\n try {\n service.projects.attachSession(c.req.param('sessionKey'), c.req.param('id'));\n const session = await service.sessions.getSession(c.req.param('sessionKey'));\n return c.json({ ok: true, session });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.delete('/api/projects/:id/sessions/:sessionKey', async (c) => {\n try {\n const projectId = c.req.param('id');\n const sessionKey = c.req.param('sessionKey');\n if (!service.projects.get(projectId)) {\n return c.json({ ok: false, error: 'Project not found' }, 404);\n }\n const session = await service.sessions.getSession(sessionKey);\n if (!session) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n if (session.projectId !== projectId) {\n return c.json({ ok: false, error: 'Session is not attached to this project' }, 409);\n }\n service.projects.detachSession(sessionKey);\n return c.json({ ok: true });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.post('/api/projects/:id/sessions/:sessionKey/summary-memory', async (c) => {\n const projectId = c.req.param('id');\n const sessionKey = c.req.param('sessionKey');\n const project = service.projects.get(projectId);\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const session = getSessionMetadata(sessionKey);\n if (!session) return c.json({ ok: false, error: 'Session not found' }, 404);\n if (session.projectId !== projectId) {\n return c.json({ ok: false, error: 'Session is not attached to this project' }, 409);\n }\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const content = buildSessionSummaryMemoryContent(\n sessionKey,\n typeof body.summary === 'string' ? body.summary : undefined,\n );\n const record = upsertMemoryRecord({\n providerId: 'local',\n kind: 'session_summary',\n agentId: session.routing?.agentId ?? 'main',\n workspaceId: session.cwd,\n sessionKey,\n projectId,\n content,\n source: {\n provider: 'project-summary',\n sessionEntryId: sessionKey,\n },\n confidence: typeof body.confidence === 'number' ? body.confidence : 0.7,\n tags: ['project', 'session-summary', project.slug],\n status: 'active',\n sensitivity: 'normal',\n evidence: [{ sessionKey }],\n });\n return c.json({ ok: true, record }, 201);\n });\n\n authenticated.post('/api/projects/:id/goals/:goalId', async (c) => {\n try {\n service.projects.attachGoal(c.req.param('goalId'), c.req.param('id'));\n return c.json({ ok: true, goal: goals.get(c.req.param('goalId')) });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.delete('/api/projects/:id/goals/:goalId', async (c) => {\n try {\n const projectId = c.req.param('id');\n const goalId = c.req.param('goalId');\n if (!service.projects.get(projectId)) {\n return c.json({ ok: false, error: 'Project not found' }, 404);\n }\n const goal = goals.get(goalId);\n if (!goal) {\n return c.json({ ok: false, error: 'Goal not found' }, 404);\n }\n if (goal.projectId !== projectId) {\n return c.json({ ok: false, error: 'Goal is not attached to this project' }, 409);\n }\n service.projects.detachGoal(goalId);\n return c.json({ ok: true });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n}\n"],"mappings":"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"}
@@ -3,7 +3,6 @@ import { join } from "node:path";
3
3
  import { existsSync, readdirSync, statSync } from "node:fs";
4
4
  //#region src/projects/project-kind.ts
5
5
  const STRONG_CODE_MARKERS = [
6
- ".git",
7
6
  "package.json",
8
7
  "pnpm-lock.yaml",
9
8
  "yarn.lock",
@@ -1 +1 @@
1
- {"version":3,"file":"project-kind.js","names":[],"sources":["../../../src/projects/project-kind.ts"],"sourcesContent":["import { existsSync, readdirSync, statSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { canonicalWorkspacePath } from './workspace-project.js';\n\nexport type ProjectKind = 'coding' | 'general' | 'unknown';\nexport type ProjectKindOverride = 'auto' | 'coding' | 'general';\n\nexport type ProjectKindInference = {\n kind: ProjectKind;\n confidence: number;\n reasons: string[];\n};\n\nconst STRONG_CODE_MARKERS = [\n '.git',\n 'package.json',\n 'pnpm-lock.yaml',\n 'yarn.lock',\n 'package-lock.json',\n 'tsconfig.json',\n 'go.mod',\n 'Cargo.toml',\n 'pyproject.toml',\n 'requirements.txt',\n 'pom.xml',\n 'build.gradle',\n 'Makefile',\n 'Dockerfile',\n 'deno.json',\n 'deno.jsonc',\n 'composer.json',\n 'Gemfile',\n] as const;\n\nconst WEAK_CODE_DIRECTORIES = ['src', 'app', 'lib', 'tests', 'test', '__tests__', '.github'] as const;\nconst CODE_EXTENSIONS = new Set([\n '.c',\n '.cc',\n '.cpp',\n '.cs',\n '.css',\n '.go',\n '.h',\n '.hpp',\n '.html',\n '.java',\n '.js',\n '.jsx',\n '.kt',\n '.mjs',\n '.php',\n '.py',\n '.rb',\n '.rs',\n '.sh',\n '.swift',\n '.ts',\n '.tsx',\n]);\n\nfunction normalizeOverride(value: string | null | undefined): ProjectKindOverride {\n const normalized = value?.trim().toLowerCase();\n return normalized === 'coding' || normalized === 'general' ? normalized : 'auto';\n}\n\nfunction hasSourceExtension(name: string): boolean {\n const lower = name.toLowerCase();\n for (const extension of CODE_EXTENSIONS) {\n if (lower.endsWith(extension)) return true;\n }\n return false;\n}\n\nfunction readDirectoryNames(pathValue: string): string[] {\n try {\n return readdirSync(pathValue).slice(0, 200);\n } catch {\n return [];\n }\n}\n\nfunction directoryExists(pathValue: string): boolean {\n try {\n return statSync(pathValue).isDirectory();\n } catch {\n return false;\n }\n}\n\nexport function inferProjectKind(input: {\n name?: string | null;\n description?: string | null;\n workspaceRoot?: string | null;\n projectKind?: string | null;\n}): ProjectKindInference {\n const override = normalizeOverride(input.projectKind);\n if (override === 'coding') return { kind: 'coding', confidence: 1, reasons: ['selected coding project type'] };\n if (override === 'general') return { kind: 'general', confidence: 1, reasons: ['selected general project type'] };\n\n const workspaceRoot = canonicalWorkspacePath(input.workspaceRoot);\n const reasons: string[] = [];\n let score = 0;\n\n if (workspaceRoot && directoryExists(workspaceRoot)) {\n for (const marker of STRONG_CODE_MARKERS) {\n if (existsSync(join(workspaceRoot, marker))) {\n score += 4;\n reasons.push(`found ${marker}`);\n break;\n }\n }\n\n for (const dir of WEAK_CODE_DIRECTORIES) {\n if (directoryExists(join(workspaceRoot, dir))) {\n score += 1;\n reasons.push(`found ${dir}/`);\n break;\n }\n }\n\n if (readDirectoryNames(workspaceRoot).some(hasSourceExtension)) {\n score += 2;\n reasons.push('found source files');\n } else {\n for (const dir of ['src', 'app', 'lib']) {\n const childDir = join(workspaceRoot, dir);\n if (directoryExists(childDir) && readDirectoryNames(childDir).some(hasSourceExtension)) {\n score += 2;\n reasons.push(`found source files in ${dir}/`);\n break;\n }\n }\n }\n }\n\n if (score >= 4) return { kind: 'coding', confidence: 0.9, reasons };\n if (score >= 3) return { kind: 'coding', confidence: 0.75, reasons };\n if (workspaceRoot) return { kind: 'general', confidence: 0.55, reasons };\n return { kind: 'unknown', confidence: 0.25, reasons };\n}\n"],"mappings":";;;;AAcA,MAAM,sBAAsB;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,MAAM,wBAAwB;CAAC;CAAO;CAAO;CAAO;CAAS;CAAQ;CAAa;CAAU;AAC5F,MAAM,kBAAkB,IAAI,IAAI;CAC9B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,SAAS,kBAAkB,OAAuD;CAChF,MAAM,aAAa,OAAO,MAAM,CAAC,aAAa;AAC9C,QAAO,eAAe,YAAY,eAAe,YAAY,aAAa;;AAG5E,SAAS,mBAAmB,MAAuB;CACjD,MAAM,QAAQ,KAAK,aAAa;AAChC,MAAK,MAAM,aAAa,gBACtB,KAAI,MAAM,SAAS,UAAU,CAAE,QAAO;AAExC,QAAO;;AAGT,SAAS,mBAAmB,WAA6B;AACvD,KAAI;AACF,SAAO,YAAY,UAAU,CAAC,MAAM,GAAG,IAAI;SACrC;AACN,SAAO,EAAE;;;AAIb,SAAS,gBAAgB,WAA4B;AACnD,KAAI;AACF,SAAO,SAAS,UAAU,CAAC,aAAa;SAClC;AACN,SAAO;;;AAIX,SAAgB,iBAAiB,OAKR;CACvB,MAAM,WAAW,kBAAkB,MAAM,YAAY;AACrD,KAAI,aAAa,SAAU,QAAO;EAAE,MAAM;EAAU,YAAY;EAAG,SAAS,CAAC,+BAA+B;EAAE;AAC9G,KAAI,aAAa,UAAW,QAAO;EAAE,MAAM;EAAW,YAAY;EAAG,SAAS,CAAC,gCAAgC;EAAE;CAEjH,MAAM,gBAAgB,uBAAuB,MAAM,cAAc;CACjE,MAAM,UAAoB,EAAE;CAC5B,IAAI,QAAQ;AAEZ,KAAI,iBAAiB,gBAAgB,cAAc,EAAE;AACnD,OAAK,MAAM,UAAU,oBACnB,KAAI,WAAW,KAAK,eAAe,OAAO,CAAC,EAAE;AAC3C,YAAS;AACT,WAAQ,KAAK,SAAS,SAAS;AAC/B;;AAIJ,OAAK,MAAM,OAAO,sBAChB,KAAI,gBAAgB,KAAK,eAAe,IAAI,CAAC,EAAE;AAC7C,YAAS;AACT,WAAQ,KAAK,SAAS,IAAI,GAAG;AAC7B;;AAIJ,MAAI,mBAAmB,cAAc,CAAC,KAAK,mBAAmB,EAAE;AAC9D,YAAS;AACT,WAAQ,KAAK,qBAAqB;QAElC,MAAK,MAAM,OAAO;GAAC;GAAO;GAAO;GAAM,EAAE;GACvC,MAAM,WAAW,KAAK,eAAe,IAAI;AACzC,OAAI,gBAAgB,SAAS,IAAI,mBAAmB,SAAS,CAAC,KAAK,mBAAmB,EAAE;AACtF,aAAS;AACT,YAAQ,KAAK,yBAAyB,IAAI,GAAG;AAC7C;;;;AAMR,KAAI,SAAS,EAAG,QAAO;EAAE,MAAM;EAAU,YAAY;EAAK;EAAS;AACnE,KAAI,SAAS,EAAG,QAAO;EAAE,MAAM;EAAU,YAAY;EAAM;EAAS;AACpE,KAAI,cAAe,QAAO;EAAE,MAAM;EAAW,YAAY;EAAM;EAAS;AACxE,QAAO;EAAE,MAAM;EAAW,YAAY;EAAM;EAAS"}
1
+ {"version":3,"file":"project-kind.js","names":[],"sources":["../../../src/projects/project-kind.ts"],"sourcesContent":["import { existsSync, readdirSync, statSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { canonicalWorkspacePath } from './workspace-project.js';\n\nexport type ProjectKind = 'coding' | 'general' | 'unknown';\nexport type ProjectKindOverride = 'auto' | 'coding' | 'general';\n\nexport type ProjectKindInference = {\n kind: ProjectKind;\n confidence: number;\n reasons: string[];\n};\n\nconst STRONG_CODE_MARKERS = [\n 'package.json',\n 'pnpm-lock.yaml',\n 'yarn.lock',\n 'package-lock.json',\n 'tsconfig.json',\n 'go.mod',\n 'Cargo.toml',\n 'pyproject.toml',\n 'requirements.txt',\n 'pom.xml',\n 'build.gradle',\n 'Makefile',\n 'Dockerfile',\n 'deno.json',\n 'deno.jsonc',\n 'composer.json',\n 'Gemfile',\n] as const;\n\nconst WEAK_CODE_DIRECTORIES = ['src', 'app', 'lib', 'tests', 'test', '__tests__', '.github'] as const;\nconst CODE_EXTENSIONS = new Set([\n '.c',\n '.cc',\n '.cpp',\n '.cs',\n '.css',\n '.go',\n '.h',\n '.hpp',\n '.html',\n '.java',\n '.js',\n '.jsx',\n '.kt',\n '.mjs',\n '.php',\n '.py',\n '.rb',\n '.rs',\n '.sh',\n '.swift',\n '.ts',\n '.tsx',\n]);\n\nfunction normalizeOverride(value: string | null | undefined): ProjectKindOverride {\n const normalized = value?.trim().toLowerCase();\n return normalized === 'coding' || normalized === 'general' ? normalized : 'auto';\n}\n\nfunction hasSourceExtension(name: string): boolean {\n const lower = name.toLowerCase();\n for (const extension of CODE_EXTENSIONS) {\n if (lower.endsWith(extension)) return true;\n }\n return false;\n}\n\nfunction readDirectoryNames(pathValue: string): string[] {\n try {\n return readdirSync(pathValue).slice(0, 200);\n } catch {\n return [];\n }\n}\n\nfunction directoryExists(pathValue: string): boolean {\n try {\n return statSync(pathValue).isDirectory();\n } catch {\n return false;\n }\n}\n\nexport function inferProjectKind(input: {\n name?: string | null;\n description?: string | null;\n workspaceRoot?: string | null;\n projectKind?: string | null;\n}): ProjectKindInference {\n const override = normalizeOverride(input.projectKind);\n if (override === 'coding') return { kind: 'coding', confidence: 1, reasons: ['selected coding project type'] };\n if (override === 'general') return { kind: 'general', confidence: 1, reasons: ['selected general project type'] };\n\n const workspaceRoot = canonicalWorkspacePath(input.workspaceRoot);\n const reasons: string[] = [];\n let score = 0;\n\n if (workspaceRoot && directoryExists(workspaceRoot)) {\n for (const marker of STRONG_CODE_MARKERS) {\n if (existsSync(join(workspaceRoot, marker))) {\n score += 4;\n reasons.push(`found ${marker}`);\n break;\n }\n }\n\n for (const dir of WEAK_CODE_DIRECTORIES) {\n if (directoryExists(join(workspaceRoot, dir))) {\n score += 1;\n reasons.push(`found ${dir}/`);\n break;\n }\n }\n\n if (readDirectoryNames(workspaceRoot).some(hasSourceExtension)) {\n score += 2;\n reasons.push('found source files');\n } else {\n for (const dir of ['src', 'app', 'lib']) {\n const childDir = join(workspaceRoot, dir);\n if (directoryExists(childDir) && readDirectoryNames(childDir).some(hasSourceExtension)) {\n score += 2;\n reasons.push(`found source files in ${dir}/`);\n break;\n }\n }\n }\n }\n\n if (score >= 4) return { kind: 'coding', confidence: 0.9, reasons };\n if (score >= 3) return { kind: 'coding', confidence: 0.75, reasons };\n if (workspaceRoot) return { kind: 'general', confidence: 0.55, reasons };\n return { kind: 'unknown', confidence: 0.25, reasons };\n}\n"],"mappings":";;;;AAcA,MAAM,sBAAsB;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,MAAM,wBAAwB;CAAC;CAAO;CAAO;CAAO;CAAS;CAAQ;CAAa;CAAU;AAC5F,MAAM,kBAAkB,IAAI,IAAI;CAC9B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,SAAS,kBAAkB,OAAuD;CAChF,MAAM,aAAa,OAAO,MAAM,CAAC,aAAa;AAC9C,QAAO,eAAe,YAAY,eAAe,YAAY,aAAa;;AAG5E,SAAS,mBAAmB,MAAuB;CACjD,MAAM,QAAQ,KAAK,aAAa;AAChC,MAAK,MAAM,aAAa,gBACtB,KAAI,MAAM,SAAS,UAAU,CAAE,QAAO;AAExC,QAAO;;AAGT,SAAS,mBAAmB,WAA6B;AACvD,KAAI;AACF,SAAO,YAAY,UAAU,CAAC,MAAM,GAAG,IAAI;SACrC;AACN,SAAO,EAAE;;;AAIb,SAAS,gBAAgB,WAA4B;AACnD,KAAI;AACF,SAAO,SAAS,UAAU,CAAC,aAAa;SAClC;AACN,SAAO;;;AAIX,SAAgB,iBAAiB,OAKR;CACvB,MAAM,WAAW,kBAAkB,MAAM,YAAY;AACrD,KAAI,aAAa,SAAU,QAAO;EAAE,MAAM;EAAU,YAAY;EAAG,SAAS,CAAC,+BAA+B;EAAE;AAC9G,KAAI,aAAa,UAAW,QAAO;EAAE,MAAM;EAAW,YAAY;EAAG,SAAS,CAAC,gCAAgC;EAAE;CAEjH,MAAM,gBAAgB,uBAAuB,MAAM,cAAc;CACjE,MAAM,UAAoB,EAAE;CAC5B,IAAI,QAAQ;AAEZ,KAAI,iBAAiB,gBAAgB,cAAc,EAAE;AACnD,OAAK,MAAM,UAAU,oBACnB,KAAI,WAAW,KAAK,eAAe,OAAO,CAAC,EAAE;AAC3C,YAAS;AACT,WAAQ,KAAK,SAAS,SAAS;AAC/B;;AAIJ,OAAK,MAAM,OAAO,sBAChB,KAAI,gBAAgB,KAAK,eAAe,IAAI,CAAC,EAAE;AAC7C,YAAS;AACT,WAAQ,KAAK,SAAS,IAAI,GAAG;AAC7B;;AAIJ,MAAI,mBAAmB,cAAc,CAAC,KAAK,mBAAmB,EAAE;AAC9D,YAAS;AACT,WAAQ,KAAK,qBAAqB;QAElC,MAAK,MAAM,OAAO;GAAC;GAAO;GAAO;GAAM,EAAE;GACvC,MAAM,WAAW,KAAK,eAAe,IAAI;AACzC,OAAI,gBAAgB,SAAS,IAAI,mBAAmB,SAAS,CAAC,KAAK,mBAAmB,EAAE;AACtF,aAAS;AACT,YAAQ,KAAK,yBAAyB,IAAI,GAAG;AAC7C;;;;AAMR,KAAI,SAAS,EAAG,QAAO;EAAE,MAAM;EAAU,YAAY;EAAK;EAAS;AACnE,KAAI,SAAS,EAAG,QAAO;EAAE,MAAM;EAAU,YAAY;EAAM;EAAS;AACpE,KAAI,cAAe,QAAO;EAAE,MAAM;EAAW,YAAY;EAAM;EAAS;AACxE,QAAO;EAAE,MAAM;EAAW,YAAY;EAAM;EAAS"}
@@ -19,8 +19,13 @@ export declare function openTimelineOverlay(svc: PickerServices, initialQuery?:
19
19
  export declare function sessionTreeSelectItems(sessions: TuiSessionItem[], currentSessionKey?: string): SelectItem[];
20
20
  export declare function openAgentPickerOverlay(svc: PickerServices): Promise<void>;
21
21
  export declare function openReviewLauncherOverlay(svc: PickerServices): Promise<void>;
22
+ export interface SessionPickerOverlayOptions {
23
+ onCancel?: () => void;
24
+ onEmpty?: () => void;
25
+ onResume?: () => void;
26
+ }
22
27
  /** Ctrl+Shift+P — session picker with rename/delete. */
23
- export declare function openSessionPickerOverlay(svc: PickerServices): Promise<void>;
28
+ export declare function openSessionPickerOverlay(svc: PickerServices, options?: SessionPickerOverlayOptions): Promise<void>;
24
29
  /** Searchable session tree navigation overlay. */
25
30
  export declare function openSessionTreeOverlay(svc: PickerServices): Promise<void>;
26
31
  /** Searchable current-transcript tree overlay. */
@@ -345,11 +345,12 @@ async function openReviewLauncherOverlay(svc) {
345
345
  openReviewPresetSelector(svc, context);
346
346
  }
347
347
  /** Ctrl+Shift+P — session picker with rename/delete. */
348
- async function openSessionPickerOverlay(svc) {
348
+ async function openSessionPickerOverlay(svc, options = {}) {
349
349
  const sessions = await svc.client.listSessions();
350
350
  if (sessions.length === 0) {
351
351
  svc.chatLog.addSystem("No sessions listed.");
352
352
  svc.tui.requestRender();
353
+ options.onEmpty?.();
353
354
  return;
354
355
  }
355
356
  const selector = new SessionSelector(sessions, {
@@ -357,6 +358,7 @@ async function openSessionPickerOverlay(svc) {
357
358
  svc.closeOverlay();
358
359
  svc.tui.setFocus(svc.editor);
359
360
  resumeSession(svc, sessionKey);
361
+ options.onResume?.();
360
362
  },
361
363
  onRename: async (sessionKey, name) => {
362
364
  return (await svc.client.renameSession(sessionKey, name)).ok ? { ok: true } : {
@@ -378,6 +380,7 @@ async function openSessionPickerOverlay(svc) {
378
380
  svc.closeOverlay();
379
381
  svc.tui.setFocus(svc.editor);
380
382
  svc.tui.requestRender();
383
+ options.onCancel?.();
381
384
  },
382
385
  requestRender: () => svc.tui.requestRender()
383
386
  }, svc.keybindings, sessions.find((s) => s.key === svc.state.currentSessionKey)?.cwd ?? process.cwd(), svc.state.currentSessionKey);