chore: snapshot WIP previo + flow 0008 + 7 sub-issues (0112-0119)

Snapshot de WIP acumulado de sesiones previas antes de merge wave 1
del flow 0008 (kanban_cpp + agent_runner_api + DoD schema).

Incluye:
- dev/flows/0008-kanban-cpp-and-agent-workflows.md
- dev/issues/0112-0119*.md (7 sub-issues)
- WIP previo en cmd/fn/doctor.go, registry/*, modules/, cpp/, etc.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-18 18:17:08 +02:00
parent ddb5366884
commit b9716a7cd6
119 changed files with 14929 additions and 3084 deletions
+63 -38
View File
@@ -1,8 +1,11 @@
#include "viz/sparkline.h"
#include "imgui.h"
void sparkline(const char* id, const float* values, int count, ImVec4 color,
float width, float height) {
// Implementacion comun. Si auto_y=true, calcula min/max de values; si no,
// usa [y_min, y_max] explicitos.
static void sparkline_impl(const char* id, const float* values, int count,
ImVec4 color, float width, float height,
bool auto_y, float y_min, float y_max) {
if (count <= 0) return;
ImGui::PushID(id);
@@ -10,67 +13,89 @@ void sparkline(const char* id, const float* values, int count, ImVec4 color,
ImVec2 pos = ImGui::GetCursorScreenPos();
ImDrawList* draw_list = ImGui::GetWindowDrawList();
// Reserve inline space
ImGui::Dummy(ImVec2(width, height));
// Find min/max for Y auto-scale
float min_val = values[0];
float max_val = values[0];
for (int i = 1; i < count; i++) {
if (values[i] < min_val) min_val = values[i];
if (values[i] > max_val) max_val = values[i];
if (auto_y) {
y_min = values[0];
y_max = values[0];
for (int i = 1; i < count; i++) {
if (values[i] < y_min) y_min = values[i];
if (values[i] > y_max) y_max = values[i];
}
}
float range = max_val - min_val;
if (range < 1e-6f) range = 1.0f; // avoid division by zero for flat lines
float range = y_max - y_min;
if (range < 1e-6f) range = 1.0f;
auto y_at = [&](float v) {
// Clamp visualmente al rango — para fixed Y sirve para que outliers
// no salgan del card; para auto Y es no-op.
if (v < y_min) v = y_min;
if (v > y_max) v = y_max;
return pos.y + height - ((v - y_min) / range) * height;
};
// Fade gradient v1.2: alpha sube de older->newer.
// El segmento [i, i+1] se pinta con alpha proporcional al endpoint derecho
// (mas cercano a "ahora"). Hace efecto de rastro / trail.
const int r_ = (int)(color.x * 255);
const int g_ = (int)(color.y * 255);
const int b_ = (int)(color.z * 255);
auto seg_t = [&](int i) {
return (count > 1) ? (float)(i + 1) / (float)(count - 1) : 1.0f;
};
// Fill area under curve (low alpha)
if (count >= 2) {
ImU32 fill_color = IM_COL32(
(int)(color.x * 255),
(int)(color.y * 255),
(int)(color.z * 255),
40);
// Build fill polygon: baseline bottom-left -> points -> baseline bottom-right
// We use AddConvexPolyFilled workaround: draw as a series of triangles from baseline
float x0 = pos.x;
float y_base = pos.y + height;
for (int i = 0; i + 1 < count; i++) {
float t = seg_t(i);
int fill_a = (int)((0.10f + 0.70f * t) * 40.0f); // 4..28 alpha
ImU32 fill_color = IM_COL32(r_, g_, b_, fill_a);
float xa = x0 + ((float)i / (count - 1)) * width;
float xb = x0 + ((float)(i + 1) / (count - 1)) * width;
float ya = pos.y + height - ((values[i] - min_val) / range) * height;
float yb = pos.y + height - ((values[i + 1] - min_val) / range) * height;
float ya = y_at(values[i]);
float yb = y_at(values[i + 1]);
draw_list->AddQuadFilled(
ImVec2(xa, y_base),
ImVec2(xa, ya),
ImVec2(xb, yb),
ImVec2(xb, y_base),
ImVec2(xa, y_base), ImVec2(xa, ya),
ImVec2(xb, yb), ImVec2(xb, y_base),
fill_color);
}
}
// Draw polyline
ImU32 line_color = IM_COL32(
(int)(color.x * 255),
(int)(color.y * 255),
(int)(color.z * 255),
(int)(color.w * 255));
for (int i = 0; i + 1 < count; i++) {
float t = seg_t(i);
float a = 0.20f + 0.80f * t;
ImU32 line_color = IM_COL32(r_, g_, b_, (int)(color.w * a * 255));
float xa = pos.x + ((float)i / (count - 1)) * width;
float xb = pos.x + ((float)(i + 1) / (count - 1)) * width;
float ya = pos.y + height - ((values[i] - min_val) / range) * height;
float yb = pos.y + height - ((values[i + 1] - min_val) / range) * height;
float ya = y_at(values[i]);
float yb = y_at(values[i + 1]);
draw_list->AddLine(ImVec2(xa, ya), ImVec2(xb, yb), line_color, 1.5f);
}
ImGui::PopID();
}
void sparkline(const char* id, const float* values, int count, ImVec4 color,
float width, float height) {
sparkline_impl(id, values, count, color, width, height,
/*auto_y=*/true, 0.0f, 0.0f);
}
void sparkline(const char* id, const float* values, int count,
float width, float height) {
// Default color: soft green
sparkline(id, values, count, ImVec4(0.35f, 0.85f, 0.45f, 1.0f), width, height);
}
void sparkline(const char* id, const float* values, int count, ImVec4 color,
float y_min, float y_max, float width, float height) {
sparkline_impl(id, values, count, color, width, height,
/*auto_y=*/false, y_min, y_max);
}
void sparkline(const char* id, const float* values, int count,
float y_min, float y_max, float width, float height) {
sparkline(id, values, count, ImVec4(0.35f, 0.85f, 0.45f, 1.0f),
y_min, y_max, width, height);
}