@lemoncat7/dsh-partner 1.6.0 → 1.7.0
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/README.md +17 -1
- package/docs/THIRD_PARTY_LICENSES.md +231 -0
- package/docs/architecture.md +23 -0
- package/lib/api/features/pendant-api.d.ts +4 -0
- package/lib/api/features/pendant-api.d.ts.map +1 -0
- package/lib/api/features/pendant-api.js +37 -0
- package/lib/api/features/pendant-api.js.map +1 -0
- package/lib/api.d.ts +2 -0
- package/lib/api.d.ts.map +1 -1
- package/lib/api.js +3 -0
- package/lib/api.js.map +1 -1
- package/lib/client-controller.d.ts +6 -1
- package/lib/client-controller.d.ts.map +1 -1
- package/lib/client-controller.js +4 -1
- package/lib/client-controller.js.map +1 -1
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +2567 -1587
- package/lib/client.js.map +4 -4
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +8 -2
- package/lib/index.js.map +1 -1
- package/lib/notifications/domain.d.ts +18 -0
- package/lib/notifications/domain.d.ts.map +1 -0
- package/lib/notifications/domain.js +2 -0
- package/lib/notifications/domain.js.map +1 -0
- package/lib/notifications/service.d.ts +15 -0
- package/lib/notifications/service.d.ts.map +1 -0
- package/lib/notifications/service.js +65 -0
- package/lib/notifications/service.js.map +1 -0
- package/lib/notifications/store.d.ts +14 -0
- package/lib/notifications/store.d.ts.map +1 -0
- package/lib/notifications/store.js +56 -0
- package/lib/notifications/store.js.map +1 -0
- package/lib/pendant/card-image.d.ts +6 -0
- package/lib/pendant/card-image.d.ts.map +1 -0
- package/lib/pendant/card-image.js +43 -0
- package/lib/pendant/card-image.js.map +1 -0
- package/lib/pendant/frame-loop.d.ts +18 -0
- package/lib/pendant/frame-loop.d.ts.map +1 -0
- package/lib/pendant/frame-loop.js +74 -0
- package/lib/pendant/frame-loop.js.map +1 -0
- package/lib/pendant/notice-motion.d.ts +12 -0
- package/lib/pendant/notice-motion.d.ts.map +1 -0
- package/lib/pendant/notice-motion.js +40 -0
- package/lib/pendant/notice-motion.js.map +1 -0
- package/lib/pendant/physics.d.ts +14 -0
- package/lib/pendant/physics.d.ts.map +1 -0
- package/lib/pendant/physics.js +29 -0
- package/lib/pendant/physics.js.map +1 -0
- package/lib/pendant/reader.d.ts +15 -0
- package/lib/pendant/reader.d.ts.map +1 -0
- package/lib/pendant/reader.js +37 -0
- package/lib/pendant/reader.js.map +1 -0
- package/lib/pendant/renderer.d.ts +24 -0
- package/lib/pendant/renderer.d.ts.map +1 -0
- package/lib/pendant/renderer.js +407 -0
- package/lib/pendant/renderer.js.map +1 -0
- package/lib/pendant/settings-panel.d.ts +2 -0
- package/lib/pendant/settings-panel.d.ts.map +1 -0
- package/lib/pendant/settings-panel.js +70 -0
- package/lib/pendant/settings-panel.js.map +1 -0
- package/lib/pendant/settings.d.ts +16 -0
- package/lib/pendant/settings.d.ts.map +1 -0
- package/lib/pendant/settings.js +18 -0
- package/lib/pendant/settings.js.map +1 -0
- package/lib/pendant/sheen.d.ts +11 -0
- package/lib/pendant/sheen.d.ts.map +1 -0
- package/lib/pendant/sheen.js +36 -0
- package/lib/pendant/sheen.js.map +1 -0
- package/lib/pendant/strap-geometry.d.ts +17 -0
- package/lib/pendant/strap-geometry.d.ts.map +1 -0
- package/lib/pendant/strap-geometry.js +69 -0
- package/lib/pendant/strap-geometry.js.map +1 -0
- package/lib/pendant/strap-preview.d.ts +5 -0
- package/lib/pendant/strap-preview.d.ts.map +1 -0
- package/lib/pendant/strap-preview.js +8 -0
- package/lib/pendant/strap-preview.js.map +1 -0
- package/lib/pendant/strap-style.d.ts +11 -0
- package/lib/pendant/strap-style.d.ts.map +1 -0
- package/lib/pendant/strap-style.js +13 -0
- package/lib/pendant/strap-style.js.map +1 -0
- package/lib/pendant/strap.d.ts +13 -0
- package/lib/pendant/strap.d.ts.map +1 -0
- package/lib/pendant/strap.js +73 -0
- package/lib/pendant/strap.js.map +1 -0
- package/lib/pendant/use-inbox.d.ts +9 -0
- package/lib/pendant/use-inbox.d.ts.map +1 -0
- package/lib/pendant/use-inbox.js +81 -0
- package/lib/pendant/use-inbox.js.map +1 -0
- package/lib/pendant/use-placement.d.ts +28 -0
- package/lib/pendant/use-placement.d.ts.map +1 -0
- package/lib/pendant/use-placement.js +108 -0
- package/lib/pendant/use-placement.js.map +1 -0
- package/lib/pendant/use-settings.d.ts +4 -0
- package/lib/pendant/use-settings.d.ts.map +1 -0
- package/lib/pendant/use-settings.js +44 -0
- package/lib/pendant/use-settings.js.map +1 -0
- package/lib/pendant/widget.d.ts +5 -0
- package/lib/pendant/widget.d.ts.map +1 -0
- package/lib/pendant/widget.js +92 -0
- package/lib/pendant/widget.js.map +1 -0
- package/lib/pendant-renderer.js +4124 -0
- package/lib/store.d.ts +2 -0
- package/lib/store.d.ts.map +1 -1
- package/lib/store.js +19 -0
- package/lib/store.js.map +1 -1
- package/lib/ui/companion-picker.d.ts +8 -0
- package/lib/ui/companion-picker.d.ts.map +1 -0
- package/lib/ui/companion-picker.js +70 -0
- package/lib/ui/companion-picker.js.map +1 -0
- package/lib/ui/task-board-panel.d.ts +4 -1
- package/lib/ui/task-board-panel.d.ts.map +1 -1
- package/lib/ui/task-board-panel.js +4 -2
- package/lib/ui/task-board-panel.js.map +1 -1
- package/package.json +9 -5
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAOlD,OAAO,EAAE,MAAM,IAAI,YAAY,EAAiB,KAAK,MAAM,IAAI,aAAa,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAOlD,OAAO,EAAE,MAAM,IAAI,YAAY,EAAiB,KAAK,MAAM,IAAI,aAAa,EAAE,MAAM,aAAa,CAAA;AAwBjG,eAAO,MAAM,MAAM,0DAAe,CAAA;AAClC,MAAM,MAAM,MAAM,GAAG,aAAa,CAAA;AAClC,cAAc,aAAa,CAAA;AAC3B,eAAO,MAAM,IAAI,gBAAgB,CAAA;AACjC,eAAO,MAAM,MAAM,UAAiJ,CAAA;AAYpK,wBAAgB,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CA4FnE"}
|
package/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { join } from 'node:path';
|
|
1
|
+
import { dirname, join } from 'node:path';
|
|
2
2
|
import { Config as ConfigSchema, resolveConfig } from './config.js';
|
|
3
3
|
import { PartnerStore } from './store.js';
|
|
4
4
|
import { PartnerCredentialVault } from './credentials.js';
|
|
@@ -20,6 +20,8 @@ import { PartnerCollaborationService } from './collaboration/service.js';
|
|
|
20
20
|
import { PartnerSchedulerService } from './scheduler/service.js';
|
|
21
21
|
import { PartnerAgentComposition } from './collaboration/composition.js';
|
|
22
22
|
import { CompanionService } from './companions/service.js';
|
|
23
|
+
import { PartnerInboxStore } from './notifications/store.js';
|
|
24
|
+
import { PartnerNoticeService } from './notifications/service.js';
|
|
23
25
|
export const Config = ConfigSchema;
|
|
24
26
|
export * from './domain.js';
|
|
25
27
|
export const name = 'dsh-partner';
|
|
@@ -29,6 +31,9 @@ export function apply(context, config) {
|
|
|
29
31
|
const resolved = resolveConfig(config);
|
|
30
32
|
ctx.effect(async () => {
|
|
31
33
|
const store = await PartnerStore.open(resolved.statePath);
|
|
34
|
+
const inbox = await PartnerInboxStore.open(join(dirname(resolved.statePath), 'partner-inbox.sqlite'));
|
|
35
|
+
const notices = new PartnerNoticeService(store, inbox, error => ctx.logger.warn(`dsh-partner inbox: ${error instanceof Error ? error.message : String(error)}`));
|
|
36
|
+
ctx.effect(() => () => { notices.close(); inbox.close(); }, 'dsh-partner.inbox');
|
|
32
37
|
const credentials = new PartnerCredentialVault(ctx.credentials);
|
|
33
38
|
const memory = new PartnerMemoryStore(resolved.defaultCwd, resolved.timeZone);
|
|
34
39
|
const concerns = new PartnerConcernStore(resolved.defaultCwd);
|
|
@@ -82,6 +87,7 @@ export function apply(context, config) {
|
|
|
82
87
|
});
|
|
83
88
|
});
|
|
84
89
|
const disposeSessionObserver = ctx.on('session/event', (session, event) => {
|
|
90
|
+
notices.observeSession(session, event);
|
|
85
91
|
void agents.observeSessionEvent(session, event).catch(error => ctx.logger.warn(`dsh-partner memory reflection failed: ${error instanceof Error ? error.message : String(error)}`));
|
|
86
92
|
void channels.observeAutonomousResult(session, event).catch(error => ctx.logger.warn(`dsh-partner autonomous delivery failed: ${error instanceof Error ? error.message : String(error)}`));
|
|
87
93
|
});
|
|
@@ -95,7 +101,7 @@ export function apply(context, config) {
|
|
|
95
101
|
const webServer = runtime.webServer ?? runtime.get('webServer');
|
|
96
102
|
if (webServer === undefined)
|
|
97
103
|
throw new Error('dsh-partner exposeWeb requires webServer');
|
|
98
|
-
disposeApi = registerPartnerApi(webServer, resolved.apiPrefix, { ctx, store, credentials, channels, agents, login, memory, concerns, heartbeat, dailyReview, skills, tasks, collaboration, scheduler, companions });
|
|
104
|
+
disposeApi = registerPartnerApi(webServer, resolved.apiPrefix, { ctx, store, credentials, channels, agents, login, memory, concerns, heartbeat, dailyReview, skills, tasks, collaboration, scheduler, companions, inbox });
|
|
99
105
|
};
|
|
100
106
|
if (ctx.inject !== undefined)
|
|
101
107
|
ctx.inject(['webServer'], mountApi);
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface PartnerNotice {
|
|
2
|
+
id: string;
|
|
3
|
+
kind: 'reply' | 'task' | 'schedule';
|
|
4
|
+
companionId: string;
|
|
5
|
+
companionName: string;
|
|
6
|
+
title: string;
|
|
7
|
+
summary: string;
|
|
8
|
+
createdAt: number;
|
|
9
|
+
readAt?: number;
|
|
10
|
+
routeId?: string;
|
|
11
|
+
sessionId?: string;
|
|
12
|
+
taskId?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface PartnerInbox {
|
|
15
|
+
items: PartnerNotice[];
|
|
16
|
+
unread: number;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=domain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domain.d.ts","sourceRoot":"","sources":["../../src/notifications/domain.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,UAAU,CAAA;IACnC,WAAW,EAAE,MAAM,CAAA;IACnB,aAAa,EAAE,MAAM,CAAA;IACrB,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AACD,MAAM,WAAW,YAAY;IAAG,KAAK,EAAE,aAAa,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domain.js","sourceRoot":"","sources":["../../src/notifications/domain.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Session, SessionEvent } from '@deepseek-ai/dsh-session';
|
|
2
|
+
import type { PartnerStore } from '../store.js';
|
|
3
|
+
import type { PartnerInboxStore } from './store.js';
|
|
4
|
+
export declare class PartnerNoticeService {
|
|
5
|
+
private readonly store;
|
|
6
|
+
private readonly inbox;
|
|
7
|
+
private readonly report;
|
|
8
|
+
private readonly stop;
|
|
9
|
+
private closed;
|
|
10
|
+
constructor(store: PartnerStore, inbox: PartnerInboxStore, report: (error: unknown) => void);
|
|
11
|
+
observeSession(session: Session, event: SessionEvent): void;
|
|
12
|
+
private recordChanges;
|
|
13
|
+
close(): void;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/notifications/service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAErE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAG/C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAEnD,qBAAa,oBAAoB;IAGnB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAAgB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAAqB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAFpH,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAY;IACjC,OAAO,CAAC,MAAM,CAAQ;gBACO,KAAK,EAAE,YAAY,EAAmB,KAAK,EAAE,iBAAiB,EAAmB,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI;IAG9I,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI;IAkB3D,OAAO,CAAC,aAAa;IAmBrB,KAAK,IAAI,IAAI;CACd"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { completedTurnEvents } from '../agent-runtime.js';
|
|
2
|
+
import { publicTaskDeliverable } from '../tasks/result.js';
|
|
3
|
+
export class PartnerNoticeService {
|
|
4
|
+
store;
|
|
5
|
+
inbox;
|
|
6
|
+
report;
|
|
7
|
+
stop;
|
|
8
|
+
closed = false;
|
|
9
|
+
constructor(store, inbox, report) {
|
|
10
|
+
this.store = store;
|
|
11
|
+
this.inbox = inbox;
|
|
12
|
+
this.report = report;
|
|
13
|
+
this.stop = store.subscribe((next, previous) => this.recordChanges(next, previous), report);
|
|
14
|
+
}
|
|
15
|
+
observeSession(session, event) {
|
|
16
|
+
if (this.closed || event.type !== 'turn/end' || event.data.reason.kind !== 'completed')
|
|
17
|
+
return;
|
|
18
|
+
try {
|
|
19
|
+
const state = this.store.snapshot();
|
|
20
|
+
const route = state.sessions.find(item => item.sessionId === session.id);
|
|
21
|
+
const companion = state.companions.find(item => item.id === route?.companionId);
|
|
22
|
+
if (!route || !companion)
|
|
23
|
+
return;
|
|
24
|
+
const events = completedTurnEvents(session.snapshotEvents(), event);
|
|
25
|
+
// Internal task/review/heartbeat turns are summarized by their terminal
|
|
26
|
+
// domain event, not surfaced as duplicate or unfinished assistant replies.
|
|
27
|
+
if (!events.some(item => item.type === 'user/message' && item.data.source.kind === 'user'))
|
|
28
|
+
return;
|
|
29
|
+
const summary = events.filter(item => item.type === 'assistant/message' && !item.data.interrupted)
|
|
30
|
+
.map(item => item.type === 'assistant/message' ? item.data.message.content.filter(block => block.type === 'text').map(block => block.type === 'text' ? block.text : '').join('\n').trim() : '')
|
|
31
|
+
.filter(Boolean).at(-1) ?? '';
|
|
32
|
+
if (!summary)
|
|
33
|
+
return;
|
|
34
|
+
this.inbox.append({ id: `reply:${session.id}:${event.data.turn}`, kind: 'reply', companionId: companion.id, companionName: companion.name, title: `${companion.name} 回复完成`, summary, createdAt: Date.now(), routeId: route.id, sessionId: session.id });
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
this.report(error);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
recordChanges(next, previous) {
|
|
41
|
+
const companions = new Map(next.companions.map(item => [item.id, item]));
|
|
42
|
+
const oldTasks = new Map(previous.tasks.map(item => [item.id, item]));
|
|
43
|
+
for (const task of next.tasks) {
|
|
44
|
+
if (!['done', 'blocked'].includes(task.status) || oldTasks.get(task.id)?.status === task.status)
|
|
45
|
+
continue;
|
|
46
|
+
const companion = companions.get(task.assigneeCompanionId ?? task.creatorCompanionId ?? '');
|
|
47
|
+
if (!companion)
|
|
48
|
+
continue;
|
|
49
|
+
this.inbox.append({ id: `task:${task.id}:${task.revision}:${task.status}`, kind: 'task', companionId: companion.id, companionName: companion.name,
|
|
50
|
+
title: `${task.status === 'done' ? '已完成' : '遇到阻塞'} · ${task.title}`, summary: task.resultAbstract || publicTaskDeliverable(task.resultSummary ?? '') || (task.status === 'done' ? '任务已完成,点击查看任务详情。' : '任务遇到阻塞,请查看任务详情。'), createdAt: task.updatedAt, taskId: task.id });
|
|
51
|
+
}
|
|
52
|
+
const oldRuns = new Map(previous.executionRuns.map(item => [item.id, item.status]));
|
|
53
|
+
for (const run of next.executionRuns) {
|
|
54
|
+
if (run.kind !== 'schedule' || !['completed', 'failed', 'timed-out', 'canceled'].includes(run.status) || oldRuns.get(run.id) === run.status)
|
|
55
|
+
continue;
|
|
56
|
+
const companion = companions.get(run.ownerCompanionId);
|
|
57
|
+
if (!companion)
|
|
58
|
+
continue;
|
|
59
|
+
const title = next.schedules.find(item => item.id === run.sourceId)?.title ?? '定时任务';
|
|
60
|
+
this.inbox.append({ id: `schedule:${run.id}:${run.status}`, kind: 'schedule', companionId: companion.id, companionName: companion.name, title: `${run.status === 'completed' ? '已完成' : '未完成'} · ${title}`, summary: run.outputSummary || run.error || '执行已结束,可到定时任务中查看记录。', createdAt: run.completedAt ?? Date.now() });
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
close() { this.closed = true; this.stop(); }
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/notifications/service.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AAG1D,MAAM,OAAO,oBAAoB;IAGF;IAAsC;IAA2C;IAF7F,IAAI,CAAY;IACzB,MAAM,GAAG,KAAK,CAAA;IACtB,YAA6B,KAAmB,EAAmB,KAAwB,EAAmB,MAAgC;QAAjH,UAAK,GAAL,KAAK,CAAc;QAAmB,UAAK,GAAL,KAAK,CAAmB;QAAmB,WAAM,GAAN,MAAM,CAA0B;QAC5I,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAA;IAC7F,CAAC;IACD,cAAc,CAAC,OAAgB,EAAE,KAAmB;QAClD,IAAI,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,WAAW;YAAE,OAAM;QAC9F,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAA;YACnC,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,KAAK,OAAO,CAAC,EAAE,CAAC,CAAA;YACxE,MAAM,SAAS,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,KAAK,EAAE,WAAW,CAAC,CAAA;YAC/E,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS;gBAAE,OAAM;YAChC,MAAM,MAAM,GAAG,mBAAmB,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,KAAK,CAAC,CAAA;YACnE,wEAAwE;YACxE,2EAA2E;YAC3E,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,cAAc,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC;gBAAE,OAAM;YAClG,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,mBAAmB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC;iBAC/F,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBAC9L,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;YAC/B,IAAI,CAAC,OAAO;gBAAE,OAAM;YACpB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,SAAS,OAAO,CAAC,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,CAAC,EAAE,EAAE,aAAa,EAAE,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,IAAI,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAA;QACzP,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAAC,CAAC;IACxC,CAAC;IACO,aAAa,CAAC,IAAkB,EAAE,QAAsB;QAC9D,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;QACxE,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;QACrE,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9B,IAAI,CAAC,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC,MAAM;gBAAE,SAAQ;YACzG,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,mBAAmB,IAAI,IAAI,CAAC,kBAAkB,IAAI,EAAE,CAAC,CAAA;YAC3F,IAAI,CAAC,SAAS;gBAAE,SAAQ;YACxB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,QAAQ,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,CAAC,EAAE,EAAE,aAAa,EAAE,SAAS,CAAC,IAAI;gBAC/I,KAAK,EAAE,GAAG,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,MAAM,IAAI,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,cAAc,IAAI,qBAAqB,CAAC,IAAI,CAAC,aAAa,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,iBAAiB,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAA;QAC3Q,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;QACnF,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACrC,IAAI,GAAG,CAAC,IAAI,KAAK,UAAU,IAAI,CAAC,CAAC,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,GAAG,CAAC,MAAM;gBAAE,SAAQ;YACrJ,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAA;YACtD,IAAI,CAAC,SAAS;gBAAE,SAAQ;YACxB,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,QAAQ,CAAC,EAAE,KAAK,IAAI,MAAM,CAAA;YACpF,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,YAAY,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,CAAC,EAAE,EAAE,aAAa,EAAE,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,MAAM,KAAK,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,aAAa,IAAI,GAAG,CAAC,KAAK,IAAI,oBAAoB,EAAE,SAAS,EAAE,GAAG,CAAC,WAAW,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;QACzT,CAAC;IACH,CAAC;IACD,KAAK,KAAW,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAA,CAAC,CAAC;CAClD"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { PartnerInbox, PartnerNotice } from './domain.js';
|
|
2
|
+
/** A bounded inbox, not another copy of conversation or task history. */
|
|
3
|
+
export declare class PartnerInboxStore {
|
|
4
|
+
private readonly db;
|
|
5
|
+
private revision;
|
|
6
|
+
get etag(): string;
|
|
7
|
+
private constructor();
|
|
8
|
+
static open(path: string): Promise<PartnerInboxStore>;
|
|
9
|
+
append(item: PartnerNotice): void;
|
|
10
|
+
snapshot(): PartnerInbox;
|
|
11
|
+
markRead(ids: string[], at?: number): void;
|
|
12
|
+
close(): void;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/notifications/store.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE9D,yEAAyE;AACzE,qBAAa,iBAAiB;IAGR,OAAO,CAAC,QAAQ,CAAC,EAAE;IAFvC,OAAO,CAAC,QAAQ,CAAa;IAC7B,IAAI,IAAI,IAAI,MAAM,CAA8C;IAChE,OAAO;WACM,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAS3D,MAAM,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI;IAQjC,QAAQ,IAAI,YAAY;IAKxB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,SAAa,GAAG,IAAI;IAM9C,KAAK,IAAI,IAAI;CACd"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
import { chmod, mkdir } from 'node:fs/promises';
|
|
3
|
+
import { dirname } from 'node:path';
|
|
4
|
+
/** A bounded inbox, not another copy of conversation or task history. */
|
|
5
|
+
export class PartnerInboxStore {
|
|
6
|
+
db;
|
|
7
|
+
revision = Date.now();
|
|
8
|
+
get etag() { return `"partner-inbox-${this.revision}"`; }
|
|
9
|
+
constructor(db) {
|
|
10
|
+
this.db = db;
|
|
11
|
+
}
|
|
12
|
+
static async open(path) {
|
|
13
|
+
await mkdir(dirname(path), { recursive: true, mode: 0o700 });
|
|
14
|
+
const db = new DatabaseSync(path);
|
|
15
|
+
try {
|
|
16
|
+
await chmod(path, 0o600);
|
|
17
|
+
db.exec('PRAGMA busy_timeout=3000; CREATE TABLE IF NOT EXISTS notices (id TEXT PRIMARY KEY, created_at INTEGER NOT NULL, read_at INTEGER, payload TEXT NOT NULL); CREATE INDEX IF NOT EXISTS notices_time ON notices(created_at DESC);');
|
|
18
|
+
return new PartnerInboxStore(db);
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
db.close();
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
append(item) {
|
|
26
|
+
if (!item.id || !item.summary.trim())
|
|
27
|
+
return;
|
|
28
|
+
const payload = { ...item, title: item.title.slice(0, 200), summary: item.summary.slice(0, 2000) };
|
|
29
|
+
delete payload.readAt;
|
|
30
|
+
const result = this.db.prepare('INSERT OR IGNORE INTO notices(id, created_at, payload) VALUES (?, ?, ?)').run(item.id, item.createdAt, JSON.stringify(payload));
|
|
31
|
+
if (result.changes)
|
|
32
|
+
this.revision++;
|
|
33
|
+
this.db.prepare('DELETE FROM notices WHERE id NOT IN (SELECT id FROM notices ORDER BY created_at DESC, id DESC LIMIT 200)').run();
|
|
34
|
+
}
|
|
35
|
+
snapshot() {
|
|
36
|
+
const rows = this.db.prepare('SELECT payload, read_at FROM notices ORDER BY created_at DESC, id DESC LIMIT 200').all();
|
|
37
|
+
const items = rows.map(row => ({ ...JSON.parse(String(row.payload)), ...(row.read_at === null ? {} : { readAt: Number(row.read_at) }) }));
|
|
38
|
+
return { items, unread: items.filter(item => item.readAt === undefined).length };
|
|
39
|
+
}
|
|
40
|
+
markRead(ids, at = Date.now()) {
|
|
41
|
+
const update = this.db.prepare('UPDATE notices SET read_at = COALESCE(read_at, ?) WHERE id = ?');
|
|
42
|
+
this.db.exec('BEGIN');
|
|
43
|
+
try {
|
|
44
|
+
for (const id of ids.slice(0, 200))
|
|
45
|
+
update.run(at, id);
|
|
46
|
+
this.db.exec('COMMIT');
|
|
47
|
+
this.revision++;
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
this.db.exec('ROLLBACK');
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
close() { this.db.close(); }
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/notifications/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare function loadCardImage(source: string): Promise<HTMLImageElement>;
|
|
2
|
+
/** Decode once on explicit upload; flatten and resize before persisting. No
|
|
3
|
+
* remote URLs, SVG execution, server upload or full-size GPU textures.
|
|
4
|
+
*/
|
|
5
|
+
export declare function prepareCardImage(file: File): Promise<string>;
|
|
6
|
+
//# sourceMappingURL=card-image.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card-image.d.ts","sourceRoot":"","sources":["../../src/pendant/card-image.ts"],"names":[],"mappings":"AAEA,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAOvE;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAkBlE"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { MAX_CARD_IMAGE_LENGTH } from './settings.js';
|
|
2
|
+
export function loadCardImage(source) {
|
|
3
|
+
return new Promise((resolve, reject) => {
|
|
4
|
+
const image = new Image();
|
|
5
|
+
image.onload = () => { image.onload = image.onerror = null; resolve(image); };
|
|
6
|
+
image.onerror = () => { image.onload = image.onerror = null; reject(new Error('图片无法解码,请重新选择 PNG、JPEG 或 WebP 图片。')); };
|
|
7
|
+
image.src = source;
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
/** Decode once on explicit upload; flatten and resize before persisting. No
|
|
11
|
+
* remote URLs, SVG execution, server upload or full-size GPU textures.
|
|
12
|
+
*/
|
|
13
|
+
export async function prepareCardImage(file) {
|
|
14
|
+
if (!['image/png', 'image/jpeg', 'image/webp'].includes(file.type))
|
|
15
|
+
throw new Error('请选择 PNG、JPEG 或 WebP 图片。');
|
|
16
|
+
if (file.size > 5 * 1024 * 1024)
|
|
17
|
+
throw new Error('图片不能超过 5 MB。');
|
|
18
|
+
const url = URL.createObjectURL(file);
|
|
19
|
+
try {
|
|
20
|
+
const image = await loadCardImage(url);
|
|
21
|
+
if (!image.naturalWidth || !image.naturalHeight || image.naturalWidth * image.naturalHeight > 25_000_000)
|
|
22
|
+
throw new Error('图片分辨率过大,请缩小至 2500 万像素以内。');
|
|
23
|
+
const canvas = document.createElement('canvas');
|
|
24
|
+
canvas.width = 512;
|
|
25
|
+
canvas.height = 704;
|
|
26
|
+
const context = canvas.getContext('2d');
|
|
27
|
+
if (!context)
|
|
28
|
+
throw new Error('当前浏览器无法处理图片。');
|
|
29
|
+
context.fillStyle = '#253235';
|
|
30
|
+
context.fillRect(0, 0, 512, 704);
|
|
31
|
+
const scale = Math.max(512 / image.naturalWidth, 704 / image.naturalHeight);
|
|
32
|
+
const width = image.naturalWidth * scale, height = image.naturalHeight * scale;
|
|
33
|
+
context.drawImage(image, (512 - width) / 2, (704 - height) / 2, width, height);
|
|
34
|
+
const result = canvas.toDataURL('image/jpeg', .9);
|
|
35
|
+
if (result.length > MAX_CARD_IMAGE_LENGTH)
|
|
36
|
+
throw new Error('图片压缩后仍然过大,请换一张图片。');
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
finally {
|
|
40
|
+
URL.revokeObjectURL(url);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=card-image.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card-image.js","sourceRoot":"","sources":["../../src/pendant/card-image.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type PendantFps } from './settings.js';
|
|
2
|
+
export interface FrameDriver {
|
|
3
|
+
now(): number;
|
|
4
|
+
request(callback: (now: number) => void): number;
|
|
5
|
+
cancel(id: number): void;
|
|
6
|
+
delay(callback: () => void, ms: number): number;
|
|
7
|
+
clear(id: number): void;
|
|
8
|
+
}
|
|
9
|
+
/** One coalesced configurable loop. Wake near the next deadline, then synchronize
|
|
10
|
+
* with the display; high-refresh screens do not multiply simulation/drawing.
|
|
11
|
+
* Sleeping resets elapsed simulation time, but not the frame-rate deadline.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createPendantFrameLoop(draw: (now: number, dt: number) => boolean, driver?: FrameDriver): {
|
|
14
|
+
setFps(fps: PendantFps): void;
|
|
15
|
+
wake(): void;
|
|
16
|
+
stop(): void;
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=frame-loop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frame-loop.d.ts","sourceRoot":"","sources":["../../src/pendant/frame-loop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiD,KAAK,UAAU,EAAE,MAAM,eAAe,CAAA;AAE9F,MAAM,WAAW,WAAW;IAC1B,GAAG,IAAI,MAAM,CAAA;IACb,OAAO,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,CAAA;IAChD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,KAAK,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IAC/C,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;CACxB;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,OAAO,EAAE,MAAM,GAAE,WAG1F;gBA6Be,UAAU;;;EAYzB"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { DEFAULT_PENDANT_SETTINGS, normalizePendantFps } from './settings.js';
|
|
2
|
+
/** One coalesced configurable loop. Wake near the next deadline, then synchronize
|
|
3
|
+
* with the display; high-refresh screens do not multiply simulation/drawing.
|
|
4
|
+
* Sleeping resets elapsed simulation time, but not the frame-rate deadline.
|
|
5
|
+
*/
|
|
6
|
+
export function createPendantFrameLoop(draw, driver = {
|
|
7
|
+
now: () => performance.now(), request: fn => requestAnimationFrame(fn), cancel: id => cancelAnimationFrame(id),
|
|
8
|
+
delay: (fn, ms) => window.setTimeout(fn, ms), clear: id => window.clearTimeout(id),
|
|
9
|
+
}) {
|
|
10
|
+
let running = false, frame, timer;
|
|
11
|
+
let interval = 1000 / DEFAULT_PENDANT_SETTINGS.fps;
|
|
12
|
+
let paintedAt, steppedAt, dueAt;
|
|
13
|
+
const cancelPending = () => {
|
|
14
|
+
if (frame !== undefined)
|
|
15
|
+
driver.cancel(frame);
|
|
16
|
+
if (timer !== undefined)
|
|
17
|
+
driver.clear(timer);
|
|
18
|
+
frame = timer = undefined;
|
|
19
|
+
};
|
|
20
|
+
const schedule = () => {
|
|
21
|
+
if (!running || frame !== undefined || timer !== undefined)
|
|
22
|
+
return;
|
|
23
|
+
const wait = dueAt === undefined ? 0 : dueAt - driver.now() - 8;
|
|
24
|
+
if (wait > 0)
|
|
25
|
+
timer = driver.delay(() => { timer = undefined; if (running)
|
|
26
|
+
frame = driver.request(tick); }, wait);
|
|
27
|
+
else
|
|
28
|
+
frame = driver.request(tick);
|
|
29
|
+
};
|
|
30
|
+
const tick = (now) => {
|
|
31
|
+
frame = undefined;
|
|
32
|
+
if (!running)
|
|
33
|
+
return;
|
|
34
|
+
// Fractional display timestamps need a small rounding tolerance.
|
|
35
|
+
if (dueAt !== undefined && now < dueAt - .5) {
|
|
36
|
+
schedule();
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const dt = steppedAt === undefined ? interval / 1000 : Math.min((now - steppedAt) / 1000, 1 / 15);
|
|
40
|
+
paintedAt = steppedAt = now;
|
|
41
|
+
// Retain fractional cadence (e.g. 24 FPS on 60 Hz), without catch-up bursts.
|
|
42
|
+
dueAt = (dueAt ?? now) + interval;
|
|
43
|
+
if (dueAt <= now + .5)
|
|
44
|
+
dueAt = now + interval;
|
|
45
|
+
if (draw(now, dt) && running)
|
|
46
|
+
schedule();
|
|
47
|
+
else {
|
|
48
|
+
running = false;
|
|
49
|
+
steppedAt = undefined;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
return {
|
|
53
|
+
setFps(fps) {
|
|
54
|
+
const next = 1000 / normalizePendantFps(fps);
|
|
55
|
+
if (next === interval)
|
|
56
|
+
return;
|
|
57
|
+
interval = next;
|
|
58
|
+
dueAt = paintedAt === undefined ? undefined : paintedAt + interval;
|
|
59
|
+
cancelPending();
|
|
60
|
+
if (running)
|
|
61
|
+
schedule();
|
|
62
|
+
},
|
|
63
|
+
wake() { if (!running) {
|
|
64
|
+
running = true;
|
|
65
|
+
schedule();
|
|
66
|
+
} },
|
|
67
|
+
stop() {
|
|
68
|
+
running = false;
|
|
69
|
+
steppedAt = undefined;
|
|
70
|
+
cancelPending();
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=frame-loop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frame-loop.js","sourceRoot":"","sources":["../../src/pendant/frame-loop.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type RAPIER from '@dimforge/rapier3d-compat';
|
|
2
|
+
/** One interruptible notice gesture, driven by the existing fixed physics step.
|
|
3
|
+
* Only a brief orientation assist owns angular velocity; ordinary play is free.
|
|
4
|
+
* Multiple arrivals coalesce; a held/thrown card is never seized by a notice.
|
|
5
|
+
*/
|
|
6
|
+
export declare function createNoticeMotion(badge: RAPIER.RigidBody): {
|
|
7
|
+
readonly phase: "pending" | "idle" | "turning";
|
|
8
|
+
request(): void;
|
|
9
|
+
cancel(): void;
|
|
10
|
+
step(dt: number, held: boolean): boolean;
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=notice-motion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notice-motion.d.ts","sourceRoot":"","sources":["../../src/pendant/notice-motion.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,2BAA2B,CAAA;AAEnD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,CAAC,SAAS;;;;aAM7C,MAAM,QAAQ,OAAO,GAAG,OAAO;EAuB3C"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/** One interruptible notice gesture, driven by the existing fixed physics step.
|
|
2
|
+
* Only a brief orientation assist owns angular velocity; ordinary play is free.
|
|
3
|
+
* Multiple arrivals coalesce; a held/thrown card is never seized by a notice.
|
|
4
|
+
*/
|
|
5
|
+
export function createNoticeMotion(badge) {
|
|
6
|
+
let phase = 'idle', elapsed = 0;
|
|
7
|
+
return {
|
|
8
|
+
get phase() { return phase; },
|
|
9
|
+
request() { if (phase === 'idle')
|
|
10
|
+
phase = 'pending'; },
|
|
11
|
+
cancel() { phase = 'idle'; elapsed = 0; },
|
|
12
|
+
step(dt, held) {
|
|
13
|
+
if (phase === 'idle' || held)
|
|
14
|
+
return false;
|
|
15
|
+
if (phase === 'pending') {
|
|
16
|
+
const v = badge.linvel(), a = badge.angvel();
|
|
17
|
+
if (Math.hypot(v.x, v.y, v.z) > 2 || Math.hypot(a.x, a.y, a.z) > 2)
|
|
18
|
+
return false;
|
|
19
|
+
phase = 'turning';
|
|
20
|
+
elapsed = 0;
|
|
21
|
+
badge.applyImpulse({ x: .45, y: .06, z: 0 }, true);
|
|
22
|
+
}
|
|
23
|
+
elapsed += dt;
|
|
24
|
+
const q = badge.rotation(), sign = q.w < 0 ? -1 : 1;
|
|
25
|
+
const angle = 2 * Math.acos(Math.min(1, Math.abs(q.w)));
|
|
26
|
+
// Inverse quaternion is the shortest world-space rotation to the upright
|
|
27
|
+
// art face. Angular velocity keeps Rapier and the visible card in sync.
|
|
28
|
+
const sine = Math.hypot(q.x, q.y, q.z);
|
|
29
|
+
const speed = sine > .0001 ? Math.min(3.2, angle * 7) * sign / sine : 0;
|
|
30
|
+
badge.setAngvel({ x: -q.x * speed, y: -q.y * speed, z: -q.z * speed }, true);
|
|
31
|
+
if ((angle < .025 && elapsed >= .5) || elapsed >= 2.5) {
|
|
32
|
+
phase = 'idle';
|
|
33
|
+
elapsed = 0;
|
|
34
|
+
return angle < .12; // Do not flash the wrong face if physics was disturbed.
|
|
35
|
+
}
|
|
36
|
+
return false;
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=notice-motion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notice-motion.js","sourceRoot":"","sources":["../../src/pendant/notice-motion.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAuB;IACxD,IAAI,KAAK,GAAmC,MAAM,EAAE,OAAO,GAAG,CAAC,CAAA;IAC/D,OAAO;QACL,IAAI,KAAK,KAAK,OAAO,KAAK,CAAA,CAAC,CAAC;QAC5B,OAAO,KAAK,IAAI,KAAK,KAAK,MAAM;YAAE,KAAK,GAAG,SAAS,CAAA,CAAC,CAAC;QACrD,MAAM,KAAK,KAAK,GAAG,MAAM,CAAC,CAAC,OAAO,GAAG,CAAC,CAAA,CAAC,CAAC;QACxC,IAAI,CAAC,EAAU,EAAE,IAAa;YAC5B,IAAI,KAAK,KAAK,MAAM,IAAI,IAAI;gBAAE,OAAO,KAAK,CAAA;YAC1C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAA;gBAC5C,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;oBAAE,OAAO,KAAK,CAAA;gBAChF,KAAK,GAAG,SAAS,CAAC;gBAAC,OAAO,GAAG,CAAC,CAAA;gBAC9B,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,IAAI,CAAC,CAAA;YACpD,CAAC;YACD,OAAO,IAAI,EAAE,CAAA;YACb,MAAM,CAAC,GAAG,KAAK,CAAC,QAAQ,EAAE,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YACnD,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YACvD,yEAAyE;YACzE,wEAAwE;YACxE,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;YACtC,MAAM,KAAK,GAAG,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,GAAG,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;YACvE,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,EAAE,EAAE,IAAI,CAAC,CAAA;YAC5E,IAAI,CAAC,KAAK,GAAG,IAAI,IAAI,OAAO,IAAI,EAAE,CAAC,IAAI,OAAO,IAAI,GAAG,EAAE,CAAC;gBACtD,KAAK,GAAG,MAAM,CAAC;gBAAC,OAAO,GAAG,CAAC,CAAA;gBAC3B,OAAO,KAAK,GAAG,GAAG,CAAA,CAAC,wDAAwD;YAC7E,CAAC;YACD,OAAO,KAAK,CAAA;QACd,CAAC;KACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import RAPIER from '@dimforge/rapier3d-compat';
|
|
2
|
+
export declare const LANYARD_STEP: number;
|
|
3
|
+
/** Call after Rapier initialization. Elastic links store the energy of a held
|
|
4
|
+
* stretch; unlike maximum-length rope joints, they recoil even after a pause.
|
|
5
|
+
* Rendering, pointer sampling and resource scheduling stay outside this module.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createLanyardPhysics(): {
|
|
8
|
+
world: RAPIER.World;
|
|
9
|
+
anchor: RAPIER.RigidBody;
|
|
10
|
+
beads: RAPIER.RigidBody[];
|
|
11
|
+
badge: RAPIER.RigidBody;
|
|
12
|
+
bodies: RAPIER.RigidBody[];
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=physics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"physics.d.ts","sourceRoot":"","sources":["../../src/pendant/physics.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,2BAA2B,CAAA;AAE9C,eAAO,MAAM,YAAY,QAAU,CAAA;AAEnC;;;GAGG;AACH,wBAAgB,oBAAoB;;;;;;EAuBnC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import RAPIER from '@dimforge/rapier3d-compat';
|
|
2
|
+
export const LANYARD_STEP = 1 / 120;
|
|
3
|
+
/** Call after Rapier initialization. Elastic links store the energy of a held
|
|
4
|
+
* stretch; unlike maximum-length rope joints, they recoil even after a pause.
|
|
5
|
+
* Rendering, pointer sampling and resource scheduling stay outside this module.
|
|
6
|
+
*/
|
|
7
|
+
export function createLanyardPhysics() {
|
|
8
|
+
const world = new RAPIER.World({ x: 0, y: -40, z: 0 });
|
|
9
|
+
world.timestep = LANYARD_STEP;
|
|
10
|
+
world.numSolverIterations = 12;
|
|
11
|
+
const anchor = world.createRigidBody(RAPIER.RigidBodyDesc.fixed().setTranslation(0, 4.15, 0));
|
|
12
|
+
const beads = [3.15, 2.15, 1.15].map(y => {
|
|
13
|
+
const body = world.createRigidBody(RAPIER.RigidBodyDesc.dynamic().setTranslation(.015, y, 0).setLinearDamping(.7).setAngularDamping(.7));
|
|
14
|
+
world.createCollider(RAPIER.ColliderDesc.ball(.035).setMass(.25).setCollisionGroups(0), body);
|
|
15
|
+
return body;
|
|
16
|
+
});
|
|
17
|
+
const badge = world.createRigidBody(RAPIER.RigidBodyDesc.dynamic().setTranslation(.015, .05, 0).setLinearDamping(.45).setAngularDamping(.45));
|
|
18
|
+
world.createCollider(RAPIER.ColliderDesc.cuboid(.71, .98, .04).setMass(1).setCollisionGroups(0), badge);
|
|
19
|
+
const bodies = [anchor, ...beads];
|
|
20
|
+
// Average supported weight is 60 force units per link. Compensating its
|
|
21
|
+
// static extension keeps the loaded strap at 3 world units as stiffness is
|
|
22
|
+
// tuned. Underdamping preserves recoil, without launching ordinary pulls.
|
|
23
|
+
const stiffness = 220, restLength = 1 - 60 / stiffness;
|
|
24
|
+
for (let i = 0; i < 3; i++)
|
|
25
|
+
world.createImpulseJoint(RAPIER.JointData.spring(restLength, stiffness, 6, { x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 0 }), bodies[i], bodies[i + 1], true);
|
|
26
|
+
world.createImpulseJoint(RAPIER.JointData.spherical({ x: 0, y: 0, z: 0 }, { x: 0, y: 1.1, z: 0 }), beads[2], badge, true);
|
|
27
|
+
return { world, anchor, beads, badge, bodies };
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=physics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"physics.js","sourceRoot":"","sources":["../../src/pendant/physics.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,2BAA2B,CAAA;AAE9C,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAG,GAAG,CAAA;AAEnC;;;GAGG;AACH,MAAM,UAAU,oBAAoB;IAClC,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;IACtD,KAAK,CAAC,QAAQ,GAAG,YAAY,CAAA;IAC7B,KAAK,CAAC,mBAAmB,GAAG,EAAE,CAAA;IAC9B,MAAM,MAAM,GAAG,KAAK,CAAC,eAAe,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;IAC7F,MAAM,KAAK,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;QACvC,MAAM,IAAI,GAAG,KAAK,CAAC,eAAe,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC,CAAA;QACxI,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAA;QAC7F,OAAO,IAAI,CAAA;IACb,CAAC,CAAC,CAAA;IACF,MAAM,KAAK,GAAG,KAAK,CAAC,eAAe,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAA;IAC7I,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;IACvG,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,CAAA;IACjC,wEAAwE;IACxE,2EAA2E;IAC3E,0EAA0E;IAC1E,MAAM,SAAS,GAAG,GAAG,EAAE,UAAU,GAAG,CAAC,GAAG,EAAE,GAAG,SAAS,CAAA;IACtD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;QAAE,KAAK,CAAC,kBAAkB,CAClD,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAC7F,MAAM,CAAC,CAAC,CAAE,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,CAAE,EAAE,IAAI,CACjC,CAAA;IACD,KAAK,CAAC,kBAAkB,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAE,EAAE,KAAK,EAAE,IAAI,CAAC,CAAA;IAC1H,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAA;AAChD,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type RefObject } from 'react';
|
|
2
|
+
import type { PartnerInbox, PartnerNotice } from '../notifications/domain.js';
|
|
3
|
+
interface Props {
|
|
4
|
+
inbox: PartnerInbox;
|
|
5
|
+
selected: string | undefined;
|
|
6
|
+
error: string;
|
|
7
|
+
anchor: RefObject<HTMLButtonElement>;
|
|
8
|
+
onSelect(item?: PartnerNotice): void;
|
|
9
|
+
onClose(keyboard?: boolean): void;
|
|
10
|
+
onVisit(item: PartnerNotice): void;
|
|
11
|
+
onReadAll(): void;
|
|
12
|
+
}
|
|
13
|
+
export declare function PendantReader({ inbox, selected, error, anchor, onSelect, onClose, onVisit, onReadAll }: Props): JSX.Element;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=reader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reader.d.ts","sourceRoot":"","sources":["../../src/pendant/reader.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgD,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAEpF,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAA;AAG7E,UAAU,KAAK;IACb,KAAK,EAAE,YAAY,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,CAAC,iBAAiB,CAAC,CAAA;IACtG,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAAC,OAAO,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAAC;IAAC,SAAS,IAAI,IAAI,CAAA;CAC/H;AACD,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAmC3H"}
|