AI-Repo-Commander/Docs/diagrams/debug-panel.puml

566 lines
16 KiB
Plaintext

' ===================================================================
' File: debug-panel.puml
' Purpose: Single source of truth for module-level activity + per-method sequences.
' Module: debug-panel.js — Draggable in-page panel: logs tail, tools/settings, queue, pause/stop.
' Edit rules: Follow the legend at bottom; preserve VIEW/METHOD anchors for automation.
' ===================================================================
' Neutral defaults — typography/layout only (keeps partition colors intact)
skinparam Shadowing false
skinparam SequenceMessageAlign center
skinparam SequenceLifeLineBorderColor #666666
skinparam SequenceLifeLineBorderThickness 1
' ==== VIEW: Branch Flow (debug-panel.js) ===================================
@startuml
title debug-panel.js — Branch Flow (full module)
start
:debug-panel;
fork
' -------- DebugPanel.constructor() --------
partition "DebugPanel.constructor()" #E7FAE3 {
:constructor;
:panel/bodyLogs/bodyTools = null;\ncollapsed=false; drag={active:false,dx:0,dy:0};
:panelState = _loadPanelState();
kill
}
fork again
' -------- _loadPanelState() --------
partition "_loadPanelState()" #FFF6D1 {
:_loadPanelState;
:JSON.parse(localStorage.getItem(STORAGE_KEYS.panel)||'{}');\ncatch -> {};
:return state;
kill
}
fork again
' -------- _savePanelState(partial) --------
partition "_savePanelState(partial)" #FFE1DB {
:_savePanelState;
:merged = {...panelState, ...partial};\npanelState=merged; localStorage.setItem(..., JSON.stringify(merged));
kill
}
fork again
' -------- flashBtn(btn, label, ms) --------
partition "flashBtn(btn, label, ms)" #DCF9EE {
:flashBtn;
:guard !btn; disable; temp label ✓; fade; setTimeout restore;
kill
}
fork again
' -------- toast(msg, ms) --------
partition "toast(msg, ms)" #FFE6F0 {
:toast;
:guard !panel; create floating div; append; auto-remove;
kill
}
fork again
' -------- copyLast(n=50) --------
partition "copyLast(n=50)" #E6F3FF {
:copyLast;
:lines = logger.getRecentLogs(n);\ntry navigator.clipboard.writeText -> info + toast;\ncatch -> _fallbackCopy(lines);
kill
}
fork again
' -------- _fallbackCopy(text, err?) --------
partition "_fallbackCopy(text, err?)" #F0E6FA {
:_fallbackCopy;
:overlay+textarea UI; select+focus; Close button;\nwarn on missing Clipboard API;
kill
}
fork again
' -------- mount() --------
partition "mount()" #E7FAF7 {
:mount;
:guard document.body else defer;\nif !cfg.debug.showPanel return;
:build root DOM (header/tabs/controls/bodies);\nappend to body;\nset refs; _wireControls(); _startLogRefresh();\npost-mount log info;
kill
}
fork again
' -------- _wireControls() --------
partition "_wireControls()" #FFF2E7 {
:_wireControls;
:bind level select; copy buttons; pause/resume; queue clear;\nSTOP; tabs; collapse; dragging; clear history;\nfeature toggles; number inputs; bridge key;\nconfig JSON save/reset;
kill
}
fork again
' -------- _loadToolsPanel() --------
partition "_loadToolsPanel()" #E7F7FF {
:_loadToolsPanel;
:sync toggles/nums from cfg;\nmask bridge key; sanitize config JSON (mask bridgeKey);
kill
}
fork again
' -------- _startLogRefresh() --------
partition "_startLogRefresh()" #FFF7E7 {
:_startLogRefresh;
:renderLogs() each second: show tail of buffer or hints;\nautoscroll;
kill
}
fork again
' -------- bootstrap --------
partition "bootstrap (new + mount)" #F7E7FF {
:panel = new DebugPanel();\nif DOMContentLoaded pending -> add listener -> mount();\nelse mount();\nwindow.AI_REPO_DEBUG_PANEL = panel;
kill
}
end fork
@enduml
' ==== METHOD: constructor() ================================================
@startuml
title debug-panel:constructor(): \n Initialize DOM refs, drag state, and persisted panel state
participant "Caller" as CL
participant "constructor()" as CTOR
participant "_loadPanelState()" as LPS
activate CL
CL -> CTOR : new DebugPanel()
activate CTOR
CTOR -> CTOR : panel=null; bodyLogs=null; bodyTools=null; collapsed=false
CTOR -> CTOR : drag={active:false,dx:0,dy:0}
CTOR -> LPS : _loadPanelState()
LPS --> CTOR : state | {}
CTOR -> CTOR : panelState = state
CTOR --> CL : instance
deactivate CTOR
deactivate CL
@enduml
' ==== METHOD: _loadPanelState() ============================================
@startuml
title debug-panel:_loadPanelState(): \n Read panel position/collapsed state from localStorage
participant "Caller" as CL
participant "_loadPanelState()" as LPS
participant "localStorage" as LS
participant "STORAGE_KEYS" as SK
activate CL
CL -> LPS : initial request
activate LPS
LPS -> SK : read STORAGE_KEYS.panel
SK --> LPS : key
LPS -> LS : getItem(key)
LS --> LPS : json | null
alt parse ok
LPS --> CL : JSON.parse(json) || {}
else parse error
LPS --> CL : {}
end
deactivate LPS
deactivate CL
@enduml
' ==== METHOD: _savePanelState(partial) ======================================
@startuml
title debug-panel:_savePanelState(partial): \n Merge and persist panel state
participant "Caller" as CL
participant "_savePanelState(partial)" as SPS
participant "localStorage" as LS
participant "STORAGE_KEYS" as SK
activate CL
CL -> SPS : partial
activate SPS
SPS -> SPS : merged = {...panelState, ...partial}; panelState=merged
SPS -> SK : STORAGE_KEYS.panel
SK --> SPS : key
SPS -> LS : setItem(key, JSON.stringify(merged))
LS --> SPS : ok
SPS --> CL : (void)
deactivate SPS
deactivate CL
@enduml
' ==== METHOD: flashBtn(btn, label='Done', ms=900) ===========================
@startuml
title debug-panel:flashBtn(btn, label, ms): \n Temporarily disable and relabel a button
participant "Caller" as CL
participant "flashBtn(btn,label,ms)" as FSH
participant "DOM" as DOM
participant "Timer" as TMR
activate CL
CL -> FSH : btn, label, ms
activate FSH
alt !btn
FSH --> CL : (void)
deactivate FSH
deactivate CL
return
end
FSH -> DOM : btn.disabled=true; store old text; set `${label} ✓`; opacity=.7
FSH -> TMR : setTimeout(ms)
TMR --> FSH : wake
FSH -> DOM : restore text; disabled=false; opacity=''
DOM --> FSH : ok
FSH --> CL : (void)
deactivate FSH
deactivate CL
@enduml
' ==== METHOD: toast(msg, ms=1200) ==========================================
@startuml
title debug-panel:toast(msg, ms): \n Show a transient floating toast in panel
participant "Caller" as CL
participant "toast(msg, ms)" as TST
participant "DOM" as DOM
participant "Timer" as TMR
activate CL
CL -> TST : msg, ms
activate TST
alt !panel
TST --> CL : (void)
deactivate TST
deactivate CL
return
end
TST -> DOM : createElement('div') with styles; appendChild(panel)
DOM --> TST : elem
TST -> TMR : setTimeout(ms)
TMR --> TST : wake
TST -> DOM : elem.remove()
DOM --> TST : removed
TST --> CL : (void)
deactivate TST
deactivate CL
@enduml
' ==== METHOD: copyLast(n=50) ===============================================
@startuml
title debug-panel:copyLast(n): \n Copy recent logs to clipboard or show manual copy overlay
participant "Caller" as CL
participant "copyLast(n)" as CPL
participant "Logger" as LOG
participant "Navigator.clipboard" as NCB
participant "toast(msg)" as TST
participant "_fallbackCopy(text,err?)" as FBC
activate CL
CL -> CPL : n
activate CPL
CPL -> LOG : getRecentLogs(n)
LOG --> CPL : lines (string)
CPL -> NCB : writeText(lines)
alt clipboard ok
NCB --> CPL : resolved
CPL -> LOG : info("Copied last n lines")
CPL -> TST : toast(`Copied last ${n} logs`)
TST --> CPL : shown
else clipboard error or unsupported
NCB --> CPL : rejected | (no API)
CPL -> FBC : _fallbackCopy(lines, error?)
FBC --> CPL : overlay shown
end
CPL --> CL : (void)
deactivate CPL
deactivate CL
@enduml
' ==== METHOD: _fallbackCopy(text, originalError) ============================
@startuml
title debug-panel:_fallbackCopy(text, originalError): \n Fullscreen overlay with textarea for manual copy
participant "Caller" as CL
participant "_fallbackCopy(text,err?)" as FBC
participant "DOM" as DOM
participant "Logger" as LOG
activate CL
CL -> FBC : text, originalError?
activate FBC
FBC -> DOM : create overlay + panel + textarea + Close button; append to body
DOM --> FBC : mounted
FBC -> DOM : textarea.focus(); textarea.select()
DOM --> FBC : selected
FBC -> LOG : warn("Clipboard API unavailable", {error})
LOG --> FBC : ok
FBC --> CL : (void)
deactivate FBC
deactivate CL
@enduml
' ==== METHOD: mount() =======================================================
@startuml
title debug-panel:mount(): \n Create panel DOM, wire controls, start log refresh, log ready
participant "Caller" as CL
participant "mount()" as MNT
participant "Config" as CFG
participant "DOM" as DOM
participant "_wireControls()" as WRC
participant "_startLogRefresh()" as LRF
participant "Logger" as LOG
participant "Timer" as TMR
activate CL
CL -> MNT : initial request
activate MNT
alt !document.body
MNT -> TMR : setTimeout(100)
TMR --> MNT : retry
MNT --> CL : (returns after scheduling)
else body present
MNT -> CFG : get('debug.showPanel')
CFG --> MNT : bool
alt disabled
MNT --> CL : (void)
else enabled
MNT -> DOM : build root HTML (header/tabs/controls/bodies)
DOM --> MNT : root
MNT -> DOM : appendChild(document.body, root)
DOM --> MNT : ok
MNT -> MNT : this.panel/root refs; bodyLogs/bodyTools
MNT -> WRC : _wireControls()
WRC --> MNT : wired
MNT -> LRF : _startLogRefresh()
LRF --> MNT : started
MNT -> TMR : setTimeout(100)
TMR --> MNT : tick
MNT -> LOG : info("Debug panel mounted...")
LOG --> MNT : ok
MNT -> LOG : info("Panel visible at: (...)")
end
MNT --> CL : (void)
end
deactivate MNT
deactivate CL
@enduml
' ==== METHOD: _wireControls() ==============================================
@startuml
title debug-panel:_wireControls(): \n Bind all UI controls to config/logger/queue/history/actions
participant "Caller" as CL
participant "_wireControls()" as WRC
participant "Config" as CFG
participant "Logger" as LOG
participant "DOM" as DOM
participant "Queue" as QUE
participant "History" as HIS
participant "Paste" as PST
activate CL
CL -> WRC : initial request
activate WRC
' Log level selector
WRC -> DOM : select('.rc-level')
DOM --> WRC : sel
WRC -> CFG : get('debug.level')
CFG --> WRC : currentLevel
WRC -> LOG : trace(`[Debug Panel] Current log level: ${currentLevel}`)
WRC -> DOM : sel.onchange -> LOG.setLevel(newLevel) + LOG.info(...)
' Copy buttons
WRC -> DOM : .rc-copy / .rc-copy-200 (onclick -> copyLast(n) + flashBtn)
DOM --> WRC : wired
' Pause/Resume runtime
WRC -> DOM : .rc-pause (onclick -> toggle cfg.runtime.paused; flashBtn; toast; log)
DOM --> WRC : wired
' Queue clear
WRC -> DOM : .rc-queue-clear (onclick -> AI_REPO_QUEUE.clear(); flashBtn; toast; log.warn)
DOM --> WRC : wired
' Emergency STOP
WRC -> DOM : .rc-stop (onclick -> AI_REPO_STOP(); flashBtn; toast; log.warn)
DOM --> WRC : wired
' Tabs + Tools load
WRC -> DOM : tabs ('Logs'/'Tools & Settings'); switch bodies; call _loadToolsPanel()
DOM --> WRC : wired
' Collapse toggle
WRC -> DOM : .rc-collapse (onclick -> toggle collapsed; save state)
DOM --> WRC : wired
' Drag header
WRC -> DOM : .rc-header (mousedown -> track; mousemove -> set left/top; mouseup -> _savePanelState)
DOM --> WRC : wired
' Clear History
WRC -> DOM : .rc-clear-history (onclick -> HIS.clear(); GM_notification?; flashBtn; toast; log)
DOM --> WRC : wired
' Toggles (checkboxes)
WRC -> DOM : .rc-toggle (bind cfg.get/set; toast; log.info)
DOM --> WRC : wired
' Numeric inputs
WRC -> DOM : .rc-num (bind cfg.get; on change -> parseInt -> cfg.set; toast; log.info)
DOM --> WRC : wired
' Bridge key save/clear
WRC -> DOM : .rc-save-bridge-key / .rc-clear-bridge-key (onclick -> cfg.set('api.bridgeKey', val|''); mask input; flashBtn; toast; log)
DOM --> WRC : wired
' Config JSON save/reset
WRC -> DOM : .rc-save-json (parse JSON; delete meta/runtime; deep-set cfg; refresh tools; toast/log), .rc-reset-defaults (confirm -> localStorage.removeItem(cfgKey) -> reload)
DOM --> WRC : wired
WRC --> CL : (void)
deactivate WRC
deactivate CL
@enduml
' ==== METHOD: _loadToolsPanel() ============================================
@startuml
title debug-panel:_loadToolsPanel(): \n Populate controls from cfg and render sanitized JSON
participant "Caller" as CL
participant "_loadToolsPanel()" as LTP
participant "Config" as CFG
participant "DOM" as DOM
activate CL
CL -> LTP : initial request
activate LTP
' Toggles and nums
LTP -> DOM : queryAll('.rc-toggle') / queryAll('.rc-num')
DOM --> LTP : lists
LTP -> CFG : get(key) for each
CFG --> LTP : values
LTP -> DOM : set .checked / .value accordingly
' Bridge key masked
LTP -> CFG : get('api.bridgeKey')
CFG --> LTP : key | ''
LTP -> DOM : .rc-bridge-key.value = key ? '••••••••' : ''
' Config JSON sanitized
LTP -> CFG : config (object)
CFG --> LTP : dump
LTP -> LTP : sanitized = deep clone; if api.bridgeKey -> mask
LTP -> DOM : .rc-json.value = JSON.stringify(sanitized, null, 2)
LTP --> CL : (void)
deactivate LTP
deactivate CL
@enduml
' ==== METHOD: _startLogRefresh() ===========================================
@startuml
title debug-panel:_startLogRefresh(): \n Tail logger buffer every second and autoscroll
participant "Caller" as CL
participant "_startLogRefresh()" as LRF
participant "Logger" as LOG
participant "DOM" as DOM
participant "Timer" as TMR
activate CL
CL -> LRF : initial request
activate LRF
LRF -> LRF : define renderLogs()
LRF -> TMR : setInterval(renderLogs, 1000)
TMR --> LRF : id
LRF -> LRF : renderLogs()
' renderLogs inner flow
LRF -> LOG : buffer?
LOG --> LRF : buffer | undefined
alt logger not ready
LRF -> DOM : bodyLogs.innerHTML = "Logger not initialized yet..."
else ready
LRF -> LRF : rows = buffer.slice(-80)
alt rows empty
LRF -> DOM : "No logs yet. Waiting for activity..."
else rows
LRF -> DOM : bodyLogs.innerHTML = rows.map(...).join('')
LRF -> DOM : bodyLogs.scrollTop = bodyLogs.scrollHeight
end
end
LRF --> CL : (void)
deactivate LRF
deactivate CL
@enduml
' ==== METHOD: bootstrap (instance + mount) =================================
@startuml
title debug-panel:bootstrap: \n Instantiate panel and mount after DOM is ready
participant "Caller" as CL
participant "bootstrap" as BOOT
participant "DOM" as DOM
participant "DebugPanel()" as CTOR
participant "mount()" as MNT
activate CL
CL -> BOOT : initial load
activate BOOT
BOOT -> CTOR : new DebugPanel()
CTOR --> BOOT : panel
BOOT -> DOM : document.readyState
DOM --> BOOT : 'loading' | 'interactive/complete'
alt loading
BOOT -> DOM : addEventListener('DOMContentLoaded', () => panel.mount())
DOM --> BOOT : listener added
else ready
BOOT -> MNT : panel.mount()
MNT --> BOOT : mounted
end
BOOT -> DOM : window.AI_REPO_DEBUG_PANEL = panel
BOOT --> CL : (void)
deactivate BOOT
deactivate CL
@enduml
' ==== LEGEND ===============================================================
@startuml
legend bottom
== debug-panel UML Style Guide (for future edits) ==
• Scope: One .puml per module. Keep two views:
(1) Activity "Branch Flow" for the whole module (partitions + soft colors),
(2) Per-function/Per-method Sequence diagrams for each exported or significant internal function.
• Sequence conventions:
1) First participant is the external caller (use "Caller" or a concrete origin).
2) Do NOT add a module/class lifeline; the name appears in the title only.
3) Include every directly-called method or subsystem as a participant
(e.g., "mount()", "_wireControls()", "copyLast()", "_fallbackCopy()", "toast()", "flashBtn()", "Queue", "History", "Logger", "Config", "Timer", "DOM", "localStorage", "STORAGE_KEYS").
4) Prefer simple messages; Use --> for returns; -> for calls.
5) Use activate/deactivate as you see fit for clarity.
6) Use alt blocks only when branches meaningfully change the message flow.
• Activity view conventions:
A) Start with module node then fork partitions for each function/method.
B) One partition per function; soft background color; terminate branches with 'kill'.
C) Keep wording aligned with code (e.g., masked bridge key, JSON sanitize, tail size ~80 rows).
• Color palette (soft pastels)
• Use --> for returns; -> for calls.
• Participants use quoted method names for internals (e.g., "_loadToolsPanel()"), and plain nouns for systems ("DOM", "Timer", "localStorage").
• Keep this legend at the end of the file to standardize edits.
endlegend
@enduml