dsh-checklists 0.3.2 → 0.3.3
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 +3 -0
- package/assets/screenshot-1.png +0 -0
- package/lib/model.js +29 -0
- package/lib/tools.js +61 -1
- package/lib/types/model.d.ts +27 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -28,6 +28,7 @@ If the agent forgets to mark something, you say so in chat and it fixes it.
|
|
|
28
28
|
| `checklist_edit` | Changes an item's text (not its state) |
|
|
29
29
|
| `checklist_list` | Full tree with ids and states, for when the digest is truncated |
|
|
30
30
|
| `checklist_delete` | Deletes a list (by id or exact title) |
|
|
31
|
+
| `checklist_rename` | Renames a list; titles stay unique within the session |
|
|
31
32
|
| `checklist_template_save` | Saves a list as a reusable template for future sessions |
|
|
32
33
|
|
|
33
34
|
Items are plain strings. **Two leading spaces per level** nest them:
|
|
@@ -88,6 +89,8 @@ document degrades to an empty list instead of failing the turn.
|
|
|
88
89
|
|
|
89
90
|
## Sidebar tab
|
|
90
91
|
|
|
92
|
+

|
|
93
|
+
|
|
91
94
|
Open the right sidebar, then the **guide** (`+`) and pick **Checklist**.
|
|
92
95
|
|
|
93
96
|
| Action | How |
|
|
Binary file
|
package/lib/model.js
CHANGED
|
@@ -147,6 +147,35 @@ export function findItemById(lists, id) {
|
|
|
147
147
|
}
|
|
148
148
|
return undefined;
|
|
149
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* Validate a checklist rename before applying it.
|
|
152
|
+
*
|
|
153
|
+
* Titles are how the user reads the sidebar and how `findList` resolves a
|
|
154
|
+
* reference, so a rename must never create a second list with the same title.
|
|
155
|
+
* Renaming a list to its own title (any case) is a no-op, not a conflict.
|
|
156
|
+
*
|
|
157
|
+
* @param lists - the session's checklists.
|
|
158
|
+
* @param ref - checklist id or exact title.
|
|
159
|
+
* @param nextTitle - the requested new title.
|
|
160
|
+
* @returns the resolved list, or the reason the rename cannot proceed.
|
|
161
|
+
*/
|
|
162
|
+
export function checkRename(lists, ref, nextTitle) {
|
|
163
|
+
const to = nextTitle.trim();
|
|
164
|
+
if (to.length === 0)
|
|
165
|
+
return { kind: 'empty' };
|
|
166
|
+
const list = findList(lists, ref);
|
|
167
|
+
if (!list) {
|
|
168
|
+
return { kind: 'missing', available: lists.map((entry) => `${entry.id} (${entry.title})`) };
|
|
169
|
+
}
|
|
170
|
+
const lower = to.toLowerCase();
|
|
171
|
+
if (list.title.trim().toLowerCase() === lower) {
|
|
172
|
+
return { kind: 'ok', list, from: list.title, to };
|
|
173
|
+
}
|
|
174
|
+
const clash = lists.find((entry) => entry !== list && entry.title.trim().toLowerCase() === lower);
|
|
175
|
+
if (clash)
|
|
176
|
+
return { kind: 'duplicate', existing: clash.title };
|
|
177
|
+
return { kind: 'ok', list, from: list.title, to };
|
|
178
|
+
}
|
|
150
179
|
/**
|
|
151
180
|
* The next item to work on, in depth-first order.
|
|
152
181
|
*
|
package/lib/tools.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* the single source of truth and the sidebar (phase 2) is a read-only mirror.
|
|
6
6
|
*/
|
|
7
7
|
import { defineTool } from '@deepseek-ai/dsh-tools';
|
|
8
|
-
import { buildItems, countItems, findList, flatten, ITEM_STATES, isItemState, mintId, nextItem, resolveRef, toLines, } from './model.js';
|
|
8
|
+
import { buildItems, checkRename, countItems, findList, flatten, ITEM_STATES, isItemState, mintId, nextItem, resolveRef, toLines, } from './model.js';
|
|
9
9
|
/** Ships with the plugin so a first run has something to instantiate. */
|
|
10
10
|
const DEFAULT_TEMPLATES = {
|
|
11
11
|
release: [
|
|
@@ -482,6 +482,66 @@ export function registerChecklistTools(ctx, store, config = {}) {
|
|
|
482
482
|
});
|
|
483
483
|
},
|
|
484
484
|
})));
|
|
485
|
+
ctx.effect(() => ctx.tools.register(defineTool({
|
|
486
|
+
name: 'checklist_rename',
|
|
487
|
+
description: 'Rename an existing checklist in the CURRENT session. Titles must be unique within the session. '
|
|
488
|
+
+ 'Pass the id from checklist_list, or the exact current title.',
|
|
489
|
+
parameters: {
|
|
490
|
+
listId: {
|
|
491
|
+
type: 'string',
|
|
492
|
+
required: true,
|
|
493
|
+
description: 'Checklist id, or its exact current title.',
|
|
494
|
+
},
|
|
495
|
+
title: {
|
|
496
|
+
type: 'string',
|
|
497
|
+
required: true,
|
|
498
|
+
description: 'New title for the checklist.',
|
|
499
|
+
},
|
|
500
|
+
},
|
|
501
|
+
output: {
|
|
502
|
+
schema: {
|
|
503
|
+
type: 'object',
|
|
504
|
+
additionalProperties: false,
|
|
505
|
+
properties: {
|
|
506
|
+
listId: { type: 'string', required: true },
|
|
507
|
+
from: { type: 'string', required: true },
|
|
508
|
+
to: { type: 'string', required: true },
|
|
509
|
+
},
|
|
510
|
+
},
|
|
511
|
+
render: (_args, value) => {
|
|
512
|
+
const result = value;
|
|
513
|
+
return [{ type: 'text', text: `Renamed "${result.from}" → "${result.to}".` }];
|
|
514
|
+
},
|
|
515
|
+
},
|
|
516
|
+
timeoutMs: 10_000,
|
|
517
|
+
async execute(args, exec) {
|
|
518
|
+
const input = args;
|
|
519
|
+
const sessionId = sessionOf(exec);
|
|
520
|
+
const ref = text(input.listId).trim();
|
|
521
|
+
const nextTitle = text(input.title).trim();
|
|
522
|
+
if (ref.length === 0)
|
|
523
|
+
throw new Error('checklist_rename: listId must not be empty');
|
|
524
|
+
if (nextTitle.length === 0)
|
|
525
|
+
throw new Error('checklist_rename: title must not be empty');
|
|
526
|
+
if (nextTitle.length > 120)
|
|
527
|
+
throw new Error('checklist_rename: title is longer than 120 characters');
|
|
528
|
+
return store.update(sessionId, (doc) => {
|
|
529
|
+
const check = checkRename(doc.lists, ref, nextTitle);
|
|
530
|
+
if (check.kind === 'empty')
|
|
531
|
+
throw new Error('checklist_rename: title must not be empty');
|
|
532
|
+
if (check.kind === 'missing') {
|
|
533
|
+
const available = check.available.join(', ');
|
|
534
|
+
throw new Error(`checklist_rename: no checklist "${ref}" in this session. `
|
|
535
|
+
+ `Available: ${available.length > 0 ? available : 'none'}`);
|
|
536
|
+
}
|
|
537
|
+
if (check.kind === 'duplicate') {
|
|
538
|
+
throw new Error(`checklist_rename: a checklist titled "${check.existing}" already exists in this session`);
|
|
539
|
+
}
|
|
540
|
+
check.list.title = check.to;
|
|
541
|
+
return { listId: check.list.id, from: check.from, to: check.to };
|
|
542
|
+
});
|
|
543
|
+
},
|
|
544
|
+
})));
|
|
485
545
|
ctx.effect(() => ctx.tools.register(defineTool({
|
|
486
546
|
name: 'checklist_delete',
|
|
487
547
|
description: 'Delete one checklist from the CURRENT session. The list and its items are gone; there is no archive. '
|
package/lib/types/model.d.ts
CHANGED
|
@@ -97,6 +97,33 @@ export declare function findItemById(lists: readonly Checklist[], id: string): {
|
|
|
97
97
|
list: Checklist;
|
|
98
98
|
item: ChecklistItem;
|
|
99
99
|
} | undefined;
|
|
100
|
+
export type RenameCheck = {
|
|
101
|
+
kind: 'ok';
|
|
102
|
+
list: Checklist;
|
|
103
|
+
from: string;
|
|
104
|
+
to: string;
|
|
105
|
+
} | {
|
|
106
|
+
kind: 'empty';
|
|
107
|
+
} | {
|
|
108
|
+
kind: 'missing';
|
|
109
|
+
available: string[];
|
|
110
|
+
} | {
|
|
111
|
+
kind: 'duplicate';
|
|
112
|
+
existing: string;
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* Validate a checklist rename before applying it.
|
|
116
|
+
*
|
|
117
|
+
* Titles are how the user reads the sidebar and how `findList` resolves a
|
|
118
|
+
* reference, so a rename must never create a second list with the same title.
|
|
119
|
+
* Renaming a list to its own title (any case) is a no-op, not a conflict.
|
|
120
|
+
*
|
|
121
|
+
* @param lists - the session's checklists.
|
|
122
|
+
* @param ref - checklist id or exact title.
|
|
123
|
+
* @param nextTitle - the requested new title.
|
|
124
|
+
* @returns the resolved list, or the reason the rename cannot proceed.
|
|
125
|
+
*/
|
|
126
|
+
export declare function checkRename(lists: readonly Checklist[], ref: string, nextTitle: string): RenameCheck;
|
|
100
127
|
export interface NextItem {
|
|
101
128
|
list: Checklist;
|
|
102
129
|
item: ChecklistItem;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-checklists",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "Session-scoped checklists for DeepSeek Harness: the agent tracks work as a tree, the model always sees a compact digest, and a read-only sidebar tab mirrors it.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"files": [
|
|
20
20
|
"lib",
|
|
21
21
|
"client",
|
|
22
|
+
"assets",
|
|
22
23
|
"cordis.patch.yml",
|
|
23
24
|
"README.md"
|
|
24
25
|
],
|