@dendelion/paper-camp 0.22.0 → 0.23.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 (26) hide show
  1. package/dist/app/assets/{index-Bkouj3B7.js → index-8_65UWKz.js} +2 -2
  2. package/dist/app/assets/{index-Bkouj3B7.js.map → index-8_65UWKz.js.map} +1 -1
  3. package/dist/app/assets/{index-BS3GyKvd.js → index-Bq3vqVCv.js} +2 -2
  4. package/dist/app/assets/{index-BS3GyKvd.js.map → index-Bq3vqVCv.js.map} +1 -1
  5. package/dist/app/assets/{index-CDlMKeg5.js → index-Co_9IFtJ.js} +2 -2
  6. package/dist/app/assets/{index-CDlMKeg5.js.map → index-Co_9IFtJ.js.map} +1 -1
  7. package/dist/app/assets/{index-UOItJyt3.js → index-DRVlFKav.js} +2 -2
  8. package/dist/app/assets/{index-UOItJyt3.js.map → index-DRVlFKav.js.map} +1 -1
  9. package/dist/app/assets/{index-BzD-BgRl.js → index-DdiMHcBX.js} +2 -2
  10. package/dist/app/assets/{index-BzD-BgRl.js.map → index-DdiMHcBX.js.map} +1 -1
  11. package/dist/app/assets/{index-DxnAxo8U.js → index-Ds_iTHi0.js} +2 -2
  12. package/dist/app/assets/{index-DxnAxo8U.js.map → index-Ds_iTHi0.js.map} +1 -1
  13. package/dist/app/assets/{index-DgEJTUYT.js → index-e0PzaU7Z.js} +2 -2
  14. package/dist/app/assets/{index-DgEJTUYT.js.map → index-e0PzaU7Z.js.map} +1 -1
  15. package/dist/app/assets/{index-jxEIOkqg.js → index-siPA4naJ.js} +2 -2
  16. package/dist/app/assets/{index-jxEIOkqg.js.map → index-siPA4naJ.js.map} +1 -1
  17. package/dist/app/assets/{main-DEUaro51.css → main-BAlJ6w7u.css} +1 -1
  18. package/dist/app/assets/{main-BPr1R-3E.js → main-C0TBUyF9.js} +106 -106
  19. package/dist/app/assets/main-C0TBUyF9.js.map +1 -0
  20. package/dist/app/assets/{sidebar-section-CVvP-dC0.js → sidebar-section-D0b_1DUA.js} +2 -2
  21. package/dist/app/assets/{sidebar-section-CVvP-dC0.js.map → sidebar-section-D0b_1DUA.js.map} +1 -1
  22. package/dist/app/index.html +2 -2
  23. package/dist/cli/index.js +1781 -1731
  24. package/dist/cli/index.js.map +1 -1
  25. package/package.json +1 -1
  26. package/dist/app/assets/main-BPr1R-3E.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index-DgEJTUYT.js","sources":["../../../src/app/features/issues/helpers.ts","../../../src/core/issues.ts","../../../src/app/features/issues/hooks/use-issues-page.ts","../../../src/app/features/issues/issue-row.tsx","../../../src/app/features/issues/issues-page.tsx"],"sourcesContent":["import { isClosedEntity } from '@/core/status';\nimport type { EntityStatus, Issue } from '@/types/index';\n\nexport const promoteLabel = (\n issue: Issue,\n entities: { id: string; status?: EntityStatus; archived?: boolean }[],\n): string => {\n const parent = issue.entityId ? entities.find((p) => p.id === issue.entityId) : undefined;\n if (!parent) return 'Promote to idea';\n return isClosedEntity(parent) ? 'Promote to fix' : `Add to ${parent.id}'s fixes`;\n};\n\nexport const formatIssueAge = (occurredAt: string | undefined): string => {\n if (!occurredAt) return '';\n const ageDays = Math.floor((Date.now() - Date.parse(occurredAt)) / 86_400_000);\n if (!Number.isFinite(ageDays)) return '';\n if (ageDays <= 0) return 'today';\n return ageDays === 1 ? '1 day ago' : `${ageDays} days ago`;\n};\n\n// Missing timestamps (a live PR review decision) sort last, not first.\nconst NO_TIMESTAMP = '9999-12-31T23:59:59.999Z';\nexport const sortIssuesByAge = <T extends { occurredAt?: string }>(issues: T[]): T[] =>\n [...issues].sort((a, b) =>\n (a.occurredAt ?? NO_TIMESTAMP).localeCompare(b.occurredAt ?? NO_TIMESTAMP),\n );\n","import type {\n DeskCheckState,\n EntityStatus,\n GitSyncFailure,\n Issue,\n PhaseItem,\n PrInfo,\n TaskLogEntry,\n ThreadMessage,\n} from '../types/index';\n\nconst issueId = (sourceKind: Issue['sourceKind'], sourceKey: string): string =>\n `${sourceKind}:${sourceKey}`;\n\n/** A failed agent run (`outcome: 'error'` in tasks.log), keyed by the plan it ran\n * against so a repeat failure on the same plan continues one issue. Runs with no\n * `planId` (e.g. a batch task) key off their own task id instead. */\nexport function collectAgentRunIssues(taskLog: TaskLogEntry[]): Issue[] {\n return taskLog\n .filter((entry) => entry.outcome === 'error')\n .map((entry) => {\n const sourceKey = entry.planId ?? entry.id;\n return {\n id: issueId('agent-run', sourceKey),\n sourceKind: 'agent-run',\n sourceKey,\n entityId: entry.planId,\n entityTitle: entry.planTitle,\n title: `${entry.planTitle} — ${entry.taskKind} failed`,\n reason: entry.reason ?? 'The run ended in error with no reason recorded.',\n occurredAt: entry.endedAt,\n thread: [],\n status: 'open',\n };\n });\n}\n\n/** A red project check (Quality/Tests/Consistency — Docs keeps its own browse flow\n * and is excluded, same carve-out as `buildCheckFixes`), keyed by check name. */\nexport function collectCheckIssues(checks: DeskCheckState[]): Issue[] {\n return checks\n .filter((check) => check.status === 'fail')\n .map((check) => ({\n id: issueId('check', check.name),\n sourceKind: 'check',\n sourceKey: check.name,\n title: `\"${check.name}\" check is failing`,\n reason: `The command was \\`${check.cmd}\\`.`,\n output: check.output || undefined,\n occurredAt: check.lastRun ?? undefined,\n thread: [],\n status: 'open',\n }));\n}\n\n/** A PR review that requested changes, keyed by PR number + head sha so a fresh\n * push that gets re-reviewed continues the same issue rather than a new one. */\nexport function collectPrReviewIssues(\n entities: { id: string; title: string; pr?: PrInfo }[],\n): Issue[] {\n return entities\n .filter((entity) => entity.pr?.reviewDecision === 'changes-requested')\n .map((entity) => {\n const pr = entity.pr as PrInfo;\n const sourceKey = `${pr.number}:${pr.headSha ?? 'unknown'}`;\n return {\n id: issueId('pr-review', sourceKey),\n sourceKind: 'pr-review',\n sourceKey,\n entityId: entity.id,\n entityTitle: entity.title,\n title: `${entity.title} — PR review requested changes`,\n reason: `PR #${pr.number} has unresolved change requests.`,\n thread: [],\n status: 'open',\n };\n });\n}\n\n/** A git rebase/sync failure on the currently checked-out branch, keyed by branch +\n * the ref it failed to reconcile against so a repeat failure of the same rebase\n * continues one issue. */\nexport function collectSyncIssues(\n failure: GitSyncFailure | undefined,\n branch: string,\n entity?: { id: string; title: string },\n): Issue[] {\n if (!failure) return [];\n const sourceKey = `${branch}:${failure.conflictRef ?? failure.stage}`;\n return [\n {\n id: issueId('sync', sourceKey),\n sourceKind: 'sync',\n sourceKey,\n entityId: entity?.id,\n entityTitle: entity?.title,\n title: `${branch} failed to sync`,\n reason: failure.message,\n output: failure.conflictedFiles?.length\n ? `Conflicted files: ${failure.conflictedFiles.join(', ')}`\n : undefined,\n thread: [],\n status: 'open',\n },\n ];\n}\n\n/** Reconciles freshly-collected issues (every one currently detected as failing, so\n * always 'open') against the existing set, keyed by `id`. A repeat failure of the\n * same thing replaces that issue's title/reason/output in place, preserving its\n * position and its thread. An existing issue absent from `fresh` has stopped\n * failing, so it closes — unless it was promoted to a fix entity that hasn't\n * shipped yet (`fixEntityStatus` reports its status), which keeps it open until\n * that entity reaches 'done'. Closure is derived here, never a mark-read button. */\nexport function reconcileIssues(\n existing: Issue[],\n fresh: Issue[],\n fixEntityStatus: (fixId: string) => EntityStatus | undefined = () => undefined,\n): Issue[] {\n const freshById = new Map(fresh.map((issue) => [issue.id, issue]));\n const merged = existing.map((issue): Issue => {\n if (issue.promotedFixId && fixEntityStatus(issue.promotedFixId) === 'done') {\n freshById.delete(issue.id);\n return { ...issue, status: 'closed' };\n }\n const next = freshById.get(issue.id);\n if (!next) return { ...issue, status: 'closed' };\n freshById.delete(issue.id);\n return { ...next, thread: issue.thread, promotedFixId: issue.promotedFixId };\n });\n return [...merged, ...freshById.values()];\n}\n\n/** A spawned fix/idea entity from Promote (IDEA-192 phase 6) stamps `issueSource`;\n * an open parent instead gets a `source: 'issue'` item appended to its inline Fixes list. */\ntype PromotionTarget = {\n id?: string;\n status?: EntityStatus;\n issueSource?: string;\n fixes?: PhaseItem[];\n};\n\n/** Matches every issue against the corpus for a prior Promote (IDEA-192 phase 6),\n * re-derived from disk on every read since issues carry no store of their own —\n * the promotion survives a reload because git holds it, not a stored issue. Once\n * matched, an issue whose target has shipped (`status: 'done'`) closes, even if\n * its original source is still detected as failing. */\nexport function applyPromotions(issues: Issue[], entities: PromotionTarget[]): Issue[] {\n return issues\n .map((issue): Issue => {\n const spawned = entities.find((e) => e.issueSource === issue.id);\n if (spawned?.id) return { ...issue, promotedFixId: spawned.id };\n const parent = issue.entityId ? entities.find((e) => e.id === issue.entityId) : undefined;\n const appended = parent?.fixes?.some((f) => f.source === 'issue' && f.text === issue.title);\n return appended && parent?.id ? { ...issue, promotedFixId: parent.id } : issue;\n })\n .filter((issue) => {\n const target = issue.promotedFixId && entities.find((e) => e.id === issue.promotedFixId);\n return !(target && target.status === 'done');\n });\n}\n\n/** \"Fix it here\" (IDEA-192) launches an `issue-fix` task carrying the issue's id;\n * this reconstructs that issue's thread from every tasks.log entry carrying it,\n * oldest first, so a repeat fix attempt reads as a continuation, not a fresh mystery. */\nexport function issueThreadFromTaskLog(issue: Issue, taskLog: TaskLogEntry[]): ThreadMessage[] {\n return taskLog\n .filter((entry) => entry.issueId === issue.id)\n .sort((a, b) => a.endedAt.localeCompare(b.endedAt))\n .map((entry) => ({\n kind: 'log',\n date: entry.endedAt.slice(0, 10),\n from: 'agent',\n text:\n entry.outcome === 'done'\n ? 'Ran a fix agent — finished.'\n : entry.outcome === 'error'\n ? `Ran a fix agent — failed: ${entry.reason ?? 'no reason recorded'}`\n : 'Ran a fix agent — superseded by a newer run.',\n }));\n}\n","import { useOpenEntity } from '@/app/hooks';\nimport { useDeskChecks } from '@/app/hooks/use-desk-checks';\nimport { promoteIssue } from '@/app/services/agent-api';\nimport { useAppStore } from '@/app/stores/app-store';\nimport {\n applyPromotions,\n collectAgentRunIssues,\n collectCheckIssues,\n collectPrReviewIssues,\n issueThreadFromTaskLog,\n} from '@/core/issues';\nimport type { Issue, PlanEntry } from '@/types/index';\nimport { useEffect, useMemo, useState } from 'react';\nimport { sortIssuesByAge } from '../helpers';\n\nexport const useIssuesPage = () => {\n const [expandedId, setExpandedId] = useState<string | null>(null);\n const [promotingId, setPromotingId] = useState<string | null>(null);\n const taskLog = useAppStore((s) => s.taskLog);\n const taskLogLoading = useAppStore((s) => s.taskLogLoading);\n const loadTaskLog = useAppStore((s) => s.loadTaskLog);\n const plans = useAppStore((s) => s.plans);\n const ideaEntries = useAppStore((s) => s.ideaEntries);\n const agentStatus = useAppStore((s) => s.agentStatus);\n const launchIssueFix = useAppStore((s) => s.launchIssueFix);\n const loadPlans = useAppStore((s) => s.loadPlans);\n const loadIdeas = useAppStore((s) => s.loadIdeas);\n const { checks } = useDeskChecks();\n const openEntity = useOpenEntity();\n\n useEffect(() => {\n loadTaskLog();\n }, [loadTaskLog]);\n\n const planEntities = useMemo(\n () => (plans?.entries ?? []).filter((p): p is PlanEntry & { id: string } => p.id != null),\n [plans],\n );\n\n const entities = useMemo(\n () =>\n [...planEntities, ...ideaEntries].filter(\n (entity): entity is typeof entity & { id: string } => entity.id != null,\n ),\n [planEntities, ideaEntries],\n );\n\n const issues = useMemo(() => {\n const collected = sortIssuesByAge([\n ...collectAgentRunIssues(taskLog),\n ...collectCheckIssues(checks),\n ...collectPrReviewIssues(entities),\n ]);\n return applyPromotions(collected, entities).map((issue) => ({\n ...issue,\n thread: issueThreadFromTaskLog(issue, taskLog),\n }));\n }, [taskLog, checks, entities]);\n\n const handlePromote = async (issue: Issue) => {\n setPromotingId(issue.id);\n try {\n await promoteIssue(issue);\n await Promise.all([loadPlans(), loadIdeas()]);\n } finally {\n setPromotingId(null);\n }\n };\n\n const fixingIssueId = agentStatus.find(\n (t) =>\n t.taskKind === 'issue-fix' &&\n t.status !== 'done' &&\n t.status !== 'error' &&\n t.status !== 'superseded',\n )?.issueId;\n\n return {\n issues,\n entities,\n taskLogLoading,\n expandedId,\n setExpandedId,\n openEntity,\n fixingIssueId,\n launchIssueFix,\n promotingId,\n handlePromote,\n };\n};\n","import { FeedbackThread, PlanIdStamp } from '@/app/features/plans/components';\nimport type { Issue } from '@/types/index';\nimport { Button, Spinner } from '@dendelion/paper-ui';\nimport { formatIssueAge } from './helpers';\n\ninterface IssueRowProps {\n issue: Issue;\n expanded: boolean;\n onToggle: () => void;\n onOpen?: () => void;\n fixing: boolean;\n fixDisabled: boolean;\n onFix: () => Promise<void>;\n promoteLabel: string;\n promoting: boolean;\n promoteDisabled: boolean;\n onPromote: () => Promise<void>;\n onOpenPromoted?: () => void;\n}\n\nexport const IssueRow = ({\n issue,\n expanded,\n onToggle,\n onOpen,\n fixing,\n fixDisabled,\n onFix,\n promoteLabel,\n promoting,\n promoteDisabled,\n onPromote,\n onOpenPromoted,\n}: IssueRowProps) => {\n const handleFix = async () => {\n try {\n await onFix();\n } catch (err) {\n alert((err as Error).message);\n }\n };\n\n const handlePromote = async () => {\n try {\n await onPromote();\n } catch (err) {\n alert((err as Error).message);\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 {onOpen && (\n <button\n type=\"button\"\n onClick={onOpen}\n aria-label={`Open ${issue.entityTitle}`}\n className=\"bg-transparent border-none p-0 cursor-pointer\"\n >\n <PlanIdStamp id={issue.entityId} />\n </button>\n )}\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 {issue.title}\n </button>\n <span className=\"opacity-50 text-xs whitespace-nowrap\">\n {formatIssueAge(issue.occurredAt)}\n </span>\n </div>\n {expanded && (\n <div className=\"flex flex-col gap-3 pb-4\">\n <p>{issue.reason}</p>\n {issue.output && (\n <pre className=\"max-h-48 overflow-auto whitespace-pre-wrap text-left font-mono text-2xs opacity-70\">\n {issue.output}\n </pre>\n )}\n {issue.thread.length > 0 && (\n <FeedbackThread messages={issue.thread} undo={null} undoing={false} onUndo={() => {}} />\n )}\n <div className=\"flex items-center gap-3\">\n {issue.promotedFixId ? (\n <Button size=\"small\" onClick={onOpenPromoted}>\n View {issue.promotedFixId}\n </Button>\n ) : (\n <>\n <Button size=\"small\" onClick={handleFix} disabled={fixDisabled}>\n {fixing ? 'Fixing…' : 'Fix it here'}\n </Button>\n {fixing && <Spinner size=\"small\" label=\"Agent fixing…\" />}\n <Button size=\"small\" onClick={handlePromote} disabled={promoteDisabled}>\n {promoting ? 'Promoting…' : promoteLabel}\n </Button>\n {promoting && <Spinner size=\"small\" label=\"Promoting…\" />}\n </>\n )}\n </div>\n </div>\n )}\n </div>\n );\n};\n","import { PageTitle } from '@/app/components/page-title';\nimport { promoteLabel } from './helpers';\nimport { useIssuesPage } from './hooks';\nimport { IssueRow } from './issue-row';\n\nexport const IssuesPage = () => {\n const {\n issues,\n entities,\n taskLogLoading,\n expandedId,\n setExpandedId,\n openEntity,\n fixingIssueId,\n launchIssueFix,\n promotingId,\n handlePromote,\n } = useIssuesPage();\n\n return (\n <div>\n <PageTitle>Issues</PageTitle>\n <p className=\"opacity-50 mb-6\">\n Every failing agent run, red check, and PR review, oldest first.\n </p>\n {taskLogLoading && issues.length === 0 && <p className=\"opacity-50\">Loading…</p>}\n {!taskLogLoading && issues.length === 0 && (\n <p className=\"opacity-50\">Nothing broken right now.</p>\n )}\n {issues.length > 0 && (\n <div className=\"flex flex-col\">\n {issues.map((issue) => {\n const promotedTitle = issue.promotedFixId\n ? (entities.find((p) => p.id === issue.promotedFixId)?.title ?? issue.promotedFixId)\n : undefined;\n return (\n <IssueRow\n key={issue.id}\n issue={issue}\n expanded={expandedId === issue.id}\n onToggle={() => setExpandedId((cur) => (cur === issue.id ? null : issue.id))}\n onOpen={\n issue.entityId && issue.entityTitle\n ? () => openEntity(issue.entityId as string, issue.entityTitle as string)\n : undefined\n }\n fixing={fixingIssueId === issue.id}\n fixDisabled={fixingIssueId !== undefined}\n onFix={() => launchIssueFix(issue.id, issue.title, issue.reason, issue.output)}\n promoteLabel={promoteLabel(issue, entities)}\n promoting={promotingId === issue.id}\n promoteDisabled={promotingId !== null}\n onPromote={() => handlePromote(issue)}\n onOpenPromoted={\n issue.promotedFixId\n ? () => openEntity(issue.promotedFixId as string, promotedTitle as string)\n : undefined\n }\n />\n );\n })}\n </div>\n )}\n </div>\n );\n};\n"],"names":["promoteLabel","issue","entities","parent","p","isClosedEntity","formatIssueAge","occurredAt","ageDays","NO_TIMESTAMP","sortIssuesByAge","issues","a","b","issueId","sourceKind","sourceKey","collectAgentRunIssues","taskLog","entry","collectCheckIssues","checks","check","collectPrReviewIssues","entity","_a","pr","applyPromotions","spawned","e","f","target","issueThreadFromTaskLog","useIssuesPage","expandedId","setExpandedId","useState","promotingId","setPromotingId","useAppStore","s","taskLogLoading","loadTaskLog","plans","ideaEntries","agentStatus","launchIssueFix","loadPlans","loadIdeas","useDeskChecks","openEntity","useOpenEntity","useEffect","planEntities","useMemo","collected","handlePromote","promoteIssue","fixingIssueId","t","IssueRow","expanded","onToggle","onOpen","fixing","fixDisabled","onFix","promoting","promoteDisabled","onPromote","onOpenPromoted","handleFix","err","jsxs","jsx","PlanIdStamp","FeedbackThread","Button","Fragment","Spinner","IssuesPage","PageTitle","promotedTitle","cur"],"mappings":"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"}
