docs(flows): DoD obligatorio con user-facing surface + abrir issues 0100-0103 (taxonomia, frontmatter migration, dev_console, work dashboard)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+5
-5
@@ -33,10 +33,10 @@ target_link_libraries(navegator_dashboard PRIVATE
|
||||
imgui_node_editor
|
||||
)
|
||||
|
||||
# fn_table_viz: provides data_table::render(), viz_render, TQL engine, Lua, LLM.
|
||||
# fn_module_data_table: provides data_table::render(), viz_render, TQL engine, Lua, LLM.
|
||||
# Guard keeps the app compilable in builds where vendor/lua is absent.
|
||||
if(TARGET fn_table_viz)
|
||||
target_link_libraries(navegator_dashboard PRIVATE fn_table_viz)
|
||||
if(TARGET fn_module_data_table)
|
||||
target_link_libraries(navegator_dashboard PRIVATE fn_module_data_table)
|
||||
endif()
|
||||
|
||||
set_target_properties(navegator_dashboard PROPERTIES WIN32_EXECUTABLE TRUE)
|
||||
@@ -65,8 +65,8 @@ if(FN_BUILD_TESTS)
|
||||
ws2_32
|
||||
imgui_node_editor
|
||||
)
|
||||
if(TARGET fn_table_viz)
|
||||
target_link_libraries(navegator_dashboard_tests PRIVATE fn_table_viz)
|
||||
if(TARGET fn_module_data_table)
|
||||
target_link_libraries(navegator_dashboard_tests PRIVATE fn_module_data_table)
|
||||
endif()
|
||||
# Excluye int main() de main.cpp; el harness define su propio main().
|
||||
target_compile_definitions(navegator_dashboard_tests PRIVATE FN_TEST_BUILD)
|
||||
|
||||
@@ -26,10 +26,14 @@ uses_functions:
|
||||
- infer_json_rows_schema_py_core
|
||||
- cdp_pick_element_js_js_browser
|
||||
uses_types: []
|
||||
uses_modules: [data_table_cpp]
|
||||
framework: "imgui"
|
||||
entry_point: "main.cpp"
|
||||
dir_path: "projects/navegator/apps/navegator_dashboard"
|
||||
repo_url: ""
|
||||
icon:
|
||||
phosphor: "compass"
|
||||
accent: "#2563eb"
|
||||
|
||||
e2e_checks:
|
||||
- id: build_windows
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "session_state.h"
|
||||
#include "py_subprocess.h"
|
||||
#include "picker_state.h"
|
||||
#include "app_base.h"
|
||||
|
||||
#include "crude_json.h"
|
||||
|
||||
@@ -123,6 +124,9 @@ try:
|
||||
out = {"tab_id": tab_id}
|
||||
if isinstance(schema, dict):
|
||||
out.update(schema)
|
||||
# llm_propose_scraping_schema returns "schema" key; remap to "fields" for parser.
|
||||
if "schema" in schema and "fields" not in schema:
|
||||
out["fields"] = schema["schema"]
|
||||
else:
|
||||
out["fields"] = schema
|
||||
print(json.dumps(out))
|
||||
@@ -141,6 +145,16 @@ except Exception as e:
|
||||
std::lock_guard<std::mutex> lk(g_ax.mu);
|
||||
g_ax.raw_python_output = r.stdout_data;
|
||||
}
|
||||
// Debug dump: stdout + diagnostic context to disk for offline inspection.
|
||||
{
|
||||
FILE* f = std::fopen(fn::local_path("autoextract_last.txt"), "wb");
|
||||
if (f) {
|
||||
std::fprintf(f, "EXIT=%d ERR=%s\n", r.exit_code, r.error.c_str());
|
||||
std::fprintf(f, "STDOUT_LEN=%zu\n--- STDOUT ---\n", r.stdout_data.size());
|
||||
std::fwrite(r.stdout_data.data(), 1, r.stdout_data.size(), f);
|
||||
std::fclose(f);
|
||||
}
|
||||
}
|
||||
if (r.exit_code != 0 || r.stdout_data.empty()) {
|
||||
std::lock_guard<std::mutex> lk(g_ax.mu);
|
||||
g_ax.last_error = r.error.empty() ? "python exited non-zero" : r.error;
|
||||
|
||||
+29
-4
@@ -13,7 +13,7 @@
|
||||
#include "core/icons_tabler.h"
|
||||
#include "core/tokens.h"
|
||||
#include "core/data_table_types.h"
|
||||
#include "viz/data_table.h"
|
||||
#include "data_table/data_table.h"
|
||||
|
||||
#include "chrome_scanner.h"
|
||||
#include "chrome_launcher.h"
|
||||
@@ -230,7 +230,14 @@ void render_browsers_panel(bool* p_open) {
|
||||
};
|
||||
}
|
||||
|
||||
data_table::render("##dt_browsers", {tbl}, g_browsers.dt_state, false);
|
||||
std::vector<data_table::TableEvent> dt_events;
|
||||
data_table::render("##dt_browsers", {tbl}, g_browsers.dt_state, &dt_events, /*show_chrome=*/false);
|
||||
for (auto& ev : dt_events) {
|
||||
if (ev.kind == data_table::TableEventKind::RowDoubleClick &&
|
||||
ev.row >= 0 && ev.row < static_cast<int>(g_browsers.instances.size())) {
|
||||
g_session().select_browser(g_browsers.instances[ev.row].port);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Actions: inline button list per row (no BeginTable — Button renderer not Fase-1) ---
|
||||
ImGui::Separator();
|
||||
@@ -445,7 +452,17 @@ void render_tabs_panel(bool* p_open) {
|
||||
};
|
||||
}
|
||||
|
||||
data_table::render("##dt_tabs", {tbl}, g_tabs_ui.dt_state, false);
|
||||
std::vector<data_table::TableEvent> dt_events;
|
||||
data_table::render("##dt_tabs", {tbl}, g_tabs_ui.dt_state, &dt_events, /*show_chrome=*/false);
|
||||
for (auto& ev : dt_events) {
|
||||
if (ev.kind == data_table::TableEventKind::RowDoubleClick &&
|
||||
ev.row >= 0 && ev.row < static_cast<int>(visible_tabs.size())) {
|
||||
const CdpTab* tp = visible_tabs[ev.row];
|
||||
if (tp && !tp->ws_url.empty()) {
|
||||
g_session().select_tab(tp->id, tp->ws_url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Actions: inline button list per visible row (no BeginTable — Button renderer not Fase-1) ---
|
||||
ImGui::Separator();
|
||||
@@ -1301,7 +1318,15 @@ void render_network_panel(bool* p_open) {
|
||||
cs.duration_error_ms = 5000.0f;
|
||||
}
|
||||
|
||||
data_table::render("##dt_requests", {req_tbl}, g_net_ui.dt_state, true);
|
||||
std::vector<data_table::TableEvent> dt_events;
|
||||
data_table::render("##dt_requests", {req_tbl}, g_net_ui.dt_state, &dt_events, /*show_chrome=*/true);
|
||||
for (auto& ev : dt_events) {
|
||||
if (ev.kind == data_table::TableEventKind::RowDoubleClick &&
|
||||
ev.row >= 0 && ev.row < static_cast<int>(filtered.size())) {
|
||||
g_net_ui.selected_id = filtered[ev.row]->id;
|
||||
g_net_ui.selected_index = ev.row;
|
||||
}
|
||||
}
|
||||
|
||||
// Context menu + selection: track clicked row by matching Name col
|
||||
// (handled inside data_table via row-click; URL copy available via right-click
|
||||
|
||||
+31
-2
@@ -68,6 +68,9 @@ std::string py_resolve_interpreter() {
|
||||
#ifdef _WIN32
|
||||
std::string venv_py = root + "\\python\\.venv\\Scripts\\python.exe";
|
||||
if (file_exists(venv_py)) return venv_py;
|
||||
// Windows venv no encontrado — intentar via WSL si FN_REGISTRY_ROOT_WSL existe.
|
||||
std::string wsl_root = getenv_str("FN_REGISTRY_ROOT_WSL");
|
||||
if (!wsl_root.empty()) return "wsl.exe"; // sentinel; py_run lo expande
|
||||
#else
|
||||
std::string venv_py = root + "/python/.venv/bin/python3";
|
||||
if (file_exists(venv_py)) return venv_py;
|
||||
@@ -108,10 +111,36 @@ PyResult py_run(const std::vector<std::string>& argv, int timeout_ms) {
|
||||
PyResult res;
|
||||
if (argv.empty()) { res.error = "argv empty"; return res; }
|
||||
|
||||
// Si argv[0] es el sentinel "wsl.exe", reescribir el comando para invocar
|
||||
// el python del venv WSL con el contexto Linux correcto:
|
||||
// wsl.exe --cd <linux_root> -- env FN_REGISTRY_ROOT=<linux_root> python3 -c "..." <args>
|
||||
// Esto garantiza que el script Python recibe FN_REGISTRY_ROOT como path Linux,
|
||||
// puede importar funciones del registry y resuelve deps del venv WSL.
|
||||
std::vector<std::string> final_argv;
|
||||
if (argv[0] == "wsl.exe") {
|
||||
std::string wsl_root = getenv_str("FN_REGISTRY_ROOT_WSL");
|
||||
if (wsl_root.empty()) {
|
||||
res.error = "wsl.exe sentinel but FN_REGISTRY_ROOT_WSL not set";
|
||||
return res;
|
||||
}
|
||||
std::string python3 = wsl_root + "/python/.venv/bin/python3";
|
||||
final_argv.push_back("wsl.exe");
|
||||
final_argv.push_back("--cd");
|
||||
final_argv.push_back(wsl_root);
|
||||
final_argv.push_back("--");
|
||||
final_argv.push_back("env");
|
||||
final_argv.push_back("FN_REGISTRY_ROOT=" + wsl_root);
|
||||
final_argv.push_back(python3);
|
||||
// Append rest of original argv (skip argv[0] = "wsl.exe")
|
||||
for (size_t i = 1; i < argv.size(); ++i) final_argv.push_back(argv[i]);
|
||||
} else {
|
||||
final_argv = argv;
|
||||
}
|
||||
|
||||
std::string cmd;
|
||||
for (size_t i = 0; i < argv.size(); ++i) {
|
||||
for (size_t i = 0; i < final_argv.size(); ++i) {
|
||||
if (i) cmd += ' ';
|
||||
cmd += quote_arg_win(argv[i]);
|
||||
cmd += quote_arg_win(final_argv[i]);
|
||||
}
|
||||
|
||||
HANDLE r_pipe = nullptr;
|
||||
|
||||
+21
-7
@@ -6,8 +6,18 @@
|
||||
//
|
||||
// Decisiones:
|
||||
// - Heredoc inline: el script Python se pasa via -c "<inline>" para evitar archivos temporales.
|
||||
// - PATH: usa "python3" o "python". Fallback: ${FN_REGISTRY_ROOT}/python/.venv/Scripts/python.exe
|
||||
// (Windows venv layout) o /python/.venv/bin/python3 (POSIX).
|
||||
// - PATH: prioridad del interprete:
|
||||
// Windows: (1) ${FN_REGISTRY_ROOT}\python\.venv\Scripts\python.exe si existe,
|
||||
// (2) wsl.exe sentinel si FN_REGISTRY_ROOT_WSL esta seteado (invoca
|
||||
// el python del venv WSL con: wsl.exe --cd <linux_root> -- env
|
||||
// FN_REGISTRY_ROOT=<linux_root> python/.venv/bin/python3 ...),
|
||||
// (3) "python" en PATH (sistema).
|
||||
// POSIX: ${FN_REGISTRY_ROOT}/python/.venv/bin/python3, luego "python3".
|
||||
// - Cuando se usa el sentinel wsl.exe, py_run reescribe el argv completo para que
|
||||
// el script Python reciba FN_REGISTRY_ROOT como path Linux, pueda importar
|
||||
// funciones del registry y use el venv WSL con todas las deps.
|
||||
// - FN_REGISTRY_ROOT y FN_REGISTRY_ROOT_WSL se propagan via launch_cpp_app_windows
|
||||
// (bash/functions/infra/launch_cpp_app_windows.sh v1.1.0).
|
||||
// - Stdout: capturado completo. El llamante parsea JSON.
|
||||
// - Stderr: redirigido a stdout para facilitar diagnostico (logs visibles).
|
||||
// - Sin consola visible en Windows (CREATE_NO_WINDOW).
|
||||
@@ -25,11 +35,15 @@ struct PyResult {
|
||||
std::string error; // mensaje propio si CreateProcess/popen fallo
|
||||
};
|
||||
|
||||
// Devuelve la ruta al interprete python a usar. Prioridad:
|
||||
// 1. ${FN_REGISTRY_ROOT}/python/.venv/Scripts/python.exe (Windows)
|
||||
// 2. ${FN_REGISTRY_ROOT}/python/.venv/bin/python3 (POSIX/MinGW)
|
||||
// 3. "python3" en PATH
|
||||
// 4. "python" en PATH (Windows default)
|
||||
// Devuelve la ruta al interprete python a usar. Prioridad (Windows):
|
||||
// 1. ${FN_REGISTRY_ROOT}\python\.venv\Scripts\python.exe — venv Windows nativo
|
||||
// 2. "wsl.exe" (sentinel) — cuando FN_REGISTRY_ROOT_WSL esta seteado.
|
||||
// py_run() lo expande a: wsl.exe --cd <linux_root> -- env FN_REGISTRY_ROOT=<linux_root>
|
||||
// <linux_root>/python/.venv/bin/python3 ...
|
||||
// 3. "python" — fallback PATH (python.exe del sistema, sin deps del registry)
|
||||
// Prioridad (POSIX):
|
||||
// 1. ${FN_REGISTRY_ROOT}/python/.venv/bin/python3
|
||||
// 2. "python3" en PATH
|
||||
std::string py_resolve_interpreter();
|
||||
|
||||
// Devuelve FN_REGISTRY_ROOT. Si no esta seteada, intenta deducirla:
|
||||
|
||||
Reference in New Issue
Block a user