feed-the-machine 1.5.0 → 1.6.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 (224) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +170 -170
  3. package/bin/generate-manifest.mjs +463 -463
  4. package/bin/install.mjs +491 -491
  5. package/docs/HOOKS.md +243 -243
  6. package/docs/INBOX.md +233 -233
  7. package/ftm/SKILL.md +122 -122
  8. package/ftm-audit/SKILL.md +623 -541
  9. package/ftm-audit/references/protocols/PROJECT-PATTERNS.md +91 -91
  10. package/ftm-audit/references/protocols/RUNTIME-WIRING.md +66 -66
  11. package/ftm-audit/references/protocols/WIRING-CONTRACTS.md +135 -135
  12. package/ftm-audit/references/strategies/AUTO-FIX-STRATEGIES.md +69 -69
  13. package/ftm-audit/references/templates/REPORT-FORMAT.md +96 -96
  14. package/ftm-audit/scripts/run-knip.sh +23 -23
  15. package/ftm-audit.yml +2 -2
  16. package/ftm-brainstorm/SKILL.md +498 -498
  17. package/ftm-brainstorm/evals/evals.json +100 -100
  18. package/ftm-brainstorm/evals/promptfoo.yaml +109 -109
  19. package/ftm-brainstorm/references/agent-prompts.md +224 -224
  20. package/ftm-brainstorm/references/plan-template.md +121 -121
  21. package/ftm-brainstorm.yml +2 -2
  22. package/ftm-browse/SKILL.md +454 -454
  23. package/ftm-browse/daemon/browser-manager.ts +206 -206
  24. package/ftm-browse/daemon/bun.lock +30 -30
  25. package/ftm-browse/daemon/cli.ts +347 -347
  26. package/ftm-browse/daemon/commands.ts +410 -410
  27. package/ftm-browse/daemon/main.ts +357 -357
  28. package/ftm-browse/daemon/package.json +17 -17
  29. package/ftm-browse/daemon/server.ts +189 -189
  30. package/ftm-browse/daemon/snapshot.ts +519 -519
  31. package/ftm-browse/daemon/tsconfig.json +22 -22
  32. package/ftm-browse.yml +4 -4
  33. package/ftm-capture/SKILL.md +370 -370
  34. package/ftm-capture.yml +4 -4
  35. package/ftm-codex-gate/SKILL.md +361 -361
  36. package/ftm-codex-gate.yml +2 -2
  37. package/ftm-config/SKILL.md +345 -345
  38. package/ftm-config.default.yml +82 -80
  39. package/ftm-config.yml +2 -2
  40. package/ftm-council/SKILL.md +416 -416
  41. package/ftm-council/references/prompts/CLAUDE-INVESTIGATION.md +60 -60
  42. package/ftm-council/references/prompts/CODEX-INVESTIGATION.md +58 -58
  43. package/ftm-council/references/prompts/GEMINI-INVESTIGATION.md +58 -58
  44. package/ftm-council/references/prompts/REBUTTAL-TEMPLATE.md +57 -57
  45. package/ftm-council/references/protocols/PREREQUISITES.md +47 -47
  46. package/ftm-council/references/protocols/STEP-0-FRAMING.md +46 -46
  47. package/ftm-council.yml +2 -2
  48. package/ftm-dashboard/SKILL.md +163 -163
  49. package/ftm-dashboard.yml +4 -4
  50. package/ftm-debug/SKILL.md +1037 -1037
  51. package/ftm-debug/references/phases/PHASE-0-INTAKE.md +58 -58
  52. package/ftm-debug/references/phases/PHASE-1-TRIAGE.md +46 -46
  53. package/ftm-debug/references/phases/PHASE-2-WAR-ROOM-AGENTS.md +279 -279
  54. package/ftm-debug/references/phases/PHASE-3-TO-6-EXECUTION.md +436 -436
  55. package/ftm-debug/references/protocols/BLACKBOARD.md +86 -86
  56. package/ftm-debug/references/protocols/EDGE-CASES.md +103 -103
  57. package/ftm-debug.yml +2 -2
  58. package/ftm-diagram/SKILL.md +277 -277
  59. package/ftm-diagram.yml +2 -2
  60. package/ftm-executor/SKILL.md +777 -767
  61. package/ftm-executor/references/STYLE-TEMPLATE.md +73 -73
  62. package/ftm-executor/references/phases/PHASE-0-VERIFICATION.md +62 -62
  63. package/ftm-executor/references/phases/PHASE-2-AGENT-ASSEMBLY.md +34 -34
  64. package/ftm-executor/references/phases/PHASE-3-WORKTREES.md +38 -38
  65. package/ftm-executor/references/phases/PHASE-4-5-AUDIT.md +72 -72
  66. package/ftm-executor/references/phases/PHASE-4-DISPATCH.md +66 -66
  67. package/ftm-executor/references/phases/PHASE-5-5-CODEX-GATE.md +73 -73
  68. package/ftm-executor/references/protocols/DOCUMENTATION-BOOTSTRAP.md +36 -36
  69. package/ftm-executor/references/protocols/MODEL-PROFILE.md +59 -44
  70. package/ftm-executor/references/protocols/PROGRESS-TRACKING.md +66 -66
  71. package/ftm-executor/runtime/ftm-runtime.mjs +252 -252
  72. package/ftm-executor/runtime/package.json +8 -8
  73. package/ftm-executor.yml +2 -2
  74. package/ftm-git/SKILL.md +441 -441
  75. package/ftm-git/evals/evals.json +26 -26
  76. package/ftm-git/evals/promptfoo.yaml +75 -75
  77. package/ftm-git/hooks/post-commit-experience.sh +92 -92
  78. package/ftm-git/references/patterns/SECRET-PATTERNS.md +104 -104
  79. package/ftm-git/references/protocols/REMEDIATION.md +139 -139
  80. package/ftm-git/scripts/pre-commit-secrets.sh +110 -110
  81. package/ftm-git.yml +2 -2
  82. package/ftm-inbox/backend/adapters/_retry.py +64 -64
  83. package/ftm-inbox/backend/adapters/base.py +230 -230
  84. package/ftm-inbox/backend/adapters/freshservice.py +104 -104
  85. package/ftm-inbox/backend/adapters/gmail.py +125 -125
  86. package/ftm-inbox/backend/adapters/jira.py +136 -136
  87. package/ftm-inbox/backend/adapters/registry.py +192 -192
  88. package/ftm-inbox/backend/adapters/slack.py +110 -110
  89. package/ftm-inbox/backend/db/connection.py +54 -54
  90. package/ftm-inbox/backend/db/schema.py +78 -78
  91. package/ftm-inbox/backend/executor/__init__.py +7 -7
  92. package/ftm-inbox/backend/executor/engine.py +149 -149
  93. package/ftm-inbox/backend/executor/step_runner.py +98 -98
  94. package/ftm-inbox/backend/main.py +103 -103
  95. package/ftm-inbox/backend/models/__init__.py +1 -1
  96. package/ftm-inbox/backend/models/unified_task.py +36 -36
  97. package/ftm-inbox/backend/planner/__init__.py +6 -6
  98. package/ftm-inbox/backend/planner/generator.py +127 -127
  99. package/ftm-inbox/backend/planner/schema.py +34 -34
  100. package/ftm-inbox/backend/requirements.txt +5 -5
  101. package/ftm-inbox/backend/routes/execute.py +186 -186
  102. package/ftm-inbox/backend/routes/health.py +52 -52
  103. package/ftm-inbox/backend/routes/inbox.py +68 -68
  104. package/ftm-inbox/backend/routes/plan.py +271 -271
  105. package/ftm-inbox/bin/launchagent.mjs +91 -91
  106. package/ftm-inbox/bin/setup.mjs +188 -188
  107. package/ftm-inbox/bin/start.sh +10 -10
  108. package/ftm-inbox/bin/status.sh +17 -17
  109. package/ftm-inbox/bin/stop.sh +8 -8
  110. package/ftm-inbox/config.example.yml +55 -55
  111. package/ftm-inbox/package-lock.json +2898 -2898
  112. package/ftm-inbox/package.json +26 -26
  113. package/ftm-inbox/postcss.config.js +6 -6
  114. package/ftm-inbox/src/app.css +199 -199
  115. package/ftm-inbox/src/app.html +18 -18
  116. package/ftm-inbox/src/lib/api.ts +166 -166
  117. package/ftm-inbox/src/lib/components/ExecutionLog.svelte +81 -81
  118. package/ftm-inbox/src/lib/components/InboxFeed.svelte +143 -143
  119. package/ftm-inbox/src/lib/components/PlanStep.svelte +271 -271
  120. package/ftm-inbox/src/lib/components/PlanView.svelte +206 -206
  121. package/ftm-inbox/src/lib/components/StreamPanel.svelte +99 -99
  122. package/ftm-inbox/src/lib/components/TaskCard.svelte +190 -190
  123. package/ftm-inbox/src/lib/components/ui/EmptyState.svelte +63 -63
  124. package/ftm-inbox/src/lib/components/ui/KawaiiCard.svelte +86 -86
  125. package/ftm-inbox/src/lib/components/ui/PillButton.svelte +106 -106
  126. package/ftm-inbox/src/lib/components/ui/StatusBadge.svelte +67 -67
  127. package/ftm-inbox/src/lib/components/ui/StreamDrawer.svelte +149 -149
  128. package/ftm-inbox/src/lib/components/ui/ThemeToggle.svelte +80 -80
  129. package/ftm-inbox/src/lib/theme.ts +47 -47
  130. package/ftm-inbox/src/routes/+layout.svelte +76 -76
  131. package/ftm-inbox/src/routes/+page.svelte +401 -401
  132. package/ftm-inbox/svelte.config.js +12 -12
  133. package/ftm-inbox/tailwind.config.ts +63 -63
  134. package/ftm-inbox/tsconfig.json +13 -13
  135. package/ftm-inbox/vite.config.ts +6 -6
  136. package/ftm-intent/SKILL.md +241 -241
  137. package/ftm-intent.yml +2 -2
  138. package/ftm-manifest.json +3794 -3794
  139. package/ftm-map/SKILL.md +291 -291
  140. package/ftm-map/scripts/db.py +712 -712
  141. package/ftm-map/scripts/index.py +415 -415
  142. package/ftm-map/scripts/parser.py +224 -224
  143. package/ftm-map/scripts/queries/go-tags.scm +20 -20
  144. package/ftm-map/scripts/queries/javascript-tags.scm +35 -35
  145. package/ftm-map/scripts/queries/python-tags.scm +31 -31
  146. package/ftm-map/scripts/queries/ruby-tags.scm +19 -19
  147. package/ftm-map/scripts/queries/rust-tags.scm +37 -37
  148. package/ftm-map/scripts/queries/typescript-tags.scm +41 -41
  149. package/ftm-map/scripts/query.py +301 -301
  150. package/ftm-map/scripts/ranker.py +377 -377
  151. package/ftm-map/scripts/requirements.txt +5 -5
  152. package/ftm-map/scripts/setup-hooks.sh +27 -27
  153. package/ftm-map/scripts/setup.sh +56 -56
  154. package/ftm-map/scripts/test_db.py +364 -364
  155. package/ftm-map/scripts/test_parser.py +174 -174
  156. package/ftm-map/scripts/test_query.py +183 -183
  157. package/ftm-map/scripts/test_ranker.py +199 -199
  158. package/ftm-map/scripts/views.py +591 -591
  159. package/ftm-map.yml +2 -2
  160. package/ftm-mind/SKILL.md +1943 -1943
  161. package/ftm-mind/evals/promptfoo.yaml +142 -142
  162. package/ftm-mind/references/blackboard-schema.md +328 -328
  163. package/ftm-mind/references/complexity-guide.md +110 -110
  164. package/ftm-mind/references/event-registry.md +319 -319
  165. package/ftm-mind/references/mcp-inventory.md +296 -296
  166. package/ftm-mind/references/protocols/COMPLEXITY-SIZING.md +72 -72
  167. package/ftm-mind/references/protocols/MCP-HEURISTICS.md +32 -32
  168. package/ftm-mind/references/protocols/PLAN-APPROVAL.md +80 -80
  169. package/ftm-mind/references/reflexion-protocol.md +249 -249
  170. package/ftm-mind/references/routing/SCENARIOS.md +22 -22
  171. package/ftm-mind/references/routing-scenarios.md +35 -35
  172. package/ftm-mind.yml +2 -2
  173. package/ftm-pause/SKILL.md +395 -395
  174. package/ftm-pause/references/protocols/SKILL-RESTORE-PROTOCOLS.md +186 -186
  175. package/ftm-pause/references/protocols/VALIDATION.md +80 -80
  176. package/ftm-pause.yml +2 -2
  177. package/ftm-researcher/SKILL.md +275 -275
  178. package/ftm-researcher/evals/agent-diversity.yaml +17 -17
  179. package/ftm-researcher/evals/synthesis-quality.yaml +12 -12
  180. package/ftm-researcher/evals/trigger-accuracy.yaml +39 -39
  181. package/ftm-researcher/references/adaptive-search.md +116 -116
  182. package/ftm-researcher/references/agent-prompts.md +193 -193
  183. package/ftm-researcher/references/council-integration.md +193 -193
  184. package/ftm-researcher/references/output-format.md +203 -203
  185. package/ftm-researcher/references/synthesis-pipeline.md +165 -165
  186. package/ftm-researcher/scripts/score_credibility.py +234 -234
  187. package/ftm-researcher/scripts/validate_research.py +92 -92
  188. package/ftm-researcher.yml +2 -2
  189. package/ftm-resume/SKILL.md +518 -518
  190. package/ftm-resume/references/protocols/VALIDATION.md +172 -172
  191. package/ftm-resume.yml +2 -2
  192. package/ftm-retro/SKILL.md +380 -380
  193. package/ftm-retro/references/protocols/SCORING-RUBRICS.md +89 -89
  194. package/ftm-retro/references/templates/REPORT-FORMAT.md +109 -109
  195. package/ftm-retro.yml +2 -2
  196. package/ftm-routine/SKILL.md +170 -170
  197. package/ftm-routine.yml +4 -4
  198. package/ftm-state/blackboard/capabilities.json +5 -5
  199. package/ftm-state/blackboard/capabilities.schema.json +27 -27
  200. package/ftm-state/blackboard/context.json +23 -23
  201. package/ftm-state/blackboard/experiences/index.json +9 -9
  202. package/ftm-state/blackboard/patterns.json +6 -6
  203. package/ftm-state/schemas/context.schema.json +130 -130
  204. package/ftm-state/schemas/experience-index.schema.json +77 -77
  205. package/ftm-state/schemas/experience.schema.json +78 -78
  206. package/ftm-state/schemas/patterns.schema.json +44 -44
  207. package/ftm-upgrade/SKILL.md +194 -194
  208. package/ftm-upgrade/scripts/check-version.sh +76 -76
  209. package/ftm-upgrade/scripts/upgrade.sh +143 -143
  210. package/ftm-upgrade.yml +2 -2
  211. package/ftm-verify.yml +2 -2
  212. package/ftm.yml +2 -2
  213. package/hooks/ftm-blackboard-enforcer.sh +93 -93
  214. package/hooks/ftm-discovery-reminder.sh +90 -90
  215. package/hooks/ftm-drafts-gate.sh +61 -61
  216. package/hooks/ftm-event-logger.mjs +107 -107
  217. package/hooks/ftm-map-autodetect.sh +79 -79
  218. package/hooks/ftm-pending-sync-check.sh +22 -22
  219. package/hooks/ftm-plan-gate.sh +92 -92
  220. package/hooks/ftm-post-commit-trigger.sh +57 -57
  221. package/hooks/settings-template.json +81 -81
  222. package/install.sh +363 -363
  223. package/package.json +84 -84
  224. package/uninstall.sh +25 -25