1
+ {"version":3,"file":"index-e0PzaU7Z.js","sources":["../../../src/app/features/issues/helpers.ts","../../../src/core/issues.ts","../../../src/app/features/issues/hooks/use-issues-page.ts","../../../src/app/features/issues/issue-row.tsx","../../../src/app/features/issues/issues-page.tsx"],"sourcesContent":["import { isClosedEntity } from '@/core/status';\nimport type { EntityStatus, Issue } from '@/types/index';\n\nexport const promoteLabel = (\n issue: Issue,\n entities: { id: string; status?: EntityStatus; archived?: boolean }[],\n): string => {\n const parent = issue.entityId ? entities.find((p) => p.id === issue.entityId) : undefined;\n if (!parent) return 'Promote to idea';\n return isClosedEntity(parent) ? 'Promote to fix' : `Add to ${parent.id}'s fixes`;\n};\n\nexport const formatIssueAge = (occurredAt: string | undefined): string => {\n if (!occurredAt) return '';\n const ageDays = Math.floor((Date.now() - Date.parse(occurredAt)) / 86_400_000);\n if (!Number.isFinite(ageDays)) return '';\n if (ageDays <= 0) return 'today';\n return ageDays === 1 ? '1 day ago' : `${ageDays} days ago`;\n};\n\n// Missing timestamps (a live PR review decision) sort last, not first.\nconst NO_TIMESTAMP = '9999-12-31T23:59:59.999Z';\nexport const sortIssuesByAge = <T extends { occurredAt?: string }>(issues: T[]): T[] =>\n [...issues].sort((a, b) =>\n (a.occurredAt ?? NO_TIMESTAMP).localeCompare(b.occurredAt ?? NO_TIMESTAMP),\n );\n","import type {\n DeskCheckState,\n EntityStatus,\n GitSyncFailure,\n Issue,\n PhaseItem,\n PrInfo,\n TaskLogEntry,\n ThreadMessage,\n} from '../types/index';\n\nconst issueId = (sourceKind: Issue['sourceKind'], sourceKey: string): string =>\n `${sourceKind}:${sourceKey}`;\n\n/** A failed agent run (`outcome: 'error'` in tasks.log), keyed by the plan it ran\n * against so a repeat failure on the same plan continues one issue. Runs with no\n * `planId` (e.g. a batch task) key off their own task id instead. */\nexport function collectAgentRunIssues(taskLog: TaskLogEntry[]): Issue[] {\n return taskLog\n .filter((entry) => entry.outcome === 'error')\n .map((entry) => {\n const sourceKey = entry.planId ?? entry.id;\n return {\n id: issueId('agent-run', sourceKey),\n sourceKind: 'agent-run',\n sourceKey,\n entityId: entry.planId,\n entityTitle: entry.planTitle,\n title: `${entry.planTitle} — ${entry.taskKind} failed`,\n reason: entry.reason ?? 'The run ended in error with no reason recorded.',\n occurredAt: entry.endedAt,\n thread: [],\n status: 'open',\n };\n });\n}\n\n/** A red project check (Quality/Tests/Consistency — Docs keeps its own browse flow\n * and is excluded, same carve-out as `buildCheckFixes`), keyed by check name. */\nexport function collectCheckIssues(checks: DeskCheckState[]): Issue[] {\n return checks\n .filter((check) => check.status === 'fail')\n .map((check) => ({\n id: issueId('check', check.name),\n sourceKind: 'check',\n sourceKey: check.name,\n title: `\"${check.name}\" check is failing`,\n reason: `The command was \\`${check.cmd}\\`.`,\n output: check.output || undefined,\n occurredAt: check.lastRun ?? undefined,\n thread: [],\n status: 'open',\n }));\n}\n\n/** A PR review that requested changes, keyed by PR number + head sha so a fresh\n * push that gets re-reviewed continues the same issue rather than a new one. */\nexport function collectPrReviewIssues(\n entities: { id: string; title: string; pr?: PrInfo }[],\n): Issue[] {\n return entities\n .filter((entity) => entity.pr?.reviewDecision === 'changes-requested')\n .map((entity) => {\n const pr = entity.pr as PrInfo;\n const sourceKey = `${pr.number}:${pr.headSha ?? 'unknown'}`;\n return {\n id: issueId('pr-review', sourceKey),\n sourceKind: 'pr-review',\n sourceKey,\n entityId: entity.id,\n entityTitle: entity.title,\n title: `${entity.title} — PR review requested changes`,\n reason: `PR #${pr.number} has unresolved change requests.`,\n thread: [],\n status: 'open',\n };\n });\n}\n\n/** A git rebase/sync failure on the currently checked-out branch, keyed by branch +\n * the ref it failed to reconcile against so a repeat failure of the same rebase\n * continues one issue. */\nexport function collectSyncIssues(\n failure: GitSyncFailure | undefined,\n branch: string,\n entity?: { id: string; title: string },\n): Issue[] {\n if (!failure) return [];\n const sourceKey = `${branch}:${failure.conflictRef ?? failure.stage}`;\n return [\n {\n id: issueId('sync', sourceKey),\n sourceKind: 'sync',\n sourceKey,\n entityId: entity?.id,\n entityTitle: entity?.title,\n title: `${branch} failed to sync`,\n reason: failure.message,\n output: failure.conflictedFiles?.length\n ? `Conflicted files: ${failure.conflictedFiles.join(', ')}`\n : undefined,\n thread: [],\n status: 'open',\n },\n ];\n}\n\n/** Reconciles freshly-collected issues (every one currently detected as failing, so\n * always 'open') against the existing set, keyed by `id`. A repeat failure of the\n * same thing replaces that issue's title/reason/output in place, preserving its\n * position and its thread. An existing issue absent from `fresh` has stopped\n * failing, so it closes — unless it was promoted to a fix entity that hasn't\n * shipped yet (`fixEntityStatus` reports its status), which keeps it open until\n * that entity reaches 'done'. Closure is derived here, never a mark-read button. */\nexport function reconcileIssues(\n existing: Issue[],\n fresh: Issue[],\n fixEntityStatus: (fixId: string) => EntityStatus | undefined = () => undefined,\n): Issue[] {\n const freshById = new Map(fresh.map((issue) => [issue.id, issue]));\n const merged = existing.map((issue): Issue => {\n if (issue.promotedFixId && fixEntityStatus(issue.promotedFixId) === 'done') {\n freshById.delete(issue.id);\n return { ...issue, status: 'closed' };\n }\n const next = freshById.get(issue.id);\n if (!next) return { ...issue, status: 'closed' };\n freshById.delete(issue.id);\n return { ...next, thread: issue.thread, promotedFixId: issue.promotedFixId };\n });\n return [...merged, ...freshById.values()];\n}\n\n/** A spawned fix/idea entity from Promote (IDEA-192 phase 6) stamps `issueSource`;\n * an open parent instead gets a `source: 'issue'` item appended to its inline Fixes list. */\ntype PromotionTarget = {\n id?: string;\n status?: EntityStatus;\n issueSource?: string;\n fixes?: PhaseItem[];\n};\n\n/** Matches every issue against the corpus for a prior Promote (IDEA-192 phase 6),\n * re-derived from disk on every read since issues carry no store of their own —\n * the promotion survives a reload because git holds it, not a stored issue. Once\n * matched, an issue whose target has shipped (`status: 'done'`) closes, even if\n * its original source is still detected as failing. */\nexport function applyPromotions(issues: Issue[], entities: PromotionTarget[]): Issue[] {\n return issues\n .map((issue): Issue => {\n const spawned = entities.find((e) => e.issueSource === issue.id);\n if (spawned?.id) return { ...issue, promotedFixId: spawned.id };\n const parent = issue.entityId ? entities.find((e) => e.id === issue.entityId) : undefined;\n const appended = parent?.fixes?.some((f) => f.source === 'issue' && f.text === issue.title);\n return appended && parent?.id ? { ...issue, promotedFixId: parent.id } : issue;\n })\n .filter((issue) => {\n const target = issue.promotedFixId && entities.find((e) => e.id === issue.promotedFixId);\n return !(target && target.status === 'done');\n });\n}\n\n/** \"Fix it here\" (IDEA-192) launches an `issue-fix` task carrying the issue's id;\n * this reconstructs that issue's thread from every tasks.log entry carrying it,\n * oldest first, so a repeat fix attempt reads as a continuation, not a fresh mystery. */\nexport function issueThreadFromTaskLog(issue: Issue, taskLog: TaskLogEntry[]): ThreadMessage[] {\n return taskLog\n .filter((entry) => entry.issueId === issue.id)\n .sort((a, b) => a.endedAt.localeCompare(b.endedAt))\n .map((entry) => ({\n kind: 'log',\n date: entry.endedAt.slice(0, 10),\n from: 'agent',\n text:\n entry.outcome === 'done'\n ? 'Ran a fix agent — finished.'\n : entry.outcome === 'error'\n ? `Ran a fix agent — failed: ${entry.reason ?? 'no reason recorded'}`\n : 'Ran a fix agent — superseded by a newer run.',\n }));\n}\n","import { useOpenEntity } from '@/app/hooks';\nimport { useDeskChecks } from '@/app/hooks/use-desk-checks';\nimport { promoteIssue } from '@/app/services/agent-api';\nimport { useAppStore } from '@/app/stores/app-store';\nimport {\n applyPromotions,\n collectAgentRunIssues,\n collectCheckIssues,\n collectPrReviewIssues,\n issueThreadFromTaskLog,\n} from '@/core/issues';\nimport type { Issue, PlanEntry } from '@/types/index';\nimport { useEffect, useMemo, useState } from 'react';\nimport { sortIssuesByAge } from '../helpers';\n\nexport const useIssuesPage = () => {\n const [expandedId, setExpandedId] = useState<string | null>(null);\n const [promotingId, setPromotingId] = useState<string | null>(null);\n const taskLog = useAppStore((s) => s.taskLog);\n const taskLogLoading = useAppStore((s) => s.taskLogLoading);\n const loadTaskLog = useAppStore((s) => s.loadTaskLog);\n const plans = useAppStore((s) => s.plans);\n const ideaEntries = useAppStore((s) => s.ideaEntries);\n const agentStatus = useAppStore((s) => s.agentStatus);\n const launchIssueFix = useAppStore((s) => s.launchIssueFix);\n const loadPlans = useAppStore((s) => s.loadPlans);\n const loadIdeas = useAppStore((s) => s.loadIdeas);\n const { checks } = useDeskChecks();\n const openEntity = useOpenEntity();\n\n useEffect(() => {\n loadTaskLog();\n }, [loadTaskLog]);\n\n const planEntities = useMemo(\n () => (plans?.entries ?? []).filter((p): p is PlanEntry & { id: string } => p.id != null),\n [plans],\n );\n\n const entities = useMemo(\n () =>\n [...planEntities, ...ideaEntries].filter(\n (entity): entity is typeof entity & { id: string } => entity.id != null,\n ),\n [planEntities, ideaEntries],\n );\n\n const issues = useMemo(() => {\n const collected = sortIssuesByAge([\n ...collectAgentRunIssues(taskLog),\n ...collectCheckIssues(checks),\n ...collectPrReviewIssues(entities),\n ]);\n return applyPromotions(collected, entities).map((issue) => ({\n ...issue,\n thread: issueThreadFromTaskLog(issue, taskLog),\n }));\n }, [taskLog, checks, entities]);\n\n const handlePromote = async (issue: Issue) => {\n setPromotingId(issue.id);\n try {\n await promoteIssue(issue);\n await Promise.all([loadPlans(), loadIdeas()]);\n } finally {\n setPromotingId(null);\n }\n };\n\n const fixingIssueId = agentStatus.find(\n (t) =>\n t.taskKind === 'issue-fix' &&\n t.status !== 'done' &&\n t.status !== 'error' &&\n t.status !== 'superseded',\n )?.issueId;\n\n return {\n issues,\n entities,\n taskLogLoading,\n expandedId,\n setExpandedId,\n openEntity,\n fixingIssueId,\n launchIssueFix,\n promotingId,\n handlePromote,\n };\n};\n","import { FeedbackThread, PlanIdStamp } from '@/app/features/plans/components';\nimport type { Issue } from '@/types/index';\nimport { Button, Spinner } from '@dendelion/paper-ui';\nimport { formatIssueAge } from './helpers';\n\ninterface IssueRowProps {\n issue: Issue;\n expanded: boolean;\n onToggle: () => void;\n onOpen?: () => void;\n fixing: boolean;\n fixDisabled: boolean;\n onFix: () => Promise<void>;\n promoteLabel: string;\n promoting: boolean;\n promoteDisabled: boolean;\n onPromote: () => Promise<void>;\n onOpenPromoted?: () => void;\n}\n\nexport const IssueRow = ({\n issue,\n expanded,\n onToggle,\n onOpen,\n fixing,\n fixDisabled,\n onFix,\n promoteLabel,\n promoting,\n promoteDisabled,\n onPromote,\n onOpenPromoted,\n}: IssueRowProps) => {\n const handleFix = async () => {\n try {\n await onFix();\n } catch (err) {\n alert((err as Error).message);\n }\n };\n\n const handlePromote = async () => {\n try {\n await onPromote();\n } catch (err) {\n alert((err as Error).message);\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 {onOpen && (\n <button\n type=\"button\"\n onClick={onOpen}\n aria-label={`Open ${issue.entityTitle}`}\n className=\"bg-transparent border-none p-0 cursor-pointer\"\n >\n <PlanIdStamp id={issue.entityId} />\n </button>\n )}\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 {issue.title}\n </button>\n <span className=\"opacity-50 text-xs whitespace-nowrap\">\n {formatIssueAge(issue.occurredAt)}\n </span>\n </div>\n {expanded && (\n <div className=\"flex flex-col gap-3 pb-4\">\n <p>{issue.reason}</p>\n {issue.output && (\n <pre className=\"max-h-48 overflow-auto whitespace-pre-wrap text-left font-mono text-2xs opacity-70\">\n {issue.output}\n </pre>\n )}\n {issue.thread.length > 0 && (\n <FeedbackThread messages={issue.thread} undo={null} undoing={false} onUndo={() => {}} />\n )}\n <div className=\"flex items-center gap-3\">\n {issue.promotedFixId ? (\n <Button size=\"small\" onClick={onOpenPromoted}>\n View {issue.promotedFixId}\n </Button>\n ) : (\n <>\n <Button size=\"small\" onClick={handleFix} disabled={fixDisabled}>\n {fixing ? 'Fixing…' : 'Fix it here'}\n </Button>\n {fixing && <Spinner size=\"small\" label=\"Agent fixing…\" />}\n <Button size=\"small\" onClick={handlePromote} disabled={promoteDisabled}>\n {promoting ? 'Promoting…' : promoteLabel}\n </Button>\n {promoting && <Spinner size=\"small\" label=\"Promoting…\" />}\n </>\n )}\n </div>\n </div>\n )}\n </div>\n );\n};\n","import { PageTitle } from '@/app/components/page-title';\nimport { promoteLabel } from './helpers';\nimport { useIssuesPage } from './hooks';\nimport { IssueRow } from './issue-row';\n\nexport const IssuesPage = () => {\n const {\n issues,\n entities,\n taskLogLoading,\n expandedId,\n setExpandedId,\n openEntity,\n fixingIssueId,\n launchIssueFix,\n promotingId,\n handlePromote,\n } = useIssuesPage();\n\n return (\n <div>\n <PageTitle>Issues</PageTitle>\n <p className=\"opacity-50 mb-6\">\n Every failing agent run, red check, and PR review, oldest first.\n </p>\n {taskLogLoading && issues.length === 0 && <p className=\"opacity-50\">Loading…</p>}\n {!taskLogLoading && issues.length === 0 && (\n <p className=\"opacity-50\">Nothing broken right now.</p>\n )}\n {issues.length > 0 && (\n <div className=\"flex flex-col\">\n {issues.map((issue) => {\n const promotedTitle = issue.promotedFixId\n ? (entities.find((p) => p.id === issue.promotedFixId)?.title ?? issue.promotedFixId)\n : undefined;\n return (\n <IssueRow\n key={issue.id}\n issue={issue}\n expanded={expandedId === issue.id}\n onToggle={() => setExpandedId((cur) => (cur === issue.id ? null : issue.id))}\n onOpen={\n issue.entityId && issue.entityTitle\n ? () => openEntity(issue.entityId as string, issue.entityTitle as string)\n : undefined\n }\n fixing={fixingIssueId === issue.id}\n fixDisabled={fixingIssueId !== undefined}\n onFix={() => launchIssueFix(issue.id, issue.title, issue.reason, issue.output)}\n promoteLabel={promoteLabel(issue, entities)}\n promoting={promotingId === issue.id}\n promoteDisabled={promotingId !== null}\n onPromote={() => handlePromote(issue)}\n onOpenPromoted={\n issue.promotedFixId\n ? () => openEntity(issue.promotedFixId as string, promotedTitle as string)\n : undefined\n }\n />\n );\n })}\n </div>\n )}\n </div>\n );\n};\n"],"names":["promoteLabel","issue","entities","parent","p","isClosedEntity","formatIssueAge","occurredAt","ageDays","NO_TIMESTAMP","sortIssuesByAge","issues","a","b","issueId","sourceKind","sourceKey","collectAgentRunIssues","taskLog","entry","collectCheckIssues","checks","check","collectPrReviewIssues","entity","_a","pr","applyPromotions","spawned","e","f","target","issueThreadFromTaskLog","useIssuesPage","expandedId","setExpandedId","useState","promotingId","setPromotingId","useAppStore","s","taskLogLoading","loadTaskLog","plans","ideaEntries","agentStatus","launchIssueFix","loadPlans","loadIdeas","useDeskChecks","openEntity","useOpenEntity","useEffect","planEntities","useMemo","collected","handlePromote","promoteIssue","fixingIssueId","t","IssueRow","expanded","onToggle","onOpen","fixing","fixDisabled","onFix","promoting","promoteDisabled","onPromote","onOpenPromoted","handleFix","err","jsxs","jsx","PlanIdStamp","FeedbackThread","Button","Fragment","Spinner","IssuesPage","PageTitle","promotedTitle","cur"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{c as K,r as u,C as U,j as e,e as L,g as F,R as P,J as S,w as A,h as te,k as X,l as ae,s as D,D as I,m as ne,n as H,o as le,u as z,t as Q,$ as ie,q as oe,a as Z,A as q,v as B,x as ce,y as re,i as G,z as de,B as ee,P as me,p as M}from"./main-BPr1R-3E.js";import{S as $}from"./sidebar-section-CVvP-dC0.js";const he=async()=>{try{const s=await fetch(K("/api/merge-policy"));return s.ok?await s.json():null}catch{return null}},pe=async()=>{try{const s=await fetch(K("/api/merge-policy/apply"),{method:"POST"});return s.ok?await s.json():null}catch{return null}},V=["phase","planDraft","ideaExtend","commitSuggest","feedback","codeReview"],ue={phase:"Phase run",planDraft:"Plan draft",ideaExtend:"Idea extend",commitSuggest:"Commit suggest",feedback:"Scout chat",codeReview:"Code review"},xe={ok:{fill:"rgba(143, 185, 150, 0.25)",text:"#5E8A66",label:"Ready"},warn:{fill:"rgba(212, 163, 115, 0.25)",text:"#A67B4F",label:"Needs attention"},missing:{fill:"rgba(201, 139, 139, 0.25)",text:"#6E3A3A",label:"Missing"}},_={upToDate:{fill:"rgba(143, 185, 150, 0.25)",text:"#5E8A66"},outdated:{fill:"rgba(212, 163, 115, 0.25)",text:"#A67B4F"}},ge="rgba(143, 185, 150, 0.25)",se={allowSquashMerge:!0,allowMergeCommit:!1,allowRebaseMerge:!1,squashMergeCommitTitle:"PR_TITLE",squashMergeCommitMessage:"PR_BODY"},Y=[{key:"allowSquashMerge",label:"Allow squash merge"},{key:"allowMergeCommit",label:"Allow merge commit"},{key:"allowRebaseMerge",label:"Allow rebase merge"},{key:"squashMergeCommitTitle",label:"Squash commit title"},{key:"squashMergeCommitMessage",label:"Squash commit message"}];function W(s){return typeof s=="boolean"?s?"Yes":"No":s}function fe(s){return Y.every(t=>s[t.key]===se[t.key])}const je=({label:s,current:t,recommended:l,isLast:a})=>{const r=t===l;return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex items-center gap-3 pb-2 pt-2",children:[e.jsx("span",{className:"flex-1",children:s}),e.jsx("span",{className:r?"opacity-[0.65] font-normal":"font-semibold",children:W(t)}),!r&&e.jsxs("span",{className:"opacity-[0.45]",children:["→ ",W(l)]})]}),!a&&e.jsx(A,{})]})},ve=()=>{const[s,t]=u.useState(void 0),[l,a]=u.useState(!1),{toast:r}=U();u.useEffect(()=>{he().then(t)},[]);const h=async()=>{a(!0);const n=await pe();a(!1),(n==null?void 0:n.status)==="ok"?(t(n),r({title:"Merge policy applied",variant:"success"})):r({title:"Failed to apply merge policy",description:(n==null?void 0:n.status)==="unavailable"?n.reason:void 0,variant:"error"})},p=(s==null?void 0:s.status)==="ok"&&fe(s.policy);return e.jsxs("div",{children:[e.jsxs("div",{className:"mb-6",children:[e.jsx("h2",{className:"m-0",children:"Merge Policy"}),e.jsx("p",{className:"opacity-50 mt-1",children:"Paper Camp's canonical policy: squash-only merges, with the commit title and body taken from the PR."})]}),s===void 0&&e.jsx("p",{children:"Loading…"}),s===null&&e.jsx(L,{variant:"warning",children:"Failed to load merge policy."}),(s==null?void 0:s.status)==="unavailable"&&e.jsx(L,{variant:"warning",children:s.reason}),(s==null?void 0:s.status)==="ok"&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex items-center gap-3 mb-3",children:[e.jsx("span",{className:"font-medium",children:s.repo}),e.jsx(F,{size:"small",fillColor:p?_.upToDate.fill:_.outdated.fill,textColor:p?_.upToDate.text:_.outdated.text,children:p?"Matches recommended policy":"Differs from recommended policy"})]}),e.jsx(P,{size:"small",texture:"kraft",children:Y.map((n,o)=>e.jsx(je,{label:n.label,current:s.policy[n.key],recommended:se[n.key],isLast:o===Y.length-1},n.key))}),e.jsx("div",{className:"mt-4",children:e.jsx(S,{size:"small",onClick:h,disabled:l||p,children:l?"Applying…":"Apply recommended policy"})})]})]})},be=()=>{const s=u.useRef(null),[t,l]=u.useState(void 0),{iconDataUri:a,loading:r}=te(),[h,p]=u.useState(null),n=h??a,[o,y]=u.useState(!1),[v,x]=u.useState(""),[N,k]=u.useState(""),{toast:g}=U();return u.useEffect(()=>{X().then(i=>{l(i),(i==null?void 0:i.port)!==void 0&&x(String(i.port)),(i==null?void 0:i.projectName)!==void 0&&k(i.projectName)})},[]),{fileRef:s,config:t,identityLoading:r,iconDataUri:n,uploading:o,portInput:v,setPortInput:x,nameInput:N,setNameInput:k,handleSaveAgentConfig:async(i,b)=>{const d=t==null?void 0:t.defaultAgents,j={phase:(d==null?void 0:d.phase)??I.phase,planDraft:(d==null?void 0:d.planDraft)??I.planDraft,ideaExtend:(d==null?void 0:d.ideaExtend)??I.ideaExtend,commitSuggest:(d==null?void 0:d.commitSuggest)??I.commitSuggest,feedback:(d==null?void 0:d.feedback)??I.feedback,codeReview:(d==null?void 0:d.codeReview)??I.codeReview,[i]:b};if(i==="codeReview"&&ne(b,j.phase)){g({title:"Failed to save",description:"Code review must use a different model than Phase run.",variant:"error"});return}const{ok:R,error:E}=await D({defaultAgents:j});R?(l(T=>T&&{...T,defaultAgents:j}),g({title:"Saved",variant:"success"})):g({title:"Failed to save",description:E,variant:"error"})},handleSavePort:async()=>{const i=Number(v);if(!t||!Number.isInteger(i)||i<=0||i===t.port)return;const{ok:b,error:d}=await D({port:i});b?(l(j=>j&&{...j,port:i}),g({title:"Saved",description:"Restart `paper-camp dev` to apply the new port.",variant:"success"})):g({title:"Failed to save",description:d,variant:"error"})},handleToggleIntegration:async()=>{var R,E,T;if(!t)return;const i=!(((E=(R=t.integration)==null?void 0:R.toolbar)==null?void 0:E.enabled)??!0),b={...t.integration,toolbar:{...(T=t.integration)==null?void 0:T.toolbar,enabled:i}},{ok:d,error:j}=await D({integration:b});d?(l(O=>O&&{...O,integration:b}),g({title:"Saved",variant:"success"})):g({title:"Failed to save",description:j,variant:"error"})},handleSaveName:async()=>{const i=N.trim();if(!t||!i||i===t.projectName)return;const{ok:b,error:d}=await D({projectName:i});b?(l(j=>j&&{...j,projectName:i}),k(i),g({title:"Saved",variant:"success"})):g({title:"Failed to save",description:d,variant:"error"})},handleFile:async i=>{var j;const b=(j=i.target.files)==null?void 0:j[0];if(!b)return;y(!0);const d=new FileReader;d.onloadend=async()=>{const R=d.result,E=await ae(R);y(!1),E?(p(R),g({title:"Saved",variant:"success"})):g({title:"Failed to save",variant:"error"})},d.readAsDataURL(b)}}},ye=()=>{const[s,t]=u.useState(null),[l,a]=u.useState(!1),[r,h]=u.useState(null),[p,n]=u.useState(null),[o,y]=u.useState(!1),{toast:v}=U(),x=u.useCallback(c=>{if(c===null){a(!0);return}a(!1),t(c)},[]);u.useEffect(()=>{H().then(x),X().then(c=>y((c==null?void 0:c.setupDismissed)??!1))},[x]);const N=async c=>{h(c),x(await H()),h(null)},k=async c=>{n(c);const w=await le(c);w?t(i=>(i==null?void 0:i.map(b=>b.id===c?w:b))??i):v({title:"Failed to connect",variant:"error"}),n(null)},g=async()=>{const c=!o,{ok:w}=await D({setupDismissed:c});w?(y(c),v({title:"Saved",variant:"success"})):v({title:"Failed to save",variant:"error"})},m=(s==null?void 0:s.every(c=>c.status==="ok"))??!0,f=(s==null?void 0:s.filter(c=>c.kind==="external"))??[],C=(s==null?void 0:s.filter(c=>c.kind==="local"))??[];return{connections:s,loadFailed:l,reloadingId:r,connectingId:p,setupDismissed:o,handleRecheck:N,handleConnect:k,handleDismissToggle:g,allOk:m,externalConnections:f,localConnections:C}},Ne=2e3,Se=s=>{const t=z(o=>o.loginRelay),l=z(o=>o.startLoginRelay),a=z(o=>o.loadLoginRelayStatus),r=z(o=>o.cancelLoginRelay),{toast:h}=U(),p=u.useRef(null),n=t==null?void 0:t.phase;return u.useEffect(()=>{if(n!=="starting"&&n!=="awaiting-authorization")return;const o=window.setInterval(()=>a(),Ne);return()=>window.clearInterval(o)},[n,a]),u.useEffect(()=>{const o=t==null?void 0:t.authorizeUrl;n!=="awaiting-authorization"||!o||p.current===o||(p.current=o,window.open(o,"_blank","noopener,noreferrer"))},[n,t==null?void 0:t.authorizeUrl]),u.useEffect(()=>{n==="success"?(h({title:"Signed in",variant:"success"}),s()):n==="error"&&h({title:"Sign-in failed",description:t==null?void 0:t.error,variant:"error"})},[n]),{phase:n,authorizeUrl:t==null?void 0:t.authorizeUrl,startLoginRelay:l,cancelLoginRelay:r}},we=({connection:s,onConnect:t,connecting:l})=>{const{connect:a}=s;return a?a.kind==="command"&&a.runnable?e.jsx(S,{size:"small",onClick:()=>t(s.id),disabled:l,children:l?"Running…":`Run \`${a.command}\``}):a.kind==="command"?e.jsx("div",{className:"mt-2",children:e.jsx(Q,{code:a.command})}):a.kind==="link"?e.jsx(S,{size:"small",onClick:()=>window.open(a.url,"_blank","noopener,noreferrer"),children:a.label}):e.jsx("p",{className:"opacity-[0.65] text-sm mt-2 mx-0 mb-0",children:a.message}):null},ke=["claude auth login","claude setup-token"],Ae=()=>e.jsxs("div",{className:"mt-2 flex flex-col gap-2",children:[e.jsx("p",{className:"opacity-[0.65] text-sm m-0",children:"The in-app relay couldn't complete. Run one of these in a terminal instead:"}),ke.map(s=>e.jsx(Q,{code:s},s)),e.jsxs("p",{className:"opacity-50 text-sm m-0",children:["Alternatively, set ",e.jsx("code",{children:"ANTHROPIC_API_KEY"})," in the server's environment — that bills as API usage rather than your Max subscription, so treat it as a fallback, not the default."]})]}),Ce=({onSignedIn:s})=>{const{phase:t,authorizeUrl:l,startLoginRelay:a,cancelLoginRelay:r}=Se(s);return t==="starting"?e.jsx(S,{size:"small",disabled:!0,children:"Starting…"}):t==="awaiting-authorization"?e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(S,{size:"small",onClick:()=>l&&window.open(l,"_blank","noopener,noreferrer"),children:"Reopen sign-in tab"}),e.jsx(S,{size:"small",onClick:()=>r(),children:"Cancel"})]}):e.jsxs("div",{children:[e.jsx(S,{size:"small",onClick:()=>a(),children:"Sign in"}),t==="error"&&e.jsx(Ae,{})]})},Ie="agent:claude-code",J=({connection:s,isLast:t,onRecheck:l,rechecking:a,onConnect:r,connecting:h})=>{const p=xe[s.status];return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"pb-3 pt-3",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{className:"flex-1 font-medium",children:s.label}),s.authenticated===!1&&e.jsx(ie,{content:"Installed, but not signed in",children:e.jsx(F,{size:"small",variant:"warning",children:"Not signed in"})}),e.jsx(F,{size:"small",fillColor:p.fill,textColor:p.text,children:p.label}),e.jsx(S,{size:"small",onClick:()=>l(s.id),disabled:a,children:a?"Checking…":"Recheck"})]}),e.jsxs("p",{className:"opacity-[0.65] text-sm mt-1 mx-0 mb-0",children:["Unlocks: ",s.unlocks]}),e.jsx("p",{className:"opacity-50 text-sm mt-1 mx-0 mb-0",children:s.detail}),e.jsx("div",{className:"mt-2",children:s.id===Ie&&s.authenticated===!1?e.jsx(Ce,{onSignedIn:()=>l(s.id)}):e.jsx(we,{connection:s,onConnect:r,connecting:h})})]}),!t&&e.jsx(A,{})]})},Re=()=>{const{connections:s,loadFailed:t,reloadingId:l,connectingId:a,setupDismissed:r,handleRecheck:h,handleConnect:p,handleDismissToggle:n,allOk:o,externalConnections:y,localConnections:v}=ye();return e.jsxs("div",{children:[e.jsx("div",{className:"mb-6",children:e.jsx("h2",{className:"m-0",children:"Setup"})}),s===null&&!t&&e.jsx("p",{children:"Loading…"}),t&&e.jsx("div",{className:"mb-4",children:e.jsx(L,{variant:"warning",children:"Failed to load connections. Try refreshing."})}),s&&e.jsxs(e.Fragment,{children:[!o&&e.jsx("div",{className:"mb-4",children:e.jsx(L,{variant:"warning",children:"Some connections are incomplete — features that depend on them stay disabled until fixed. Run the connect command below, then recheck."})}),y.length>0&&e.jsxs("div",{className:"mb-4",children:[e.jsx("p",{className:"opacity-[0.45] text-sm mt-0 mb-2",children:"External services — reached on your behalf with their own remote credential."}),e.jsx(P,{size:"small",texture:"kraft",children:y.map((x,N)=>e.jsx(J,{connection:x,isLast:N===y.length-1,onRecheck:h,rechecking:l===x.id,onConnect:p,connecting:a===x.id},x.id))})]}),v.length>0&&e.jsxs("div",{className:"mb-4",children:[e.jsx("p",{className:"opacity-[0.45] text-sm mt-0 mb-2",children:"Local adapters — driven on this machine with their own local session."}),e.jsx(P,{size:"small",texture:"kraft",children:v.map((x,N)=>e.jsx(J,{connection:x,isLast:N===v.length-1,onRecheck:h,rechecking:l===x.id,onConnect:p,connecting:a===x.id},x.id))})]}),e.jsx("div",{className:"mt-4",children:e.jsx(S,{size:"small",onClick:n,children:r?"Show Setup on open again":"Don't show Setup on open"})})]})]})},Ee=()=>{const{subjects:s,loading:t,available:l}=oe(),a=Z();return e.jsxs("div",{children:[e.jsxs("div",{className:"mb-6",children:[e.jsx("h2",{className:"m-0",children:"Subjects"}),e.jsx("p",{className:"opacity-50 mt-1",children:"Subjects are the roadmap's bets and standing concerns. Edit the vocabulary on the Roadmap page."})]}),t&&e.jsx("p",{children:"Loading…"}),!t&&!l&&e.jsx("p",{className:"opacity-60 m-0",children:"Couldn't load subjects — check the server config."}),!t&&l&&e.jsxs(P,{size:"small",texture:"kraft",children:[s.length===0&&e.jsx("p",{className:"opacity-[0.45] m-0 pb-2",children:"No subjects yet."}),s.map((r,h)=>e.jsxs("div",{children:[e.jsx("div",{className:"pb-2 pt-2",children:r}),h<s.length-1&&e.jsx(A,{})]},r)),s.length>0&&e.jsx(A,{}),e.jsx("div",{className:"pt-3",children:e.jsx(S,{size:"small",onClick:()=>a({to:"/roadmap"}),children:"Go to Roadmap"})})]})]})},Te=140,De=160,Le=110,Pe=({taskKey:s,agentConfig:t,isLast:l,onSave:a,authorConfig:r})=>{const h=q[t.agent]??q["claude-code"],p=r&&r.agent===t.agent?r.model??"":void 0,n=Array.isArray(h.model)?h.model.filter(m=>m!==p):h.model,o=h.effort,[y,v]=u.useState(t.model??"");u.useEffect(()=>{v(t.model??"")},[t.model]);const x=m=>{var w;const f=m,C=q[f],c={agent:f};t.model&&(C.model===null||(w=C.model)!=null&&w.includes(t.model))&&(c.model=t.model),t.effort&&Array.isArray(C.effort)&&(c.effort=t.effort),a(s,c)},N=m=>{a(s,{...t,model:m||void 0})},k=()=>{a(s,{...t,model:y||void 0})},g=m=>{a(s,{...t,effort:m||void 0})};return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex items-center gap-3 pb-2 pt-2",children:[e.jsx("span",{className:"w-[110px] shrink-0 text-sm opacity-[0.65]",children:ue[s]}),e.jsx(B,{size:"small",width:Te,value:t.agent,onChange:x,options:ce.map(m=>({value:m,label:re[m]}))}),Array.isArray(n)?e.jsx(B,{size:"small",width:De,value:t.model??"",onChange:N,options:[...p===""?[]:[{value:"",label:"Default"}],...n.map(m=>({value:m,label:m}))]}):n===null?e.jsx(G,{size:"small",className:"w-[160px]",value:y,placeholder:"Default model",onChange:m=>v(m.target.value),onBlur:k}):null,e.jsx("div",{className:Array.isArray(o)?"visible":"invisible",children:e.jsx(B,{size:"small",width:Le,value:t.effort??"",onChange:g,options:[{value:"",label:"Default"},...(Array.isArray(o)?o:[]).map(m=>({value:m,label:m}))]})})]}),!l&&e.jsx(A,{})]})},ze=()=>e.jsxs("div",{className:"flex items-center gap-3 pb-1",children:[e.jsx("span",{className:"w-[110px] shrink-0 text-sm opacity-[0.45]",children:"Task"}),e.jsx("span",{className:"w-[140px] shrink-0 text-sm opacity-[0.45]",children:"Agent"}),e.jsx("span",{className:"w-[160px] shrink-0 text-sm opacity-[0.45]",children:"Model"}),e.jsx("span",{className:"w-[110px] shrink-0 text-sm opacity-[0.45]",children:"Effort"})]}),Me=()=>{var g,m;const{fileRef:s,config:t,identityLoading:l,iconDataUri:a,uploading:r,portInput:h,setPortInput:p,nameInput:n,setNameInput:o,handleSaveAgentConfig:y,handleSavePort:v,handleToggleIntegration:x,handleSaveName:N,handleFile:k}=be();return e.jsxs("div",{children:[e.jsx("div",{className:"mb-6",children:e.jsx("h2",{className:"m-0",children:"Project Info"})}),t===void 0&&e.jsx("p",{children:"Loading…"}),t===null&&e.jsxs(L,{variant:"warning",children:["No papercamp/config.json found — run ",e.jsx("code",{children:"paper-camp init"})," in this directory first."]}),t&&e.jsxs(P,{size:"small",texture:"kraft",children:[e.jsxs("div",{className:"flex items-end gap-3 pb-3",children:[e.jsx(G,{value:n,onChange:f=>o(f.target.value),onBlur:N,label:"Project Name"}),e.jsxs(F,{size:"small",fillColor:ge,textColor:de.accentGreenDark,children:["v",t.version]})]}),e.jsx(A,{}),e.jsxs("div",{className:"flex items-center gap-3 pb-3 pt-3",children:[a&&e.jsx("img",{src:a,alt:"Project icon",className:"w-10 h-10 object-contain shrink-0 rounded"}),e.jsxs("div",{children:[e.jsx("input",{ref:s,type:"file",accept:".svg,.png,.jpg,.jpeg,.gif,.webp",onChange:k,className:"hidden"}),e.jsx(S,{size:"small",onClick:()=>{var f;return(f=s.current)==null?void 0:f.click()},disabled:r,children:r?"Uploading…":"Choose File"}),l&&e.jsx("p",{className:"text-sm opacity-50 mt-1 mx-0 mb-0",children:"Loading…"}),!l&&!a&&!r&&e.jsx("p",{className:"text-sm opacity-[0.45] mt-1 mx-0 mb-0",children:"No icon set."})]})]}),e.jsx(A,{}),e.jsx("div",{className:"flex items-end gap-3 pb-3 pt-3",children:e.jsx(G,{type:"number",value:h,onChange:f=>p(f.target.value),onBlur:v,label:"Port",helperText:"Default for `paper-camp dev`. Restart the server to apply a change."})}),e.jsx(A,{}),e.jsxs("div",{className:"flex items-center justify-between gap-3 pb-3 pt-3",children:[e.jsxs("div",{children:[e.jsx("p",{className:"m-0",children:"In-app dev toolbar"}),e.jsx("p",{className:"opacity-[0.45] text-sm mt-1 mx-0 mb-0",children:"Inject the paper-camp toolbar into this project's dev server via the Vite plugin."})]}),e.jsx(S,{size:"small",onClick:x,children:((m=(g=t.integration)==null?void 0:g.toolbar)==null?void 0:m.enabled)??!0?"Disable":"Enable"})]}),e.jsx(A,{}),e.jsx(ze,{}),V.map((f,C)=>{var c,w;return e.jsx(Pe,{taskKey:f,agentConfig:((c=t.defaultAgents)==null?void 0:c[f])??I[f],isLast:C===V.length-1,onSave:y,authorConfig:f==="codeReview"?((w=t.defaultAgents)==null?void 0:w.phase)??I.phase:void 0},f)})]}),e.jsxs("p",{className:"opacity-[0.45] text-sm mt-4",children:[e.jsx("strong",{children:"Initialized:"})," ",t?new Date(t.initializedAt).toLocaleString():"—"]})]})},Ue=()=>{const s=ee();return e.jsxs("div",{children:[e.jsx(me,{children:"Settings"}),s==="subjects"?e.jsx(Ee,{}):s==="setup"?e.jsx(Re,{}):s==="merge-policy"?e.jsx(ve,{}):e.jsx(Me,{})]})},Oe=()=>{const s=ee(),t=Z();return e.jsxs(e.Fragment,{children:[e.jsxs($,{label:"General",children:[e.jsx(M,{size:"small",className:"pc-row text-xs",active:s===null,onClick:()=>t({to:"/settings"}),children:"Project Info"}),e.jsx(M,{size:"small",className:"pc-row text-xs",active:s==="setup",onClick:()=>t({to:"/settings/$section",params:{section:"setup"}}),children:"Setup"}),e.jsx(M,{size:"small",className:"pc-row text-xs",active:s==="merge-policy",onClick:()=>t({to:"/settings/$section",params:{section:"merge-policy"}}),children:"Merge Policy"})]}),e.jsx($,{label:"Ideas",children:e.jsx(M,{size:"small",className:"pc-row text-xs",active:s==="subjects",onClick:()=>t({to:"/settings/$section",params:{section:"subjects"}}),children:"Subjects"})})]})};export{Ue as SettingsPage,Oe as SettingsSidebar};
2
- //# sourceMappingURL=index-jxEIOkqg.js.map
1
+ import{c as K,r as u,C as U,j as e,e as L,g as F,R as P,J as S,w as A,h as te,k as X,l as ae,s as D,D as I,m as ne,n as H,o as le,u as z,t as Q,$ as ie,q as oe,a as Z,A as q,v as B,x as ce,y as re,i as G,z as de,B as ee,P as me,p as M}from"./main-C0TBUyF9.js";import{S as $}from"./sidebar-section-D0b_1DUA.js";const he=async()=>{try{const s=await fetch(K("/api/merge-policy"));return s.ok?await s.json():null}catch{return null}},pe=async()=>{try{const s=await fetch(K("/api/merge-policy/apply"),{method:"POST"});return s.ok?await s.json():null}catch{return null}},V=["phase","planDraft","ideaExtend","commitSuggest","feedback","codeReview"],ue={phase:"Phase run",planDraft:"Plan draft",ideaExtend:"Idea extend",commitSuggest:"Commit suggest",feedback:"Scout chat",codeReview:"Code review"},xe={ok:{fill:"rgba(143, 185, 150, 0.25)",text:"#5E8A66",label:"Ready"},warn:{fill:"rgba(212, 163, 115, 0.25)",text:"#A67B4F",label:"Needs attention"},missing:{fill:"rgba(201, 139, 139, 0.25)",text:"#6E3A3A",label:"Missing"}},_={upToDate:{fill:"rgba(143, 185, 150, 0.25)",text:"#5E8A66"},outdated:{fill:"rgba(212, 163, 115, 0.25)",text:"#A67B4F"}},ge="rgba(143, 185, 150, 0.25)",se={allowSquashMerge:!0,allowMergeCommit:!1,allowRebaseMerge:!1,squashMergeCommitTitle:"PR_TITLE",squashMergeCommitMessage:"PR_BODY"},Y=[{key:"allowSquashMerge",label:"Allow squash merge"},{key:"allowMergeCommit",label:"Allow merge commit"},{key:"allowRebaseMerge",label:"Allow rebase merge"},{key:"squashMergeCommitTitle",label:"Squash commit title"},{key:"squashMergeCommitMessage",label:"Squash commit message"}];function W(s){return typeof s=="boolean"?s?"Yes":"No":s}function fe(s){return Y.every(t=>s[t.key]===se[t.key])}const je=({label:s,current:t,recommended:l,isLast:a})=>{const r=t===l;return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex items-center gap-3 pb-2 pt-2",children:[e.jsx("span",{className:"flex-1",children:s}),e.jsx("span",{className:r?"opacity-[0.65] font-normal":"font-semibold",children:W(t)}),!r&&e.jsxs("span",{className:"opacity-[0.45]",children:["→ ",W(l)]})]}),!a&&e.jsx(A,{})]})},ve=()=>{const[s,t]=u.useState(void 0),[l,a]=u.useState(!1),{toast:r}=U();u.useEffect(()=>{he().then(t)},[]);const h=async()=>{a(!0);const n=await pe();a(!1),(n==null?void 0:n.status)==="ok"?(t(n),r({title:"Merge policy applied",variant:"success"})):r({title:"Failed to apply merge policy",description:(n==null?void 0:n.status)==="unavailable"?n.reason:void 0,variant:"error"})},p=(s==null?void 0:s.status)==="ok"&&fe(s.policy);return e.jsxs("div",{children:[e.jsxs("div",{className:"mb-6",children:[e.jsx("h2",{className:"m-0",children:"Merge Policy"}),e.jsx("p",{className:"opacity-50 mt-1",children:"Paper Camp's canonical policy: squash-only merges, with the commit title and body taken from the PR."})]}),s===void 0&&e.jsx("p",{children:"Loading…"}),s===null&&e.jsx(L,{variant:"warning",children:"Failed to load merge policy."}),(s==null?void 0:s.status)==="unavailable"&&e.jsx(L,{variant:"warning",children:s.reason}),(s==null?void 0:s.status)==="ok"&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex items-center gap-3 mb-3",children:[e.jsx("span",{className:"font-medium",children:s.repo}),e.jsx(F,{size:"small",fillColor:p?_.upToDate.fill:_.outdated.fill,textColor:p?_.upToDate.text:_.outdated.text,children:p?"Matches recommended policy":"Differs from recommended policy"})]}),e.jsx(P,{size:"small",texture:"kraft",children:Y.map((n,o)=>e.jsx(je,{label:n.label,current:s.policy[n.key],recommended:se[n.key],isLast:o===Y.length-1},n.key))}),e.jsx("div",{className:"mt-4",children:e.jsx(S,{size:"small",onClick:h,disabled:l||p,children:l?"Applying…":"Apply recommended policy"})})]})]})},be=()=>{const s=u.useRef(null),[t,l]=u.useState(void 0),{iconDataUri:a,loading:r}=te(),[h,p]=u.useState(null),n=h??a,[o,y]=u.useState(!1),[v,x]=u.useState(""),[N,k]=u.useState(""),{toast:g}=U();return u.useEffect(()=>{X().then(i=>{l(i),(i==null?void 0:i.port)!==void 0&&x(String(i.port)),(i==null?void 0:i.projectName)!==void 0&&k(i.projectName)})},[]),{fileRef:s,config:t,identityLoading:r,iconDataUri:n,uploading:o,portInput:v,setPortInput:x,nameInput:N,setNameInput:k,handleSaveAgentConfig:async(i,b)=>{const d=t==null?void 0:t.defaultAgents,j={phase:(d==null?void 0:d.phase)??I.phase,planDraft:(d==null?void 0:d.planDraft)??I.planDraft,ideaExtend:(d==null?void 0:d.ideaExtend)??I.ideaExtend,commitSuggest:(d==null?void 0:d.commitSuggest)??I.commitSuggest,feedback:(d==null?void 0:d.feedback)??I.feedback,codeReview:(d==null?void 0:d.codeReview)??I.codeReview,[i]:b};if(i==="codeReview"&&ne(b,j.phase)){g({title:"Failed to save",description:"Code review must use a different model than Phase run.",variant:"error"});return}const{ok:R,error:E}=await D({defaultAgents:j});R?(l(T=>T&&{...T,defaultAgents:j}),g({title:"Saved",variant:"success"})):g({title:"Failed to save",description:E,variant:"error"})},handleSavePort:async()=>{const i=Number(v);if(!t||!Number.isInteger(i)||i<=0||i===t.port)return;const{ok:b,error:d}=await D({port:i});b?(l(j=>j&&{...j,port:i}),g({title:"Saved",description:"Restart `paper-camp dev` to apply the new port.",variant:"success"})):g({title:"Failed to save",description:d,variant:"error"})},handleToggleIntegration:async()=>{var R,E,T;if(!t)return;const i=!(((E=(R=t.integration)==null?void 0:R.toolbar)==null?void 0:E.enabled)??!0),b={...t.integration,toolbar:{...(T=t.integration)==null?void 0:T.toolbar,enabled:i}},{ok:d,error:j}=await D({integration:b});d?(l(O=>O&&{...O,integration:b}),g({title:"Saved",variant:"success"})):g({title:"Failed to save",description:j,variant:"error"})},handleSaveName:async()=>{const i=N.trim();if(!t||!i||i===t.projectName)return;const{ok:b,error:d}=await D({projectName:i});b?(l(j=>j&&{...j,projectName:i}),k(i),g({title:"Saved",variant:"success"})):g({title:"Failed to save",description:d,variant:"error"})},handleFile:async i=>{var j;const b=(j=i.target.files)==null?void 0:j[0];if(!b)return;y(!0);const d=new FileReader;d.onloadend=async()=>{const R=d.result,E=await ae(R);y(!1),E?(p(R),g({title:"Saved",variant:"success"})):g({title:"Failed to save",variant:"error"})},d.readAsDataURL(b)}}},ye=()=>{const[s,t]=u.useState(null),[l,a]=u.useState(!1),[r,h]=u.useState(null),[p,n]=u.useState(null),[o,y]=u.useState(!1),{toast:v}=U(),x=u.useCallback(c=>{if(c===null){a(!0);return}a(!1),t(c)},[]);u.useEffect(()=>{H().then(x),X().then(c=>y((c==null?void 0:c.setupDismissed)??!1))},[x]);const N=async c=>{h(c),x(await H()),h(null)},k=async c=>{n(c);const w=await le(c);w?t(i=>(i==null?void 0:i.map(b=>b.id===c?w:b))??i):v({title:"Failed to connect",variant:"error"}),n(null)},g=async()=>{const c=!o,{ok:w}=await D({setupDismissed:c});w?(y(c),v({title:"Saved",variant:"success"})):v({title:"Failed to save",variant:"error"})},m=(s==null?void 0:s.every(c=>c.status==="ok"))??!0,f=(s==null?void 0:s.filter(c=>c.kind==="external"))??[],C=(s==null?void 0:s.filter(c=>c.kind==="local"))??[];return{connections:s,loadFailed:l,reloadingId:r,connectingId:p,setupDismissed:o,handleRecheck:N,handleConnect:k,handleDismissToggle:g,allOk:m,externalConnections:f,localConnections:C}},Ne=2e3,Se=s=>{const t=z(o=>o.loginRelay),l=z(o=>o.startLoginRelay),a=z(o=>o.loadLoginRelayStatus),r=z(o=>o.cancelLoginRelay),{toast:h}=U(),p=u.useRef(null),n=t==null?void 0:t.phase;return u.useEffect(()=>{if(n!=="starting"&&n!=="awaiting-authorization")return;const o=window.setInterval(()=>a(),Ne);return()=>window.clearInterval(o)},[n,a]),u.useEffect(()=>{const o=t==null?void 0:t.authorizeUrl;n!=="awaiting-authorization"||!o||p.current===o||(p.current=o,window.open(o,"_blank","noopener,noreferrer"))},[n,t==null?void 0:t.authorizeUrl]),u.useEffect(()=>{n==="success"?(h({title:"Signed in",variant:"success"}),s()):n==="error"&&h({title:"Sign-in failed",description:t==null?void 0:t.error,variant:"error"})},[n]),{phase:n,authorizeUrl:t==null?void 0:t.authorizeUrl,startLoginRelay:l,cancelLoginRelay:r}},we=({connection:s,onConnect:t,connecting:l})=>{const{connect:a}=s;return a?a.kind==="command"&&a.runnable?e.jsx(S,{size:"small",onClick:()=>t(s.id),disabled:l,children:l?"Running…":`Run \`${a.command}\``}):a.kind==="command"?e.jsx("div",{className:"mt-2",children:e.jsx(Q,{code:a.command})}):a.kind==="link"?e.jsx(S,{size:"small",onClick:()=>window.open(a.url,"_blank","noopener,noreferrer"),children:a.label}):e.jsx("p",{className:"opacity-[0.65] text-sm mt-2 mx-0 mb-0",children:a.message}):null},ke=["claude auth login","claude setup-token"],Ae=()=>e.jsxs("div",{className:"mt-2 flex flex-col gap-2",children:[e.jsx("p",{className:"opacity-[0.65] text-sm m-0",children:"The in-app relay couldn't complete. Run one of these in a terminal instead:"}),ke.map(s=>e.jsx(Q,{code:s},s)),e.jsxs("p",{className:"opacity-50 text-sm m-0",children:["Alternatively, set ",e.jsx("code",{children:"ANTHROPIC_API_KEY"})," in the server's environment — that bills as API usage rather than your Max subscription, so treat it as a fallback, not the default."]})]}),Ce=({onSignedIn:s})=>{const{phase:t,authorizeUrl:l,startLoginRelay:a,cancelLoginRelay:r}=Se(s);return t==="starting"?e.jsx(S,{size:"small",disabled:!0,children:"Starting…"}):t==="awaiting-authorization"?e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(S,{size:"small",onClick:()=>l&&window.open(l,"_blank","noopener,noreferrer"),children:"Reopen sign-in tab"}),e.jsx(S,{size:"small",onClick:()=>r(),children:"Cancel"})]}):e.jsxs("div",{children:[e.jsx(S,{size:"small",onClick:()=>a(),children:"Sign in"}),t==="error"&&e.jsx(Ae,{})]})},Ie="agent:claude-code",J=({connection:s,isLast:t,onRecheck:l,rechecking:a,onConnect:r,connecting:h})=>{const p=xe[s.status];return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"pb-3 pt-3",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{className:"flex-1 font-medium",children:s.label}),s.authenticated===!1&&e.jsx(ie,{content:"Installed, but not signed in",children:e.jsx(F,{size:"small",variant:"warning",children:"Not signed in"})}),e.jsx(F,{size:"small",fillColor:p.fill,textColor:p.text,children:p.label}),e.jsx(S,{size:"small",onClick:()=>l(s.id),disabled:a,children:a?"Checking…":"Recheck"})]}),e.jsxs("p",{className:"opacity-[0.65] text-sm mt-1 mx-0 mb-0",children:["Unlocks: ",s.unlocks]}),e.jsx("p",{className:"opacity-50 text-sm mt-1 mx-0 mb-0",children:s.detail}),e.jsx("div",{className:"mt-2",children:s.id===Ie&&s.authenticated===!1?e.jsx(Ce,{onSignedIn:()=>l(s.id)}):e.jsx(we,{connection:s,onConnect:r,connecting:h})})]}),!t&&e.jsx(A,{})]})},Re=()=>{const{connections:s,loadFailed:t,reloadingId:l,connectingId:a,setupDismissed:r,handleRecheck:h,handleConnect:p,handleDismissToggle:n,allOk:o,externalConnections:y,localConnections:v}=ye();return e.jsxs("div",{children:[e.jsx("div",{className:"mb-6",children:e.jsx("h2",{className:"m-0",children:"Setup"})}),s===null&&!t&&e.jsx("p",{children:"Loading…"}),t&&e.jsx("div",{className:"mb-4",children:e.jsx(L,{variant:"warning",children:"Failed to load connections. Try refreshing."})}),s&&e.jsxs(e.Fragment,{children:[!o&&e.jsx("div",{className:"mb-4",children:e.jsx(L,{variant:"warning",children:"Some connections are incomplete — features that depend on them stay disabled until fixed. Run the connect command below, then recheck."})}),y.length>0&&e.jsxs("div",{className:"mb-4",children:[e.jsx("p",{className:"opacity-[0.45] text-sm mt-0 mb-2",children:"External services — reached on your behalf with their own remote credential."}),e.jsx(P,{size:"small",texture:"kraft",children:y.map((x,N)=>e.jsx(J,{connection:x,isLast:N===y.length-1,onRecheck:h,rechecking:l===x.id,onConnect:p,connecting:a===x.id},x.id))})]}),v.length>0&&e.jsxs("div",{className:"mb-4",children:[e.jsx("p",{className:"opacity-[0.45] text-sm mt-0 mb-2",children:"Local adapters — driven on this machine with their own local session."}),e.jsx(P,{size:"small",texture:"kraft",children:v.map((x,N)=>e.jsx(J,{connection:x,isLast:N===v.length-1,onRecheck:h,rechecking:l===x.id,onConnect:p,connecting:a===x.id},x.id))})]}),e.jsx("div",{className:"mt-4",children:e.jsx(S,{size:"small",onClick:n,children:r?"Show Setup on open again":"Don't show Setup on open"})})]})]})},Ee=()=>{const{subjects:s,loading:t,available:l}=oe(),a=Z();return e.jsxs("div",{children:[e.jsxs("div",{className:"mb-6",children:[e.jsx("h2",{className:"m-0",children:"Subjects"}),e.jsx("p",{className:"opacity-50 mt-1",children:"Subjects are the roadmap's bets and standing concerns. Edit the vocabulary on the Roadmap page."})]}),t&&e.jsx("p",{children:"Loading…"}),!t&&!l&&e.jsx("p",{className:"opacity-60 m-0",children:"Couldn't load subjects — check the server config."}),!t&&l&&e.jsxs(P,{size:"small",texture:"kraft",children:[s.length===0&&e.jsx("p",{className:"opacity-[0.45] m-0 pb-2",children:"No subjects yet."}),s.map((r,h)=>e.jsxs("div",{children:[e.jsx("div",{className:"pb-2 pt-2",children:r}),h<s.length-1&&e.jsx(A,{})]},r)),s.length>0&&e.jsx(A,{}),e.jsx("div",{className:"pt-3",children:e.jsx(S,{size:"small",onClick:()=>a({to:"/roadmap"}),children:"Go to Roadmap"})})]})]})},Te=140,De=160,Le=110,Pe=({taskKey:s,agentConfig:t,isLast:l,onSave:a,authorConfig:r})=>{const h=q[t.agent]??q["claude-code"],p=r&&r.agent===t.agent?r.model??"":void 0,n=Array.isArray(h.model)?h.model.filter(m=>m!==p):h.model,o=h.effort,[y,v]=u.useState(t.model??"");u.useEffect(()=>{v(t.model??"")},[t.model]);const x=m=>{var w;const f=m,C=q[f],c={agent:f};t.model&&(C.model===null||(w=C.model)!=null&&w.includes(t.model))&&(c.model=t.model),t.effort&&Array.isArray(C.effort)&&(c.effort=t.effort),a(s,c)},N=m=>{a(s,{...t,model:m||void 0})},k=()=>{a(s,{...t,model:y||void 0})},g=m=>{a(s,{...t,effort:m||void 0})};return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex items-center gap-3 pb-2 pt-2",children:[e.jsx("span",{className:"w-[110px] shrink-0 text-sm opacity-[0.65]",children:ue[s]}),e.jsx(B,{size:"small",width:Te,value:t.agent,onChange:x,options:ce.map(m=>({value:m,label:re[m]}))}),Array.isArray(n)?e.jsx(B,{size:"small",width:De,value:t.model??"",onChange:N,options:[...p===""?[]:[{value:"",label:"Default"}],...n.map(m=>({value:m,label:m}))]}):n===null?e.jsx(G,{size:"small",className:"w-[160px]",value:y,placeholder:"Default model",onChange:m=>v(m.target.value),onBlur:k}):null,e.jsx("div",{className:Array.isArray(o)?"visible":"invisible",children:e.jsx(B,{size:"small",width:Le,value:t.effort??"",onChange:g,options:[{value:"",label:"Default"},...(Array.isArray(o)?o:[]).map(m=>({value:m,label:m}))]})})]}),!l&&e.jsx(A,{})]})},ze=()=>e.jsxs("div",{className:"flex items-center gap-3 pb-1",children:[e.jsx("span",{className:"w-[110px] shrink-0 text-sm opacity-[0.45]",children:"Task"}),e.jsx("span",{className:"w-[140px] shrink-0 text-sm opacity-[0.45]",children:"Agent"}),e.jsx("span",{className:"w-[160px] shrink-0 text-sm opacity-[0.45]",children:"Model"}),e.jsx("span",{className:"w-[110px] shrink-0 text-sm opacity-[0.45]",children:"Effort"})]}),Me=()=>{var g,m;const{fileRef:s,config:t,identityLoading:l,iconDataUri:a,uploading:r,portInput:h,setPortInput:p,nameInput:n,setNameInput:o,handleSaveAgentConfig:y,handleSavePort:v,handleToggleIntegration:x,handleSaveName:N,handleFile:k}=be();return e.jsxs("div",{children:[e.jsx("div",{className:"mb-6",children:e.jsx("h2",{className:"m-0",children:"Project Info"})}),t===void 0&&e.jsx("p",{children:"Loading…"}),t===null&&e.jsxs(L,{variant:"warning",children:["No papercamp/config.json found — run ",e.jsx("code",{children:"paper-camp init"})," in this directory first."]}),t&&e.jsxs(P,{size:"small",texture:"kraft",children:[e.jsxs("div",{className:"flex items-end gap-3 pb-3",children:[e.jsx(G,{value:n,onChange:f=>o(f.target.value),onBlur:N,label:"Project Name"}),e.jsxs(F,{size:"small",fillColor:ge,textColor:de.accentGreenDark,children:["v",t.version]})]}),e.jsx(A,{}),e.jsxs("div",{className:"flex items-center gap-3 pb-3 pt-3",children:[a&&e.jsx("img",{src:a,alt:"Project icon",className:"w-10 h-10 object-contain shrink-0 rounded"}),e.jsxs("div",{children:[e.jsx("input",{ref:s,type:"file",accept:".svg,.png,.jpg,.jpeg,.gif,.webp",onChange:k,className:"hidden"}),e.jsx(S,{size:"small",onClick:()=>{var f;return(f=s.current)==null?void 0:f.click()},disabled:r,children:r?"Uploading…":"Choose File"}),l&&e.jsx("p",{className:"text-sm opacity-50 mt-1 mx-0 mb-0",children:"Loading…"}),!l&&!a&&!r&&e.jsx("p",{className:"text-sm opacity-[0.45] mt-1 mx-0 mb-0",children:"No icon set."})]})]}),e.jsx(A,{}),e.jsx("div",{className:"flex items-end gap-3 pb-3 pt-3",children:e.jsx(G,{type:"number",value:h,onChange:f=>p(f.target.value),onBlur:v,label:"Port",helperText:"Default for `paper-camp dev`. Restart the server to apply a change."})}),e.jsx(A,{}),e.jsxs("div",{className:"flex items-center justify-between gap-3 pb-3 pt-3",children:[e.jsxs("div",{children:[e.jsx("p",{className:"m-0",children:"In-app dev toolbar"}),e.jsx("p",{className:"opacity-[0.45] text-sm mt-1 mx-0 mb-0",children:"Inject the paper-camp toolbar into this project's dev server via the Vite plugin."})]}),e.jsx(S,{size:"small",onClick:x,children:((m=(g=t.integration)==null?void 0:g.toolbar)==null?void 0:m.enabled)??!0?"Disable":"Enable"})]}),e.jsx(A,{}),e.jsx(ze,{}),V.map((f,C)=>{var c,w;return e.jsx(Pe,{taskKey:f,agentConfig:((c=t.defaultAgents)==null?void 0:c[f])??I[f],isLast:C===V.length-1,onSave:y,authorConfig:f==="codeReview"?((w=t.defaultAgents)==null?void 0:w.phase)??I.phase:void 0},f)})]}),e.jsxs("p",{className:"opacity-[0.45] text-sm mt-4",children:[e.jsx("strong",{children:"Initialized:"})," ",t?new Date(t.initializedAt).toLocaleString():"—"]})]})},Ue=()=>{const s=ee();return e.jsxs("div",{children:[e.jsx(me,{children:"Settings"}),s==="subjects"?e.jsx(Ee,{}):s==="setup"?e.jsx(Re,{}):s==="merge-policy"?e.jsx(ve,{}):e.jsx(Me,{})]})},Oe=()=>{const s=ee(),t=Z();return e.jsxs(e.Fragment,{children:[e.jsxs($,{label:"General",children:[e.jsx(M,{size:"small",className:"pc-row text-xs",active:s===null,onClick:()=>t({to:"/settings"}),children:"Project Info"}),e.jsx(M,{size:"small",className:"pc-row text-xs",active:s==="setup",onClick:()=>t({to:"/settings/$section",params:{section:"setup"}}),children:"Setup"}),e.jsx(M,{size:"small",className:"pc-row text-xs",active:s==="merge-policy",onClick:()=>t({to:"/settings/$section",params:{section:"merge-policy"}}),children:"Merge Policy"})]}),e.jsx($,{label:"Ideas",children:e.jsx(M,{size:"small",className:"pc-row text-xs",active:s==="subjects",onClick:()=>t({to:"/settings/$section",params:{section:"subjects"}}),children:"Subjects"})})]})};export{Ue as SettingsPage,Oe as SettingsSidebar};
2
+ //# sourceMappingURL=index-siPA4naJ.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-jxEIOkqg.js","sources":["../../../src/app/services/system/merge-policy-api.ts","../../../src/app/features/settings/constants.ts","../../../src/app/features/settings/components/merge-policy-section.tsx","../../../src/app/features/settings/hooks/use-settings-page.ts","../../../src/app/features/settings/hooks/use-setup-section.ts","../../../src/app/features/settings/hooks/use-sign-in-action.ts","../../../src/app/features/settings/components/connect-action-view.tsx","../../../src/app/features/settings/components/relay-fallback-guide.tsx","../../../src/app/features/settings/components/sign-in-action.tsx","../../../src/app/features/settings/components/connection-row.tsx","../../../src/app/features/settings/components/setup-section.tsx","../../../src/app/features/settings/components/subjects-section.tsx","../../../src/app/features/settings/views/agent-task-row.tsx","../../../src/app/features/settings/views/agent-task-row-header.tsx","../../../src/app/features/settings/views/general-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 type { CapabilityStatus } from '@/types/index';\n\nexport const TASK_TYPE_KEYS = [\n 'phase',\n 'planDraft',\n 'ideaExtend',\n 'commitSuggest',\n 'feedback',\n 'codeReview',\n] as const;\nexport type TaskTypeKey = (typeof TASK_TYPE_KEYS)[number];\n\nexport const 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\nexport const CAPABILITY_STATUS_STAMP: Record<\n CapabilityStatus,\n { fill: string; text: string; label: string }\n> = {\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\nexport const MERGE_POLICY_STAMP: Record<'upToDate' | 'outdated', { fill: string; text: string }> = {\n upToDate: { fill: 'rgba(143, 185, 150, 0.25)', text: '#5E8A66' },\n outdated: { fill: 'rgba(212, 163, 115, 0.25)', text: '#A67B4F' },\n};\n\nexport const VERSION_STAMP_FILL = 'rgba(143, 185, 150, 0.25)';\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';\nimport { MERGE_POLICY_STAMP } from '../constants';\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={\n upToDate ? MERGE_POLICY_STAMP.upToDate.fill : MERGE_POLICY_STAMP.outdated.fill\n }\n textColor={\n upToDate ? MERGE_POLICY_STAMP.upToDate.text : MERGE_POLICY_STAMP.outdated.text\n }\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 { useProjectIdentity } from '@/app/hooks';\nimport { fetchConfig, saveConfig, uploadIcon } from '@/app/services/system';\nimport {\n type AgentConfig,\n DEFAULT_AGENTS,\n type DefaultAgentsMap,\n type PaperCampConfig,\n agentConfigsEqual,\n} from '@/types/index';\nimport { useToast } from '@dendelion/paper-ui';\nimport { useEffect, useRef, useState } from 'react';\nimport type { TaskTypeKey } from '../constants';\n\nexport const useSettingsPage = () => {\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 fileRef,\n config,\n identityLoading,\n iconDataUri,\n uploading,\n portInput,\n setPortInput,\n nameInput,\n setNameInput,\n handleSaveAgentConfig,\n handleSavePort,\n handleToggleIntegration,\n handleSaveName,\n handleFile,\n };\n};\n","import { connectService, fetchConfig, fetchConnections, saveConfig } from '@/app/services/system';\nimport type { ConnectionResult } from '@/types/index';\nimport { useToast } from '@dendelion/paper-ui';\nimport { useCallback, useEffect, useState } from 'react';\n\nexport const useSetupSection = () => {\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 const externalConnections = connections?.filter((c) => c.kind === 'external') ?? [];\n const localConnections = connections?.filter((c) => c.kind === 'local') ?? [];\n\n return {\n connections,\n loadFailed,\n reloadingId,\n connectingId,\n setupDismissed,\n handleRecheck,\n handleConnect,\n handleDismissToggle,\n allOk,\n externalConnections,\n localConnections,\n };\n};\n","import { useAppStore } from '@/app/stores/app-store';\nimport { useToast } from '@dendelion/paper-ui';\nimport { useEffect, useRef } from 'react';\n\nconst RELAY_POLL_MS = 2000;\n\nexport const useSignInAction = (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 return {\n phase,\n authorizeUrl: loginRelay?.authorizeUrl,\n startLoginRelay,\n cancelLoginRelay,\n };\n};\n","import type { ConnectionResult } from '@/types/index';\nimport { Button, CodeBlock } from '@dendelion/paper-ui';\n\ninterface ConnectActionViewProps {\n connection: ConnectionResult;\n onConnect: (id: string) => void;\n connecting: boolean;\n}\n\nexport const ConnectActionView = ({\n connection,\n onConnect,\n connecting,\n}: ConnectActionViewProps) => {\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","import { CodeBlock } from '@dendelion/paper-ui';\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\nexport const 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","import { Button } from '@dendelion/paper-ui';\nimport { useSignInAction } from '../hooks';\nimport { RelayFallbackGuide } from './relay-fallback-guide';\n\ninterface SignInActionProps {\n onSignedIn: () => void;\n}\n\nexport const SignInAction = ({ onSignedIn }: SignInActionProps) => {\n const { phase, authorizeUrl, startLoginRelay, cancelLoginRelay } = useSignInAction(onSignedIn);\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={() => authorizeUrl && window.open(authorizeUrl, '_blank', 'noopener,noreferrer')}\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","import type { ConnectionResult } from '@/types/index';\nimport { Button, Divider, Stamp, Tooltip } from '@dendelion/paper-ui';\nimport { CAPABILITY_STATUS_STAMP } from '../constants';\nimport { ConnectActionView } from './connect-action-view';\nimport { SignInAction } from './sign-in-action';\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\ninterface ConnectionRowProps {\n connection: ConnectionResult;\n isLast: boolean;\n onRecheck: (id: string) => void;\n rechecking: boolean;\n onConnect: (id: string) => void;\n connecting: boolean;\n}\n\nexport const ConnectionRow = ({\n connection,\n isLast,\n onRecheck,\n rechecking,\n onConnect,\n connecting,\n}: ConnectionRowProps) => {\n const stamp = CAPABILITY_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","import { Alert, Button, Card } from '@dendelion/paper-ui';\nimport { useSetupSection } from '../hooks';\nimport { ConnectionRow } from './connection-row';\n\nexport const SetupSection = () => {\n const {\n connections,\n loadFailed,\n reloadingId,\n connectingId,\n setupDismissed,\n handleRecheck,\n handleConnect,\n handleDismissToggle,\n allOk,\n externalConnections,\n localConnections,\n } = useSetupSection();\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 {externalConnections.length > 0 && (\n <div className=\"mb-4\">\n <p className=\"opacity-[0.45] text-sm mt-0 mb-2\">\n External services — reached on your behalf with their own remote credential.\n </p>\n <Card size=\"small\" texture=\"kraft\">\n {externalConnections.map((c, idx) => (\n <ConnectionRow\n key={c.id}\n connection={c}\n isLast={idx === externalConnections.length - 1}\n onRecheck={handleRecheck}\n rechecking={reloadingId === c.id}\n onConnect={handleConnect}\n connecting={connectingId === c.id}\n />\n ))}\n </Card>\n </div>\n )}\n {localConnections.length > 0 && (\n <div className=\"mb-4\">\n <p className=\"opacity-[0.45] text-sm mt-0 mb-2\">\n Local adapters — driven on this machine with their own local session.\n </p>\n <Card size=\"small\" texture=\"kraft\">\n {localConnections.map((c, idx) => (\n <ConnectionRow\n key={c.id}\n connection={c}\n isLast={idx === localConnections.length - 1}\n onRecheck={handleRecheck}\n rechecking={reloadingId === c.id}\n onConnect={handleConnect}\n connecting={connectingId === c.id}\n />\n ))}\n </Card>\n </div>\n )}\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 {\n AGENT_IDS,\n AGENT_LABELS,\n AGENT_OPTIONS,\n type AgentConfig,\n type AgentId,\n} from '@/types/index';\nimport { Divider, Input, Select } from '@dendelion/paper-ui';\nimport { useEffect, useState } from 'react';\nimport { TASK_TYPE_LABELS, type TaskTypeKey } from '../constants';\n\nconst AGENT_COLUMN_WIDTH = 140;\nconst MODEL_COLUMN_WIDTH = 160;\nconst EFFORT_COLUMN_WIDTH = 110;\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\nexport const 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 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","export const 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","import { color } from '@/app/styles/tokens';\nimport { DEFAULT_AGENTS } from '@/types/index';\nimport { Alert, Button, Card, Divider, Input, Stamp } from '@dendelion/paper-ui';\nimport { TASK_TYPE_KEYS, VERSION_STAMP_FILL } from '../constants';\nimport { useSettingsPage } from '../hooks';\nimport { AgentTaskRow } from './agent-task-row';\nimport { AgentTaskRowHeader } from './agent-task-row-header';\n\nexport const GeneralSection = () => {\n const {\n fileRef,\n config,\n identityLoading,\n iconDataUri,\n uploading,\n portInput,\n setPortInput,\n nameInput,\n setNameInput,\n handleSaveAgentConfig,\n handleSavePort,\n handleToggleIntegration,\n handleSaveName,\n handleFile,\n } = useSettingsPage();\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 size=\"small\" fillColor={VERSION_STAMP_FILL} textColor={color.accentGreenDark}>\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","import { PageTitle } from '@/app/components/page-title';\nimport { useActiveSettingsSection } from '@/app/hooks';\nimport { MergePolicySection } from './components/merge-policy-section';\nimport { SetupSection } from './components/setup-section';\nimport { SubjectsSection } from './components/subjects-section';\nimport { GeneralSection } from './views';\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 className=\"pc-row text-xs\"\n active={section === null}\n onClick={() => navigate({ to: '/settings' })}\n >\n Project Info\n </ListItem>\n <ListItem\n size=\"small\"\n className=\"pc-row text-xs\"\n active={section === 'setup'}\n onClick={() => navigate({ to: '/settings/$section', params: { section: 'setup' } })}\n >\n Setup\n </ListItem>\n <ListItem\n size=\"small\"\n className=\"pc-row text-xs\"\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 className=\"pc-row text-xs\"\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","TASK_TYPE_KEYS","TASK_TYPE_LABELS","CAPABILITY_STATUS_STAMP","MERGE_POLICY_STAMP","VERSION_STAMP_FILL","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","useSettingsPage","fileRef","useRef","config","setConfig","fetchedIconDataUri","identityLoading","useProjectIdentity","uploadedIconDataUri","setUploadedIconDataUri","iconDataUri","uploading","setUploading","portInput","setPortInput","nameInput","setNameInput","fetchConfig","c","key","newEntry","updated","DEFAULT_AGENTS","agentConfigsEqual","ok","error","saveConfig","prev","port","next","_b","_a","integration","_c","projectName","e","file","reader","dataUri","uploadIcon","useSetupSection","connections","setConnections","loadFailed","setLoadFailed","reloadingId","setReloadingId","connectingId","setConnectingId","setupDismissed","setSetupDismissed","applyConnections","useCallback","fetchConnections","handleRecheck","id","handleConnect","connectService","handleDismissToggle","allOk","externalConnections","localConnections","RELAY_POLL_MS","useSignInAction","onSignedIn","loginRelay","useAppStore","s","startLoginRelay","loadLoginRelayStatus","cancelLoginRelay","openedUrlRef","phase","url","ConnectActionView","connection","onConnect","connecting","connect","CodeBlock","AUTH_FIX_COMMANDS","RelayFallbackGuide","cmd","SignInAction","authorizeUrl","RELAY_CONNECTION_ID","ConnectionRow","onRecheck","rechecking","stamp","Tooltip","SetupSection","SubjectsSection","subjects","loading","available","useSubjectVocabulary","navigate","useNavigate","name","AGENT_COLUMN_WIDTH","MODEL_COLUMN_WIDTH","EFFORT_COLUMN_WIDTH","AgentTaskRow","taskKey","agentConfig","onSave","authorConfig","opts","AGENT_OPTIONS","excludedModel","modelOpts","effortOpts","localModel","setLocalModel","handleAgentChange","v","newId","newOpts","newConfig","handleModelSelectChange","handleModelInputBlur","handleEffortChange","Select","AGENT_IDS","AGENT_LABELS","Input","AgentTaskRowHeader","GeneralSection","handleSaveAgentConfig","handleSavePort","handleToggleIntegration","handleSaveName","handleFile","color","SettingsPage","section","useActiveSettingsSection","PageTitle","SettingsSidebar","SidebarSection","ListItem"],"mappings":"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"}
1
+ {"version":3,"file":"index-siPA4naJ.js","sources":["../../../src/app/services/system/merge-policy-api.ts","../../../src/app/features/settings/constants.ts","../../../src/app/features/settings/components/merge-policy-section.tsx","../../../src/app/features/settings/hooks/use-settings-page.ts","../../../src/app/features/settings/hooks/use-setup-section.ts","../../../src/app/features/settings/hooks/use-sign-in-action.ts","../../../src/app/features/settings/components/connect-action-view.tsx","../../../src/app/features/settings/components/relay-fallback-guide.tsx","../../../src/app/features/settings/components/sign-in-action.tsx","../../../src/app/features/settings/components/connection-row.tsx","../../../src/app/features/settings/components/setup-section.tsx","../../../src/app/features/settings/components/subjects-section.tsx","../../../src/app/features/settings/views/agent-task-row.tsx","../../../src/app/features/settings/views/agent-task-row-header.tsx","../../../src/app/features/settings/views/general-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 type { CapabilityStatus } from '@/types/index';\n\nexport const TASK_TYPE_KEYS = [\n 'phase',\n 'planDraft',\n 'ideaExtend',\n 'commitSuggest',\n 'feedback',\n 'codeReview',\n] as const;\nexport type TaskTypeKey = (typeof TASK_TYPE_KEYS)[number];\n\nexport const 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\nexport const CAPABILITY_STATUS_STAMP: Record<\n CapabilityStatus,\n { fill: string; text: string; label: string }\n> = {\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\nexport const MERGE_POLICY_STAMP: Record<'upToDate' | 'outdated', { fill: string; text: string }> = {\n upToDate: { fill: 'rgba(143, 185, 150, 0.25)', text: '#5E8A66' },\n outdated: { fill: 'rgba(212, 163, 115, 0.25)', text: '#A67B4F' },\n};\n\nexport const VERSION_STAMP_FILL = 'rgba(143, 185, 150, 0.25)';\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';\nimport { MERGE_POLICY_STAMP } from '../constants';\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={\n upToDate ? MERGE_POLICY_STAMP.upToDate.fill : MERGE_POLICY_STAMP.outdated.fill\n }\n textColor={\n upToDate ? MERGE_POLICY_STAMP.upToDate.text : MERGE_POLICY_STAMP.outdated.text\n }\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 { useProjectIdentity } from '@/app/hooks';\nimport { fetchConfig, saveConfig, uploadIcon } from '@/app/services/system';\nimport {\n type AgentConfig,\n DEFAULT_AGENTS,\n type DefaultAgentsMap,\n type PaperCampConfig,\n agentConfigsEqual,\n} from '@/types/index';\nimport { useToast } from '@dendelion/paper-ui';\nimport { useEffect, useRef, useState } from 'react';\nimport type { TaskTypeKey } from '../constants';\n\nexport const useSettingsPage = () => {\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 fileRef,\n config,\n identityLoading,\n iconDataUri,\n uploading,\n portInput,\n setPortInput,\n nameInput,\n setNameInput,\n handleSaveAgentConfig,\n handleSavePort,\n handleToggleIntegration,\n handleSaveName,\n handleFile,\n };\n};\n","import { connectService, fetchConfig, fetchConnections, saveConfig } from '@/app/services/system';\nimport type { ConnectionResult } from '@/types/index';\nimport { useToast } from '@dendelion/paper-ui';\nimport { useCallback, useEffect, useState } from 'react';\n\nexport const useSetupSection = () => {\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 const externalConnections = connections?.filter((c) => c.kind === 'external') ?? [];\n const localConnections = connections?.filter((c) => c.kind === 'local') ?? [];\n\n return {\n connections,\n loadFailed,\n reloadingId,\n connectingId,\n setupDismissed,\n handleRecheck,\n handleConnect,\n handleDismissToggle,\n allOk,\n externalConnections,\n localConnections,\n };\n};\n","import { useAppStore } from '@/app/stores/app-store';\nimport { useToast } from '@dendelion/paper-ui';\nimport { useEffect, useRef } from 'react';\n\nconst RELAY_POLL_MS = 2000;\n\nexport const useSignInAction = (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 return {\n phase,\n authorizeUrl: loginRelay?.authorizeUrl,\n startLoginRelay,\n cancelLoginRelay,\n };\n};\n","import type { ConnectionResult } from '@/types/index';\nimport { Button, CodeBlock } from '@dendelion/paper-ui';\n\ninterface ConnectActionViewProps {\n connection: ConnectionResult;\n onConnect: (id: string) => void;\n connecting: boolean;\n}\n\nexport const ConnectActionView = ({\n connection,\n onConnect,\n connecting,\n}: ConnectActionViewProps) => {\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","import { CodeBlock } from '@dendelion/paper-ui';\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\nexport const 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","import { Button } from '@dendelion/paper-ui';\nimport { useSignInAction } from '../hooks';\nimport { RelayFallbackGuide } from './relay-fallback-guide';\n\ninterface SignInActionProps {\n onSignedIn: () => void;\n}\n\nexport const SignInAction = ({ onSignedIn }: SignInActionProps) => {\n const { phase, authorizeUrl, startLoginRelay, cancelLoginRelay } = useSignInAction(onSignedIn);\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={() => authorizeUrl && window.open(authorizeUrl, '_blank', 'noopener,noreferrer')}\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","import type { ConnectionResult } from '@/types/index';\nimport { Button, Divider, Stamp, Tooltip } from '@dendelion/paper-ui';\nimport { CAPABILITY_STATUS_STAMP } from '../constants';\nimport { ConnectActionView } from './connect-action-view';\nimport { SignInAction } from './sign-in-action';\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\ninterface ConnectionRowProps {\n connection: ConnectionResult;\n isLast: boolean;\n onRecheck: (id: string) => void;\n rechecking: boolean;\n onConnect: (id: string) => void;\n connecting: boolean;\n}\n\nexport const ConnectionRow = ({\n connection,\n isLast,\n onRecheck,\n rechecking,\n onConnect,\n connecting,\n}: ConnectionRowProps) => {\n const stamp = CAPABILITY_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","import { Alert, Button, Card } from '@dendelion/paper-ui';\nimport { useSetupSection } from '../hooks';\nimport { ConnectionRow } from './connection-row';\n\nexport const SetupSection = () => {\n const {\n connections,\n loadFailed,\n reloadingId,\n connectingId,\n setupDismissed,\n handleRecheck,\n handleConnect,\n handleDismissToggle,\n allOk,\n externalConnections,\n localConnections,\n } = useSetupSection();\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 {externalConnections.length > 0 && (\n <div className=\"mb-4\">\n <p className=\"opacity-[0.45] text-sm mt-0 mb-2\">\n External services — reached on your behalf with their own remote credential.\n </p>\n <Card size=\"small\" texture=\"kraft\">\n {externalConnections.map((c, idx) => (\n <ConnectionRow\n key={c.id}\n connection={c}\n isLast={idx === externalConnections.length - 1}\n onRecheck={handleRecheck}\n rechecking={reloadingId === c.id}\n onConnect={handleConnect}\n connecting={connectingId === c.id}\n />\n ))}\n </Card>\n </div>\n )}\n {localConnections.length > 0 && (\n <div className=\"mb-4\">\n <p className=\"opacity-[0.45] text-sm mt-0 mb-2\">\n Local adapters — driven on this machine with their own local session.\n </p>\n <Card size=\"small\" texture=\"kraft\">\n {localConnections.map((c, idx) => (\n <ConnectionRow\n key={c.id}\n connection={c}\n isLast={idx === localConnections.length - 1}\n onRecheck={handleRecheck}\n rechecking={reloadingId === c.id}\n onConnect={handleConnect}\n connecting={connectingId === c.id}\n />\n ))}\n </Card>\n </div>\n )}\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 {\n AGENT_IDS,\n AGENT_LABELS,\n AGENT_OPTIONS,\n type AgentConfig,\n type AgentId,\n} from '@/types/index';\nimport { Divider, Input, Select } from '@dendelion/paper-ui';\nimport { useEffect, useState } from 'react';\nimport { TASK_TYPE_LABELS, type TaskTypeKey } from '../constants';\n\nconst AGENT_COLUMN_WIDTH = 140;\nconst MODEL_COLUMN_WIDTH = 160;\nconst EFFORT_COLUMN_WIDTH = 110;\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\nexport const 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 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","export const 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","import { color } from '@/app/styles/tokens';\nimport { DEFAULT_AGENTS } from '@/types/index';\nimport { Alert, Button, Card, Divider, Input, Stamp } from '@dendelion/paper-ui';\nimport { TASK_TYPE_KEYS, VERSION_STAMP_FILL } from '../constants';\nimport { useSettingsPage } from '../hooks';\nimport { AgentTaskRow } from './agent-task-row';\nimport { AgentTaskRowHeader } from './agent-task-row-header';\n\nexport const GeneralSection = () => {\n const {\n fileRef,\n config,\n identityLoading,\n iconDataUri,\n uploading,\n portInput,\n setPortInput,\n nameInput,\n setNameInput,\n handleSaveAgentConfig,\n handleSavePort,\n handleToggleIntegration,\n handleSaveName,\n handleFile,\n } = useSettingsPage();\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 size=\"small\" fillColor={VERSION_STAMP_FILL} textColor={color.accentGreenDark}>\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","import { PageTitle } from '@/app/components/page-title';\nimport { useActiveSettingsSection } from '@/app/hooks';\nimport { MergePolicySection } from './components/merge-policy-section';\nimport { SetupSection } from './components/setup-section';\nimport { SubjectsSection } from './components/subjects-section';\nimport { GeneralSection } from './views';\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 className=\"pc-row text-xs\"\n active={section === null}\n onClick={() => navigate({ to: '/settings' })}\n >\n Project Info\n </ListItem>\n <ListItem\n size=\"small\"\n className=\"pc-row text-xs\"\n active={section === 'setup'}\n onClick={() => navigate({ to: '/settings/$section', params: { section: 'setup' } })}\n >\n Setup\n </ListItem>\n <ListItem\n size=\"small\"\n className=\"pc-row text-xs\"\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 className=\"pc-row text-xs\"\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","TASK_TYPE_KEYS","TASK_TYPE_LABELS","CAPABILITY_STATUS_STAMP","MERGE_POLICY_STAMP","VERSION_STAMP_FILL","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","useSettingsPage","fileRef","useRef","config","setConfig","fetchedIconDataUri","identityLoading","useProjectIdentity","uploadedIconDataUri","setUploadedIconDataUri","iconDataUri","uploading","setUploading","portInput","setPortInput","nameInput","setNameInput","fetchConfig","c","key","newEntry","updated","DEFAULT_AGENTS","agentConfigsEqual","ok","error","saveConfig","prev","port","next","_b","_a","integration","_c","projectName","e","file","reader","dataUri","uploadIcon","useSetupSection","connections","setConnections","loadFailed","setLoadFailed","reloadingId","setReloadingId","connectingId","setConnectingId","setupDismissed","setSetupDismissed","applyConnections","useCallback","fetchConnections","handleRecheck","id","handleConnect","connectService","handleDismissToggle","allOk","externalConnections","localConnections","RELAY_POLL_MS","useSignInAction","onSignedIn","loginRelay","useAppStore","s","startLoginRelay","loadLoginRelayStatus","cancelLoginRelay","openedUrlRef","phase","url","ConnectActionView","connection","onConnect","connecting","connect","CodeBlock","AUTH_FIX_COMMANDS","RelayFallbackGuide","cmd","SignInAction","authorizeUrl","RELAY_CONNECTION_ID","ConnectionRow","onRecheck","rechecking","stamp","Tooltip","SetupSection","SubjectsSection","subjects","loading","available","useSubjectVocabulary","navigate","useNavigate","name","AGENT_COLUMN_WIDTH","MODEL_COLUMN_WIDTH","EFFORT_COLUMN_WIDTH","AgentTaskRow","taskKey","agentConfig","onSave","authorConfig","opts","AGENT_OPTIONS","excludedModel","modelOpts","effortOpts","localModel","setLocalModel","handleAgentChange","v","newId","newOpts","newConfig","handleModelSelectChange","handleModelInputBlur","handleEffortChange","Select","AGENT_IDS","AGENT_LABELS","Input","AgentTaskRowHeader","GeneralSection","handleSaveAgentConfig","handleSavePort","handleToggleIntegration","handleSaveName","handleFile","color","SettingsPage","section","useActiveSettingsSection","PageTitle","SettingsSidebar","SidebarSection","ListItem"],"mappings":"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"}