@dendelion/paper-camp 0.14.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/dist/app/assets/index-2ahHj0hk.js +7 -0
  2. package/dist/app/assets/index-2ahHj0hk.js.map +1 -0
  3. package/dist/app/assets/{index-D2zDC3YW.js → index-BSp1FE97.js} +2 -2
  4. package/dist/app/assets/{index-D2zDC3YW.js.map → index-BSp1FE97.js.map} +1 -1
  5. package/dist/app/assets/{index-C5as2mi1.js → index-BTyua-6D.js} +3 -3
  6. package/dist/app/assets/{index-C5as2mi1.js.map → index-BTyua-6D.js.map} +1 -1
  7. package/dist/app/assets/{index-DrOhvDGC.js → index-Bi4fur5H.js} +2 -2
  8. package/dist/app/assets/{index-DrOhvDGC.js.map → index-Bi4fur5H.js.map} +1 -1
  9. package/dist/app/assets/index-Bo0V9-3F.js +2 -0
  10. package/dist/app/assets/index-Bo0V9-3F.js.map +1 -0
  11. package/dist/app/assets/index-Cz9HEIaO.js +2 -0
  12. package/dist/app/assets/{index-BTh66TxZ.js.map → index-Cz9HEIaO.js.map} +1 -1
  13. package/dist/app/assets/{index-SjRbcqaJ.js → index-DKjtMMrA.js} +2 -2
  14. package/dist/app/assets/{index-SjRbcqaJ.js.map → index-DKjtMMrA.js.map} +1 -1
  15. package/dist/app/assets/main-BW24wv9K.js +207 -0
  16. package/dist/app/assets/main-BW24wv9K.js.map +1 -0
  17. package/dist/app/assets/main-C-ynmROL.css +1 -0
  18. package/dist/app/assets/{sidebar-section-BlseNbG8.js → sidebar-section-BHLbvk_X.js} +2 -2
  19. package/dist/app/assets/{sidebar-section-BlseNbG8.js.map → sidebar-section-BHLbvk_X.js.map} +1 -1
  20. package/dist/app/index.html +6 -6
  21. package/dist/app/toolbar.js +11684 -0
  22. package/dist/app/toolbar.js.map +1 -0
  23. package/dist/chunks/{scaffold.BL48Net9.js → parked-questions.BoAnCnQA.js} +814 -730
  24. package/dist/chunks/parked-questions.BoAnCnQA.js.map +1 -0
  25. package/dist/cli/index.js +7479 -7384
  26. package/dist/cli/index.js.map +1 -1
  27. package/dist/core/index.d.ts +2 -0
  28. package/dist/core/index.d.ts.map +1 -1
  29. package/dist/core/index.js +85 -78
  30. package/dist/core/parked-questions.d.ts +6 -0
  31. package/dist/core/parked-questions.d.ts.map +1 -0
  32. package/dist/core/parked-questions.test.d.ts +2 -0
  33. package/dist/core/parked-questions.test.d.ts.map +1 -0
  34. package/dist/core/parse/parser.d.ts.map +1 -1
  35. package/dist/core/parse/schemas.d.ts +1 -0
  36. package/dist/core/parse/schemas.d.ts.map +1 -1
  37. package/dist/core/readers.d.ts.map +1 -1
  38. package/dist/core/release-notes.d.ts +4 -0
  39. package/dist/core/release-notes.d.ts.map +1 -0
  40. package/dist/core/release-notes.test.d.ts +2 -0
  41. package/dist/core/release-notes.test.d.ts.map +1 -0
  42. package/dist/core/serialize/serializer.d.ts +1 -0
  43. package/dist/core/serialize/serializer.d.ts.map +1 -1
  44. package/dist/core/trail.d.ts +6 -0
  45. package/dist/core/trail.d.ts.map +1 -1
  46. package/dist/types/index.d.ts +24 -2
  47. package/dist/types/index.d.ts.map +1 -1
  48. package/dist/types/index.js +4 -4
  49. package/dist/types/index.js.map +1 -1
  50. package/dist/vite/index.d.ts.map +1 -1
  51. package/dist/vite/index.js +28 -27
  52. package/dist/vite/index.js.map +1 -1
  53. package/package.json +5 -3
  54. package/dist/app/assets/index-BTh66TxZ.js +0 -2
  55. package/dist/app/assets/index-CXl1uFWF.js +0 -2
  56. package/dist/app/assets/index-CXl1uFWF.js.map +0 -1
  57. package/dist/app/assets/main-BC7PxPmE.js +0 -207
  58. package/dist/app/assets/main-BC7PxPmE.js.map +0 -1
  59. package/dist/app/assets/main-uLU_O3GC.css +0 -1
  60. package/dist/chunks/helpers.CUQjsQwc.js +0 -9
  61. package/dist/chunks/helpers.CUQjsQwc.js.map +0 -1
  62. package/dist/chunks/scaffold.BL48Net9.js.map +0 -1
  63. package/dist/toolbar/focus-panel.d.ts +0 -7
  64. package/dist/toolbar/focus-panel.d.ts.map +0 -1
  65. package/dist/toolbar/index.d.ts +0 -2
  66. package/dist/toolbar/index.d.ts.map +0 -1
  67. package/dist/toolbar/runs-panel.d.ts +0 -12
  68. package/dist/toolbar/runs-panel.d.ts.map +0 -1
  69. package/dist/toolbar/scout-panel.d.ts +0 -10
  70. package/dist/toolbar/scout-panel.d.ts.map +0 -1
  71. package/dist/toolbar/ship-panel.d.ts +0 -6
  72. package/dist/toolbar/ship-panel.d.ts.map +0 -1
  73. package/dist/toolbar/toolbar-element.d.ts +0 -7
  74. package/dist/toolbar/toolbar-element.d.ts.map +0 -1
  75. package/dist/toolbar/toolbar-idle.d.ts +0 -4
  76. package/dist/toolbar/toolbar-idle.d.ts.map +0 -1
  77. package/dist/toolbar/toolbar-idle.test.d.ts +0 -2
  78. package/dist/toolbar/toolbar-idle.test.d.ts.map +0 -1
  79. package/dist/toolbar/toolbar-link.d.ts +0 -7
  80. package/dist/toolbar/toolbar-link.d.ts.map +0 -1
  81. package/dist/toolbar/toolbar-shell.d.ts +0 -15
  82. package/dist/toolbar/toolbar-shell.d.ts.map +0 -1
  83. package/dist/toolbar/toolbar-shell.test.d.ts +0 -2
  84. package/dist/toolbar/toolbar-shell.test.d.ts.map +0 -1
  85. package/dist/toolbar/toolbar.d.ts +0 -2
  86. package/dist/toolbar/toolbar.d.ts.map +0 -1
  87. package/dist/toolbar/use-toolbar-shell.d.ts +0 -8
  88. package/dist/toolbar/use-toolbar-shell.d.ts.map +0 -1
  89. package/dist/toolbar.d.ts +0 -1
  90. package/dist/toolbar.js +0 -27019
  91. package/dist/toolbar.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index-DrOhvDGC.js","sources":["../../../src/app/features/roadmap/promote-roadmap-item-modal.tsx","../../../src/app/features/roadmap/roadmap-page.tsx"],"sourcesContent":["import { buildRoadmapPromotePrompt } from '@/app/features/plans/prompts';\nimport { useSubjectVocabulary } from '@/app/hooks/use-subject-vocabulary';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { oneLineErrorSummary } from '@/app/utils/error-summary';\nimport type { RoadmapItem } from '@/types/index';\nimport { Button, Modal, Select, useToast } from '@dendelion/paper-ui';\nimport { useEffect, useState } from 'react';\n\nconst NO_SUBJECT = '__no-subject__';\n\ninterface PromoteRoadmapItemModalProps {\n horizonTitle: string | null;\n item: RoadmapItem | null;\n candidateName?: string | null;\n onClose: () => void;\n onPromoted: () => void;\n}\n\nexport const PromoteRoadmapItemModal = ({\n horizonTitle,\n item,\n candidateName,\n onClose,\n onPromoted,\n}: PromoteRoadmapItemModalProps) => {\n const promoteRoadmapItem = useAppStore((s) => s.promoteRoadmapItem);\n const launchIdeaExtend = useAppStore((s) => s.launchIdeaExtend);\n const { subjects, available: subjectsAvailable } = useSubjectVocabulary();\n const [subject, setSubject] = useState(NO_SUBJECT);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const { toast } = useToast();\n\n useEffect(() => {\n if (item) {\n // A candidate defaults to its parent item's name — the \"big bet becomes a\n // Subject\" rule — but the picker still lets the user override it.\n setSubject(candidateName ? item.name : NO_SUBJECT);\n setLoading(false);\n setError(null);\n }\n }, [item, candidateName]);\n\n const handlePromote = async () => {\n if (!item || !horizonTitle) return;\n setLoading(true);\n setError(null);\n try {\n const id = await promoteRoadmapItem(\n horizonTitle,\n item,\n subject === NO_SUBJECT ? undefined : subject,\n candidateName ?? undefined,\n );\n const idea = useAppStore.getState().ideaEntries.find((e) => e.id === id);\n if (idea) {\n try {\n await launchIdeaExtend(id, buildRoadmapPromotePrompt(idea, horizonTitle));\n } catch (err) {\n // The idea was created either way — a failed refine launch just means\n // no background research ran, not that the promotion itself failed.\n toast({\n title: 'Idea created, but the refine agent failed to launch',\n description: oneLineErrorSummary((err as Error).message),\n variant: 'error',\n });\n }\n }\n onPromoted();\n onClose();\n } catch (err) {\n setError((err as Error).message);\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <Modal\n open={item !== null}\n onClose={onClose}\n title={candidateName ?? item?.name ?? ''}\n size=\"small\"\n >\n <div className=\"flex flex-col gap-4\">\n {!candidateName && <p className=\"m-0 opacity-80\">{item?.description}</p>}\n <div>\n <Select\n size=\"small\"\n value={subject}\n onChange={setSubject}\n disabled={loading || !subjectsAvailable}\n options={[\n { value: NO_SUBJECT, label: 'No subject' },\n ...(!subjectsAvailable && subject !== NO_SUBJECT\n ? [{ value: subject, label: subject }]\n : []),\n ...subjects.map((s) => ({ value: s, label: s })),\n ]}\n />\n </div>\n {error && <p className=\"m-0 text-watercolor-rose-dark text-sm\">{error}</p>}\n <div className=\"flex justify-end gap-2\">\n <Button type=\"button\" variant=\"ghost\" onClick={onClose} disabled={loading}>\n Cancel\n </Button>\n <Button type=\"button\" variant=\"primary\" onClick={handlePromote} disabled={loading}>\n {loading ? 'Promoting…' : 'Promote to idea'}\n </Button>\n </div>\n </div>\n </Modal>\n );\n};\n","import { Markdown } from '@/app/components/markdown';\nimport { PageTitle } from '@/app/components/page-title';\nimport { PrBadge } from '@/app/features/plans/components/pr-badge';\nimport { STATUS_LABEL, STATUS_STAMP } from '@/app/features/plans/constants';\nimport { addRoadmapCandidate, addRoadmapItem, fetchRoadmap } from '@/app/services/content/docs-api';\nimport { useAppStore } from '@/app/stores/app-store';\nimport type {\n PlanEntry,\n ResolvedRoadmap,\n ResolvedRoadmapItem,\n RoadmapEvent,\n RoadmapEventKind,\n RoadmapLink,\n} from '@/types/index';\nimport { Button, Card, Input, Stamp, Tooltip } from '@dendelion/paper-ui';\nimport { useNavigate, useSearch } from '@tanstack/react-router';\nimport { useEffect, useRef, useState } from 'react';\nimport { PromoteRoadmapItemModal } from './promote-roadmap-item-modal';\n\nconst graduationCounts = (graduated: PlanEntry[]) => ({\n shipped: graduated.filter((p) => p.status === 'done').length,\n queued: graduated.filter((p) => p.status !== 'done' && p.status !== 'dropped').length,\n});\n\nconst HORIZON_HEADER_CLASSES =\n 'font-handwritten text-md font-semibold opacity-70 leading-none pt-2 px-1 pb-0';\n\nconst HORIZON_PULSE_CLASSES = 'text-2xs font-normal px-1 py-0 opacity-50';\n\nconst ChevronRightIcon = ({ size = 14 }: { size?: number }) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <polyline points=\"9 18 15 12 9 6\" />\n </svg>\n);\n\nconst CandidateRow = ({\n name,\n onPromote,\n}: {\n name: string;\n onPromote: () => void;\n}) => (\n <Card size=\"small\" texture=\"kraft\" className=\"plan-row-card\">\n <div className=\"flex items-center gap-3\">\n <span className=\"flex-1\">{name}</span>\n <Button type=\"button\" variant=\"ghost\" size=\"small\" onClick={onPromote}>\n Promote to idea\n </Button>\n </div>\n </Card>\n);\n\nconst AddCandidateForm = ({ onAdd }: { onAdd: (name: string) => Promise<void> }) => {\n const [name, setName] = useState('');\n const [saving, setSaving] = useState(false);\n\n const handleAdd = async () => {\n if (!name.trim()) return;\n setSaving(true);\n try {\n await onAdd(name.trim());\n setName('');\n } finally {\n setSaving(false);\n }\n };\n\n return (\n <div className=\"flex gap-2\">\n <Input\n size=\"small\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') handleAdd();\n }}\n placeholder=\"Add option…\"\n disabled={saving}\n className=\"flex-1\"\n />\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"small\"\n onClick={handleAdd}\n disabled={saving || !name.trim()}\n >\n Add\n </Button>\n </div>\n );\n};\n\nconst AddItemForm = ({\n onAdd,\n}: {\n onAdd: (name: string, description: string) => Promise<void>;\n}) => {\n const [open, setOpen] = useState(false);\n const [name, setName] = useState('');\n const [description, setDescription] = useState('');\n const [saving, setSaving] = useState(false);\n\n const handleAdd = async () => {\n if (!name.trim()) return;\n setSaving(true);\n try {\n await onAdd(name.trim(), description.trim());\n setName('');\n setDescription('');\n setOpen(false);\n } finally {\n setSaving(false);\n }\n };\n\n if (!open) {\n return (\n <Button type=\"button\" variant=\"ghost\" size=\"small\" onClick={() => setOpen(true)}>\n + Add item\n </Button>\n );\n }\n\n return (\n <div className=\"flex flex-col gap-2\">\n <Input\n size=\"small\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"Item name…\"\n disabled={saving}\n autoFocus\n />\n <Input\n size=\"small\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') handleAdd();\n }}\n placeholder=\"Description…\"\n disabled={saving}\n />\n <div className=\"flex justify-end gap-2\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"small\"\n onClick={() => setOpen(false)}\n disabled={saving}\n >\n Cancel\n </Button>\n <Button type=\"button\" size=\"small\" onClick={handleAdd} disabled={saving || !name.trim()}>\n Add\n </Button>\n </div>\n </div>\n );\n};\n\nconst plural = (count: number, noun: string) => `${count} ${noun}${count === 1 ? '' : 's'}`;\n\nconst RoadmapLinkTrail = ({ link }: { link: RoadmapLink }) => (\n <div className=\"flex items-center gap-1\">\n <Tooltip content={`${plural(link.taskRuns, 'task run')}${link.released ? ' · released' : ''}`}>\n <Stamp\n size=\"small\"\n fillColor={STATUS_STAMP[link.status].fill}\n textColor={STATUS_STAMP[link.status].text}\n >\n {link.id}\n </Stamp>\n </Tooltip>\n {link.pr && <PrBadge pr={link.pr} />}\n </div>\n);\n\nconst GraduatedRow = ({ plan, onOpen }: { plan: PlanEntry; onOpen: () => void }) => (\n <Card size=\"small\" texture=\"kraft\" className=\"plan-row-card\">\n <button\n type=\"button\"\n onClick={onOpen}\n className=\"flex items-center gap-3 w-full bg-transparent border-none p-0 cursor-pointer [font:inherit] text-inherit text-left\"\n >\n <span className=\"flex-1 overflow-hidden text-ellipsis whitespace-nowrap\">{plan.title}</span>\n <Stamp\n size=\"small\"\n fillColor={STATUS_STAMP[plan.status].fill}\n textColor={STATUS_STAMP[plan.status].text}\n >\n {STATUS_LABEL[plan.status]}\n </Stamp>\n </button>\n </Card>\n);\n\nconst RoadmapItemRow = ({\n item,\n graduated,\n highlighted,\n onPromote,\n onPromoteCandidate,\n onAddCandidate,\n onViewGraduated,\n onOpenGraduated,\n}: {\n item: ResolvedRoadmapItem;\n graduated: PlanEntry[];\n highlighted: boolean;\n onPromote: () => void;\n onPromoteCandidate: (candidateName: string) => void;\n onAddCandidate: (name: string) => Promise<void>;\n onViewGraduated: () => void;\n onOpenGraduated: (title: string) => void;\n}) => {\n const [expanded, setExpanded] = useState(highlighted);\n const hasCandidates = item.candidates.length > 0;\n const { shipped, queued } = graduationCounts(graduated);\n\n return (\n <div\n className={`flex flex-col gap-1 ${highlighted ? 'roadmap-item-highlighted outline outline-2 outline-offset-[-2px] outline-[rgba(200,154,90,0.5)]' : ''}`}\n >\n <Card size=\"small\" texture=\"canvas\" className=\"plan-row-card\">\n <div className=\"flex flex-col gap-1\">\n <div className=\"flex items-center gap-2\">\n {/* Raw <button>: icon-only toggle, paper-ui Button doesn't offer this compact chrome. */}\n <button\n type=\"button\"\n aria-expanded={expanded}\n aria-label={expanded ? 'Collapse item' : 'Expand item'}\n onClick={() => setExpanded((v) => !v)}\n className={`inline-flex items-center bg-transparent border-none cursor-pointer opacity-50 p-0 ${expanded ? 'rotate-90' : ''}`}\n >\n <ChevronRightIcon />\n </button>\n <span className=\"font-semibold flex-1\">{item.name}</span>\n <Button type=\"button\" variant=\"ghost\" size=\"small\" onClick={onPromote}>\n Promote to idea\n </Button>\n </div>\n <span className={`text-sm opacity-70 ${expanded ? '' : 'line-clamp-2'}`}>\n {item.description}\n </span>\n <div className=\"flex items-center gap-1\">\n {(queued > 0 || shipped > 0) && (\n <button\n type=\"button\"\n onClick={onViewGraduated}\n className=\"flex items-center gap-1 bg-transparent border-none p-0 cursor-pointer\"\n >\n {queued > 0 && (\n <Stamp\n size=\"small\"\n fillColor={STATUS_STAMP.planned.fill}\n textColor={STATUS_STAMP.planned.text}\n >\n {queued} in queue\n </Stamp>\n )}\n {shipped > 0 && (\n <Stamp\n size=\"small\"\n fillColor={STATUS_STAMP.done.fill}\n textColor={STATUS_STAMP.done.text}\n >\n {shipped} shipped\n </Stamp>\n )}\n </button>\n )}\n {hasCandidates && (\n <Stamp size=\"small\" fillColor=\"rgba(0, 0, 0, 0.06)\" textColor=\"rgba(0, 0, 0, 0.55)\">\n {item.candidates.length} candidate{item.candidates.length === 1 ? '' : 's'}\n </Stamp>\n )}\n {item.rollup.total > 0 && (\n <Stamp\n size=\"small\"\n fillColor={STATUS_STAMP.planned.fill}\n textColor={STATUS_STAMP.planned.text}\n >\n {item.rollup.done}/{item.rollup.total} done\n </Stamp>\n )}\n </div>\n {item.links.length > 0 && (\n <div className=\"flex items-center gap-1 flex-wrap\">\n {item.links.map((link) => (\n <RoadmapLinkTrail key={link.id} link={link} />\n ))}\n </div>\n )}\n </div>\n </Card>\n {expanded && (\n <div className=\"flex flex-col gap-1 pl-6\">\n {item.candidates.map((candidateName) => (\n <CandidateRow\n key={candidateName}\n name={candidateName}\n onPromote={() => onPromoteCandidate(candidateName)}\n />\n ))}\n {graduated.map((plan) => (\n <GraduatedRow key={plan.title} plan={plan} onOpen={() => onOpenGraduated(plan.title)} />\n ))}\n <AddCandidateForm onAdd={onAddCandidate} />\n </div>\n )}\n </div>\n );\n};\n\nconst GoalBanner = ({ goal }: { goal: string }) => {\n const [expanded, setExpanded] = useState(false);\n const [firstParagraph, ...restParagraphs] = goal.split(/\\n{2,}/);\n const hasMore = restParagraphs.length > 0;\n\n return (\n <div className=\"mb-6 pb-4 border-b border-black/[8%]\">\n <span className=\"font-handwritten text-xs font-semibold opacity-[0.55]\">The goal</span>\n <div className=\"font-display-luminari text-lg leading-[1.4] mt-2\">\n <div className={expanded ? undefined : 'line-clamp-1'}>\n <Markdown>{firstParagraph}</Markdown>\n </div>\n {expanded && hasMore && <Markdown>{restParagraphs.join('\\n\\n')}</Markdown>}\n </div>\n {hasMore && (\n <button\n type=\"button\"\n onClick={() => setExpanded((v) => !v)}\n className=\"bg-transparent border-none p-0 mt-2 cursor-pointer text-2xs opacity-[0.65] underline\"\n >\n {expanded ? 'Show less' : 'Show more'}\n </button>\n )}\n </div>\n );\n};\n\ntype RoadmapViewMode = 'tree' | 'map' | 'timeline';\n\nconst VIEW_MODES: { id: RoadmapViewMode; label: string }[] = [\n { id: 'tree', label: 'Outline' },\n { id: 'map', label: 'Board' },\n { id: 'timeline', label: 'Timeline' },\n];\n\nconst RoadmapViewModeSwitch = ({\n mode,\n onChange,\n}: {\n mode: RoadmapViewMode;\n onChange: (mode: RoadmapViewMode) => void;\n}) => (\n <nav aria-label=\"Roadmap view\" className=\"flex gap-1 mb-4\">\n {VIEW_MODES.map((viewMode) => (\n <Button\n key={viewMode.id}\n type=\"button\"\n variant=\"ghost\"\n size=\"small\"\n isActive={mode === viewMode.id}\n aria-pressed={mode === viewMode.id}\n onClick={() => onChange(viewMode.id)}\n >\n {viewMode.label}\n </Button>\n ))}\n </nav>\n);\n\nconst HorizonPulse = ({\n items,\n graduatedByItem,\n}: {\n items: ResolvedRoadmapItem[];\n graduatedByItem: (item: ResolvedRoadmapItem) => PlanEntry[];\n}) => {\n const graduated = items.filter((item) => graduatedByItem(item).length > 0).length;\n const charted = items.length - graduated;\n return (\n <div className={HORIZON_PULSE_CLASSES}>\n {graduated} graduated · {charted} charted\n </div>\n );\n};\n\nconst EVENT_KIND_COLOR: Record<RoadmapEventKind, string> = {\n created: 'bg-watercolor-slate',\n 'task-run': 'bg-watercolor-amber',\n};\n\nconst RoadmapTimelineTrack = ({\n events,\n rangeStart,\n rangeEnd,\n}: {\n events: RoadmapEvent[];\n rangeStart: number;\n rangeEnd: number;\n}) => {\n const span = rangeEnd - rangeStart || 1;\n return (\n <div className=\"relative h-8 mx-1 border-b border-black/10\">\n {events.map((event, i) => (\n <button\n type=\"button\"\n key={`${event.entityId}-${event.kind}-${i}`}\n className={`absolute top-1/2 w-2.5 h-2.5 p-0 border-none rounded-full -translate-x-1/2 -translate-y-1/2 cursor-pointer ${EVENT_KIND_COLOR[event.kind]}`}\n style={{\n left: `${((Date.parse(event.date) - rangeStart) / span) * 100}%`,\n }}\n title={`${event.itemName} — ${event.label} (${event.date})`}\n aria-label={`${event.itemName} — ${event.label} (${event.date})`}\n />\n ))}\n </div>\n );\n};\n\nconst RoadmapMapItem = ({ item }: { item: ResolvedRoadmapItem }) => {\n const percent =\n item.rollup.total > 0 ? Math.round((item.rollup.done / item.rollup.total) * 100) : 0;\n return (\n <div className=\"flex flex-col gap-1 py-2 px-2.5\">\n <div className=\"font-semibold text-sm\">{item.name}</div>\n <div className=\"h-1.5 rounded-full bg-black/[0.08] overflow-hidden\">\n <div\n className={`h-full rounded-full ${item.rollup.total > 0 ? 'bg-watercolor-green' : 'bg-transparent'}`}\n style={{\n width: `${percent}%`,\n }}\n />\n </div>\n <div className=\"text-2xs opacity-50\">\n {item.rollup.total > 0 ? `${item.rollup.done}/${item.rollup.total} done` : 'not started'}\n </div>\n </div>\n );\n};\n\nconst RoadmapMap = ({\n roadmap,\n graduatedByItem,\n}: {\n roadmap: ResolvedRoadmap;\n graduatedByItem: (item: ResolvedRoadmapItem) => PlanEntry[];\n}) => (\n <div className=\"flex flex-col gap-6\">\n {roadmap.horizons.map((horizon) => (\n <div key={horizon.title} className=\"flex flex-col gap-1\">\n <div className=\"flex items-baseline gap-2\">\n <div className={HORIZON_HEADER_CLASSES}>{horizon.title}</div>\n <HorizonPulse items={horizon.items} graduatedByItem={graduatedByItem} />\n </div>\n <div className=\"flex flex-wrap items-start gap-2.5\">\n {horizon.items.map((item) => (\n <div\n key={item.name}\n className=\"flex-[1_1_240px] max-w-[320px] max-[480px]:flex-[1_1_100%] max-[480px]:max-w-none\"\n >\n <RoadmapMapItem item={item} />\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n);\n\nconst RoadmapTimeline = ({ roadmap }: { roadmap: ResolvedRoadmap }) => {\n if (roadmap.events.length === 0) {\n return <p className=\"opacity-50\">No dated events yet.</p>;\n }\n\n const dates = roadmap.events.map((event) => Date.parse(event.date));\n const rangeStart = Math.min(...dates);\n const rangeEnd = Math.max(...dates);\n\n return (\n <div className=\"flex flex-col gap-6\">\n {roadmap.horizons.map((horizon) => {\n const events = roadmap.events.filter((event) => event.horizonTitle === horizon.title);\n return (\n <div key={horizon.title} className=\"flex flex-col gap-1\">\n <div className={HORIZON_HEADER_CLASSES}>{horizon.title}</div>\n {events.length === 0 ? (\n <div className=\"text-2xs font-normal px-1 py-0 opacity-40\">No events yet</div>\n ) : (\n <RoadmapTimelineTrack events={events} rangeStart={rangeStart} rangeEnd={rangeEnd} />\n )}\n </div>\n );\n })}\n <div className=\"flex justify-between text-2xs opacity-50\">\n <span>{new Date(rangeStart).toLocaleDateString()}</span>\n <span>{new Date(rangeEnd).toLocaleDateString()}</span>\n </div>\n </div>\n );\n};\n\nexport const RoadmapPage = () => {\n const [roadmap, setRoadmap] = useState<ResolvedRoadmap | null>(null);\n const [loading, setLoading] = useState(true);\n const [loadFailed, setLoadFailed] = useState(false);\n const [promoting, setPromoting] = useState<{\n horizonTitle: string;\n item: ResolvedRoadmapItem;\n candidateName?: string;\n } | null>(null);\n const [viewMode, setViewMode] = useState<RoadmapViewMode>('tree');\n const plans = useAppStore((s) => s.plans);\n const navigate = useNavigate();\n const { item: highlightedItem } = useSearch({ from: '/roadmap' });\n const containerRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n fetchRoadmap()\n .then(setRoadmap)\n .catch(() => setLoadFailed(true))\n .finally(() => setLoading(false));\n }, []);\n\n useEffect(() => {\n if (!highlightedItem || loading) return;\n const row = containerRef.current?.querySelector('.roadmap-item-highlighted');\n row?.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }, [highlightedItem, loading]);\n\n if (loading) {\n return (\n <div>\n <PageTitle>Roadmap</PageTitle>\n <p className=\"opacity-50\">Loading…</p>\n </div>\n );\n }\n\n if (loadFailed) {\n return (\n <div>\n <PageTitle>Roadmap</PageTitle>\n <p className=\"opacity-50\">\n Couldn't load the roadmap — the server may need a restart to pick up new routes.\n </p>\n </div>\n );\n }\n\n if (!roadmap || roadmap.horizons.length === 0) {\n return (\n <div>\n <PageTitle>Roadmap</PageTitle>\n <p className=\"opacity-50\">No `ROADMAP.md` found at the project root.</p>\n </div>\n );\n }\n\n const graduatedByItem = (item: ResolvedRoadmapItem) =>\n plans?.entries.filter((p) => p.subject === item.name) ?? [];\n\n const handleAddItem = async (horizonTitle: string, name: string, description: string) => {\n await addRoadmapItem(horizonTitle, name, description);\n setRoadmap(await fetchRoadmap());\n };\n\n const handleAddCandidate = async (horizonTitle: string, itemName: string, name: string) => {\n await addRoadmapCandidate(horizonTitle, itemName, name);\n setRoadmap(await fetchRoadmap());\n };\n\n return (\n <div ref={containerRef}>\n <GoalBanner goal={roadmap.goal} />\n <RoadmapViewModeSwitch mode={viewMode} onChange={setViewMode} />\n {viewMode === 'tree' && (\n <div className=\"flex flex-col gap-6\">\n {roadmap.horizons.map((horizon) => (\n <div key={horizon.title} className=\"flex flex-col gap-1\">\n <div className=\"flex items-baseline gap-2\">\n <div className={HORIZON_HEADER_CLASSES}>{horizon.title}</div>\n <HorizonPulse items={horizon.items} graduatedByItem={graduatedByItem} />\n </div>\n <div className=\"flex flex-wrap items-start gap-2.5\">\n {horizon.items.map((item) => (\n <div\n key={item.name}\n className=\"flex-[1_1_240px] max-w-[320px] max-[480px]:flex-[1_1_100%] max-[480px]:max-w-none\"\n >\n <RoadmapItemRow\n item={item}\n graduated={graduatedByItem(item)}\n highlighted={item.name === highlightedItem}\n onPromote={() => setPromoting({ horizonTitle: horizon.title, item })}\n onPromoteCandidate={(candidateName) =>\n setPromoting({ horizonTitle: horizon.title, item, candidateName })\n }\n onAddCandidate={(name) => handleAddCandidate(horizon.title, item.name, name)}\n onViewGraduated={() => navigate({ to: '/', search: { subject: item.name } })}\n onOpenGraduated={(title) =>\n navigate({\n to: '/plans/$planId',\n params: { planId: encodeURIComponent(title) },\n })\n }\n />\n </div>\n ))}\n <div className=\"flex-[1_1_240px] max-w-[320px] max-[480px]:flex-[1_1_100%] max-[480px]:max-w-none\">\n <AddItemForm\n onAdd={(name, description) => handleAddItem(horizon.title, name, description)}\n />\n </div>\n </div>\n </div>\n ))}\n </div>\n )}\n {viewMode === 'map' && <RoadmapMap roadmap={roadmap} graduatedByItem={graduatedByItem} />}\n {viewMode === 'timeline' && <RoadmapTimeline roadmap={roadmap} />}\n <PromoteRoadmapItemModal\n horizonTitle={promoting?.horizonTitle ?? null}\n item={promoting?.item ?? null}\n candidateName={promoting?.candidateName}\n onClose={() => setPromoting(null)}\n onPromoted={() => fetchRoadmap().then(setRoadmap)}\n />\n </div>\n );\n};\n"],"names":["NO_SUBJECT","PromoteRoadmapItemModal","horizonTitle","item","candidateName","onClose","onPromoted","promoteRoadmapItem","useAppStore","s","launchIdeaExtend","subjects","subjectsAvailable","useSubjectVocabulary","subject","setSubject","useState","loading","setLoading","error","setError","toast","useToast","useEffect","handlePromote","id","idea","e","buildRoadmapPromotePrompt","err","oneLineErrorSummary","jsx","Modal","jsxs","Select","Button","graduationCounts","graduated","p","HORIZON_HEADER_CLASSES","HORIZON_PULSE_CLASSES","ChevronRightIcon","size","CandidateRow","name","onPromote","Card","AddCandidateForm","onAdd","setName","saving","setSaving","handleAdd","Input","AddItemForm","open","setOpen","description","setDescription","plural","count","noun","RoadmapLinkTrail","link","Tooltip","Stamp","STATUS_STAMP","PrBadge","GraduatedRow","plan","onOpen","STATUS_LABEL","RoadmapItemRow","highlighted","onPromoteCandidate","onAddCandidate","onViewGraduated","onOpenGraduated","expanded","setExpanded","hasCandidates","shipped","queued","v","GoalBanner","goal","firstParagraph","restParagraphs","hasMore","Markdown","VIEW_MODES","RoadmapViewModeSwitch","mode","onChange","viewMode","HorizonPulse","items","graduatedByItem","charted","EVENT_KIND_COLOR","RoadmapTimelineTrack","events","rangeStart","rangeEnd","span","event","i","RoadmapMapItem","percent","RoadmapMap","roadmap","horizon","RoadmapTimeline","dates","RoadmapPage","setRoadmap","loadFailed","setLoadFailed","promoting","setPromoting","setViewMode","plans","navigate","useNavigate","highlightedItem","useSearch","containerRef","useRef","fetchRoadmap","row","_a","PageTitle","handleAddItem","addRoadmapItem","handleAddCandidate","itemName","addRoadmapCandidate","title"],"mappings":"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"}
1
+ {"version":3,"file":"index-Bi4fur5H.js","sources":["../../../src/app/features/roadmap/promote-roadmap-item-modal.tsx","../../../src/app/features/roadmap/roadmap-page.tsx"],"sourcesContent":["import { buildRoadmapPromotePrompt } from '@/app/features/plans/prompts';\nimport { useSubjectVocabulary } from '@/app/hooks/use-subject-vocabulary';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { oneLineErrorSummary } from '@/app/utils/error-summary';\nimport type { RoadmapItem } from '@/types/index';\nimport { Button, Modal, Select, useToast } from '@dendelion/paper-ui';\nimport { useEffect, useState } from 'react';\n\nconst NO_SUBJECT = '__no-subject__';\n\ninterface PromoteRoadmapItemModalProps {\n horizonTitle: string | null;\n item: RoadmapItem | null;\n candidateName?: string | null;\n onClose: () => void;\n onPromoted: () => void;\n}\n\nexport const PromoteRoadmapItemModal = ({\n horizonTitle,\n item,\n candidateName,\n onClose,\n onPromoted,\n}: PromoteRoadmapItemModalProps) => {\n const promoteRoadmapItem = useAppStore((s) => s.promoteRoadmapItem);\n const launchIdeaExtend = useAppStore((s) => s.launchIdeaExtend);\n const { subjects, available: subjectsAvailable } = useSubjectVocabulary();\n const [subject, setSubject] = useState(NO_SUBJECT);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const { toast } = useToast();\n\n useEffect(() => {\n if (item) {\n // A candidate defaults to its parent item's name — the \"big bet becomes a\n // Subject\" rule — but the picker still lets the user override it.\n setSubject(candidateName ? item.name : NO_SUBJECT);\n setLoading(false);\n setError(null);\n }\n }, [item, candidateName]);\n\n const handlePromote = async () => {\n if (!item || !horizonTitle) return;\n setLoading(true);\n setError(null);\n try {\n const id = await promoteRoadmapItem(\n horizonTitle,\n item,\n subject === NO_SUBJECT ? undefined : subject,\n candidateName ?? undefined,\n );\n const idea = useAppStore.getState().ideaEntries.find((e) => e.id === id);\n if (idea) {\n try {\n await launchIdeaExtend(id, buildRoadmapPromotePrompt(idea, horizonTitle));\n } catch (err) {\n // The idea was created either way — a failed refine launch just means\n // no background research ran, not that the promotion itself failed.\n toast({\n title: 'Idea created, but the refine agent failed to launch',\n description: oneLineErrorSummary((err as Error).message),\n variant: 'error',\n });\n }\n }\n onPromoted();\n onClose();\n } catch (err) {\n setError((err as Error).message);\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <Modal\n open={item !== null}\n onClose={onClose}\n title={candidateName ?? item?.name ?? ''}\n size=\"small\"\n >\n <div className=\"flex flex-col gap-4\">\n {!candidateName && <p className=\"m-0 opacity-80\">{item?.description}</p>}\n <div>\n <Select\n size=\"small\"\n value={subject}\n onChange={setSubject}\n disabled={loading || !subjectsAvailable}\n options={[\n { value: NO_SUBJECT, label: 'No subject' },\n ...(!subjectsAvailable && subject !== NO_SUBJECT\n ? [{ value: subject, label: subject }]\n : []),\n ...subjects.map((s) => ({ value: s, label: s })),\n ]}\n />\n </div>\n {error && <p className=\"m-0 text-watercolor-rose-dark text-sm\">{error}</p>}\n <div className=\"flex justify-end gap-2\">\n <Button type=\"button\" variant=\"ghost\" onClick={onClose} disabled={loading}>\n Cancel\n </Button>\n <Button type=\"button\" variant=\"primary\" onClick={handlePromote} disabled={loading}>\n {loading ? 'Promoting…' : 'Promote to idea'}\n </Button>\n </div>\n </div>\n </Modal>\n );\n};\n","import { Markdown } from '@/app/components/markdown';\nimport { PageTitle } from '@/app/components/page-title';\nimport { PrBadge } from '@/app/features/plans/components/pr-badge';\nimport { STATUS_LABEL, STATUS_STAMP } from '@/app/features/plans/constants';\nimport { addRoadmapCandidate, addRoadmapItem, fetchRoadmap } from '@/app/services/content/docs-api';\nimport { useAppStore } from '@/app/stores/app-store';\nimport type {\n PlanEntry,\n ResolvedRoadmap,\n ResolvedRoadmapItem,\n RoadmapEvent,\n RoadmapEventKind,\n RoadmapLink,\n} from '@/types/index';\nimport { Button, Card, Input, Stamp, Tooltip } from '@dendelion/paper-ui';\nimport { useNavigate, useSearch } from '@tanstack/react-router';\nimport { useEffect, useRef, useState } from 'react';\nimport { PromoteRoadmapItemModal } from './promote-roadmap-item-modal';\n\nconst graduationCounts = (graduated: PlanEntry[]) => ({\n shipped: graduated.filter((p) => p.status === 'done').length,\n queued: graduated.filter((p) => p.status !== 'done' && p.status !== 'dropped').length,\n});\n\nconst HORIZON_HEADER_CLASSES =\n 'font-handwritten text-md font-semibold opacity-70 leading-none pt-2 px-1 pb-0';\n\nconst HORIZON_PULSE_CLASSES = 'text-2xs font-normal px-1 py-0 opacity-50';\n\nconst ChevronRightIcon = ({ size = 14 }: { size?: number }) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <polyline points=\"9 18 15 12 9 6\" />\n </svg>\n);\n\nconst CandidateRow = ({\n name,\n onPromote,\n}: {\n name: string;\n onPromote: () => void;\n}) => (\n <Card size=\"small\" texture=\"kraft\" className=\"plan-row-card\">\n <div className=\"flex items-center gap-3\">\n <span className=\"flex-1\">{name}</span>\n <Button type=\"button\" variant=\"ghost\" size=\"small\" onClick={onPromote}>\n Promote to idea\n </Button>\n </div>\n </Card>\n);\n\nconst AddCandidateForm = ({ onAdd }: { onAdd: (name: string) => Promise<void> }) => {\n const [name, setName] = useState('');\n const [saving, setSaving] = useState(false);\n\n const handleAdd = async () => {\n if (!name.trim()) return;\n setSaving(true);\n try {\n await onAdd(name.trim());\n setName('');\n } finally {\n setSaving(false);\n }\n };\n\n return (\n <div className=\"flex gap-2\">\n <Input\n size=\"small\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') handleAdd();\n }}\n placeholder=\"Add option…\"\n disabled={saving}\n className=\"flex-1\"\n />\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"small\"\n onClick={handleAdd}\n disabled={saving || !name.trim()}\n >\n Add\n </Button>\n </div>\n );\n};\n\nconst AddItemForm = ({\n onAdd,\n}: {\n onAdd: (name: string, description: string) => Promise<void>;\n}) => {\n const [open, setOpen] = useState(false);\n const [name, setName] = useState('');\n const [description, setDescription] = useState('');\n const [saving, setSaving] = useState(false);\n\n const handleAdd = async () => {\n if (!name.trim()) return;\n setSaving(true);\n try {\n await onAdd(name.trim(), description.trim());\n setName('');\n setDescription('');\n setOpen(false);\n } finally {\n setSaving(false);\n }\n };\n\n if (!open) {\n return (\n <Button type=\"button\" variant=\"ghost\" size=\"small\" onClick={() => setOpen(true)}>\n + Add item\n </Button>\n );\n }\n\n return (\n <div className=\"flex flex-col gap-2\">\n <Input\n size=\"small\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"Item name…\"\n disabled={saving}\n autoFocus\n />\n <Input\n size=\"small\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') handleAdd();\n }}\n placeholder=\"Description…\"\n disabled={saving}\n />\n <div className=\"flex justify-end gap-2\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"small\"\n onClick={() => setOpen(false)}\n disabled={saving}\n >\n Cancel\n </Button>\n <Button type=\"button\" size=\"small\" onClick={handleAdd} disabled={saving || !name.trim()}>\n Add\n </Button>\n </div>\n </div>\n );\n};\n\nconst plural = (count: number, noun: string) => `${count} ${noun}${count === 1 ? '' : 's'}`;\n\nconst RoadmapLinkTrail = ({ link }: { link: RoadmapLink }) => (\n <div className=\"flex items-center gap-1\">\n <Tooltip content={`${plural(link.taskRuns, 'task run')}${link.released ? ' · released' : ''}`}>\n <Stamp\n size=\"small\"\n fillColor={STATUS_STAMP[link.status].fill}\n textColor={STATUS_STAMP[link.status].text}\n >\n {link.id}\n </Stamp>\n </Tooltip>\n {link.pr && <PrBadge pr={link.pr} />}\n </div>\n);\n\nconst GraduatedRow = ({ plan, onOpen }: { plan: PlanEntry; onOpen: () => void }) => (\n <Card size=\"small\" texture=\"kraft\" className=\"plan-row-card\">\n <button\n type=\"button\"\n onClick={onOpen}\n className=\"flex items-center gap-3 w-full bg-transparent border-none p-0 cursor-pointer [font:inherit] text-inherit text-left\"\n >\n <span className=\"flex-1 overflow-hidden text-ellipsis whitespace-nowrap\">{plan.title}</span>\n <Stamp\n size=\"small\"\n fillColor={STATUS_STAMP[plan.status].fill}\n textColor={STATUS_STAMP[plan.status].text}\n >\n {STATUS_LABEL[plan.status]}\n </Stamp>\n </button>\n </Card>\n);\n\nconst RoadmapItemRow = ({\n item,\n graduated,\n highlighted,\n onPromote,\n onPromoteCandidate,\n onAddCandidate,\n onViewGraduated,\n onOpenGraduated,\n}: {\n item: ResolvedRoadmapItem;\n graduated: PlanEntry[];\n highlighted: boolean;\n onPromote: () => void;\n onPromoteCandidate: (candidateName: string) => void;\n onAddCandidate: (name: string) => Promise<void>;\n onViewGraduated: () => void;\n onOpenGraduated: (title: string) => void;\n}) => {\n const [expanded, setExpanded] = useState(highlighted);\n const hasCandidates = item.candidates.length > 0;\n const { shipped, queued } = graduationCounts(graduated);\n\n return (\n <div\n className={`flex flex-col gap-1 ${highlighted ? 'roadmap-item-highlighted outline outline-2 outline-offset-[-2px] outline-[rgba(200,154,90,0.5)]' : ''}`}\n >\n <Card size=\"small\" texture=\"canvas\" className=\"plan-row-card\">\n <div className=\"flex flex-col gap-1\">\n <div className=\"flex items-center gap-2\">\n {/* Raw <button>: icon-only toggle, paper-ui Button doesn't offer this compact chrome. */}\n <button\n type=\"button\"\n aria-expanded={expanded}\n aria-label={expanded ? 'Collapse item' : 'Expand item'}\n onClick={() => setExpanded((v) => !v)}\n className={`inline-flex items-center bg-transparent border-none cursor-pointer opacity-50 p-0 ${expanded ? 'rotate-90' : ''}`}\n >\n <ChevronRightIcon />\n </button>\n <span className=\"font-semibold flex-1\">{item.name}</span>\n <Button type=\"button\" variant=\"ghost\" size=\"small\" onClick={onPromote}>\n Promote to idea\n </Button>\n </div>\n <span className={`text-sm opacity-70 ${expanded ? '' : 'line-clamp-2'}`}>\n {item.description}\n </span>\n <div className=\"flex items-center gap-1\">\n {(queued > 0 || shipped > 0) && (\n <button\n type=\"button\"\n onClick={onViewGraduated}\n className=\"flex items-center gap-1 bg-transparent border-none p-0 cursor-pointer\"\n >\n {queued > 0 && (\n <Stamp\n size=\"small\"\n fillColor={STATUS_STAMP.planned.fill}\n textColor={STATUS_STAMP.planned.text}\n >\n {queued} in queue\n </Stamp>\n )}\n {shipped > 0 && (\n <Stamp\n size=\"small\"\n fillColor={STATUS_STAMP.done.fill}\n textColor={STATUS_STAMP.done.text}\n >\n {shipped} shipped\n </Stamp>\n )}\n </button>\n )}\n {hasCandidates && (\n <Stamp size=\"small\" fillColor=\"rgba(0, 0, 0, 0.06)\" textColor=\"rgba(0, 0, 0, 0.55)\">\n {item.candidates.length} candidate{item.candidates.length === 1 ? '' : 's'}\n </Stamp>\n )}\n {item.rollup.total > 0 && (\n <Stamp\n size=\"small\"\n fillColor={STATUS_STAMP.planned.fill}\n textColor={STATUS_STAMP.planned.text}\n >\n {item.rollup.done}/{item.rollup.total} done\n </Stamp>\n )}\n </div>\n {item.links.length > 0 && (\n <div className=\"flex items-center gap-1 flex-wrap\">\n {item.links.map((link) => (\n <RoadmapLinkTrail key={link.id} link={link} />\n ))}\n </div>\n )}\n </div>\n </Card>\n {expanded && (\n <div className=\"flex flex-col gap-1 pl-6\">\n {item.candidates.map((candidateName) => (\n <CandidateRow\n key={candidateName}\n name={candidateName}\n onPromote={() => onPromoteCandidate(candidateName)}\n />\n ))}\n {graduated.map((plan) => (\n <GraduatedRow key={plan.title} plan={plan} onOpen={() => onOpenGraduated(plan.title)} />\n ))}\n <AddCandidateForm onAdd={onAddCandidate} />\n </div>\n )}\n </div>\n );\n};\n\nconst GoalBanner = ({ goal }: { goal: string }) => {\n const [expanded, setExpanded] = useState(false);\n const [firstParagraph, ...restParagraphs] = goal.split(/\\n{2,}/);\n const hasMore = restParagraphs.length > 0;\n\n return (\n <div className=\"mb-6 pb-4 border-b border-black/[8%]\">\n <span className=\"font-handwritten text-xs font-semibold opacity-[0.55]\">The goal</span>\n <div className=\"font-display-luminari text-lg leading-[1.4] mt-2\">\n <div className={expanded ? undefined : 'line-clamp-1'}>\n <Markdown>{firstParagraph}</Markdown>\n </div>\n {expanded && hasMore && <Markdown>{restParagraphs.join('\\n\\n')}</Markdown>}\n </div>\n {hasMore && (\n <button\n type=\"button\"\n onClick={() => setExpanded((v) => !v)}\n className=\"bg-transparent border-none p-0 mt-2 cursor-pointer text-2xs opacity-[0.65] underline\"\n >\n {expanded ? 'Show less' : 'Show more'}\n </button>\n )}\n </div>\n );\n};\n\ntype RoadmapViewMode = 'tree' | 'map' | 'timeline';\n\nconst VIEW_MODES: { id: RoadmapViewMode; label: string }[] = [\n { id: 'tree', label: 'Outline' },\n { id: 'map', label: 'Board' },\n { id: 'timeline', label: 'Timeline' },\n];\n\nconst RoadmapViewModeSwitch = ({\n mode,\n onChange,\n}: {\n mode: RoadmapViewMode;\n onChange: (mode: RoadmapViewMode) => void;\n}) => (\n <nav aria-label=\"Roadmap view\" className=\"flex gap-1 mb-4\">\n {VIEW_MODES.map((viewMode) => (\n <Button\n key={viewMode.id}\n type=\"button\"\n variant=\"ghost\"\n size=\"small\"\n isActive={mode === viewMode.id}\n aria-pressed={mode === viewMode.id}\n onClick={() => onChange(viewMode.id)}\n >\n {viewMode.label}\n </Button>\n ))}\n </nav>\n);\n\nconst HorizonPulse = ({\n items,\n graduatedByItem,\n}: {\n items: ResolvedRoadmapItem[];\n graduatedByItem: (item: ResolvedRoadmapItem) => PlanEntry[];\n}) => {\n const graduated = items.filter((item) => graduatedByItem(item).length > 0).length;\n const charted = items.length - graduated;\n return (\n <div className={HORIZON_PULSE_CLASSES}>\n {graduated} graduated · {charted} charted\n </div>\n );\n};\n\nconst EVENT_KIND_COLOR: Record<RoadmapEventKind, string> = {\n created: 'bg-watercolor-slate',\n 'task-run': 'bg-watercolor-amber',\n};\n\nconst RoadmapTimelineTrack = ({\n events,\n rangeStart,\n rangeEnd,\n}: {\n events: RoadmapEvent[];\n rangeStart: number;\n rangeEnd: number;\n}) => {\n const span = rangeEnd - rangeStart || 1;\n return (\n <div className=\"relative h-8 mx-1 border-b border-black/10\">\n {events.map((event, i) => (\n <button\n type=\"button\"\n key={`${event.entityId}-${event.kind}-${i}`}\n className={`absolute top-1/2 w-2.5 h-2.5 p-0 border-none rounded-full -translate-x-1/2 -translate-y-1/2 cursor-pointer ${EVENT_KIND_COLOR[event.kind]}`}\n style={{\n left: `${((Date.parse(event.date) - rangeStart) / span) * 100}%`,\n }}\n title={`${event.itemName} — ${event.label} (${event.date})`}\n aria-label={`${event.itemName} — ${event.label} (${event.date})`}\n />\n ))}\n </div>\n );\n};\n\nconst RoadmapMapItem = ({ item }: { item: ResolvedRoadmapItem }) => {\n const percent =\n item.rollup.total > 0 ? Math.round((item.rollup.done / item.rollup.total) * 100) : 0;\n return (\n <div className=\"flex flex-col gap-1 py-2 px-2.5\">\n <div className=\"font-semibold text-sm\">{item.name}</div>\n <div className=\"h-1.5 rounded-full bg-black/[0.08] overflow-hidden\">\n <div\n className={`h-full rounded-full ${item.rollup.total > 0 ? 'bg-watercolor-green' : 'bg-transparent'}`}\n style={{\n width: `${percent}%`,\n }}\n />\n </div>\n <div className=\"text-2xs opacity-50\">\n {item.rollup.total > 0 ? `${item.rollup.done}/${item.rollup.total} done` : 'not started'}\n </div>\n </div>\n );\n};\n\nconst RoadmapMap = ({\n roadmap,\n graduatedByItem,\n}: {\n roadmap: ResolvedRoadmap;\n graduatedByItem: (item: ResolvedRoadmapItem) => PlanEntry[];\n}) => (\n <div className=\"flex flex-col gap-6\">\n {roadmap.horizons.map((horizon) => (\n <div key={horizon.title} className=\"flex flex-col gap-1\">\n <div className=\"flex items-baseline gap-2\">\n <div className={HORIZON_HEADER_CLASSES}>{horizon.title}</div>\n <HorizonPulse items={horizon.items} graduatedByItem={graduatedByItem} />\n </div>\n <div className=\"flex flex-wrap items-start gap-2.5\">\n {horizon.items.map((item) => (\n <div\n key={item.name}\n className=\"flex-[1_1_240px] max-w-[320px] max-[480px]:flex-[1_1_100%] max-[480px]:max-w-none\"\n >\n <RoadmapMapItem item={item} />\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n);\n\nconst RoadmapTimeline = ({ roadmap }: { roadmap: ResolvedRoadmap }) => {\n if (roadmap.events.length === 0) {\n return <p className=\"opacity-50\">No dated events yet.</p>;\n }\n\n const dates = roadmap.events.map((event) => Date.parse(event.date));\n const rangeStart = Math.min(...dates);\n const rangeEnd = Math.max(...dates);\n\n return (\n <div className=\"flex flex-col gap-6\">\n {roadmap.horizons.map((horizon) => {\n const events = roadmap.events.filter((event) => event.horizonTitle === horizon.title);\n return (\n <div key={horizon.title} className=\"flex flex-col gap-1\">\n <div className={HORIZON_HEADER_CLASSES}>{horizon.title}</div>\n {events.length === 0 ? (\n <div className=\"text-2xs font-normal px-1 py-0 opacity-40\">No events yet</div>\n ) : (\n <RoadmapTimelineTrack events={events} rangeStart={rangeStart} rangeEnd={rangeEnd} />\n )}\n </div>\n );\n })}\n <div className=\"flex justify-between text-2xs opacity-50\">\n <span>{new Date(rangeStart).toLocaleDateString()}</span>\n <span>{new Date(rangeEnd).toLocaleDateString()}</span>\n </div>\n </div>\n );\n};\n\nexport const RoadmapPage = () => {\n const [roadmap, setRoadmap] = useState<ResolvedRoadmap | null>(null);\n const [loading, setLoading] = useState(true);\n const [loadFailed, setLoadFailed] = useState(false);\n const [promoting, setPromoting] = useState<{\n horizonTitle: string;\n item: ResolvedRoadmapItem;\n candidateName?: string;\n } | null>(null);\n const [viewMode, setViewMode] = useState<RoadmapViewMode>('tree');\n const plans = useAppStore((s) => s.plans);\n const navigate = useNavigate();\n const { item: highlightedItem } = useSearch({ from: '/roadmap' });\n const containerRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n fetchRoadmap()\n .then(setRoadmap)\n .catch(() => setLoadFailed(true))\n .finally(() => setLoading(false));\n }, []);\n\n useEffect(() => {\n if (!highlightedItem || loading) return;\n const row = containerRef.current?.querySelector('.roadmap-item-highlighted');\n row?.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }, [highlightedItem, loading]);\n\n if (loading) {\n return (\n <div>\n <PageTitle>Roadmap</PageTitle>\n <p className=\"opacity-50\">Loading…</p>\n </div>\n );\n }\n\n if (loadFailed) {\n return (\n <div>\n <PageTitle>Roadmap</PageTitle>\n <p className=\"opacity-50\">\n Couldn't load the roadmap — the server may need a restart to pick up new routes.\n </p>\n </div>\n );\n }\n\n if (!roadmap || roadmap.horizons.length === 0) {\n return (\n <div>\n <PageTitle>Roadmap</PageTitle>\n <p className=\"opacity-50\">No `ROADMAP.md` found at the project root.</p>\n </div>\n );\n }\n\n const graduatedByItem = (item: ResolvedRoadmapItem) =>\n plans?.entries.filter((p) => p.subject === item.name) ?? [];\n\n const handleAddItem = async (horizonTitle: string, name: string, description: string) => {\n await addRoadmapItem(horizonTitle, name, description);\n setRoadmap(await fetchRoadmap());\n };\n\n const handleAddCandidate = async (horizonTitle: string, itemName: string, name: string) => {\n await addRoadmapCandidate(horizonTitle, itemName, name);\n setRoadmap(await fetchRoadmap());\n };\n\n return (\n <div ref={containerRef}>\n <GoalBanner goal={roadmap.goal} />\n <RoadmapViewModeSwitch mode={viewMode} onChange={setViewMode} />\n {viewMode === 'tree' && (\n <div className=\"flex flex-col gap-6\">\n {roadmap.horizons.map((horizon) => (\n <div key={horizon.title} className=\"flex flex-col gap-1\">\n <div className=\"flex items-baseline gap-2\">\n <div className={HORIZON_HEADER_CLASSES}>{horizon.title}</div>\n <HorizonPulse items={horizon.items} graduatedByItem={graduatedByItem} />\n </div>\n <div className=\"flex flex-wrap items-start gap-2.5\">\n {horizon.items.map((item) => (\n <div\n key={item.name}\n className=\"flex-[1_1_240px] max-w-[320px] max-[480px]:flex-[1_1_100%] max-[480px]:max-w-none\"\n >\n <RoadmapItemRow\n item={item}\n graduated={graduatedByItem(item)}\n highlighted={item.name === highlightedItem}\n onPromote={() => setPromoting({ horizonTitle: horizon.title, item })}\n onPromoteCandidate={(candidateName) =>\n setPromoting({ horizonTitle: horizon.title, item, candidateName })\n }\n onAddCandidate={(name) => handleAddCandidate(horizon.title, item.name, name)}\n onViewGraduated={() => navigate({ to: '/', search: { subject: item.name } })}\n onOpenGraduated={(title) =>\n navigate({\n to: '/plans/$planId',\n params: { planId: encodeURIComponent(title) },\n })\n }\n />\n </div>\n ))}\n <div className=\"flex-[1_1_240px] max-w-[320px] max-[480px]:flex-[1_1_100%] max-[480px]:max-w-none\">\n <AddItemForm\n onAdd={(name, description) => handleAddItem(horizon.title, name, description)}\n />\n </div>\n </div>\n </div>\n ))}\n </div>\n )}\n {viewMode === 'map' && <RoadmapMap roadmap={roadmap} graduatedByItem={graduatedByItem} />}\n {viewMode === 'timeline' && <RoadmapTimeline roadmap={roadmap} />}\n <PromoteRoadmapItemModal\n horizonTitle={promoting?.horizonTitle ?? null}\n item={promoting?.item ?? null}\n candidateName={promoting?.candidateName}\n onClose={() => setPromoting(null)}\n onPromoted={() => fetchRoadmap().then(setRoadmap)}\n />\n </div>\n );\n};\n"],"names":["NO_SUBJECT","PromoteRoadmapItemModal","horizonTitle","item","candidateName","onClose","onPromoted","promoteRoadmapItem","useAppStore","s","launchIdeaExtend","subjects","subjectsAvailable","useSubjectVocabulary","subject","setSubject","useState","loading","setLoading","error","setError","toast","useToast","useEffect","handlePromote","id","idea","e","buildRoadmapPromotePrompt","err","oneLineErrorSummary","jsx","Modal","jsxs","Select","Button","graduationCounts","graduated","p","HORIZON_HEADER_CLASSES","HORIZON_PULSE_CLASSES","ChevronRightIcon","size","CandidateRow","name","onPromote","Card","AddCandidateForm","onAdd","setName","saving","setSaving","handleAdd","Input","AddItemForm","open","setOpen","description","setDescription","plural","count","noun","RoadmapLinkTrail","link","Tooltip","Stamp","STATUS_STAMP","PrBadge","GraduatedRow","plan","onOpen","STATUS_LABEL","RoadmapItemRow","highlighted","onPromoteCandidate","onAddCandidate","onViewGraduated","onOpenGraduated","expanded","setExpanded","hasCandidates","shipped","queued","v","GoalBanner","goal","firstParagraph","restParagraphs","hasMore","Markdown","VIEW_MODES","RoadmapViewModeSwitch","mode","onChange","viewMode","HorizonPulse","items","graduatedByItem","charted","EVENT_KIND_COLOR","RoadmapTimelineTrack","events","rangeStart","rangeEnd","span","event","i","RoadmapMapItem","percent","RoadmapMap","roadmap","horizon","RoadmapTimeline","dates","RoadmapPage","setRoadmap","loadFailed","setLoadFailed","promoting","setPromoting","setViewMode","plans","navigate","useNavigate","highlightedItem","useSearch","containerRef","useRef","fetchRoadmap","row","_a","PageTitle","handleAddItem","addRoadmapItem","handleAddCandidate","itemName","addRoadmapCandidate","title"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{k as N,r as h,W as k,j as e,X as g,Y as v,Z as I,_ as w,J as P,u as p,a as C,P as E}from"./main-BW24wv9K.js";const j=n=>Number.isFinite(n)?n<=0?"today":n===1?"1 day ago":`${n} days ago`:"age unknown",T=({question:n,plan:x,expanded:a,onToggle:u,onOpen:t,reload:y})=>{const{toast:l}=N(),[i,m]=h.useState(""),{sending:o,send:s,undo:d,undoing:r,undoEdit:b}=k(x,{reload:y,notify:l}),c=async()=>{i.trim()&&await s(i.trim())&&m("")};return e.jsxs("div",{className:"border-b border-black/10 last:border-b-0",children:[e.jsxs("div",{className:"flex items-center gap-3 py-2.5",children:[e.jsx("button",{type:"button",onClick:t,"aria-label":`Open ${n.entityTitle}`,className:"bg-transparent border-none p-0 cursor-pointer",children:e.jsx(g,{id:n.entityId})}),e.jsx("button",{type:"button",onClick:u,"aria-expanded":a,className:"flex-1 min-w-0 truncate text-left bg-transparent border-none p-0 cursor-pointer",children:n.text}),e.jsx("span",{className:"opacity-50 text-xs whitespace-nowrap",children:j(n.ageDays)})]}),a&&e.jsxs("div",{className:"flex flex-col gap-3 pb-4",children:[e.jsx(v,{messages:x.thread??[],undo:d,undoing:r,onUndo:b}),e.jsx(I,{value:i,onChange:f=>m(f.target.value),"aria-label":`Reply to ${n.entityTitle}`,placeholder:"Reply to resolve and resume…",rows:2,disabled:o}),e.jsxs("div",{className:"flex justify-end items-center gap-3",children:[e.jsx("span",{className:o?"visible":"invisible",children:e.jsx(w,{size:"small",label:"Agent replying…"})}),e.jsx(P,{size:"small",onClick:c,disabled:o||!i.trim(),children:"Reply"})]})]})]})},R=()=>{const[n,x]=h.useState(null),a=p(s=>s.parkedQuestions),u=p(s=>s.parkedQuestionsError!==null),t=p(s=>s.plans),y=p(s=>s.loadPlans),l=p(s=>s.loadParkedQuestions),i=C();h.useEffect(()=>{l()},[l]);const m=async()=>{await Promise.all([y(),l()])},o=s=>{t!=null&&t.entries.some(d=>d.title===s)?i({to:"/plans/$planId",params:{planId:encodeURIComponent(s)}}):i({to:"/ideas/$ideaId",params:{ideaId:encodeURIComponent(s)}})};return e.jsxs("div",{children:[e.jsx(E,{children:"Inbox"}),e.jsx("p",{className:"opacity-50 mb-6",children:"Every open agent question, oldest first — parked decisions waiting on a human."}),u&&e.jsx("p",{className:"opacity-50",children:"Couldn't load parked questions."}),!u&&!a&&e.jsx("p",{className:"opacity-50",children:"Loading…"}),a&&a.length===0&&e.jsx("p",{className:"opacity-50",children:"Nothing parked — every agent question has an answer."}),a&&a.length>0&&e.jsx("div",{className:"flex flex-col",children:a.map((s,d)=>{const r=`${s.entityId}-${d}`,b=t==null?void 0:t.entries.find(c=>c.id===s.entityId);return b?e.jsx(T,{question:s,plan:b,expanded:n===r,onToggle:()=>x(c=>c===r?null:r),onOpen:()=>o(s.entityTitle),reload:m},r):e.jsxs("div",{className:"flex items-center gap-3 py-2.5 border-b border-black/10 last:border-b-0",children:[e.jsx("button",{type:"button",onClick:()=>o(s.entityTitle),"aria-label":`Open ${s.entityTitle}`,className:"bg-transparent border-none p-0 cursor-pointer",children:e.jsx(g,{id:s.entityId})}),e.jsx("span",{className:"flex-1 min-w-0 truncate",children:s.text}),e.jsx("span",{className:"opacity-50 text-xs whitespace-nowrap",children:j(s.ageDays)})]},r)})})]})};export{R as InboxPage};
2
+ //# sourceMappingURL=index-Bo0V9-3F.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-Bo0V9-3F.js","sources":["../../../src/app/features/inbox/helpers.ts","../../../src/app/features/inbox/question-row.tsx","../../../src/app/features/inbox/inbox-page.tsx"],"sourcesContent":["export const formatAge = (ageDays: number): string => {\n if (!Number.isFinite(ageDays)) return 'age unknown';\n if (ageDays <= 0) return 'today';\n return ageDays === 1 ? '1 day ago' : `${ageDays} days ago`;\n};\n","import { FeedbackThread, PlanIdStamp } from '@/app/features/plans/components';\nimport { useSendFeedbackMessage } from '@/app/features/plans/hooks';\nimport type { ParkedQuestion, PlanEntry } from '@/types/index';\nimport { Button, Spinner, Textarea, useToast } from '@dendelion/paper-ui';\nimport { useState } from 'react';\nimport { formatAge } from './helpers';\n\ninterface QuestionRowProps {\n question: ParkedQuestion;\n plan: PlanEntry;\n expanded: boolean;\n onToggle: () => void;\n onOpen: () => void;\n reload: () => Promise<void>;\n}\n\nexport const QuestionRow = ({\n question,\n plan,\n expanded,\n onToggle,\n onOpen,\n reload,\n}: QuestionRowProps) => {\n const { toast } = useToast();\n const [input, setInput] = useState('');\n const { sending, send, undo, undoing, undoEdit } = useSendFeedbackMessage(plan, {\n reload,\n notify: toast,\n });\n\n const handleSend = async () => {\n if (!input.trim()) return;\n if (await send(input.trim())) setInput('');\n };\n\n return (\n <div className=\"border-b border-black/10 last:border-b-0\">\n <div className=\"flex items-center gap-3 py-2.5\">\n <button\n type=\"button\"\n onClick={onOpen}\n aria-label={`Open ${question.entityTitle}`}\n className=\"bg-transparent border-none p-0 cursor-pointer\"\n >\n <PlanIdStamp id={question.entityId} />\n </button>\n <button\n type=\"button\"\n onClick={onToggle}\n aria-expanded={expanded}\n className=\"flex-1 min-w-0 truncate text-left bg-transparent border-none p-0 cursor-pointer\"\n >\n {question.text}\n </button>\n <span className=\"opacity-50 text-xs whitespace-nowrap\">{formatAge(question.ageDays)}</span>\n </div>\n {expanded && (\n <div className=\"flex flex-col gap-3 pb-4\">\n <FeedbackThread\n messages={plan.thread ?? []}\n undo={undo}\n undoing={undoing}\n onUndo={undoEdit}\n />\n <Textarea\n value={input}\n onChange={(e) => setInput(e.target.value)}\n aria-label={`Reply to ${question.entityTitle}`}\n placeholder=\"Reply to resolve and resume…\"\n rows={2}\n disabled={sending}\n />\n <div className=\"flex justify-end items-center gap-3\">\n <span className={sending ? 'visible' : 'invisible'}>\n <Spinner size=\"small\" label=\"Agent replying…\" />\n </span>\n <Button size=\"small\" onClick={handleSend} disabled={sending || !input.trim()}>\n Reply\n </Button>\n </div>\n </div>\n )}\n </div>\n );\n};\n","import { PageTitle } from '@/app/components/page-title';\nimport { PlanIdStamp } from '@/app/features/plans/components';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { useNavigate } from '@tanstack/react-router';\nimport { useEffect, useState } from 'react';\nimport { formatAge } from './helpers';\nimport { QuestionRow } from './question-row';\n\nexport const InboxPage = () => {\n const [expandedKey, setExpandedKey] = useState<string | null>(null);\n const questions = useAppStore((s) => s.parkedQuestions);\n const loadFailed = useAppStore((s) => s.parkedQuestionsError !== null);\n const plans = useAppStore((s) => s.plans);\n const loadPlans = useAppStore((s) => s.loadPlans);\n const loadParkedQuestions = useAppStore((s) => s.loadParkedQuestions);\n const navigate = useNavigate();\n\n useEffect(() => {\n loadParkedQuestions();\n }, [loadParkedQuestions]);\n\n const reload = async () => {\n await Promise.all([loadPlans(), loadParkedQuestions()]);\n };\n\n const openEntity = (title: string) => {\n if (plans?.entries.some((p) => p.title === title)) {\n navigate({ to: '/plans/$planId', params: { planId: encodeURIComponent(title) } });\n } else {\n navigate({ to: '/ideas/$ideaId', params: { ideaId: encodeURIComponent(title) } });\n }\n };\n\n return (\n <div>\n <PageTitle>Inbox</PageTitle>\n <p className=\"opacity-50 mb-6\">\n Every open agent question, oldest first — parked decisions waiting on a human.\n </p>\n {loadFailed && <p className=\"opacity-50\">Couldn't load parked questions.</p>}\n {!loadFailed && !questions && <p className=\"opacity-50\">Loading…</p>}\n {questions && questions.length === 0 && (\n <p className=\"opacity-50\">Nothing parked — every agent question has an answer.</p>\n )}\n {questions && questions.length > 0 && (\n <div className=\"flex flex-col\">\n {questions.map((q, i) => {\n const key = `${q.entityId}-${i}`;\n const plan = plans?.entries.find((p) => p.id === q.entityId);\n if (!plan) {\n return (\n <div\n key={key}\n className=\"flex items-center gap-3 py-2.5 border-b border-black/10 last:border-b-0\"\n >\n <button\n type=\"button\"\n onClick={() => openEntity(q.entityTitle)}\n aria-label={`Open ${q.entityTitle}`}\n className=\"bg-transparent border-none p-0 cursor-pointer\"\n >\n <PlanIdStamp id={q.entityId} />\n </button>\n <span className=\"flex-1 min-w-0 truncate\">{q.text}</span>\n <span className=\"opacity-50 text-xs whitespace-nowrap\">\n {formatAge(q.ageDays)}\n </span>\n </div>\n );\n }\n return (\n <QuestionRow\n key={key}\n question={q}\n plan={plan}\n expanded={expandedKey === key}\n onToggle={() => setExpandedKey((cur) => (cur === key ? null : key))}\n onOpen={() => openEntity(q.entityTitle)}\n reload={reload}\n />\n );\n })}\n </div>\n )}\n </div>\n );\n};\n"],"names":["formatAge","ageDays","QuestionRow","question","plan","expanded","onToggle","onOpen","reload","toast","useToast","input","setInput","useState","sending","send","undo","undoing","undoEdit","useSendFeedbackMessage","handleSend","jsxs","jsx","PlanIdStamp","FeedbackThread","Textarea","e","Spinner","Button","InboxPage","expandedKey","setExpandedKey","questions","useAppStore","loadFailed","plans","loadPlans","loadParkedQuestions","navigate","useNavigate","useEffect","openEntity","title","p","PageTitle","q","i","key","cur"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{r as d,k as _,j as e,l as M,U as P,w as F,J as f,p as v,c as V,e as K,g as se,h as te,s as D,u as T,V as X,m as ae,a as Q,n as Z,P as ne,q as le,o as G,D as z,t as ie,A as O,v as q,x as oe,z as re,i as L}from"./main-BW24wv9K.js";import{c as ce}from"./tokens-C3C44lLs.js";import{S as W}from"./sidebar-section-BHLbvk_X.js";const de=async()=>{try{const s=await fetch("/api/merge-policy");return s.ok?await s.json():null}catch{return null}},me=async()=>{try{const s=await fetch("/api/merge-policy/apply",{method:"POST"});return s.ok?await s.json():null}catch{return null}},ee={allowSquashMerge:!0,allowMergeCommit:!1,allowRebaseMerge:!1,squashMergeCommitTitle:"PR_TITLE",squashMergeCommitMessage:"PR_BODY"},B=[{key:"allowSquashMerge",label:"Allow squash merge"},{key:"allowMergeCommit",label:"Allow merge commit"},{key:"allowRebaseMerge",label:"Allow rebase merge"},{key:"squashMergeCommitTitle",label:"Squash commit title"},{key:"squashMergeCommitMessage",label:"Squash commit message"}];function $(s){return typeof s=="boolean"?s?"Yes":"No":s}function pe(s){return B.every(t=>s[t.key]===ee[t.key])}const he=({label:s,current:t,recommended:r,isLast:l})=>{const p=t===r;return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex items-center gap-3 pb-2 pt-2",children:[e.jsx("span",{className:"flex-1",children:s}),e.jsx("span",{className:p?"opacity-[0.65] font-normal":"font-semibold",children:$(t)}),!p&&e.jsxs("span",{className:"opacity-[0.45]",children:["→ ",$(r)]})]}),!l&&e.jsx(v,{})]})},ue=()=>{const[s,t]=d.useState(void 0),[r,l]=d.useState(!1),{toast:p}=_();d.useEffect(()=>{de().then(t)},[]);const u=async()=>{l(!0);const n=await me();l(!1),(n==null?void 0:n.status)==="ok"?(t(n),p({title:"Merge policy applied",variant:"success"})):p({title:"Failed to apply merge policy",description:(n==null?void 0:n.status)==="unavailable"?n.reason:void 0,variant:"error"})},h=(s==null?void 0:s.status)==="ok"&&pe(s.policy);return e.jsxs("div",{children:[e.jsxs("div",{className:"mb-6",children:[e.jsx("h2",{className:"m-0",children:"Merge Policy"}),e.jsx("p",{className:"opacity-50 mt-1",children:"Paper Camp's canonical policy: squash-only merges, with the commit title and body taken from the PR."})]}),s===void 0&&e.jsx("p",{children:"Loading…"}),s===null&&e.jsx(M,{variant:"warning",children:"Failed to load merge policy."}),(s==null?void 0:s.status)==="unavailable"&&e.jsx(M,{variant:"warning",children:s.reason}),(s==null?void 0:s.status)==="ok"&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex items-center gap-3 mb-3",children:[e.jsx("span",{className:"font-medium",children:s.repo}),e.jsx(P,{size:"small",fillColor:h?"rgba(143, 185, 150, 0.25)":"rgba(212, 163, 115, 0.25)",textColor:h?"#5E8A66":"#A67B4F",children:h?"Matches recommended policy":"Differs from recommended policy"})]}),e.jsx(F,{size:"small",texture:"kraft",children:B.map((n,c)=>e.jsx(he,{label:n.label,current:s.policy[n.key],recommended:ee[n.key],isLast:c===B.length-1},n.key))}),e.jsx("div",{className:"mt-4",children:e.jsx(f,{size:"small",onClick:u,disabled:r||h,children:r?"Applying…":"Apply recommended policy"})})]})]})},xe=2e3,je="agent:claude-code",ge=["claude auth login","claude setup-token"],fe=()=>e.jsxs("div",{className:"mt-2 flex flex-col gap-2",children:[e.jsx("p",{className:"opacity-[0.65] text-sm m-0",children:"The in-app relay couldn't complete. Run one of these in a terminal instead:"}),ge.map(s=>e.jsx(X,{code:s},s)),e.jsxs("p",{className:"opacity-50 text-sm m-0",children:["Alternatively, set ",e.jsx("code",{children:"ANTHROPIC_API_KEY"})," in the server's environment — that bills as API usage rather than your Max subscription, so treat it as a fallback, not the default."]})]}),be=({onSignedIn:s})=>{const t=T(c=>c.loginRelay),r=T(c=>c.startLoginRelay),l=T(c=>c.loadLoginRelayStatus),p=T(c=>c.cancelLoginRelay),{toast:u}=_(),h=d.useRef(null),n=t==null?void 0:t.phase;return d.useEffect(()=>{if(n!=="starting"&&n!=="awaiting-authorization")return;const c=window.setInterval(()=>l(),xe);return()=>window.clearInterval(c)},[n,l]),d.useEffect(()=>{const c=t==null?void 0:t.authorizeUrl;n!=="awaiting-authorization"||!c||h.current===c||(h.current=c,window.open(c,"_blank","noopener,noreferrer"))},[n,t==null?void 0:t.authorizeUrl]),d.useEffect(()=>{n==="success"?(u({title:"Signed in",variant:"success"}),s()):n==="error"&&u({title:"Sign-in failed",description:t==null?void 0:t.error,variant:"error"})},[n]),n==="starting"?e.jsx(f,{size:"small",disabled:!0,children:"Starting…"}):n==="awaiting-authorization"?e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(f,{size:"small",onClick:()=>(t==null?void 0:t.authorizeUrl)&&window.open(t.authorizeUrl,"_blank","noopener,noreferrer"),children:"Reopen sign-in tab"}),e.jsx(f,{size:"small",onClick:()=>p(),children:"Cancel"})]}):e.jsxs("div",{children:[e.jsx(f,{size:"small",onClick:()=>r(),children:"Sign in"}),n==="error"&&e.jsx(fe,{})]})},ve={ok:{fill:"rgba(143, 185, 150, 0.25)",text:"#5E8A66",label:"Ready"},warn:{fill:"rgba(212, 163, 115, 0.25)",text:"#A67B4F",label:"Needs attention"},missing:{fill:"rgba(201, 139, 139, 0.25)",text:"#6E3A3A",label:"Missing"}},ye=({connection:s,onConnect:t,connecting:r})=>{const{connect:l}=s;return l?l.kind==="command"&&l.runnable?e.jsx(f,{size:"small",onClick:()=>t(s.id),disabled:r,children:r?"Running…":`Run \`${l.command}\``}):l.kind==="command"?e.jsx("div",{className:"mt-2",children:e.jsx(X,{code:l.command})}):l.kind==="link"?e.jsx(f,{size:"small",onClick:()=>window.open(l.url,"_blank","noopener,noreferrer"),children:l.label}):e.jsx("p",{className:"opacity-[0.65] text-sm mt-2 mx-0 mb-0",children:l.message}):null},Ne=({connection:s,isLast:t,onRecheck:r,rechecking:l,onConnect:p,connecting:u})=>{const h=ve[s.status];return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"pb-3 pt-3",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{className:"flex-1 font-medium",children:s.label}),s.authenticated===!1&&e.jsx(se,{content:"Installed, but not signed in",children:e.jsx(P,{size:"small",variant:"warning",children:"Not signed in"})}),e.jsx(P,{size:"small",fillColor:h.fill,textColor:h.text,children:h.label}),e.jsx(f,{size:"small",onClick:()=>r(s.id),disabled:l,children:l?"Checking…":"Recheck"})]}),e.jsxs("p",{className:"opacity-[0.65] text-sm mt-1 mx-0 mb-0",children:["Unlocks: ",s.unlocks]}),e.jsx("p",{className:"opacity-50 text-sm mt-1 mx-0 mb-0",children:s.detail}),e.jsx("div",{className:"mt-2",children:s.id===je&&s.authenticated===!1?e.jsx(be,{onSignedIn:()=>r(s.id)}):e.jsx(ye,{connection:s,onConnect:p,connecting:u})})]}),!t&&e.jsx(v,{})]})},Se=()=>{const[s,t]=d.useState(null),[r,l]=d.useState(!1),[p,u]=d.useState(null),[h,n]=d.useState(null),[c,S]=d.useState(!1),{toast:y}=_(),N=d.useCallback(i=>{if(i===null){l(!0);return}l(!1),t(i)},[]);d.useEffect(()=>{V().then(N),K().then(i=>S((i==null?void 0:i.setupDismissed)??!1))},[N]);const A=async i=>{u(i),N(await V()),u(null)},m=async i=>{n(i);const b=await te(i);b?t(C=>(C==null?void 0:C.map(R=>R.id===i?b:R))??C):y({title:"Failed to connect",variant:"error"}),n(null)},x=async()=>{const i=!c,{ok:b}=await D({setupDismissed:i});b?(S(i),y({title:"Saved",variant:"success"})):y({title:"Failed to save",variant:"error"})},k=(s==null?void 0:s.every(i=>i.status==="ok"))??!0;return e.jsxs("div",{children:[e.jsx("div",{className:"mb-6",children:e.jsx("h2",{className:"m-0",children:"Setup"})}),s===null&&!r&&e.jsx("p",{children:"Loading…"}),r&&e.jsx("div",{className:"mb-4",children:e.jsx(M,{variant:"warning",children:"Failed to load connections. Try refreshing."})}),s&&e.jsxs(e.Fragment,{children:[!k&&e.jsx("div",{className:"mb-4",children:e.jsx(M,{variant:"warning",children:"Some connections are incomplete — features that depend on them stay disabled until fixed. Run the connect command below, then recheck."})}),e.jsx(F,{size:"small",texture:"kraft",children:s.map((i,b)=>e.jsx(Ne,{connection:i,isLast:b===s.length-1,onRecheck:A,rechecking:p===i.id,onConnect:m,connecting:h===i.id},i.id))}),e.jsx("div",{className:"mt-4",children:e.jsx(f,{size:"small",onClick:x,children:c?"Show Setup on open again":"Don't show Setup on open"})})]})]})},ke=()=>{const{subjects:s,loading:t,available:r}=ae(),l=Q();return e.jsxs("div",{children:[e.jsxs("div",{className:"mb-6",children:[e.jsx("h2",{className:"m-0",children:"Subjects"}),e.jsx("p",{className:"opacity-50 mt-1",children:"Subjects are the roadmap's bets and standing concerns. Edit the vocabulary on the Roadmap page."})]}),t&&e.jsx("p",{children:"Loading…"}),!t&&!r&&e.jsx("p",{className:"opacity-60 m-0",children:"Couldn't load subjects — check the server config."}),!t&&r&&e.jsxs(F,{size:"small",texture:"kraft",children:[s.length===0&&e.jsx("p",{className:"opacity-[0.45] m-0 pb-2",children:"No subjects yet."}),s.map((p,u)=>e.jsxs("div",{children:[e.jsx("div",{className:"pb-2 pt-2",children:p}),u<s.length-1&&e.jsx(v,{})]},p)),s.length>0&&e.jsx(v,{}),e.jsx("div",{className:"pt-3",children:e.jsx(f,{size:"small",onClick:()=>l({to:"/roadmap"}),children:"Go to Roadmap"})})]})]})},J=["phase","planDraft","ideaExtend","commitSuggest","feedback"],we={phase:"Phase run",planDraft:"Plan draft",ideaExtend:"Idea extend",commitSuggest:"Commit suggest",feedback:"Scout chat"},Ae=140,Ce=160,Ee=110,Ie=()=>e.jsxs("div",{className:"flex items-center gap-3 pb-1",children:[e.jsx("span",{className:"w-[110px] shrink-0 text-sm opacity-[0.45]",children:"Task"}),e.jsx("span",{className:"w-[140px] shrink-0 text-sm opacity-[0.45]",children:"Agent"}),e.jsx("span",{className:"w-[160px] shrink-0 text-sm opacity-[0.45]",children:"Model"}),e.jsx("span",{className:"w-[110px] shrink-0 text-sm opacity-[0.45]",children:"Effort"})]}),ze=({taskKey:s,agentConfig:t,isLast:r,onSave:l})=>{const p=O[t.agent]??O["claude-code"],u=p.model,h=p.effort,[n,c]=d.useState(t.model??"");d.useEffect(()=>{c(t.model??"")},[t.model]);const S=m=>{var b;const x=m,k=O[x],i={agent:x};t.model&&(k.model===null||(b=k.model)!=null&&b.includes(t.model))&&(i.model=t.model),t.effort&&Array.isArray(k.effort)&&(i.effort=t.effort),l(s,i)},y=m=>{l(s,{...t,model:m||void 0})},N=()=>{l(s,{...t,model:n||void 0})},A=m=>{l(s,{...t,effort:m||void 0})};return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex items-center gap-3 pb-2 pt-2",children:[e.jsx("span",{className:"w-[110px] shrink-0 text-sm opacity-[0.65]",children:we[s]}),e.jsx(q,{size:"small",width:Ae,value:t.agent,onChange:S,options:oe.map(m=>({value:m,label:re[m]}))}),Array.isArray(u)?e.jsx(q,{size:"small",width:Ce,value:t.model??"",onChange:y,options:[{value:"",label:"Default"},...u.map(m=>({value:m,label:m}))]}):u===null?e.jsx(G,{size:"small",className:"w-[160px]",value:n,placeholder:"Default model",onChange:m=>c(m.target.value),onBlur:N}):null,e.jsx("div",{className:Array.isArray(h)?"visible":"invisible",children:e.jsx(q,{size:"small",width:Ee,value:t.effort??"",onChange:A,options:[{value:"",label:"Default"},...(Array.isArray(h)?h:[]).map(m=>({value:m,label:m}))]})})]}),!r&&e.jsx(v,{})]})},De=()=>{var Y,H;const s=d.useRef(null),[t,r]=d.useState(void 0),{iconDataUri:l,loading:p}=le(),[u,h]=d.useState(null),n=u??l,[c,S]=d.useState(!1),[y,N]=d.useState(""),[A,m]=d.useState(""),{toast:x}=_();d.useEffect(()=>{K().then(a=>{r(a),(a==null?void 0:a.port)!==void 0&&N(String(a.port)),(a==null?void 0:a.projectName)!==void 0&&m(a.projectName)})},[]);const k=async(a,g)=>{const o=t==null?void 0:t.defaultAgents,j={phase:(o==null?void 0:o.phase)??z.phase,planDraft:(o==null?void 0:o.planDraft)??z.planDraft,ideaExtend:(o==null?void 0:o.ideaExtend)??z.ideaExtend,commitSuggest:(o==null?void 0:o.commitSuggest)??z.commitSuggest,feedback:(o==null?void 0:o.feedback)??z.feedback,[a]:g},{ok:w,error:E}=await D({defaultAgents:j});w?(r(I=>I&&{...I,defaultAgents:j}),x({title:"Saved",variant:"success"})):x({title:"Failed to save",description:E,variant:"error"})},i=async()=>{const a=Number(y);if(!t||!Number.isInteger(a)||a<=0||a===t.port)return;const{ok:g,error:o}=await D({port:a});g?(r(j=>j&&{...j,port:a}),x({title:"Saved",description:"Restart `paper-camp dev` to apply the new port.",variant:"success"})):x({title:"Failed to save",description:o,variant:"error"})},b=async()=>{var w,E,I;if(!t)return;const a=!(((E=(w=t.integration)==null?void 0:w.toolbar)==null?void 0:E.enabled)??!0),g={...t.integration,toolbar:{...(I=t.integration)==null?void 0:I.toolbar,enabled:a}},{ok:o,error:j}=await D({integration:g});o?(r(U=>U&&{...U,integration:g}),x({title:"Saved",variant:"success"})):x({title:"Failed to save",description:j,variant:"error"})},C=async()=>{const a=A.trim();if(!t||!a||a===t.projectName)return;const{ok:g,error:o}=await D({projectName:a});g?(r(j=>j&&{...j,projectName:a}),m(a),x({title:"Saved",variant:"success"})):x({title:"Failed to save",description:o,variant:"error"})},R=async a=>{var j;const g=(j=a.target.files)==null?void 0:j[0];if(!g)return;S(!0);const o=new FileReader;o.onloadend=async()=>{const w=o.result,E=await ie(w);S(!1),E?(h(w),x({title:"Saved",variant:"success"})):x({title:"Failed to save",variant:"error"})},o.readAsDataURL(g)};return e.jsxs("div",{children:[e.jsx("div",{className:"mb-6",children:e.jsx("h2",{className:"m-0",children:"Project Info"})}),t===void 0&&e.jsx("p",{children:"Loading…"}),t===null&&e.jsxs(M,{variant:"warning",children:["No papercamp/config.json found — run ",e.jsx("code",{children:"paper-camp init"})," in this directory first."]}),t&&e.jsxs(F,{size:"small",texture:"kraft",children:[e.jsxs("div",{className:"flex items-end gap-3 pb-3",children:[e.jsx(G,{value:A,onChange:a=>m(a.target.value),onBlur:C,label:"Project Name"}),e.jsxs(P,{size:"small",fillColor:"rgba(143, 185, 150, 0.25)",textColor:ce.accentGreenDark,children:["v",t.version]})]}),e.jsx(v,{}),e.jsxs("div",{className:"flex items-center gap-3 pb-3 pt-3",children:[n&&e.jsx("img",{src:n,alt:"Project icon",className:"w-10 h-10 object-contain shrink-0 rounded"}),e.jsxs("div",{children:[e.jsx("input",{ref:s,type:"file",accept:".svg,.png,.jpg,.jpeg,.gif,.webp",onChange:R,className:"hidden"}),e.jsx(f,{size:"small",onClick:()=>{var a;return(a=s.current)==null?void 0:a.click()},disabled:c,children:c?"Uploading…":"Choose File"}),p&&e.jsx("p",{className:"text-sm opacity-50 mt-1 mx-0 mb-0",children:"Loading…"}),!p&&!n&&!c&&e.jsx("p",{className:"text-sm opacity-[0.45] mt-1 mx-0 mb-0",children:"No icon set."})]})]}),e.jsx(v,{}),e.jsx("div",{className:"flex items-end gap-3 pb-3 pt-3",children:e.jsx(G,{type:"number",value:y,onChange:a=>N(a.target.value),onBlur:i,label:"Port",helperText:"Default for `paper-camp dev`. Restart the server to apply a change."})}),e.jsx(v,{}),e.jsxs("div",{className:"flex items-center justify-between gap-3 pb-3 pt-3",children:[e.jsxs("div",{children:[e.jsx("p",{className:"m-0",children:"In-app dev toolbar"}),e.jsx("p",{className:"opacity-[0.45] text-sm mt-1 mx-0 mb-0",children:"Inject the paper-camp toolbar into this project's dev server via the Vite plugin."})]}),e.jsx(f,{size:"small",onClick:b,children:((H=(Y=t.integration)==null?void 0:Y.toolbar)==null?void 0:H.enabled)??!0?"Disable":"Enable"})]}),e.jsx(v,{}),e.jsx(Ie,{}),J.map((a,g)=>{var o;return e.jsx(ze,{taskKey:a,agentConfig:((o=t.defaultAgents)==null?void 0:o[a])??z[a],isLast:g===J.length-1,onSave:k},a)})]}),e.jsxs("p",{className:"opacity-[0.45] text-sm mt-4",children:[e.jsx("strong",{children:"Initialized:"})," ",t?new Date(t.initializedAt).toLocaleString():"—"]})]})},Le=()=>{const s=Z();return e.jsxs("div",{children:[e.jsx(ne,{children:"Settings"}),s==="subjects"?e.jsx(ke,{}):s==="setup"?e.jsx(Se,{}):s==="merge-policy"?e.jsx(ue,{}):e.jsx(De,{})]})},Pe=()=>{const s=Z(),t=Q();return e.jsxs(e.Fragment,{children:[e.jsxs(W,{label:"General",children:[e.jsx(L,{size:"small",active:s===null,onClick:()=>t({to:"/settings"}),children:"Project Info"}),e.jsx(L,{size:"small",active:s==="setup",onClick:()=>t({to:"/settings/$section",params:{section:"setup"}}),children:"Setup"}),e.jsx(L,{size:"small",active:s==="merge-policy",onClick:()=>t({to:"/settings/$section",params:{section:"merge-policy"}}),children:"Merge Policy"})]}),e.jsx(W,{label:"Ideas",children:e.jsx(L,{size:"small",active:s==="subjects",onClick:()=>t({to:"/settings/$section",params:{section:"subjects"}}),children:"Subjects"})})]})};export{Le as SettingsPage,Pe as SettingsSidebar};
2
+ //# sourceMappingURL=index-Cz9HEIaO.js.map