v2.1: add Property Inspector with poll interval setting
This commit is contained in:
@@ -21,6 +21,7 @@
|
|||||||
"UserTitleEnabled": true,
|
"UserTitleEnabled": true,
|
||||||
"SupportedInMultiActions": true,
|
"SupportedInMultiActions": true,
|
||||||
"Tooltip": "Codex Desktop 工作流状态监控"
|
"Tooltip": "Codex Desktop 工作流状态监控"
|
||||||
|
"PropertyInspectorPath": "propertyInspector/monitor/index.html"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"UUID": "com.streamdock.ai-monitor.claude",
|
"UUID": "com.streamdock.ai-monitor.claude",
|
||||||
@@ -43,6 +44,7 @@
|
|||||||
"UserTitleEnabled": true,
|
"UserTitleEnabled": true,
|
||||||
"SupportedInMultiActions": true,
|
"SupportedInMultiActions": true,
|
||||||
"Tooltip": "Claude Desktop 工作流状态监控"
|
"Tooltip": "Claude Desktop 工作流状态监控"
|
||||||
|
"PropertyInspectorPath": "propertyInspector/monitor/index.html"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"UUID": "com.streamdock.ai-monitor.opencode",
|
"UUID": "com.streamdock.ai-monitor.opencode",
|
||||||
@@ -65,6 +67,7 @@
|
|||||||
"UserTitleEnabled": true,
|
"UserTitleEnabled": true,
|
||||||
"SupportedInMultiActions": true,
|
"SupportedInMultiActions": true,
|
||||||
"Tooltip": "opencode 工作流状态监控"
|
"Tooltip": "opencode 工作流状态监控"
|
||||||
|
"PropertyInspectorPath": "propertyInspector/monitor/index.html"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"SDKVersion": 1,
|
"SDKVersion": 1,
|
||||||
|
|||||||
@@ -185,6 +185,14 @@ function makeActionFn(agentKey) {
|
|||||||
if (states[ctx] && states[ctx].timer) { clearInterval(states[ctx].timer); }
|
if (states[ctx] && states[ctx].timer) { clearInterval(states[ctx].timer); }
|
||||||
delete states[ctx];
|
delete states[ctx];
|
||||||
},
|
},
|
||||||
|
_didReceiveSettings: function(data) {
|
||||||
|
var ctx = data.context;
|
||||||
|
var ss = states[ctx]; if (!ss) return;
|
||||||
|
if (ss.timer) clearInterval(ss.timer);
|
||||||
|
var settings = plugin[agentKey].data[ctx];
|
||||||
|
var interval = (settings && settings.pollInterval) || POLL_INTERVAL;
|
||||||
|
ss.timer = setInterval(function() { poll(ctx); }, interval);
|
||||||
|
},
|
||||||
keyUp: function(data) { poll(data.context); },
|
keyUp: function(data) { poll(data.context); },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>AI Monitor Settings</title>
|
||||||
|
<link rel="stylesheet" href="../utils/css/sdpi.css">
|
||||||
|
<style>
|
||||||
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #1a1a2e; color: #e0e0e0; padding: 16px; margin: 0; }
|
||||||
|
label { display: block; font-size: 12px; color: #888; margin-bottom: 4px; text-transform: uppercase; letter-spacing: 0.5px; }
|
||||||
|
.row { display: flex; align-items: center; gap: 8px; }
|
||||||
|
input[type="range"] { flex: 1; accent-color: #f59e0b; }
|
||||||
|
.row span { font-size: 12px; color: #f59e0b; min-width: 50px; text-align: right; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<label>Poll Interval (ms)</label>
|
||||||
|
<div class="row">
|
||||||
|
<input type="range" id="pollInterval" min="500" max="5000" step="100" value="1000">
|
||||||
|
<span id="pollVal">1000ms</span>
|
||||||
|
</div>
|
||||||
|
<script src="../utils/action.js"></script>
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
var slider = document.getElementById('pollInterval');
|
||||||
|
var val = document.getElementById('pollVal');
|
||||||
|
slider.addEventListener('input', function () { val.textContent = this.value + 'ms'; $settings.pollInterval = parseInt(this.value, 10); });
|
||||||
|
if ($settings.pollInterval) slider.value = $settings.pollInterval;
|
||||||
|
else $settings.pollInterval = 1000;
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
let $websocket, $uuid, $action, $context, $settings, $lang, $FileID = '';
|
||||||
|
|
||||||
|
WebSocket.prototype.setGlobalSettings = function(payload) {
|
||||||
|
this.send(JSON.stringify({
|
||||||
|
event: "setGlobalSettings",
|
||||||
|
context: $uuid, payload
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
WebSocket.prototype.getGlobalSettings = function() {
|
||||||
|
this.send(JSON.stringify({
|
||||||
|
event: "getGlobalSettings",
|
||||||
|
context: $uuid,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 与插件通信
|
||||||
|
WebSocket.prototype.sendToPlugin = function (payload) {
|
||||||
|
this.send(JSON.stringify({
|
||||||
|
event: "sendToPlugin",
|
||||||
|
action: $action,
|
||||||
|
context: $uuid,
|
||||||
|
payload
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
//设置标题
|
||||||
|
WebSocket.prototype.setTitle = function (str, row = 0, num = 6) {
|
||||||
|
console.log(str);
|
||||||
|
let newStr = '';
|
||||||
|
if (row) {
|
||||||
|
let nowRow = 1, strArr = str.split('');
|
||||||
|
strArr.forEach((item, index) => {
|
||||||
|
if (nowRow < row && index >= nowRow * num) { nowRow++; newStr += '\n'; }
|
||||||
|
if (nowRow <= row && index < nowRow * num) { newStr += item; }
|
||||||
|
});
|
||||||
|
if (strArr.length > row * num) { newStr = newStr.substring(0, newStr.length - 1); newStr += '..'; }
|
||||||
|
}
|
||||||
|
this.send(JSON.stringify({
|
||||||
|
event: "setTitle",
|
||||||
|
context: $context,
|
||||||
|
payload: {
|
||||||
|
target: 0,
|
||||||
|
title: newStr || str
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置状态
|
||||||
|
WebSocket.prototype.setState = function (state) {
|
||||||
|
this.send(JSON.stringify({
|
||||||
|
event: "setState",
|
||||||
|
context: $context,
|
||||||
|
payload: { state }
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
// 设置背景
|
||||||
|
WebSocket.prototype.setImage = function (url) {
|
||||||
|
let image = new Image();
|
||||||
|
image.src = url;
|
||||||
|
image.onload = () => {
|
||||||
|
let canvas = document.createElement("canvas");
|
||||||
|
canvas.width = image.naturalWidth;
|
||||||
|
canvas.height = image.naturalHeight;
|
||||||
|
let ctx = canvas.getContext("2d");
|
||||||
|
ctx.drawImage(image, 0, 0);
|
||||||
|
this.send(JSON.stringify({
|
||||||
|
event: "setImage",
|
||||||
|
context: $context,
|
||||||
|
payload: {
|
||||||
|
target: 0,
|
||||||
|
image: canvas.toDataURL("image/png")
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 打开网页
|
||||||
|
WebSocket.prototype.openUrl = function (url) {
|
||||||
|
this.send(JSON.stringify({
|
||||||
|
event: "openUrl",
|
||||||
|
payload: { url }
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
// 保存持久化数据
|
||||||
|
WebSocket.prototype.saveData = $.debounce(function (payload) {
|
||||||
|
this.send(JSON.stringify({
|
||||||
|
event: "setSettings",
|
||||||
|
context: $uuid,
|
||||||
|
payload
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
// StreamDock 软件入口函数
|
||||||
|
const connectSocket = connectElgatoStreamDeckSocket;
|
||||||
|
async function connectElgatoStreamDeckSocket(port, uuid, event, app, info) {
|
||||||
|
info = JSON.parse(info);
|
||||||
|
$uuid = uuid; $action = info.action;
|
||||||
|
$context = info.context;
|
||||||
|
$websocket = new WebSocket('ws://127.0.0.1:' + port);
|
||||||
|
$websocket.onopen = () => $websocket.send(JSON.stringify({ event, uuid }));
|
||||||
|
|
||||||
|
// 持久数据代理
|
||||||
|
$websocket.onmessage = e => {
|
||||||
|
let data = JSON.parse(e.data);
|
||||||
|
if (data.event === 'didReceiveSettings') {
|
||||||
|
$settings = new Proxy(data.payload.settings, {
|
||||||
|
get(target, property) {
|
||||||
|
return target[property];
|
||||||
|
},
|
||||||
|
set(target, property, value) {
|
||||||
|
target[property] = value;
|
||||||
|
$websocket.saveData(data.payload.settings);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!$back) $dom.main.style.display = 'block';
|
||||||
|
}
|
||||||
|
$propEvent[data.event]?.(data.payload);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 自动翻译页面
|
||||||
|
if (!$local) return;
|
||||||
|
$lang = await new Promise(resolve => {
|
||||||
|
const req = new XMLHttpRequest();
|
||||||
|
req.open('GET', `../../${JSON.parse(app).application.language}.json`);
|
||||||
|
req.send();
|
||||||
|
req.onreadystatechange = () => {
|
||||||
|
if (req.readyState === 4) {
|
||||||
|
resolve(JSON.parse(req.responseText).Localization);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// 遍历文本节点并翻译所有文本节点
|
||||||
|
const walker = document.createTreeWalker($dom.main, NodeFilter.SHOW_TEXT, (e) => {
|
||||||
|
return e.data.trim() && NodeFilter.FILTER_ACCEPT;
|
||||||
|
});
|
||||||
|
while (walker.nextNode()) {
|
||||||
|
console.log(walker.currentNode.data);
|
||||||
|
walker.currentNode.data = $lang[walker.currentNode.data];
|
||||||
|
}
|
||||||
|
// placeholder 特殊处理
|
||||||
|
const translate = item => {
|
||||||
|
if (item.placeholder?.trim()) {
|
||||||
|
console.log(item.placeholder);
|
||||||
|
item.placeholder = $lang[item.placeholder];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
$('input', true).forEach(translate);
|
||||||
|
$('textarea', true).forEach(translate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// StreamDock 文件路径回调
|
||||||
|
Array.from($('input[type="file"]', true)).forEach(item => item.addEventListener('click', () => $FileID = item.id));
|
||||||
|
const onFilePickerReturn = (url) => $emit.send(`File-${$FileID}`, JSON.parse(url));
|
||||||
File diff suppressed because one or more lines are too long
+1556
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,81 @@
|
|||||||
|
// 自定义事件类
|
||||||
|
class EventPlus {
|
||||||
|
constructor() {
|
||||||
|
this.event = new EventTarget();
|
||||||
|
}
|
||||||
|
on(name, callback) {
|
||||||
|
this.event.addEventListener(name, e => callback(e.detail));
|
||||||
|
}
|
||||||
|
send(name, data) {
|
||||||
|
this.event.dispatchEvent(new CustomEvent(name, {
|
||||||
|
detail: data,
|
||||||
|
bubbles: false,
|
||||||
|
cancelable: false
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 补零
|
||||||
|
String.prototype.fill = function () {
|
||||||
|
return this >= 10 ? this : '0' + this;
|
||||||
|
};
|
||||||
|
|
||||||
|
// unicode编码转换字符串
|
||||||
|
String.prototype.uTs = function () {
|
||||||
|
return eval('"' + Array.from(this).join('') + '"');
|
||||||
|
};
|
||||||
|
|
||||||
|
// 字符串转换unicode编码
|
||||||
|
String.prototype.sTu = function (str = '') {
|
||||||
|
Array.from(this).forEach(item => str += `\\u${item.charCodeAt(0).toString(16)}`);
|
||||||
|
return str;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 全局变量/方法
|
||||||
|
const $emit = new EventPlus(), $ = (selector, isAll = false) => {
|
||||||
|
const element = document.querySelector(selector), methods = {
|
||||||
|
on: function (event, callback) {
|
||||||
|
this.addEventListener(event, callback);
|
||||||
|
},
|
||||||
|
attr: function (name, value = '') {
|
||||||
|
value && this.setAttribute(name, value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (!isAll && element) {
|
||||||
|
return Object.assign(element, methods);
|
||||||
|
} else if (!isAll && !element) {
|
||||||
|
throw `HTML没有 ${selector} 元素! 请检查是否拼写错误`;
|
||||||
|
}
|
||||||
|
return Array.from(document.querySelectorAll(selector)).map(item => Object.assign(item, methods));
|
||||||
|
};
|
||||||
|
|
||||||
|
// 节流函数
|
||||||
|
$.throttle = (fn, delay) => {
|
||||||
|
let Timer = null;
|
||||||
|
return function () {
|
||||||
|
if (Timer) return;
|
||||||
|
Timer = setTimeout(() => {
|
||||||
|
fn.apply(this, arguments);
|
||||||
|
Timer = null;
|
||||||
|
}, delay);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 防抖函数
|
||||||
|
$.debounce = (fn, delay) => {
|
||||||
|
let Timer = null;
|
||||||
|
return function () {
|
||||||
|
clearTimeout(Timer);
|
||||||
|
Timer = setTimeout(() => fn.apply(this, arguments), delay);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 绑定限制数字方法
|
||||||
|
Array.from($('input[type="num"]', true)).forEach(item => {
|
||||||
|
item.addEventListener('input', function limitNum() {
|
||||||
|
if (!item.value || /^\d+$/.test(item.value)) return;
|
||||||
|
item.value = item.value.slice(0, -1);
|
||||||
|
limitNum(item);
|
||||||
|
});
|
||||||
|
});
|
||||||
Binary file not shown.
BIN
Binary file not shown.
@@ -1 +1 @@
|
|||||||
<svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Codex</title><path d="M19.503 0H4.496A4.496 4.496 0 000 4.496v15.007A4.496 4.496 0 004.496 24h15.007A4.496 4.496 0 0024 19.503V4.496A4.496 4.496 0 0019.503 0z" fill="#fff"></path><path d="M9.064 3.344a4.578 4.578 0 012.285-.312c1 .115 1.891.54 2.673 1.275.01.01.024.017.037.021a.09.09 0 00.043 0 4.55 4.55 0 013.046.275l.047.022.116.057a4.581 4.581 0 012.188 2.399c.209.51.313 1.041.315 1.595a4.24 4.24 0 01-.134 1.223.123.123 0 00.03.115c.594.607.988 1.33 1.183 2.17.289 1.425-.007 2.71-.887 3.854l-.136.166a4.548 4.548 0 01-2.201 1.388.123.123 0 00-.081.076c-.191.551-.383 1.023-.74 1.494-.9 1.187-2.222 1.846-3.711 1.838-1.187-.006-2.239-.44-3.157-1.302a.107.107 0 00-.105-.024c-.388.125-.78.143-1.204.138a4.441 4.441 0 01-1.945-.466 4.544 4.544 0 01-1.61-1.335c-.152-.202-.303-.392-.414-.617a5.81 5.81 0 01-.37-.961 4.582 4.582 0 01-.014-2.298.124.124 0 00.006-.056.085.085 0 00-.027-.048 4.467 4.467 0 01-1.034-1.651 3.896 3.896 0 01-.251-1.192 5.189 5.189 0 01.141-1.6c.337-1.112.982-1.985 1.933-2.618.212-.141.413-.251.601-.33.215-.089.43-.164.646-.227a.098.098 0 00.065-.066 4.51 4.51 0 01.829-1.615 4.535 4.535 0 011.837-1.388zm3.482 10.565a.637.637 0 000 1.272h3.636a.637.637 0 100-1.272h-3.636zM8.462 9.23a.637.637 0 00-1.106.631l1.272 2.224-1.266 2.136a.636.636 0 101.095.649l1.454-2.455a.636.636 0 00.005-.64L8.462 9.23z" fill="url(#lobe-icons-codex-_R_0_)"></path><defs><linearGradient gradientUnits="userSpaceOnUse" id="lobe-icons-codex-_R_0_" x1="12" x2="12" y1="3" y2="21"><stop stop-color="#B1A7FF"></stop><stop offset=".5" stop-color="#7A9DFF"></stop><stop offset="1" stop-color="#3941FF"></stop></linearGradient></defs></svg>
|
<svg fill="none" height="2500" viewBox="0 0 24 24" width="2500" xmlns="http://www.w3.org/2000/svg"><title>Codex</title><path d="M19.503 0H4.496A4.496 4.496 0 000 4.496v15.007A4.496 4.496 0 004.496 24h15.007A4.496 4.496 0 0024 19.503V4.496A4.496 4.496 0 0019.503 0z" fill="#fff"></path><path d="M9.064 3.344a4.578 4.578 0 012.285-.312c1 .115 1.891.54 2.673 1.275.01.01.024.017.037.021a.09.09 0 00.043 0 4.55 4.55 0 013.046.275l.047.022.116.057a4.581 4.581 0 012.188 2.399c.209.51.313 1.041.315 1.595a4.24 4.24 0 01-.134 1.223.123.123 0 00.03.115c.594.607.988 1.33 1.183 2.17.289 1.425-.007 2.71-.887 3.854l-.136.166a4.548 4.548 0 01-2.201 1.388.123.123 0 00-.081.076c-.191.551-.383 1.023-.74 1.494-.9 1.187-2.222 1.846-3.711 1.838-1.187-.006-2.239-.44-3.157-1.302a.107.107 0 00-.105-.024c-.388.125-.78.143-1.204.138a4.441 4.441 0 01-1.945-.466 4.544 4.544 0 01-1.61-1.335c-.152-.202-.303-.392-.414-.617a5.81 5.81 0 01-.37-.961 4.582 4.582 0 01-.014-2.298.124.124 0 00.006-.056.085.085 0 00-.027-.048 4.467 4.467 0 01-1.034-1.651 3.896 3.896 0 01-.251-1.192 5.189 5.189 0 01.141-1.6c.337-1.112.982-1.985 1.933-2.618.212-.141.413-.251.601-.33.215-.089.43-.164.646-.227a.098.098 0 00.065-.066 4.51 4.51 0 01.829-1.615 4.535 4.535 0 011.837-1.388zm3.482 10.565a.637.637 0 000 1.272h3.636a.637.637 0 100-1.272h-3.636zM8.462 9.23a.637.637 0 00-1.106.631l1.272 2.224-1.266 2.136a.636.636 0 101.095.649l1.454-2.455a.636.636 0 00.005-.64L8.462 9.23z" fill="url(#lobe-icons-codex-_R_0_)"></path><defs><linearGradient gradientUnits="userSpaceOnUse" id="lobe-icons-codex-_R_0_" x1="12" x2="12" y1="3" y2="21"><stop stop-color="#B1A7FF"></stop><stop offset=".5" stop-color="#7A9DFF"></stop><stop offset="1" stop-color="#3941FF"></stop></linearGradient></defs></svg>
|
||||||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Reference in New Issue
Block a user