@clowder-ai/companion 0.1.0-alpha.30 → 0.1.0-alpha.32
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/manifest.json +2 -2
- package/package.json +1 -1
- package/plugin.yaml +2 -2
- package/renderer/app-assist-controller.mjs +2 -1
- package/renderer/app-assist-countdown.mjs +16 -0
- package/renderer/conversation-surface.mjs +2 -3
- package/renderer/index.html +4 -0
- package/renderer/style.css +10 -1
- package/renderer/surface.mjs +3 -1
package/manifest.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"pluginId": "official.companion",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.32",
|
|
4
4
|
"contractVersion": "0.1.0",
|
|
5
5
|
"name": "猫猫球",
|
|
6
6
|
"icon": {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"bridgeVersion": "1.6.0",
|
|
41
41
|
"surface": {
|
|
42
42
|
"entrypoint": "renderer/index.html",
|
|
43
|
-
"integrity": "sha256-
|
|
43
|
+
"integrity": "sha256-0OpVp+p2y+xDJduVuzWZf48TNLBnWZZfq/TuGe0joyY="
|
|
44
44
|
},
|
|
45
45
|
"presentation": {
|
|
46
46
|
"width": 300,
|
package/package.json
CHANGED
package/plugin.yaml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"pluginId": "official.companion",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.32",
|
|
4
4
|
"contractVersion": "0.1.0",
|
|
5
5
|
"name": "猫猫球",
|
|
6
6
|
"icon": {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"bridgeVersion": "1.6.0",
|
|
41
41
|
"surface": {
|
|
42
42
|
"entrypoint": "renderer/index.html",
|
|
43
|
-
"integrity": "sha256-
|
|
43
|
+
"integrity": "sha256-0OpVp+p2y+xDJduVuzWZf48TNLBnWZZfq/TuGe0joyY="
|
|
44
44
|
},
|
|
45
45
|
"presentation": {
|
|
46
46
|
"width": 300,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const ACTIONS = new Set(['dismiss', 'timeout', 'accept']);
|
|
2
|
+
export const APP_ASSIST_TIMEOUT_MS = 15_000;
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Renderer projection only. The Host owns offer creation, expiry and clearing;
|
|
@@ -12,7 +13,7 @@ export class AppAssistController {
|
|
|
12
13
|
accepted = () => {},
|
|
13
14
|
scheduleTimeout = setTimeout,
|
|
14
15
|
cancelTimeout = clearTimeout,
|
|
15
|
-
timeoutMs =
|
|
16
|
+
timeoutMs = APP_ASSIST_TIMEOUT_MS,
|
|
16
17
|
}) {
|
|
17
18
|
this.client = client;
|
|
18
19
|
this.changed = changed;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { APP_ASSIST_TIMEOUT_MS } from './app-assist-controller.mjs';
|
|
2
|
+
|
|
3
|
+
/** Projects the existing renderer deadline without owning or extending it. */
|
|
4
|
+
export function bindAppAssistCountdown(element, durationMs = APP_ASSIST_TIMEOUT_MS) {
|
|
5
|
+
let offerRef = null;
|
|
6
|
+
element.style.setProperty('--app-assist-duration', `${durationMs}ms`);
|
|
7
|
+
return offer => {
|
|
8
|
+
const nextRef = offer?.offerRef ?? null;
|
|
9
|
+
if (nextRef === offerRef) return;
|
|
10
|
+
offerRef = nextRef;
|
|
11
|
+
element.removeAttribute('data-active');
|
|
12
|
+
if (!nextRef) return;
|
|
13
|
+
void element.getBoundingClientRect?.();
|
|
14
|
+
element.setAttribute('data-active', 'true');
|
|
15
|
+
};
|
|
16
|
+
}
|
|
@@ -6,11 +6,11 @@ import { ReplyLetterView } from './reply-letter-view.mjs';
|
|
|
6
6
|
|
|
7
7
|
/** Owns the chat panel's history, durable draft and reply-letter interaction. */
|
|
8
8
|
export class ConversationSurface {
|
|
9
|
-
constructor({ document, client, controls, bubble, transcript,
|
|
9
|
+
constructor({ document, client, controls, bubble, transcript,
|
|
10
10
|
onAccepted, retryLegacy, status, scheduleInterval = setInterval,
|
|
11
11
|
cancelInterval = clearInterval }) {
|
|
12
12
|
this.$ = id => document.getElementById(id);
|
|
13
|
-
Object.assign(this, { client, controls, bubble, transcript,
|
|
13
|
+
Object.assign(this, { client, controls, bubble, transcript,
|
|
14
14
|
onAccepted, retryLegacy, status });
|
|
15
15
|
this.scheduleInterval = (...args) => Reflect.apply(scheduleInterval, globalThis, args);
|
|
16
16
|
this.cancelInterval = (...args) => Reflect.apply(cancelInterval, globalThis, args);
|
|
@@ -140,7 +140,6 @@ export class ConversationSurface {
|
|
|
140
140
|
try {
|
|
141
141
|
const page = await this.client.readConversationPage(before === undefined ? {} : { before });
|
|
142
142
|
this.history.loadPage(page, { older });
|
|
143
|
-
void this.controls.setAmbient(this.getCallPhase() === 'idle' ? 'none' : 'actions');
|
|
144
143
|
this.$('chat-connection-status').textContent = page.status === 'stale'
|
|
145
144
|
? '聊天位置已变化 · 请重新往上翻' : '';
|
|
146
145
|
} catch (error) {
|
package/renderer/index.html
CHANGED
|
@@ -48,6 +48,10 @@
|
|
|
48
48
|
<p id="bubble-first" hidden></p><p id="bubble-second" hidden></p>
|
|
49
49
|
</section>
|
|
50
50
|
<section id="app-assist" class="floating app-assist" aria-label="应用旁的轻提示" data-candidate="true" hidden>
|
|
51
|
+
<svg id="app-assist-countdown" class="app-assist-countdown" viewBox="0 0 20 20" role="img" aria-label="提示将在约十五秒后自动收起">
|
|
52
|
+
<circle class="app-assist-countdown-track" cx="10" cy="10" r="7.5" pathLength="1"/>
|
|
53
|
+
<circle id="app-assist-countdown-progress" cx="10" cy="10" r="7.5" pathLength="1"/>
|
|
54
|
+
</svg>
|
|
51
55
|
<p>你打开了 <strong id="app-assist-name"></strong>。要我一起看吗?</p>
|
|
52
56
|
<div><button id="app-assist-dismiss" type="button">暂不</button><button id="app-assist-start" class="primary" type="button">打开通话控制</button></div>
|
|
53
57
|
</section>
|
package/renderer/style.css
CHANGED
|
@@ -79,10 +79,19 @@ button:disabled { opacity: .45; cursor: default; }
|
|
|
79
79
|
#bubble p + p { margin-top: 4px; }
|
|
80
80
|
#bubble [data-role="user"] { color: var(--cafe-text-secondary); }
|
|
81
81
|
.app-assist { width: 320px; padding: 12px; }
|
|
82
|
-
.app-assist p { margin: 0; color: var(--desktop-body); font-size: 13px; line-height: 1.5; }
|
|
82
|
+
.app-assist p { margin: 0; padding-right: 22px; color: var(--desktop-body); font-size: 13px; line-height: 1.5; }
|
|
83
83
|
.app-assist p strong { color: var(--desktop-ink); font-weight: 600; }
|
|
84
84
|
.app-assist > div { display: flex; justify-content: flex-end; gap: 6px; margin-top: 9px; }
|
|
85
85
|
.app-assist > div button { min-height: 30px; padding: 5px 10px; font-size: 12px; }
|
|
86
|
+
.app-assist-countdown { position: absolute; top: 10px; right: 10px; width: 16px; height: 16px; overflow: visible; transform: rotate(-90deg); }
|
|
87
|
+
.app-assist-countdown circle { fill: none; stroke-width: 2; }
|
|
88
|
+
.app-assist-countdown-track { stroke: var(--desktop-line-strong); }
|
|
89
|
+
#app-assist-countdown-progress { stroke: var(--desktop-muted); stroke-linecap: round; stroke-dasharray: 1; stroke-dashoffset: 0; }
|
|
90
|
+
.app-assist-countdown[data-active="true"] #app-assist-countdown-progress { animation: app-assist-expiry var(--app-assist-duration) linear forwards; }
|
|
91
|
+
@keyframes app-assist-expiry { to { stroke-dashoffset: 1; } }
|
|
92
|
+
@media (prefers-reduced-motion: reduce) {
|
|
93
|
+
.app-assist-countdown[data-active="true"] #app-assist-countdown-progress { animation-timing-function: steps(15, end); }
|
|
94
|
+
}
|
|
86
95
|
#call-bubble { width: 320px; max-height: 80px; overflow: hidden; padding: 9px 11px; pointer-events: none; }
|
|
87
96
|
#call-bubble:not(:has(p:not([hidden]))) { display: none; }
|
|
88
97
|
#call-bubble p { margin: 0; display: flex; min-width: 0; overflow: hidden; white-space: nowrap; font-size: 12px; line-height: 1.45; }
|
package/renderer/surface.mjs
CHANGED
|
@@ -24,6 +24,7 @@ import { ConversationSurface } from './conversation-surface.mjs';
|
|
|
24
24
|
import { CallControlsPresentation } from './call-controls-presentation.mjs';
|
|
25
25
|
import { CallDuration } from './call-duration.mjs';
|
|
26
26
|
import { AppAssistController } from './app-assist-controller.mjs';
|
|
27
|
+
import { bindAppAssistCountdown } from './app-assist-countdown.mjs';
|
|
27
28
|
const $ = id => document.getElementById(id);
|
|
28
29
|
const label = (id, text) => { $(id).querySelector('.label').textContent = text; };
|
|
29
30
|
const status = text => {
|
|
@@ -61,6 +62,7 @@ let previousControlPanel = 'none';
|
|
|
61
62
|
const ambientPanel = active => active ? 'actions' : appAssistOffer ? 'app-assist' : 'none';
|
|
62
63
|
const setTexts = (ids, text) => { for (const id of ids) $(id).textContent = text; };
|
|
63
64
|
const setHidden = (ids, hidden) => { for (const id of ids) $(id).hidden = hidden; };
|
|
65
|
+
const renderAppAssistCountdown = bindAppAssistCountdown($('app-assist-countdown'));
|
|
64
66
|
if (!window.clowderCompanion) {
|
|
65
67
|
$('actions').hidden = false; $('status').hidden = false;
|
|
66
68
|
status('请从 Clowder 的聊聊入口打开猫猫球');
|
|
@@ -144,6 +146,7 @@ if (!window.clowderCompanion) {
|
|
|
144
146
|
changed: value => {
|
|
145
147
|
appAssistOffer = value.offer;
|
|
146
148
|
$('app-assist-name').textContent = appAssistOffer?.appName ?? '';
|
|
149
|
+
renderAppAssistCountdown(appAssistOffer);
|
|
147
150
|
void controls.setAmbient(ambientPanel(previousPhase !== 'idle'));
|
|
148
151
|
},
|
|
149
152
|
accepted: () => {
|
|
@@ -301,7 +304,6 @@ if (!window.clowderCompanion) {
|
|
|
301
304
|
$('app-assist-start').onclick = () => { void appAssist.settle('accept'); };
|
|
302
305
|
conversationSurface = new ConversationSurface({
|
|
303
306
|
document, client, controls, bubble, transcript,
|
|
304
|
-
getCallPhase: () => conversation.phase,
|
|
305
307
|
onAccepted: () => motion.signal('received'),
|
|
306
308
|
retryLegacy: text => conversation.send(text),
|
|
307
309
|
status,
|