feed-the-machine 1.6.0 → 1.7.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 (269) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +170 -170
  3. package/bin/brain.py +1340 -0
  4. package/bin/convert_claude_skills_to_codex.py +490 -0
  5. package/bin/generate-manifest.mjs +463 -463
  6. package/bin/harden_codex_skills.py +141 -0
  7. package/bin/install.mjs +491 -491
  8. package/bin/migrate-eng-buddy-data.py +875 -0
  9. package/bin/playbook_engine/__init__.py +1 -0
  10. package/bin/playbook_engine/conftest.py +8 -0
  11. package/bin/playbook_engine/extractor.py +33 -0
  12. package/bin/playbook_engine/manager.py +102 -0
  13. package/bin/playbook_engine/models.py +84 -0
  14. package/bin/playbook_engine/registry.py +35 -0
  15. package/bin/playbook_engine/test_extractor.py +72 -0
  16. package/bin/playbook_engine/test_integration.py +129 -0
  17. package/bin/playbook_engine/test_manager.py +85 -0
  18. package/bin/playbook_engine/test_models.py +166 -0
  19. package/bin/playbook_engine/test_registry.py +67 -0
  20. package/bin/playbook_engine/test_tracer.py +86 -0
  21. package/bin/playbook_engine/tracer.py +93 -0
  22. package/bin/tasks_db.py +456 -0
  23. package/docs/HOOKS.md +243 -243
  24. package/docs/INBOX.md +233 -233
  25. package/ftm/SKILL.md +125 -122
  26. package/ftm-audit/SKILL.md +623 -623
  27. package/ftm-audit/references/protocols/PROJECT-PATTERNS.md +91 -91
  28. package/ftm-audit/references/protocols/RUNTIME-WIRING.md +66 -66
  29. package/ftm-audit/references/protocols/WIRING-CONTRACTS.md +135 -135
  30. package/ftm-audit/references/strategies/AUTO-FIX-STRATEGIES.md +69 -69
  31. package/ftm-audit/references/templates/REPORT-FORMAT.md +96 -96
  32. package/ftm-audit/scripts/run-knip.sh +23 -23
  33. package/ftm-audit.yml +2 -2
  34. package/ftm-brainstorm/SKILL.md +1003 -498
  35. package/ftm-brainstorm/evals/evals.json +180 -100
  36. package/ftm-brainstorm/evals/promptfoo.yaml +109 -109
  37. package/ftm-brainstorm/references/agent-prompts.md +552 -224
  38. package/ftm-brainstorm/references/plan-template.md +209 -121
  39. package/ftm-brainstorm.yml +2 -2
  40. package/ftm-browse/SKILL.md +454 -454
  41. package/ftm-browse/daemon/browser-manager.ts +206 -206
  42. package/ftm-browse/daemon/bun.lock +30 -30
  43. package/ftm-browse/daemon/cli.ts +347 -347
  44. package/ftm-browse/daemon/commands.ts +410 -410
  45. package/ftm-browse/daemon/main.ts +357 -357
  46. package/ftm-browse/daemon/package.json +17 -17
  47. package/ftm-browse/daemon/server.ts +189 -189
  48. package/ftm-browse/daemon/snapshot.ts +519 -519
  49. package/ftm-browse/daemon/tsconfig.json +22 -22
  50. package/ftm-browse.yml +4 -4
  51. package/ftm-capture/SKILL.md +370 -370
  52. package/ftm-capture.yml +4 -4
  53. package/ftm-codex-gate/SKILL.md +361 -361
  54. package/ftm-codex-gate.yml +2 -2
  55. package/ftm-config/SKILL.md +422 -345
  56. package/ftm-config.default.yml +125 -82
  57. package/ftm-config.yml +44 -2
  58. package/ftm-council/SKILL.md +416 -416
  59. package/ftm-council/references/prompts/CLAUDE-INVESTIGATION.md +60 -60
  60. package/ftm-council/references/prompts/CODEX-INVESTIGATION.md +58 -58
  61. package/ftm-council/references/prompts/GEMINI-INVESTIGATION.md +58 -58
  62. package/ftm-council/references/prompts/REBUTTAL-TEMPLATE.md +57 -57
  63. package/ftm-council/references/protocols/PREREQUISITES.md +47 -47
  64. package/ftm-council/references/protocols/STEP-0-FRAMING.md +46 -46
  65. package/ftm-council.yml +2 -2
  66. package/ftm-dashboard/SKILL.md +163 -163
  67. package/ftm-dashboard.yml +4 -4
  68. package/ftm-debug/SKILL.md +1037 -1037
  69. package/ftm-debug/references/phases/PHASE-0-INTAKE.md +58 -58
  70. package/ftm-debug/references/phases/PHASE-1-TRIAGE.md +46 -46
  71. package/ftm-debug/references/phases/PHASE-2-WAR-ROOM-AGENTS.md +279 -279
  72. package/ftm-debug/references/phases/PHASE-3-TO-6-EXECUTION.md +436 -436
  73. package/ftm-debug/references/protocols/BLACKBOARD.md +86 -86
  74. package/ftm-debug/references/protocols/EDGE-CASES.md +103 -103
  75. package/ftm-debug.yml +2 -2
  76. package/ftm-diagram/SKILL.md +277 -277
  77. package/ftm-diagram.yml +2 -2
  78. package/ftm-executor/SKILL.md +777 -777
  79. package/ftm-executor/references/STYLE-TEMPLATE.md +73 -73
  80. package/ftm-executor/references/phases/PHASE-0-VERIFICATION.md +62 -62
  81. package/ftm-executor/references/phases/PHASE-2-AGENT-ASSEMBLY.md +34 -34
  82. package/ftm-executor/references/phases/PHASE-3-WORKTREES.md +38 -38
  83. package/ftm-executor/references/phases/PHASE-4-5-AUDIT.md +72 -72
  84. package/ftm-executor/references/phases/PHASE-4-DISPATCH.md +66 -66
  85. package/ftm-executor/references/phases/PHASE-5-5-CODEX-GATE.md +73 -73
  86. package/ftm-executor/references/protocols/DOCUMENTATION-BOOTSTRAP.md +36 -36
  87. package/ftm-executor/references/protocols/MODEL-PROFILE.md +59 -59
  88. package/ftm-executor/references/protocols/PROGRESS-TRACKING.md +66 -66
  89. package/ftm-executor/runtime/ftm-runtime.mjs +252 -252
  90. package/ftm-executor/runtime/package.json +8 -8
  91. package/ftm-executor.yml +2 -2
  92. package/ftm-git/SKILL.md +441 -441
  93. package/ftm-git/evals/evals.json +26 -26
  94. package/ftm-git/evals/promptfoo.yaml +75 -75
  95. package/ftm-git/hooks/post-commit-experience.sh +92 -92
  96. package/ftm-git/references/patterns/SECRET-PATTERNS.md +104 -104
  97. package/ftm-git/references/protocols/REMEDIATION.md +139 -139
  98. package/ftm-git/scripts/pre-commit-secrets.sh +110 -110
  99. package/ftm-git.yml +2 -2
  100. package/ftm-inbox/backend/__pycache__/main.cpython-314.pyc +0 -0
  101. package/ftm-inbox/backend/adapters/_retry.py +64 -64
  102. package/ftm-inbox/backend/adapters/base.py +230 -230
  103. package/ftm-inbox/backend/adapters/freshservice.py +104 -104
  104. package/ftm-inbox/backend/adapters/gmail.py +125 -125
  105. package/ftm-inbox/backend/adapters/jira.py +136 -136
  106. package/ftm-inbox/backend/adapters/registry.py +192 -192
  107. package/ftm-inbox/backend/adapters/slack.py +110 -110
  108. package/ftm-inbox/backend/db/connection.py +54 -54
  109. package/ftm-inbox/backend/db/schema.py +78 -78
  110. package/ftm-inbox/backend/executor/__init__.py +7 -7
  111. package/ftm-inbox/backend/executor/engine.py +149 -149
  112. package/ftm-inbox/backend/executor/step_runner.py +98 -98
  113. package/ftm-inbox/backend/main.py +103 -103
  114. package/ftm-inbox/backend/models/__init__.py +1 -1
  115. package/ftm-inbox/backend/models/unified_task.py +36 -36
  116. package/ftm-inbox/backend/planner/__init__.py +6 -6
  117. package/ftm-inbox/backend/planner/__pycache__/__init__.cpython-314.pyc +0 -0
  118. package/ftm-inbox/backend/planner/__pycache__/generator.cpython-314.pyc +0 -0
  119. package/ftm-inbox/backend/planner/__pycache__/schema.cpython-314.pyc +0 -0
  120. package/ftm-inbox/backend/planner/generator.py +127 -127
  121. package/ftm-inbox/backend/planner/schema.py +34 -34
  122. package/ftm-inbox/backend/requirements.txt +5 -5
  123. package/ftm-inbox/backend/routes/__pycache__/plan.cpython-314.pyc +0 -0
  124. package/ftm-inbox/backend/routes/execute.py +186 -186
  125. package/ftm-inbox/backend/routes/health.py +52 -52
  126. package/ftm-inbox/backend/routes/inbox.py +68 -68
  127. package/ftm-inbox/backend/routes/plan.py +271 -271
  128. package/ftm-inbox/bin/launchagent.mjs +91 -91
  129. package/ftm-inbox/bin/setup.mjs +188 -188
  130. package/ftm-inbox/bin/start.sh +10 -10
  131. package/ftm-inbox/bin/status.sh +17 -17
  132. package/ftm-inbox/bin/stop.sh +8 -8
  133. package/ftm-inbox/config.example.yml +55 -55
  134. package/ftm-inbox/package-lock.json +2898 -2898
  135. package/ftm-inbox/package.json +26 -26
  136. package/ftm-inbox/postcss.config.js +6 -6
  137. package/ftm-inbox/src/app.css +199 -199
  138. package/ftm-inbox/src/app.html +18 -18
  139. package/ftm-inbox/src/lib/api.ts +166 -166
  140. package/ftm-inbox/src/lib/components/ExecutionLog.svelte +81 -81
  141. package/ftm-inbox/src/lib/components/InboxFeed.svelte +143 -143
  142. package/ftm-inbox/src/lib/components/PlanStep.svelte +271 -271
  143. package/ftm-inbox/src/lib/components/PlanView.svelte +206 -206
  144. package/ftm-inbox/src/lib/components/StreamPanel.svelte +99 -99
  145. package/ftm-inbox/src/lib/components/TaskCard.svelte +190 -190
  146. package/ftm-inbox/src/lib/components/ui/EmptyState.svelte +63 -63
  147. package/ftm-inbox/src/lib/components/ui/KawaiiCard.svelte +86 -86
  148. package/ftm-inbox/src/lib/components/ui/PillButton.svelte +106 -106
  149. package/ftm-inbox/src/lib/components/ui/StatusBadge.svelte +67 -67
  150. package/ftm-inbox/src/lib/components/ui/StreamDrawer.svelte +149 -149
  151. package/ftm-inbox/src/lib/components/ui/ThemeToggle.svelte +80 -80
  152. package/ftm-inbox/src/lib/theme.ts +47 -47
  153. package/ftm-inbox/src/routes/+layout.svelte +76 -76
  154. package/ftm-inbox/src/routes/+page.svelte +401 -401
  155. package/ftm-inbox/svelte.config.js +12 -12
  156. package/ftm-inbox/tailwind.config.ts +63 -63
  157. package/ftm-inbox/tsconfig.json +13 -13
  158. package/ftm-inbox/vite.config.ts +6 -6
  159. package/ftm-intent/SKILL.md +241 -241
  160. package/ftm-intent.yml +2 -2
  161. package/ftm-manifest.json +3794 -3794
  162. package/ftm-map/SKILL.md +291 -291
  163. package/ftm-map/scripts/db.py +712 -712
  164. package/ftm-map/scripts/index.py +415 -415
  165. package/ftm-map/scripts/parser.py +224 -224
  166. package/ftm-map/scripts/queries/go-tags.scm +20 -20
  167. package/ftm-map/scripts/queries/javascript-tags.scm +35 -35
  168. package/ftm-map/scripts/queries/python-tags.scm +31 -31
  169. package/ftm-map/scripts/queries/ruby-tags.scm +19 -19
  170. package/ftm-map/scripts/queries/rust-tags.scm +37 -37
  171. package/ftm-map/scripts/queries/typescript-tags.scm +41 -41
  172. package/ftm-map/scripts/query.py +301 -301
  173. package/ftm-map/scripts/ranker.py +377 -377
  174. package/ftm-map/scripts/requirements.txt +5 -5
  175. package/ftm-map/scripts/setup-hooks.sh +27 -27
  176. package/ftm-map/scripts/setup.sh +56 -56
  177. package/ftm-map/scripts/test_db.py +364 -364
  178. package/ftm-map/scripts/test_parser.py +174 -174
  179. package/ftm-map/scripts/test_query.py +183 -183
  180. package/ftm-map/scripts/test_ranker.py +199 -199
  181. package/ftm-map/scripts/views.py +591 -591
  182. package/ftm-map.yml +2 -2
  183. package/ftm-mind/SKILL.md +201 -1943
  184. package/ftm-mind/evals/promptfoo.yaml +142 -142
  185. package/ftm-mind/references/blackboard-protocol.md +110 -0
  186. package/ftm-mind/references/blackboard-schema.md +328 -328
  187. package/ftm-mind/references/complexity-guide.md +110 -110
  188. package/ftm-mind/references/complexity-sizing.md +138 -0
  189. package/ftm-mind/references/decide-act-protocol.md +172 -0
  190. package/ftm-mind/references/direct-execution.md +51 -0
  191. package/ftm-mind/references/environment-discovery.md +77 -0
  192. package/ftm-mind/references/event-registry.md +319 -319
  193. package/ftm-mind/references/mcp-inventory.md +300 -296
  194. package/ftm-mind/references/ops-routing.md +47 -0
  195. package/ftm-mind/references/orient-protocol.md +234 -0
  196. package/ftm-mind/references/personality.md +40 -0
  197. package/ftm-mind/references/protocols/COMPLEXITY-SIZING.md +72 -72
  198. package/ftm-mind/references/protocols/MCP-HEURISTICS.md +32 -32
  199. package/ftm-mind/references/protocols/PLAN-APPROVAL.md +80 -80
  200. package/ftm-mind/references/reflexion-protocol.md +249 -249
  201. package/ftm-mind/references/routing/SCENARIOS.md +22 -22
  202. package/ftm-mind/references/routing-scenarios.md +35 -35
  203. package/ftm-mind.yml +2 -2
  204. package/ftm-ops.yml +4 -0
  205. package/ftm-pause/SKILL.md +395 -395
  206. package/ftm-pause/references/protocols/SKILL-RESTORE-PROTOCOLS.md +186 -186
  207. package/ftm-pause/references/protocols/VALIDATION.md +80 -80
  208. package/ftm-pause.yml +2 -2
  209. package/ftm-researcher/SKILL.md +275 -275
  210. package/ftm-researcher/evals/agent-diversity.yaml +17 -17
  211. package/ftm-researcher/evals/synthesis-quality.yaml +12 -12
  212. package/ftm-researcher/evals/trigger-accuracy.yaml +39 -39
  213. package/ftm-researcher/references/adaptive-search.md +116 -116
  214. package/ftm-researcher/references/agent-prompts.md +193 -193
  215. package/ftm-researcher/references/council-integration.md +193 -193
  216. package/ftm-researcher/references/output-format.md +203 -203
  217. package/ftm-researcher/references/synthesis-pipeline.md +165 -165
  218. package/ftm-researcher/scripts/score_credibility.py +234 -234
  219. package/ftm-researcher/scripts/validate_research.py +92 -92
  220. package/ftm-researcher.yml +2 -2
  221. package/ftm-resume/SKILL.md +518 -518
  222. package/ftm-resume/references/protocols/VALIDATION.md +172 -172
  223. package/ftm-resume.yml +2 -2
  224. package/ftm-retro/SKILL.md +380 -380
  225. package/ftm-retro/references/protocols/SCORING-RUBRICS.md +89 -89
  226. package/ftm-retro/references/templates/REPORT-FORMAT.md +109 -109
  227. package/ftm-retro.yml +2 -2
  228. package/ftm-routine/SKILL.md +170 -170
  229. package/ftm-routine.yml +4 -4
  230. package/ftm-state/blackboard/capabilities.json +5 -5
  231. package/ftm-state/blackboard/capabilities.schema.json +27 -27
  232. package/ftm-state/blackboard/context.json +37 -23
  233. package/ftm-state/blackboard/experiences/doom-statusline-fix.json +26 -0
  234. package/ftm-state/blackboard/experiences/hackathon-pages-site.json +26 -0
  235. package/ftm-state/blackboard/experiences/hindsight-sso-kickoff.json +42 -0
  236. package/ftm-state/blackboard/experiences/index.json +58 -9
  237. package/ftm-state/blackboard/experiences/learning-ragnarok-api-access.json +23 -0
  238. package/ftm-state/blackboard/experiences/nordlayer-members-auto-assign.json +26 -0
  239. package/ftm-state/blackboard/experiences/saml2aws-stale-session-fix.json +41 -0
  240. package/ftm-state/blackboard/patterns.json +6 -6
  241. package/ftm-state/schemas/context.schema.json +130 -130
  242. package/ftm-state/schemas/experience-index.schema.json +77 -77
  243. package/ftm-state/schemas/experience.schema.json +78 -78
  244. package/ftm-state/schemas/patterns.schema.json +44 -44
  245. package/ftm-upgrade/SKILL.md +194 -194
  246. package/ftm-upgrade/scripts/check-version.sh +76 -76
  247. package/ftm-upgrade/scripts/upgrade.sh +143 -143
  248. package/ftm-upgrade.yml +2 -2
  249. package/ftm-verify.yml +2 -2
  250. package/ftm.yml +2 -2
  251. package/hooks/ftm-auto-log.sh +137 -0
  252. package/hooks/ftm-blackboard-enforcer.sh +93 -93
  253. package/hooks/ftm-discovery-reminder.sh +90 -90
  254. package/hooks/ftm-drafts-gate.sh +61 -61
  255. package/hooks/ftm-event-logger.mjs +107 -107
  256. package/hooks/ftm-install-hooks.sh +240 -0
  257. package/hooks/ftm-learning-capture.sh +117 -0
  258. package/hooks/ftm-map-autodetect.sh +79 -79
  259. package/hooks/ftm-pending-sync-check.sh +22 -22
  260. package/hooks/ftm-plan-gate.sh +92 -92
  261. package/hooks/ftm-post-commit-trigger.sh +57 -57
  262. package/hooks/ftm-post-compaction.sh +138 -0
  263. package/hooks/ftm-pre-compaction.sh +147 -0
  264. package/hooks/ftm-session-end.sh +52 -0
  265. package/hooks/ftm-session-snapshot.sh +213 -0
  266. package/hooks/settings-template.json +81 -81
  267. package/install.sh +363 -363
  268. package/package.json +84 -84
  269. package/uninstall.sh +25 -25
