chore: add UI field hover help and update project notes

This commit is contained in:
2026-02-23 20:57:51 -05:00
parent e7dbc9870f
commit 9b4ef8fed8
4 changed files with 629 additions and 99 deletions

View File

@@ -120,6 +120,101 @@ const MANIFEST_EVENT_TRIGGERS = [
const RUN_MANIFEST_EDITOR_VALUE = "__editor__";
const RUN_MANIFEST_EDITOR_LABEL = "[Use Manifest Editor JSON]";
const LABEL_HELP_BY_CONTROL = Object.freeze({
"session-select": "Select which session the graph and feed should focus on.",
"graph-manifest-select": "Choose the manifest context used when rendering the selected session graph.",
"run-prompt": "Describe the task objective you want the run to complete.",
"run-manifest-select": "Choose a saved manifest or use the JSON currently in the editor.",
"run-execution-mode": "Use provider for live model execution or mock for simulated execution.",
"run-provider": "Choose which model provider backend handles provider-mode runs.",
"run-topology-hint": "Optional hint that nudges orchestration toward a topology strategy.",
"run-flags": "Optional JSON object passed in as initial run flags.",
"run-validation-nodes": "Optional comma-separated node IDs to simulate validation outcomes for.",
"events-limit": "Set how many recent runtime events are loaded per refresh.",
"cfg-webhook-url": "Webhook endpoint that receives runtime event notifications.",
"cfg-webhook-severity": "Minimum severity level that triggers webhook notifications.",
"cfg-webhook-always": "Event types that should always notify, regardless of severity.",
"cfg-security-mode": "Policy behavior used when a command violates security rules.",
"cfg-security-binaries": "Comma-separated command binaries permitted by policy.",
"cfg-security-timeout": "Maximum command execution time before forced timeout.",
"cfg-security-inherit": "Environment variable names to pass through to subprocesses.",
"cfg-security-scrub": "Environment variable names to strip before command execution.",
"cfg-limit-concurrent": "Maximum number of agents that can run concurrently across sessions.",
"cfg-limit-session": "Maximum number of agents that can run concurrently within a single session.",
"cfg-limit-depth": "Maximum recursive spawn depth allowed for agent tasks.",
"cfg-topology-depth": "Maximum orchestration graph depth permitted by topology rules.",
"cfg-topology-retries": "Maximum retry expansions allowed by topology orchestration.",
"cfg-relationship-children": "Maximum children each persona relationship can spawn.",
"cfg-port-base": "Starting port number for provisioning port allocations.",
"cfg-port-block-size": "Number of ports reserved per allocated block.",
"cfg-port-block-count": "Number of port blocks available for allocation.",
"cfg-port-primary-offset": "Offset within each block used for the primary service port.",
"manifest-path": "Workspace-relative manifest file path to load, validate, or save.",
"helper-topology-sequential": "Allow sequential execution topology in this manifest.",
"helper-topology-parallel": "Allow parallel execution topology in this manifest.",
"helper-topology-hierarchical": "Allow hierarchical parent-child execution topology.",
"helper-topology-retry-unrolled": "Allow retry-unrolled topology for explicit retry paths.",
"helper-topology-max-depth": "Top-level cap on orchestration depth in this manifest.",
"helper-topology-max-retries": "Top-level cap on retry attempts in this manifest.",
"helper-entry-node-id": "Node ID used as the pipeline entry point.",
"helper-persona-id": "Stable persona identifier referenced by nodes and relationships.",
"helper-persona-display-name": "Human-readable persona name shown in summaries and tooling.",
"helper-persona-model-constraint": "Optional model restriction for this persona only.",
"helper-persona-system-prompt": "Base prompt template that defines persona behavior.",
"helper-persona-allowlist": "Comma-separated tool names this persona may use.",
"helper-persona-banlist": "Comma-separated tool names this persona must not use.",
"helper-relationship-parent": "Parent persona ID that can spawn or delegate to the child.",
"helper-relationship-child": "Child persona ID allowed under the selected parent.",
"helper-relationship-max-depth": "Optional override limiting recursion depth for this relationship.",
"helper-relationship-max-children": "Optional override limiting child fan-out for this relationship.",
"helper-node-id": "Unique pipeline node identifier used by entry node and edges.",
"helper-node-actor-id": "Runtime actor identifier assigned to this node.",
"helper-node-persona-id": "Persona applied when this node executes.",
"helper-node-topology-kind": "Optional node-level topology override.",
"helper-node-block-id": "Optional topology block identifier for grouped scheduling logic.",
"helper-node-max-retries": "Optional node-level retry limit override.",
"helper-edge-from": "Source node where this edge starts.",
"helper-edge-to": "Target node activated when this edge condition matches.",
"helper-edge-trigger-kind": "Choose whether edge activation is status-based or event-based.",
"helper-edge-on": "Node status value that triggers this edge when using status mode.",
"helper-edge-event": "Domain event name that triggers this edge when using event mode.",
"helper-edge-when": "Optional JSON array of additional conditions required to follow the edge.",
});
function extractLabelText(label) {
const clone = label.cloneNode(true);
for (const field of clone.querySelectorAll("input, select, textarea")) {
field.remove();
}
return clone.textContent?.replace(/\s+/g, " ").trim() || "this field";
}
function applyLabelTooltips(root = document) {
for (const label of root.querySelectorAll("label")) {
const control = label.querySelector("input,select,textarea");
if (!control) {
continue;
}
let help = LABEL_HELP_BY_CONTROL[control.id] || "";
if (!help) {
for (const className of control.classList) {
help = LABEL_HELP_BY_CONTROL[className] || "";
if (help) {
break;
}
}
}
if (!help) {
const labelText = extractLabelText(label).toLowerCase();
help = `Set ${labelText} for this configuration.`;
}
label.title = help;
control.title = help;
}
}
function fmtMoney(value) {
return `$${Number(value || 0).toFixed(4)}`;
}
@@ -575,6 +670,8 @@ function renderManifestHelper() {
`;
})
.join("");
applyLabelTooltips(dom.manifestForm);
}
function readManifestDraftFromHelper() {
@@ -1737,6 +1834,7 @@ async function refreshAll() {
async function initialize() {
bindUiEvents();
applyLabelTooltips();
try {
await apiRequest("/api/health");