@dendelion/paper-camp 0.9.0 → 0.11.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 (64) hide show
  1. package/dist/app/assets/index-CwotynaS.js +2 -0
  2. package/dist/app/assets/index-CwotynaS.js.map +1 -0
  3. package/dist/app/assets/index-DHHPg0hQ.js +4 -0
  4. package/dist/app/assets/index-DHHPg0hQ.js.map +1 -0
  5. package/dist/app/assets/index-DyLHu3dg.js +2 -0
  6. package/dist/app/assets/index-DyLHu3dg.js.map +1 -0
  7. package/dist/app/assets/index-DzMK8ayh.js +3 -0
  8. package/dist/app/assets/index-DzMK8ayh.js.map +1 -0
  9. package/dist/app/assets/main-B7k4s_9g.css +1 -0
  10. package/dist/app/assets/main-BNLbBO0E.js +233 -0
  11. package/dist/app/assets/main-BNLbBO0E.js.map +1 -0
  12. package/dist/app/assets/sidebar-section-DVSoUVEe.js +2 -0
  13. package/dist/app/assets/sidebar-section-DVSoUVEe.js.map +1 -0
  14. package/dist/app/index.html +2 -2
  15. package/dist/chunks/{serializer.DqcFa2e1.js → roadmap.HCld8rN3.js} +1727 -1595
  16. package/dist/chunks/roadmap.HCld8rN3.js.map +1 -0
  17. package/dist/cli/index.js +6880 -6440
  18. package/dist/cli/index.js.map +1 -1
  19. package/dist/core/git-pr/pr-lookup.d.ts.map +1 -1
  20. package/dist/core/git-pr/pr.d.ts +17 -10
  21. package/dist/core/git-pr/pr.d.ts.map +1 -1
  22. package/dist/core/git-pr/scopes.d.ts +3 -0
  23. package/dist/core/git-pr/scopes.d.ts.map +1 -1
  24. package/dist/core/index.d.ts +1 -0
  25. package/dist/core/index.d.ts.map +1 -1
  26. package/dist/core/index.js +86 -75
  27. package/dist/core/parse/parser.d.ts.map +1 -1
  28. package/dist/core/parse/schemas.d.ts +2 -0
  29. package/dist/core/parse/schemas.d.ts.map +1 -1
  30. package/dist/core/readers.d.ts +2 -1
  31. package/dist/core/readers.d.ts.map +1 -1
  32. package/dist/core/roadmap.d.ts +6 -0
  33. package/dist/core/roadmap.d.ts.map +1 -0
  34. package/dist/core/roadmap.test.d.ts +2 -0
  35. package/dist/core/roadmap.test.d.ts.map +1 -0
  36. package/dist/core/run-order.d.ts +23 -0
  37. package/dist/core/run-order.d.ts.map +1 -0
  38. package/dist/core/run-order.test.d.ts +2 -0
  39. package/dist/core/run-order.test.d.ts.map +1 -0
  40. package/dist/core/scaffold/scaffold.d.ts.map +1 -1
  41. package/dist/core/sections.d.ts +18 -0
  42. package/dist/core/sections.d.ts.map +1 -0
  43. package/dist/core/serialize/serializer.d.ts +3 -0
  44. package/dist/core/serialize/serializer.d.ts.map +1 -1
  45. package/dist/core/serialize/serializer.test.d.ts +2 -0
  46. package/dist/core/serialize/serializer.test.d.ts.map +1 -0
  47. package/dist/core/status/status.d.ts +4 -0
  48. package/dist/core/status/status.d.ts.map +1 -1
  49. package/dist/types/index.d.ts +50 -1
  50. package/dist/types/index.d.ts.map +1 -1
  51. package/dist/types/index.js.map +1 -1
  52. package/package.json +2 -2
  53. package/dist/app/assets/index-C0wWs5ba.js +0 -2
  54. package/dist/app/assets/index-C0wWs5ba.js.map +0 -1
  55. package/dist/app/assets/index-D-nmg_4I.js +0 -2
  56. package/dist/app/assets/index-D-nmg_4I.js.map +0 -1
  57. package/dist/app/assets/index-Djq8LvrZ.js +0 -3
  58. package/dist/app/assets/index-Djq8LvrZ.js.map +0 -1
  59. package/dist/app/assets/main-BA1w2y_E.css +0 -1
  60. package/dist/app/assets/main-DUy5DFoq.js +0 -218
  61. package/dist/app/assets/main-DUy5DFoq.js.map +0 -1
  62. package/dist/app/assets/sidebar-section-mXpllayv.js +0 -2
  63. package/dist/app/assets/sidebar-section-mXpllayv.js.map +0 -1
  64. package/dist/chunks/serializer.DqcFa2e1.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/types/index.ts"],"sourcesContent":["export type PlanStatus = 'idea' | 'planned' | 'in-progress' | 'review' | 'done' | 'dropped';\n\nexport const PLAN_STATUSES: PlanStatus[] = [\n 'idea',\n 'planned',\n 'in-progress',\n 'review',\n 'done',\n 'dropped',\n];\n\nexport interface LogEntry {\n date: string;\n text: string;\n}\n\nexport type PlanKind = 'feat' | 'fix' | 'chore' | 'docs' | 'refactor';\n\nexport const PLAN_KINDS: PlanKind[] = ['feat', 'fix', 'chore', 'docs', 'refactor'];\n\nexport const AGENT_IDS = ['claude-code', 'opencode'] as const;\n\nexport type AgentId = (typeof AGENT_IDS)[number];\n\nexport const AGENT_LABELS: Record<AgentId, string> = {\n 'claude-code': 'Claude Code',\n opencode: 'OpenCode',\n};\n\nexport type DecisionStatus = 'decided' | 'superseded';\n\nexport type QuestionStatus = 'open' | 'resolved';\n\nexport interface PhaseItem {\n done: boolean;\n text: string;\n description?: string;\n source?: 'review';\n}\n\nexport interface RawEntry {\n title: string;\n fields: Record<string, string>;\n body: string;\n phases: PhaseItem[];\n log?: LogEntry[];\n clarifications?: LogEntry[];\n}\n\nexport interface ParseWarning {\n title: string;\n message: string;\n}\n\nexport interface ParseResult<T> {\n entries: T[];\n warnings: ParseWarning[];\n}\n\n/** A PR's reviewable/mergeable state, as surfaced by `gh pr list`. */\nexport type PrState = 'draft' | 'open' | 'closed' | 'merged';\n\n/** GitHub's PR review decision, as surfaced by `gh pr list --json reviewDecision`. */\nexport type ReviewDecision = 'approved' | 'changes-requested' | 'review-required';\n\n// Per-comment detail; PrInfo.unresolvedThreadCount only counts these.\nexport interface ReviewThread {\n /** GraphQL node id — what `resolveReviewThread`/`replyToReviewThread` address. */\n id: string;\n /** File path the comment is anchored to; absent for a PR-level (not diff-anchored) comment. */\n path?: string;\n line?: number;\n author?: string;\n body: string;\n}\n\n// Parsed from the JSON object a fix-review agent's prompt requires as its final line.\nexport interface FixReviewResult {\n commit: { title: string; message: string };\n addressed: string[];\n skipped: { threadId: string; why: string }[];\n}\n\n/** Live-resolved PR info for an entity's branch — see `core/pr.ts`. */\nexport interface PrInfo {\n number: number;\n url: string;\n state: PrState;\n /** Undefined when no review has been requested/decided, or when unresolved (offline, closed/merged PR). */\n reviewDecision?: ReviewDecision;\n /** Count of unresolved review threads. Only fetched for open/draft PRs; undefined when not fetched or unresolved. */\n unresolvedThreadCount?: number;\n /** Whether a comment or review landed after the PR's last commit — a proxy for \"since the last agent pass\" (a pass ends with a push). Only fetched for open/draft PRs. */\n hasNewCommentsSincePush?: boolean;\n}\n\nexport interface PlanEntry {\n title: string;\n status: PlanStatus;\n kind?: PlanKind;\n id?: string;\n idea?: string;\n agent?: AgentId;\n created: string;\n updated?: string;\n audited?: string;\n auditedHash?: string;\n tags: string[];\n body: string;\n phases: PhaseItem[];\n log?: LogEntry[];\n clarifications?: LogEntry[];\n pr?: PrInfo;\n}\n\nexport interface DecisionEntry {\n title: string;\n date: string;\n status: DecisionStatus;\n supersededBy?: string;\n body: string;\n}\n\nexport interface OpenQuestionEntry {\n title: string;\n status: QuestionStatus;\n raised: string;\n resolvedBy?: string;\n blocks?: string;\n body: string;\n}\n\nexport type ConsistencyIssueKind =\n | 'dangling-resolved-by'\n | 'dangling-superseded-by'\n | 'blocked-plan-active';\n\nexport interface ConsistencyIssue {\n kind: ConsistencyIssueKind;\n section: 'decisions' | 'open-questions';\n title: string;\n message: string;\n planId?: string;\n}\n\nexport type IdeaKind = 'idea' | 'note';\n\nexport type IdeaStatus = 'open' | 'done' | 'dropped';\n\nexport interface IdeaEntry {\n id: string | null;\n title: string;\n body: string;\n kind?: IdeaKind;\n status?: IdeaStatus;\n log?: LogEntry[];\n}\n\n// Unified entity — one file per entity, plan as an optional Phases section.\n// Supersedes PlanEntry/IdeaEntry once the migration cutover lands.\n\n/** Work classification — same Conventional-Commits values as PlanKind; `kind` renamed to `type` in the unified schema. */\nexport type EntityType = PlanKind;\n\n/** Plan lifecycle plus the note-only `open`. Notes use open → done/dropped; everything else uses the PlanStatus track. */\nexport type EntityStatus = PlanStatus | 'open';\n\nexport interface EntityEntry {\n id: string;\n title: string;\n /** Absent until the entity is classified (usually when its plan is drafted). */\n type?: EntityType;\n /** \"note\" marks an entity that never grows phases. */\n kind?: 'note';\n /** Stored override, not the source of truth — see entityFrontmatterSchema. */\n status?: EntityStatus;\n agent?: AgentId;\n created: string;\n updated?: string;\n audited?: string;\n auditedHash?: string;\n tags: string[];\n body: string;\n phases: PhaseItem[];\n log?: LogEntry[];\n clarifications?: LogEntry[];\n}\n\nexport interface ProgressEntry {\n date: string;\n items: string[];\n}\n\n// No `id`/`status`: it only becomes a real idea if a human promotes it.\nexport interface SuggestionEntry {\n date: string;\n title: string;\n description: string;\n}\n\nexport interface EnvEntry {\n key: string;\n value: string;\n /** Set on GET responses when the value is withheld — secrets never reach the client. */\n isSet?: boolean;\n}\n\nexport interface AgentConfig {\n agent: AgentId;\n model?: string;\n effort?: string;\n}\n\n/** Model/effort passed to an adapter's buildArgs — the AgentConfig minus the agent id. */\nexport interface AgentRunOptions {\n model?: string;\n effort?: string;\n}\n\n/** Maps option names to a fixed value list (renders a Select) or null (free-text or hidden). */\nexport type AgentOptionsDescriptor = Record<string, string[] | null | undefined>;\n\nexport const AGENT_OPTIONS: Record<AgentId, AgentOptionsDescriptor> = {\n 'claude-code': {\n model: ['opus', 'sonnet', 'fable', 'haiku'],\n effort: ['low', 'medium', 'high', 'xhigh', 'max'],\n },\n opencode: {\n model: null,\n },\n};\n\nexport function coerceAgentConfig(v: unknown): AgentConfig {\n const toAgent = (a: unknown): AgentId =>\n AGENT_IDS.includes(a as AgentId) ? (a as AgentId) : 'claude-code';\n if (typeof v === 'string') return { agent: toAgent(v) };\n // A missing key must not throw — that would 500 the /api/config read this protects.\n const obj = (v ?? {}) as Record<string, unknown>;\n return {\n agent: toAgent(obj.agent),\n ...(typeof obj.model === 'string' && { model: obj.model }),\n ...(typeof obj.effort === 'string' && { effort: obj.effort }),\n };\n}\n\nexport interface DefaultAgentsMap {\n phase: AgentConfig;\n planDraft: AgentConfig;\n ideaExtend: AgentConfig;\n commitSuggest: AgentConfig;\n}\n\nexport const DEFAULT_AGENTS: DefaultAgentsMap = {\n phase: { agent: 'opencode' },\n planDraft: { agent: 'claude-code' },\n ideaExtend: { agent: 'claude-code' },\n commitSuggest: { agent: 'claude-code' },\n};\n\nexport interface PaperCampConfig {\n version: string;\n projectName: string;\n initializedAt: string;\n /** The unified-entity `idea` counter; the per-kind plan counters are legacy, present only in pre-migration configs. */\n nextId?: Partial<Record<PlanKind, number>> & { idea?: number };\n port?: number;\n defaultAgents?: DefaultAgentsMap;\n /** Off by default. When true, the PostToolUse hook logs new-file creations to progress.md. */\n autoLogNewFiles?: boolean;\n}\n\nexport type CheckStatus = 'stale' | 'running' | 'pass' | 'fail';\n\nexport interface CheckResult {\n status: CheckStatus;\n lastRun: string | null;\n output: string;\n}\n\nexport type CheckName = 'lint' | 'format' | 'test' | 'consistency';\n\nexport interface GitStatusEntry {\n path: string;\n status: string;\n staged: boolean;\n renameSource?: string;\n}\n\nexport interface GitStatusResponse {\n branch: string;\n entries: GitStatusEntry[];\n ahead: number;\n branchHygiene: BranchHygieneStatus;\n}\n\nexport type BranchHygieneStatus =\n | 'clean-on-main'\n | 'stale-merged'\n | 'stale-no-upstream'\n | 'dirty'\n | 'fine';\n\nexport type AgentTaskStatus = 'starting' | 'running' | 'stopping' | 'done' | 'error';\n\nexport type TaskKind =\n | 'phase'\n | 'audit'\n | 'batch-reconcile'\n | 'run-all'\n | 'draft'\n | 'extend'\n | 'suggest'\n | 'commit-suggest'\n | 'overlap-check'\n | 'sync'\n | 'reconcile'\n | 'fix-review';\n\n// Persisted to papercamp/tasks.log (JSON Lines) — survives a dev-server restart,\n// unlike the in-memory task registry.\nexport interface TaskLogEntry {\n id: string;\n taskKind: TaskKind;\n planId?: string;\n planTitle: string;\n agentId: AgentId;\n startedAt: string;\n endedAt: string;\n outcome: 'done' | 'error';\n}\n\nexport interface AgentTaskState {\n id: string;\n status: AgentTaskStatus;\n taskKind: TaskKind;\n planTitle: string;\n planId?: string;\n phaseIndex?: number;\n ideaId?: string;\n agentId: AgentId;\n lines: string[];\n // fix-review only: prefills the commit form once the agent has reported.\n suggestedCommit?: { title: string; message: string };\n}\n\nexport interface OverlapVerdict {\n verdict: 'existing' | 'extend' | 'new';\n targetId: string | null;\n reasoning: string;\n}\n\nexport interface ReconcileQueueItem {\n planId: string;\n title: string;\n before: { body: string; phases: PhaseItem[] };\n}\n"],"names":["PLAN_STATUSES","PLAN_KINDS","AGENT_IDS","AGENT_LABELS","AGENT_OPTIONS","coerceAgentConfig","v","toAgent","a","obj","DEFAULT_AGENTS"],"mappings":"AAEO,MAAMA,IAA8B;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GASaC,IAAyB,CAAC,QAAQ,OAAO,SAAS,QAAQ,UAAU,GAEpEC,IAAY,CAAC,eAAe,UAAU,GAItCC,IAAwC;AAAA,EACnD,eAAe;AAAA,EACf,UAAU;AACZ,GAmMaC,IAAyD;AAAA,EACpE,eAAe;AAAA,IACb,OAAO,CAAC,QAAQ,UAAU,SAAS,OAAO;AAAA,IAC1C,QAAQ,CAAC,OAAO,UAAU,QAAQ,SAAS,KAAK;AAAA,EAAA;AAAA,EAElD,UAAU;AAAA,IACR,OAAO;AAAA,EAAA;AAEX;AAEO,SAASC,EAAkBC,GAAyB;AACzD,QAAMC,IAAU,CAACC,MACfN,EAAU,SAASM,CAAY,IAAKA,IAAgB;AACtD,MAAI,OAAOF,KAAM,SAAU,QAAO,EAAE,OAAOC,EAAQD,CAAC,EAAA;AAEpD,QAAMG,IAAOH,KAAK,CAAA;AAClB,SAAO;AAAA,IACL,OAAOC,EAAQE,EAAI,KAAK;AAAA,IACxB,GAAI,OAAOA,EAAI,SAAU,YAAY,EAAE,OAAOA,EAAI,MAAA;AAAA,IAClD,GAAI,OAAOA,EAAI,UAAW,YAAY,EAAE,QAAQA,EAAI,OAAA;AAAA,EAAO;AAE/D;AASO,MAAMC,IAAmC;AAAA,EAC9C,OAAO,EAAE,OAAO,WAAA;AAAA,EAChB,WAAW,EAAE,OAAO,cAAA;AAAA,EACpB,YAAY,EAAE,OAAO,cAAA;AAAA,EACrB,eAAe,EAAE,OAAO,cAAA;AAC1B;"}
