@mindexec/cli 0.2.22 → 0.2.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@ import vm from 'node:vm';
|
|
|
7
7
|
import { fileURLToPath } from 'node:url';
|
|
8
8
|
import { createRemoteHub } from '../remote-hub.js';
|
|
9
9
|
|
|
10
|
-
const SYNTHETIC_COUNT = Number(process.env.REMOTE_FLEET_RENDER_SMOKE_COUNT ||
|
|
10
|
+
const SYNTHETIC_COUNT = Number(process.env.REMOTE_FLEET_RENDER_SMOKE_COUNT || 500);
|
|
11
11
|
|
|
12
12
|
function dataAttributeToDatasetKey(name) {
|
|
13
13
|
return String(name || '').replace(/^data-/, '').replace(/-([a-z])/g, (_, char) => char.toUpperCase());
|
|
@@ -627,6 +627,18 @@ try {
|
|
|
627
627
|
};
|
|
628
628
|
}
|
|
629
629
|
|
|
630
|
+
if (methodName === 'DispatchRemoteFleetTaskFromJs') {
|
|
631
|
+
const useAiAssist = args[3] === true;
|
|
632
|
+
const total = useAiAssist ? aiCount : connectedCount;
|
|
633
|
+
return {
|
|
634
|
+
success: true,
|
|
635
|
+
total,
|
|
636
|
+
queued: total,
|
|
637
|
+
failed: 0,
|
|
638
|
+
approvalLevel: useAiAssist ? 'ai-assist' : 'task-only'
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
|
|
630
642
|
return { success: true };
|
|
631
643
|
}
|
|
632
644
|
};
|
|
@@ -717,6 +729,47 @@ try {
|
|
|
717
729
|
assert.match(feedback.textContent, new RegExp(`Queued ${connectedCount - 1}/${connectedCount} visible remote task\\(s\\); 1 failed`));
|
|
718
730
|
assert.match(feedback.textContent, /device-ai-assist-unavailable/);
|
|
719
731
|
|
|
732
|
+
const activeSelects = bodyView.querySelectorAll('select');
|
|
733
|
+
assert.equal(activeSelects.length, 4);
|
|
734
|
+
const [aiFilterSelect] = activeSelects;
|
|
735
|
+
const aiToggle = bodyView.querySelector('[data-remote-fleet-ai-toggle="true"]');
|
|
736
|
+
assert.ok(aiToggle);
|
|
737
|
+
aiFilterSelect.value = 'ai';
|
|
738
|
+
aiFilterSelect.dispatchEvent({ type: 'change' });
|
|
739
|
+
aiToggle.checked = true;
|
|
740
|
+
aiToggle.dispatchEvent({ type: 'change' });
|
|
741
|
+
assert.equal(bodyView.querySelector('[data-remote-fleet-match-count="true"]')?.textContent, `${aiCount}/${SYNTHETIC_COUNT}`);
|
|
742
|
+
assert.equal(sendVisibleButton.disabled, false);
|
|
743
|
+
taskInput.value = 'Dispatch visible AI smoke';
|
|
744
|
+
const aiDispatchCallStart = dotNetCalls.length;
|
|
745
|
+
sendVisibleButton.dispatchEvent({ type: 'click' });
|
|
746
|
+
await wait();
|
|
747
|
+
const aiBatchCall = dotNetCalls
|
|
748
|
+
.slice(aiDispatchCallStart)
|
|
749
|
+
.find(call => call.methodName === 'DispatchRemoteFleetTaskBatchFromJs');
|
|
750
|
+
assert.ok(aiBatchCall);
|
|
751
|
+
const aiTargetIds = Array.isArray(aiBatchCall.args[1]) ? aiBatchCall.args[1] : [];
|
|
752
|
+
const expectedAiTargetIds = devices
|
|
753
|
+
.filter(device => device.Connected && device.AiAssistEnabled)
|
|
754
|
+
.map(device => device.DeviceId)
|
|
755
|
+
.sort();
|
|
756
|
+
assert.deepEqual([...aiTargetIds].sort(), expectedAiTargetIds);
|
|
757
|
+
assert.equal(aiBatchCall.args[3], true);
|
|
758
|
+
|
|
759
|
+
const sendConnectedButton = bodyView.querySelector('[data-remote-fleet-action="task-connected"]');
|
|
760
|
+
assert.ok(sendConnectedButton);
|
|
761
|
+
taskInput.value = 'Dispatch all AI smoke';
|
|
762
|
+
const allAiDispatchCallStart = dotNetCalls.length;
|
|
763
|
+
sendConnectedButton.dispatchEvent({ type: 'click' });
|
|
764
|
+
await wait();
|
|
765
|
+
const allAiCall = dotNetCalls
|
|
766
|
+
.slice(allAiDispatchCallStart)
|
|
767
|
+
.find(call => call.methodName === 'DispatchRemoteFleetTaskFromJs');
|
|
768
|
+
assert.ok(allAiCall);
|
|
769
|
+
assert.equal(allAiCall.args[1], '');
|
|
770
|
+
assert.equal(allAiCall.args[3], true);
|
|
771
|
+
assert.match(feedback.textContent, new RegExp(`Queued ${aiCount}/${aiCount} AI task\\(s\\)`));
|
|
772
|
+
|
|
720
773
|
const deviceBody = document.createElement('div');
|
|
721
774
|
document.body.appendChild(deviceBody);
|
|
722
775
|
manager.renderRemoteFleetDeviceForTest(deviceBody, buildDeviceNode(focusedDevice, hub.getStatus()));
|
|
@@ -8,7 +8,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
8
8
|
|
|
9
9
|
const BRIDGE_TOKEN = 'remote-http-smoke-token';
|
|
10
10
|
const PAIR_TOKEN = 'remote-http-pair-token';
|
|
11
|
-
const SYNTHETIC_COUNT = Number(process.env.REMOTE_HTTP_SMOKE_COUNT ||
|
|
11
|
+
const SYNTHETIC_COUNT = Number(process.env.REMOTE_HTTP_SMOKE_COUNT || 500);
|
|
12
12
|
|
|
13
13
|
function wait(ms) {
|
|
14
14
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
@@ -148,9 +148,9 @@ try {
|
|
|
148
148
|
|
|
149
149
|
const connectedTargets = devicesResult.payload.devices
|
|
150
150
|
.filter(device => device.connected && device.capabilities?.taskDispatch)
|
|
151
|
-
.slice(0,
|
|
151
|
+
.slice(0, 500)
|
|
152
152
|
.map(device => device.deviceId);
|
|
153
|
-
assert.ok(connectedTargets.length >=
|
|
153
|
+
assert.ok(connectedTargets.length >= 400);
|
|
154
154
|
|
|
155
155
|
const batch = await fetchJson(`${baseUrl}/api/remote/tasks`, {
|
|
156
156
|
method: 'POST',
|
|
@@ -171,6 +171,32 @@ try {
|
|
|
171
171
|
assert.equal(batch.payload?.batch?.failed, 0);
|
|
172
172
|
assert.equal(batch.payload?.batch?.status, 'completed');
|
|
173
173
|
|
|
174
|
+
const aiTargets = devicesResult.payload.devices
|
|
175
|
+
.filter(device => device.connected && device.capabilities?.taskDispatch && device.capabilities?.aiAssist)
|
|
176
|
+
.map(device => device.deviceId);
|
|
177
|
+
assert.ok(aiTargets.length >= 200);
|
|
178
|
+
const allAiBatch = await fetchJson(`${baseUrl}/api/remote/tasks`, {
|
|
179
|
+
method: 'POST',
|
|
180
|
+
token: BRIDGE_TOKEN,
|
|
181
|
+
body: JSON.stringify({
|
|
182
|
+
allConnected: true,
|
|
183
|
+
title: 'HTTP smoke all AI task batch',
|
|
184
|
+
instruction: 'HTTP smoke AI batch: summarize fleet condition only on AI-capable agents.',
|
|
185
|
+
approvalLevel: 'ai-assist'
|
|
186
|
+
})
|
|
187
|
+
});
|
|
188
|
+
assert.equal(allAiBatch.ok, true, JSON.stringify(allAiBatch.payload));
|
|
189
|
+
assert.equal(allAiBatch.payload?.ok, true);
|
|
190
|
+
assert.equal(allAiBatch.payload?.approvalLevel, 'ai-assist');
|
|
191
|
+
assert.equal(allAiBatch.payload?.total, aiTargets.length);
|
|
192
|
+
assert.equal(allAiBatch.payload?.queued, aiTargets.length);
|
|
193
|
+
assert.equal(allAiBatch.payload?.batch?.completed, aiTargets.length);
|
|
194
|
+
assert.equal(allAiBatch.payload?.batch?.failed, 0);
|
|
195
|
+
assert.equal(allAiBatch.payload?.batch?.status, 'completed');
|
|
196
|
+
assert.deepEqual(
|
|
197
|
+
[...(allAiBatch.payload?.results || []).map(result => result.deviceId)].sort(),
|
|
198
|
+
[...aiTargets].sort());
|
|
199
|
+
|
|
174
200
|
const aiTarget = devicesResult.payload.devices.find(device =>
|
|
175
201
|
device.connected && device.capabilities?.taskDispatch && device.capabilities?.aiAssist);
|
|
176
202
|
assert.ok(aiTarget);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import assert from 'assert/strict';
|
|
4
4
|
import { createRemoteHub } from '../remote-hub.js';
|
|
5
5
|
|
|
6
|
-
const SYNTHETIC_COUNT = Number(process.env.REMOTE_HUB_SCALE_SMOKE_COUNT ||
|
|
6
|
+
const SYNTHETIC_COUNT = Number(process.env.REMOTE_HUB_SCALE_SMOKE_COUNT || 500);
|
|
7
7
|
|
|
8
8
|
const hub = createRemoteHub({
|
|
9
9
|
env: {
|
|
@@ -76,8 +76,8 @@ try {
|
|
|
76
76
|
|
|
77
77
|
const connectedTargets = hub.listDevices()
|
|
78
78
|
.filter(device => device.connected && device.capabilities?.taskDispatch)
|
|
79
|
-
.slice(0,
|
|
80
|
-
assert.ok(connectedTargets.length >=
|
|
79
|
+
.slice(0, 500);
|
|
80
|
+
assert.ok(connectedTargets.length >= 400);
|
|
81
81
|
const scaleBatch = hub.requestAgentTaskBatch(connectedTargets.map(device => device.deviceId), {
|
|
82
82
|
instruction: 'Synthetic scale task: report current status to the manager.',
|
|
83
83
|
title: 'Scale task batch'
|
package/server.js
CHANGED
|
@@ -7038,15 +7038,21 @@ app.post('/api/remote/tasks', (req, res) => {
|
|
|
7038
7038
|
? req.body.deviceIds.map(value => String(value || '').trim()).filter(Boolean)
|
|
7039
7039
|
: [];
|
|
7040
7040
|
const allConnected = req.body?.allConnected !== false;
|
|
7041
|
+
const approvalLevel = req.body?.approvalLevel === 'ai-assist' ? 'ai-assist' : 'task-only';
|
|
7041
7042
|
const devices = remoteHub.listDevices();
|
|
7042
7043
|
const targetIds = requestedDeviceIds.length > 0
|
|
7043
7044
|
? requestedDeviceIds
|
|
7044
|
-
: (allConnected
|
|
7045
|
+
: (allConnected
|
|
7046
|
+
? devices
|
|
7047
|
+
.filter(device => device.connected)
|
|
7048
|
+
.filter(device => approvalLevel !== 'ai-assist' || isRemoteCapabilityEnabled(device, 'aiAssist'))
|
|
7049
|
+
.map(device => device.deviceId)
|
|
7050
|
+
: []);
|
|
7045
7051
|
const uniqueTargetIds = [...new Set(targetIds)].slice(0, 500);
|
|
7046
7052
|
const result = remoteHub.requestAgentTaskBatch(uniqueTargetIds, {
|
|
7047
7053
|
instruction: req.body?.instruction,
|
|
7048
7054
|
title: req.body?.title,
|
|
7049
|
-
approvalLevel
|
|
7055
|
+
approvalLevel,
|
|
7050
7056
|
model: req.body?.model,
|
|
7051
7057
|
batchId: req.body?.batchId
|
|
7052
7058
|
});
|
|
@@ -7055,11 +7061,24 @@ app.post('/api/remote/tasks', (req, res) => {
|
|
|
7055
7061
|
ok: result.ok === true,
|
|
7056
7062
|
total: uniqueTargetIds.length,
|
|
7057
7063
|
queued: result.queued || 0,
|
|
7058
|
-
approvalLevel
|
|
7064
|
+
approvalLevel,
|
|
7059
7065
|
error: result.ok === true ? undefined : (uniqueTargetIds.length === 0 ? 'no-target-devices' : (result.error || 'no-task-queued'))
|
|
7060
7066
|
});
|
|
7061
7067
|
});
|
|
7062
7068
|
|
|
7069
|
+
function isRemoteCapabilityEnabled(device, key) {
|
|
7070
|
+
const value = device?.capabilities?.[key];
|
|
7071
|
+
if (typeof value === 'boolean') {
|
|
7072
|
+
return value;
|
|
7073
|
+
}
|
|
7074
|
+
|
|
7075
|
+
if (typeof value === 'number') {
|
|
7076
|
+
return value !== 0;
|
|
7077
|
+
}
|
|
7078
|
+
|
|
7079
|
+
return /^(1|true|yes|on)$/i.test(String(value || '').trim());
|
|
7080
|
+
}
|
|
7081
|
+
|
|
7063
7082
|
app.get('/api/remote/devices/:deviceId/thumbnail', (req, res) => {
|
|
7064
7083
|
res.setHeader('Cache-Control', 'no-store');
|
|
7065
7084
|
const thumbnail = remoteHub.getDeviceThumbnail(req.params.deviceId);
|