@@ -1,190 +1,190 @@
1
- <script lang="ts">
2
- import { createEventDispatcher } from 'svelte';
3
- import { fly } from 'svelte/transition';
4
- import StatusBadge from './ui/StatusBadge.svelte';
5
- import PillButton from './ui/PillButton.svelte';
6
- import type { UnifiedTask } from '$lib/api';
7
-
8
- export let task: UnifiedTask;
9
- export let selected = false;
10
-
11
- const dispatch = createEventDispatcher<{
12
- select: UnifiedTask;
13
- generatePlan: UnifiedTask;
14
- }>();
15
-
16
- const sourceColors: Record<string, string> = {
17
- jira: '#bbdefb',
18
- freshservice: '#c8e6c9',
19
- slack: '#e1bee7',
20
- gmail: '#ffcdd2'
21
- };
22
-
23
- const sourceTextColors: Record<string, string> = {
24
- jira: '#0d47a1',
25
- freshservice: '#1b5e20',
26
- slack: '#4a148c',
27
- gmail: '#b71c1c'
28
- };
29
-
30
- function relativeTime(dateStr: string | null): string {
31
- if (!dateStr) return '';
32
- const now = Date.now();
33
- const then = new Date(dateStr).getTime();
34
- if (isNaN(then)) return '';
35
- const diff = Math.floor((now - then) / 1000);
36
- if (diff < 60) return 'just now';
37
- if (diff < 3600) return `${Math.floor(diff / 60)}m ago`;
38
- if (diff < 86400) return `${Math.floor(diff / 3600)}h ago`;
39
- return `${Math.floor(diff / 86400)}d ago`;
40
- }
41
-
42
- function mapStatus(s: string): 'pending' | 'planning' | 'approved' | 'executing' | 'complete' | 'failed' {
43
- const map: Record<string, 'pending' | 'planning' | 'approved' | 'executing' | 'complete' | 'failed'> = {
44
- open: 'pending',
45
- pending: 'planning',
46
- resolved: 'complete',
47
- closed: 'complete',
48
- };
49
- return map[s] ?? 'pending';
50
- }
51
-
52
- const priorityIndicator: Record<string, string> = {
53
- low: '○',
54
- medium: '◑',
55
- high: '●',
56
- urgent: '◉'
57
- };
58
- </script>
59
-
60
- <button
61
- class="task-card"
62
- class:selected
63
- on:click={() => dispatch('select', task)}
64
- transition:fly={{ x: -20, duration: 200 }}
65
- >
66
- <div class="card-top">
67
- <span
68
- class="source-badge"
69
- style="background: {sourceColors[task.source] ?? '#e0e0e0'}; color: {sourceTextColors[task.source] ?? '#333'}"
70
- >
71
- {task.source}
72
- </span>
73
- <span class="card-time">{relativeTime(task.ingested_at ?? task.created_at)}</span>
74
- </div>
75
-
76
- <p class="card-title">{task.title}</p>
77
-
78
- <div class="card-meta">
79
- {#if task.priority}
80
- <span class="priority" title={task.priority}>
81
- {priorityIndicator[task.priority] ?? '○'} {task.priority}
82
- </span>
83
- {/if}
84
- {#if task.assignee}
85
- <span class="assignee" title="Assignee: {task.assignee}">
86
- {task.assignee}
87
- </span>
88
- {/if}
89
- </div>
90
-
91
- <div class="card-bottom">
92
- <StatusBadge status={mapStatus(task.status)} />
93
- <PillButton
94
- variant="primary"
95
- size="sm"
96
- on:click={(e) => { e.stopPropagation(); dispatch('generatePlan', task); }}
97
- >
98
-
99
- Generate Plan
100
- </PillButton>
101
- </div>
102
- </button>
103
-
104
- <style>
105
- .task-card {
106
- display: block;
107
- width: 100%;
108
- text-align: left;
109
- background: var(--bg-card);
110
- border: 2px solid var(--border-card);
111
- border-radius: 12px;
112
- padding: 0.65rem 0.75rem;
113
- cursor: pointer;
114
- transition:
115
- border-color 0.15s ease,
116
- box-shadow 0.15s ease,
117
- transform 0.15s cubic-bezier(0.68, -0.55, 0.265, 1.55);
118
- font-family: 'Nunito', sans-serif;
119
- }
120
-
121
- .task-card:hover {
122
- border-color: var(--accent-primary);
123
- transform: translateX(2px);
124
- }
125
-
126
- .task-card.selected {
127
- border-color: var(--accent-primary);
128
- box-shadow: var(--shadow-card-hover);
129
- background: var(--bg-secondary);
130
- }
131
-
132
- .card-top {
133
- display: flex;
134
- align-items: center;
135
- justify-content: space-between;
136
- margin-bottom: 0.3rem;
137
- }
138
-
139
- .source-badge {
140
- font-size: 0.65rem;
141
- font-weight: 800;
142
- text-transform: uppercase;
143
- letter-spacing: 0.06em;
144
- padding: 2px 8px;
145
- border-radius: 9999px;
146
- }
147
-
148
- .card-time {
149
- font-size: 0.68rem;
150
- color: var(--text-muted);
151
- }
152
-
153
- .card-title {
154
- font-size: 0.8rem;
155
- font-weight: 700;
156
- color: var(--text-primary);
157
- margin: 0 0 0.3rem;
158
- line-height: 1.35;
159
- display: -webkit-box;
160
- -webkit-line-clamp: 2;
161
- -webkit-box-orient: vertical;
162
- overflow: hidden;
163
- }
164
-
165
- .card-meta {
166
- display: flex;
167
- align-items: center;
168
- gap: 0.5rem;
169
- margin-bottom: 0.4rem;
170
- font-size: 0.68rem;
171
- color: var(--text-muted);
172
- }
173
-
174
- .priority {
175
- font-weight: 700;
176
- }
177
-
178
- .assignee {
179
- max-width: 120px;
180
- overflow: hidden;
181
- text-overflow: ellipsis;
182
- white-space: nowrap;
183
- }
184
-
185
- .card-bottom {
186
- display: flex;
187
- align-items: center;
188
- justify-content: space-between;
189
- }
190
- </style>
1
+ <script lang="ts">
2
+ import { createEventDispatcher } from 'svelte';
3
+ import { fly } from 'svelte/transition';
4
+ import StatusBadge from './ui/StatusBadge.svelte';
5
+ import PillButton from './ui/PillButton.svelte';
6
+ import type { UnifiedTask } from '$lib/api';
7
+
8
+ export let task: UnifiedTask;
9
+ export let selected = false;
10
+
11
+ const dispatch = createEventDispatcher<{
12
+ select: UnifiedTask;
13
+ generatePlan: UnifiedTask;
14
+ }>();
15
+
16
+ const sourceColors: Record<string, string> = {
17
+ jira: '#bbdefb',
18
+ freshservice: '#c8e6c9',
19
+ slack: '#e1bee7',
20
+ gmail: '#ffcdd2'
21
+ };
22
+
23
+ const sourceTextColors: Record<string, string> = {
24
+ jira: '#0d47a1',
25
+ freshservice: '#1b5e20',
26
+ slack: '#4a148c',
27
+ gmail: '#b71c1c'
28
+ };
29
+
30
+ function relativeTime(dateStr: string | null): string {
31
+ if (!dateStr) return '';
32
+ const now = Date.now();
33
+ const then = new Date(dateStr).getTime();
34
+ if (isNaN(then)) return '';
35
+ const diff = Math.floor((now - then) / 1000);
36
+ if (diff < 60) return 'just now';
37
+ if (diff < 3600) return `${Math.floor(diff / 60)}m ago`;
38
+ if (diff < 86400) return `${Math.floor(diff / 3600)}h ago`;
39
+ return `${Math.floor(diff / 86400)}d ago`;
40
+ }
41
+
42
+ function mapStatus(s: string): 'pending' | 'planning' | 'approved' | 'executing' | 'complete' | 'failed' {
43
+ const map: Record<string, 'pending' | 'planning' | 'approved' | 'executing' | 'complete' | 'failed'> = {
44
+ open: 'pending',
45
+ pending: 'planning',
46
+ resolved: 'complete',
47
+ closed: 'complete',
48
+ };
49
+ return map[s] ?? 'pending';
50
+ }
51
+
52
+ const priorityIndicator: Record<string, string> = {
53
+ low: '○',
54
+ medium: '◑',
55
+ high: '●',
56
+ urgent: '◉'
57
+ };
58
+ </script>
59
+
60
+ <button
61
+ class="task-card"
62
+ class:selected
63
+ on:click={() => dispatch('select', task)}
64
+ transition:fly={{ x: -20, duration: 200 }}
65
+ >
66
+ <div class="card-top">
67
+ <span
68
+ class="source-badge"
69
+ style="background: {sourceColors[task.source] ?? '#e0e0e0'}; color: {sourceTextColors[task.source] ?? '#333'}"
70
+ >
71
+ {task.source}
72
+ </span>
73
+ <span class="card-time">{relativeTime(task.ingested_at ?? task.created_at)}</span>
74
+ </div>
75
+
76
+ <p class="card-title">{task.title}</p>
77
+
78
+ <div class="card-meta">
79
+ {#if task.priority}
80
+ <span class="priority" title={task.priority}>
81
+ {priorityIndicator[task.priority] ?? '○'} {task.priority}
82
+ </span>
83
+ {/if}
84
+ {#if task.assignee}
85
+ <span class="assignee" title="Assignee: {task.assignee}">
86
+ {task.assignee}
87
+ </span>
88
+ {/if}
89
+ </div>
90
+
91
+ <div class="card-bottom">
92
+ <StatusBadge status={mapStatus(task.status)} />
93
+ <PillButton
94
+ variant="primary"
95
+ size="sm"
96
+ on:click={(e) => { e.stopPropagation(); dispatch('generatePlan', task); }}
97
+ >
98
+
99
+ Generate Plan
100
+ </PillButton>
101
+ </div>
102
+ </button>
103
+
104
+ <style>
105
+ .task-card {
106
+ display: block;
107
+ width: 100%;
108
+ text-align: left;
109
+ background: var(--bg-card);
110
+ border: 2px solid var(--border-card);
111
+ border-radius: 12px;
112
+ padding: 0.65rem 0.75rem;
113
+ cursor: pointer;
114
+ transition:
115
+ border-color 0.15s ease,
116
+ box-shadow 0.15s ease,
117
+ transform 0.15s cubic-bezier(0.68, -0.55, 0.265, 1.55);
118
+ font-family: 'Nunito', sans-serif;
119
+ }
120
+
121
+ .task-card:hover {
122
+ border-color: var(--accent-primary);
123
+ transform: translateX(2px);
124
+ }
125
+
126
+ .task-card.selected {
127
+ border-color: var(--accent-primary);
128
+ box-shadow: var(--shadow-card-hover);
129
+ background: var(--bg-secondary);
130
+ }
131
+
132
+ .card-top {
133
+ display: flex;
134
+ align-items: center;
135
+ justify-content: space-between;
136
+ margin-bottom: 0.3rem;
137
+ }
138
+
139
+ .source-badge {
140
+ font-size: 0.65rem;
141
+ font-weight: 800;
142
+ text-transform: uppercase;
143
+ letter-spacing: 0.06em;
144
+ padding: 2px 8px;
145
+ border-radius: 9999px;
146
+ }
147
+
148
+ .card-time {
149
+ font-size: 0.68rem;
150
+ color: var(--text-muted);
151
+ }
152
+
153
+ .card-title {
154
+ font-size: 0.8rem;
155
+ font-weight: 700;
156
+ color: var(--text-primary);
157
+ margin: 0 0 0.3rem;
158
+ line-height: 1.35;
159
+ display: -webkit-box;
160
+ -webkit-line-clamp: 2;
161
+ -webkit-box-orient: vertical;
162
+ overflow: hidden;
163
+ }
164
+
165
+ .card-meta {
166
+ display: flex;
167
+ align-items: center;
168
+ gap: 0.5rem;
169
+ margin-bottom: 0.4rem;
170
+ font-size: 0.68rem;
171
+ color: var(--text-muted);
172
+ }
173
+
174
+ .priority {
175
+ font-weight: 700;
176
+ }
177
+
178
+ .assignee {
179
+ max-width: 120px;
180
+ overflow: hidden;
181
+ text-overflow: ellipsis;
182
+ white-space: nowrap;
183
+ }
184
+
185
+ .card-bottom {
186
+ display: flex;
187
+ align-items: center;
188
+ justify-content: space-between;
189
+ }
190
+ </style>
@@ -1,63 +1,63 @@
1
- <script lang="ts">
2
- export let emoji = '🌱';
3
- export let title = 'Nothing here yet';
4
- export let message = 'Items will appear here when they arrive.';
5
- </script>
6
-
7
- <div class="empty-state">
8
- <div class="empty-emoji" aria-hidden="true">{emoji}</div>
9
- <p class="empty-title">{title}</p>
10
- <p class="empty-message">{message}</p>
11
- {#if $$slots.action}
12
- <div class="empty-action">
13
- <slot name="action" />
14
- </div>
15
- {/if}
16
- </div>
17
-
18
- <style>
19
- .empty-state {
20
- display: flex;
21
- flex-direction: column;
22
- align-items: center;
23
- justify-content: center;
24
- gap: 0.5rem;
25
- padding: 2.5rem 1rem;
26
- text-align: center;
27
- color: var(--text-muted);
28
- min-height: 120px;
29
- }
30
-
31
- .empty-emoji {
32
- font-size: 2.5rem;
33
- line-height: 1;
34
- margin-bottom: 0.25rem;
35
- filter: saturate(0.7) opacity(0.8);
36
- animation: gentle-float 3s ease-in-out infinite;
37
- }
38
-
39
- .empty-title {
40
- font-family: 'Nunito', sans-serif;
41
- font-weight: 700;
42
- font-size: 0.95rem;
43
- color: var(--text-secondary);
44
- margin: 0;
45
- }
46
-
47
- .empty-message {
48
- font-size: 0.8rem;
49
- color: var(--text-muted);
50
- margin: 0;
51
- max-width: 200px;
52
- line-height: 1.5;
53
- }
54
-
55
- .empty-action {
56
- margin-top: 0.75rem;
57
- }
58
-
59
- @keyframes gentle-float {
60
- 0%, 100% { transform: translateY(0px); }
61
- 50% { transform: translateY(-5px); }
62
- }
63
- </style>
1
+ <script lang="ts">
2
+ export let emoji = '🌱';
3
+ export let title = 'Nothing here yet';
4
+ export let message = 'Items will appear here when they arrive.';
5
+ </script>
6
+
7
+ <div class="empty-state">
8
+ <div class="empty-emoji" aria-hidden="true">{emoji}</div>
9
+ <p class="empty-title">{title}</p>
10
+ <p class="empty-message">{message}</p>
11
+ {#if $$slots.action}
12
+ <div class="empty-action">
13
+ <slot name="action" />
14
+ </div>
15
+ {/if}
16
+ </div>
17
+
18
+ <style>
19
+ .empty-state {
20
+ display: flex;
21
+ flex-direction: column;
22
+ align-items: center;
23
+ justify-content: center;
24
+ gap: 0.5rem;
25
+ padding: 2.5rem 1rem;
26
+ text-align: center;
27
+ color: var(--text-muted);
28
+ min-height: 120px;
29
+ }
30
+
31
+ .empty-emoji {
32
+ font-size: 2.5rem;
33
+ line-height: 1;
34
+ margin-bottom: 0.25rem;
35
+ filter: saturate(0.7) opacity(0.8);
36
+ animation: gentle-float 3s ease-in-out infinite;
37
+ }
38
+
39
+ .empty-title {
40
+ font-family: 'Nunito', sans-serif;
41
+ font-weight: 700;
42
+ font-size: 0.95rem;
43
+ color: var(--text-secondary);
44
+ margin: 0;
45
+ }
46
+
47
+ .empty-message {
48
+ font-size: 0.8rem;
49
+ color: var(--text-muted);
50
+ margin: 0;
51
+ max-width: 200px;
52
+ line-height: 1.5;
53
+ }
54
+
55
+ .empty-action {
56
+ margin-top: 0.75rem;
57
+ }
58
+
59
+ @keyframes gentle-float {
60
+ 0%, 100% { transform: translateY(0px); }
61
+ 50% { transform: translateY(-5px); }
62
+ }
63
+ </style>
@@ -1,86 +1,86 @@
1
- <script lang="ts">
2
- export let accent: 'green' | 'yellow' | 'blue' | 'coral' | 'teal' | 'orange' = 'green';
3
- export let hoverable = false;
4
- export let compact = false;
5
-
6
- const accentColors: Record<typeof accent, string> = {
7
- green: '#4caf50',
8
- yellow: '#ffd54f',
9
- blue: '#42a5f5',
10
- coral: '#ff7043',
11
- teal: '#26a69a',
12
- orange: '#ff9800'
13
- };
14
-
15
- $: borderColor = accentColors[accent];
16
- </script>
17
-
18
- <div
19
- class="kawaii-card"
20
- class:hoverable
21
- class:compact
22
- style="--card-accent: {borderColor}"
23
- >
24
- {#if $$slots.header}
25
- <div class="card-header">
26
- <slot name="header" />
27
- </div>
28
- {/if}
29
-
30
- <div class="card-body">
31
- <slot />
32
- </div>
33
-
34
- {#if $$slots.footer}
35
- <div class="card-footer">
36
- <slot name="footer" />
37
- </div>
38
- {/if}
39
- </div>
40
-
41
- <style>
42
- .kawaii-card {
43
- background: var(--bg-card);
44
- border: 2px solid var(--border-card);
45
- border-left: 4px solid var(--card-accent);
46
- border-radius: 16px;
47
- box-shadow: var(--shadow-card);
48
- transition:
49
- box-shadow 0.2s ease,
50
- transform 0.2s cubic-bezier(0.68, -0.55, 0.265, 1.55),
51
- border-color 0.2s ease;
52
- overflow: hidden;
53
- }
54
-
55
- .kawaii-card.hoverable:hover {
56
- box-shadow: var(--shadow-card-hover);
57
- transform: translateY(-2px);
58
- border-color: var(--card-accent);
59
- }
60
-
61
- .kawaii-card.hoverable:active {
62
- transform: translateY(0);
63
- }
64
-
65
- .card-header {
66
- padding: 12px 16px 8px;
67
- border-bottom: 1px solid var(--border-card);
68
- }
69
-
70
- .card-body {
71
- padding: 16px;
72
- }
73
-
74
- .compact .card-body {
75
- padding: 10px 14px;
76
- }
77
-
78
- .compact .card-header {
79
- padding: 8px 14px 6px;
80
- }
81
-
82
- .card-footer {
83
- padding: 8px 16px 12px;
84
- border-top: 1px solid var(--border-card);
85
- }
86
- </style>
1
+ <script lang="ts">
2
+ export let accent: 'green' | 'yellow' | 'blue' | 'coral' | 'teal' | 'orange' = 'green';
3
+ export let hoverable = false;
4
+ export let compact = false;
5
+
6
+ const accentColors: Record<typeof accent, string> = {
7
+ green: '#4caf50',
8
+ yellow: '#ffd54f',
9
+ blue: '#42a5f5',
10
+ coral: '#ff7043',
11
+ teal: '#26a69a',
12
+ orange: '#ff9800'
13
+ };
14
+
15
+ $: borderColor = accentColors[accent];
16
+ </script>
17
+
18
+ <div
19
+ class="kawaii-card"
20
+ class:hoverable
21
+ class:compact
22
+ style="--card-accent: {borderColor}"
23
+ >
24
+ {#if $$slots.header}
25
+ <div class="card-header">
26
+ <slot name="header" />
27
+ </div>
28
+ {/if}
29
+
30
+ <div class="card-body">
31
+ <slot />
32
+ </div>
33
+
34
+ {#if $$slots.footer}
35
+ <div class="card-footer">
36
+ <slot name="footer" />
37
+ </div>
38
+ {/if}
39
+ </div>
40
+
41
+ <style>
42
+ .kawaii-card {
43
+ background: var(--bg-card);
44
+ border: 2px solid var(--border-card);
45
+ border-left: 4px solid var(--card-accent);
46
+ border-radius: 16px;
47
+ box-shadow: var(--shadow-card);
48
+ transition:
49
+ box-shadow 0.2s ease,
50
+ transform 0.2s cubic-bezier(0.68, -0.55, 0.265, 1.55),
51
+ border-color 0.2s ease;
52
+ overflow: hidden;
53
+ }
54
+
55
+ .kawaii-card.hoverable:hover {
56
+ box-shadow: var(--shadow-card-hover);
57
+ transform: translateY(-2px);
58
+ border-color: var(--card-accent);
59
+ }
60
+
61
+ .kawaii-card.hoverable:active {
62
+ transform: translateY(0);
63
+ }
64
+
65
+ .card-header {
66
+ padding: 12px 16px 8px;
67
+ border-bottom: 1px solid var(--border-card);
68
+ }
69
+
70
+ .card-body {
71
+ padding: 16px;
72
+ }
73
+
74
+ .compact .card-body {
75
+ padding: 10px 14px;
76
+ }
77
+
78
+ .compact .card-header {
79
+ padding: 8px 14px 6px;
80
+ }
81
+
82
+ .card-footer {
83
+ padding: 8px 16px 12px;
84
+ border-top: 1px solid var(--border-card);
85
+ }
86
+ </style>