1
+ {"version":3,"file":"index.js","sources":["../../src/types/index.ts"],"sourcesContent":["export type PlanStatus = 'idea' | 'planned' | 'in-progress' | 'review' | 'done' | 'dropped';\n\nexport const PLAN_STATUSES: PlanStatus[] = [\n 'idea',\n 'planned',\n 'in-progress',\n 'review',\n 'done',\n 'dropped',\n];\n\nexport interface LogEntry {\n date: string;\n text: string;\n}\n\nexport type PlanKind = 'feat' | 'fix' | 'chore' | 'docs' | 'refactor';\n\nexport const PLAN_KINDS: PlanKind[] = ['feat', 'fix', 'chore', 'docs', 'refactor'];\n\nexport const AGENT_IDS = ['claude-code', 'opencode'] as const;\n\nexport type AgentId = (typeof AGENT_IDS)[number];\n\nexport const AGENT_LABELS: Record<AgentId, string> = {\n 'claude-code': 'Claude Code',\n opencode: 'OpenCode',\n};\n\nexport type DecisionStatus = 'decided' | 'superseded';\n\nexport type QuestionStatus = 'open' | 'resolved';\n\nexport interface PhaseItem {\n done: boolean;\n text: string;\n description?: string;\n source?: 'review';\n}\n\nexport interface RawEntry {\n title: string;\n fields: Record<string, string>;\n body: string;\n phases: PhaseItem[];\n log?: LogEntry[];\n clarifications?: LogEntry[];\n}\n\nexport interface ParseWarning {\n title: string;\n message: string;\n}\n\nexport interface ParseResult<T> {\n entries: T[];\n warnings: ParseWarning[];\n}\n\n/** A PR's reviewable/mergeable state, as surfaced by `gh pr list`. */\nexport type PrState = 'draft' | 'open' | 'closed' | 'merged';\n\n/** GitHub's PR review decision, as surfaced by `gh pr list --json reviewDecision`. */\nexport type ReviewDecision = 'approved' | 'changes-requested' | 'review-required';\n\n// Per-comment detail; PrInfo.unresolvedThreadCount only counts these.\nexport interface ReviewThread {\n /** GraphQL node id — what `resolveReviewThread`/`replyToReviewThread` address. */\n id: string;\n /** File path the comment is anchored to; absent for a PR-level (not diff-anchored) comment. */\n path?: string;\n line?: number;\n author?: string;\n body: string;\n}\n\n// Parsed from the JSON object a fix-review agent's prompt requires as its final line.\nexport interface FixReviewResult {\n commit: { title: string; message: string };\n addressed: string[];\n skipped: { threadId: string; why: string }[];\n}\n\n/** Live-resolved PR info for an entity's branch — see `core/pr.ts`. */\nexport interface PrInfo {\n number: number;\n url: string;\n state: PrState;\n /** Undefined when no review has been requested/decided, or when unresolved (offline, closed/merged PR). */\n reviewDecision?: ReviewDecision;\n /** Count of unresolved review threads. Only fetched for open/draft PRs; undefined when not fetched or unresolved. */\n unresolvedThreadCount?: number;\n /** Whether a comment or review landed after the PR's last commit — a proxy for \"since the last agent pass\" (a pass ends with a push). Only fetched for open/draft PRs. */\n hasNewCommentsSincePush?: boolean;\n}\n\nexport interface PlanEntry {\n title: string;\n status: PlanStatus;\n kind?: PlanKind;\n id?: string;\n idea?: string;\n agent?: AgentId;\n created: string;\n updated?: string;\n audited?: string;\n auditedHash?: string;\n tags: string[];\n /** Absent renders under the virtual \"No subject\" group. */\n subject?: string;\n /** Absent means unordered — sorts after all ordered entries, by created date. */\n order?: number;\n body: string;\n phases: PhaseItem[];\n log?: LogEntry[];\n clarifications?: LogEntry[];\n pr?: PrInfo;\n}\n\nexport interface ArchivableIdea {\n id: string;\n title: string;\n pr: PrInfo;\n}\n\nexport interface DecisionEntry {\n title: string;\n date: string;\n status: DecisionStatus;\n supersededBy?: string;\n body: string;\n}\n\nexport interface OpenQuestionEntry {\n title: string;\n status: QuestionStatus;\n raised: string;\n resolvedBy?: string;\n blocks?: string;\n body: string;\n}\n\nexport type ConsistencyIssueKind =\n | 'dangling-resolved-by'\n | 'dangling-superseded-by'\n | 'blocked-plan-active';\n\nexport interface ConsistencyIssue {\n kind: ConsistencyIssueKind;\n section: 'decisions' | 'open-questions';\n title: string;\n message: string;\n planId?: string;\n}\n\nexport type IdeaKind = 'idea' | 'note';\n\nexport type IdeaStatus = 'open' | 'done' | 'dropped';\n\nexport interface IdeaEntry {\n id: string | null;\n title: string;\n body: string;\n kind?: IdeaKind;\n status?: IdeaStatus;\n /** Absent renders under the virtual \"No subject\" group. */\n subject?: string;\n /** Absent means unordered — sorts after all ordered entries, by created date. */\n order?: number;\n /** Fallback sort key for unordered entries — see `order`. Absent on view-model-only IdeaEntry literals that never enter the worklist sort. */\n created?: string;\n log?: LogEntry[];\n}\n\n// Unified entity — one file per entity, plan as an optional Phases section.\n// Supersedes PlanEntry/IdeaEntry once the migration cutover lands.\n\n/** Work classification — same Conventional-Commits values as PlanKind; `kind` renamed to `type` in the unified schema. */\nexport type EntityType = PlanKind;\n\n/** Plan lifecycle plus the note-only `open`. Notes use open → done/dropped; everything else uses the PlanStatus track. */\nexport type EntityStatus = PlanStatus | 'open';\n\nexport interface EntityEntry {\n id: string;\n title: string;\n /** Absent until the entity is classified (usually when its plan is drafted). */\n type?: EntityType;\n /** \"note\" marks an entity that never grows phases. */\n kind?: 'note';\n /** Stored override, not the source of truth — see entityFrontmatterSchema. */\n status?: EntityStatus;\n agent?: AgentId;\n created: string;\n updated?: string;\n audited?: string;\n auditedHash?: string;\n tags: string[];\n /** Absent renders as the virtual \"No subject\" group. */\n subject?: string;\n /** Absent means unordered — sorts after all ordered entries, by created date. */\n order?: number;\n body: string;\n phases: PhaseItem[];\n log?: LogEntry[];\n clarifications?: LogEntry[];\n /** Set by readEntities from which of the two scanned dirs the file came from, not the frontmatter. */\n archived?: boolean;\n}\n\nexport interface ProgressEntry {\n date: string;\n items: string[];\n}\n\n// No `id`/`status`: it only becomes a real idea if a human promotes it.\nexport interface SuggestionEntry {\n date: string;\n title: string;\n description: string;\n}\n\nexport interface RoadmapItem {\n name: string;\n description: string;\n candidates: string[];\n}\n\nexport interface RoadmapHorizon {\n title: string;\n items: RoadmapItem[];\n}\n\nexport interface Roadmap {\n goal: string;\n horizons: RoadmapHorizon[];\n}\n\nexport interface EnvEntry {\n key: string;\n value: string;\n /** Set on GET responses when the value is withheld — secrets never reach the client. */\n isSet?: boolean;\n}\n\nexport interface AgentConfig {\n agent: AgentId;\n model?: string;\n effort?: string;\n}\n\n/** Model/effort passed to an adapter's buildArgs — the AgentConfig minus the agent id. */\nexport interface AgentRunOptions {\n model?: string;\n effort?: string;\n}\n\n/** Maps option names to a fixed value list (renders a Select) or null (free-text or hidden). */\nexport type AgentOptionsDescriptor = Record<string, string[] | null | undefined>;\n\nexport const AGENT_OPTIONS: Record<AgentId, AgentOptionsDescriptor> = {\n 'claude-code': {\n model: ['opus', 'sonnet', 'fable', 'haiku'],\n effort: ['low', 'medium', 'high', 'xhigh', 'max'],\n },\n opencode: {\n model: null,\n },\n};\n\nexport function coerceAgentConfig(v: unknown): AgentConfig {\n const toAgent = (a: unknown): AgentId =>\n AGENT_IDS.includes(a as AgentId) ? (a as AgentId) : 'claude-code';\n if (typeof v === 'string') return { agent: toAgent(v) };\n // A missing key must not throw — that would 500 the /api/config read this protects.\n const obj = (v ?? {}) as Record<string, unknown>;\n return {\n agent: toAgent(obj.agent),\n ...(typeof obj.model === 'string' && { model: obj.model }),\n ...(typeof obj.effort === 'string' && { effort: obj.effort }),\n };\n}\n\nexport interface DefaultAgentsMap {\n phase: AgentConfig;\n planDraft: AgentConfig;\n ideaExtend: AgentConfig;\n commitSuggest: AgentConfig;\n}\n\nexport const DEFAULT_AGENTS: DefaultAgentsMap = {\n phase: { agent: 'opencode' },\n planDraft: { agent: 'claude-code' },\n ideaExtend: { agent: 'claude-code' },\n commitSuggest: { agent: 'claude-code' },\n};\n\nexport interface PaperCampConfig {\n version: string;\n projectName: string;\n initializedAt: string;\n /** The unified-entity `idea` counter; the per-kind plan counters are legacy, present only in pre-migration configs. */\n nextId?: Partial<Record<PlanKind, number>> & { idea?: number };\n port?: number;\n defaultAgents?: DefaultAgentsMap;\n /** Off by default. When true, the PostToolUse hook logs new-file creations to progress.md. */\n autoLogNewFiles?: boolean;\n /** The managed subject list; an idea's `subject` not present here renders as \"No subject\". */\n subjects?: string[];\n /** Opts out of the first-run redirect to Settings > Setup while capabilities are incomplete. */\n setupDismissed?: boolean;\n}\n\nexport type CheckStatus = 'stale' | 'running' | 'pass' | 'fail';\n\nexport interface CheckResult {\n status: CheckStatus;\n lastRun: string | null;\n output: string;\n}\n\nexport type CheckName = 'lint' | 'format' | 'test' | 'consistency';\n\nexport type CapabilityStatus = 'ok' | 'warn' | 'missing';\n\nexport interface CapabilityResult {\n id: string;\n status: CapabilityStatus;\n detail: string;\n}\n\nexport interface GitStatusEntry {\n path: string;\n status: string;\n staged: boolean;\n renameSource?: string;\n}\n\nexport interface GitStatusResponse {\n branch: string;\n entries: GitStatusEntry[];\n ahead: number;\n branchHygiene: BranchHygieneStatus;\n}\n\nexport type BranchHygieneStatus =\n | 'clean-on-main'\n | 'stale-merged'\n | 'stale-no-upstream'\n | 'dirty'\n | 'fine';\n\nexport type AgentTaskStatus = 'starting' | 'running' | 'stopping' | 'done' | 'error';\n\nexport type TaskKind =\n | 'phase'\n | 'audit'\n | 'batch-reconcile'\n | 'run-all'\n | 'draft'\n | 'extend'\n | 'suggest'\n | 'commit-suggest'\n | 'overlap-check'\n | 'prioritise'\n | 'sync'\n | 'reconcile'\n | 'fix-review';\n\n// Persisted to papercamp/tasks.log (JSON Lines) — survives a dev-server restart,\n// unlike the in-memory task registry.\nexport interface TaskLogEntry {\n id: string;\n taskKind: TaskKind;\n planId?: string;\n planTitle: string;\n agentId: AgentId;\n startedAt: string;\n endedAt: string;\n outcome: 'done' | 'error';\n}\n\nexport interface AgentTaskState {\n id: string;\n status: AgentTaskStatus;\n taskKind: TaskKind;\n planTitle: string;\n planId?: string;\n phaseIndex?: number;\n ideaId?: string;\n agentId: AgentId;\n lines: string[];\n // fix-review only: prefills the commit form once the agent has reported.\n suggestedCommit?: { title: string; message: string };\n}\n\nexport interface OverlapVerdict {\n verdict: 'existing' | 'extend' | 'new';\n targetId: string | null;\n reasoning: string;\n}\n\n/** `why` carries one line per entry in `order`, same index — the reason for that id's placement. */\nexport interface PrioritiseVerdict {\n order: string[];\n why: string;\n}\n\nexport interface ReconcileQueueItem {\n planId: string;\n title: string;\n before: { body: string; phases: PhaseItem[] };\n}\n"],"names":["PLAN_STATUSES","PLAN_KINDS","AGENT_IDS","AGENT_LABELS","AGENT_OPTIONS","coerceAgentConfig","v","toAgent","a","obj","DEFAULT_AGENTS"],"mappings":"AAEO,MAAMA,IAA8B;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GASaC,IAAyB,CAAC,QAAQ,OAAO,SAAS,QAAQ,UAAU,GAEpEC,IAAY,CAAC,eAAe,UAAU,GAItCC,IAAwC;AAAA,EACnD,eAAe;AAAA,EACf,UAAU;AACZ,GAyOaC,IAAyD;AAAA,EACpE,eAAe;AAAA,IACb,OAAO,CAAC,QAAQ,UAAU,SAAS,OAAO;AAAA,IAC1C,QAAQ,CAAC,OAAO,UAAU,QAAQ,SAAS,KAAK;AAAA,EAAA;AAAA,EAElD,UAAU;AAAA,IACR,OAAO;AAAA,EAAA;AAEX;AAEO,SAASC,EAAkBC,GAAyB;AACzD,QAAMC,IAAU,CAACC,MACfN,EAAU,SAASM,CAAY,IAAKA,IAAgB;AACtD,MAAI,OAAOF,KAAM,SAAU,QAAO,EAAE,OAAOC,EAAQD,CAAC,EAAA;AAEpD,QAAMG,IAAOH,KAAK,CAAA;AAClB,SAAO;AAAA,IACL,OAAOC,EAAQE,EAAI,KAAK;AAAA,IACxB,GAAI,OAAOA,EAAI,SAAU,YAAY,EAAE,OAAOA,EAAI,MAAA;AAAA,IAClD,GAAI,OAAOA,EAAI,UAAW,YAAY,EAAE,QAAQA,EAAI,OAAA;AAAA,EAAO;AAE/D;AASO,MAAMC,IAAmC;AAAA,EAC9C,OAAO,EAAE,OAAO,WAAA;AAAA,EAChB,WAAW,EAAE,OAAO,cAAA;AAAA,EACpB,YAAY,EAAE,OAAO,cAAA;AAAA,EACrB,eAAe,EAAE,OAAO,cAAA;AAC1B;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dendelion/paper-camp",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "Local-first, AI-native project management with retro aesthetics",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@10.12.1",
@@ -31,7 +31,7 @@
31
31
  "dev:lib": "vite",
32
32
  "cli": "bun src/cli/index.ts",
33
33
  "check-types": "tsc --noEmit",
34
- "lint": "biome check .",
34
+ "lint": "biome check . && node scripts/check-comments.mjs",
35
35
  "lint:write": "biome check --write .",
36
36
  "test": "vitest run",
37
37
  "test:watch": "vitest",
@@ -1,2 +0,0 @@
1
- import{u as T,j as e,P as Z,r as p,m as q,e as X,s as d,n as M,p as W,X as D,O as Q,c as ee,q as F,Z as z,t as I,f as b,$,b as N,v as te,w as se,x as ne,y as ae,A as P,Y as O,z as ie,B as le,o as _}from"./main-DUy5DFoq.js";import{S as R}from"./sidebar-section-mXpllayv.js";const oe=async()=>{try{const n=await fetch("/api/config");return n.ok?n.json():null}catch{return null}},U=async n=>{try{return(await fetch("/api/config",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)})).ok}catch{return!1}},re=async()=>{try{const n=await fetch("/api/configs");return n.ok?(await n.json()).files:[]}catch{return[]}},ce=async n=>{try{const t=await fetch(`/api/configs?name=${encodeURIComponent(n)}`);return t.ok?(await t.json()).content:null}catch{return null}},H=async()=>{try{const n=await fetch("/api/env");return n.ok?await n.json():{exists:!1,exampleExists:!1,entries:[],missingKeys:[]}}catch{return{exists:!1,exampleExists:!1,entries:[],missingKeys:[]}}},de=async n=>{try{return(await fetch("/api/env",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({entries:n})})).ok}catch{return!1}},K=["phase","planDraft","ideaExtend","commitSuggest"],pe={phase:"Phase run",planDraft:"Plan draft",ideaExtend:"Idea extend",commitSuggest:"Commit suggest"},Y=110,J=140,B=160,V=110,he=()=>e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:d[3],paddingBottom:d[1]},children:[e.jsx("span",{style:{width:Y,flexShrink:0,fontSize:b.sm,opacity:.45},children:"Task"}),e.jsx("span",{style:{width:J,flexShrink:0,fontSize:b.sm,opacity:.45},children:"Agent"}),e.jsx("span",{style:{width:B,flexShrink:0,fontSize:b.sm,opacity:.45},children:"Model"}),e.jsx("span",{style:{width:V,flexShrink:0,fontSize:b.sm,opacity:.45},children:"Effort"})]}),ue=({taskKey:n,agentConfig:t,isLast:u,onSave:h})=>{const m=P[t.agent]??P["claude-code"],g=m.model,l=m.effort,[x,y]=p.useState(t.model??"");p.useEffect(()=>{y(t.model??"")},[t.model]);const v=c=>{var C;const f=c,k=P[f],w={agent:f};t.model&&(k.model===null||(C=k.model)!=null&&C.includes(t.model))&&(w.model=t.model),t.effort&&Array.isArray(k.effort)&&(w.effort=t.effort),h(n,w)},A=c=>{h(n,{...t,model:c||void 0})},j=()=>{h(n,{...t,model:x||void 0})},S=c=>{h(n,{...t,effort:c||void 0})};return e.jsxs(e.Fragment,{children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:d[3],paddingBottom:d[2],paddingTop:d[2]},children:[e.jsx("span",{style:{width:Y,flexShrink:0,fontSize:b.sm,opacity:.65},children:pe[n]}),e.jsx(O,{size:"small",width:J,value:t.agent,onChange:v,options:ie.map(c=>({value:c,label:le[c]}))}),Array.isArray(g)?e.jsx(O,{size:"small",width:B,value:t.model??"",onChange:A,options:[{value:"",label:"Default"},...g.map(c=>({value:c,label:c}))]}):g===null?e.jsx(D,{size:"small",style:{width:B},value:x,placeholder:"Default model",onChange:c=>y(c.target.value),onBlur:j}):null,e.jsx("div",{style:{visibility:Array.isArray(l)?"visible":"hidden"},children:e.jsx(O,{size:"small",width:V,value:t.effort??"",onChange:S,options:[{value:"",label:"Default"},...(Array.isArray(l)?l:[]).map(c=>({value:c,label:c}))]})})]}),!u&&e.jsx(F,{})]})},fe=()=>{const n=p.useRef(null),[t,u]=p.useState(void 0),{iconDataUri:h,loading:m}=q(),[g,l]=p.useState(null),x=g??h,[y,v]=p.useState(!1),[A,j]=p.useState(""),[S,c]=p.useState(""),{toast:f}=X();p.useEffect(()=>{oe().then(i=>{u(i),(i==null?void 0:i.port)!==void 0&&j(String(i.port)),(i==null?void 0:i.projectName)!==void 0&&c(i.projectName)})},[]);const k=async(i,a)=>{const s=t==null?void 0:t.defaultAgents,o={phase:(s==null?void 0:s.phase)??I.phase,planDraft:(s==null?void 0:s.planDraft)??I.planDraft,ideaExtend:(s==null?void 0:s.ideaExtend)??I.ideaExtend,commitSuggest:(s==null?void 0:s.commitSuggest)??I.commitSuggest,[i]:a};await U({defaultAgents:o})?(u(E=>E&&{...E,defaultAgents:o}),f({title:"Saved",variant:"success"})):f({title:"Failed to save",variant:"error"})},w=async()=>{const i=Number(A);if(!t||!Number.isInteger(i)||i<=0||i===t.port)return;await U({port:i})?(u(s=>s&&{...s,port:i}),f({title:"Saved",variant:"success"})):f({title:"Failed to save",variant:"error"})},C=async()=>{const i=S.trim();if(!t||!i||i===t.projectName)return;await U({projectName:i})?(u(s=>s&&{...s,projectName:i}),c(i),f({title:"Saved",variant:"success"})):f({title:"Failed to save",variant:"error"})},L=async i=>{var o;const a=(o=i.target.files)==null?void 0:o[0];if(!a)return;v(!0);const s=new FileReader;s.onloadend=async()=>{const r=s.result,E=await ae(r);v(!1),E?(l(r),f({title:"Saved",variant:"success"})):f({title:"Failed to save",variant:"error"})},s.readAsDataURL(a)};return e.jsxs("div",{children:[e.jsx("div",{style:{marginBottom:d[6]},children:e.jsx("h2",{style:{margin:0},children:"Project Info"})}),t===void 0&&e.jsx("p",{children:"Loading…"}),t===null&&e.jsxs(M,{variant:"warning",children:["No papercamp/config.json found — run ",e.jsx("code",{children:"paper-camp init"})," in this directory first."]}),t&&e.jsxs(W,{size:"small",children:[e.jsxs("div",{style:{display:"flex",alignItems:"flex-end",gap:d[3],paddingBottom:d[3]},children:[e.jsx(D,{value:S,onChange:i=>c(i.target.value),onBlur:C,label:"Project Name"}),e.jsxs(Q,{size:"small",fillColor:"rgba(143, 185, 150, 0.25)",textColor:ee.accentGreenDark,children:["v",t.version]})]}),e.jsx(F,{}),e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:d[3],paddingBottom:d[3],paddingTop:d[3]},children:[x&&e.jsx("img",{src:x,alt:"Project icon",style:{width:40,height:40,objectFit:"contain",flexShrink:0,borderRadius:4}}),e.jsxs("div",{children:[e.jsx("input",{ref:n,type:"file",accept:".svg,.png,.jpg,.jpeg,.gif,.webp",onChange:L,style:{display:"none"}}),e.jsx(z,{variant:"secondary",size:"small",onClick:()=>{var i;return(i=n.current)==null?void 0:i.click()},disabled:y,children:y?"Uploading…":"Choose File"}),m&&e.jsx("p",{className:"text-sm",style:{opacity:.5,margin:`${d[1]} 0 0`},children:"Loading…"}),!m&&!x&&!y&&e.jsx("p",{className:"text-sm",style:{opacity:.45,margin:`${d[1]} 0 0`},children:"No icon set."})]})]}),e.jsx(F,{}),e.jsx("div",{style:{display:"flex",alignItems:"flex-end",gap:d[3],paddingBottom:d[3],paddingTop:d[3]},children:e.jsx(D,{type:"number",value:A,onChange:i=>j(i.target.value),onBlur:w,label:"Port",helperText:"Default for `paper-camp dev`. Does not affect the running server."})}),e.jsx(F,{}),e.jsx(he,{}),K.map((i,a)=>{var s;return e.jsx(ue,{taskKey:i,agentConfig:((s=t.defaultAgents)==null?void 0:s[i])??I[i],isLast:a===K.length-1,onSave:k},i)})]}),e.jsxs("p",{style:{opacity:.45,fontSize:b.sm,marginTop:d[4]},children:[e.jsx("strong",{children:"Initialized:"})," ",t?new Date(t.initializedAt).toLocaleString():"—"]})]})},me=n=>{try{const t=JSON.parse(n);return!t.scripts||typeof t.scripts!="object"?null:Object.entries(t.scripts).map(([u,h])=>({name:u,command:h}))}catch{return null}},ge=({fileName:n})=>{const[t,u]=p.useState(null),[h,m]=p.useState(!0);if(p.useEffect(()=>{m(!0),ce(n).then(l=>{u(l),m(!1)})},[n]),h)return e.jsx("p",{children:"Loading…"});if(t===null)return e.jsxs(M,{variant:"warning",children:["Could not load file — ",n," not found."]});const g=n==="package.json"?me(t):null;return e.jsxs("div",{children:[e.jsx("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:d[4]},children:e.jsx("h2",{style:{margin:0},children:n})}),g?e.jsx($,{data:g,columns:[{key:"name",header:"Script",cell:l=>e.jsx("span",{style:{fontFamily:N.mono},children:l.name}),width:4},{key:"command",header:"Command",cell:l=>e.jsx("span",{style:{fontFamily:N.mono},children:l.command})}]}):e.jsx(ne,{code:t,filename:n})]})},G=n=>/key|secret|token|password/i.test(n),xe=()=>{const[n,t]=p.useState(!0),[u,h]=p.useState([]),[m,g]=p.useState([]),[l,x]=p.useState(new Set),[y,v]=p.useState(!1),[A,j]=p.useState(!1),[S,c]=p.useState(null);p.useEffect(()=>{H().then(a=>{h(a.entries),g(a.missingKeys),t(!1)})},[]);const f=(a,s)=>{h(o=>o.map((r,E)=>E===a?{...r,...s}:r))},k=()=>h(a=>[...a,{key:"",value:""}]),w=a=>{h(s=>[...s,{key:a,value:""}]),g(s=>s.filter(o=>o!==a))},C=a=>{h(s=>s.filter((o,r)=>r!==a)),x(s=>{const o=new Set(s);return o.delete(a),o})},L=a=>x(s=>{const o=new Set(s);return o.has(a)?o.delete(a):o.add(a),o}),i=async()=>{const a=u.map(r=>({key:r.key.trim(),value:r.value,isSet:r.isSet})).filter(r=>r.key.length>0);if(new Set(a.map(r=>r.key)).size!==a.length){c("Duplicate keys are not allowed");return}c(null),v(!0);const o=await de(a.map(r=>({key:r.key,value:r.value,keep:!!r.isSet&&r.value===""})));v(!1),o?(h(a.map(r=>({key:r.key,value:"",isSet:!0}))),j(!0),setTimeout(()=>j(!1),2e3)):c("Failed to save .env")};return n?e.jsx("p",{children:"Loading…"}):e.jsxs("div",{children:[e.jsx("h2",{style:{margin:0,marginBottom:d[4]},children:"Environment Variables"}),S&&e.jsxs(M,{variant:"warning",children:["Could not save — ",S]}),m.length>0&&e.jsxs(W,{size:"small",accent:!0,accentColor:"amber",children:[e.jsx("p",{style:{margin:0,fontWeight:600},children:"Missing from .env"}),e.jsxs("div",{style:{display:"flex",flexWrap:"wrap",gap:d[2],alignItems:"center"},children:[e.jsx("span",{children:"Present in .env.example but not set:"}),m.map(a=>e.jsxs(z,{variant:"secondary",size:"small",onClick:()=>w(a),children:["+ ",a]},a))]})]}),e.jsx($,{data:u,columns:[{key:"key",header:"Key",cell:(a,s)=>e.jsx(D,{value:a.key,placeholder:"KEY",style:{fontFamily:N.mono},onChange:o=>f(s,{key:o.target.value})}),width:6},{key:"value",header:"Value",cell:(a,s)=>{const o=G(a.key)&&!l.has(s);return e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:d[2]},children:[e.jsx(D,{type:o?"password":"text",value:a.value,placeholder:a.isSet?"•••••• set — leave blank to keep":"value",style:{fontFamily:N.mono,flex:1},onChange:r=>f(s,{value:r.target.value})}),G(a.key)&&e.jsx(z,{variant:"ghost",size:"small",onClick:()=>L(s),children:o?"Show":"Hide"})]})}},{key:"actions",header:"",width:2,cell:(a,s)=>e.jsx(te,{icon:e.jsx(se,{}),variant:"ghost",size:"small",label:"Remove variable",onClick:()=>C(s)})}]}),e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:d[3],marginTop:d[4]},children:[e.jsx(z,{variant:"secondary",size:"small",onClick:k,children:"+ Add variable"}),e.jsx(z,{variant:"primary",size:"small",onClick:i,disabled:y,children:y?"Saving…":"Save"}),A&&e.jsx("span",{className:"text-sm",style:{opacity:.6},children:"Saved"})]})]})},je=()=>{const n=T(t=>t.activeSettingsSection);return e.jsxs("div",{children:[e.jsx(Z,{children:"Settings"}),n==="general"&&e.jsx(fe,{}),n==="env"&&e.jsx(xe,{}),n.startsWith("config:")&&e.jsx(ge,{fileName:n.slice(7)})]})},Se=()=>{const n=T(l=>l.activeSettingsSection),t=T(l=>l.setActiveSettingsSection),u=T(l=>l.settingsConfigFiles),h=T(l=>l.setSettingsConfigFiles),[m,g]=p.useState(!1);return p.useEffect(()=>{re().then(h),H().then(l=>g(l.exists||l.exampleExists))},[h]),e.jsxs(e.Fragment,{children:[e.jsx(R,{label:"General",children:e.jsx(_,{size:"small",active:n==="general",onClick:()=>t("general"),children:"Project Info"})}),m&&e.jsx(R,{label:"Environment",children:e.jsx(_,{size:"small",active:n==="env",onClick:()=>t("env"),children:"Env Vars"})}),u.length>0&&e.jsx(R,{label:"Config Files",children:u.map(l=>e.jsx(_,{size:"small",active:n===`config:${l}`,onClick:()=>t(`config:${l}`),children:l},l))})]})};export{je as SettingsPage,Se as SettingsSidebar};
2
- //# sourceMappingURL=index-C0wWs5ba.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-C0wWs5ba.js","sources":["../../../src/app/services/system/config-api.ts","../../../src/app/services/system/config-files-api.ts","../../../src/app/services/system/env-api.ts","../../../src/app/features/settings/settings-page.tsx","../../../src/app/features/settings/components/settings-sidebar.tsx"],"sourcesContent":["import type { AgentId, DefaultAgentsMap, PaperCampConfig } from '@/types/index';\n\nexport const fetchConfig = async (): Promise<PaperCampConfig | null> => {\n try {\n const response = await fetch('/api/config');\n if (!response.ok) return null;\n return response.json();\n } catch {\n return null;\n }\n};\n\nexport const saveConfig = async (updates: {\n port?: number;\n projectName?: string;\n defaultAgent?: AgentId;\n defaultAgents?: DefaultAgentsMap;\n}): Promise<boolean> => {\n try {\n const response = await fetch('/api/config', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(updates),\n });\n return response.ok;\n } catch {\n return false;\n }\n};\n","export const fetchConfigs = async (): Promise<string[]> => {\n try {\n const response = await fetch('/api/configs');\n if (!response.ok) return [];\n const data = (await response.json()) as { files: string[] };\n return data.files;\n } catch {\n return [];\n }\n};\n\nexport const fetchConfigFile = async (name: string): Promise<string | null> => {\n try {\n const response = await fetch(`/api/configs?name=${encodeURIComponent(name)}`);\n if (!response.ok) return null;\n const data = (await response.json()) as { name: string; content: string };\n return data.content;\n } catch {\n return null;\n }\n};\n","import type { EnvEntry } from '@/types/index';\n\nexport interface EnvFile {\n exists: boolean;\n exampleExists: boolean;\n entries: EnvEntry[];\n missingKeys: string[];\n}\n\nexport const fetchEnv = async (): Promise<EnvFile> => {\n try {\n const response = await fetch('/api/env');\n if (!response.ok) return { exists: false, exampleExists: false, entries: [], missingKeys: [] };\n return await response.json();\n } catch {\n return { exists: false, exampleExists: false, entries: [], missingKeys: [] };\n }\n};\n\n/** `keep` preserves a set key's existing value server-side (the client never has\n * it, since GET withholds secret values). */\nexport type EnvEntryInput = { key: string; value: string; keep?: boolean };\n\nexport const saveEnv = async (entries: EnvEntryInput[]): Promise<boolean> => {\n try {\n const response = await fetch('/api/env', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ entries }),\n });\n return response.ok;\n } catch {\n return false;\n }\n};\n","import { PageTitle } from '@/app/components/page-title';\nimport { useProjectIdentity } from '@/app/hooks';\nimport {\n fetchConfig,\n fetchConfigFile,\n fetchEnv,\n saveConfig,\n saveEnv,\n uploadIcon,\n} from '@/app/services/system';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { color, fontFamily, fontSize, space } from '@/app/styles/tokens';\nimport {\n AGENT_IDS,\n AGENT_LABELS,\n AGENT_OPTIONS,\n type AgentConfig,\n type AgentId,\n DEFAULT_AGENTS,\n type DefaultAgentsMap,\n type EnvEntry,\n type PaperCampConfig,\n} from '@/types/index';\nimport {\n Alert,\n Button,\n Card,\n CloseIcon,\n CodeBlock,\n Divider,\n IconButton,\n Input,\n Select,\n Stamp,\n Table,\n useToast,\n} from '@dendelion/paper-ui';\nimport { useEffect, useRef, useState } from 'react';\n\nconst TASK_TYPE_KEYS = ['phase', 'planDraft', 'ideaExtend', 'commitSuggest'] as const;\ntype TaskTypeKey = (typeof TASK_TYPE_KEYS)[number];\n\nconst TASK_TYPE_LABELS: Record<TaskTypeKey, string> = {\n phase: 'Phase run',\n planDraft: 'Plan draft',\n ideaExtend: 'Idea extend',\n commitSuggest: 'Commit suggest',\n};\n\ninterface AgentTaskRowProps {\n taskKey: TaskTypeKey;\n agentConfig: AgentConfig;\n isLast: boolean;\n onSave: (key: TaskTypeKey, config: AgentConfig) => Promise<void>;\n}\n\nconst TASK_COLUMN_WIDTH = 110;\nconst AGENT_COLUMN_WIDTH = 140;\nconst MODEL_COLUMN_WIDTH = 160;\nconst EFFORT_COLUMN_WIDTH = 110;\n\nconst AgentTaskRowHeader = () => (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: space[3],\n paddingBottom: space[1],\n }}\n >\n <span style={{ width: TASK_COLUMN_WIDTH, flexShrink: 0, fontSize: fontSize.sm, opacity: 0.45 }}>\n Task\n </span>\n <span\n style={{ width: AGENT_COLUMN_WIDTH, flexShrink: 0, fontSize: fontSize.sm, opacity: 0.45 }}\n >\n Agent\n </span>\n <span\n style={{ width: MODEL_COLUMN_WIDTH, flexShrink: 0, fontSize: fontSize.sm, opacity: 0.45 }}\n >\n Model\n </span>\n <span\n style={{ width: EFFORT_COLUMN_WIDTH, flexShrink: 0, fontSize: fontSize.sm, opacity: 0.45 }}\n >\n Effort\n </span>\n </div>\n);\n\nconst AgentTaskRow = ({ taskKey, agentConfig, isLast, onSave }: 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 modelOpts = 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\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: space[3],\n paddingBottom: space[2],\n paddingTop: space[2],\n }}\n >\n <span\n style={{ width: TASK_COLUMN_WIDTH, flexShrink: 0, fontSize: fontSize.sm, opacity: 0.65 }}\n >\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 { value: '', label: 'Default' },\n ...modelOpts.map((m) => ({ value: m, label: m })),\n ]}\n />\n ) : modelOpts === null ? (\n <Input\n size=\"small\"\n style={{ width: MODEL_COLUMN_WIDTH }}\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 style={{ visibility: Array.isArray(effortOpts) ? 'visible' : 'hidden' }}>\n <Select\n size=\"small\"\n width={EFFORT_COLUMN_WIDTH}\n value={agentConfig.effort ?? ''}\n onChange={handleEffortChange}\n options={[\n { value: '', label: 'Default' },\n ...(Array.isArray(effortOpts) ? effortOpts : []).map((e) => ({ value: e, label: e })),\n ]}\n />\n </div>\n </div>\n {!isLast && <Divider />}\n </>\n );\n};\n\nconst GeneralSection = () => {\n const fileRef = useRef<HTMLInputElement>(null);\n const [config, setConfig] = useState<PaperCampConfig | null | undefined>(undefined);\n const { iconDataUri: fetchedIconDataUri, loading: identityLoading } = useProjectIdentity();\n const [uploadedIconDataUri, setUploadedIconDataUri] = useState<string | null>(null);\n const iconDataUri = uploadedIconDataUri ?? fetchedIconDataUri;\n const [uploading, setUploading] = useState(false);\n const [portInput, setPortInput] = useState('');\n const [nameInput, setNameInput] = useState('');\n const { toast } = useToast();\n\n useEffect(() => {\n fetchConfig().then((c) => {\n setConfig(c);\n if (c?.port !== undefined) setPortInput(String(c.port));\n if (c?.projectName !== undefined) setNameInput(c.projectName);\n });\n }, []);\n\n const handleSaveAgentConfig = async (key: TaskTypeKey, newEntry: AgentConfig) => {\n const current = config?.defaultAgents;\n const updated: DefaultAgentsMap = {\n phase: current?.phase ?? DEFAULT_AGENTS.phase,\n planDraft: current?.planDraft ?? DEFAULT_AGENTS.planDraft,\n ideaExtend: current?.ideaExtend ?? DEFAULT_AGENTS.ideaExtend,\n commitSuggest: current?.commitSuggest ?? DEFAULT_AGENTS.commitSuggest,\n [key]: newEntry,\n };\n const ok = 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', 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 = await saveConfig({ port });\n if (ok) {\n setConfig((prev) => (prev ? { ...prev, port } : prev));\n toast({ title: 'Saved', variant: 'success' });\n } else {\n toast({ title: 'Failed to save', 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 = 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', variant: 'error' });\n }\n };\n\n const handleFile = async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n setUploading(true);\n const reader = new FileReader();\n reader.onloadend = async () => {\n const dataUri = reader.result as string;\n const ok = await uploadIcon(dataUri);\n setUploading(false);\n if (ok) {\n setUploadedIconDataUri(dataUri);\n toast({ title: 'Saved', variant: 'success' });\n } else {\n toast({ title: 'Failed to save', variant: 'error' });\n }\n };\n reader.readAsDataURL(file);\n };\n\n return (\n <div>\n <div style={{ marginBottom: space[6] }}>\n <h2 style={{ margin: 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\">\n <div\n style={{\n display: 'flex',\n alignItems: 'flex-end',\n gap: space[3],\n paddingBottom: space[3],\n }}\n >\n <Input\n value={nameInput}\n onChange={(e) => setNameInput(e.target.value)}\n onBlur={handleSaveName}\n label=\"Project Name\"\n />\n <Stamp\n size=\"small\"\n fillColor=\"rgba(143, 185, 150, 0.25)\"\n textColor={color.accentGreenDark}\n >\n v{config.version}\n </Stamp>\n </div>\n <Divider />\n\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: space[3],\n paddingBottom: space[3],\n paddingTop: space[3],\n }}\n >\n {iconDataUri && (\n <img\n src={iconDataUri}\n alt=\"Project icon\"\n style={{\n width: 40,\n height: 40,\n objectFit: 'contain',\n flexShrink: 0,\n borderRadius: 4,\n }}\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 style={{ display: 'none' }}\n />\n <Button\n variant=\"secondary\"\n size=\"small\"\n onClick={() => fileRef.current?.click()}\n disabled={uploading}\n >\n {uploading ? 'Uploading…' : 'Choose File'}\n </Button>\n {identityLoading && (\n <p className=\"text-sm\" style={{ opacity: 0.5, margin: `${space[1]} 0 0` }}>\n Loading…\n </p>\n )}\n {!identityLoading && !iconDataUri && !uploading && (\n <p className=\"text-sm\" style={{ opacity: 0.45, margin: `${space[1]} 0 0` }}>\n No icon set.\n </p>\n )}\n </div>\n </div>\n <Divider />\n\n <div\n style={{\n display: 'flex',\n alignItems: 'flex-end',\n gap: space[3],\n paddingBottom: space[3],\n paddingTop: space[3],\n }}\n >\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`. Does not affect the running server.\"\n />\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 />\n ))}\n </Card>\n )}\n\n <p style={{ opacity: 0.45, fontSize: fontSize.sm, marginTop: space[4] }}>\n <strong>Initialized:</strong>{' '}\n {config ? new Date(config.initializedAt).toLocaleString() : '—'}\n </p>\n </div>\n );\n};\n\ninterface ScriptRow {\n name: string;\n command: string;\n}\n\nconst parsePackageScripts = (content: string): ScriptRow[] | null => {\n try {\n const parsed = JSON.parse(content) as { scripts?: Record<string, string> };\n if (!parsed.scripts || typeof parsed.scripts !== 'object') return null;\n return Object.entries(parsed.scripts).map(([name, command]) => ({ name, command }));\n } catch {\n return null;\n }\n};\n\nconst ConfigEditorSection = ({ fileName }: { fileName: string }) => {\n const [content, setContent] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n\n useEffect(() => {\n setLoading(true);\n fetchConfigFile(fileName).then((c) => {\n setContent(c);\n setLoading(false);\n });\n }, [fileName]);\n\n if (loading) return <p>Loading…</p>;\n if (content === null) {\n return <Alert variant=\"warning\">Could not load file — {fileName} not found.</Alert>;\n }\n\n const scripts = fileName === 'package.json' ? parsePackageScripts(content) : null;\n\n return (\n <div>\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n marginBottom: space[4],\n }}\n >\n <h2 style={{ margin: 0 }}>{fileName}</h2>\n </div>\n {scripts ? (\n <Table\n data={scripts}\n columns={[\n {\n key: 'name',\n header: 'Script',\n cell: (row: ScriptRow) => (\n <span style={{ fontFamily: fontFamily.mono }}>{row.name}</span>\n ),\n width: 4,\n },\n {\n key: 'command',\n header: 'Command',\n cell: (row: ScriptRow) => (\n <span style={{ fontFamily: fontFamily.mono }}>{row.command}</span>\n ),\n },\n ]}\n />\n ) : (\n <CodeBlock code={content} filename={fileName} />\n )}\n </div>\n );\n};\n\nconst isSecretKey = (key: string) => /key|secret|token|password/i.test(key);\n\nconst EnvSection = () => {\n const [loading, setLoading] = useState(true);\n const [rows, setRows] = useState<EnvEntry[]>([]);\n const [missingKeys, setMissingKeys] = useState<string[]>([]);\n const [revealed, setRevealed] = useState<Set<number>>(new Set());\n const [saving, setSaving] = useState(false);\n const [saved, setSaved] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n fetchEnv().then((env) => {\n setRows(env.entries);\n setMissingKeys(env.missingKeys);\n setLoading(false);\n });\n }, []);\n\n const updateRow = (index: number, patch: Partial<EnvEntry>) => {\n setRows((prev) => prev.map((row, i) => (i === index ? { ...row, ...patch } : row)));\n };\n\n const handleAddRow = () => setRows((prev) => [...prev, { key: '', value: '' }]);\n\n const handleAddMissingKey = (key: string) => {\n setRows((prev) => [...prev, { key, value: '' }]);\n setMissingKeys((prev) => prev.filter((k) => k !== key));\n };\n\n const handleDeleteRow = (index: number) => {\n setRows((prev) => prev.filter((_, i) => i !== index));\n setRevealed((prev) => {\n const next = new Set(prev);\n next.delete(index);\n return next;\n });\n };\n\n const toggleReveal = (index: number) =>\n setRevealed((prev) => {\n const next = new Set(prev);\n if (next.has(index)) next.delete(index);\n else next.add(index);\n return next;\n });\n\n const handleSave = async () => {\n const trimmed = rows\n .map((row) => ({ key: row.key.trim(), value: row.value, isSet: row.isSet }))\n .filter((row) => row.key.length > 0);\n const keys = new Set(trimmed.map((row) => row.key));\n if (keys.size !== trimmed.length) {\n setError('Duplicate keys are not allowed');\n return;\n }\n setError(null);\n setSaving(true);\n // A set key left blank keeps its existing (withheld) value; a typed value\n // replaces it. The server never received the old secret, so it backfills.\n const ok = await saveEnv(\n trimmed.map((row) => ({\n key: row.key,\n value: row.value,\n keep: !!row.isSet && row.value === '',\n })),\n );\n setSaving(false);\n if (ok) {\n // Everything just saved now exists with a withheld value — reflect that.\n setRows(trimmed.map((row) => ({ key: row.key, value: '', isSet: true })));\n setSaved(true);\n setTimeout(() => setSaved(false), 2000);\n } else {\n setError('Failed to save .env');\n }\n };\n\n if (loading) return <p>Loading…</p>;\n\n return (\n <div>\n <h2 style={{ margin: 0, marginBottom: space[4] }}>Environment Variables</h2>\n {error && <Alert variant=\"warning\">Could not save — {error}</Alert>}\n {missingKeys.length > 0 && (\n <Card size=\"small\" accent accentColor=\"amber\">\n <p style={{ margin: 0, fontWeight: 600 }}>Missing from .env</p>\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: space[2], alignItems: 'center' }}>\n <span>Present in .env.example but not set:</span>\n {missingKeys.map((key) => (\n <Button\n key={key}\n variant=\"secondary\"\n size=\"small\"\n onClick={() => handleAddMissingKey(key)}\n >\n + {key}\n </Button>\n ))}\n </div>\n </Card>\n )}\n <Table\n data={rows}\n columns={[\n {\n key: 'key',\n header: 'Key',\n cell: (row: EnvEntry, index: number) => (\n <Input\n value={row.key}\n placeholder=\"KEY\"\n style={{ fontFamily: fontFamily.mono }}\n onChange={(e) => updateRow(index, { key: e.target.value })}\n />\n ),\n width: 6,\n },\n {\n key: 'value',\n header: 'Value',\n cell: (row: EnvEntry, index: number) => {\n const masked = isSecretKey(row.key) && !revealed.has(index);\n return (\n <div style={{ display: 'flex', alignItems: 'center', gap: space[2] }}>\n <Input\n type={masked ? 'password' : 'text'}\n value={row.value}\n placeholder={row.isSet ? '•••••• set — leave blank to keep' : 'value'}\n style={{ fontFamily: fontFamily.mono, flex: 1 }}\n onChange={(e) => updateRow(index, { value: e.target.value })}\n />\n {isSecretKey(row.key) && (\n <Button variant=\"ghost\" size=\"small\" onClick={() => toggleReveal(index)}>\n {masked ? 'Show' : 'Hide'}\n </Button>\n )}\n </div>\n );\n },\n },\n {\n key: 'actions',\n header: '',\n width: 2,\n cell: (_row: EnvEntry, index: number) => (\n <IconButton\n icon={<CloseIcon />}\n variant=\"ghost\"\n size=\"small\"\n label=\"Remove variable\"\n onClick={() => handleDeleteRow(index)}\n />\n ),\n },\n ]}\n />\n <div style={{ display: 'flex', alignItems: 'center', gap: space[3], marginTop: space[4] }}>\n <Button variant=\"secondary\" size=\"small\" onClick={handleAddRow}>\n + Add variable\n </Button>\n <Button variant=\"primary\" size=\"small\" onClick={handleSave} disabled={saving}>\n {saving ? 'Saving…' : 'Save'}\n </Button>\n {saved && (\n <span className=\"text-sm\" style={{ opacity: 0.6 }}>\n Saved\n </span>\n )}\n </div>\n </div>\n );\n};\n\nexport const SettingsPage = () => {\n const activeSection = useAppStore((s) => s.activeSettingsSection);\n\n return (\n <div>\n <PageTitle>Settings</PageTitle>\n {activeSection === 'general' && <GeneralSection />}\n {activeSection === 'env' && <EnvSection />}\n {activeSection.startsWith('config:') && (\n <ConfigEditorSection fileName={activeSection.slice('config:'.length)} />\n )}\n </div>\n );\n};\n","import { fetchConfigs, fetchEnv } from '@/app/services/system';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { ListItem } from '@dendelion/paper-ui';\nimport { useEffect, useState } from 'react';\nimport { SidebarSection } from '../../plans/components/sidebar-section';\n\nexport const SettingsSidebar = () => {\n const activeSection = useAppStore((s) => s.activeSettingsSection);\n const setActiveSection = useAppStore((s) => s.setActiveSettingsSection);\n const configFiles = useAppStore((s) => s.settingsConfigFiles);\n const setConfigFiles = useAppStore((s) => s.setSettingsConfigFiles);\n const [showEnv, setShowEnv] = useState(false);\n\n useEffect(() => {\n fetchConfigs().then(setConfigFiles);\n fetchEnv().then((env) => setShowEnv(env.exists || env.exampleExists));\n }, [setConfigFiles]);\n\n return (\n <>\n <SidebarSection label=\"General\">\n <ListItem\n size=\"small\"\n active={activeSection === 'general'}\n onClick={() => setActiveSection('general')}\n >\n Project Info\n </ListItem>\n </SidebarSection>\n\n {showEnv && (\n <SidebarSection label=\"Environment\">\n <ListItem\n size=\"small\"\n active={activeSection === 'env'}\n onClick={() => setActiveSection('env')}\n >\n Env Vars\n </ListItem>\n </SidebarSection>\n )}\n\n {configFiles.length > 0 && (\n <SidebarSection label=\"Config Files\">\n {configFiles.map((name) => (\n <ListItem\n key={name}\n size=\"small\"\n active={activeSection === `config:${name}`}\n onClick={() => setActiveSection(`config:${name}`)}\n >\n {name}\n </ListItem>\n ))}\n </SidebarSection>\n )}\n </>\n );\n};\n"],"names":["fetchConfig","response","saveConfig","updates","fetchConfigs","fetchConfigFile","name","fetchEnv","saveEnv","entries","TASK_TYPE_KEYS","TASK_TYPE_LABELS","TASK_COLUMN_WIDTH","AGENT_COLUMN_WIDTH","MODEL_COLUMN_WIDTH","EFFORT_COLUMN_WIDTH","AgentTaskRowHeader","jsxs","space","jsx","fontSize","AgentTaskRow","taskKey","agentConfig","isLast","onSave","opts","AGENT_OPTIONS","modelOpts","effortOpts","localModel","setLocalModel","useState","useEffect","handleAgentChange","v","newId","newOpts","newConfig","_a","handleModelSelectChange","handleModelInputBlur","handleEffortChange","Fragment","Select","AGENT_IDS","id","AGENT_LABELS","m","Input","e","Divider","GeneralSection","fileRef","useRef","config","setConfig","fetchedIconDataUri","identityLoading","useProjectIdentity","uploadedIconDataUri","setUploadedIconDataUri","iconDataUri","uploading","setUploading","portInput","setPortInput","nameInput","setNameInput","toast","useToast","c","handleSaveAgentConfig","key","newEntry","current","updated","DEFAULT_AGENTS","prev","handleSavePort","port","handleSaveName","projectName","handleFile","file","reader","dataUri","ok","uploadIcon","Alert","Card","Stamp","color","Button","idx","parsePackageScripts","content","parsed","command","ConfigEditorSection","fileName","setContent","loading","setLoading","scripts","Table","row","fontFamily","CodeBlock","isSecretKey","EnvSection","rows","setRows","missingKeys","setMissingKeys","revealed","setRevealed","saving","setSaving","saved","setSaved","error","setError","env","updateRow","index","patch","i","handleAddRow","handleAddMissingKey","k","handleDeleteRow","_","next","toggleReveal","handleSave","trimmed","masked","_row","IconButton","CloseIcon","SettingsPage","activeSection","useAppStore","s","PageTitle","SettingsSidebar","setActiveSection","configFiles","setConfigFiles","showEnv","setShowEnv","SidebarSection","ListItem"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{j as e,c as B,u as i,a as $,s as r,d as M,O as W,D as H,l as L,f as T,b,M as F,Z as w,e as J,r as k,Q as E,J as Z,X as U,g as G,h as K,i as _,P as R,k as V,o as N}from"./main-DUy5DFoq.js";import{S as z}from"./sidebar-section-mXpllayv.js";const I=({children:t,onClick:l})=>e.jsx("button",{type:"button",onClick:l,style:{background:"none",border:"none",padding:0,color:B.accentAmberDark,cursor:"pointer",textDecoration:"underline",font:"inherit"},children:t}),Y=()=>{const t=i(p=>p.decisions),l=i(p=>p.openQuestions),d=i(p=>p.activeDocTitle),a=i(p=>p.setActiveDocTitle),n=$(),c=t.find(p=>p.title===d);if(!c)return null;const h=l.filter(p=>p.resolvedBy===c.title);return e.jsxs("div",{children:[e.jsx("h2",{style:{...M,margin:`0 0 ${r[3]}`},children:c.title}),e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:r[2],marginBottom:r[5]},children:[e.jsx("span",{className:"text-sm",style:{opacity:.5},children:c.date}),e.jsx(W,{size:"small",fillColor:H[c.status].fill,textColor:H[c.status].text,children:c.status}),c.supersededBy&&e.jsxs("span",{className:"text-sm",style:{opacity:.5},children:["Superseded by"," ",e.jsx(I,{onClick:()=>a(c.supersededBy),children:c.supersededBy})]}),h.length>0&&e.jsxs("span",{className:"text-sm",style:{opacity:.5},children:[h.length===1?"Resolves":"Resolves all of"," ",h.map((p,x)=>e.jsxs("span",{children:[x>0&&", ",e.jsx(I,{onClick:()=>{n({to:"/docs/$section",params:{section:"questions"}}),a(p.title)},children:p.title})]},p.title))]})]}),e.jsx("div",{style:{fontFamily:b.body,fontSize:T.base,lineHeight:L.relaxed,color:B.textProse},children:e.jsx(F,{children:c.body})})]})},D=(t,l)=>t.toLowerCase().includes(l.toLowerCase()),P=(t,l,d=120)=>{const a=t.toLowerCase().indexOf(l.toLowerCase());if(a===-1)return t.slice(0,d);const n=Math.max(0,a-40),c=Math.min(t.length,a+l.length+40);let h=t.slice(n,c);return n>0&&(h=`…${h}`),c<t.length&&(h=`${h}…`),h},q=({query:t})=>{const l=i(o=>o.decisions),d=i(o=>o.openQuestions),a=i(o=>o.progress),n=i(o=>o.repoDocs),c=i(o=>o.setActiveDocTitle),h=i(o=>o.setDocSearchQuery),p=$(),x=[];for(const o of l)(D(o.title,t)||D(o.body,t))&&x.push({section:"decisions",sectionLabel:"Decisions",title:o.title,snippet:P(o.body||o.title,t)});for(const o of d)(D(o.title,t)||D(o.body,t))&&x.push({section:"questions",sectionLabel:"Open Questions",title:o.title,snippet:P(o.body||o.title,t)});for(const o of a)for(const u of o.items)if(D(u,t)){x.push({section:"progress",sectionLabel:"Progress",title:o.date,snippet:P(u,t)});break}for(const o of n)(D(o.name,t)||D(o.content,t))&&x.push({section:"repo-docs",sectionLabel:"Repo Docs",title:o.name,snippet:P(o.content,t)});const j={};for(const o of x)j[o.section]||(j[o.section]=[]),j[o.section].push(o);const v=(o,u)=>{p({to:"/docs/$section",params:{section:o}}),c(u),h("")};return x.length===0?e.jsxs("p",{style:{opacity:.5},children:['No results found for "',t,'".']}):e.jsxs("div",{children:[e.jsxs("p",{className:"text-sm",style:{opacity:.5,marginBottom:r[3]},children:[x.length," result",x.length===1?"":"s",' for "',t,'"']}),Object.entries(j).map(([o,u])=>e.jsxs("div",{style:{marginBottom:r[6]},children:[e.jsx("h3",{className:"text-xs",style:{fontWeight:600,letterSpacing:"0.1em",textTransform:"uppercase",opacity:.4,margin:`0 0 ${r[2]}`},children:u[0].sectionLabel}),e.jsx("div",{style:{display:"flex",flexDirection:"column",gap:r[1]},children:u.map(m=>e.jsx(w,{variant:"ghost",size:"small",fullWidth:!0,onClick:()=>v(m.section,m.title),style:{justifyContent:"flex-start",padding:`${r[2]} ${r[3]}`},children:e.jsxs("span",{style:{textAlign:"left"},children:[e.jsx("span",{style:{fontFamily:b.serif,fontWeight:600,fontSize:"0.95rem",display:"block",marginBottom:"0.2rem"},children:m.title}),e.jsx("span",{className:"text-sm",style:{opacity:.6},children:m.snippet})]})},`${m.section}-${m.title}`))})]},o))]})},ee=()=>{const t=i(g=>g.openQuestions),l=i(g=>g.activeDocTitle),d=i(g=>g.setActiveDocTitle),a=i(g=>g.loadDecisions),n=i(g=>g.loadOpenQuestions),c=$(),{toast:h}=J(),[p,x]=k.useState(!1),[j,v]=k.useState(""),[o,u]=k.useState(""),[m,Q]=k.useState(!1),f=t.find(g=>g.title===l);if(!f)return null;const S=()=>{f.resolvedBy&&(c({to:"/docs/$section",params:{section:"decisions"}}),d(f.resolvedBy))},C=()=>{v(""),u(""),Q(!1),x(!0)},O=()=>{x(!1)},s=async g=>{if(g.preventDefault(),!(!j.trim()||m)){Q(!0);try{await K(f.title,j.trim(),o.trim()||void 0),x(!1),await Promise.all([a(),n()])}catch(X){Q(!1),h({title:"Resolve failed",description:X.message,variant:"error"})}}};return e.jsxs("div",{children:[e.jsx("h2",{style:{...M,margin:`0 0 ${r[3]}`},children:f.title}),e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:r[2],marginBottom:r[5]},children:[e.jsx("span",{className:"text-sm",style:{opacity:.5},children:f.raised}),e.jsx(W,{size:"small",fillColor:E[f.status].fill,textColor:E[f.status].text,children:f.status}),f.resolvedBy&&e.jsxs("span",{className:"text-sm",style:{opacity:.5},children:["Resolved by"," ",e.jsx(I,{onClick:S,children:f.resolvedBy})]}),f.status==="open"&&e.jsx(w,{surface:"chalkboard",onClick:C,children:"Resolve"})]}),e.jsx("div",{style:{fontFamily:b.body,fontSize:T.base,lineHeight:L.relaxed,color:B.textProse},children:e.jsx(F,{children:f.body})}),e.jsx(Z,{open:p,onClose:O,title:"Resolve question",size:"small",children:e.jsxs("form",{onSubmit:s,style:{display:"flex",flexDirection:"column",gap:r[4]},children:[e.jsx(U,{label:"Decision",value:j,onChange:g=>v(g.target.value),placeholder:"What was decided?",disabled:m,autoFocus:!0,required:!0}),e.jsx(G,{label:"Rationale",value:o,onChange:g=>u(g.target.value),placeholder:"Optional reasoning…",disabled:m,rows:4}),e.jsxs("div",{style:{display:"flex",justifyContent:"flex-end",gap:r[2]},children:[e.jsx(w,{type:"button",variant:"ghost",onClick:O,disabled:m,children:"Cancel"}),e.jsx(w,{type:"submit",variant:"primary",disabled:!j.trim()||m,children:"Resolve"})]})]})})]})},se=()=>{const t=i(n=>n.progress),l=i(n=>n.activeDocTitle),a=[...l?t.filter(n=>n.date===l):t].sort((n,c)=>c.date.localeCompare(n.date));return a.length===0?e.jsx("p",{style:{opacity:.5},children:"No progress entries found."}):e.jsx("div",{children:a.map(n=>e.jsxs("div",{style:{marginBottom:r[8]},children:[e.jsx("h3",{style:{fontFamily:b.serif,fontWeight:600,fontSize:T.md,margin:`0 0 ${r[3]}`,lineHeight:L.tight,opacity:.8},children:n.date}),e.jsx("ul",{style:{listStyle:"none",padding:0,margin:0,display:"flex",flexDirection:"column",gap:r[2]},children:n.items.map((c,h)=>e.jsx("li",{style:{fontFamily:b.body,fontSize:T.sm,lineHeight:1.55,color:B.textProse,paddingLeft:r[4],borderLeft:"2px solid rgba(0,0,0,0.08)"},children:e.jsx(F,{children:c})},`${n.date}-${h}`))})]},n.date))})},te=()=>{const t=i(n=>n.repoDocs),l=i(n=>n.activeDocTitle),d=t.find(n=>n.name===l);if(!d)return null;const a=d.name.endsWith(".md");return e.jsxs("div",{children:[e.jsx("h2",{style:{...M,margin:`0 0 ${r[4]}`},children:d.name}),a?e.jsx("div",{style:{fontFamily:b.body,fontSize:T.base,lineHeight:L.relaxed,color:B.textProse},children:e.jsx(F,{children:d.content})}):e.jsx("pre",{style:{fontFamily:b.mono,fontSize:T.xs,background:"rgba(0,0,0,0.04)",borderRadius:6,padding:r[4],overflowX:"auto",lineHeight:L.normal,whiteSpace:"pre-wrap"},children:d.content})]})},A=({itemId:t,label:l,onBack:d})=>e.jsx("div",{style:{marginBottom:r[4]},children:e.jsx(V,{items:[{id:"docs",label:"Docs",onClick:d},{id:t,label:l}]})}),le=()=>{const t=i(c=>c.docSearchQuery),l=i(c=>c.activeDocTitle),d=$(),a=_(),n=()=>d({to:"/docs"});return t.trim()?e.jsx("div",{children:e.jsx(q,{query:t})}):a==="decisions"&&l?e.jsxs("div",{children:[e.jsx(A,{itemId:"decision",label:l,onBack:n}),e.jsx(R,{children:"Decisions"}),e.jsx(Y,{})]}):a==="questions"&&l?e.jsxs("div",{children:[e.jsx(A,{itemId:"question",label:l,onBack:n}),e.jsx(R,{children:"Open Questions"}),e.jsx(ee,{})]}):a==="progress"?e.jsxs("div",{children:[e.jsx(A,{itemId:"progress",label:l??"Progress",onBack:n}),e.jsx(R,{children:"Progress"}),e.jsx(se,{})]}):a==="repo-docs"&&l?e.jsxs("div",{children:[e.jsx(A,{itemId:"repo-doc",label:l,onBack:n}),e.jsx(te,{})]}):e.jsxs("div",{children:[e.jsx(R,{children:"Docs"}),e.jsx("p",{style:{opacity:.5},children:"Select a section from the sidebar."})]})},oe=t=>t.charAt(0).toUpperCase()+t.slice(1).toLowerCase(),y=({children:t})=>e.jsx("span",{className:"text-sm",style:{display:"block",padding:`${r[1]} ${r[3]}`,opacity:.35,fontStyle:"italic"},children:t}),ce=()=>{const t=i(s=>s.decisions),l=i(s=>s.openQuestions),d=i(s=>s.progress),a=i(s=>s.repoDocs),n=i(s=>s.decisionsLoading),c=i(s=>s.openQuestionsLoading),h=i(s=>s.progressLoading),p=i(s=>s.repoDocsLoading),x=i(s=>s.loadDecisions),j=i(s=>s.loadOpenQuestions),v=i(s=>s.loadProgress),o=i(s=>s.loadRepoDocs),u=i(s=>s.activeDocTitle),m=i(s=>s.setActiveDocTitle),Q=i(s=>s.docSearchQuery),f=i(s=>s.setDocSearchQuery),S=_(),C=$();k.useEffect(()=>{x(),j(),v(),o()},[x,j,v,o]);const O=s=>{C({to:"/docs/$section",params:{section:"decisions"}}),m(s)};return e.jsxs(e.Fragment,{children:[e.jsx("div",{style:{marginBottom:r[4]},children:e.jsx(U,{size:"small","aria-label":"Search docs",placeholder:"Search docs…",value:Q,onChange:s=>f(s.target.value)})}),e.jsx(z,{label:"Repo Docs",children:p&&a.length===0?e.jsx(y,{children:"Loading…"}):a.length>0?a.map(s=>e.jsx(N,{size:"small",active:S==="repo-docs"&&u===s.name,onClick:()=>{C({to:"/docs/$section",params:{section:"repo-docs"}}),m(s.name)},children:oe(s.name)},s.name)):e.jsx(y,{children:"No repo docs found"})}),e.jsx(z,{label:"Decisions",children:n&&t.length===0?e.jsx(y,{children:"Loading…"}):t.length>0?t.map(s=>e.jsx(N,{size:"small",active:S==="decisions"&&u===s.title,onClick:()=>O(s.title),children:s.title},s.title)):e.jsx(y,{children:"No decisions yet"})}),e.jsx(z,{label:"Open Questions",children:c&&l.length===0?e.jsx(y,{children:"Loading…"}):l.length>0?l.map(s=>e.jsx(N,{size:"small",active:S==="questions"&&u===s.title,onClick:()=>{C({to:"/docs/$section",params:{section:"questions"}}),m(s.title)},children:s.title},s.title)):e.jsx(y,{children:"No open questions"})}),e.jsx(z,{label:"Progress",children:h&&d.length===0?e.jsx(y,{children:"Loading…"}):d.length>0?d.map(s=>e.jsx(N,{size:"small",active:S==="progress"&&u===s.date,onClick:()=>{C({to:"/docs/$section",params:{section:"progress"}}),m(s.date)},children:s.date},s.date)):e.jsx(y,{children:"No progress entries"})})]})};export{le as DocsPage,ce as DocsSidebar};
2
- //# sourceMappingURL=index-D-nmg_4I.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-D-nmg_4I.js","sources":["../../../src/app/components/link-button.tsx","../../../src/app/features/docs/components/decision-detail.tsx","../../../src/app/features/docs/components/docs-search.tsx","../../../src/app/features/docs/components/open-question-detail.tsx","../../../src/app/features/docs/components/progress-timeline.tsx","../../../src/app/features/docs/components/repo-doc-detail.tsx","../../../src/app/features/docs/docs-page.tsx","../../../src/app/features/docs/components/docs-sidebar.tsx"],"sourcesContent":["import { color } from '@/app/styles/tokens';\n\ninterface LinkButtonProps {\n children: React.ReactNode;\n onClick: () => void;\n}\n\nexport const LinkButton = ({ children, onClick }: LinkButtonProps) => (\n <button\n type=\"button\"\n onClick={onClick}\n style={{\n background: 'none',\n border: 'none',\n padding: 0,\n color: color.accentAmberDark,\n cursor: 'pointer',\n textDecoration: 'underline',\n font: 'inherit',\n }}\n >\n {children}\n </button>\n);\n","import { LinkButton, Markdown } from '@/app/components';\nimport { detailHeadingStyle } from '@/app/components/detail-heading-style';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { color, fontFamily, fontSize, lineHeight, space } from '@/app/styles/tokens';\nimport { Stamp } from '@dendelion/paper-ui';\nimport { useNavigate } from '@tanstack/react-router';\nimport { DECISION_STATUS_STAMP } from '../../plans/constants';\n\nexport const DecisionDetail = () => {\n const decisions = useAppStore((s) => s.decisions);\n const openQuestions = useAppStore((s) => s.openQuestions);\n const activeDocTitle = useAppStore((s) => s.activeDocTitle);\n const setActiveDocTitle = useAppStore((s) => s.setActiveDocTitle);\n const navigate = useNavigate();\n\n const decision = decisions.find((d) => d.title === activeDocTitle);\n if (!decision) return null;\n\n const resolvedQuestions = openQuestions.filter((q) => q.resolvedBy === decision.title);\n\n return (\n <div>\n <h2 style={{ ...detailHeadingStyle, margin: `0 0 ${space[3]}` }}>{decision.title}</h2>\n\n <div style={{ display: 'flex', alignItems: 'center', gap: space[2], marginBottom: space[5] }}>\n <span className=\"text-sm\" style={{ opacity: 0.5 }}>\n {decision.date}\n </span>\n <Stamp\n size=\"small\"\n fillColor={DECISION_STATUS_STAMP[decision.status].fill}\n textColor={DECISION_STATUS_STAMP[decision.status].text}\n >\n {decision.status}\n </Stamp>\n {decision.supersededBy && (\n <span className=\"text-sm\" style={{ opacity: 0.5 }}>\n Superseded by{' '}\n <LinkButton onClick={() => setActiveDocTitle(decision.supersededBy!)}>\n {decision.supersededBy}\n </LinkButton>\n </span>\n )}\n {resolvedQuestions.length > 0 && (\n <span className=\"text-sm\" style={{ opacity: 0.5 }}>\n {resolvedQuestions.length === 1 ? 'Resolves' : 'Resolves all of'}{' '}\n {resolvedQuestions.map((q, i) => (\n <span key={q.title}>\n {i > 0 && ', '}\n <LinkButton\n onClick={() => {\n navigate({ to: '/docs/$section', params: { section: 'questions' } });\n setActiveDocTitle(q.title);\n }}\n >\n {q.title}\n </LinkButton>\n </span>\n ))}\n </span>\n )}\n </div>\n\n <div\n style={{\n fontFamily: fontFamily.body,\n fontSize: fontSize.base,\n lineHeight: lineHeight.relaxed,\n color: color.textProse,\n }}\n >\n <Markdown>{decision.body}</Markdown>\n </div>\n </div>\n );\n};\n","import { useAppStore } from '@/app/stores/app-store';\nimport { fontFamily, space } from '@/app/styles/tokens';\nimport { Button } from '@dendelion/paper-ui';\nimport { useNavigate } from '@tanstack/react-router';\n\ninterface SearchMatch {\n section: 'decisions' | 'questions' | 'progress' | 'repo-docs';\n sectionLabel: string;\n title: string;\n snippet: string;\n}\n\ninterface DocsSearchProps {\n query: string;\n}\n\nconst searchIn = (text: string, query: string): boolean =>\n text.toLowerCase().includes(query.toLowerCase());\n\nconst snippet = (text: string, query: string, maxLen = 120): string => {\n const idx = text.toLowerCase().indexOf(query.toLowerCase());\n if (idx === -1) return text.slice(0, maxLen);\n const start = Math.max(0, idx - 40);\n const end = Math.min(text.length, idx + query.length + 40);\n let s = text.slice(start, end);\n if (start > 0) s = `…${s}`;\n if (end < text.length) s = `${s}…`;\n return s;\n};\n\nexport const DocsSearch = ({ query }: DocsSearchProps) => {\n const decisions = useAppStore((s) => s.decisions);\n const openQuestions = useAppStore((s) => s.openQuestions);\n const progress = useAppStore((s) => s.progress);\n const repoDocs = useAppStore((s) => s.repoDocs);\n const setActiveDocTitle = useAppStore((s) => s.setActiveDocTitle);\n const setDocSearchQuery = useAppStore((s) => s.setDocSearchQuery);\n const navigate = useNavigate();\n\n const results: SearchMatch[] = [];\n\n for (const d of decisions) {\n if (searchIn(d.title, query) || searchIn(d.body, query)) {\n results.push({\n section: 'decisions',\n sectionLabel: 'Decisions',\n title: d.title,\n snippet: snippet(d.body || d.title, query),\n });\n }\n }\n\n for (const q of openQuestions) {\n if (searchIn(q.title, query) || searchIn(q.body, query)) {\n results.push({\n section: 'questions',\n sectionLabel: 'Open Questions',\n title: q.title,\n snippet: snippet(q.body || q.title, query),\n });\n }\n }\n\n for (const p of progress) {\n for (const item of p.items) {\n if (searchIn(item, query)) {\n results.push({\n section: 'progress',\n sectionLabel: 'Progress',\n title: p.date,\n snippet: snippet(item, query),\n });\n break;\n }\n }\n }\n\n for (const f of repoDocs) {\n if (searchIn(f.name, query) || searchIn(f.content, query)) {\n results.push({\n section: 'repo-docs',\n sectionLabel: 'Repo Docs',\n title: f.name,\n snippet: snippet(f.content, query),\n });\n }\n }\n\n const grouped: Record<string, SearchMatch[]> = {};\n for (const r of results) {\n if (!grouped[r.section]) grouped[r.section] = [];\n grouped[r.section].push(r);\n }\n\n const handleSelect = (section: SearchMatch['section'], title: string) => {\n navigate({ to: '/docs/$section', params: { section } });\n setActiveDocTitle(title);\n setDocSearchQuery('');\n };\n\n if (results.length === 0) {\n return <p style={{ opacity: 0.5 }}>No results found for \"{query}\".</p>;\n }\n\n return (\n <div>\n <p className=\"text-sm\" style={{ opacity: 0.5, marginBottom: space[3] }}>\n {results.length} result{results.length === 1 ? '' : 's'} for \"{query}\"\n </p>\n {Object.entries(grouped).map(([section, matches]) => (\n <div key={section} style={{ marginBottom: space[6] }}>\n <h3\n className=\"text-xs\"\n style={{\n fontWeight: 600,\n letterSpacing: '0.1em',\n textTransform: 'uppercase',\n opacity: 0.4,\n margin: `0 0 ${space[2]}`,\n }}\n >\n {matches[0].sectionLabel}\n </h3>\n <div style={{ display: 'flex', flexDirection: 'column', gap: space[1] }}>\n {matches.map((m) => (\n <Button\n key={`${m.section}-${m.title}`}\n variant=\"ghost\"\n size=\"small\"\n fullWidth\n onClick={() => handleSelect(m.section, m.title)}\n style={{ justifyContent: 'flex-start', padding: `${space[2]} ${space[3]}` }}\n >\n <span style={{ textAlign: 'left' }}>\n <span\n style={{\n fontFamily: fontFamily.serif,\n fontWeight: 600,\n fontSize: '0.95rem',\n display: 'block',\n marginBottom: '0.2rem',\n }}\n >\n {m.title}\n </span>\n <span className=\"text-sm\" style={{ opacity: 0.6 }}>\n {m.snippet}\n </span>\n </span>\n </Button>\n ))}\n </div>\n </div>\n ))}\n </div>\n );\n};\n","import { LinkButton, Markdown } from '@/app/components';\nimport { detailHeadingStyle } from '@/app/components/detail-heading-style';\nimport { resolveOpenQuestion } from '@/app/services/content';\nimport { useAppStore } from '@/app/stores';\nimport { color, fontFamily, fontSize, lineHeight, space } from '@/app/styles/tokens';\nimport { Button, Input, Modal, Stamp, Textarea, useToast } from '@dendelion/paper-ui';\nimport { useNavigate } from '@tanstack/react-router';\nimport { useState } from 'react';\nimport { QUESTION_STATUS_STAMP } from '../../plans/constants';\n\nexport const OpenQuestionDetail = () => {\n const openQuestions = useAppStore((s) => s.openQuestions);\n const activeDocTitle = useAppStore((s) => s.activeDocTitle);\n const setActiveDocTitle = useAppStore((s) => s.setActiveDocTitle);\n const loadDecisions = useAppStore((s) => s.loadDecisions);\n const loadOpenQuestions = useAppStore((s) => s.loadOpenQuestions);\n const navigate = useNavigate();\n const { toast } = useToast();\n\n const [modalOpen, setModalOpen] = useState(false);\n const [decision, setDecision] = useState('');\n const [rationale, setRationale] = useState('');\n const [loading, setLoading] = useState(false);\n\n const question = openQuestions.find((q) => q.title === activeDocTitle);\n if (!question) return null;\n\n const handleResolvedByClick = () => {\n if (question.resolvedBy) {\n navigate({ to: '/docs/$section', params: { section: 'decisions' } });\n setActiveDocTitle(question.resolvedBy);\n }\n };\n\n const handleOpenModal = () => {\n setDecision('');\n setRationale('');\n setLoading(false);\n setModalOpen(true);\n };\n\n const handleClose = () => {\n setModalOpen(false);\n };\n\n const handleResolve = async (e: React.FormEvent) => {\n e.preventDefault();\n if (!decision.trim() || loading) return;\n setLoading(true);\n try {\n await resolveOpenQuestion(question.title, decision.trim(), rationale.trim() || undefined);\n setModalOpen(false);\n await Promise.all([loadDecisions(), loadOpenQuestions()]);\n } catch (err) {\n setLoading(false);\n toast({\n title: 'Resolve failed',\n description: (err as Error).message,\n variant: 'error',\n });\n }\n };\n\n return (\n <div>\n <h2 style={{ ...detailHeadingStyle, margin: `0 0 ${space[3]}` }}>{question.title}</h2>\n\n <div style={{ display: 'flex', alignItems: 'center', gap: space[2], marginBottom: space[5] }}>\n <span className=\"text-sm\" style={{ opacity: 0.5 }}>\n {question.raised}\n </span>\n <Stamp\n size=\"small\"\n fillColor={QUESTION_STATUS_STAMP[question.status].fill}\n textColor={QUESTION_STATUS_STAMP[question.status].text}\n >\n {question.status}\n </Stamp>\n {question.resolvedBy && (\n <span className=\"text-sm\" style={{ opacity: 0.5 }}>\n Resolved by{' '}\n <LinkButton onClick={handleResolvedByClick}>{question.resolvedBy}</LinkButton>\n </span>\n )}\n {question.status === 'open' && (\n <Button surface=\"chalkboard\" onClick={handleOpenModal}>\n Resolve\n </Button>\n )}\n </div>\n\n <div\n style={{\n fontFamily: fontFamily.body,\n fontSize: fontSize.base,\n lineHeight: lineHeight.relaxed,\n color: color.textProse,\n }}\n >\n <Markdown>{question.body}</Markdown>\n </div>\n\n <Modal open={modalOpen} onClose={handleClose} title=\"Resolve question\" size=\"small\">\n <form\n onSubmit={handleResolve}\n style={{ display: 'flex', flexDirection: 'column', gap: space[4] }}\n >\n <Input\n label=\"Decision\"\n value={decision}\n onChange={(e) => setDecision(e.target.value)}\n placeholder=\"What was decided?\"\n disabled={loading}\n autoFocus\n required\n />\n <Textarea\n label=\"Rationale\"\n value={rationale}\n onChange={(e) => setRationale(e.target.value)}\n placeholder=\"Optional reasoning…\"\n disabled={loading}\n rows={4}\n />\n <div style={{ display: 'flex', justifyContent: 'flex-end', gap: space[2] }}>\n <Button type=\"button\" variant=\"ghost\" onClick={handleClose} disabled={loading}>\n Cancel\n </Button>\n <Button type=\"submit\" variant=\"primary\" disabled={!decision.trim() || loading}>\n Resolve\n </Button>\n </div>\n </form>\n </Modal>\n </div>\n );\n};\n","import { Markdown } from '@/app/components/markdown';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { color, fontFamily, fontSize, lineHeight, space } from '@/app/styles/tokens';\n\nexport const ProgressTimeline = () => {\n const progress = useAppStore((s) => s.progress);\n const activeDocTitle = useAppStore((s) => s.activeDocTitle);\n\n const entries = activeDocTitle ? progress.filter((p) => p.date === activeDocTitle) : progress;\n\n const sorted = [...entries].sort((a, b) => b.date.localeCompare(a.date));\n\n if (sorted.length === 0) {\n return <p style={{ opacity: 0.5 }}>No progress entries found.</p>;\n }\n\n return (\n <div>\n {sorted.map((entry) => (\n <div key={entry.date} style={{ marginBottom: space[8] }}>\n <h3\n style={{\n fontFamily: fontFamily.serif,\n fontWeight: 600,\n fontSize: fontSize.md,\n margin: `0 0 ${space[3]}`,\n lineHeight: lineHeight.tight,\n opacity: 0.8,\n }}\n >\n {entry.date}\n </h3>\n <ul\n style={{\n listStyle: 'none',\n padding: 0,\n margin: 0,\n display: 'flex',\n flexDirection: 'column',\n gap: space[2],\n }}\n >\n {entry.items.map((item, i) => (\n <li\n key={`${entry.date}-${i}`}\n style={{\n fontFamily: fontFamily.body,\n fontSize: fontSize.sm,\n lineHeight: 1.55,\n color: color.textProse,\n paddingLeft: space[4],\n borderLeft: '2px solid rgba(0,0,0,0.08)',\n }}\n >\n <Markdown>{item}</Markdown>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n );\n};\n","import { detailHeadingStyle } from '@/app/components/detail-heading-style';\nimport { Markdown } from '@/app/components/markdown';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { color, fontFamily, fontSize, lineHeight, space } from '@/app/styles/tokens';\n\nexport const RepoDocDetail = () => {\n const repoDocs = useAppStore((s) => s.repoDocs);\n const activeDocTitle = useAppStore((s) => s.activeDocTitle);\n\n const file = repoDocs.find((f) => f.name === activeDocTitle);\n if (!file) return null;\n\n const isMarkdown = file.name.endsWith('.md');\n\n return (\n <div>\n <h2 style={{ ...detailHeadingStyle, margin: `0 0 ${space[4]}` }}>{file.name}</h2>\n\n {isMarkdown ? (\n <div\n style={{\n fontFamily: fontFamily.body,\n fontSize: fontSize.base,\n lineHeight: lineHeight.relaxed,\n color: color.textProse,\n }}\n >\n <Markdown>{file.content}</Markdown>\n </div>\n ) : (\n <pre\n style={{\n fontFamily: fontFamily.mono,\n fontSize: fontSize.xs,\n background: 'rgba(0,0,0,0.04)',\n borderRadius: 6,\n padding: space[4],\n overflowX: 'auto',\n lineHeight: lineHeight.normal,\n whiteSpace: 'pre-wrap',\n }}\n >\n {file.content}\n </pre>\n )}\n </div>\n );\n};\n","import { PageTitle } from '@/app/components/page-title';\nimport { useResolvedDocSection } from '@/app/hooks';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { space } from '@/app/styles/tokens';\nimport { Breadcrumb } from '@dendelion/paper-ui';\nimport { useNavigate } from '@tanstack/react-router';\nimport { DecisionDetail } from './components/decision-detail';\nimport { DocsSearch } from './components/docs-search';\nimport { OpenQuestionDetail } from './components/open-question-detail';\nimport { ProgressTimeline } from './components/progress-timeline';\nimport { RepoDocDetail } from './components/repo-doc-detail';\n\n/** Docs / <item> breadcrumb above a doc detail view — the \"Docs\" crumb navigates back. */\nconst DocsBreadcrumb = ({\n itemId,\n label,\n onBack,\n}: {\n itemId: string;\n label: string;\n onBack: () => void;\n}) => (\n <div style={{ marginBottom: space[4] }}>\n <Breadcrumb\n items={[\n { id: 'docs', label: 'Docs', onClick: onBack },\n { id: itemId, label },\n ]}\n />\n </div>\n);\n\nexport const DocsPage = () => {\n const docSearchQuery = useAppStore((s) => s.docSearchQuery);\n const activeDocTitle = useAppStore((s) => s.activeDocTitle);\n const navigate = useNavigate();\n const activeDocSection = useResolvedDocSection();\n\n const handleBackToDocs = () => navigate({ to: '/docs' });\n\n if (docSearchQuery.trim()) {\n return (\n <div>\n <DocsSearch query={docSearchQuery} />\n </div>\n );\n }\n\n if (activeDocSection === 'decisions' && activeDocTitle) {\n return (\n <div>\n <DocsBreadcrumb itemId=\"decision\" label={activeDocTitle} onBack={handleBackToDocs} />\n <PageTitle>Decisions</PageTitle>\n <DecisionDetail />\n </div>\n );\n }\n\n if (activeDocSection === 'questions' && activeDocTitle) {\n return (\n <div>\n <DocsBreadcrumb itemId=\"question\" label={activeDocTitle} onBack={handleBackToDocs} />\n <PageTitle>Open Questions</PageTitle>\n <OpenQuestionDetail />\n </div>\n );\n }\n\n if (activeDocSection === 'progress') {\n return (\n <div>\n <DocsBreadcrumb\n itemId=\"progress\"\n label={activeDocTitle ?? 'Progress'}\n onBack={handleBackToDocs}\n />\n <PageTitle>Progress</PageTitle>\n <ProgressTimeline />\n </div>\n );\n }\n\n if (activeDocSection === 'repo-docs' && activeDocTitle) {\n return (\n <div>\n <DocsBreadcrumb itemId=\"repo-doc\" label={activeDocTitle} onBack={handleBackToDocs} />\n <RepoDocDetail />\n </div>\n );\n }\n\n return (\n <div>\n <PageTitle>Docs</PageTitle>\n <p style={{ opacity: 0.5 }}>Select a section from the sidebar.</p>\n </div>\n );\n};\n","import { useResolvedDocSection } from '@/app/hooks';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { space } from '@/app/styles/tokens';\nimport { Input, ListItem } from '@dendelion/paper-ui';\nimport { useNavigate } from '@tanstack/react-router';\nimport { useEffect } from 'react';\nimport { SidebarSection } from '../../plans/components/sidebar-section';\n\nconst simplecaseLabel = (name: string) =>\n name.charAt(0).toUpperCase() + name.slice(1).toLowerCase();\n\nconst EmptyState = ({ children }: { children: React.ReactNode }) => (\n <span\n className=\"text-sm\"\n style={{\n display: 'block',\n padding: `${space[1]} ${space[3]}`,\n opacity: 0.35,\n fontStyle: 'italic',\n }}\n >\n {children}\n </span>\n);\n\nexport const DocsSidebar = () => {\n const decisions = useAppStore((s) => s.decisions);\n const openQuestions = useAppStore((s) => s.openQuestions);\n const progress = useAppStore((s) => s.progress);\n const repoDocs = useAppStore((s) => s.repoDocs);\n const decisionsLoading = useAppStore((s) => s.decisionsLoading);\n const openQuestionsLoading = useAppStore((s) => s.openQuestionsLoading);\n const progressLoading = useAppStore((s) => s.progressLoading);\n const repoDocsLoading = useAppStore((s) => s.repoDocsLoading);\n const loadDecisions = useAppStore((s) => s.loadDecisions);\n const loadOpenQuestions = useAppStore((s) => s.loadOpenQuestions);\n const loadProgress = useAppStore((s) => s.loadProgress);\n const loadRepoDocs = useAppStore((s) => s.loadRepoDocs);\n const activeDocTitle = useAppStore((s) => s.activeDocTitle);\n const setActiveDocTitle = useAppStore((s) => s.setActiveDocTitle);\n const docSearchQuery = useAppStore((s) => s.docSearchQuery);\n const setDocSearchQuery = useAppStore((s) => s.setDocSearchQuery);\n const activeDocSection = useResolvedDocSection();\n const navigate = useNavigate();\n\n useEffect(() => {\n loadDecisions();\n loadOpenQuestions();\n loadProgress();\n loadRepoDocs();\n }, [loadDecisions, loadOpenQuestions, loadProgress, loadRepoDocs]);\n\n const handleSelectDecision = (title: string) => {\n navigate({ to: '/docs/$section', params: { section: 'decisions' } });\n setActiveDocTitle(title);\n };\n\n return (\n <>\n <div style={{ marginBottom: space[4] }}>\n <Input\n size=\"small\"\n aria-label=\"Search docs\"\n placeholder=\"Search docs…\"\n value={docSearchQuery}\n onChange={(e) => setDocSearchQuery(e.target.value)}\n />\n </div>\n\n <SidebarSection label=\"Repo Docs\">\n {repoDocsLoading && repoDocs.length === 0 ? (\n <EmptyState>Loading…</EmptyState>\n ) : repoDocs.length > 0 ? (\n repoDocs.map((f) => (\n <ListItem\n key={f.name}\n size=\"small\"\n active={activeDocSection === 'repo-docs' && activeDocTitle === f.name}\n onClick={() => {\n navigate({ to: '/docs/$section', params: { section: 'repo-docs' } });\n setActiveDocTitle(f.name);\n }}\n >\n {simplecaseLabel(f.name)}\n </ListItem>\n ))\n ) : (\n <EmptyState>No repo docs found</EmptyState>\n )}\n </SidebarSection>\n\n <SidebarSection label=\"Decisions\">\n {decisionsLoading && decisions.length === 0 ? (\n <EmptyState>Loading…</EmptyState>\n ) : decisions.length > 0 ? (\n decisions.map((d) => (\n <ListItem\n key={d.title}\n size=\"small\"\n active={activeDocSection === 'decisions' && activeDocTitle === d.title}\n onClick={() => handleSelectDecision(d.title)}\n >\n {d.title}\n </ListItem>\n ))\n ) : (\n <EmptyState>No decisions yet</EmptyState>\n )}\n </SidebarSection>\n\n <SidebarSection label=\"Open Questions\">\n {openQuestionsLoading && openQuestions.length === 0 ? (\n <EmptyState>Loading…</EmptyState>\n ) : openQuestions.length > 0 ? (\n openQuestions.map((q) => (\n <ListItem\n key={q.title}\n size=\"small\"\n active={activeDocSection === 'questions' && activeDocTitle === q.title}\n onClick={() => {\n navigate({ to: '/docs/$section', params: { section: 'questions' } });\n setActiveDocTitle(q.title);\n }}\n >\n {q.title}\n </ListItem>\n ))\n ) : (\n <EmptyState>No open questions</EmptyState>\n )}\n </SidebarSection>\n\n <SidebarSection label=\"Progress\">\n {progressLoading && progress.length === 0 ? (\n <EmptyState>Loading…</EmptyState>\n ) : progress.length > 0 ? (\n progress.map((p) => (\n <ListItem\n key={p.date}\n size=\"small\"\n active={activeDocSection === 'progress' && activeDocTitle === p.date}\n onClick={() => {\n navigate({ to: '/docs/$section', params: { section: 'progress' } });\n setActiveDocTitle(p.date);\n }}\n >\n {p.date}\n </ListItem>\n ))\n ) : (\n <EmptyState>No progress entries</EmptyState>\n )}\n </SidebarSection>\n </>\n );\n};\n"],"names":["LinkButton","children","onClick","jsx","color","DecisionDetail","decisions","useAppStore","s","openQuestions","activeDocTitle","setActiveDocTitle","navigate","useNavigate","decision","d","resolvedQuestions","q","detailHeadingStyle","space","Stamp","DECISION_STATUS_STAMP","jsxs","i","fontFamily","fontSize","lineHeight","Markdown","searchIn","text","query","snippet","maxLen","idx","start","end","DocsSearch","progress","repoDocs","setDocSearchQuery","results","p","item","f","grouped","r","handleSelect","section","title","matches","Button","OpenQuestionDetail","loadDecisions","loadOpenQuestions","toast","useToast","modalOpen","setModalOpen","useState","setDecision","rationale","setRationale","loading","setLoading","question","handleResolvedByClick","handleOpenModal","handleClose","handleResolve","e","resolveOpenQuestion","err","QUESTION_STATUS_STAMP","Modal","Input","Textarea","ProgressTimeline","sorted","a","b","entry","RepoDocDetail","file","isMarkdown","DocsBreadcrumb","itemId","label","onBack","Breadcrumb","DocsPage","docSearchQuery","activeDocSection","useResolvedDocSection","handleBackToDocs","PageTitle","simplecaseLabel","name","EmptyState","DocsSidebar","decisionsLoading","openQuestionsLoading","progressLoading","repoDocsLoading","loadProgress","loadRepoDocs","useEffect","handleSelectDecision","Fragment","SidebarSection","ListItem"],"mappings":"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"}
@@ -1,3 +0,0 @@
1
- import{u as h,C as j,r as i,j as e,P as k,s as f,p as x,f as p,B as w,b as u,O as y,c as m,E as S}from"./main-DUy5DFoq.js";const v={phase:"Phase run",audit:"Audit","batch-reconcile":"Batch reconcile","run-all":"Run all phases",draft:"Draft",extend:"Extend",suggest:"Suggest ideas","commit-suggest":"Commit suggest","overlap-check":"Overlap check",sync:"Sync",reconcile:"Reconcile","fix-review":"Fix review"},g=s=>{const t=new Date(s),a=o=>String(o).padStart(2,"0");return`${a(t.getDate())}/${a(t.getMonth()+1)} ${a(t.getHours())}:${a(t.getMinutes())}:${a(t.getSeconds())}`},r={fontSize:p.sm,fontWeight:600,opacity:.6,whiteSpace:"nowrap",overflow:"hidden"},L=({id:s})=>{const[t,a]=i.useState(null);return i.useEffect(()=>{a(null),S(s).then(o=>a(o.lines)).catch(()=>a([]))},[s]),t===null?e.jsx("p",{style:{opacity:.5,margin:0},children:"Loading…"}):t.length===0?e.jsx("p",{style:{opacity:.5,margin:0},children:"No output recorded."}):e.jsx("pre",{style:{fontFamily:u.mono,fontSize:p.xs,margin:0,maxHeight:320,overflowY:"auto",whiteSpace:"pre-wrap"},children:t.join(`
2
- `)})},N=({size:s=14})=>e.jsx("svg",{width:s,height:s,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:e.jsx("polyline",{points:"9 18 15 12 9 6"})}),E=({entry:s,highlighted:t})=>{const[a,o]=i.useState(t);i.useEffect(()=>{t&&o(!0)},[t]);const c=()=>o(l=>!l);return e.jsxs("div",{className:t?"task-row-highlighted":void 0,style:{display:"flex",flexDirection:"column",gap:f[1],borderRadius:10},children:[e.jsx("div",{role:"button",tabIndex:0,onClick:c,onKeyDown:l=>{(l.key==="Enter"||l.key===" ")&&(l.preventDefault(),c())},style:{cursor:"pointer",borderRadius:10},children:e.jsx(x,{size:"small",texture:"canvas",className:"plan-row-card",children:e.jsxs("div",{className:"task-rows-grid",children:[e.jsx("span",{className:"task-rows-chevron","aria-expanded":a,style:{display:"inline-flex",alignItems:"center",opacity:.5},children:e.jsx(N,{})}),e.jsx("span",{style:{fontWeight:600,whiteSpace:"nowrap",overflow:"hidden"},children:v[s.taskKind]}),e.jsx("span",{style:{overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",opacity:.7},children:s.planTitle}),e.jsx("span",{className:"text-sm",style:{opacity:.5,whiteSpace:"nowrap"},children:w[s.agentId]}),e.jsx("span",{className:"task-rows-cell-time",style:{fontFamily:u.mono,fontSize:p.xs,opacity:.55,whiteSpace:"nowrap"},children:g(s.startedAt)}),e.jsx("span",{className:"task-rows-cell-time",style:{fontFamily:u.mono,fontSize:p.xs,opacity:.55,whiteSpace:"nowrap"},children:g(s.endedAt)}),e.jsx("div",{style:{display:"flex",alignItems:"center"},children:e.jsx(y,{size:"small",fillColor:s.outcome==="done"?"rgba(143, 185, 150, 0.25)":"rgba(201, 139, 139, 0.25)",textColor:s.outcome==="done"?m.accentGreenDark:m.accentRoseDark,children:s.outcome})})]})})}),a&&e.jsx(x,{size:"small",texture:"kraft",className:"plan-row-card",children:e.jsx(L,{id:s.id})})]})},b=()=>{const s=h(n=>n.taskLog),t=h(n=>n.taskLogLoading),a=h(n=>n.loadTaskLog),{taskId:o}=j({from:"/tasks"}),c=i.useRef(null);i.useEffect(()=>{a()},[a]),i.useEffect(()=>{var d;if(!o)return;const n=(d=c.current)==null?void 0:d.querySelector(".task-row-highlighted");n==null||n.scrollIntoView({behavior:"smooth",block:"center"})},[o]);const l=[...s].sort((n,d)=>d.endedAt.localeCompare(n.endedAt));return e.jsxs("div",{ref:c,children:[e.jsx(k,{children:"Tasks"}),t&&e.jsx("p",{style:{opacity:.5},children:"Loading…"}),!t&&l.length===0&&e.jsx("p",{style:{opacity:.5},children:"No tasks have run yet."}),!t&&l.length>0&&e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:f[1]},children:[e.jsx(x,{size:"small",texture:"kraft",className:"plan-row-card",children:e.jsxs("div",{className:"task-rows-grid",children:[e.jsx("span",{}),e.jsx("span",{style:r,children:"Task"}),e.jsx("span",{style:r,children:"Plan"}),e.jsx("span",{style:r,children:"Agent"}),e.jsx("span",{className:"task-rows-cell-time",style:r,children:"Started"}),e.jsx("span",{className:"task-rows-cell-time",style:r,children:"Ended"}),e.jsx("span",{style:r,children:"Outcome"})]})}),l.map(n=>e.jsx(E,{entry:n,highlighted:n.id===o},n.id))]})]})};export{b as TasksPage};
3
- //# sourceMappingURL=index-Djq8LvrZ.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-Djq8LvrZ.js","sources":["../../../src/app/features/tasks/tasks-page.tsx"],"sourcesContent":["import { PageTitle } from '@/app/components/page-title';\nimport { fetchTaskLogLines } from '@/app/services/content/docs-api';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { color, fontFamily, fontSize, space } from '@/app/styles/tokens';\nimport { AGENT_LABELS, type TaskKind, type TaskLogEntry } from '@/types/index';\nimport { Card, Stamp } from '@dendelion/paper-ui';\nimport { useSearch } from '@tanstack/react-router';\nimport { useEffect, useRef, useState } from 'react';\n\nconst TASK_KIND_LABELS: Record<TaskKind, string> = {\n phase: 'Phase run',\n audit: 'Audit',\n 'batch-reconcile': 'Batch reconcile',\n 'run-all': 'Run all phases',\n draft: 'Draft',\n extend: 'Extend',\n suggest: 'Suggest ideas',\n 'commit-suggest': 'Commit suggest',\n 'overlap-check': 'Overlap check',\n sync: 'Sync',\n reconcile: 'Reconcile',\n 'fix-review': 'Fix review',\n};\n\nconst formatTimestamp = (iso: string) => {\n const d = new Date(iso);\n const pad = (n: number) => String(n).padStart(2, '0');\n return `${pad(d.getDate())}/${pad(d.getMonth() + 1)} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;\n};\n\nconst headerLabelStyle: React.CSSProperties = {\n fontSize: fontSize.sm,\n fontWeight: 600,\n opacity: 0.6,\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n};\n\nconst TaskLogLines = ({ id }: { id: string }) => {\n const [lines, setLines] = useState<string[] | null>(null);\n\n useEffect(() => {\n setLines(null);\n fetchTaskLogLines(id)\n .then((data) => setLines(data.lines))\n .catch(() => setLines([]));\n }, [id]);\n\n if (lines === null) return <p style={{ opacity: 0.5, margin: 0 }}>Loading…</p>;\n if (lines.length === 0) return <p style={{ opacity: 0.5, margin: 0 }}>No output recorded.</p>;\n return (\n <pre\n style={{\n fontFamily: fontFamily.mono,\n fontSize: fontSize.xs,\n margin: 0,\n maxHeight: 320,\n overflowY: 'auto',\n whiteSpace: 'pre-wrap',\n }}\n >\n {lines.join('\\n')}\n </pre>\n );\n};\n\nconst ChevronRightIcon = ({ size = 14 }: { size?: number }) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <polyline points=\"9 18 15 12 9 6\" />\n </svg>\n);\n\nconst TaskRow = ({ entry, highlighted }: { entry: TaskLogEntry; highlighted: boolean }) => {\n const [expanded, setExpanded] = useState(highlighted);\n useEffect(() => {\n if (highlighted) setExpanded(true);\n }, [highlighted]);\n const toggle = () => setExpanded((v) => !v);\n\n return (\n <div\n className={highlighted ? 'task-row-highlighted' : undefined}\n style={{ display: 'flex', flexDirection: 'column', gap: space[1], borderRadius: 10 }}\n >\n {/* biome-ignore lint/a11y/useSemanticElements: the clickable row wraps a Card whose block layout a native <button> would break; keyboard toggling is wired on the div. */}\n <div\n role=\"button\"\n tabIndex={0}\n onClick={toggle}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n toggle();\n }\n }}\n style={{ cursor: 'pointer', borderRadius: 10 }}\n >\n <Card size=\"small\" texture=\"canvas\" className=\"plan-row-card\">\n <div className=\"task-rows-grid\">\n <span\n className=\"task-rows-chevron\"\n aria-expanded={expanded}\n style={{ display: 'inline-flex', alignItems: 'center', opacity: 0.5 }}\n >\n <ChevronRightIcon />\n </span>\n <span style={{ fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden' }}>\n {TASK_KIND_LABELS[entry.taskKind]}\n </span>\n <span\n style={{\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n opacity: 0.7,\n }}\n >\n {entry.planTitle}\n </span>\n <span className=\"text-sm\" style={{ opacity: 0.5, whiteSpace: 'nowrap' }}>\n {AGENT_LABELS[entry.agentId]}\n </span>\n <span\n className=\"task-rows-cell-time\"\n style={{\n fontFamily: fontFamily.mono,\n fontSize: fontSize.xs,\n opacity: 0.55,\n whiteSpace: 'nowrap',\n }}\n >\n {formatTimestamp(entry.startedAt)}\n </span>\n <span\n className=\"task-rows-cell-time\"\n style={{\n fontFamily: fontFamily.mono,\n fontSize: fontSize.xs,\n opacity: 0.55,\n whiteSpace: 'nowrap',\n }}\n >\n {formatTimestamp(entry.endedAt)}\n </span>\n <div style={{ display: 'flex', alignItems: 'center' }}>\n <Stamp\n size=\"small\"\n fillColor={\n entry.outcome === 'done'\n ? 'rgba(143, 185, 150, 0.25)'\n : 'rgba(201, 139, 139, 0.25)'\n }\n textColor={entry.outcome === 'done' ? color.accentGreenDark : color.accentRoseDark}\n >\n {entry.outcome}\n </Stamp>\n </div>\n </div>\n </Card>\n </div>\n {expanded && (\n <Card size=\"small\" texture=\"kraft\" className=\"plan-row-card\">\n <TaskLogLines id={entry.id} />\n </Card>\n )}\n </div>\n );\n};\n\nexport const TasksPage = () => {\n const taskLog = useAppStore((s) => s.taskLog);\n const taskLogLoading = useAppStore((s) => s.taskLogLoading);\n const loadTaskLog = useAppStore((s) => s.loadTaskLog);\n const { taskId } = useSearch({ from: '/tasks' });\n const containerRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n loadTaskLog();\n }, [loadTaskLog]);\n\n useEffect(() => {\n if (!taskId) return;\n const row = containerRef.current?.querySelector('.task-row-highlighted');\n row?.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }, [taskId]);\n\n const sorted = [...taskLog].sort((a, b) => b.endedAt.localeCompare(a.endedAt));\n\n return (\n <div ref={containerRef}>\n <PageTitle>Tasks</PageTitle>\n {taskLogLoading && <p style={{ opacity: 0.5 }}>Loading…</p>}\n {!taskLogLoading && sorted.length === 0 && (\n <p style={{ opacity: 0.5 }}>No tasks have run yet.</p>\n )}\n {!taskLogLoading && sorted.length > 0 && (\n <div style={{ display: 'flex', flexDirection: 'column', gap: space[1] }}>\n <Card size=\"small\" texture=\"kraft\" className=\"plan-row-card\">\n <div className=\"task-rows-grid\">\n <span />\n <span style={headerLabelStyle}>Task</span>\n <span style={headerLabelStyle}>Plan</span>\n <span style={headerLabelStyle}>Agent</span>\n <span className=\"task-rows-cell-time\" style={headerLabelStyle}>\n Started\n </span>\n <span className=\"task-rows-cell-time\" style={headerLabelStyle}>\n Ended\n </span>\n <span style={headerLabelStyle}>Outcome</span>\n </div>\n </Card>\n {sorted.map((entry) => (\n <TaskRow key={entry.id} entry={entry} highlighted={entry.id === taskId} />\n ))}\n </div>\n )}\n </div>\n );\n};\n"],"names":["TASK_KIND_LABELS","formatTimestamp","iso","d","pad","n","headerLabelStyle","fontSize","TaskLogLines","id","lines","setLines","useState","useEffect","fetchTaskLogLines","data","jsx","fontFamily","ChevronRightIcon","size","TaskRow","entry","highlighted","expanded","setExpanded","toggle","v","jsxs","space","e","Card","AGENT_LABELS","Stamp","color","TasksPage","taskLog","useAppStore","s","taskLogLoading","loadTaskLog","taskId","useSearch","containerRef","useRef","row","_a","sorted","a","b","PageTitle"],"mappings":"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"}