@musnows/scriverse 0.9.5 → 0.9.7
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/dist/ai-protocol.js +6 -0
- package/dist/ai-protocol.js.map +1 -1
- package/dist/ai-skills.js +134 -0
- package/dist/ai-skills.js.map +1 -0
- package/dist/ai.js +1546 -62
- package/dist/ai.js.map +1 -1
- package/dist/app.js +143 -19
- package/dist/app.js.map +1 -1
- package/dist/chapter-title-numbering.js +56 -0
- package/dist/chapter-title-numbering.js.map +1 -0
- package/dist/database.js +142 -2
- package/dist/database.js.map +1 -1
- package/dist/public/ai-skill-menu.js +42 -0
- package/dist/public/ai-usage.d.ts +5 -2
- package/dist/public/ai-usage.js +50 -37
- package/dist/public/app.js +917 -242
- package/dist/public/chapter-line-id-tracker.d.ts +6 -0
- package/dist/public/chapter-line-id-tracker.js +24 -0
- package/dist/public/index.html +22 -11
- package/dist/public/model-config.d.ts +1 -0
- package/dist/public/model-config.js +9 -4
- package/dist/public/styles.css +135 -11
- package/dist/remote-mcp.js +496 -0
- package/dist/remote-mcp.js.map +1 -0
- package/dist/security.js +4 -0
- package/dist/security.js.map +1 -1
- package/dist/semantic-search.js +225 -0
- package/dist/semantic-search.js.map +1 -0
- package/dist/skills/continue-writing/SKILL.md +23 -0
- package/dist/skills/polish-writing/SKILL.md +23 -0
- package/dist/store.js +246 -33
- package/dist/store.js.map +1 -1
- package/dist/user-auth.js +11 -0
- package/dist/user-auth.js.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -1
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export const AI_SKILL_COMMAND_OPTIONS = Object.freeze([
|
|
2
|
+
Object.freeze({
|
|
3
|
+
name: "continue-writing",
|
|
4
|
+
label: "续写正文",
|
|
5
|
+
description: "延续当前章节,并保持情节、人物与设定一致。"
|
|
6
|
+
}),
|
|
7
|
+
Object.freeze({
|
|
8
|
+
name: "polish-writing",
|
|
9
|
+
label: "润色选中文本",
|
|
10
|
+
description: "润色当前章节的精确选区,并生成可确认的替换建议。"
|
|
11
|
+
})
|
|
12
|
+
]);
|
|
13
|
+
|
|
14
|
+
export function findAiSkillCommand(value, cursor = String(value ?? "").length) {
|
|
15
|
+
const text = String(value ?? "");
|
|
16
|
+
const safeCursor = Math.max(0, Math.min(Number(cursor) || 0, text.length));
|
|
17
|
+
const match = text.slice(0, safeCursor).match(/(?:^|\s)(\/([^/\s]*))$/u);
|
|
18
|
+
if (!match) return null;
|
|
19
|
+
return {
|
|
20
|
+
start: safeCursor - match[1].length,
|
|
21
|
+
end: safeCursor,
|
|
22
|
+
query: match[2]
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function listAiSkillOptions(query = "") {
|
|
27
|
+
const keyword = String(query).trim().toLocaleLowerCase("zh-CN");
|
|
28
|
+
if (!keyword) return [...AI_SKILL_COMMAND_OPTIONS];
|
|
29
|
+
return AI_SKILL_COMMAND_OPTIONS.filter((skill) => [skill.name, skill.label]
|
|
30
|
+
.some((value) => value.toLocaleLowerCase("zh-CN").includes(keyword)));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function applyAiSkillCommand(value, match, skillName) {
|
|
34
|
+
const text = String(value ?? "");
|
|
35
|
+
const command = `/${String(skillName).trim()}`;
|
|
36
|
+
const separator = /^\s/u.test(text.slice(match.end)) ? "" : " ";
|
|
37
|
+
return {
|
|
38
|
+
text: `${text.slice(0, match.start)}${command}${separator}${text.slice(match.end)}`,
|
|
39
|
+
command,
|
|
40
|
+
cursor: match.start + command.length + separator.length
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export type AiUsageCalendarCell = {
|
|
2
2
|
date: string;
|
|
3
3
|
totalTokens: number;
|
|
4
|
+
outsideYear: boolean;
|
|
4
5
|
future: boolean;
|
|
5
6
|
week: number;
|
|
6
7
|
weekday: number;
|
|
@@ -10,12 +11,14 @@ export type AiUsageCalendarCell = {
|
|
|
10
11
|
export function formatTokenCount(value: unknown): string;
|
|
11
12
|
export function formatCacheHitRate(value: unknown): string;
|
|
12
13
|
export function formatEstimatedCost(value: unknown): string;
|
|
14
|
+
export function usageCalendarYears(daily: Array<{ date: string; totalTokens: number }> | unknown): number[];
|
|
13
15
|
export function buildUsageCalendar(
|
|
14
16
|
daily: Array<{ date: string; totalTokens: number }> | unknown,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
year: number,
|
|
18
|
+
todayDateKey?: string
|
|
17
19
|
): {
|
|
18
20
|
cells: AiUsageCalendarCell[];
|
|
19
21
|
months: Array<{ week: number; label: string }>;
|
|
20
22
|
weekCount: number;
|
|
23
|
+
year: number | null;
|
|
21
24
|
};
|
package/dist/public/ai-usage.js
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
return
|
|
1
|
+
const usageDateKeyPattern = /^(\d{4})-(\d{2})-(\d{2})$/u;
|
|
2
|
+
|
|
3
|
+
function usageDateFromKey(value) {
|
|
4
|
+
const match = usageDateKeyPattern.exec(String(value));
|
|
5
|
+
if (!match) return null;
|
|
6
|
+
const year = Number(match[1]);
|
|
7
|
+
const month = Number(match[2]);
|
|
8
|
+
const day = Number(match[3]);
|
|
9
|
+
const date = new Date(Date.UTC(year, month - 1, day));
|
|
10
|
+
return year >= 1_000 && date.toISOString().slice(0, 10) === String(value) ? date : null;
|
|
6
11
|
}
|
|
7
12
|
|
|
8
|
-
function
|
|
9
|
-
|
|
10
|
-
date.setHours(0, 0, 0, 0);
|
|
11
|
-
return date;
|
|
13
|
+
function usageDateKey(date) {
|
|
14
|
+
return date.toISOString().slice(0, 10);
|
|
12
15
|
}
|
|
13
16
|
|
|
14
17
|
export function formatTokenCount(value) {
|
|
15
18
|
const count = Math.max(0, Math.round(Number(value) || 0));
|
|
16
19
|
if (count < 10_000) return count.toLocaleString("zh-CN");
|
|
20
|
+
if (count >= 100_000_000) return `${(count / 100_000_000).toFixed(2)}亿`;
|
|
17
21
|
return new Intl.NumberFormat("zh-CN", {
|
|
18
22
|
notation: "compact",
|
|
19
23
|
compactDisplay: "short",
|
|
@@ -38,26 +42,43 @@ export function formatEstimatedCost(value) {
|
|
|
38
42
|
})}`;
|
|
39
43
|
}
|
|
40
44
|
|
|
41
|
-
export function
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
export function usageCalendarYears(daily) {
|
|
46
|
+
return [...new Set((Array.isArray(daily) ? daily : [])
|
|
47
|
+
.filter((item) => usageDateFromKey(item?.date) && Math.max(0, Number(item?.totalTokens) || 0) > 0)
|
|
48
|
+
.map((item) => Number(String(item.date).slice(0, 4))))]
|
|
49
|
+
.sort((left, right) => right - left);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function buildUsageCalendar(daily, year, todayDateKey) {
|
|
53
|
+
const selectedYear = Number.isInteger(Number(year)) ? Number(year) : usageCalendarYears(daily)[0];
|
|
54
|
+
if (!selectedYear || selectedYear < 1_000 || selectedYear > 9_999) {
|
|
55
|
+
return { cells: [], months: [], weekCount: 0, year: null };
|
|
56
|
+
}
|
|
57
|
+
const firstDay = new Date(Date.UTC(selectedYear, 0, 1));
|
|
58
|
+
const lastDay = new Date(Date.UTC(selectedYear, 11, 31));
|
|
59
|
+
const start = new Date(firstDay);
|
|
60
|
+
start.setUTCDate(start.getUTCDate() - start.getUTCDay());
|
|
61
|
+
const end = new Date(lastDay);
|
|
62
|
+
end.setUTCDate(end.getUTCDate() + (6 - end.getUTCDay()));
|
|
63
|
+
const weekCount = Math.floor((end.getTime() - start.getTime()) / (7 * 24 * 60 * 60_000)) + 1;
|
|
64
|
+
const normalizedTodayKey = usageDateFromKey(todayDateKey) ? String(todayDateKey) : null;
|
|
65
|
+
const usageByDate = new Map((Array.isArray(daily) ? daily : [])
|
|
66
|
+
.filter((item) => usageDateFromKey(item?.date)?.getUTCFullYear() === selectedYear)
|
|
67
|
+
.map((item) => [String(item.date), Math.max(0, Number(item.totalTokens) || 0)]));
|
|
49
68
|
const visibleValues = [];
|
|
50
69
|
const cells = [];
|
|
51
|
-
for (let index = 0; index <
|
|
70
|
+
for (let index = 0; index < weekCount * 7; index += 1) {
|
|
52
71
|
const date = new Date(start);
|
|
53
|
-
date.
|
|
54
|
-
const dateKey =
|
|
55
|
-
const
|
|
56
|
-
const
|
|
57
|
-
|
|
72
|
+
date.setUTCDate(start.getUTCDate() + index);
|
|
73
|
+
const dateKey = usageDateKey(date);
|
|
74
|
+
const outsideYear = date.getUTCFullYear() !== selectedYear;
|
|
75
|
+
const totalTokens = outsideYear ? 0 : usageByDate.get(dateKey) ?? 0;
|
|
76
|
+
const future = !outsideYear && normalizedTodayKey !== null && dateKey > normalizedTodayKey;
|
|
77
|
+
if (!outsideYear && !future && totalTokens > 0) visibleValues.push(totalTokens);
|
|
58
78
|
cells.push({
|
|
59
79
|
date: dateKey,
|
|
60
80
|
totalTokens,
|
|
81
|
+
outsideYear,
|
|
61
82
|
future,
|
|
62
83
|
week: Math.floor(index / 7),
|
|
63
84
|
weekday: index % 7,
|
|
@@ -66,21 +87,13 @@ export function buildUsageCalendar(daily, today = new Date(), weekCount = 53) {
|
|
|
66
87
|
}
|
|
67
88
|
const maximum = Math.max(0, ...visibleValues);
|
|
68
89
|
for (const cell of cells) {
|
|
69
|
-
cell.level = cell.future || cell.totalTokens <= 0 || maximum <= 0
|
|
90
|
+
cell.level = cell.outsideYear || cell.future || cell.totalTokens <= 0 || maximum <= 0
|
|
70
91
|
? 0
|
|
71
92
|
: Math.max(1, Math.min(4, Math.ceil(Math.sqrt(cell.totalTokens / maximum) * 4)));
|
|
72
93
|
}
|
|
73
|
-
const months =
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
if (week === 0 || previous?.getMonth() !== date.getMonth()) {
|
|
79
|
-
months.push({
|
|
80
|
-
week,
|
|
81
|
-
label: new Intl.DateTimeFormat("zh-CN", { month: "short" }).format(date)
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
return { cells, months, weekCount: Math.max(1, weekCount) };
|
|
94
|
+
const months = Array.from({ length: 12 }, (_, month) => ({
|
|
95
|
+
week: Math.floor((Date.UTC(selectedYear, month, 1) - start.getTime()) / (7 * 24 * 60 * 60_000)),
|
|
96
|
+
label: `${month + 1}月`
|
|
97
|
+
}));
|
|
98
|
+
return { cells, months, weekCount, year: selectedYear };
|
|
86
99
|
}
|