@dendelion/paper-camp 0.18.0 → 0.19.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 (55) hide show
  1. package/dist/app/assets/index-B6251tL6.js +2 -0
  2. package/dist/app/assets/{index-B_KrbzkW.js.map → index-B6251tL6.js.map} +1 -1
  3. package/dist/app/assets/{index-BiMhnqOS.js → index-BNoowtMI.js} +2 -2
  4. package/dist/app/assets/{index-BiMhnqOS.js.map → index-BNoowtMI.js.map} +1 -1
  5. package/dist/app/assets/index-D2iIIpI1.js +4 -0
  6. package/dist/app/assets/{index-Db-zMFvA.js.map → index-D2iIIpI1.js.map} +1 -1
  7. package/dist/app/assets/index-D5j1njQR.js +2 -0
  8. package/dist/app/assets/index-D5j1njQR.js.map +1 -0
  9. package/dist/app/assets/index-DLkUANCR.js +2 -0
  10. package/dist/app/assets/index-DLkUANCR.js.map +1 -0
  11. package/dist/app/assets/{index-UPIRvQZS.js → index-nuVVSVma.js} +3 -3
  12. package/dist/app/assets/index-nuVVSVma.js.map +1 -0
  13. package/dist/app/assets/index-s6CVH54G.js +6 -0
  14. package/dist/app/assets/index-s6CVH54G.js.map +1 -0
  15. package/dist/app/assets/main--EStESJz.js +217 -0
  16. package/dist/app/assets/main--EStESJz.js.map +1 -0
  17. package/dist/app/assets/main-CAJuC1Pz.css +1 -0
  18. package/dist/app/assets/{sidebar-section-Lss_HMtQ.js → sidebar-section-DTU8Naqm.js} +2 -2
  19. package/dist/app/assets/{sidebar-section-Lss_HMtQ.js.map → sidebar-section-DTU8Naqm.js.map} +1 -1
  20. package/dist/app/index.html +2 -2
  21. package/dist/app/toolbar.js +4070 -3975
  22. package/dist/app/toolbar.js.map +1 -1
  23. package/dist/chunks/{phase-progress.BIIDRJmI.js → phase-progress.CwSKAAZ-.js} +1364 -1254
  24. package/dist/chunks/phase-progress.CwSKAAZ-.js.map +1 -0
  25. package/dist/cli/index.js +7948 -7439
  26. package/dist/cli/index.js.map +1 -1
  27. package/dist/core/git-pr/pr-lookup.d.ts +33 -1
  28. package/dist/core/git-pr/pr-lookup.d.ts.map +1 -1
  29. package/dist/core/git-pr/pr.d.ts +5 -1
  30. package/dist/core/git-pr/pr.d.ts.map +1 -1
  31. package/dist/core/index.js +107 -101
  32. package/dist/core/parse/schemas.d.ts +8 -0
  33. package/dist/core/parse/schemas.d.ts.map +1 -1
  34. package/dist/core/readers.d.ts +1 -1
  35. package/dist/core/readers.d.ts.map +1 -1
  36. package/dist/types/index.d.ts +53 -2
  37. package/dist/types/index.d.ts.map +1 -1
  38. package/dist/types/index.js +23 -17
  39. package/dist/types/index.js.map +1 -1
  40. package/package.json +1 -1
  41. package/dist/app/assets/index-2KbxO2gv.js +0 -2
  42. package/dist/app/assets/index-2KbxO2gv.js.map +0 -1
  43. package/dist/app/assets/index-B_KrbzkW.js +0 -2
  44. package/dist/app/assets/index-DahTzD09.js +0 -6
  45. package/dist/app/assets/index-DahTzD09.js.map +0 -1
  46. package/dist/app/assets/index-Db-zMFvA.js +0 -4
  47. package/dist/app/assets/index-Dw1f2idP.js +0 -2
  48. package/dist/app/assets/index-Dw1f2idP.js.map +0 -1
  49. package/dist/app/assets/index-UPIRvQZS.js.map +0 -1
  50. package/dist/app/assets/main-BuCfycKH.css +0 -1
  51. package/dist/app/assets/main-CfeIUKG-.js +0 -217
  52. package/dist/app/assets/main-CfeIUKG-.js.map +0 -1
  53. package/dist/app/assets/tokens-C3C44lLs.js +0 -2
  54. package/dist/app/assets/tokens-C3C44lLs.js.map +0 -1
  55. package/dist/chunks/phase-progress.BIIDRJmI.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-D5j1njQR.js","sources":["../../../src/app/services/system/merge-policy-api.ts","../../../src/app/features/settings/components/merge-policy-section.tsx","../../../src/app/features/settings/components/setup-section.tsx","../../../src/app/features/settings/components/subjects-section.tsx","../../../src/app/features/settings/settings-page.tsx","../../../src/app/features/settings/components/settings-sidebar.tsx"],"sourcesContent":["import type { MergePolicyResult } from '@/types/index';\nimport { apiUrl } from '../api-base';\n\nexport const fetchMergePolicy = async (): Promise<MergePolicyResult | null> => {\n try {\n const response = await fetch(apiUrl('/api/merge-policy'));\n if (!response.ok) return null;\n return (await response.json()) as MergePolicyResult;\n } catch {\n return null;\n }\n};\n\nexport const applyMergePolicy = async (): Promise<MergePolicyResult | null> => {\n try {\n const response = await fetch(apiUrl('/api/merge-policy/apply'), { method: 'POST' });\n if (!response.ok) return null;\n return (await response.json()) as MergePolicyResult;\n } catch {\n return null;\n }\n};\n","import { applyMergePolicy, fetchMergePolicy } from '@/app/services/system';\nimport type { MergePolicy, MergePolicyResult } from '@/types/index';\nimport { Alert, Button, Card, Divider, Stamp, useToast } from '@dendelion/paper-ui';\nimport { useEffect, useState } from 'react';\n\nconst RECOMMENDED: MergePolicy = {\n allowSquashMerge: true,\n allowMergeCommit: false,\n allowRebaseMerge: false,\n squashMergeCommitTitle: 'PR_TITLE',\n squashMergeCommitMessage: 'PR_BODY',\n};\n\nconst POLICY_ROWS: { key: keyof MergePolicy; label: string }[] = [\n { key: 'allowSquashMerge', label: 'Allow squash merge' },\n { key: 'allowMergeCommit', label: 'Allow merge commit' },\n { key: 'allowRebaseMerge', label: 'Allow rebase merge' },\n { key: 'squashMergeCommitTitle', label: 'Squash commit title' },\n { key: 'squashMergeCommitMessage', label: 'Squash commit message' },\n];\n\nfunction formatValue(value: boolean | string): string {\n return typeof value === 'boolean' ? (value ? 'Yes' : 'No') : value;\n}\n\nfunction matchesRecommended(policy: MergePolicy): boolean {\n return POLICY_ROWS.every((row) => policy[row.key] === RECOMMENDED[row.key]);\n}\n\ninterface PolicyRowProps {\n label: string;\n current: boolean | string;\n recommended: boolean | string;\n isLast: boolean;\n}\n\nconst PolicyRow = ({ label, current, recommended, isLast }: PolicyRowProps) => {\n const matches = current === recommended;\n return (\n <>\n <div className=\"flex items-center gap-3 pb-2 pt-2\">\n <span className=\"flex-1\">{label}</span>\n <span className={matches ? 'opacity-[0.65] font-normal' : 'font-semibold'}>\n {formatValue(current)}\n </span>\n {!matches && <span className=\"opacity-[0.45]\">→ {formatValue(recommended)}</span>}\n </div>\n {!isLast && <Divider />}\n </>\n );\n};\n\nexport const MergePolicySection = () => {\n const [result, setResult] = useState<MergePolicyResult | null | undefined>(undefined);\n const [applying, setApplying] = useState(false);\n const { toast } = useToast();\n\n useEffect(() => {\n fetchMergePolicy().then(setResult);\n }, []);\n\n const handleApply = async () => {\n setApplying(true);\n const applied = await applyMergePolicy();\n setApplying(false);\n if (applied?.status === 'ok') {\n setResult(applied);\n toast({ title: 'Merge policy applied', variant: 'success' });\n } else {\n toast({\n title: 'Failed to apply merge policy',\n description: applied?.status === 'unavailable' ? applied.reason : undefined,\n variant: 'error',\n });\n }\n };\n\n const upToDate = result?.status === 'ok' && matchesRecommended(result.policy);\n\n return (\n <div>\n <div className=\"mb-6\">\n <h2 className=\"m-0\">Merge Policy</h2>\n <p className=\"opacity-50 mt-1\">\n Paper Camp's canonical policy: squash-only merges, with the commit title and body taken\n from the PR.\n </p>\n </div>\n {result === undefined && <p>Loading…</p>}\n {result === null && <Alert variant=\"warning\">Failed to load merge policy.</Alert>}\n {result?.status === 'unavailable' && <Alert variant=\"warning\">{result.reason}</Alert>}\n {result?.status === 'ok' && (\n <>\n <div className=\"flex items-center gap-3 mb-3\">\n <span className=\"font-medium\">{result.repo}</span>\n <Stamp\n size=\"small\"\n fillColor={upToDate ? 'rgba(143, 185, 150, 0.25)' : 'rgba(212, 163, 115, 0.25)'}\n textColor={upToDate ? '#5E8A66' : '#A67B4F'}\n >\n {upToDate ? 'Matches recommended policy' : 'Differs from recommended policy'}\n </Stamp>\n </div>\n <Card size=\"small\" texture=\"kraft\">\n {POLICY_ROWS.map((row, idx) => (\n <PolicyRow\n key={row.key}\n label={row.label}\n current={result.policy[row.key]}\n recommended={RECOMMENDED[row.key]}\n isLast={idx === POLICY_ROWS.length - 1}\n />\n ))}\n </Card>\n <div className=\"mt-4\">\n <Button size=\"small\" onClick={handleApply} disabled={applying || upToDate}>\n {applying ? 'Applying…' : 'Apply recommended policy'}\n </Button>\n </div>\n </>\n )}\n </div>\n );\n};\n","import { connectService, fetchConfig, fetchConnections, saveConfig } from '@/app/services/system';\nimport { useAppStore } from '@/app/stores/app-store';\nimport type { CapabilityStatus, ConnectionResult } from '@/types/index';\nimport {\n Alert,\n Button,\n Card,\n CodeBlock,\n Divider,\n Stamp,\n Tooltip,\n useToast,\n} from '@dendelion/paper-ui';\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\nconst RELAY_POLL_MS = 2000;\n\n// Only claude-code exposes `auth login`/`auth status` (see agentAuthenticated in server/services.ts).\nconst RELAY_CONNECTION_ID: ConnectionResult['id'] = 'agent:claude-code';\n\n// Same two commands the relay drives interactively — shown as copy-paste fallback\n// when the relay itself can't run (no PTY, offline, unsupported CLI version).\nconst AUTH_FIX_COMMANDS = ['claude auth login', 'claude setup-token'] as const;\n\nconst RelayFallbackGuide = () => (\n <div className=\"mt-2 flex flex-col gap-2\">\n <p className=\"opacity-[0.65] text-sm m-0\">\n The in-app relay couldn't complete. Run one of these in a terminal instead:\n </p>\n {AUTH_FIX_COMMANDS.map((cmd) => (\n <CodeBlock key={cmd} code={cmd} />\n ))}\n <p className=\"opacity-50 text-sm m-0\">\n {/* paper-ui has no inline-code component, only the block-level CodeBlock */}\n Alternatively, set <code>ANTHROPIC_API_KEY</code> in the server's environment — that bills as\n API usage rather than your Max subscription, so treat it as a fallback, not the default.\n </p>\n </div>\n);\n\nconst SignInAction = ({ onSignedIn }: { onSignedIn: () => void }) => {\n const loginRelay = useAppStore((s) => s.loginRelay);\n const startLoginRelay = useAppStore((s) => s.startLoginRelay);\n const loadLoginRelayStatus = useAppStore((s) => s.loadLoginRelayStatus);\n const cancelLoginRelay = useAppStore((s) => s.cancelLoginRelay);\n const { toast } = useToast();\n const openedUrlRef = useRef<string | null>(null);\n const phase = loginRelay?.phase;\n\n useEffect(() => {\n if (phase !== 'starting' && phase !== 'awaiting-authorization') return;\n const id = window.setInterval(() => loadLoginRelayStatus(), RELAY_POLL_MS);\n return () => window.clearInterval(id);\n }, [phase, loadLoginRelayStatus]);\n\n useEffect(() => {\n const url = loginRelay?.authorizeUrl;\n if (phase !== 'awaiting-authorization' || !url || openedUrlRef.current === url) return;\n openedUrlRef.current = url;\n window.open(url, '_blank', 'noopener,noreferrer');\n }, [phase, loginRelay?.authorizeUrl]);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: keyed on phase transitions only — toast/onSignedIn aren't stable across renders, and including them would refire on every relay poll\n useEffect(() => {\n if (phase === 'success') {\n toast({ title: 'Signed in', variant: 'success' });\n onSignedIn();\n } else if (phase === 'error') {\n toast({ title: 'Sign-in failed', description: loginRelay?.error, variant: 'error' });\n }\n }, [phase]);\n\n if (phase === 'starting') {\n return (\n <Button size=\"small\" disabled>\n Starting…\n </Button>\n );\n }\n if (phase === 'awaiting-authorization') {\n return (\n <div className=\"flex items-center gap-2\">\n <Button\n size=\"small\"\n onClick={() =>\n loginRelay?.authorizeUrl &&\n window.open(loginRelay.authorizeUrl, '_blank', 'noopener,noreferrer')\n }\n >\n Reopen sign-in tab\n </Button>\n <Button size=\"small\" onClick={() => cancelLoginRelay()}>\n Cancel\n </Button>\n </div>\n );\n }\n return (\n <div>\n <Button size=\"small\" onClick={() => startLoginRelay()}>\n Sign in\n </Button>\n {phase === 'error' && <RelayFallbackGuide />}\n </div>\n );\n};\n\nconst STATUS_STAMP: Record<CapabilityStatus, { fill: string; text: string; label: string }> = {\n ok: { fill: 'rgba(143, 185, 150, 0.25)', text: '#5E8A66', label: 'Ready' },\n warn: { fill: 'rgba(212, 163, 115, 0.25)', text: '#A67B4F', label: 'Needs attention' },\n missing: { fill: 'rgba(201, 139, 139, 0.25)', text: '#6E3A3A', label: 'Missing' },\n};\n\nconst ConnectActionView = ({\n connection,\n onConnect,\n connecting,\n}: {\n connection: ConnectionResult;\n onConnect: (id: string) => void;\n connecting: boolean;\n}) => {\n const { connect } = connection;\n if (!connect) return null;\n if (connect.kind === 'command' && connect.runnable) {\n return (\n <Button size=\"small\" onClick={() => onConnect(connection.id)} disabled={connecting}>\n {connecting ? 'Running…' : `Run \\`${connect.command}\\``}\n </Button>\n );\n }\n if (connect.kind === 'command') {\n return (\n <div className=\"mt-2\">\n <CodeBlock code={connect.command} />\n </div>\n );\n }\n if (connect.kind === 'link') {\n return (\n <Button\n size=\"small\"\n onClick={() => window.open(connect.url, '_blank', 'noopener,noreferrer')}\n >\n {connect.label}\n </Button>\n );\n }\n return <p className=\"opacity-[0.65] text-sm mt-2 mx-0 mb-0\">{connect.message}</p>;\n};\n\nconst ConnectionRow = ({\n connection,\n isLast,\n onRecheck,\n rechecking,\n onConnect,\n connecting,\n}: {\n connection: ConnectionResult;\n isLast: boolean;\n onRecheck: (id: string) => void;\n rechecking: boolean;\n onConnect: (id: string) => void;\n connecting: boolean;\n}) => {\n const stamp = STATUS_STAMP[connection.status];\n return (\n <>\n <div className=\"pb-3 pt-3\">\n <div className=\"flex items-center gap-3\">\n <span className=\"flex-1 font-medium\">{connection.label}</span>\n {connection.authenticated === false && (\n <Tooltip content=\"Installed, but not signed in\">\n <Stamp size=\"small\" variant=\"warning\">\n Not signed in\n </Stamp>\n </Tooltip>\n )}\n <Stamp size=\"small\" fillColor={stamp.fill} textColor={stamp.text}>\n {stamp.label}\n </Stamp>\n <Button size=\"small\" onClick={() => onRecheck(connection.id)} disabled={rechecking}>\n {rechecking ? 'Checking…' : 'Recheck'}\n </Button>\n </div>\n <p className=\"opacity-[0.65] text-sm mt-1 mx-0 mb-0\">Unlocks: {connection.unlocks}</p>\n <p className=\"opacity-50 text-sm mt-1 mx-0 mb-0\">{connection.detail}</p>\n <div className=\"mt-2\">\n {connection.id === RELAY_CONNECTION_ID && connection.authenticated === false ? (\n <SignInAction onSignedIn={() => onRecheck(connection.id)} />\n ) : (\n <ConnectActionView\n connection={connection}\n onConnect={onConnect}\n connecting={connecting}\n />\n )}\n </div>\n </div>\n {!isLast && <Divider />}\n </>\n );\n};\n\nexport const SetupSection = () => {\n const [connections, setConnections] = useState<ConnectionResult[] | null>(null);\n const [loadFailed, setLoadFailed] = useState(false);\n const [reloadingId, setReloadingId] = useState<string | null>(null);\n const [connectingId, setConnectingId] = useState<string | null>(null);\n const [setupDismissed, setSetupDismissed] = useState(false);\n const { toast } = useToast();\n\n const applyConnections = useCallback((result: ConnectionResult[] | null) => {\n if (result === null) {\n setLoadFailed(true);\n return;\n }\n setLoadFailed(false);\n setConnections(result);\n }, []);\n\n useEffect(() => {\n fetchConnections().then(applyConnections);\n fetchConfig().then((c) => setSetupDismissed(c?.setupDismissed ?? false));\n }, [applyConnections]);\n\n const handleRecheck = async (id: string) => {\n setReloadingId(id);\n applyConnections(await fetchConnections());\n setReloadingId(null);\n };\n\n const handleConnect = async (id: string) => {\n setConnectingId(id);\n const updated = await connectService(id);\n if (updated) {\n setConnections((prev) => prev?.map((c) => (c.id === id ? updated : c)) ?? prev);\n } else {\n toast({ title: 'Failed to connect', variant: 'error' });\n }\n setConnectingId(null);\n };\n\n const handleDismissToggle = async () => {\n const next = !setupDismissed;\n const { ok } = await saveConfig({ setupDismissed: next });\n if (ok) {\n setSetupDismissed(next);\n toast({ title: 'Saved', variant: 'success' });\n } else {\n toast({ title: 'Failed to save', variant: 'error' });\n }\n };\n\n const allOk = connections?.every((c) => c.status === 'ok') ?? true;\n\n return (\n <div>\n <div className=\"mb-6\">\n <h2 className=\"m-0\">Setup</h2>\n </div>\n {connections === null && !loadFailed && <p>Loading…</p>}\n {loadFailed && (\n <div className=\"mb-4\">\n <Alert variant=\"warning\">Failed to load connections. Try refreshing.</Alert>\n </div>\n )}\n {connections && (\n <>\n {!allOk && (\n <div className=\"mb-4\">\n <Alert variant=\"warning\">\n Some connections are incomplete — features that depend on them stay disabled until\n fixed. Run the connect command below, then recheck.\n </Alert>\n </div>\n )}\n <Card size=\"small\" texture=\"kraft\">\n {connections.map((c, idx) => (\n <ConnectionRow\n key={c.id}\n connection={c}\n isLast={idx === connections.length - 1}\n onRecheck={handleRecheck}\n rechecking={reloadingId === c.id}\n onConnect={handleConnect}\n connecting={connectingId === c.id}\n />\n ))}\n </Card>\n <div className=\"mt-4\">\n <Button size=\"small\" onClick={handleDismissToggle}>\n {setupDismissed ? 'Show Setup on open again' : \"Don't show Setup on open\"}\n </Button>\n </div>\n </>\n )}\n </div>\n );\n};\n","import { useSubjectVocabulary } from '@/app/hooks';\nimport { Button, Card, Divider } from '@dendelion/paper-ui';\nimport { useNavigate } from '@tanstack/react-router';\n\nexport const SubjectsSection = () => {\n const { subjects, loading, available } = useSubjectVocabulary();\n const navigate = useNavigate();\n\n return (\n <div>\n <div className=\"mb-6\">\n <h2 className=\"m-0\">Subjects</h2>\n <p className=\"opacity-50 mt-1\">\n Subjects are the roadmap's bets and standing concerns. Edit the vocabulary on the Roadmap\n page.\n </p>\n </div>\n {loading && <p>Loading…</p>}\n {!loading && !available && (\n <p className=\"opacity-60 m-0\">Couldn't load subjects — check the server config.</p>\n )}\n {!loading && available && (\n <Card size=\"small\" texture=\"kraft\">\n {subjects.length === 0 && <p className=\"opacity-[0.45] m-0 pb-2\">No subjects yet.</p>}\n {subjects.map((name, idx) => (\n <div key={name}>\n <div className=\"pb-2 pt-2\">{name}</div>\n {idx < subjects.length - 1 && <Divider />}\n </div>\n ))}\n {subjects.length > 0 && <Divider />}\n <div className=\"pt-3\">\n <Button size=\"small\" onClick={() => navigate({ to: '/roadmap' })}>\n Go to Roadmap\n </Button>\n </div>\n </Card>\n )}\n </div>\n );\n};\n","import { PageTitle } from '@/app/components/page-title';\nimport { useActiveSettingsSection, useProjectIdentity } from '@/app/hooks';\nimport { fetchConfig, saveConfig, uploadIcon } from '@/app/services/system';\nimport { color } from '@/app/styles/tokens';\nimport {\n AGENT_IDS,\n AGENT_LABELS,\n AGENT_OPTIONS,\n type AgentConfig,\n type AgentId,\n DEFAULT_AGENTS,\n type DefaultAgentsMap,\n type PaperCampConfig,\n agentConfigsEqual,\n} from '@/types/index';\nimport { Alert, Button, Card, Divider, Input, Select, Stamp, useToast } from '@dendelion/paper-ui';\nimport { useEffect, useRef, useState } from 'react';\nimport { MergePolicySection } from './components/merge-policy-section';\nimport { SetupSection } from './components/setup-section';\nimport { SubjectsSection } from './components/subjects-section';\n\nconst TASK_TYPE_KEYS = [\n 'phase',\n 'planDraft',\n 'ideaExtend',\n 'commitSuggest',\n 'feedback',\n 'codeReview',\n] as const;\ntype TaskTypeKey = (typeof TASK_TYPE_KEYS)[number];\n\nconst TASK_TYPE_LABELS: Record<TaskTypeKey, string> = {\n phase: 'Phase run',\n planDraft: 'Plan draft',\n ideaExtend: 'Idea extend',\n commitSuggest: 'Commit suggest',\n feedback: 'Scout chat',\n codeReview: 'Code review',\n};\n\ninterface AgentTaskRowProps {\n taskKey: TaskTypeKey;\n agentConfig: AgentConfig;\n isLast: boolean;\n onSave: (key: TaskTypeKey, config: AgentConfig) => Promise<void>;\n /** The code-authoring task's config — codeReview's model must never match it (IDEA-170). */\n authorConfig?: AgentConfig;\n}\n\nconst TASK_COLUMN_WIDTH = 110;\nconst AGENT_COLUMN_WIDTH = 140;\nconst MODEL_COLUMN_WIDTH = 160;\nconst EFFORT_COLUMN_WIDTH = 110;\n\nconst AgentTaskRowHeader = () => (\n <div className=\"flex items-center gap-3 pb-1\">\n <span className=\"w-[110px] shrink-0 text-sm opacity-[0.45]\">Task</span>\n <span className=\"w-[140px] shrink-0 text-sm opacity-[0.45]\">Agent</span>\n <span className=\"w-[160px] shrink-0 text-sm opacity-[0.45]\">Model</span>\n <span className=\"w-[110px] shrink-0 text-sm opacity-[0.45]\">Effort</span>\n </div>\n);\n\nconst AgentTaskRow = ({\n taskKey,\n agentConfig,\n isLast,\n onSave,\n authorConfig,\n}: AgentTaskRowProps) => {\n // Fall back if the config carries an unknown agent id — never white-screen the page.\n const opts = AGENT_OPTIONS[agentConfig.agent] ?? AGENT_OPTIONS['claude-code'];\n // Only the author's model is excluded, and only while both rows share the same agent id.\n const excludedModel =\n authorConfig && authorConfig.agent === agentConfig.agent\n ? (authorConfig.model ?? '')\n : undefined;\n const modelOpts = Array.isArray(opts.model)\n ? opts.model.filter((m) => m !== excludedModel)\n : opts.model;\n const effortOpts = opts.effort;\n const [localModel, setLocalModel] = useState(agentConfig.model ?? '');\n\n useEffect(() => {\n setLocalModel(agentConfig.model ?? '');\n }, [agentConfig.model]);\n\n const handleAgentChange = (v: string) => {\n const newId = v as AgentId;\n const newOpts = AGENT_OPTIONS[newId];\n const newConfig: AgentConfig = { agent: newId };\n // Only carry the model over if the new agent accepts it — otherwise a claude\n // model like 'opus' would leak into opencode and fail at launch.\n if (\n agentConfig.model &&\n (newOpts.model === null || newOpts.model?.includes(agentConfig.model))\n ) {\n newConfig.model = agentConfig.model;\n }\n if (agentConfig.effort && Array.isArray(newOpts.effort)) newConfig.effort = agentConfig.effort;\n onSave(taskKey, newConfig);\n };\n\n const handleModelSelectChange = (v: string) => {\n onSave(taskKey, { ...agentConfig, model: v || undefined });\n };\n\n const handleModelInputBlur = () => {\n onSave(taskKey, { ...agentConfig, model: localModel || undefined });\n };\n\n const handleEffortChange = (v: string) => {\n onSave(taskKey, { ...agentConfig, effort: v || undefined });\n };\n\n return (\n <>\n <div className=\"flex items-center gap-3 pb-2 pt-2\">\n <span className=\"w-[110px] shrink-0 text-sm opacity-[0.65]\">\n {TASK_TYPE_LABELS[taskKey]}\n </span>\n <Select\n size=\"small\"\n width={AGENT_COLUMN_WIDTH}\n value={agentConfig.agent}\n onChange={handleAgentChange}\n options={AGENT_IDS.map((id) => ({ value: id, label: AGENT_LABELS[id] }))}\n />\n {Array.isArray(modelOpts) ? (\n <Select\n size=\"small\"\n width={MODEL_COLUMN_WIDTH}\n value={agentConfig.model ?? ''}\n onChange={handleModelSelectChange}\n options={[\n ...(excludedModel === '' ? [] : [{ value: '', label: 'Default' }]),\n ...modelOpts.map((m) => ({ value: m, label: m })),\n ]}\n />\n ) : modelOpts === null ? (\n <Input\n size=\"small\"\n className=\"w-[160px]\"\n value={localModel}\n placeholder=\"Default model\"\n onChange={(e) => setLocalModel(e.target.value)}\n onBlur={handleModelInputBlur}\n />\n ) : null}\n {/* Reserve the effort slot even when the agent has no effort options, so\n switching agents doesn't change the control count and shift the row. */}\n <div className={Array.isArray(effortOpts) ? 'visible' : 'invisible'}>\n <Select\n size=\"small\"\n width={EFFORT_COLUMN_WIDTH}\n value={agentConfig.effort ?? ''}\n onChange={handleEffortChange}\n options={[\n { value: '', label: 'Default' },\n ...(Array.isArray(effortOpts) ? effortOpts : []).map((e) => ({ value: e, label: e })),\n ]}\n />\n </div>\n </div>\n {!isLast && <Divider />}\n </>\n );\n};\n\nconst GeneralSection = () => {\n const fileRef = useRef<HTMLInputElement>(null);\n const [config, setConfig] = useState<PaperCampConfig | null | undefined>(undefined);\n const { iconDataUri: fetchedIconDataUri, loading: identityLoading } = useProjectIdentity();\n const [uploadedIconDataUri, setUploadedIconDataUri] = useState<string | null>(null);\n const iconDataUri = uploadedIconDataUri ?? fetchedIconDataUri;\n const [uploading, setUploading] = useState(false);\n const [portInput, setPortInput] = useState('');\n const [nameInput, setNameInput] = useState('');\n const { toast } = useToast();\n\n useEffect(() => {\n fetchConfig().then((c) => {\n setConfig(c);\n if (c?.port !== undefined) setPortInput(String(c.port));\n if (c?.projectName !== undefined) setNameInput(c.projectName);\n });\n }, []);\n\n const handleSaveAgentConfig = async (key: TaskTypeKey, newEntry: AgentConfig) => {\n const current = config?.defaultAgents;\n const updated: DefaultAgentsMap = {\n phase: current?.phase ?? DEFAULT_AGENTS.phase,\n planDraft: current?.planDraft ?? DEFAULT_AGENTS.planDraft,\n ideaExtend: current?.ideaExtend ?? DEFAULT_AGENTS.ideaExtend,\n commitSuggest: current?.commitSuggest ?? DEFAULT_AGENTS.commitSuggest,\n feedback: current?.feedback ?? DEFAULT_AGENTS.feedback,\n codeReview: current?.codeReview ?? DEFAULT_AGENTS.codeReview,\n [key]: newEntry,\n };\n if (key === 'codeReview' && agentConfigsEqual(newEntry, updated.phase)) {\n toast({\n title: 'Failed to save',\n description: 'Code review must use a different model than Phase run.',\n variant: 'error',\n });\n return;\n }\n const { ok, error } = await saveConfig({ defaultAgents: updated });\n if (ok) {\n setConfig((prev) => (prev ? { ...prev, defaultAgents: updated } : prev));\n toast({ title: 'Saved', variant: 'success' });\n } else {\n toast({ title: 'Failed to save', description: error, variant: 'error' });\n }\n };\n\n const handleSavePort = async () => {\n const port = Number(portInput);\n if (!config || !Number.isInteger(port) || port <= 0 || port === config.port) return;\n const { ok, error } = await saveConfig({ port });\n if (ok) {\n setConfig((prev) => (prev ? { ...prev, port } : prev));\n toast({\n title: 'Saved',\n description: 'Restart `paper-camp dev` to apply the new port.',\n variant: 'success',\n });\n } else {\n toast({ title: 'Failed to save', description: error, variant: 'error' });\n }\n };\n\n const handleToggleIntegration = async () => {\n if (!config) return;\n const next = !(config.integration?.toolbar?.enabled ?? true);\n const integration = {\n ...config.integration,\n toolbar: { ...config.integration?.toolbar, enabled: next },\n };\n const { ok, error } = await saveConfig({ integration });\n if (ok) {\n setConfig((prev) => (prev ? { ...prev, integration } : prev));\n toast({ title: 'Saved', variant: 'success' });\n } else {\n toast({ title: 'Failed to save', description: error, variant: 'error' });\n }\n };\n\n const handleSaveName = async () => {\n const projectName = nameInput.trim();\n if (!config || !projectName || projectName === config.projectName) return;\n const { ok, error } = await saveConfig({ projectName });\n if (ok) {\n setConfig((prev) => (prev ? { ...prev, projectName } : prev));\n setNameInput(projectName);\n toast({ title: 'Saved', variant: 'success' });\n } else {\n toast({ title: 'Failed to save', description: error, variant: 'error' });\n }\n };\n\n const handleFile = async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n setUploading(true);\n const reader = new FileReader();\n reader.onloadend = async () => {\n const dataUri = reader.result as string;\n const ok = await uploadIcon(dataUri);\n setUploading(false);\n if (ok) {\n setUploadedIconDataUri(dataUri);\n toast({ title: 'Saved', variant: 'success' });\n } else {\n toast({ title: 'Failed to save', variant: 'error' });\n }\n };\n reader.readAsDataURL(file);\n };\n\n return (\n <div>\n <div className=\"mb-6\">\n <h2 className=\"m-0\">Project Info</h2>\n </div>\n {config === undefined && <p>Loading…</p>}\n {config === null && (\n <Alert variant=\"warning\">\n No papercamp/config.json found — run <code>paper-camp init</code> in this directory first.\n </Alert>\n )}\n {config && (\n <Card size=\"small\" texture=\"kraft\">\n <div className=\"flex items-end gap-3 pb-3\">\n <Input\n value={nameInput}\n onChange={(e) => setNameInput(e.target.value)}\n onBlur={handleSaveName}\n label=\"Project Name\"\n />\n <Stamp\n size=\"small\"\n fillColor=\"rgba(143, 185, 150, 0.25)\"\n textColor={color.accentGreenDark}\n >\n v{config.version}\n </Stamp>\n </div>\n <Divider />\n\n <div className=\"flex items-center gap-3 pb-3 pt-3\">\n {iconDataUri && (\n <img\n src={iconDataUri}\n alt=\"Project icon\"\n className=\"w-10 h-10 object-contain shrink-0 rounded\"\n />\n )}\n <div>\n {/* paper-ui has no file-input component, so this raw input is intentional */}\n <input\n ref={fileRef}\n type=\"file\"\n accept=\".svg,.png,.jpg,.jpeg,.gif,.webp\"\n onChange={handleFile}\n className=\"hidden\"\n />\n <Button size=\"small\" onClick={() => fileRef.current?.click()} disabled={uploading}>\n {uploading ? 'Uploading…' : 'Choose File'}\n </Button>\n {identityLoading && <p className=\"text-sm opacity-50 mt-1 mx-0 mb-0\">Loading…</p>}\n {!identityLoading && !iconDataUri && !uploading && (\n <p className=\"text-sm opacity-[0.45] mt-1 mx-0 mb-0\">No icon set.</p>\n )}\n </div>\n </div>\n <Divider />\n\n <div className=\"flex items-end gap-3 pb-3 pt-3\">\n <Input\n type=\"number\"\n value={portInput}\n onChange={(e) => setPortInput(e.target.value)}\n onBlur={handleSavePort}\n label=\"Port\"\n helperText=\"Default for `paper-camp dev`. Restart the server to apply a change.\"\n />\n </div>\n <Divider />\n\n <div className=\"flex items-center justify-between gap-3 pb-3 pt-3\">\n <div>\n <p className=\"m-0\">In-app dev toolbar</p>\n <p className=\"opacity-[0.45] text-sm mt-1 mx-0 mb-0\">\n Inject the paper-camp toolbar into this project's dev server via the Vite plugin.\n </p>\n </div>\n <Button size=\"small\" onClick={handleToggleIntegration}>\n {(config.integration?.toolbar?.enabled ?? true) ? 'Disable' : 'Enable'}\n </Button>\n </div>\n <Divider />\n\n <AgentTaskRowHeader />\n {TASK_TYPE_KEYS.map((key, idx) => (\n <AgentTaskRow\n key={key}\n taskKey={key}\n agentConfig={config.defaultAgents?.[key] ?? DEFAULT_AGENTS[key]}\n isLast={idx === TASK_TYPE_KEYS.length - 1}\n onSave={handleSaveAgentConfig}\n authorConfig={\n key === 'codeReview'\n ? (config.defaultAgents?.phase ?? DEFAULT_AGENTS.phase)\n : undefined\n }\n />\n ))}\n </Card>\n )}\n\n <p className=\"opacity-[0.45] text-sm mt-4\">\n <strong>Initialized:</strong>{' '}\n {config ? new Date(config.initializedAt).toLocaleString() : '—'}\n </p>\n </div>\n );\n};\n\nexport const SettingsPage = () => {\n const section = useActiveSettingsSection();\n return (\n <div>\n <PageTitle>Settings</PageTitle>\n {section === 'subjects' ? (\n <SubjectsSection />\n ) : section === 'setup' ? (\n <SetupSection />\n ) : section === 'merge-policy' ? (\n <MergePolicySection />\n ) : (\n <GeneralSection />\n )}\n </div>\n );\n};\n","import { useActiveSettingsSection } from '@/app/hooks';\nimport { ListItem } from '@dendelion/paper-ui';\nimport { useNavigate } from '@tanstack/react-router';\nimport { SidebarSection } from '../../plans/components/sidebar-section';\n\nexport const SettingsSidebar = () => {\n const section = useActiveSettingsSection();\n const navigate = useNavigate();\n\n return (\n <>\n <SidebarSection label=\"General\">\n <ListItem\n size=\"small\"\n active={section === null}\n onClick={() => navigate({ to: '/settings' })}\n >\n Project Info\n </ListItem>\n <ListItem\n size=\"small\"\n active={section === 'setup'}\n onClick={() => navigate({ to: '/settings/$section', params: { section: 'setup' } })}\n >\n Setup\n </ListItem>\n <ListItem\n size=\"small\"\n active={section === 'merge-policy'}\n onClick={() =>\n navigate({ to: '/settings/$section', params: { section: 'merge-policy' } })\n }\n >\n Merge Policy\n </ListItem>\n </SidebarSection>\n <SidebarSection label=\"Ideas\">\n <ListItem\n size=\"small\"\n active={section === 'subjects'}\n onClick={() => navigate({ to: '/settings/$section', params: { section: 'subjects' } })}\n >\n Subjects\n </ListItem>\n </SidebarSection>\n </>\n );\n};\n"],"names":["fetchMergePolicy","response","apiUrl","applyMergePolicy","RECOMMENDED","POLICY_ROWS","formatValue","value","matchesRecommended","policy","row","PolicyRow","label","current","recommended","isLast","matches","jsxs","Fragment","jsx","Divider","MergePolicySection","result","setResult","useState","applying","setApplying","toast","useToast","useEffect","handleApply","applied","upToDate","Alert","Stamp","Card","idx","Button","RELAY_POLL_MS","RELAY_CONNECTION_ID","AUTH_FIX_COMMANDS","RelayFallbackGuide","cmd","CodeBlock","SignInAction","onSignedIn","loginRelay","useAppStore","s","startLoginRelay","loadLoginRelayStatus","cancelLoginRelay","openedUrlRef","useRef","phase","id","url","STATUS_STAMP","ConnectActionView","connection","onConnect","connecting","connect","ConnectionRow","onRecheck","rechecking","stamp","Tooltip","SetupSection","connections","setConnections","loadFailed","setLoadFailed","reloadingId","setReloadingId","connectingId","setConnectingId","setupDismissed","setSetupDismissed","applyConnections","useCallback","fetchConnections","fetchConfig","handleRecheck","handleConnect","updated","connectService","prev","c","handleDismissToggle","next","ok","saveConfig","allOk","SubjectsSection","subjects","loading","available","useSubjectVocabulary","navigate","useNavigate","name","TASK_TYPE_KEYS","TASK_TYPE_LABELS","AGENT_COLUMN_WIDTH","MODEL_COLUMN_WIDTH","EFFORT_COLUMN_WIDTH","AgentTaskRowHeader","AgentTaskRow","taskKey","agentConfig","onSave","authorConfig","opts","AGENT_OPTIONS","excludedModel","modelOpts","effortOpts","localModel","setLocalModel","handleAgentChange","v","newId","newOpts","newConfig","_a","handleModelSelectChange","handleModelInputBlur","handleEffortChange","Select","AGENT_IDS","AGENT_LABELS","Input","e","GeneralSection","fileRef","config","setConfig","fetchedIconDataUri","identityLoading","useProjectIdentity","uploadedIconDataUri","setUploadedIconDataUri","iconDataUri","uploading","setUploading","portInput","setPortInput","nameInput","setNameInput","handleSaveAgentConfig","key","newEntry","DEFAULT_AGENTS","agentConfigsEqual","error","handleSavePort","port","handleToggleIntegration","_b","integration","_c","handleSaveName","projectName","handleFile","file","reader","dataUri","uploadIcon","color","SettingsPage","section","useActiveSettingsSection","PageTitle","SettingsSidebar","SidebarSection","ListItem"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{j as a,af as j,C as w,r as u,ag as v,ah as I,ai as E,aj as $,ak as C,aa as R,J as D,al as P,u as x,a as T,P as S,N as k}from"./main--EStESJz.js";function L(t){return Math.floor((Date.now()-Date.parse(t))/864e5)}function A(t){return t.kind==="question"?t.ageDays:L(t.date)}const N=t=>Number.isFinite(t)?t<=0?"today":t===1?"1 day ago":`${t} days ago`:"age unknown",F={completed:"Completed",reply:"Reply"},K=({notification:t,ageDays:d,onOpen:s})=>a.jsxs("div",{className:"flex items-center gap-3 py-2.5 border-b border-black/10 last:border-b-0",children:[a.jsx("button",{type:"button",onClick:s,"aria-label":`Open ${t.entityTitle}`,className:"bg-transparent border-none p-0 cursor-pointer",children:a.jsx(j,{id:t.entityId})}),a.jsx("span",{className:"text-xs uppercase tracking-wide opacity-40 whitespace-nowrap",children:F[t.kind]}),a.jsx("span",{className:"flex-1 min-w-0 truncate",children:t.text}),a.jsx("span",{className:"opacity-50 text-xs whitespace-nowrap",children:N(d)})]}),O=({question:t,plan:d,expanded:s,onToggle:f,onOpen:o,reload:h})=>{const{toast:m}=w(),[r,p]=u.useState(""),{sending:y,send:g,undo:e,undoing:c,undoEdit:n}=v(d,{reload:h,notify:m}),i=`question-reply:${t.entityId}`;u.useEffect(()=>{const l=I(i);l&&p(l)},[i]),u.useEffect(()=>{r&&E(i,r)},[i,r]);const b=async()=>{r.trim()&&await g(r.trim())&&(p(""),P(i))};return a.jsxs("div",{className:"border-b border-black/10 last:border-b-0",children:[a.jsxs("div",{className:"flex items-center gap-3 py-2.5",children:[a.jsx("button",{type:"button",onClick:o,"aria-label":`Open ${t.entityTitle}`,className:"bg-transparent border-none p-0 cursor-pointer",children:a.jsx(j,{id:t.entityId})}),a.jsx("button",{type:"button",onClick:f,"aria-expanded":s,className:"flex-1 min-w-0 truncate text-left bg-transparent border-none p-0 cursor-pointer",children:t.text}),a.jsx("span",{className:"opacity-50 text-xs whitespace-nowrap",children:N(t.ageDays)})]}),s&&a.jsxs("div",{className:"flex flex-col gap-3 pb-4",children:[a.jsx($,{messages:d.thread??[],undo:e,undoing:c,onUndo:n}),a.jsx(C,{value:r,onChange:l=>p(l.target.value),"aria-label":`Reply to ${t.entityTitle}`,placeholder:"Reply to resolve and resume…",rows:2,disabled:y}),a.jsxs("div",{className:"flex justify-end items-center gap-3",children:[a.jsx("span",{className:y?"visible":"invisible",children:a.jsx(R,{size:"small",label:"Agent replying…"})}),a.jsx(D,{size:"small",onClick:b,disabled:y||!r.trim(),children:"Reply"})]})]})]})},z=()=>{const[t,d]=u.useState(null),s=x(e=>e.notifications),f=x(e=>e.notificationsError!==null),o=x(e=>e.plans),h=x(e=>e.loadPlans),m=x(e=>e.loadNotifications),r=x(e=>e.markRead),p=T();u.useEffect(()=>{m()},[m]),u.useEffect(()=>{if(s)for(const e of s)e.kind!=="question"&&!e.read&&r(e.id)},[s,r]);const y=async()=>{await Promise.all([h(),m()])},g=(e,c)=>{o!=null&&o.entries.some(n=>n.id===e||n.title===c)?p({to:"/plans/$planId",params:{planId:k(e,c)}}):p({to:"/ideas/$ideaId",params:{ideaId:k(e,c)}})};return a.jsxs("div",{children:[a.jsx(S,{children:"Inbox"}),a.jsx("p",{className:"opacity-50 mb-6",children:"Every parked question, completed run, and agent reply, oldest first."}),f&&a.jsx("p",{className:"opacity-50",children:"Couldn't load notifications."}),!f&&!s&&a.jsx("p",{className:"opacity-50",children:"Loading…"}),s&&s.length===0&&a.jsx("p",{className:"opacity-50",children:"Nothing here — no parked questions or recent activity."}),s&&s.length>0&&a.jsx("div",{className:"flex flex-col",children:s.map((e,c)=>{const n=`${e.entityId}-${e.kind}-${c}`,i=()=>g(e.entityId,e.entityTitle);if(e.kind!=="question")return a.jsx(K,{notification:e,ageDays:A(e),onOpen:i},n);const b=o==null?void 0:o.entries.find(l=>l.id===e.entityId);return b?a.jsx(O,{question:e,plan:b,expanded:t===n,onToggle:()=>d(l=>l===n?null:n),onOpen:i,reload:y},n):a.jsxs("div",{className:"flex items-center gap-3 py-2.5 border-b border-black/10 last:border-b-0",children:[a.jsx("button",{type:"button",onClick:i,"aria-label":`Open ${e.entityTitle}`,className:"bg-transparent border-none p-0 cursor-pointer",children:a.jsx(j,{id:e.entityId})}),a.jsx("span",{className:"flex-1 min-w-0 truncate",children:e.text}),a.jsx("span",{className:"opacity-50 text-xs whitespace-nowrap",children:N(e.ageDays)})]},n)})})]})};export{z as InboxPage};
2
+ //# sourceMappingURL=index-DLkUANCR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-DLkUANCR.js","sources":["../../../src/core/notifications.ts","../../../src/app/features/inbox/helpers.ts","../../../src/app/features/inbox/notification-row.tsx","../../../src/app/features/inbox/question-row.tsx","../../../src/app/features/inbox/inbox-page.tsx"],"sourcesContent":["import type { Notification, ParkedQuestion, StoredNotification } from '../types/index';\n\nfunction ageInDays(date: string): number {\n return Math.floor((Date.now() - Date.parse(date)) / 86_400_000);\n}\n\nexport function notificationAgeDays(notification: Notification): number {\n return notification.kind === 'question' ? notification.ageDays : ageInDays(notification.date);\n}\n\n/** Every parked question alongside completed/reply notifications, oldest-first — the\n * unified feed (IDEA-153) replacing the questions-only Inbox. */\nexport function mergeNotifications(\n parkedQuestions: ParkedQuestion[],\n stored: StoredNotification[],\n): Notification[] {\n const entries: Notification[] = [\n ...parkedQuestions.map((q): Notification => ({ ...q, kind: 'question' })),\n ...stored,\n ];\n return entries.sort((a, b) => notificationAgeDays(b) - notificationAgeDays(a));\n}\n","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 { PlanIdStamp } from '@/app/features/plans/components';\nimport type { StoredNotification } from '@/types/index';\nimport { formatAge } from './helpers';\n\nconst KIND_LABELS: Record<StoredNotification['kind'], string> = {\n completed: 'Completed',\n reply: 'Reply',\n};\n\ninterface NotificationRowProps {\n notification: StoredNotification;\n ageDays: number;\n onOpen: () => void;\n}\n\nexport const NotificationRow = ({ notification, ageDays, onOpen }: NotificationRowProps) => (\n <div className=\"flex items-center gap-3 py-2.5 border-b border-black/10 last:border-b-0\">\n <button\n type=\"button\"\n onClick={onOpen}\n aria-label={`Open ${notification.entityTitle}`}\n className=\"bg-transparent border-none p-0 cursor-pointer\"\n >\n <PlanIdStamp id={notification.entityId} />\n </button>\n <span className=\"text-xs uppercase tracking-wide opacity-40 whitespace-nowrap\">\n {KIND_LABELS[notification.kind]}\n </span>\n <span className=\"flex-1 min-w-0 truncate\">{notification.text}</span>\n <span className=\"opacity-50 text-xs whitespace-nowrap\">{formatAge(ageDays)}</span>\n </div>\n);\n","import { FeedbackThread, PlanIdStamp } from '@/app/features/plans/components';\nimport { useSendFeedbackMessage } from '@/app/features/plans/hooks';\nimport { readLocalDraft, removeLocalDraft, writeLocalDraft } from '@/app/utils/local-draft-store';\nimport type { ParkedQuestion, PlanEntry } from '@/types/index';\nimport { Button, Spinner, Textarea, useToast } from '@dendelion/paper-ui';\nimport { useEffect, 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 draftKey = `question-reply:${question.entityId}`;\n\n useEffect(() => {\n const draft = readLocalDraft<string>(draftKey);\n if (draft) setInput(draft);\n }, [draftKey]);\n\n useEffect(() => {\n if (!input) return;\n writeLocalDraft(draftKey, input);\n }, [draftKey, input]);\n\n const handleSend = async () => {\n if (!input.trim()) return;\n if (await send(input.trim())) {\n setInput('');\n removeLocalDraft(draftKey);\n }\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 { entityRouteParam } from '@/app/hooks';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { notificationAgeDays } from '@/core/notifications';\nimport { useNavigate } from '@tanstack/react-router';\nimport { useEffect, useState } from 'react';\nimport { formatAge } from './helpers';\nimport { NotificationRow } from './notification-row';\nimport { QuestionRow } from './question-row';\n\nexport const InboxPage = () => {\n const [expandedKey, setExpandedKey] = useState<string | null>(null);\n const notifications = useAppStore((s) => s.notifications);\n const loadFailed = useAppStore((s) => s.notificationsError !== null);\n const plans = useAppStore((s) => s.plans);\n const loadPlans = useAppStore((s) => s.loadPlans);\n const loadNotifications = useAppStore((s) => s.loadNotifications);\n const markRead = useAppStore((s) => s.markRead);\n const navigate = useNavigate();\n\n useEffect(() => {\n loadNotifications();\n }, [loadNotifications]);\n\n useEffect(() => {\n if (!notifications) return;\n for (const n of notifications) {\n if (n.kind !== 'question' && !n.read) markRead(n.id);\n }\n }, [notifications, markRead]);\n\n const reload = async () => {\n await Promise.all([loadPlans(), loadNotifications()]);\n };\n\n const openEntity = (id: string, title: string) => {\n if (plans?.entries.some((p) => p.id === id || p.title === title)) {\n navigate({ to: '/plans/$planId', params: { planId: entityRouteParam(id, title) } });\n } else {\n navigate({ to: '/ideas/$ideaId', params: { ideaId: entityRouteParam(id, title) } });\n }\n };\n\n return (\n <div>\n <PageTitle>Inbox</PageTitle>\n <p className=\"opacity-50 mb-6\">\n Every parked question, completed run, and agent reply, oldest first.\n </p>\n {loadFailed && <p className=\"opacity-50\">Couldn't load notifications.</p>}\n {!loadFailed && !notifications && <p className=\"opacity-50\">Loading…</p>}\n {notifications && notifications.length === 0 && (\n <p className=\"opacity-50\">Nothing here — no parked questions or recent activity.</p>\n )}\n {notifications && notifications.length > 0 && (\n <div className=\"flex flex-col\">\n {notifications.map((n, i) => {\n const key = `${n.entityId}-${n.kind}-${i}`;\n const onOpen = () => openEntity(n.entityId, n.entityTitle);\n\n if (n.kind !== 'question') {\n return (\n <NotificationRow\n key={key}\n notification={n}\n ageDays={notificationAgeDays(n)}\n onOpen={onOpen}\n />\n );\n }\n\n const plan = plans?.entries.find((p) => p.id === n.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={onOpen}\n aria-label={`Open ${n.entityTitle}`}\n className=\"bg-transparent border-none p-0 cursor-pointer\"\n >\n <PlanIdStamp id={n.entityId} />\n </button>\n <span className=\"flex-1 min-w-0 truncate\">{n.text}</span>\n <span className=\"opacity-50 text-xs whitespace-nowrap\">\n {formatAge(n.ageDays)}\n </span>\n </div>\n );\n }\n return (\n <QuestionRow\n key={key}\n question={n}\n plan={plan}\n expanded={expandedKey === key}\n onToggle={() => setExpandedKey((cur) => (cur === key ? null : key))}\n onOpen={onOpen}\n reload={reload}\n />\n );\n })}\n </div>\n )}\n </div>\n );\n};\n"],"names":["ageInDays","date","notificationAgeDays","notification","formatAge","ageDays","KIND_LABELS","NotificationRow","onOpen","jsxs","jsx","PlanIdStamp","QuestionRow","question","plan","expanded","onToggle","reload","toast","useToast","input","setInput","useState","sending","send","undo","undoing","undoEdit","useSendFeedbackMessage","draftKey","useEffect","draft","readLocalDraft","writeLocalDraft","handleSend","removeLocalDraft","FeedbackThread","Textarea","e","Spinner","Button","InboxPage","expandedKey","setExpandedKey","notifications","useAppStore","s","loadFailed","plans","loadPlans","loadNotifications","markRead","navigate","useNavigate","n","openEntity","id","title","p","entityRouteParam","PageTitle","i","key","cur"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- import{u as h,z as v,r,j as e,P as L,R as u,y,g as S,B as A,J as T}from"./main-CfeIUKG-.js";import{c as f}from"./tokens-C3C44lLs.js";const b={phase:"Phase run",audit:"Audit","batch-reconcile":"Batch reconcile","run-all":"Run all phases",draft:"Draft",extend:"Extend",suggest:"Suggest ideas","commit-suggest":"Commit suggest","overlap-check":"Overlap check",prioritise:"Prioritise queue",sync:"Sync",reconcile:"Reconcile","fix-review":"Fix review","resolve-conflict":"Resolve conflict",feedback:"Feedback reply"},m=s=>String(s).padStart(2,"0"),_=s=>{const a=new Date(s);return`${a.getFullYear()}-${m(a.getMonth()+1)}-${m(a.getDate())}`},D=s=>new Date(s).toLocaleDateString(void 0,{weekday:"long",year:"numeric",month:"long",day:"numeric"}),k=s=>{const a=new Date(s);return`${m(a.getHours())}:${m(a.getMinutes())}:${m(a.getSeconds())}`},p="text-sm font-semibold whitespace-nowrap overflow-hidden",N="grid grid-cols-[20px_116px_minmax(0,1fr)_88px_150px_72px] gap-2.5 items-center max-lg:grid-cols-[20px_116px_minmax(0,1fr)_88px_72px] max-[480px]:grid-cols-1 max-[480px]:gap-1",R=({id:s})=>{const[a,c]=r.useState(null),[l,i]=r.useState(!1),[o,x]=r.useState(0);r.useEffect(()=>{let n=!1,d;c(null),i(!1);const g=j=>{A(s).then(w=>{n||c(w.lines??[])}).catch(()=>{if(!n){if(j>0){d=setTimeout(()=>g(j-1),700);return}i(!0),c([])}})};return g(3),()=>{n=!0,d&&clearTimeout(d)}},[s,o]);const t=e.jsx(T,{variant:"ghost",size:"small",onClick:()=>x(n=>n+1),children:"Retry"});return a===null?e.jsx("p",{className:"opacity-50 m-0",children:"Loading…"}):l?e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("p",{className:"opacity-50 m-0",children:"Couldn't load this task's output."}),t]}):a.length===0?e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("p",{className:"opacity-50 m-0",children:"No output recorded."}),t]}):e.jsx("pre",{className:"font-mono text-xs m-0 max-h-[320px] overflow-y-auto whitespace-pre-wrap",children:a.join(`
2
- `)})},E=({size:s=14,className:a})=>e.jsx("svg",{width:s,height:s,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",className:a,children:e.jsx("polyline",{points:"9 18 15 12 9 6"})}),$=({entry:s,highlighted:a})=>{const[c,l]=r.useState(a);r.useEffect(()=>{a&&l(!0)},[a]);const i=()=>l(o=>!o);return e.jsxs("div",{className:a?"task-row-highlighted flex flex-col gap-1 rounded-[10px] outline outline-2 outline-offset-[-2px] outline-[rgba(200,154,90,0.5)]":"flex flex-col gap-1 rounded-[10px]",children:[e.jsx("div",{role:"button",tabIndex:0,"aria-expanded":c,onClick:i,onKeyDown:o=>{(o.key==="Enter"||o.key===" ")&&(o.preventDefault(),i())},className:"group cursor-pointer rounded-[10px]",children:e.jsx(u,{size:"small",texture:"canvas",className:"plan-row-card",children:e.jsxs("div",{className:N,children:[e.jsx("span",{className:"inline-flex items-center opacity-50",children:e.jsx(E,{className:"group-aria-expanded:rotate-90"})}),e.jsx("span",{className:"font-semibold whitespace-nowrap overflow-hidden",children:b[s.taskKind]??s.taskKind}),e.jsx("span",{className:"overflow-hidden text-ellipsis whitespace-nowrap opacity-70",children:s.planTitle}),e.jsx("span",{className:"text-sm opacity-50 whitespace-nowrap",children:y[s.agentId]}),e.jsxs("span",{className:"max-lg:hidden font-mono text-xs opacity-[0.55] whitespace-nowrap",children:[k(s.startedAt),"–",k(s.endedAt)]}),e.jsx("div",{className:"flex items-center",children:e.jsx(S,{size:"small",fillColor:s.outcome==="done"?"rgba(143, 185, 150, 0.25)":s.outcome==="superseded"?"rgba(212, 163, 115, 0.25)":"rgba(201, 139, 139, 0.25)",textColor:s.outcome==="done"?f.accentGreenDark:s.outcome==="superseded"?f.accentAmberDark:f.accentRoseDark,children:s.outcome})})]})})}),c&&e.jsxs(u,{size:"small",texture:"kraft",className:"plan-row-card",children:[s.outcome==="error"&&s.reason&&e.jsx("p",{className:"m-0 mb-2 text-sm text-state-danger",children:s.reason}),e.jsx(R,{id:s.id})]})]})},K=()=>{const s=h(t=>t.taskLog),a=h(t=>t.taskLogLoading),c=h(t=>t.loadTaskLog),{taskId:l}=v({from:"/tasks"}),i=r.useRef(null);r.useEffect(()=>{c()},[c]),r.useEffect(()=>{var n;if(!l)return;const t=(n=i.current)==null?void 0:n.querySelector(".task-row-highlighted");t==null||t.scrollIntoView({behavior:"smooth",block:"center"})},[l]);const o=[...s].sort((t,n)=>n.endedAt.localeCompare(t.endedAt)),x=[];for(const t of o){const n=_(t.endedAt),d=x.at(-1);(d==null?void 0:d.key)===n?d.entries.push(t):x.push({key:n,entries:[t]})}return e.jsxs("div",{ref:i,children:[e.jsx(L,{children:"Tasks"}),a&&e.jsx("p",{className:"opacity-50",children:"Loading…"}),!a&&o.length===0&&e.jsx("p",{className:"opacity-50",children:"No tasks have run yet."}),!a&&o.length>0&&e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(u,{size:"small",texture:"kraft",className:"plan-row-card",children:e.jsxs("div",{className:N,children:[e.jsx("span",{}),e.jsx("span",{className:`${p} opacity-60`,children:"Task"}),e.jsx("span",{className:`${p} opacity-60`,children:"Plan"}),e.jsx("span",{className:`${p} opacity-60`,children:"Agent"}),e.jsx("span",{className:`max-lg:hidden ${p} opacity-60`,children:"Time"}),e.jsx("span",{className:`${p} opacity-60`,children:"Outcome"})]})}),x.map(t=>e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(u,{size:"small",texture:"kraft",className:"plan-row-card",children:e.jsx("span",{className:`${p} opacity-75`,children:D(t.entries[0].endedAt)})}),t.entries.map(n=>e.jsx($,{entry:n,highlighted:n.id===l},n.id))]},t.key))]})]})};export{K as TasksPage};
3
- //# sourceMappingURL=index-UPIRvQZS.js.map
1
+ import{u as h,F as v,r,j as e,P as L,R as u,z as y,g as S,q as f,G as b,J as A}from"./main--EStESJz.js";const T={phase:"Phase run",audit:"Audit","batch-reconcile":"Batch reconcile","batch-draft":"Batch draft","run-all":"Run all phases",draft:"Draft",extend:"Extend",suggest:"Suggest ideas","commit-suggest":"Commit suggest","overlap-check":"Overlap check",prioritise:"Prioritise queue",sync:"Sync",reconcile:"Reconcile","fix-review":"Fix review","resolve-conflict":"Resolve conflict",feedback:"Feedback reply","pr-review":"PR review"},m=s=>String(s).padStart(2,"0"),R=s=>{const a=new Date(s);return`${a.getFullYear()}-${m(a.getMonth()+1)}-${m(a.getDate())}`},_=s=>new Date(s).toLocaleDateString(void 0,{weekday:"long",year:"numeric",month:"long",day:"numeric"}),k=s=>{const a=new Date(s);return`${m(a.getHours())}:${m(a.getMinutes())}:${m(a.getSeconds())}`},p="text-sm font-semibold whitespace-nowrap overflow-hidden",N="grid grid-cols-[20px_116px_minmax(0,1fr)_88px_150px_72px] gap-2.5 items-center max-lg:grid-cols-[20px_116px_minmax(0,1fr)_88px_72px] max-[480px]:grid-cols-1 max-[480px]:gap-1",D=({id:s})=>{const[a,c]=r.useState(null),[l,i]=r.useState(!1),[o,x]=r.useState(0);r.useEffect(()=>{let n=!1,d;c(null),i(!1);const g=j=>{b(s).then(w=>{n||c(w.lines??[])}).catch(()=>{if(!n){if(j>0){d=setTimeout(()=>g(j-1),700);return}i(!0),c([])}})};return g(3),()=>{n=!0,d&&clearTimeout(d)}},[s,o]);const t=e.jsx(A,{variant:"ghost",size:"small",onClick:()=>x(n=>n+1),children:"Retry"});return a===null?e.jsx("p",{className:"opacity-50 m-0",children:"Loading…"}):l?e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("p",{className:"opacity-50 m-0",children:"Couldn't load this task's output."}),t]}):a.length===0?e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("p",{className:"opacity-50 m-0",children:"No output recorded."}),t]}):e.jsx("pre",{className:"font-mono text-xs m-0 max-h-[320px] overflow-y-auto whitespace-pre-wrap",children:a.join(`
2
+ `)})},E=({size:s=14,className:a})=>e.jsx("svg",{width:s,height:s,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",className:a,children:e.jsx("polyline",{points:"9 18 15 12 9 6"})}),$=({entry:s,highlighted:a})=>{const[c,l]=r.useState(a);r.useEffect(()=>{a&&l(!0)},[a]);const i=()=>l(o=>!o);return e.jsxs("div",{className:a?"task-row-highlighted flex flex-col gap-1 rounded-[10px] outline outline-2 outline-offset-[-2px] outline-[rgba(200,154,90,0.5)]":"flex flex-col gap-1 rounded-[10px]",children:[e.jsx("div",{role:"button",tabIndex:0,"aria-expanded":c,onClick:i,onKeyDown:o=>{(o.key==="Enter"||o.key===" ")&&(o.preventDefault(),i())},className:"group cursor-pointer rounded-[10px]",children:e.jsx(u,{size:"small",texture:"canvas",className:"plan-row-card",children:e.jsxs("div",{className:N,children:[e.jsx("span",{className:"inline-flex items-center opacity-50",children:e.jsx(E,{className:"group-aria-expanded:rotate-90"})}),e.jsx("span",{className:"font-semibold whitespace-nowrap overflow-hidden",children:T[s.taskKind]??s.taskKind}),e.jsx("span",{className:"overflow-hidden text-ellipsis whitespace-nowrap opacity-70",children:s.planTitle}),e.jsx("span",{className:"text-sm opacity-50 whitespace-nowrap",children:y[s.agentId]}),e.jsxs("span",{className:"max-lg:hidden font-mono text-xs opacity-[0.55] whitespace-nowrap",children:[k(s.startedAt),"–",k(s.endedAt)]}),e.jsx("div",{className:"flex items-center",children:e.jsx(S,{size:"small",fillColor:s.outcome==="done"?"rgba(143, 185, 150, 0.25)":s.outcome==="superseded"?"rgba(212, 163, 115, 0.25)":"rgba(201, 139, 139, 0.25)",textColor:s.outcome==="done"?f.accentGreenDark:s.outcome==="superseded"?f.accentAmberDark:f.accentRoseDark,children:s.outcome})})]})})}),c&&e.jsxs(u,{size:"small",texture:"kraft",className:"plan-row-card",children:[s.outcome==="error"&&s.reason&&e.jsx("p",{className:"m-0 mb-2 text-sm text-state-danger",children:s.reason}),e.jsx(D,{id:s.id})]})]})},I=()=>{const s=h(t=>t.taskLog),a=h(t=>t.taskLogLoading),c=h(t=>t.loadTaskLog),{taskId:l}=v({from:"/tasks"}),i=r.useRef(null);r.useEffect(()=>{c()},[c]),r.useEffect(()=>{var n;if(!l)return;const t=(n=i.current)==null?void 0:n.querySelector(".task-row-highlighted");t==null||t.scrollIntoView({behavior:"smooth",block:"center"})},[l]);const o=[...s].sort((t,n)=>n.endedAt.localeCompare(t.endedAt)),x=[];for(const t of o){const n=R(t.endedAt),d=x.at(-1);(d==null?void 0:d.key)===n?d.entries.push(t):x.push({key:n,entries:[t]})}return e.jsxs("div",{ref:i,children:[e.jsx(L,{children:"Tasks"}),a&&e.jsx("p",{className:"opacity-50",children:"Loading…"}),!a&&o.length===0&&e.jsx("p",{className:"opacity-50",children:"No tasks have run yet."}),!a&&o.length>0&&e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(u,{size:"small",texture:"kraft",className:"plan-row-card",children:e.jsxs("div",{className:N,children:[e.jsx("span",{}),e.jsx("span",{className:`${p} opacity-60`,children:"Task"}),e.jsx("span",{className:`${p} opacity-60`,children:"Plan"}),e.jsx("span",{className:`${p} opacity-60`,children:"Agent"}),e.jsx("span",{className:`max-lg:hidden ${p} opacity-60`,children:"Time"}),e.jsx("span",{className:`${p} opacity-60`,children:"Outcome"})]})}),x.map(t=>e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(u,{size:"small",texture:"kraft",className:"plan-row-card",children:e.jsx("span",{className:`${p} opacity-75`,children:_(t.entries[0].endedAt)})}),t.entries.map(n=>e.jsx($,{entry:n,highlighted:n.id===l},n.id))]},t.key))]})]})};export{I as TasksPage};
3
+ //# sourceMappingURL=index-nuVVSVma.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-nuVVSVma.js","sources":["../../../src/app/features/tasks/tasks-page.tsx"],"sourcesContent":["import { PageTitle } from '@/app/components/page-title';\nimport { fetchTaskLogLines } from '@/app/services/content/docs-api';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { color } from '@/app/styles/tokens';\nimport { AGENT_LABELS, type TaskKind, type TaskLogEntry } from '@/types/index';\nimport { Button, Card, Stamp } from '@dendelion/paper-ui';\nimport { useSearch } from '@tanstack/react-router';\nimport { useEffect, useRef, useState } from 'react';\n\nconst TASK_KIND_LABELS: Record<TaskKind, string> = {\n phase: 'Phase run',\n audit: 'Audit',\n 'batch-reconcile': 'Batch reconcile',\n 'batch-draft': 'Batch draft',\n 'run-all': 'Run all phases',\n draft: 'Draft',\n extend: 'Extend',\n suggest: 'Suggest ideas',\n 'commit-suggest': 'Commit suggest',\n 'overlap-check': 'Overlap check',\n prioritise: 'Prioritise queue',\n sync: 'Sync',\n reconcile: 'Reconcile',\n 'fix-review': 'Fix review',\n 'resolve-conflict': 'Resolve conflict',\n feedback: 'Feedback reply',\n 'pr-review': 'PR review',\n};\n\nconst pad = (n: number) => String(n).padStart(2, '0');\n\nconst dayKey = (iso: string) => {\n const d = new Date(iso);\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;\n};\n\nconst formatDayHeader = (iso: string) =>\n new Date(iso).toLocaleDateString(undefined, {\n weekday: 'long',\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n });\n\nconst formatTime = (iso: string) => {\n const d = new Date(iso);\n return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;\n};\n\nconst headerLabelClassName = 'text-sm font-semibold whitespace-nowrap overflow-hidden';\n\nconst TASK_ROWS_GRID_CLASS =\n 'grid grid-cols-[20px_116px_minmax(0,1fr)_88px_150px_72px] gap-2.5 items-center max-lg:grid-cols-[20px_116px_minmax(0,1fr)_88px_72px] max-[480px]:grid-cols-1 max-[480px]:gap-1';\n\nconst TaskLogLines = ({ id }: { id: string }) => {\n const [lines, setLines] = useState<string[] | null>(null);\n const [failed, setFailed] = useState(false);\n const [attempt, setAttempt] = useState(0);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: attempt is the retry trigger (re-runs the fetch), not a value read in the body.\n useEffect(() => {\n let cancelled = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n setLines(null);\n setFailed(false);\n // Auto-retry first (dev server briefly drops requests on hot reload); manual Retry only if it stays down.\n const load = (remaining: number) => {\n fetchTaskLogLines(id)\n .then((data) => {\n if (cancelled) return;\n setLines(data.lines ?? []);\n })\n .catch(() => {\n if (cancelled) return;\n if (remaining > 0) {\n timer = setTimeout(() => load(remaining - 1), 700);\n return;\n }\n // Empty result != failed request: conflating them mislabels a fetch error as \"no output\".\n setFailed(true);\n setLines([]);\n });\n };\n load(3);\n return () => {\n cancelled = true;\n if (timer) clearTimeout(timer);\n };\n }, [id, attempt]);\n\n const retry = (\n <Button variant=\"ghost\" size=\"small\" onClick={() => setAttempt((n) => n + 1)}>\n Retry\n </Button>\n );\n\n if (lines === null) return <p className=\"opacity-50 m-0\">Loading…</p>;\n if (failed)\n return (\n <div className=\"flex items-center gap-2\">\n <p className=\"opacity-50 m-0\">Couldn't load this task's output.</p>\n {retry}\n </div>\n );\n if (lines.length === 0)\n return (\n <div className=\"flex items-center gap-2\">\n <p className=\"opacity-50 m-0\">No output recorded.</p>\n {retry}\n </div>\n );\n return (\n <pre className=\"font-mono text-xs m-0 max-h-[320px] overflow-y-auto whitespace-pre-wrap\">\n {lines.join('\\n')}\n </pre>\n );\n};\n\nconst ChevronRightIcon = ({ size = 14, className }: { size?: number; className?: string }) => (\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 className={className}\n >\n <polyline points=\"9 18 15 12 9 6\" />\n </svg>\n);\n\nconst TaskRow = ({ entry, highlighted }: { entry: TaskLogEntry; highlighted: boolean }) => {\n const [expanded, setExpanded] = useState(highlighted);\n useEffect(() => {\n if (highlighted) setExpanded(true);\n }, [highlighted]);\n const toggle = () => setExpanded((v) => !v);\n\n return (\n <div\n className={\n highlighted\n ? 'task-row-highlighted flex flex-col gap-1 rounded-[10px] outline outline-2 outline-offset-[-2px] outline-[rgba(200,154,90,0.5)]'\n : 'flex flex-col gap-1 rounded-[10px]'\n }\n >\n {/* biome-ignore lint/a11y/useSemanticElements: the clickable row wraps a Card whose block layout a native <button> would break; keyboard toggling is wired on the div. */}\n <div\n role=\"button\"\n tabIndex={0}\n aria-expanded={expanded}\n onClick={toggle}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n toggle();\n }\n }}\n className=\"group cursor-pointer rounded-[10px]\"\n >\n <Card size=\"small\" texture=\"canvas\" className=\"plan-row-card\">\n <div className={TASK_ROWS_GRID_CLASS}>\n <span className=\"inline-flex items-center opacity-50\">\n <ChevronRightIcon className=\"group-aria-expanded:rotate-90\" />\n </span>\n <span className=\"font-semibold whitespace-nowrap overflow-hidden\">\n {TASK_KIND_LABELS[entry.taskKind] ?? entry.taskKind}\n </span>\n <span className=\"overflow-hidden text-ellipsis whitespace-nowrap opacity-70\">\n {entry.planTitle}\n </span>\n <span className=\"text-sm opacity-50 whitespace-nowrap\">\n {AGENT_LABELS[entry.agentId]}\n </span>\n <span className=\"max-lg:hidden font-mono text-xs opacity-[0.55] whitespace-nowrap\">\n {formatTime(entry.startedAt)}–{formatTime(entry.endedAt)}\n </span>\n <div className=\"flex items-center\">\n <Stamp\n size=\"small\"\n fillColor={\n entry.outcome === 'done'\n ? 'rgba(143, 185, 150, 0.25)'\n : entry.outcome === 'superseded'\n ? 'rgba(212, 163, 115, 0.25)'\n : 'rgba(201, 139, 139, 0.25)'\n }\n textColor={\n entry.outcome === 'done'\n ? color.accentGreenDark\n : entry.outcome === 'superseded'\n ? color.accentAmberDark\n : color.accentRoseDark\n }\n >\n {entry.outcome}\n </Stamp>\n </div>\n </div>\n </Card>\n </div>\n {expanded && (\n <Card size=\"small\" texture=\"kraft\" className=\"plan-row-card\">\n {entry.outcome === 'error' && entry.reason && (\n <p className=\"m-0 mb-2 text-sm text-state-danger\">{entry.reason}</p>\n )}\n <TaskLogLines id={entry.id} />\n </Card>\n )}\n </div>\n );\n};\n\nexport const TasksPage = () => {\n const taskLog = useAppStore((s) => s.taskLog);\n const taskLogLoading = useAppStore((s) => s.taskLogLoading);\n const loadTaskLog = useAppStore((s) => s.loadTaskLog);\n const { taskId } = useSearch({ from: '/tasks' });\n const containerRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n loadTaskLog();\n }, [loadTaskLog]);\n\n useEffect(() => {\n if (!taskId) return;\n const row = containerRef.current?.querySelector('.task-row-highlighted');\n row?.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }, [taskId]);\n\n const sorted = [...taskLog].sort((a, b) => b.endedAt.localeCompare(a.endedAt));\n\n const groups: { key: string; entries: TaskLogEntry[] }[] = [];\n for (const entry of sorted) {\n const key = dayKey(entry.endedAt);\n const group = groups.at(-1);\n if (group?.key === key) group.entries.push(entry);\n else groups.push({ key, entries: [entry] });\n }\n\n return (\n <div ref={containerRef}>\n <PageTitle>Tasks</PageTitle>\n {taskLogLoading && <p className=\"opacity-50\">Loading…</p>}\n {!taskLogLoading && sorted.length === 0 && (\n <p className=\"opacity-50\">No tasks have run yet.</p>\n )}\n {!taskLogLoading && sorted.length > 0 && (\n <div className=\"flex flex-col gap-1\">\n <Card size=\"small\" texture=\"kraft\" className=\"plan-row-card\">\n <div className={TASK_ROWS_GRID_CLASS}>\n <span />\n <span className={`${headerLabelClassName} opacity-60`}>Task</span>\n <span className={`${headerLabelClassName} opacity-60`}>Plan</span>\n <span className={`${headerLabelClassName} opacity-60`}>Agent</span>\n <span className={`max-lg:hidden ${headerLabelClassName} opacity-60`}>Time</span>\n <span className={`${headerLabelClassName} opacity-60`}>Outcome</span>\n </div>\n </Card>\n {groups.map((group) => (\n <div key={group.key} className=\"flex flex-col gap-1\">\n <Card size=\"small\" texture=\"kraft\" className=\"plan-row-card\">\n <span className={`${headerLabelClassName} opacity-75`}>\n {formatDayHeader(group.entries[0].endedAt)}\n </span>\n </Card>\n {group.entries.map((entry) => (\n <TaskRow key={entry.id} entry={entry} highlighted={entry.id === taskId} />\n ))}\n </div>\n ))}\n </div>\n )}\n </div>\n );\n};\n"],"names":["TASK_KIND_LABELS","pad","n","dayKey","iso","d","formatDayHeader","formatTime","headerLabelClassName","TASK_ROWS_GRID_CLASS","TaskLogLines","id","lines","setLines","useState","failed","setFailed","attempt","setAttempt","useEffect","cancelled","timer","load","remaining","fetchTaskLogLines","data","retry","jsx","Button","jsxs","ChevronRightIcon","size","className","TaskRow","entry","highlighted","expanded","setExpanded","toggle","v","e","Card","AGENT_LABELS","Stamp","color","TasksPage","taskLog","useAppStore","s","taskLogLoading","loadTaskLog","taskId","useSearch","containerRef","useRef","row","_a","sorted","a","b","groups","key","group","PageTitle"],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import{j as s,g as u,u as f,a3 as F,a4 as D,a5 as E,r as h,a6 as L,J as b,$ as P,a7 as $,P as j,a8 as v,a9 as w,aa as A,ab as T,w as I,C as R,ac as _,p as G,ad as M,ae as y,K as z}from"./main--EStESJz.js";const U=/^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/;function H(e){if(!e)return[];const a=(e.endsWith(`
2
+ `)?e.slice(0,-1):e).split(`
3
+ `),i=[];let n=null,l=0,o=0;for(const c of a){const d=c.match(U);if(d){n={header:c,lines:[]},i.push(n),l=Number(d[1]),o=Number(d[2]);continue}n&&(c.startsWith("\\")||(c.startsWith("+")?(n.lines.push({type:"add",text:c.slice(1),oldLine:null,newLine:o}),o++):c.startsWith("-")?(n.lines.push({type:"remove",text:c.slice(1),oldLine:l,newLine:null}),l++):(n.lines.push({type:"context",text:c.startsWith(" ")?c.slice(1):c,oldLine:l,newLine:o}),l++,o++)))}return i}function K(e){return e?[{header:"",lines:(e.endsWith(`
4
+ `)?e.slice(0,-1):e).split(`
5
+ `).map((i,n)=>({type:"add",text:i,oldLine:null,newLine:n+1}))}]:[]}const C=({additions:e,deletions:a})=>s.jsxs("span",{className:"inline-flex shrink-0 gap-2 font-mono text-2xs",children:[s.jsxs("span",{className:"text-watercolor-green-dark",children:["+",e]}),s.jsxs("span",{className:"text-watercolor-rose-dark",children:["-",a]})]});function O(e){const a=e.lastIndexOf("/");return a===-1?{dir:"",base:e}:{dir:e.slice(0,a+1),base:e.slice(a+1)}}const S=({path:e,prefix:a,className:i=""})=>{const{dir:n,base:l}=O(e),o=`${a??""}${n}`;return s.jsxs("span",{className:`flex min-w-0 items-center font-mono ${i}`,children:[o&&s.jsx("span",{className:"min-w-0 overflow-hidden text-ellipsis whitespace-nowrap opacity-50",children:o}),s.jsx("span",{className:"shrink-0 whitespace-nowrap",children:l})]})},W={A:{letter:"A",label:"Added",variant:"success"},M:{letter:"M",label:"Modified",variant:"info"},D:{letter:"D",label:"Deleted",variant:"error"},R:{letter:"R",label:"Renamed",variant:"info"},C:{letter:"C",label:"Copied",variant:"info"},U:{letter:"U",label:"Conflicted",variant:"warning"}},B=e=>{if(e==="??")return{letter:"??",label:"Untracked",variant:"neutral"};const[a,i]=e,n=a!==" "&&a!=="?"?a:i;return W[n]??{letter:n??"?",label:n??"Unknown",variant:"neutral"}},k=({status:e})=>{const a=B(e);return s.jsx("span",{title:a.label,children:s.jsx(u,{size:"small",variant:a.variant,children:a.letter})})},q=60,J={add:"bg-watercolor-green/[18%] text-watercolor-green-dark",remove:"bg-watercolor-rose/[18%] text-watercolor-rose-dark",context:""},Q={add:"+",remove:"-",context:" "},V=({entry:e})=>s.jsxs("div",{className:"flex w-full min-w-0 items-center gap-3",children:[s.jsx(k,{status:e.status}),s.jsx(S,{path:e.path,prefix:e.renameSource?`${e.renameSource} → `:void 0,className:"min-w-0 flex-1 text-xs"}),s.jsxs("span",{className:"flex shrink-0 items-center gap-2",children:[e.staged&&s.jsx(u,{size:"small",children:"staged"}),!e.binary&&s.jsx(C,{additions:e.additions,deletions:e.deletions})]})]}),X=({entry:e})=>{if(e.binary)return s.jsx("p",{className:"m-0 opacity-60",children:"Binary file not shown."});if(e.contentKind==="too-large")return s.jsx("p",{className:"m-0 opacity-60",children:"File too large to preview."});const a=e.contentKind==="raw"?K(e.patch):H(e.patch);return a.length===0?e.renameSource?s.jsx("p",{className:"m-0 opacity-60",children:e.additions===0&&e.deletions===0?"Renamed, no content changes.":"Renamed with unrelated content — diff omitted."}):s.jsx("p",{className:"m-0 opacity-60",children:"No changes to preview."}):s.jsx("div",{className:"flex min-w-0 max-w-full flex-col gap-3",children:a.map((i,n)=>s.jsxs("div",{className:"min-w-0 max-w-full",children:[i.header&&s.jsx("div",{className:"mb-1 font-mono text-2xs opacity-50",children:i.header}),s.jsx("pre",{className:"m-0 min-w-0 max-w-full overflow-x-auto font-mono text-2xs leading-normal",children:i.lines.map((l,o)=>s.jsxs("span",{className:`flex ${J[l.type]}`,children:[s.jsxs("span",{className:"inline-flex shrink-0 select-none gap-2 pr-2 opacity-40","aria-hidden":"true",children:[s.jsx("span",{className:"w-8 text-right",children:l.oldLine??""}),s.jsx("span",{className:"w-8 text-right",children:l.newLine??""})]}),s.jsxs("span",{children:[Q[l.type],l.text]})]},`${l.type}-${o}`))})]},`${i.header}-${n}`))})},Y=({entry:e})=>{const a=f(c=>c.manuallyExpandedDiffPaths.has(e.path)),i=f(c=>c.manuallyCollapsedDiffPaths.has(e.path)),n=f(c=>c.setDiffCollapsed),l=i||!a&&e.additions+e.deletions>q,o=e.renameSource?`${e.renameSource} → ${e.path}`:e.path;return s.jsxs("div",{"data-diff-path":e.path,className:"min-w-0 max-w-full scroll-mt-4",children:[s.jsx("h2",{className:"sr-only",children:o}),s.jsx(F,{title:s.jsx(V,{entry:e}),expanded:!l,onToggle:()=>n(e.path,!l),children:s.jsx(X,{entry:e})})]})},Z="__git__",ee=()=>!0,se=e=>D(e,{formKey:Z,matchesSuggestionTask:ee}),te=({state:e,filesEmpty:a})=>{const i=f(r=>r.status),{checks:n}=E(),{qualityStatus:l,testStatus:o,consistencyStatus:c}=h.useMemo(()=>L(i,n),[i,n]),d=[l==="fail"&&"Quality",o==="fail"&&"Tests",c==="fail"&&"Consistency"].filter(r=>r!==!1),t=s.jsx(b,{size:"small",disabled:a||!e.commitTitle.trim()||e.committing||e.commitInFlight,onClick:e.handleCommit,children:e.committing||e.commitInFlight?"Committing…":e.stagedCount>0?`Commit ${e.stagedCount} staged`:"Commit"});return d.length===0?t:s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx(P,{content:`${d.join(", ")} failing`,children:s.jsx(u,{size:"small",variant:"warning",children:"!"})}),t]})},ce=()=>{const e=f(t=>t.diffFiles),a=f(t=>t.diffLoadFailed),i=f(t=>t.loadDiffFiles),n=f(t=>t.setActiveDiffPath),l=h.useRef(null),o=h.useMemo(()=>(e==null?void 0:e.map(t=>({path:t.path,staged:t.staged})))??[],[e]),c=se(o);h.useEffect(()=>{i()},[i]),h.useEffect(()=>{let t;const r=$(x=>{x.message==="changed"&&(t&&clearTimeout(t),t=setTimeout(i,250))}),m=()=>i();return window.addEventListener("focus",m),()=>{t&&clearTimeout(t),window.removeEventListener("focus",m),r()}},[i]),h.useEffect(()=>{const t=l.current;if(!t)return;const r=Array.from(t.querySelectorAll("[data-diff-path]"));if(r.length===0)return;const m=new Set,x=new IntersectionObserver(g=>{for(const p of g)p.isIntersecting?m.add(p.target):m.delete(p.target);const N=r.find(p=>m.has(p));N&&n(N.dataset.diffPath??null)},{rootMargin:"0px 0px -70% 0px"});for(const g of r)x.observe(g);return()=>x.disconnect()},[e,n]);const d="min-h-page";return a?s.jsxs("div",{children:[s.jsx(j,{children:"Git"}),s.jsxs("div",{className:"mb-4 flex items-center gap-2",children:[s.jsx(v,{}),s.jsx(w,{})]}),s.jsxs("div",{className:`${d} flex flex-col items-start gap-3`,children:[s.jsx("p",{className:"opacity-50 m-0",children:"Couldn't load the working-tree diff."}),s.jsx(b,{variant:"secondary",size:"small",onClick:i,children:"Retry"})]})]}):e?s.jsxs("div",{children:[s.jsx(j,{children:"Git"}),s.jsxs("div",{className:"mb-4 flex items-center gap-2",children:[s.jsx(v,{}),s.jsx(w,{})]}),e.length===0?s.jsx("div",{className:d,children:s.jsx("p",{className:"opacity-50",children:"No changed files."})}):s.jsxs(s.Fragment,{children:[s.jsxs("div",{className:"sticky top-0 z-10 mb-6 flex items-start gap-2 bg-[var(--pui-bg-base)] py-3 shadow-paper-sm",children:[s.jsx("div",{className:"flex-1",children:s.jsx(T,{state:c,filesEmpty:!1})}),s.jsx(te,{state:c,filesEmpty:!1})]}),s.jsx("div",{ref:l,className:`flex min-w-0 flex-col gap-6 ${d}`,children:e.map((t,r)=>s.jsxs(h.Fragment,{children:[r>0&&s.jsx(I,{}),s.jsx(Y,{entry:t})]},t.path))})]})]}):s.jsxs("div",{children:[s.jsx(j,{children:"Git"}),s.jsxs("div",{className:"mb-4 flex items-center gap-2",children:[s.jsx(v,{}),s.jsx(w,{})]}),s.jsx("div",{className:d,children:s.jsx(A,{label:"Loading the working-tree diff…"})})]})},ae="text-2xs font-semibold tracking-[0.08em] uppercase text-ink-300 mb-2",ie=(e,a)=>{a(e),requestAnimationFrame(()=>{var i;(i=document.querySelector(`[data-diff-path="${CSS.escape(e)}"]`))==null||i.scrollIntoView({behavior:"smooth",block:"start"})})},ne=e=>{const[a,i]=e;return a!==" "&&a!=="?"&&i!==" "&&i!=="?"},oe=()=>{const e=f(t=>t.diffFiles),a=f(t=>t.activeDiffPath),i=f(t=>t.loadDiffFiles),n=f(t=>t.expandDiffPath),[l,o]=h.useState(new Set),{toast:c}=R();if(!e||e.length===0)return null;const d=async(t,r)=>{o(m=>new Set(m).add(t.path));try{await(r?M(t.path):y(t.path)),await i()}catch(m){c({title:r?"Stage failed":"Unstage failed",description:z(m.message),variant:"error"})}finally{o(m=>{const x=new Set(m);return x.delete(t.path),x})}};return s.jsx("nav",{"aria-label":"Changed files",className:"flex flex-col gap-8 -mt-5",children:s.jsxs("div",{children:[s.jsx("div",{className:ae,children:"Changed files"}),s.jsx("ul",{className:"m-0 flex list-none flex-col gap-1 p-0",children:e.map(t=>s.jsxs("li",{className:"flex items-center gap-2",children:[s.jsx(_,{checked:t.staged,indeterminate:ne(t.status),disabled:l.has(t.path),onChange:r=>d(t,r.target.checked),"aria-label":t.staged?`Unstage ${t.path}`:`Stage ${t.path}`}),s.jsx(k,{status:t.status}),s.jsx(G,{size:"small",active:t.path===a,onClick:()=>ie(t.path,n),className:"flex-1",action:s.jsxs("span",{className:"flex items-center gap-2",children:[t.staged&&s.jsx(u,{size:"small",children:"staged"}),!t.binary&&s.jsx(C,{additions:t.additions,deletions:t.deletions})]}),children:s.jsx(S,{path:t.path,className:"text-2xs"})})]},t.path))})]})})};export{oe as GitFileList,ce as GitPage};
6
+ //# sourceMappingURL=index-s6CVH54G.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-s6CVH54G.js","sources":["../../../src/app/utils/parse-diff.ts","../../../src/app/features/git/count-badge.tsx","../../../src/app/utils/path-display.ts","../../../src/app/features/git/file-path.tsx","../../../src/app/features/git/git-status-marker.tsx","../../../src/app/features/git/file-diff-section.tsx","../../../src/app/features/git/git-commit-controls.tsx","../../../src/app/features/git/git-page.tsx","../../../src/app/features/git/git-file-list.tsx"],"sourcesContent":["export type DiffLineType = 'add' | 'remove' | 'context';\n\nexport interface DiffLine {\n type: DiffLineType;\n text: string;\n oldLine: number | null;\n newLine: number | null;\n}\n\nexport interface DiffHunk {\n header: string;\n lines: DiffLine[];\n}\n\nconst HUNK_HEADER = /^@@ -(\\d+)(?:,\\d+)? \\+(\\d+)(?:,\\d+)? @@/;\n\n// Parses a unified diff (git.ts getWorkingDiff, contentKind: 'diff'). A real diff\n// with no hunks (pure rename, mode-only change) is just the preamble, so it yields [].\nexport function parsePatch(patch: string): DiffHunk[] {\n if (!patch) return [];\n const lines = (patch.endsWith('\\n') ? patch.slice(0, -1) : patch).split('\\n');\n\n const hunks: DiffHunk[] = [];\n let current: DiffHunk | null = null;\n let oldLine = 0;\n let newLine = 0;\n for (const line of lines) {\n const header = line.match(HUNK_HEADER);\n if (header) {\n current = { header: line, lines: [] };\n hunks.push(current);\n oldLine = Number(header[1]);\n newLine = Number(header[2]);\n continue;\n }\n if (!current) continue; // preamble: diff --git / index / --- / +++\n if (line.startsWith('\\\\')) continue; // \"\\"\n if (line.startsWith('+')) {\n current.lines.push({ type: 'add', text: line.slice(1), oldLine: null, newLine });\n newLine++;\n } else if (line.startsWith('-')) {\n current.lines.push({ type: 'remove', text: line.slice(1), oldLine, newLine: null });\n oldLine++;\n } else {\n current.lines.push({\n type: 'context',\n text: line.startsWith(' ') ? line.slice(1) : line,\n oldLine,\n newLine,\n });\n oldLine++;\n newLine++;\n }\n }\n return hunks;\n}\n\n// Untracked files store raw content, not a diff (git.ts getWorkingDiff, contentKind:\n// 'raw') — synthesize a single all-added hunk so the renderer only has one shape to draw.\nexport function rawContentHunks(content: string): DiffHunk[] {\n if (!content) return [];\n const lines = (content.endsWith('\\n') ? content.slice(0, -1) : content).split('\\n');\n return [\n {\n header: '',\n lines: lines.map((text, i) => ({ type: 'add', text, oldLine: null, newLine: i + 1 })),\n },\n ];\n}\n","interface CountBadgeProps {\n additions: number;\n deletions: number;\n}\n\nexport const CountBadge = ({ additions, deletions }: CountBadgeProps) => (\n <span className=\"inline-flex shrink-0 gap-2 font-mono text-2xs\">\n <span className=\"text-watercolor-green-dark\">+{additions}</span>\n <span className=\"text-watercolor-rose-dark\">-{deletions}</span>\n </span>\n);\n","export interface SplitPath {\n dir: string;\n base: string;\n}\n\nexport function splitPathForDisplay(path: string): SplitPath {\n const slash = path.lastIndexOf('/');\n return slash === -1\n ? { dir: '', base: path }\n : { dir: path.slice(0, slash + 1), base: path.slice(slash + 1) };\n}\n","import { splitPathForDisplay } from '@/app/utils/path-display';\n\ninterface FilePathProps {\n path: string;\n prefix?: string;\n className?: string;\n}\n\nexport const FilePath = ({ path, prefix, className = '' }: FilePathProps) => {\n const { dir, base } = splitPathForDisplay(path);\n const dimmed = `${prefix ?? ''}${dir}`;\n return (\n <span className={`flex min-w-0 items-center font-mono ${className}`}>\n {dimmed && (\n <span className=\"min-w-0 overflow-hidden text-ellipsis whitespace-nowrap opacity-50\">\n {dimmed}\n </span>\n )}\n <span className=\"shrink-0 whitespace-nowrap\">{base}</span>\n </span>\n );\n};\n","import { Stamp, type StampVariant } from '@dendelion/paper-ui';\n\ninterface StatusInfo {\n letter: string;\n label: string;\n variant: StampVariant;\n}\n\nconst STATUS_INFO: Record<string, StatusInfo> = {\n A: { letter: 'A', label: 'Added', variant: 'success' },\n M: { letter: 'M', label: 'Modified', variant: 'info' },\n D: { letter: 'D', label: 'Deleted', variant: 'error' },\n R: { letter: 'R', label: 'Renamed', variant: 'info' },\n C: { letter: 'C', label: 'Copied', variant: 'info' },\n U: { letter: 'U', label: 'Conflicted', variant: 'warning' },\n};\n\n// Git's porcelain code is two characters: index status then worktree status.\n// The index one wins when both are set — it's the state that would actually commit.\nexport const gitStatusInfo = (status: string): StatusInfo => {\n if (status === '??') return { letter: '??', label: 'Untracked', variant: 'neutral' };\n const [x, y] = status;\n const code = x !== ' ' && x !== '?' ? x : y;\n return STATUS_INFO[code] ?? { letter: code ?? '?', label: code ?? 'Unknown', variant: 'neutral' };\n};\n\ninterface GitStatusMarkerProps {\n status: string;\n}\n\nexport const GitStatusMarker = ({ status }: GitStatusMarkerProps) => {\n const info = gitStatusInfo(status);\n return (\n <span title={info.label}>\n <Stamp size=\"small\" variant={info.variant}>\n {info.letter}\n </Stamp>\n </span>\n );\n};\n","import { useAppStore } from '@/app/stores/app-store';\nimport { type DiffLineType, parsePatch, rawContentHunks } from '@/app/utils/parse-diff';\nimport type { FileDiffEntry } from '@/types/index';\nimport { Accordion, Stamp } from '@dendelion/paper-ui';\nimport { CountBadge } from './count-badge';\nimport { FilePath } from './file-path';\nimport { GitStatusMarker } from './git-status-marker';\n\nconst COLLAPSE_LINE_THRESHOLD = 60;\n\nconst LINE_CLASS: Record<DiffLineType, string> = {\n add: 'bg-watercolor-green/[18%] text-watercolor-green-dark',\n remove: 'bg-watercolor-rose/[18%] text-watercolor-rose-dark',\n context: '',\n};\n\nconst LINE_PREFIX: Record<DiffLineType, string> = { add: '+', remove: '-', context: ' ' };\n\ninterface FileHeaderProps {\n entry: FileDiffEntry;\n}\n\nconst FileHeader = ({ entry }: FileHeaderProps) => (\n <div className=\"flex w-full min-w-0 items-center gap-3\">\n <GitStatusMarker status={entry.status} />\n <FilePath\n path={entry.path}\n prefix={entry.renameSource ? `${entry.renameSource} → ` : undefined}\n className=\"min-w-0 flex-1 text-xs\"\n />\n <span className=\"flex shrink-0 items-center gap-2\">\n {entry.staged && <Stamp size=\"small\">staged</Stamp>}\n {!entry.binary && <CountBadge additions={entry.additions} deletions={entry.deletions} />}\n </span>\n </div>\n);\n\ninterface DiffBodyProps {\n entry: FileDiffEntry;\n}\n\nconst DiffBody = ({ entry }: DiffBodyProps) => {\n if (entry.binary) {\n return <p className=\"m-0 opacity-60\">Binary file not shown.</p>;\n }\n if (entry.contentKind === 'too-large') {\n return <p className=\"m-0 opacity-60\">File too large to preview.</p>;\n }\n const hunks =\n entry.contentKind === 'raw' ? rawContentHunks(entry.patch) : parsePatch(entry.patch);\n if (hunks.length === 0) {\n if (entry.renameSource) {\n return (\n <p className=\"m-0 opacity-60\">\n {entry.additions === 0 && entry.deletions === 0\n ? 'Renamed, no content changes.'\n : 'Renamed with unrelated content — diff omitted.'}\n </p>\n );\n }\n return <p className=\"m-0 opacity-60\">No changes to preview.</p>;\n }\n return (\n <div className=\"flex min-w-0 max-w-full flex-col gap-3\">\n {hunks.map((hunk, i) => (\n <div key={`${hunk.header}-${i}`} className=\"min-w-0 max-w-full\">\n {hunk.header && <div className=\"mb-1 font-mono text-2xs opacity-50\">{hunk.header}</div>}\n {/* paper-ui's CodeBlock has no per-line add/remove styling. */}\n <pre className=\"m-0 min-w-0 max-w-full overflow-x-auto font-mono text-2xs leading-normal\">\n {hunk.lines.map((line, j) => (\n <span key={`${line.type}-${j}`} className={`flex ${LINE_CLASS[line.type]}`}>\n <span\n className=\"inline-flex shrink-0 select-none gap-2 pr-2 opacity-40\"\n aria-hidden=\"true\"\n >\n <span className=\"w-8 text-right\">{line.oldLine ?? ''}</span>\n <span className=\"w-8 text-right\">{line.newLine ?? ''}</span>\n </span>\n <span>\n {LINE_PREFIX[line.type]}\n {line.text}\n </span>\n </span>\n ))}\n </pre>\n </div>\n ))}\n </div>\n );\n};\n\ninterface FileDiffSectionProps {\n entry: FileDiffEntry;\n}\n\nexport const FileDiffSection = ({ entry }: FileDiffSectionProps) => {\n const manuallyExpanded = useAppStore((s) => s.manuallyExpandedDiffPaths.has(entry.path));\n const manuallyCollapsed = useAppStore((s) => s.manuallyCollapsedDiffPaths.has(entry.path));\n const setDiffCollapsed = useAppStore((s) => s.setDiffCollapsed);\n const collapsed =\n manuallyCollapsed ||\n (!manuallyExpanded && entry.additions + entry.deletions > COLLAPSE_LINE_THRESHOLD);\n\n const headingText = entry.renameSource ? `${entry.renameSource} → ${entry.path}` : entry.path;\n\n return (\n <div data-diff-path={entry.path} className=\"min-w-0 max-w-full scroll-mt-4\">\n <h2 className=\"sr-only\">{headingText}</h2>\n <Accordion\n title={<FileHeader entry={entry} />}\n expanded={!collapsed}\n onToggle={() => setDiffCollapsed(entry.path, !collapsed)}\n >\n <DiffBody entry={entry} />\n </Accordion>\n </div>\n );\n};\n","import { type CommitFormFile, useCommitForm } from '@/app/hooks/use-commit-form';\nimport { useDeskChecks } from '@/app/hooks/use-desk-checks';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { deriveCheckStatuses } from '@/app/utils/check-status';\nimport { Button, Stamp, Tooltip } from '@dendelion/paper-ui';\nimport { useMemo } from 'react';\n\n// Stable across renders, and the same value used before this idea's staging/body\n// work — keeps drafts saved under the git page's key from being orphaned.\nconst GIT_PAGE_FORM_KEY = '__git__';\n\nconst matchAnySuggestionTask = () => true;\n\n// No plan on the git page, so this is bare commit mechanics — no phase recording, no Fix.\nexport const useGitCommitForm = (files: CommitFormFile[]) =>\n useCommitForm(files, {\n formKey: GIT_PAGE_FORM_KEY,\n matchesSuggestionTask: matchAnySuggestionTask,\n });\n\nexport type GitCommitFormState = ReturnType<typeof useGitCommitForm>;\n\n// Never Fix (plan-scoped, and the git page never has one) — a failing check is a warning instead.\nexport const GitCommitButton = ({\n state,\n filesEmpty,\n}: {\n state: GitCommitFormState;\n filesEmpty: boolean;\n}) => {\n const status = useAppStore((s) => s.status);\n const { checks: deskChecks } = useDeskChecks();\n const { qualityStatus, testStatus, consistencyStatus } = useMemo(\n () => deriveCheckStatuses(status, deskChecks),\n [status, deskChecks],\n );\n const failingChecks = [\n qualityStatus === 'fail' && 'Quality',\n testStatus === 'fail' && 'Tests',\n consistencyStatus === 'fail' && 'Consistency',\n ].filter((label): label is Exclude<typeof label, false> => label !== false);\n\n const commitButton = (\n <Button\n size=\"small\"\n disabled={filesEmpty || !state.commitTitle.trim() || state.committing || state.commitInFlight}\n onClick={state.handleCommit}\n >\n {state.committing || state.commitInFlight\n ? 'Committing…'\n : state.stagedCount > 0\n ? `Commit ${state.stagedCount} staged`\n : 'Commit'}\n </Button>\n );\n\n if (failingChecks.length === 0) return commitButton;\n\n return (\n <div className=\"flex items-center gap-2\">\n <Tooltip content={`${failingChecks.join(', ')} failing`}>\n <Stamp size=\"small\" variant=\"warning\">\n !\n </Stamp>\n </Tooltip>\n {commitButton}\n </div>\n );\n};\n","import { CommitMessageFields, GitStashSurface, GitSyncActions } from '@/app/components';\nimport { PageTitle } from '@/app/components/page-title';\nimport { FileDiffSection } from '@/app/features/git/file-diff-section';\nimport { GitCommitButton, useGitCommitForm } from '@/app/features/git/git-commit-controls';\nimport { subscribeToActivityStream } from '@/app/services/activity-stream';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { Button, Divider, Spinner } from '@dendelion/paper-ui';\nimport { Fragment, useEffect, useMemo, useRef } from 'react';\n\nexport const GitPage = () => {\n const files = useAppStore((s) => s.diffFiles);\n const loadFailed = useAppStore((s) => s.diffLoadFailed);\n const loadDiffFiles = useAppStore((s) => s.loadDiffFiles);\n const setActiveDiffPath = useAppStore((s) => s.setActiveDiffPath);\n const sectionsRef = useRef<HTMLDivElement>(null);\n const commitFiles = useMemo(\n () => files?.map((entry) => ({ path: entry.path, staged: entry.staged })) ?? [],\n [files],\n );\n const commitForm = useGitCommitForm(commitFiles);\n\n useEffect(() => {\n loadDiffFiles();\n }, [loadDiffFiles]);\n\n useEffect(() => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n const unsubscribe = subscribeToActivityStream((payload) => {\n if (payload.message !== 'changed') return;\n if (timer) clearTimeout(timer);\n timer = setTimeout(loadDiffFiles, 250);\n });\n const onFocus = () => loadDiffFiles();\n window.addEventListener('focus', onFocus);\n return () => {\n if (timer) clearTimeout(timer);\n window.removeEventListener('focus', onFocus);\n unsubscribe();\n };\n }, [loadDiffFiles]);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: files is the trigger to rebuild the observer, not a value read in the body.\n useEffect(() => {\n const root = sectionsRef.current;\n if (!root) return;\n const sections = Array.from(root.querySelectorAll<HTMLElement>('[data-diff-path]'));\n if (sections.length === 0) return;\n const visible = new Set<HTMLElement>();\n const observer = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n if (entry.isIntersecting) visible.add(entry.target as HTMLElement);\n else visible.delete(entry.target as HTMLElement);\n }\n const topmost = sections.find((el) => visible.has(el));\n if (topmost) setActiveDiffPath(topmost.dataset.diffPath ?? null);\n },\n { rootMargin: '0px 0px -70% 0px' },\n );\n for (const el of sections) observer.observe(el);\n return () => observer.disconnect();\n }, [files, setActiveDiffPath]);\n\n const contentClass = 'min-h-page';\n\n if (loadFailed) {\n return (\n <div>\n <PageTitle>Git</PageTitle>\n <div className=\"mb-4 flex items-center gap-2\">\n <GitSyncActions />\n <GitStashSurface />\n </div>\n <div className={`${contentClass} flex flex-col items-start gap-3`}>\n <p className=\"opacity-50 m-0\">Couldn't load the working-tree diff.</p>\n <Button variant=\"secondary\" size=\"small\" onClick={loadDiffFiles}>\n Retry\n </Button>\n </div>\n </div>\n );\n }\n\n if (!files) {\n return (\n <div>\n <PageTitle>Git</PageTitle>\n <div className=\"mb-4 flex items-center gap-2\">\n <GitSyncActions />\n <GitStashSurface />\n </div>\n <div className={contentClass}>\n <Spinner label=\"Loading the working-tree diff…\" />\n </div>\n </div>\n );\n }\n\n return (\n <div>\n <PageTitle>Git</PageTitle>\n <div className=\"mb-4 flex items-center gap-2\">\n <GitSyncActions />\n <GitStashSurface />\n </div>\n {files.length === 0 ? (\n <div className={contentClass}>\n <p className=\"opacity-50\">No changed files.</p>\n </div>\n ) : (\n <>\n <div className=\"sticky top-0 z-10 mb-6 flex items-start gap-2 bg-[var(--pui-bg-base)] py-3 shadow-paper-sm\">\n <div className=\"flex-1\">\n <CommitMessageFields state={commitForm} filesEmpty={false} />\n </div>\n <GitCommitButton state={commitForm} filesEmpty={false} />\n </div>\n <div ref={sectionsRef} className={`flex min-w-0 flex-col gap-6 ${contentClass}`}>\n {files.map((entry, idx) => (\n <Fragment key={entry.path}>\n {idx > 0 && <Divider />}\n <FileDiffSection entry={entry} />\n </Fragment>\n ))}\n </div>\n </>\n )}\n </div>\n );\n};\n","import { CountBadge } from '@/app/features/git/count-badge';\nimport { FilePath } from '@/app/features/git/file-path';\nimport { GitStatusMarker } from '@/app/features/git/git-status-marker';\nimport { stagePath, unstagePath } from '@/app/services/git-api';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { oneLineErrorSummary } from '@/app/utils/error-summary';\nimport type { FileDiffEntry } from '@/types/index';\nimport { Checkbox, ListItem, Stamp, useToast } from '@dendelion/paper-ui';\nimport { useState } from 'react';\n\nconst sectionLabelClass = 'text-2xs font-semibold tracking-[0.08em] uppercase text-ink-300 mb-2';\n\nconst scrollToFile = (path: string, expandDiffPath: (path: string) => void) => {\n expandDiffPath(path);\n requestAnimationFrame(() => {\n document\n .querySelector(`[data-diff-path=\"${CSS.escape(path)}\"]`)\n ?.scrollIntoView({ behavior: 'smooth', block: 'start' });\n });\n};\n\n// Both status characters set (and neither '?', which pairs up for untracked) means\n// part of the file is staged and part isn't — git can't be checked or unchecked.\nconst isPartiallyStaged = (status: string) => {\n const [x, y] = status;\n return x !== ' ' && x !== '?' && y !== ' ' && y !== '?';\n};\n\nexport const GitFileList = () => {\n const files = useAppStore((s) => s.diffFiles);\n const activePath = useAppStore((s) => s.activeDiffPath);\n const loadDiffFiles = useAppStore((s) => s.loadDiffFiles);\n const expandDiffPath = useAppStore((s) => s.expandDiffPath);\n const [pending, setPending] = useState<Set<string>>(new Set());\n const { toast } = useToast();\n\n if (!files || files.length === 0) return null;\n\n const toggleStaged = async (entry: FileDiffEntry, next: boolean) => {\n setPending((prev) => new Set(prev).add(entry.path));\n try {\n await (next ? stagePath(entry.path) : unstagePath(entry.path));\n await loadDiffFiles();\n } catch (err) {\n toast({\n title: next ? 'Stage failed' : 'Unstage failed',\n description: oneLineErrorSummary((err as Error).message),\n variant: 'error',\n });\n } finally {\n setPending((prev) => {\n const updated = new Set(prev);\n updated.delete(entry.path);\n return updated;\n });\n }\n };\n\n return (\n <nav aria-label=\"Changed files\" className=\"flex flex-col gap-8 -mt-5\">\n <div>\n <div className={sectionLabelClass}>Changed files</div>\n <ul className=\"m-0 flex list-none flex-col gap-1 p-0\">\n {files.map((entry) => (\n <li key={entry.path} className=\"flex items-center gap-2\">\n <Checkbox\n checked={entry.staged}\n indeterminate={isPartiallyStaged(entry.status)}\n disabled={pending.has(entry.path)}\n onChange={(e) => toggleStaged(entry, e.target.checked)}\n aria-label={entry.staged ? `Unstage ${entry.path}` : `Stage ${entry.path}`}\n />\n <GitStatusMarker status={entry.status} />\n <ListItem\n size=\"small\"\n active={entry.path === activePath}\n onClick={() => scrollToFile(entry.path, expandDiffPath)}\n className=\"flex-1\"\n action={\n <span className=\"flex items-center gap-2\">\n {entry.staged && <Stamp size=\"small\">staged</Stamp>}\n {!entry.binary && (\n <CountBadge additions={entry.additions} deletions={entry.deletions} />\n )}\n </span>\n }\n >\n <FilePath path={entry.path} className=\"text-2xs\" />\n </ListItem>\n </li>\n ))}\n </ul>\n </div>\n </nav>\n );\n};\n"],"names":["HUNK_HEADER","parsePatch","patch","lines","hunks","current","oldLine","newLine","line","header","rawContentHunks","content","text","i","CountBadge","additions","deletions","jsxs","splitPathForDisplay","path","slash","FilePath","prefix","className","dir","base","dimmed","jsx","STATUS_INFO","gitStatusInfo","status","x","y","code","GitStatusMarker","info","Stamp","COLLAPSE_LINE_THRESHOLD","LINE_CLASS","LINE_PREFIX","FileHeader","entry","DiffBody","hunk","j","FileDiffSection","manuallyExpanded","useAppStore","s","manuallyCollapsed","setDiffCollapsed","collapsed","headingText","Accordion","GIT_PAGE_FORM_KEY","matchAnySuggestionTask","useGitCommitForm","files","useCommitForm","GitCommitButton","state","filesEmpty","deskChecks","useDeskChecks","qualityStatus","testStatus","consistencyStatus","useMemo","deriveCheckStatuses","failingChecks","label","commitButton","Button","Tooltip","GitPage","loadFailed","loadDiffFiles","setActiveDiffPath","sectionsRef","useRef","commitFiles","commitForm","useEffect","timer","unsubscribe","subscribeToActivityStream","payload","onFocus","root","sections","visible","observer","entries","topmost","el","contentClass","PageTitle","GitSyncActions","GitStashSurface","Fragment","CommitMessageFields","idx","Divider","Spinner","sectionLabelClass","scrollToFile","expandDiffPath","_a","isPartiallyStaged","GitFileList","activePath","pending","setPending","useState","toast","useToast","toggleStaged","next","prev","stagePath","unstagePath","err","oneLineErrorSummary","updated","Checkbox","e","ListItem"],"mappings":"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"}