@@ -1,271 +1,271 @@
1
- <script lang="ts">
2
- import { createEventDispatcher } from 'svelte';
3
- import PillButton from '$lib/components/ui/PillButton.svelte';
4
- import type { PlanStep as PlanStepType } from '$lib/api';
5
-
6
- export let step: PlanStepType;
7
- export let index: number;
8
-
9
- const dispatch = createEventDispatcher<{
10
- approve: { stepId: number };
11
- reject: { stepId: number };
12
- }>();
13
-
14
- const riskColor: Record<string, string> = {
15
- low: 'risk-low',
16
- medium: 'risk-medium',
17
- high: 'risk-high'
18
- };
19
-
20
- const riskEmoji: Record<string, string> = {
21
- low: '🟢',
22
- medium: '🟡',
23
- high: '🔴'
24
- };
25
-
26
- const statusEmoji: Record<string, string> = {
27
- pending: '⏳',
28
- approved: '✅',
29
- rejected: '❌',
30
- running: '⚡',
31
- completed: '🎉',
32
- failed: '💥'
33
- };
34
-
35
- $: isPending = step.status === 'pending';
36
- $: isApproved = step.status === 'approved';
37
- $: isCompleted = step.status === 'completed';
38
- $: isFailed = step.status === 'failed';
39
- </script>
40
-
41
- <div
42
- class="plan-step"
43
- class:step-approved={isApproved}
44
- class:step-completed={isCompleted}
45
- class:step-failed={isFailed}
46
- role="listitem"
47
- >
48
- <!-- Step number bubble -->
49
- <div class="step-num" aria-hidden="true">{index}</div>
50
-
51
- <!-- Main content -->
52
- <div class="step-content">
53
- <div class="step-top">
54
- <span class="step-title">{step.title}</span>
55
- <span class="step-status" title="Status: {step.status}">
56
- {statusEmoji[step.status] ?? '⏳'}
57
- </span>
58
- </div>
59
-
60
- <div class="step-meta">
61
- {#if step.target_system}
62
- <span class="meta-badge badge-system">{step.target_system}</span>
63
- {/if}
64
- <span class="meta-badge {riskColor[step.risk_level] ?? 'risk-low'}">
65
- {riskEmoji[step.risk_level] ?? '🟢'} {step.risk_level}
66
- </span>
67
- {#if step.approval_required}
68
- <span class="meta-badge badge-approval">approval required</span>
69
- {/if}
70
- </div>
71
-
72
- {#if step.method_primary}
73
- <div class="step-method">
74
- <span class="method-label">primary:</span>
75
- <code class="method-value">{step.method_primary}</code>
76
- {#if step.method_fallback}
77
- <span class="method-label">fallback:</span>
78
- <code class="method-value">{step.method_fallback}</code>
79
- {/if}
80
- </div>
81
- {/if}
82
-
83
- {#if step.rollback}
84
- <div class="step-rollback">
85
- <span class="rollback-label">↩</span>
86
- <span class="rollback-text">{step.rollback}</span>
87
- </div>
88
- {/if}
89
-
90
- {#if isPending}
91
- <div class="step-actions">
92
- <PillButton
93
- variant="primary"
94
- size="sm"
95
- on:click={() => dispatch('approve', { stepId: step.id })}
96
- >
97
- Approve
98
- </PillButton>
99
- <PillButton
100
- variant="danger"
101
- size="sm"
102
- on:click={() => dispatch('reject', { stepId: step.id })}
103
- >
104
- Reject
105
- </PillButton>
106
- </div>
107
- {/if}
108
- </div>
109
- </div>
110
-
111
- <style>
112
- .plan-step {
113
- display: flex;
114
- gap: 0.75rem;
115
- padding: 0.75rem;
116
- border-radius: 12px;
117
- background: var(--bg-secondary, #f8f9fa);
118
- border: 1.5px solid var(--border-card, #e0e0e0);
119
- transition:
120
- border-color 0.2s ease,
121
- background 0.2s ease,
122
- transform 0.25s cubic-bezier(0.68, -0.55, 0.265, 1.55);
123
- }
124
-
125
- .plan-step:hover {
126
- transform: translateY(-1px);
127
- }
128
-
129
- .step-approved {
130
- border-color: #a5d6a7;
131
- background: rgba(165, 214, 167, 0.10);
132
- }
133
-
134
- .step-completed {
135
- border-color: #81c784;
136
- background: rgba(129, 199, 132, 0.12);
137
- opacity: 0.85;
138
- }
139
-
140
- .step-failed {
141
- border-color: #ef9a9a;
142
- background: rgba(239, 154, 154, 0.10);
143
- }
144
-
145
- /* Step number bubble */
146
- .step-num {
147
- display: flex;
148
- align-items: center;
149
- justify-content: center;
150
- width: 26px;
151
- height: 26px;
152
- border-radius: 9999px;
153
- background: var(--border-card, #e0e0e0);
154
- font-size: 0.7rem;
155
- font-weight: 800;
156
- color: var(--text-secondary, #555);
157
- flex-shrink: 0;
158
- margin-top: 2px;
159
- }
160
-
161
- .step-approved .step-num { background: #c8e6c9; color: #1b5e20; }
162
- .step-completed .step-num { background: #a5d6a7; color: #1b5e20; }
163
- .step-failed .step-num { background: #ffcdd2; color: #b71c1c; }
164
-
165
- /* Content */
166
- .step-content {
167
- flex: 1;
168
- min-width: 0;
169
- display: flex;
170
- flex-direction: column;
171
- gap: 0.35rem;
172
- }
173
-
174
- .step-top {
175
- display: flex;
176
- align-items: flex-start;
177
- justify-content: space-between;
178
- gap: 0.5rem;
179
- }
180
-
181
- .step-title {
182
- font-size: 0.875rem;
183
- font-weight: 700;
184
- color: var(--text-primary, #222);
185
- line-height: 1.35;
186
- flex: 1;
187
- }
188
-
189
- .step-status {
190
- font-size: 0.9rem;
191
- flex-shrink: 0;
192
- }
193
-
194
- /* Meta badges */
195
- .step-meta {
196
- display: flex;
197
- flex-wrap: wrap;
198
- gap: 0.3rem;
199
- }
200
-
201
- .meta-badge {
202
- display: inline-flex;
203
- align-items: center;
204
- gap: 0.2rem;
205
- padding: 2px 8px;
206
- border-radius: 9999px;
207
- font-size: 0.65rem;
208
- font-weight: 700;
209
- letter-spacing: 0.04em;
210
- text-transform: uppercase;
211
- }
212
-
213
- .badge-system {
214
- background: rgba(66, 165, 245, 0.15);
215
- color: #1565c0;
216
- border: 1px solid rgba(66, 165, 245, 0.3);
217
- }
218
-
219
- .risk-low { background: #e8f5e9; color: #2e7d32; border: 1px solid #a5d6a7; }
220
- .risk-medium { background: #fffde7; color: #f57f17; border: 1px solid #ffe082; }
221
- .risk-high { background: #fce4ec; color: #c62828; border: 1px solid #ef9a9a; }
222
-
223
- .badge-approval {
224
- background: rgba(255, 152, 0, 0.12);
225
- color: #e65100;
226
- border: 1px solid rgba(255, 152, 0, 0.3);
227
- }
228
-
229
- /* Method row */
230
- .step-method {
231
- display: flex;
232
- flex-wrap: wrap;
233
- align-items: center;
234
- gap: 0.3rem;
235
- font-size: 0.72rem;
236
- }
237
-
238
- .method-label {
239
- color: var(--text-muted, #888);
240
- font-weight: 600;
241
- }
242
-
243
- .method-value {
244
- background: var(--bg-card, #fff);
245
- border: 1px solid var(--border-card, #e0e0e0);
246
- border-radius: 4px;
247
- padding: 1px 5px;
248
- font-family: 'Menlo', monospace;
249
- font-size: 0.68rem;
250
- color: var(--text-secondary, #555);
251
- }
252
-
253
- /* Rollback */
254
- .step-rollback {
255
- display: flex;
256
- align-items: center;
257
- gap: 0.3rem;
258
- font-size: 0.7rem;
259
- color: var(--text-muted, #888);
260
- }
261
-
262
- .rollback-label { font-size: 0.8rem; }
263
- .rollback-text { font-style: italic; }
264
-
265
- /* Actions */
266
- .step-actions {
267
- display: flex;
268
- gap: 0.4rem;
269
- margin-top: 0.25rem;
270
- }
271
- </style>
1
+ <script lang="ts">
2
+ import { createEventDispatcher } from 'svelte';
3
+ import PillButton from '$lib/components/ui/PillButton.svelte';
4
+ import type { PlanStep as PlanStepType } from '$lib/api';
5
+
6
+ export let step: PlanStepType;
7
+ export let index: number;
8
+
9
+ const dispatch = createEventDispatcher<{
10
+ approve: { stepId: number };
11
+ reject: { stepId: number };
12
+ }>();
13
+
14
+ const riskColor: Record<string, string> = {
15
+ low: 'risk-low',
16
+ medium: 'risk-medium',
17
+ high: 'risk-high'
18
+ };
19
+
20
+ const riskEmoji: Record<string, string> = {
21
+ low: '🟢',
22
+ medium: '🟡',
23
+ high: '🔴'
24
+ };
25
+
26
+ const statusEmoji: Record<string, string> = {
27
+ pending: '⏳',
28
+ approved: '✅',
29
+ rejected: '❌',
30
+ running: '⚡',
31
+ completed: '🎉',
32
+ failed: '💥'
33
+ };
34
+
35
+ $: isPending = step.status === 'pending';
36
+ $: isApproved = step.status === 'approved';
37
+ $: isCompleted = step.status === 'completed';
38
+ $: isFailed = step.status === 'failed';
39
+ </script>
40
+
41
+ <div
42
+ class="plan-step"
43
+ class:step-approved={isApproved}
44
+ class:step-completed={isCompleted}
45
+ class:step-failed={isFailed}
46
+ role="listitem"
47
+ >
48
+ <!-- Step number bubble -->
49
+ <div class="step-num" aria-hidden="true">{index}</div>
50
+
51
+ <!-- Main content -->
52
+ <div class="step-content">
53
+ <div class="step-top">
54
+ <span class="step-title">{step.title}</span>
55
+ <span class="step-status" title="Status: {step.status}">
56
+ {statusEmoji[step.status] ?? '⏳'}
57
+ </span>
58
+ </div>
59
+
60
+ <div class="step-meta">
61
+ {#if step.target_system}
62
+ <span class="meta-badge badge-system">{step.target_system}</span>
63
+ {/if}
64
+ <span class="meta-badge {riskColor[step.risk_level] ?? 'risk-low'}">
65
+ {riskEmoji[step.risk_level] ?? '🟢'} {step.risk_level}
66
+ </span>
67
+ {#if step.approval_required}
68
+ <span class="meta-badge badge-approval">approval required</span>
69
+ {/if}
70
+ </div>
71
+
72
+ {#if step.method_primary}
73
+ <div class="step-method">
74
+ <span class="method-label">primary:</span>
75
+ <code class="method-value">{step.method_primary}</code>
76
+ {#if step.method_fallback}
77
+ <span class="method-label">fallback:</span>
78
+ <code class="method-value">{step.method_fallback}</code>
79
+ {/if}
80
+ </div>
81
+ {/if}
82
+
83
+ {#if step.rollback}
84
+ <div class="step-rollback">
85
+ <span class="rollback-label">↩</span>
86
+ <span class="rollback-text">{step.rollback}</span>
87
+ </div>
88
+ {/if}
89
+
90
+ {#if isPending}
91
+ <div class="step-actions">
92
+ <PillButton
93
+ variant="primary"
94
+ size="sm"
95
+ on:click={() => dispatch('approve', { stepId: step.id })}
96
+ >
97
+ Approve
98
+ </PillButton>
99
+ <PillButton
100
+ variant="danger"
101
+ size="sm"
102
+ on:click={() => dispatch('reject', { stepId: step.id })}
103
+ >
104
+ Reject
105
+ </PillButton>
106
+ </div>
107
+ {/if}
108
+ </div>
109
+ </div>
110
+
111
+ <style>
112
+ .plan-step {
113
+ display: flex;
114
+ gap: 0.75rem;
115
+ padding: 0.75rem;
116
+ border-radius: 12px;
117
+ background: var(--bg-secondary, #f8f9fa);
118
+ border: 1.5px solid var(--border-card, #e0e0e0);
119
+ transition:
120
+ border-color 0.2s ease,
121
+ background 0.2s ease,
122
+ transform 0.25s cubic-bezier(0.68, -0.55, 0.265, 1.55);
123
+ }
124
+
125
+ .plan-step:hover {
126
+ transform: translateY(-1px);
127
+ }
128
+
129
+ .step-approved {
130
+ border-color: #a5d6a7;
131
+ background: rgba(165, 214, 167, 0.10);
132
+ }
133
+
134
+ .step-completed {
135
+ border-color: #81c784;
136
+ background: rgba(129, 199, 132, 0.12);
137
+ opacity: 0.85;
138
+ }
139
+
140
+ .step-failed {
141
+ border-color: #ef9a9a;
142
+ background: rgba(239, 154, 154, 0.10);
143
+ }
144
+
145
+ /* Step number bubble */
146
+ .step-num {
147
+ display: flex;
148
+ align-items: center;
149
+ justify-content: center;
150
+ width: 26px;
151
+ height: 26px;
152
+ border-radius: 9999px;
153
+ background: var(--border-card, #e0e0e0);
154
+ font-size: 0.7rem;
155
+ font-weight: 800;
156
+ color: var(--text-secondary, #555);
157
+ flex-shrink: 0;
158
+ margin-top: 2px;
159
+ }
160
+
161
+ .step-approved .step-num { background: #c8e6c9; color: #1b5e20; }
162
+ .step-completed .step-num { background: #a5d6a7; color: #1b5e20; }
163
+ .step-failed .step-num { background: #ffcdd2; color: #b71c1c; }
164
+
165
+ /* Content */
166
+ .step-content {
167
+ flex: 1;
168
+ min-width: 0;
169
+ display: flex;
170
+ flex-direction: column;
171
+ gap: 0.35rem;
172
+ }
173
+
174
+ .step-top {
175
+ display: flex;
176
+ align-items: flex-start;
177
+ justify-content: space-between;
178
+ gap: 0.5rem;
179
+ }
180
+
181
+ .step-title {
182
+ font-size: 0.875rem;
183
+ font-weight: 700;
184
+ color: var(--text-primary, #222);
185
+ line-height: 1.35;
186
+ flex: 1;
187
+ }
188
+
189
+ .step-status {
190
+ font-size: 0.9rem;
191
+ flex-shrink: 0;
192
+ }
193
+
194
+ /* Meta badges */
195
+ .step-meta {
196
+ display: flex;
197
+ flex-wrap: wrap;
198
+ gap: 0.3rem;
199
+ }
200
+
201
+ .meta-badge {
202
+ display: inline-flex;
203
+ align-items: center;
204
+ gap: 0.2rem;
205
+ padding: 2px 8px;
206
+ border-radius: 9999px;
207
+ font-size: 0.65rem;
208
+ font-weight: 700;
209
+ letter-spacing: 0.04em;
210
+ text-transform: uppercase;
211
+ }
212
+
213
+ .badge-system {
214
+ background: rgba(66, 165, 245, 0.15);
215
+ color: #1565c0;
216
+ border: 1px solid rgba(66, 165, 245, 0.3);
217
+ }
218
+
219
+ .risk-low { background: #e8f5e9; color: #2e7d32; border: 1px solid #a5d6a7; }
220
+ .risk-medium { background: #fffde7; color: #f57f17; border: 1px solid #ffe082; }
221
+ .risk-high { background: #fce4ec; color: #c62828; border: 1px solid #ef9a9a; }
222
+
223
+ .badge-approval {
224
+ background: rgba(255, 152, 0, 0.12);
225
+ color: #e65100;
226
+ border: 1px solid rgba(255, 152, 0, 0.3);
227
+ }
228
+
229
+ /* Method row */
230
+ .step-method {
231
+ display: flex;
232
+ flex-wrap: wrap;
233
+ align-items: center;
234
+ gap: 0.3rem;
235
+ font-size: 0.72rem;
236
+ }
237
+
238
+ .method-label {
239
+ color: var(--text-muted, #888);
240
+ font-weight: 600;
241
+ }
242
+
243
+ .method-value {
244
+ background: var(--bg-card, #fff);
245
+ border: 1px solid var(--border-card, #e0e0e0);
246
+ border-radius: 4px;
247
+ padding: 1px 5px;
248
+ font-family: 'Menlo', monospace;
249
+ font-size: 0.68rem;
250
+ color: var(--text-secondary, #555);
251
+ }
252
+
253
+ /* Rollback */
254
+ .step-rollback {
255
+ display: flex;
256
+ align-items: center;
257
+ gap: 0.3rem;
258
+ font-size: 0.7rem;
259
+ color: var(--text-muted, #888);
260
+ }
261
+
262
+ .rollback-label { font-size: 0.8rem; }
263
+ .rollback-text { font-style: italic; }
264
+
265
+ /* Actions */
266
+ .step-actions {
267
+ display: flex;
268
+ gap: 0.4rem;
269
+ margin-top: 0.25rem;
270
+ }
271
+ </style>