@awiki/dsh-plugin 0.2.0-rc.4 → 0.2.0-rc.5
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 +2 -1
- package/README.zh.md +2 -1
- package/lib/client.js +54 -10
- package/lib/client.js.map +1 -1
- package/lib/types/client/AwikiOverlay.d.ts.map +1 -1
- package/lib/types/client/AwikiOverlay.js +27 -3
- package/lib/types/client/AwikiOverlay.js.map +1 -1
- package/lib/types/client/controller.d.ts +2 -0
- package/lib/types/client/controller.d.ts.map +1 -1
- package/lib/types/client/controller.js +30 -4
- package/lib/types/client/controller.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,9 +20,10 @@ TypeScript SDK `identity.json`; create a new Rust-backed identity after upgradin
|
|
|
20
20
|
- Open the top-left AWiki account menu to sign out locally without deleting the encrypted identity or message database; **Resume** restores the same DID and Handle, including across DSH restarts.
|
|
21
21
|
- Reuse that identity across the root Agent and its subagents.
|
|
22
22
|
- Direct-message and existing-group conversation lists, unread counts, latest-message previews, and persisted display names.
|
|
23
|
-
- Text messages plus one attachment per message, with image previews and SHA verification.
|
|
23
|
+
- Text messages plus one attachment per message, with Enter-to-send, Shift+Enter line breaks, image previews, and SHA verification.
|
|
24
24
|
- A draggable circular launcher, adaptive popup placement, dark mode, and remembered active conversation.
|
|
25
25
|
- User-triggered AI summaries for up to 50 recent or unread messages, kept only in runtime memory with explicit stale, retry, copy, and source-navigation states.
|
|
26
|
+
- OTP registration keeps the verification form visible and disables resend with a visible server-directed cooldown countdown.
|
|
26
27
|
- An AWiki page in DSH Settings for a durable, validated default Handle domain.
|
|
27
28
|
- A typed second confirmation in the Settings danger zone before permanently clearing local AWiki identity, key, token, registration-draft, and message-index state.
|
|
28
29
|
- Five approval-aware Agent tools: identity status, conversations, history, text send, and attachment send.
|
package/README.zh.md
CHANGED
|
@@ -14,9 +14,10 @@ Rust 身份。
|
|
|
14
14
|
- 点击 AWiki 面板左上角图标可打开账户菜单;普通退出只锁定本机会话,不删除加密身份或消息数据库,重新进入及重启 DSH 后仍恢复同一个 DID 和 Handle。
|
|
15
15
|
- 注册失败时保留手机号、Handle、验证码和本机待注册密钥;注册未开放、验证码状态失效和提交冲突会给出对应的安全处理提示。
|
|
16
16
|
- 私聊和已有群聊列表、未读角标、最新消息预览、时间更新与昵称持久化。
|
|
17
|
-
-
|
|
17
|
+
- 文本和单附件消息;Enter 发送、Shift+Enter 换行,并支持图片预览、附件说明与 SHA 校验。
|
|
18
18
|
- 圆形可拖动入口、自适应四角弹窗、深色模式和当前会话记忆。
|
|
19
19
|
- 用户点击后才生成的 AI 对话总结:最多处理 50 条最近或未读消息,按会话保留本次运行期缓存,并支持过期提示、重试、复制与跳转原消息。
|
|
20
|
+
- OTP 注册会保留验证码输入表单,并按服务端返回的冷却时间显示重发倒计时、禁用提前重发。
|
|
20
21
|
- 在 DSH 设置中提供 AWiki 页面,可持久化修改并校验默认 Handle 域名。
|
|
21
22
|
- 在设置页危险区域中,经输入确认词的二次确认后,永久清空本机 AWiki 身份、密钥、令牌、注册草稿和消息索引。
|
|
22
23
|
- 五个受 Harness 审批约束的 Agent 工具:身份、会话、历史、文本发送、附件发送。
|
package/lib/client.js
CHANGED
|
@@ -5452,6 +5452,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
5452
5452
|
disposed = false;
|
|
5453
5453
|
polling = false;
|
|
5454
5454
|
unreadAtOpen = /* @__PURE__ */ new Map();
|
|
5455
|
+
summaryBaselines = /* @__PURE__ */ new Map();
|
|
5455
5456
|
/** @param remote - generated Host Remote namespace. */
|
|
5456
5457
|
constructor(remote) {
|
|
5457
5458
|
this.remote = remote;
|
|
@@ -5475,6 +5476,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
5475
5476
|
error: "AWiki 插件已卸载"
|
|
5476
5477
|
};
|
|
5477
5478
|
this.close();
|
|
5479
|
+
this.summaryBaselines.clear();
|
|
5478
5480
|
const generation = this.generation;
|
|
5479
5481
|
this.publish({
|
|
5480
5482
|
...INITIAL_VIEW,
|
|
@@ -5525,6 +5527,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
5525
5527
|
this.close();
|
|
5526
5528
|
this.conversationsCursor = void 0;
|
|
5527
5529
|
this.historyCursor = void 0;
|
|
5530
|
+
this.summaryBaselines.clear();
|
|
5528
5531
|
this.publish({
|
|
5529
5532
|
...INITIAL_VIEW,
|
|
5530
5533
|
status: "ready",
|
|
@@ -5771,6 +5774,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
5771
5774
|
stale: false,
|
|
5772
5775
|
result: result.value
|
|
5773
5776
|
});
|
|
5777
|
+
const latestSentAt = Math.max(result.value.range.endedAt, ...this.view.messages.map((message) => message.sentAt));
|
|
5778
|
+
const messageIdsAtLatest = new Set(this.view.messages.filter((message) => message.sentAt === latestSentAt).map((message) => message.id));
|
|
5779
|
+
if (result.value.range.endedAt === latestSentAt) messageIdsAtLatest.add(result.value.range.lastMessageId);
|
|
5780
|
+
this.summaryBaselines.set(conversationId, {
|
|
5781
|
+
latestSentAt,
|
|
5782
|
+
messageIdsAtLatest
|
|
5783
|
+
});
|
|
5774
5784
|
return result;
|
|
5775
5785
|
}
|
|
5776
5786
|
/** Expand or collapse one cached summary without another model call. */
|
|
@@ -5872,6 +5882,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
5872
5882
|
this.conversationsCursor = void 0;
|
|
5873
5883
|
this.historyCursor = void 0;
|
|
5874
5884
|
this.unreadAtOpen.clear();
|
|
5885
|
+
this.summaryBaselines.clear();
|
|
5875
5886
|
this.publish({
|
|
5876
5887
|
...INITIAL_VIEW,
|
|
5877
5888
|
status: "ready"
|
|
@@ -5929,7 +5940,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
5929
5940
|
...this.view,
|
|
5930
5941
|
messages,
|
|
5931
5942
|
historyHasMore: result.value.hasMore && result.value.nextCursor !== void 0,
|
|
5932
|
-
summaries: this.staleSummaries(conversationId,
|
|
5943
|
+
summaries: older ? this.view.summaries : this.staleSummaries(conversationId, result.value.items)
|
|
5933
5944
|
});
|
|
5934
5945
|
return {
|
|
5935
5946
|
ok: true,
|
|
@@ -5945,13 +5956,15 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
5945
5956
|
if (selected === null || !this.current(generation)) return;
|
|
5946
5957
|
const result = await call(() => this.remote.getHistory({ conversationId: selected }));
|
|
5947
5958
|
if (!this.current(generation) || !result.ok || this.view.selectedConversationId !== selected) return;
|
|
5959
|
+
const existingIds = new Set(this.view.messages.map((message) => message.id));
|
|
5960
|
+
const incoming = result.value.items.filter((message) => !existingIds.has(message.id));
|
|
5948
5961
|
const messages = appendUnique(this.view.messages, result.value.items, (value) => value.id);
|
|
5949
5962
|
const added = messages.length - this.view.messages.length;
|
|
5950
5963
|
if (added > 0 && (this.unreadAtOpen.get(selected) ?? 0) > 0) this.unreadAtOpen.set(selected, (this.unreadAtOpen.get(selected) ?? 0) + added);
|
|
5951
5964
|
this.publish({
|
|
5952
5965
|
...this.view,
|
|
5953
5966
|
messages,
|
|
5954
|
-
summaries: this.staleSummaries(selected,
|
|
5967
|
+
summaries: this.staleSummaries(selected, incoming)
|
|
5955
5968
|
});
|
|
5956
5969
|
} finally {
|
|
5957
5970
|
this.polling = false;
|
|
@@ -5978,12 +5991,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
5978
5991
|
return result;
|
|
5979
5992
|
}
|
|
5980
5993
|
appendMessage(message) {
|
|
5994
|
+
const isNew = !this.view.messages.some((current) => current.id === message.id);
|
|
5981
5995
|
const messages = appendUnique(this.view.messages, [message], (value) => value.id);
|
|
5982
5996
|
if ((this.unreadAtOpen.get(message.conversationId) ?? 0) > 0 && messages.length > this.view.messages.length) this.unreadAtOpen.set(message.conversationId, (this.unreadAtOpen.get(message.conversationId) ?? 0) + 1);
|
|
5983
5997
|
this.publish({
|
|
5984
5998
|
...this.view,
|
|
5985
5999
|
messages,
|
|
5986
|
-
summaries: this.
|
|
6000
|
+
summaries: isNew ? this.markSummaryStale(message.conversationId) : this.view.summaries,
|
|
5987
6001
|
error: null
|
|
5988
6002
|
});
|
|
5989
6003
|
}
|
|
@@ -5999,7 +6013,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
5999
6013
|
staleSummaries(conversationId, messages) {
|
|
6000
6014
|
const summary = this.view.summaries[conversationId];
|
|
6001
6015
|
if (summary?.status !== "success" || summary.result === void 0 || summary.stale) return this.view.summaries;
|
|
6002
|
-
|
|
6016
|
+
const baseline = this.summaryBaselines.get(conversationId) ?? {
|
|
6017
|
+
latestSentAt: summary.result.range.endedAt,
|
|
6018
|
+
messageIdsAtLatest: /* @__PURE__ */ new Set([summary.result.range.lastMessageId])
|
|
6019
|
+
};
|
|
6020
|
+
if (!messages.some((message) => message.sentAt > baseline.latestSentAt || message.sentAt === baseline.latestSentAt && !baseline.messageIdsAtLatest.has(message.id))) return this.view.summaries;
|
|
6021
|
+
return this.markSummaryStale(conversationId);
|
|
6022
|
+
}
|
|
6023
|
+
markSummaryStale(conversationId) {
|
|
6024
|
+
const summary = this.view.summaries[conversationId];
|
|
6025
|
+
if (summary?.status !== "success" || summary.stale) return this.view.summaries;
|
|
6003
6026
|
return Object.freeze({
|
|
6004
6027
|
...this.view.summaries,
|
|
6005
6028
|
[conversationId]: Object.freeze({
|
|
@@ -6347,14 +6370,32 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
6347
6370
|
const [otp, setOtp] = (0, react.useState)("");
|
|
6348
6371
|
const [otpSent, setOtpSent] = (0, react.useState)(false);
|
|
6349
6372
|
const [notice, setNotice] = (0, react.useState)(null);
|
|
6373
|
+
const [retryDeadline, setRetryDeadline] = (0, react.useState)(null);
|
|
6374
|
+
const [retrySeconds, setRetrySeconds] = (0, react.useState)(0);
|
|
6375
|
+
(0, react.useEffect)(() => {
|
|
6376
|
+
if (retryDeadline === null) return;
|
|
6377
|
+
const update = () => {
|
|
6378
|
+
const remaining = Math.max(0, Math.ceil((retryDeadline - Date.now()) / 1e3));
|
|
6379
|
+
setRetrySeconds(remaining);
|
|
6380
|
+
if (remaining === 0) setRetryDeadline(null);
|
|
6381
|
+
};
|
|
6382
|
+
update();
|
|
6383
|
+
const timer = setInterval(update, 250);
|
|
6384
|
+
return () => {
|
|
6385
|
+
clearInterval(timer);
|
|
6386
|
+
};
|
|
6387
|
+
}, [retryDeadline]);
|
|
6350
6388
|
const requestOtp = async () => {
|
|
6351
6389
|
const result = await props.sendRegistrationOtp({
|
|
6352
6390
|
handle: handle.trim(),
|
|
6353
6391
|
phone: phone.trim()
|
|
6354
6392
|
});
|
|
6355
6393
|
if (!result.ok) return;
|
|
6394
|
+
const cooldownSeconds = Math.max(0, Math.ceil(result.value.retryAfterSeconds));
|
|
6356
6395
|
setOtpSent(true);
|
|
6357
|
-
|
|
6396
|
+
setRetryDeadline(Date.now() + cooldownSeconds * 1e3);
|
|
6397
|
+
setRetrySeconds(cooldownSeconds);
|
|
6398
|
+
setNotice(`验证码已发送;${cooldownSeconds} 秒后可重新获取。`);
|
|
6358
6399
|
};
|
|
6359
6400
|
const register = async () => {
|
|
6360
6401
|
/* v8 ignore next -- the registration action is rendered only after an OTP challenge starts. */
|
|
@@ -6419,13 +6460,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
6419
6460
|
(0, react_jsx_runtime.jsx)("button", {
|
|
6420
6461
|
type: "button",
|
|
6421
6462
|
className: _dsh_awiki_css_AwikiOverlay_module_css_default.linkButton,
|
|
6422
|
-
disabled: props.pending,
|
|
6463
|
+
disabled: props.pending || retrySeconds > 0,
|
|
6423
6464
|
onClick: () => {
|
|
6424
|
-
|
|
6425
|
-
setOtp("");
|
|
6426
|
-
setNotice(null);
|
|
6465
|
+
requestOtp();
|
|
6427
6466
|
},
|
|
6428
|
-
children: "重新获取验证码"
|
|
6467
|
+
children: retrySeconds > 0 ? `${retrySeconds} 秒后重新获取` : "重新获取验证码"
|
|
6429
6468
|
})
|
|
6430
6469
|
] }),
|
|
6431
6470
|
notice !== null && (0, react_jsx_runtime.jsx)("p", {
|
|
@@ -7135,6 +7174,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
7135
7174
|
onChange: (event) => {
|
|
7136
7175
|
setText(event.target.value);
|
|
7137
7176
|
},
|
|
7177
|
+
onKeyDown: (event) => {
|
|
7178
|
+
if (event.key !== "Enter" || event.shiftKey || event.nativeEvent.isComposing) return;
|
|
7179
|
+
event.preventDefault();
|
|
7180
|
+
if (view.pending === null && (file !== null || text.trim() !== "")) sendMessage();
|
|
7181
|
+
},
|
|
7138
7182
|
placeholder: "输入消息",
|
|
7139
7183
|
rows: 2
|
|
7140
7184
|
}),
|