dsh-task-ledger 0.0.124 → 0.0.126
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/client.js +1441 -533
- package/dist/client.js.map +1 -1
- package/dist/host/errors.d.ts +2 -2
- package/dist/host/repositories/cache.d.ts +2 -2
- package/dist/host/repositories/trend.repository.d.ts +13 -3
- package/dist/host/repositories/trend.repository.js +24 -5
- package/dist/host/routes.js +14 -0
- package/dist/host/services/history.service.d.ts +2 -0
- package/dist/host/services/history.service.js +130 -0
- package/dist/host/services/trend.service.js +2 -2
- package/dist/host/types.d.ts +55 -1
- package/package.json +2 -2
- package/skill/package.json +1 -1
- package/skill/scripts/bin/ledger-darwin-arm64 +0 -0
- package/skill/scripts/bin/ledger-linux-amd64 +0 -0
- package/skill/scripts/bin/ledger-windows-amd64.exe +0 -0
package/dist/host/errors.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ export interface DegradedInfo {
|
|
|
20
20
|
readonly workspaceId: string;
|
|
21
21
|
readonly workspaceTitle: string;
|
|
22
22
|
/** 哪个读挂了(skill 子命令;趋势走 `stats --trend`,单独一档便于区分)。 */
|
|
23
|
-
readonly op: "list" | "owners" | "trend";
|
|
23
|
+
readonly op: "list" | "owners" | "trend" | "history";
|
|
24
24
|
readonly code: LedgerErrorCode;
|
|
25
25
|
/** 人话,可直接上界面(真源:脚本 stderr / records 校验文案)。 */
|
|
26
26
|
readonly message: string;
|
|
@@ -36,7 +36,7 @@ export declare function messageOf(error: unknown): string;
|
|
|
36
36
|
export declare function settleWorkspaces<W extends {
|
|
37
37
|
id: string;
|
|
38
38
|
title: string;
|
|
39
|
-
}, T, R>(workspaces: readonly W[], op: "list" | "owners", read: (workspace: W) => Promise<T>, merge: (rows: readonly T[]) => R): Promise<{
|
|
39
|
+
}, T, R>(workspaces: readonly W[], op: "list" | "owners" | "history", read: (workspace: W) => Promise<T>, merge: (rows: readonly T[]) => R): Promise<{
|
|
40
40
|
data: R;
|
|
41
41
|
degraded: readonly DegradedInfo[];
|
|
42
42
|
}>;
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
/** 缓存有效期(2026-10-18 拍板 1.5s:够挡同一屏的重复读,短到不会让人看到旧数据)。 */
|
|
12
12
|
export declare const CACHE_TTL_MS = 1500;
|
|
13
13
|
/** 缓存的操作种类(= skill 脚本子命令;worklog 不进缓存故不在此列)。
|
|
14
|
-
* `history`
|
|
15
|
-
export type CacheOp = "list" | "stats" | "owners";
|
|
14
|
+
* `history` 供历史页顶部日趋势使用(2026-10-29 重新接入)。 */
|
|
15
|
+
export type CacheOp = "history" | "list" | "stats" | "owners";
|
|
16
16
|
/** 缓存键:`op:workspace:filter` 三条信息都要,否则不同筛选 / 不同工作区会串味。 */
|
|
17
17
|
export declare function cacheKey(workspaceId: string, op: CacheOp, detail: string): string;
|
|
18
18
|
/**
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { LedgerWorkspace } from "../types.js";
|
|
2
|
-
/**
|
|
3
|
-
|
|
2
|
+
/**
|
|
3
|
+
* 趋势图的窗口(周数):近半年。
|
|
4
|
+
* 2026-10-30 由 8 周放宽 —— 卡片按宽度能放几周就放几周(宽屏 12~14 周),
|
|
5
|
+
* 8 周不够铺满,也没得翻页;26 周 ≈ 4 屏,左右箭头一次翻 4 周。
|
|
6
|
+
*/
|
|
7
|
+
export declare const TREND_WEEKS = 26;
|
|
4
8
|
/** 一个人在一个周桶里的三个数(skill 口径:新增按 creator、完成 / 未结按 owner)。 */
|
|
5
9
|
export interface OwnerCounts {
|
|
6
10
|
readonly added: number;
|
|
@@ -30,7 +34,13 @@ export interface WorkspaceTrend {
|
|
|
30
34
|
readonly coverageFrom: string;
|
|
31
35
|
readonly coverageTo: string;
|
|
32
36
|
}
|
|
33
|
-
/** 单工作区趋势(skill `stats --trend week --last
|
|
37
|
+
/** 单工作区趋势(skill `stats --trend week --last 26w --by-owner`;过 1.5s 读缓存)。 */
|
|
34
38
|
export declare function readTrend(workspace: LedgerWorkspace): Promise<WorkspaceTrend>;
|
|
39
|
+
/**
|
|
40
|
+
* 历史页趋势的取数:`stats --trend <gran> --since --until`(明确窗口 ⇒ 不受
|
|
41
|
+
* day 粒度 365 桶上限的 --last 换算影响)。桶的切分 / 新增口径 / 补空桶全在 skill
|
|
42
|
+
* (用户 2026-10-30 定:聚合算法不自己写,host 只做跨工作区求和)。
|
|
43
|
+
*/
|
|
44
|
+
export declare function readTrendGran(workspace: LedgerWorkspace, gran: "day" | "week" | "month", since: string, until: string): Promise<WorkspaceTrend>;
|
|
35
45
|
/** `stats --trend` → {@link WorkspaceTrend}(容器级严格:缺字段即坏,不当 0)。 */
|
|
36
46
|
export declare function parseTrend(raw: unknown, where: string): WorkspaceTrend;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 趋势面取数:近
|
|
2
|
+
* 趋势面取数:近 26 周的「完成 / 未结 / 新增」,**整段桶序列一次拿回**(skill `stats --trend`)。
|
|
3
3
|
*
|
|
4
4
|
* 为什么不再拼现有方法:`history` 只给明细、且按**结案时间**过滤(新增取不到);
|
|
5
5
|
* 插件侧拉全量明细再聚合已被实测否决(20 万条 3s+、30MB 过进程边界)。
|
|
@@ -11,8 +11,12 @@
|
|
|
11
11
|
import { LedgerDataError } from "../errors.js";
|
|
12
12
|
import { cached, cacheKey } from "./cache.js";
|
|
13
13
|
import { runLedgerScript } from "./runner.js";
|
|
14
|
-
/**
|
|
15
|
-
|
|
14
|
+
/**
|
|
15
|
+
* 趋势图的窗口(周数):近半年。
|
|
16
|
+
* 2026-10-30 由 8 周放宽 —— 卡片按宽度能放几周就放几周(宽屏 12~14 周),
|
|
17
|
+
* 8 周不够铺满,也没得翻页;26 周 ≈ 4 屏,左右箭头一次翻 4 周。
|
|
18
|
+
*/
|
|
19
|
+
export const TREND_WEEKS = 26;
|
|
16
20
|
const TREND_LAST = `${String(TREND_WEEKS)}w`;
|
|
17
21
|
function isPlainObject(value) {
|
|
18
22
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
@@ -48,7 +52,7 @@ function parseOwners(raw, where) {
|
|
|
48
52
|
}
|
|
49
53
|
return out;
|
|
50
54
|
}
|
|
51
|
-
/** 单工作区趋势(skill `stats --trend week --last
|
|
55
|
+
/** 单工作区趋势(skill `stats --trend week --last 26w --by-owner`;过 1.5s 读缓存)。 */
|
|
52
56
|
export async function readTrend(workspace) {
|
|
53
57
|
// 缓存 op 仍记 "stats"(脚本子命令就是 stats),detail 里写清是哪个窗口的趋势
|
|
54
58
|
return await cached(cacheKey(workspace.id, "stats", `trend:${TREND_LAST}`), async () => {
|
|
@@ -56,7 +60,22 @@ export async function readTrend(workspace) {
|
|
|
56
60
|
const result = await runLedgerScript("stats",
|
|
57
61
|
// --by-owner:一次就把「全部」与「按人」两套数都拿回来 ⇒ 勾「只看我的」零请求
|
|
58
62
|
["--repo", workspace.path, "--trend", "week", "--last", TREND_LAST, "--by-owner"],
|
|
59
|
-
//
|
|
63
|
+
// 半年窗口最坏要读 7 个历史文件(skill 有月度缓存),比单月读重:给到 20s 再判超时
|
|
64
|
+
{ timeoutMs: 20_000 });
|
|
65
|
+
if (!result.ok)
|
|
66
|
+
throw new Error(`${workspace.title}: ${result.error}`);
|
|
67
|
+
return parseTrend(result.data, workspace.title);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* 历史页趋势的取数:`stats --trend <gran> --since --until`(明确窗口 ⇒ 不受
|
|
72
|
+
* day 粒度 365 桶上限的 --last 换算影响)。桶的切分 / 新增口径 / 补空桶全在 skill
|
|
73
|
+
* (用户 2026-10-30 定:聚合算法不自己写,host 只做跨工作区求和)。
|
|
74
|
+
*/
|
|
75
|
+
export async function readTrendGran(workspace, gran, since, until) {
|
|
76
|
+
return await cached(cacheKey(workspace.id, "stats", `trend:${gran}:${since}:${until}`), async () => {
|
|
77
|
+
const result = await runLedgerScript("stats", ["--repo", workspace.path, "--trend", gran, "--since", since, "--until", until],
|
|
78
|
+
// 与周趋势同档:整年窗口最坏要读十几个历史文件
|
|
60
79
|
{ timeoutMs: 20_000 });
|
|
61
80
|
if (!result.ok)
|
|
62
81
|
throw new Error(`${workspace.title}: ${result.error}`);
|
package/dist/host/routes.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { invalidate } from "./repositories/cache.js";
|
|
2
2
|
import { getBoardHome } from "./services/stats.service.js";
|
|
3
|
+
import { getHistoryTrend } from "./services/history.service.js";
|
|
3
4
|
import { resolveWorkspaces } from "./workspace.js";
|
|
4
5
|
/** API 前缀(唯一真源就在这一处)。 */
|
|
5
6
|
const API_PREFIX = "/api/task-ledger";
|
|
@@ -48,4 +49,17 @@ export function registerRoutes(webServer, deps) {
|
|
|
48
49
|
});
|
|
49
50
|
}
|
|
50
51
|
});
|
|
52
|
+
// 历史页顶部趋势(粒度 day/week/month,桶全在 skill):切粒度 = 重新请求,host 有读缓存。
|
|
53
|
+
registerRead("/history/trend", async (req, res) => {
|
|
54
|
+
try {
|
|
55
|
+
const raw = new URL(req.url ?? "/", "http://localhost").searchParams.get("gran");
|
|
56
|
+
const gran = raw === "week" || raw === "month" ? raw : "day";
|
|
57
|
+
sendJson(res, 200, await getHistoryTrend(await workspacesOf(deps), gran));
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
sendJson(res, 500, {
|
|
61
|
+
error: error instanceof Error ? error.message : String(error),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
});
|
|
51
65
|
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 历史页顶部趋势:**数字真源是 skill `stats --trend <gran>`**,本文件只做两件事 ——
|
|
3
|
+
* ① 每工作区拉「当前粒度 + day」两套桶(day 服务 4 数显与窗口锚点);
|
|
4
|
+
* ② 跨工作区**求和**。周期切分、新增口径、补空桶全在 skill
|
|
5
|
+
* (用户 2026-10-30 定:聚合算法不自己写,本地只加总,免得与核心口径漂移)。
|
|
6
|
+
*/
|
|
7
|
+
import { settleWorkspaces } from "../errors.js";
|
|
8
|
+
import { readTrendGran } from "../repositories/trend.repository.js";
|
|
9
|
+
function pad2(n) {
|
|
10
|
+
return String(n).padStart(2, "0");
|
|
11
|
+
}
|
|
12
|
+
function ymdOf(date) {
|
|
13
|
+
return `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}`;
|
|
14
|
+
}
|
|
15
|
+
function addDays(value, delta) {
|
|
16
|
+
const date = new Date(`${value}T00:00:00`);
|
|
17
|
+
date.setDate(date.getDate() + delta);
|
|
18
|
+
return ymdOf(date);
|
|
19
|
+
}
|
|
20
|
+
/** 本周一(周一为一周之始,与 skill 同口径)。 */
|
|
21
|
+
function mondayOf(value) {
|
|
22
|
+
const date = new Date(`${value}T00:00:00`);
|
|
23
|
+
date.setDate(date.getDate() - ((date.getDay() + 6) % 7));
|
|
24
|
+
return ymdOf(date);
|
|
25
|
+
}
|
|
26
|
+
function monthStart(value) {
|
|
27
|
+
return `${value.slice(0, 7)}-01`;
|
|
28
|
+
}
|
|
29
|
+
function prevMonthStart(value) {
|
|
30
|
+
const date = new Date(`${monthStart(value)}T00:00:00`);
|
|
31
|
+
date.setMonth(date.getMonth() - 1);
|
|
32
|
+
return ymdOf(date);
|
|
33
|
+
}
|
|
34
|
+
/** 所在季度首日(自然季度:1 / 4 / 7 / 10 月)。 */
|
|
35
|
+
function quarterStart(value) {
|
|
36
|
+
const date = new Date(`${monthStart(value)}T00:00:00`);
|
|
37
|
+
date.setMonth(date.getMonth() - (date.getMonth() % 3));
|
|
38
|
+
return ymdOf(date);
|
|
39
|
+
}
|
|
40
|
+
export async function getHistoryTrend(workspaces, gran = "day") {
|
|
41
|
+
const today = ymdOf(new Date());
|
|
42
|
+
// 窗口 = 最近 365 个自然日:day 粒度恰好顶满 skill 的 365 桶上限又不越线;周 / 月桶更少
|
|
43
|
+
const since = addDays(today, -364);
|
|
44
|
+
const settled = await settleWorkspaces(workspaces, "history", async (workspace) => {
|
|
45
|
+
// gran = day 时两套是同一份(同 cacheKey)⇒ 共用一个 Promise,不跑两遍脚本
|
|
46
|
+
const granRun = readTrendGran(workspace, gran, since, today);
|
|
47
|
+
const dayRun = gran === "day" ? granRun : readTrendGran(workspace, "day", since, today);
|
|
48
|
+
const [granTrend, dayTrend] = await Promise.all([granRun, dayRun]);
|
|
49
|
+
return { workspace, granTrend, dayTrend };
|
|
50
|
+
}, (rows) => rows);
|
|
51
|
+
// ① 柱 / 曲线:当前粒度,按桶起始日跨工作区求和 —— 本地唯一的「算法」就是加法
|
|
52
|
+
const merged = new Map();
|
|
53
|
+
for (const { workspace, granTrend } of settled.data) {
|
|
54
|
+
for (const bucket of granTrend.buckets) {
|
|
55
|
+
const acc = merged.get(bucket.from) ?? {
|
|
56
|
+
to: bucket.to,
|
|
57
|
+
done: 0,
|
|
58
|
+
cancelled: 0,
|
|
59
|
+
added: 0,
|
|
60
|
+
byWorkspace: {},
|
|
61
|
+
};
|
|
62
|
+
acc.to = bucket.to;
|
|
63
|
+
acc.done += bucket.done;
|
|
64
|
+
acc.cancelled += bucket.cancelled;
|
|
65
|
+
acc.added += bucket.added;
|
|
66
|
+
const ws = acc.byWorkspace[workspace.id] ?? { done: 0, cancelled: 0 };
|
|
67
|
+
ws.done += bucket.done;
|
|
68
|
+
ws.cancelled += bucket.cancelled;
|
|
69
|
+
acc.byWorkspace[workspace.id] = ws;
|
|
70
|
+
merged.set(bucket.from, acc);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// ② day 桶:4 数显求和
|
|
74
|
+
const dayMap = new Map();
|
|
75
|
+
for (const { dayTrend } of settled.data) {
|
|
76
|
+
for (const bucket of dayTrend.buckets) {
|
|
77
|
+
const acc = dayMap.get(bucket.from) ?? { done: 0, cancelled: 0, added: 0 };
|
|
78
|
+
acc.done += bucket.done;
|
|
79
|
+
acc.cancelled += bucket.cancelled;
|
|
80
|
+
acc.added += bucket.added;
|
|
81
|
+
dayMap.set(bucket.from, acc);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const sumIn = (rangeFrom, rangeTo) => {
|
|
85
|
+
let done = 0;
|
|
86
|
+
let cancelled = 0;
|
|
87
|
+
for (const [key, cell] of dayMap) {
|
|
88
|
+
if (key < rangeFrom || key > rangeTo)
|
|
89
|
+
continue;
|
|
90
|
+
done += cell.done;
|
|
91
|
+
cancelled += cell.cancelled;
|
|
92
|
+
}
|
|
93
|
+
return { done, cancelled };
|
|
94
|
+
};
|
|
95
|
+
const yesterday = addDays(today, -1);
|
|
96
|
+
const lastWeekEnd = addDays(mondayOf(today), -1);
|
|
97
|
+
const quarterFrom = quarterStart(today);
|
|
98
|
+
const lastQuarterEnd = addDays(quarterFrom, -1);
|
|
99
|
+
const totals = {
|
|
100
|
+
today: sumIn(today, today),
|
|
101
|
+
yesterday: sumIn(yesterday, yesterday),
|
|
102
|
+
week: sumIn(mondayOf(today), today),
|
|
103
|
+
lastWeek: sumIn(addDays(mondayOf(today), -7), lastWeekEnd),
|
|
104
|
+
month: sumIn(monthStart(today), today),
|
|
105
|
+
lastMonth: sumIn(prevMonthStart(today), addDays(monthStart(today), -1)),
|
|
106
|
+
quarter: sumIn(quarterFrom, today),
|
|
107
|
+
lastQuarter: sumIn(quarterStart(lastQuarterEnd), lastQuarterEnd),
|
|
108
|
+
};
|
|
109
|
+
// 整段窗口直接下发(不按有数据范围裁剪):翻页边界交给前端按 key 补空槽,
|
|
110
|
+
// 免得「正好显示完就不能翻、中间空一大段反而能翻」这种判断(用户 2026-10-30)
|
|
111
|
+
const buckets = [...merged.entries()]
|
|
112
|
+
.sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0))
|
|
113
|
+
.map(([key, cell]) => ({
|
|
114
|
+
key,
|
|
115
|
+
to: cell.to,
|
|
116
|
+
done: cell.done,
|
|
117
|
+
cancelled: cell.cancelled,
|
|
118
|
+
added: cell.added,
|
|
119
|
+
byWorkspace: cell.byWorkspace,
|
|
120
|
+
}));
|
|
121
|
+
return {
|
|
122
|
+
workspaces: workspaces.map((workspace) => ({
|
|
123
|
+
id: workspace.id,
|
|
124
|
+
title: workspace.title,
|
|
125
|
+
})),
|
|
126
|
+
buckets,
|
|
127
|
+
totals,
|
|
128
|
+
degraded: settled.degraded,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 首页趋势图的用例:跨工作区把「近
|
|
2
|
+
* 首页趋势图的用例:跨工作区把「近 26 周」的桶**按周求和**。
|
|
3
3
|
*
|
|
4
|
-
* 数字真源全在 skill(每工作区 `stats --trend week --last
|
|
4
|
+
* 数字真源全在 skill(每工作区 `stats --trend week --last 26w`),本文件只做两件事:
|
|
5
5
|
* 按 `from` 把各工作区同周的数加在一起、把读挂的工作区归进 `degraded`。
|
|
6
6
|
*
|
|
7
7
|
* ⚠️ 这里**不抛**「全部失败」:趋势只是首页的一块图,不能因为它把 8 张卡和列表一起打成 500。
|
package/dist/host/types.d.ts
CHANGED
|
@@ -145,6 +145,60 @@ export interface TrendView {
|
|
|
145
145
|
export interface TrendPayload extends TrendView {
|
|
146
146
|
readonly degraded: readonly DegradedInfo[];
|
|
147
147
|
}
|
|
148
|
+
/** 历史趋势的周期粒度(一根柱 = 一个周期;桶的切分与口径全在 skill)。 */
|
|
149
|
+
export type HistoryGran = "day" | "week" | "month";
|
|
150
|
+
/** 历史趋势里某工作区一个周期内的结案数。 */
|
|
151
|
+
export interface HistoryWorkspaceCell {
|
|
152
|
+
readonly done: number;
|
|
153
|
+
readonly cancelled: number;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* 历史页顶部的一个周期桶:**数字真源是 skill `stats --trend <gran>`**,
|
|
157
|
+
* host 只做跨工作区求和(用户 2026-10-30 定:不自己写聚合算法)。
|
|
158
|
+
*/
|
|
159
|
+
export interface HistoryBucket {
|
|
160
|
+
/** 周期起始日(日 = 当天、周 = 周一、月 = 1 号;skill 口径)。 */
|
|
161
|
+
readonly key: string;
|
|
162
|
+
/** 周期结束日(含边界;skill 口径,浮卡的区间标题用)。 */
|
|
163
|
+
readonly to: string;
|
|
164
|
+
readonly done: number;
|
|
165
|
+
readonly cancelled: number;
|
|
166
|
+
/** 该周期新建(含在办 / 待认领)。 */
|
|
167
|
+
readonly added: number;
|
|
168
|
+
/** 工作区 id → 该区该周期的 done / cancelled(分色用)。 */
|
|
169
|
+
readonly byWorkspace: Readonly<Record<string, HistoryWorkspaceCell>>;
|
|
170
|
+
}
|
|
171
|
+
/** 一个周期的结案拆分(合计 = done + cancelled)—— 小字要分别显示「完成 / 取消」。 */
|
|
172
|
+
export interface PeriodCount {
|
|
173
|
+
readonly done: number;
|
|
174
|
+
readonly cancelled: number;
|
|
175
|
+
}
|
|
176
|
+
/** 历史页顶部数显(host 从 day 桶求和:今日 / 昨日 / 本周 / 上周 / 本月 / 上月 / 本季度 / 上季度)。 */
|
|
177
|
+
export interface HistoryTotals {
|
|
178
|
+
readonly today: PeriodCount;
|
|
179
|
+
readonly yesterday: PeriodCount;
|
|
180
|
+
readonly week: PeriodCount;
|
|
181
|
+
readonly lastWeek: PeriodCount;
|
|
182
|
+
readonly month: PeriodCount;
|
|
183
|
+
readonly lastMonth: PeriodCount;
|
|
184
|
+
readonly quarter: PeriodCount;
|
|
185
|
+
readonly lastQuarter: PeriodCount;
|
|
186
|
+
}
|
|
187
|
+
/** 历史页顶部数据:当前粒度的桶序列 + 4 数显。
|
|
188
|
+
* 桶只覆盖最近 365 天(skill 的 day 粒度上限);更早的窗口由前端按 key 补空槽。 */
|
|
189
|
+
export interface HistoryTrendView {
|
|
190
|
+
readonly workspaces: readonly {
|
|
191
|
+
readonly id: string;
|
|
192
|
+
readonly title: string;
|
|
193
|
+
}[];
|
|
194
|
+
/** 桶序列(升序;空桶 = 该周期无结案)。 */
|
|
195
|
+
readonly buckets: readonly HistoryBucket[];
|
|
196
|
+
readonly totals: HistoryTotals;
|
|
197
|
+
}
|
|
198
|
+
/** 历史日趋势 + 降级。 */
|
|
199
|
+
export interface HistoryTrendPayload extends HistoryTrendView {
|
|
200
|
+
readonly degraded: readonly DegradedInfo[];
|
|
201
|
+
}
|
|
148
202
|
/** 一个工作区的花名册(skill `owners --json`:含当前没任务的人)。 */
|
|
149
203
|
export interface WorkspaceOwners {
|
|
150
204
|
readonly workspaceId: string;
|
|
@@ -161,7 +215,7 @@ export interface WorkspaceOwners {
|
|
|
161
215
|
* 前端只筛不判。
|
|
162
216
|
*/
|
|
163
217
|
export interface BoardHomePayload extends StatsPayload {
|
|
164
|
-
/** 首页右侧趋势图(近
|
|
218
|
+
/** 首页右侧趋势图(近 26 周)。 */
|
|
165
219
|
readonly trend: TrendView;
|
|
166
220
|
readonly workspaces: readonly LedgerWorkspace[];
|
|
167
221
|
readonly tasks: readonly TaskRow[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-task-ledger",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.126",
|
|
4
4
|
"description": "Task ledger board for dsh (DeepSeek Harness): read-only board over task-ledger skill workspaces. The task-ledger skill is bundled — install the plugin, get the skill globally.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek",
|
|
@@ -57,6 +57,6 @@
|
|
|
57
57
|
}
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"dsh-plugin-core": "^0.
|
|
60
|
+
"dsh-plugin-core": "^0.12.0"
|
|
61
61
|
}
|
|
62
62
|
}
|
package/skill/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "task-ledger",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.47",
|
|
4
4
|
"description": "Task-ledger skill for coding agents: per-workspace progress tracking (ledger/pool.json + owners/<hash>.json shards + owners.json index, history, worklog) driven by a CLI script. Standalone install for CodeBuddy and other agents; also bundled inside the dsh-task-ledger DSH plugin.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"skill",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|