opencube 0.2.0 → 0.2.1
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 +1 -1
- package/src/main.js +138 -14
- package/src/plugin-server.cjs +30 -0
package/package.json
CHANGED
package/src/main.js
CHANGED
|
@@ -26,6 +26,7 @@ let interactionEvents = []
|
|
|
26
26
|
let petSignals = []
|
|
27
27
|
let sessionMap = new Map()
|
|
28
28
|
let activeToolsBySession = new Map()
|
|
29
|
+
let pendingPermissionsByRequest = new Map()
|
|
29
30
|
let cleanupTimer = null
|
|
30
31
|
let dragState = null
|
|
31
32
|
|
|
@@ -131,6 +132,7 @@ function recordEvent(event) {
|
|
|
131
132
|
}
|
|
132
133
|
applySessionEvent(item)
|
|
133
134
|
applyToolEvent(item)
|
|
135
|
+
applyPermissionEvent(item)
|
|
134
136
|
if (item.type === "hello" || item.type === "fancy_hello") {
|
|
135
137
|
petSignals.push({
|
|
136
138
|
id: item.id,
|
|
@@ -148,6 +150,36 @@ function recordEvent(event) {
|
|
|
148
150
|
return item
|
|
149
151
|
}
|
|
150
152
|
|
|
153
|
+
function applyPermissionEvent(event) {
|
|
154
|
+
if (!event || typeof event.sessionID !== "string") return
|
|
155
|
+
|
|
156
|
+
if (event.type === "permission.ask") {
|
|
157
|
+
const requestID = typeof event.requestID === "string" ? event.requestID : event.id
|
|
158
|
+
if (!requestID) return
|
|
159
|
+
pendingPermissionsByRequest.set(requestID, {
|
|
160
|
+
requestID,
|
|
161
|
+
sessionID: event.sessionID,
|
|
162
|
+
permission: event.permission,
|
|
163
|
+
patterns: event.patterns,
|
|
164
|
+
metadata: event.metadata,
|
|
165
|
+
always: event.always,
|
|
166
|
+
tool: event.tool,
|
|
167
|
+
askedAt: event.receivedAt || Date.now(),
|
|
168
|
+
})
|
|
169
|
+
return
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (event.type === "permission.reply") {
|
|
173
|
+
if (typeof event.requestID === "string") pendingPermissionsByRequest.delete(event.requestID)
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function clearPendingPermissionsForSession(sessionID) {
|
|
178
|
+
for (const [requestID, permission] of pendingPermissionsByRequest) {
|
|
179
|
+
if (permission?.sessionID === sessionID) pendingPermissionsByRequest.delete(requestID)
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
151
183
|
function applyToolEvent(event) {
|
|
152
184
|
if (!event || typeof event.sessionID !== "string" || typeof event.callID !== "string") return
|
|
153
185
|
if (event.type !== "tool.start" && event.type !== "tool.finish") return
|
|
@@ -204,6 +236,7 @@ function applySessionEvent(event) {
|
|
|
204
236
|
|
|
205
237
|
if (event.type === "session.idle") {
|
|
206
238
|
activeToolsBySession.delete(event.sessionID)
|
|
239
|
+
clearPendingPermissionsForSession(event.sessionID)
|
|
207
240
|
sessionMap.set(event.sessionID, {
|
|
208
241
|
sessionID: event.sessionID,
|
|
209
242
|
state: "idle",
|
|
@@ -225,6 +258,7 @@ function pruneIdleSessions(refresh = true) {
|
|
|
225
258
|
if (session.state === "idle" && expiresFrom && now - expiresFrom > IDLE_TTL_MS) {
|
|
226
259
|
sessionMap.delete(sessionID)
|
|
227
260
|
activeToolsBySession.delete(sessionID)
|
|
261
|
+
clearPendingPermissionsForSession(sessionID)
|
|
228
262
|
changed = true
|
|
229
263
|
}
|
|
230
264
|
}
|
|
@@ -259,6 +293,7 @@ function getPetState() {
|
|
|
259
293
|
idleIndex: session.state === "idle" ? idleIndex++ : undefined,
|
|
260
294
|
color: DEFAULT_SESSION_COLORS[index % DEFAULT_SESSION_COLORS.length],
|
|
261
295
|
})),
|
|
296
|
+
permissions: Array.from(pendingPermissionsByRequest.values()),
|
|
262
297
|
signals: petSignals,
|
|
263
298
|
}
|
|
264
299
|
}
|
|
@@ -678,6 +713,7 @@ function petHtml3D() {
|
|
|
678
713
|
const colorReleaseSpeed = 90
|
|
679
714
|
const faceMeshes = new Map()
|
|
680
715
|
const glowMeshes = new Map()
|
|
716
|
+
const permissionGlowMeshes = new Map()
|
|
681
717
|
let snapshot = window.__PET_STATE || { sessions: [] }
|
|
682
718
|
let lastFrame = performance.now()
|
|
683
719
|
let rotation = { x: -14, y: -28, z: 0 }
|
|
@@ -723,6 +759,7 @@ function petHtml3D() {
|
|
|
723
759
|
const dragParticleTexture = createDragParticleTexture()
|
|
724
760
|
const faceGeometry = new THREE.PlaneGeometry(0.60, 0.60)
|
|
725
761
|
const glowGeometry = new THREE.PlaneGeometry(1.18, 1.18)
|
|
762
|
+
const permissionGlowGeometry = new THREE.PlaneGeometry(1.42, 1.42)
|
|
726
763
|
const rad = THREE.MathUtils.degToRad
|
|
727
764
|
|
|
728
765
|
function createGlowTexture() {
|
|
@@ -763,6 +800,8 @@ function petHtml3D() {
|
|
|
763
800
|
const dragParticles = []
|
|
764
801
|
const toolParticles = []
|
|
765
802
|
const toolEmitAccumulators = new Map()
|
|
803
|
+
const toolEmissionStates = new Map()
|
|
804
|
+
const toolEmissionHoldMs = 2000
|
|
766
805
|
const faceVectors = {
|
|
767
806
|
front: { position: new THREE.Vector3(0, 0, 0.34), normal: new THREE.Vector3(0, 0, 1) },
|
|
768
807
|
back: { position: new THREE.Vector3(0, 0, -0.34), normal: new THREE.Vector3(0, 0, -1) },
|
|
@@ -855,25 +894,61 @@ function petHtml3D() {
|
|
|
855
894
|
return true
|
|
856
895
|
}
|
|
857
896
|
|
|
858
|
-
function updateToolParticles(sessions, dt) {
|
|
859
|
-
const
|
|
860
|
-
const
|
|
897
|
+
function updateToolParticles(sessions, dt, now) {
|
|
898
|
+
const activeIDs = new Set()
|
|
899
|
+
const emitters = []
|
|
900
|
+
const busyIDs = new Set(
|
|
901
|
+
sessions
|
|
902
|
+
.filter((session) => session?.state === "busy" && typeof session.sessionID === "string")
|
|
903
|
+
.map((session) => session.sessionID),
|
|
904
|
+
)
|
|
905
|
+
|
|
906
|
+
for (const session of sessions) {
|
|
907
|
+
if (session?.state !== "busy" || typeof session.sessionID !== "string" || !session.activeTools?.length) continue
|
|
908
|
+
const currentState = toolEmissionStates.get(session.sessionID)
|
|
909
|
+
const faceName = sessionFaceMap.get(session.sessionID) || currentState?.faceName
|
|
910
|
+
if (!faceName) continue
|
|
911
|
+
const color = sessionColorMap.get(session.sessionID) || currentState?.color || randomSessionGlowColor()
|
|
912
|
+
|
|
913
|
+
activeIDs.add(session.sessionID)
|
|
914
|
+
toolEmissionStates.set(session.sessionID, {
|
|
915
|
+
faceName,
|
|
916
|
+
color,
|
|
917
|
+
holdUntil: now + toolEmissionHoldMs,
|
|
918
|
+
})
|
|
919
|
+
emitters.push({ sessionID: session.sessionID, faceName, color, held: false, holdRemainingMs: toolEmissionHoldMs })
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
for (const [sessionID, state] of Array.from(toolEmissionStates.entries())) {
|
|
923
|
+
if (activeIDs.has(sessionID)) continue
|
|
924
|
+
if (!busyIDs.has(sessionID) || !state?.faceName || state.holdUntil <= now) {
|
|
925
|
+
toolEmissionStates.delete(sessionID)
|
|
926
|
+
toolEmitAccumulators.delete(sessionID)
|
|
927
|
+
continue
|
|
928
|
+
}
|
|
929
|
+
emitters.push({
|
|
930
|
+
sessionID,
|
|
931
|
+
faceName: state.faceName,
|
|
932
|
+
color: state.color || randomSessionGlowColor(),
|
|
933
|
+
held: true,
|
|
934
|
+
holdRemainingMs: state.holdUntil - now,
|
|
935
|
+
})
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
const emittingIDs = new Set(emitters.map((emitter) => emitter.sessionID))
|
|
861
939
|
for (const sessionID of Array.from(toolEmitAccumulators.keys())) {
|
|
862
|
-
if (!
|
|
940
|
+
if (!emittingIDs.has(sessionID)) toolEmitAccumulators.delete(sessionID)
|
|
863
941
|
}
|
|
864
942
|
|
|
865
|
-
for (const
|
|
866
|
-
const faceName = sessionFaceMap.get(session.sessionID)
|
|
867
|
-
if (!faceName) continue
|
|
868
|
-
const color = sessionColorMap.get(session.sessionID) || randomSessionGlowColor()
|
|
943
|
+
for (const emitter of emitters) {
|
|
869
944
|
const jitterRate = randomBetween(7.5, 11.5)
|
|
870
|
-
const next = (toolEmitAccumulators.get(
|
|
945
|
+
const next = (toolEmitAccumulators.get(emitter.sessionID) || 0) + dt * jitterRate
|
|
871
946
|
let accumulator = next
|
|
872
947
|
while (accumulator >= 1) {
|
|
873
|
-
if (!emitToolParticle(faceName, color)) break
|
|
948
|
+
if (!emitToolParticle(emitter.faceName, emitter.color)) break
|
|
874
949
|
accumulator -= 1
|
|
875
950
|
}
|
|
876
|
-
toolEmitAccumulators.set(
|
|
951
|
+
toolEmitAccumulators.set(emitter.sessionID, accumulator)
|
|
877
952
|
}
|
|
878
953
|
|
|
879
954
|
let activeCount = 0
|
|
@@ -895,8 +970,9 @@ function petHtml3D() {
|
|
|
895
970
|
particle.scale.setScalar(data.size * (1.02 + age * 0.42))
|
|
896
971
|
particle.material.opacity = Math.min(1, 0.24 + Math.sin(age * Math.PI) * 1.18)
|
|
897
972
|
}
|
|
898
|
-
|
|
899
|
-
|
|
973
|
+
const heldSessions = emitters.filter((emitter) => emitter.held).length
|
|
974
|
+
toolParticleGroup.visible = activeCount > 0 || emitters.length > 0
|
|
975
|
+
return { activeSessions: activeIDs.size, emittingSessions: emitters.length, heldSessions, activeCount }
|
|
900
976
|
}
|
|
901
977
|
|
|
902
978
|
function activeDragColors() {
|
|
@@ -1198,6 +1274,23 @@ function petHtml3D() {
|
|
|
1198
1274
|
glow.rotation.set(...rotation)
|
|
1199
1275
|
cubeGroup.add(glow)
|
|
1200
1276
|
glowMeshes.set(name, glow)
|
|
1277
|
+
|
|
1278
|
+
const permissionGlow = new THREE.Mesh(
|
|
1279
|
+
permissionGlowGeometry,
|
|
1280
|
+
new THREE.MeshBasicMaterial({
|
|
1281
|
+
map: glowTexture,
|
|
1282
|
+
color: 0xff2448,
|
|
1283
|
+
transparent: true,
|
|
1284
|
+
opacity: 0,
|
|
1285
|
+
blending: THREE.AdditiveBlending,
|
|
1286
|
+
depthWrite: false,
|
|
1287
|
+
side: THREE.DoubleSide,
|
|
1288
|
+
}),
|
|
1289
|
+
)
|
|
1290
|
+
permissionGlow.position.set(...glowPosition.map((value) => value === 0 ? 0 : value * 1.055))
|
|
1291
|
+
permissionGlow.rotation.set(...rotation)
|
|
1292
|
+
cubeGroup.add(permissionGlow)
|
|
1293
|
+
permissionGlowMeshes.set(name, permissionGlow)
|
|
1201
1294
|
}
|
|
1202
1295
|
|
|
1203
1296
|
function magnitude(vector) {
|
|
@@ -1384,6 +1477,35 @@ function petHtml3D() {
|
|
|
1384
1477
|
return active
|
|
1385
1478
|
}
|
|
1386
1479
|
|
|
1480
|
+
function applyPermissionGlowFaces(permissions, now) {
|
|
1481
|
+
const pendingSessionIDs = new Set(
|
|
1482
|
+
(permissions || [])
|
|
1483
|
+
.map((permission) => permission?.sessionID)
|
|
1484
|
+
.filter((sessionID) => typeof sessionID === "string"),
|
|
1485
|
+
)
|
|
1486
|
+
const active = {}
|
|
1487
|
+
const wave = (Math.sin(now * 0.0095) + 1) / 2
|
|
1488
|
+
const pulse = Math.pow(wave, 1.85)
|
|
1489
|
+
|
|
1490
|
+
for (const faceName of faceOrder) {
|
|
1491
|
+
const permissionGlow = permissionGlowMeshes.get(faceName)
|
|
1492
|
+
if (!permissionGlow) continue
|
|
1493
|
+
|
|
1494
|
+
const sessionID = Array.from(pendingSessionIDs).find((id) => sessionFaceMap.get(id) === faceName)
|
|
1495
|
+
if (!sessionID) {
|
|
1496
|
+
permissionGlow.material.opacity = 0
|
|
1497
|
+
continue
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
permissionGlow.material.color.setRGB(1, 0.08, 0.16)
|
|
1501
|
+
permissionGlow.material.opacity = 0.16 + pulse * 0.62
|
|
1502
|
+
permissionGlow.scale.setScalar(1.00 + pulse * 0.34)
|
|
1503
|
+
active[faceName] = { sessionID, pulse, pending: true }
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
return active
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1387
1509
|
window.__setPetState = setSnapshot
|
|
1388
1510
|
window.__getPetDebug = () => latestDebug
|
|
1389
1511
|
|
|
@@ -1440,9 +1562,10 @@ function petHtml3D() {
|
|
|
1440
1562
|
const glowB = Math.round(232 + (210 - 232) * glow)
|
|
1441
1563
|
const dragParticles = updateDragParticles(now, frictionHoldLevel, speed, dt)
|
|
1442
1564
|
const busyFaces = syncBusyFaces(sessions, speed)
|
|
1443
|
-
const toolParticles = updateToolParticles(sessions, dt)
|
|
1565
|
+
const toolParticles = updateToolParticles(sessions, dt, now)
|
|
1444
1566
|
processSignals(snapshot.signals || [], now)
|
|
1445
1567
|
const helloFlashes = applyFlashFaces(now)
|
|
1568
|
+
const permissionGlows = applyPermissionGlowFaces(snapshot.permissions || [], now)
|
|
1446
1569
|
renderCube()
|
|
1447
1570
|
latestDebug = {
|
|
1448
1571
|
now: Date.now(),
|
|
@@ -1472,6 +1595,7 @@ function petHtml3D() {
|
|
|
1472
1595
|
faceRotations,
|
|
1473
1596
|
busyFaces,
|
|
1474
1597
|
helloFlashes,
|
|
1598
|
+
permissionGlows,
|
|
1475
1599
|
}
|
|
1476
1600
|
requestAnimationFrame(tick)
|
|
1477
1601
|
}
|
package/src/plugin-server.cjs
CHANGED
|
@@ -139,6 +139,36 @@ module.exports = {
|
|
|
139
139
|
},
|
|
140
140
|
|
|
141
141
|
event: async ({ event }) => {
|
|
142
|
+
if (event.type === "permission.asked") {
|
|
143
|
+
const permission = event.properties || {}
|
|
144
|
+
await sendEvent({
|
|
145
|
+
type: "permission.ask",
|
|
146
|
+
message: "opencode is waiting for permission",
|
|
147
|
+
sessionID: permission.sessionID,
|
|
148
|
+
requestID: permission.id,
|
|
149
|
+
permission: permission.permission,
|
|
150
|
+
patterns: permission.patterns,
|
|
151
|
+
metadata: permission.metadata,
|
|
152
|
+
always: permission.always,
|
|
153
|
+
tool: permission.tool,
|
|
154
|
+
source: "opencube-plugin",
|
|
155
|
+
})
|
|
156
|
+
return
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (event.type === "permission.replied") {
|
|
160
|
+
const permission = event.properties || {}
|
|
161
|
+
await sendEvent({
|
|
162
|
+
type: "permission.reply",
|
|
163
|
+
message: "opencode permission was answered",
|
|
164
|
+
sessionID: permission.sessionID,
|
|
165
|
+
requestID: permission.requestID,
|
|
166
|
+
reply: permission.reply,
|
|
167
|
+
source: "opencube-plugin",
|
|
168
|
+
})
|
|
169
|
+
return
|
|
170
|
+
}
|
|
171
|
+
|
|
142
172
|
if (event.type !== "session.status") return
|
|
143
173
|
|
|
144
174
|
const sessionID = event.properties?.sessionID
|