dsh-task-ledger 0.0.45 → 0.0.47
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 +130 -46
- package/dist/client.js.map +1 -1
- package/dist/host/board.d.ts +13 -108
- package/dist/host/board.js +19 -285
- package/dist/host/errors.d.ts +42 -0
- package/dist/host/errors.js +55 -0
- package/dist/host/repositories/cache.d.ts +27 -0
- package/dist/host/repositories/cache.js +57 -0
- package/dist/host/repositories/identity.repository.d.ts +9 -0
- package/dist/host/repositories/identity.repository.js +20 -0
- package/dist/host/{ledger-read.d.ts → repositories/ledger.repository.d.ts} +10 -4
- package/dist/host/repositories/ledger.repository.js +85 -0
- package/dist/host/repositories/records.d.ts +5 -0
- package/dist/host/repositories/records.js +48 -0
- package/dist/host/{script.js → repositories/runner.js} +3 -2
- package/dist/host/routes.d.ts +17 -0
- package/dist/host/routes.js +215 -64
- package/dist/host/services/dates.d.ts +37 -0
- package/dist/host/services/dates.js +71 -0
- package/dist/host/services/history.service.d.ts +24 -0
- package/dist/host/services/history.service.js +61 -0
- package/dist/host/services/home.service.d.ts +13 -0
- package/dist/host/services/home.service.js +50 -0
- package/dist/host/services/session.service.d.ts +110 -0
- package/dist/host/services/session.service.js +145 -0
- package/dist/host/services/trend.service.d.ts +26 -0
- package/dist/host/services/trend.service.js +134 -0
- package/dist/host/{skill-registration.d.ts → skill/registration.d.ts} +2 -0
- package/dist/host/{skill-registration.js → skill/registration.js} +5 -2
- package/dist/host/types.d.ts +94 -0
- package/dist/host/workspace.d.ts +8 -0
- package/dist/host/workspace.js +6 -9
- package/dist/index.js +31 -2
- package/package.json +4 -3
- package/dist/host/ledger-read.js +0 -64
- /package/dist/host/{script.d.ts → repositories/runner.d.ts} +0 -0
package/dist/host/types.d.ts
CHANGED
|
@@ -66,3 +66,97 @@ export interface LedgerFilter {
|
|
|
66
66
|
/** 只读最近 N 个月的历史文件(插件传 13;不传 = 脚本默认读全部)。 */
|
|
67
67
|
months?: number;
|
|
68
68
|
}
|
|
69
|
+
/** 一个自然周期内的两个计数(核心永远是「完成」,新增只作对照)。 */
|
|
70
|
+
export interface PeriodCounts {
|
|
71
|
+
readonly done: number;
|
|
72
|
+
readonly created: number;
|
|
73
|
+
/** 周期起(YYYY-MM-DD,含)。 */
|
|
74
|
+
readonly from: string;
|
|
75
|
+
/** 周期止(YYYY-MM-DD,含)。 */
|
|
76
|
+
readonly to: string;
|
|
77
|
+
}
|
|
78
|
+
/** 统计台四个自然周期(用户 2026-10-17 定稿:本周 / 上周 / 本月 / 上月,不用 7/30 天)。 */
|
|
79
|
+
export interface TrendPeriods {
|
|
80
|
+
readonly thisWeek: PeriodCounts;
|
|
81
|
+
readonly lastWeek: PeriodCounts;
|
|
82
|
+
readonly thisMonth: PeriodCounts;
|
|
83
|
+
readonly lastMonth: PeriodCounts;
|
|
84
|
+
}
|
|
85
|
+
/** 趋势图一桶(一周):完成 + 新增 + 截止时仍未完成。 */
|
|
86
|
+
export interface WeeklyBucket {
|
|
87
|
+
/** 该周周一(YYYY-MM-DD)。 */
|
|
88
|
+
readonly week: string;
|
|
89
|
+
/** 该周截止日(YYYY-MM-DD):历史周=当周周日,当前周=今天——图表 x 轴标它,因为数据是按截止日判的。 */
|
|
90
|
+
readonly end: string;
|
|
91
|
+
readonly done: number;
|
|
92
|
+
readonly created: number;
|
|
93
|
+
/** 该周截止时仍未完成(在办)的任务数:cumulative(创建 - 完成) 到该周末,含窗口前遗留。 */
|
|
94
|
+
readonly remaining: number;
|
|
95
|
+
}
|
|
96
|
+
/** 趋势图数据按范围各一份(切换零请求)。 */
|
|
97
|
+
export interface ClosedSummary {
|
|
98
|
+
readonly weekly: {
|
|
99
|
+
readonly all: readonly WeeklyBucket[];
|
|
100
|
+
readonly mine: readonly WeeklyBucket[];
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/** 首页统计卡的六个面(阈值 / 天数全在 host 算,前端只渲染——单一真源)。 */
|
|
104
|
+
export interface BoardStats {
|
|
105
|
+
/** 我的 doing + blocked。 */
|
|
106
|
+
readonly myActive: number;
|
|
107
|
+
/** 我的 blocked。 */
|
|
108
|
+
readonly myBlocked: number;
|
|
109
|
+
/** 待认领(open)。 */
|
|
110
|
+
readonly open: number;
|
|
111
|
+
/** 全部 doing。 */
|
|
112
|
+
readonly doing: number;
|
|
113
|
+
/** 全部 blocked。 */
|
|
114
|
+
readonly blocked: number;
|
|
115
|
+
/** 停滞 = doing|blocked 且 ageDays > STALE_DAYS。 */
|
|
116
|
+
readonly stale: number;
|
|
117
|
+
/** 停滞阈值(天)——随响应下发,界面文案不硬编码(单一真源)。 */
|
|
118
|
+
readonly staleDays: number;
|
|
119
|
+
/** 最老一条待认领躺了多少天(没有待认领 = null)。 */
|
|
120
|
+
readonly oldestOpenDays: number | null;
|
|
121
|
+
}
|
|
122
|
+
/** 列表行附加工资字段(host 算,前端不判阈值)。 */
|
|
123
|
+
export interface BoardTask extends TaskRow {
|
|
124
|
+
/** 认领后未动天数(doing / blocked;open 与解析不了的时间为 null)。 */
|
|
125
|
+
readonly ageDays: number | null;
|
|
126
|
+
/** 停滞标记。 */
|
|
127
|
+
readonly stale: boolean;
|
|
128
|
+
}
|
|
129
|
+
export interface BoardSnapshot {
|
|
130
|
+
readonly at: string;
|
|
131
|
+
readonly workspaces: readonly LedgerWorkspace[];
|
|
132
|
+
/** 全部在办任务(UI 自己筛「我的 / 待认领」——筛选是前端的事)。 */
|
|
133
|
+
readonly tasks: readonly BoardTask[];
|
|
134
|
+
readonly stats: BoardStats;
|
|
135
|
+
/**
|
|
136
|
+
* 工作区 id → 该工作区的当前 git 身份(取不到为 null)。
|
|
137
|
+
* 「我的待办」在前端按 `owner === identities[workspace.id]` 筛——身份只在 host 侧取得到
|
|
138
|
+
* (cwd = 该工作区跑 `git config user.name`),UI 不摸 git。
|
|
139
|
+
*/
|
|
140
|
+
readonly identities: Readonly<Record<string, string | null>>;
|
|
141
|
+
}
|
|
142
|
+
/** 首页一次 `/board` 的全部聚合(**每个工作区只读一次** list + history + git 身份)。 */
|
|
143
|
+
export interface HomeAggregate {
|
|
144
|
+
readonly snapshot: BoardSnapshot;
|
|
145
|
+
readonly closed: ClosedSummary;
|
|
146
|
+
readonly trend: TrendPeriods;
|
|
147
|
+
}
|
|
148
|
+
/** 快路径作用域:在办 + 身份。**没有 history 字段**——想从它算趋势,编译器直接拦住。 */
|
|
149
|
+
export interface TaskScope {
|
|
150
|
+
readonly workspace: LedgerWorkspace;
|
|
151
|
+
readonly tasks: readonly TaskRow[];
|
|
152
|
+
readonly identity: string | null;
|
|
153
|
+
}
|
|
154
|
+
/** 慢路径作用域:快路径 + history。趋势 / 筛选候选的原料。 */
|
|
155
|
+
export interface TrendScope extends TaskScope {
|
|
156
|
+
readonly history: readonly HistoryRecord[];
|
|
157
|
+
}
|
|
158
|
+
export interface FilterOptions {
|
|
159
|
+
readonly owners: string[];
|
|
160
|
+
readonly categories: string[];
|
|
161
|
+
readonly tags: string[];
|
|
162
|
+
}
|
package/dist/host/workspace.d.ts
CHANGED
|
@@ -4,10 +4,18 @@ export interface RegistryWorkspace {
|
|
|
4
4
|
readonly id: string;
|
|
5
5
|
readonly title: string;
|
|
6
6
|
readonly path: string;
|
|
7
|
+
/**
|
|
8
|
+
* 把会话登记进本工作区的 `sessionIds`(会话归组的唯一途径)。
|
|
9
|
+
* ⚠️ 只设 `meta.cwd` **不会**自动归组(reference: dsh-task-dispatch-table 决策 22 真机结论);
|
|
10
|
+
* 宿主旧版本可能没有该面 ⇒ optional,调用方按缺失降级并如实回报。
|
|
11
|
+
*/
|
|
12
|
+
readonly attachSession?: (sessionId: string) => Promise<void>;
|
|
7
13
|
}
|
|
8
14
|
/**
|
|
9
15
|
* 工作区发现:宿主 registry 全量 → 逐个查 <path>/ledger/progress.json,只返回有的。
|
|
10
16
|
* 未初始化(有 ledger/ 无 progress.json)= 隐藏,后端无此概念(2026-10-17 拍板)。
|
|
11
17
|
* 补充源(registry 未收录目录)暂不做——形态待拍板,见 architecture §五。
|
|
18
|
+
*
|
|
19
|
+
* 探测走 repository 的 hasLedger()——本文件不碰 node:fs(IO 唯一出口纪律)。
|
|
12
20
|
*/
|
|
13
21
|
export declare function resolveWorkspaces(registryList: readonly RegistryWorkspace[]): LedgerWorkspace[];
|
package/dist/host/workspace.js
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import path from 'node:path';
|
|
1
|
+
import { hasLedger } from './repositories/ledger.repository.js';
|
|
3
2
|
/**
|
|
4
3
|
* 工作区发现:宿主 registry 全量 → 逐个查 <path>/ledger/progress.json,只返回有的。
|
|
5
4
|
* 未初始化(有 ledger/ 无 progress.json)= 隐藏,后端无此概念(2026-10-17 拍板)。
|
|
6
5
|
* 补充源(registry 未收录目录)暂不做——形态待拍板,见 architecture §五。
|
|
6
|
+
*
|
|
7
|
+
* 探测走 repository 的 hasLedger()——本文件不碰 node:fs(IO 唯一出口纪律)。
|
|
7
8
|
*/
|
|
8
9
|
export function resolveWorkspaces(registryList) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
found.push({ id: workspace.id, title: workspace.title, path: workspace.path });
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
return found;
|
|
10
|
+
return registryList
|
|
11
|
+
.filter((workspace) => hasLedger(workspace.path))
|
|
12
|
+
.map((workspace) => ({ id: workspace.id, title: workspace.title, path: workspace.path }));
|
|
16
13
|
}
|
package/dist/index.js
CHANGED
|
@@ -9,9 +9,22 @@
|
|
|
9
9
|
* 满足不了的依赖会令 entry 一直 pending、卡死整个 dsh 启动);两条注入线
|
|
10
10
|
* 互相独立——skills 缺席不挡数据面,反之亦然。
|
|
11
11
|
*/
|
|
12
|
-
import { registerRoutes } from './host/routes.js';
|
|
13
|
-
import { buildSkillRegistration } from './host/skill
|
|
12
|
+
import { registerRoutes, registerSessionRoutes } from './host/routes.js';
|
|
13
|
+
import { buildSkillRegistration } from './host/skill/registration.js';
|
|
14
14
|
export const name = 'dsh-task-ledger';
|
|
15
|
+
/**
|
|
16
|
+
* 惰性服务读取:cordis ctx 的属性是 getter,**没 inject 的服务读一下就 throw**
|
|
17
|
+
* (参考插件真机实证:`cannot get property "agentTeams" without inject`)。
|
|
18
|
+
* 探测语义是「有就用、没有就降级」,所以把 throw 归一成 undefined。
|
|
19
|
+
*/
|
|
20
|
+
function readService(services, name) {
|
|
21
|
+
try {
|
|
22
|
+
return services[name];
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
15
28
|
export function apply(ctx) {
|
|
16
29
|
// ── 数据面(任务 3) ──
|
|
17
30
|
ctx.inject(['workspaceRegistry', 'webServer'], (services) => {
|
|
@@ -24,6 +37,22 @@ export function apply(ctx) {
|
|
|
24
37
|
registerRoutes(webServer, { registry });
|
|
25
38
|
console.info('[task-ledger] 数据面路由已注册(/api/task-ledger/*)');
|
|
26
39
|
});
|
|
40
|
+
// ── 会话交接(按钮侧「结束任务」,2026-10-18 拍板 B 案:只有结束走会话) ──
|
|
41
|
+
// 单独一条注入线:agents 缺席只影响这一个端点,不该拖累数据面(上一条线只等 registry + webServer)。
|
|
42
|
+
ctx.inject(['agents', 'workspaceRegistry', 'webServer'], (services) => {
|
|
43
|
+
const registry = services.workspaceRegistry;
|
|
44
|
+
const webServer = services.webServer;
|
|
45
|
+
if (registry === undefined || webServer === undefined) {
|
|
46
|
+
console.warn('[task-ledger] workspaceRegistry / webServer 未就位,「结束任务」端点不注册');
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
registerSessionRoutes(webServer, {
|
|
50
|
+
registry,
|
|
51
|
+
agents: services.agents,
|
|
52
|
+
getService: (name) => readService(services, name),
|
|
53
|
+
});
|
|
54
|
+
console.info('[task-ledger] 「结束任务」端点已注册(POST /api/task-ledger/close)');
|
|
55
|
+
});
|
|
27
56
|
// ── skill 全局注册(任务 2) ──
|
|
28
57
|
// unscoped 注册落全局层,模型可 load;disposer 随插件 dispose 自动注销。
|
|
29
58
|
ctx.inject(['skills'], (services) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-task-ledger",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.47",
|
|
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",
|
|
@@ -25,10 +25,11 @@
|
|
|
25
25
|
],
|
|
26
26
|
"scripts": {
|
|
27
27
|
"build": "npm run build:host && npm run build:client",
|
|
28
|
-
"build:host": "tsc && node scripts/copy-skill.mjs",
|
|
28
|
+
"build:host": "node scripts/clean-dist.mjs && tsc && node scripts/copy-skill.mjs",
|
|
29
29
|
"build:client": "tsc --noEmit -p tsconfig.client.json && tsdown --config tsdown.client.config.ts",
|
|
30
30
|
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.client.json",
|
|
31
|
-
"smoke": "node scripts/smoke.mjs"
|
|
31
|
+
"smoke": "node scripts/smoke.mjs",
|
|
32
|
+
"verify": "npm run build && npm run typecheck && npm run smoke"
|
|
32
33
|
},
|
|
33
34
|
"engines": {
|
|
34
35
|
"node": ">=22.5"
|
package/dist/host/ledger-read.js
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { readFile } from 'node:fs/promises';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { runLedgerScript } from './script.js';
|
|
4
|
-
/**
|
|
5
|
-
* LedgerFilter → skill 脚本参数(只拼调用方给了的;undefined 一律不拼,
|
|
6
|
-
* 让脚本走自己的默认——插件不替脚本决定默认值)。
|
|
7
|
-
*/
|
|
8
|
-
export function filterArgs(filter) {
|
|
9
|
-
const args = [];
|
|
10
|
-
if (filter.status !== undefined)
|
|
11
|
-
args.push('--status', filter.status);
|
|
12
|
-
if (filter.owner !== undefined)
|
|
13
|
-
args.push('--owner', filter.owner);
|
|
14
|
-
if (filter.category !== undefined)
|
|
15
|
-
args.push('--category', filter.category);
|
|
16
|
-
if (filter.tag !== undefined)
|
|
17
|
-
args.push('--tag', filter.tag);
|
|
18
|
-
if (filter.since !== undefined)
|
|
19
|
-
args.push('--since', filter.since);
|
|
20
|
-
if (filter.until !== undefined)
|
|
21
|
-
args.push('--until', filter.until);
|
|
22
|
-
if (filter.limit !== undefined)
|
|
23
|
-
args.push('--limit', String(filter.limit));
|
|
24
|
-
if (filter.months !== undefined)
|
|
25
|
-
args.push('--months', String(filter.months));
|
|
26
|
-
return args;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* 在办任务(包 `list --json`;结果打上 workspace)。
|
|
30
|
-
* 脚本失败抛错——路由层转 500 + 人话,不静默返空(空 = 撒谎)。
|
|
31
|
-
*/
|
|
32
|
-
export async function readTasks(workspace, filter = {}) {
|
|
33
|
-
const result = await runLedgerScript('list', ['--repo', workspace.path, '--json', ...filterArgs(filter)]);
|
|
34
|
-
if (!result.ok)
|
|
35
|
-
throw new Error(`${workspace.title}: ${result.error}`);
|
|
36
|
-
return Object.entries(result.data).map(([id, task]) => ({ ...task, id, workspace }));
|
|
37
|
-
}
|
|
38
|
-
/** 已结案记录(包 `history --json`;结果打上 workspace)。 */
|
|
39
|
-
export async function readHistory(workspace, filter = {}) {
|
|
40
|
-
const result = await runLedgerScript('history', ['--repo', workspace.path, '--json', ...filterArgs(filter)]);
|
|
41
|
-
if (!result.ok)
|
|
42
|
-
throw new Error(`${workspace.title}: ${result.error}`);
|
|
43
|
-
return (result.data.records ?? []).map((record) => ({ ...record, workspace }));
|
|
44
|
-
}
|
|
45
|
-
/** 单条在办(展开行 / 详情用)。取不到回 null,不抛。 */
|
|
46
|
-
export async function getTask(workspace, taskId) {
|
|
47
|
-
const rows = await readTasks(workspace);
|
|
48
|
-
return rows.find((row) => row.id === taskId) ?? null;
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* 过程文档正文(`task.worklog` 相对 `ledger/` 的路径)。
|
|
52
|
-
* 读不到回 null(文件被清 / 路径坏都不炸——由调用方展示「过程文档缺失」)。
|
|
53
|
-
*/
|
|
54
|
-
export async function readWorklog(workspace, task) {
|
|
55
|
-
const relative = task.worklog;
|
|
56
|
-
if (relative === undefined || relative === null || relative === '')
|
|
57
|
-
return null;
|
|
58
|
-
try {
|
|
59
|
-
return await readFile(path.join(workspace.path, 'ledger', relative), 'utf-8');
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
File without changes
|