@oisin-ee/pi-todo 0.9.3 → 0.10.0
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 +5 -1
- package/package.json +1 -1
- package/src/display.ts +5 -2
- package/src/generated/todo_core.d.ts +55 -1
- package/src/generated/todo_core.js +29 -0
- package/src/generated/todo_core_bg.wasm +0 -0
- package/src/generated/todo_core_bg.wasm.d.ts +1 -0
- package/src/guidance.ts +3 -1
- package/src/index.ts +1 -1
- package/src/schema.ts +15 -2
- package/src/wasm.ts +4 -0
- package/src/work.ts +1 -1
package/README.md
CHANGED
|
@@ -25,6 +25,8 @@ The model calls `todo` with one `op`. Tasks are addressed by their exact content
|
|
|
25
25
|
Creation and append leave tasks pending. Nothing starts automatically. This replaces the previous single-active, automatic-start behavior.
|
|
26
26
|
Use `start` to activate or reopen work explicitly. Starting a child also opens its parent. Starting a parent does not start its children.
|
|
27
27
|
|
|
28
|
+
Keep `content` a short headline: aim under 60 characters, imperative, no trailing detail. Put context, approach, or acceptance detail in the optional `description` (one or two sentences). Outcomes and subtask drafts accept `description`; a plain string item has none. A blank description counts as none. `update` with `description` sets it on an open task or subtask, and a blank value clears it. It never changes `content` or how a task is selected. `view` prints a description on the line under its headline; the Pi widget shows headlines only.
|
|
29
|
+
|
|
28
30
|
`items` accepts strings or outcomes with string subtasks:
|
|
29
31
|
|
|
30
32
|
```json
|
|
@@ -89,8 +91,10 @@ Alt+J/K scrolls the hosted rows. Alt+I toggles their expansion. Ordinary editor
|
|
|
89
91
|
`/todos` and Alt+T request the shared Todos view. `/todos list` still prints the full list.
|
|
90
92
|
When shared presentation ends, the standalone widget returns without changing task state.
|
|
91
93
|
|
|
92
|
-
The [version
|
|
94
|
+
The [version 3 display contract](https://github.com/oisin-ee/dogsled/blob/main/docs/pi-work.md)
|
|
93
95
|
defines the snapshot request, acknowledgement, release, and read-only view events.
|
|
96
|
+
Version 3 adds `display.sections` to the snapshot: four typed status groups (`in_progress`, `pending`, `completed`, `abandoned`), always present and in that order, each with a count and its items. Each item carries its text, optional description, review flag, contract summary, and all subtasks (each with its own optional description). The core owns this grouping; a presenter only draws it.
|
|
97
|
+
Pi-todo does not answer version 2 requests.
|
|
94
98
|
Incompatible versions leave the standalone widget available. Rendering failures restore it without changing saved tasks.
|
|
95
99
|
|
|
96
100
|
## Plannotator plans
|
package/package.json
CHANGED
package/src/display.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { Subtask, TodoList } from "./wasm.ts";
|
|
1
|
+
import type { Subtask, TodoList, TodoSection } from "./wasm.ts";
|
|
2
|
+
import { sections, view } from "./wasm.ts";
|
|
2
3
|
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
3
4
|
import { TodoView } from "./embedded.ts";
|
|
4
|
-
import { view } from "./wasm.ts";
|
|
5
5
|
|
|
6
6
|
/** Host-owned layout and rendering services for an inline todo view. */
|
|
7
7
|
interface ViewHost {
|
|
@@ -25,6 +25,8 @@ interface TodoDisplay {
|
|
|
25
25
|
readonly summary: string;
|
|
26
26
|
readonly current: string;
|
|
27
27
|
readonly text: string;
|
|
28
|
+
/** Status groups owned by the core: in_progress, pending, completed, abandoned. */
|
|
29
|
+
readonly sections: readonly TodoSection[];
|
|
28
30
|
readonly state: unknown;
|
|
29
31
|
readonly createView: (host: ViewHost) => HostedView;
|
|
30
32
|
}
|
|
@@ -58,6 +60,7 @@ const emptyCount = 0,
|
|
|
58
60
|
createView: (host) => new TodoView(list, host),
|
|
59
61
|
current,
|
|
60
62
|
empty: list.tasks.length === emptyCount,
|
|
63
|
+
sections: sections(list),
|
|
61
64
|
state: list,
|
|
62
65
|
summary: text.split("\n").at(headerIndex) ?? "",
|
|
63
66
|
text,
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export interface DraftItem {
|
|
7
7
|
content: string;
|
|
8
|
+
description?: string;
|
|
8
9
|
key?: string | undefined;
|
|
9
10
|
contract?: ContractDraft;
|
|
10
11
|
}
|
|
@@ -14,6 +15,10 @@ export interface DraftItem {
|
|
|
14
15
|
*/
|
|
15
16
|
export interface Subtask {
|
|
16
17
|
content: string;
|
|
18
|
+
/**
|
|
19
|
+
* Detail behind the short `content` headline.
|
|
20
|
+
*/
|
|
21
|
+
description?: string;
|
|
17
22
|
status: Status;
|
|
18
23
|
unit?: Unit;
|
|
19
24
|
}
|
|
@@ -31,6 +36,10 @@ export interface Change {
|
|
|
31
36
|
*/
|
|
32
37
|
export interface Task {
|
|
33
38
|
content: string;
|
|
39
|
+
/**
|
|
40
|
+
* Detail behind the short `content` headline.
|
|
41
|
+
*/
|
|
42
|
+
description?: string;
|
|
34
43
|
status: Status;
|
|
35
44
|
subtasks?: Subtask[];
|
|
36
45
|
unit?: Unit;
|
|
@@ -199,6 +208,10 @@ export interface Request {
|
|
|
199
208
|
contract?: ContractDraft | undefined;
|
|
200
209
|
start?: string | undefined;
|
|
201
210
|
evidence?: string | undefined;
|
|
211
|
+
/**
|
|
212
|
+
* For `update`: sets the description; blank clears it; absent leaves it.
|
|
213
|
+
*/
|
|
214
|
+
description?: string | undefined;
|
|
202
215
|
}
|
|
203
216
|
|
|
204
217
|
/**
|
|
@@ -217,6 +230,28 @@ export interface WidgetRow {
|
|
|
217
230
|
text: string;
|
|
218
231
|
}
|
|
219
232
|
|
|
233
|
+
/**
|
|
234
|
+
* One subtask of a section item, with its contract summary.
|
|
235
|
+
*/
|
|
236
|
+
export interface SectionChild {
|
|
237
|
+
status: Status;
|
|
238
|
+
text: string;
|
|
239
|
+
description: string | undefined;
|
|
240
|
+
unit: string | undefined;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* One top-level task of a section, with every subtask.
|
|
245
|
+
*/
|
|
246
|
+
export interface SectionItem {
|
|
247
|
+
status: Status;
|
|
248
|
+
text: string;
|
|
249
|
+
review: boolean;
|
|
250
|
+
description: string | undefined;
|
|
251
|
+
unit: string | undefined;
|
|
252
|
+
children: SectionChild[];
|
|
253
|
+
}
|
|
254
|
+
|
|
220
255
|
/**
|
|
221
256
|
* Opaque executor identity; no process interpretation belongs here.
|
|
222
257
|
*/
|
|
@@ -280,7 +315,7 @@ export interface Scope {
|
|
|
280
315
|
/**
|
|
281
316
|
* Root creation accepts standalone outcomes or outcomes with leaf work units.
|
|
282
317
|
*/
|
|
283
|
-
export type Item = string | { content: string; subtasks: LeafItem[] } | DraftItem;
|
|
318
|
+
export type Item = string | { content: string; description?: string; subtasks: LeafItem[] } | DraftItem;
|
|
284
319
|
|
|
285
320
|
/**
|
|
286
321
|
* Semantic styling for a terminal row.
|
|
@@ -316,6 +351,15 @@ export type Operation = "init" | "start" | "done" | "drop" | "append" | "view" |
|
|
|
316
351
|
*/
|
|
317
352
|
export type Status = "pending" | "in_progress" | "completed" | "abandoned";
|
|
318
353
|
|
|
354
|
+
/**
|
|
355
|
+
* The tasks of one status, in list order.
|
|
356
|
+
*/
|
|
357
|
+
export interface TodoSection {
|
|
358
|
+
status: Status;
|
|
359
|
+
count: number;
|
|
360
|
+
items: SectionItem[];
|
|
361
|
+
}
|
|
362
|
+
|
|
319
363
|
/**
|
|
320
364
|
* The whole todo list of a session branch.
|
|
321
365
|
*/
|
|
@@ -442,6 +486,15 @@ export function parse(snapshot: unknown): TodoList;
|
|
|
442
486
|
*/
|
|
443
487
|
export function protect(before: TodoList, after: TodoList, leases: UnitRef[]): void;
|
|
444
488
|
|
|
489
|
+
/**
|
|
490
|
+
* Typed status groups of `list`: always four sections, in a fixed order.
|
|
491
|
+
*
|
|
492
|
+
* # Errors
|
|
493
|
+
*
|
|
494
|
+
* Throws when `list` is not a valid todo list.
|
|
495
|
+
*/
|
|
496
|
+
export function sections(list: TodoList): TodoSection[];
|
|
497
|
+
|
|
445
498
|
/**
|
|
446
499
|
* Records an executor's exact release evidence, never acceptance.
|
|
447
500
|
*
|
|
@@ -482,6 +535,7 @@ export interface InitOutput {
|
|
|
482
535
|
readonly inspect: (a: number, b: number, c: number, d: number) => void;
|
|
483
536
|
readonly parse: (a: number, b: number) => void;
|
|
484
537
|
readonly protect: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
538
|
+
readonly sections: (a: number, b: number) => void;
|
|
485
539
|
readonly settle: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
|
|
486
540
|
readonly view: (a: number, b: number) => void;
|
|
487
541
|
readonly widget: (a: number, b: number, c: number) => void;
|
|
@@ -290,6 +290,35 @@ export function protect(before, after, leases) {
|
|
|
290
290
|
}
|
|
291
291
|
}
|
|
292
292
|
|
|
293
|
+
/**
|
|
294
|
+
* Typed status groups of `list`: always four sections, in a fixed order.
|
|
295
|
+
*
|
|
296
|
+
* # Errors
|
|
297
|
+
*
|
|
298
|
+
* Throws when `list` is not a valid todo list.
|
|
299
|
+
* @param {TodoList} list
|
|
300
|
+
* @returns {TodoSection[]}
|
|
301
|
+
*/
|
|
302
|
+
export function sections(list) {
|
|
303
|
+
try {
|
|
304
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
305
|
+
wasm.sections(retptr, addBorrowedObject(list));
|
|
306
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
307
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
308
|
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
|
309
|
+
var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
|
|
310
|
+
if (r3) {
|
|
311
|
+
throw takeObject(r2);
|
|
312
|
+
}
|
|
313
|
+
var v1 = getArrayJsValueFromWasm0(r0, r1);
|
|
314
|
+
wasm.__wbindgen_export4(r0, r1 * 4, 4);
|
|
315
|
+
return v1;
|
|
316
|
+
} finally {
|
|
317
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
318
|
+
heap[stack_pointer++] = undefined;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
293
322
|
/**
|
|
294
323
|
* Records an executor's exact release evidence, never acceptance.
|
|
295
324
|
*
|
|
Binary file
|
|
@@ -11,6 +11,7 @@ export const init: (a: number, b: number, c: number) => void;
|
|
|
11
11
|
export const inspect: (a: number, b: number, c: number, d: number) => void;
|
|
12
12
|
export const parse: (a: number, b: number) => void;
|
|
13
13
|
export const protect: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
14
|
+
export const sections: (a: number, b: number) => void;
|
|
14
15
|
export const settle: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
|
|
15
16
|
export const view: (a: number, b: number) => void;
|
|
16
17
|
export const widget: (a: number, b: number, c: number) => void;
|
package/src/guidance.ts
CHANGED
|
@@ -7,6 +7,8 @@ const workUnitGuidance =
|
|
|
7
7
|
"Supply deliverable, repository-relative scope, acceptance, prerequisite IDs, and self or worker/profile assignment. " +
|
|
8
8
|
"Use local keys for new prerequisites and the optional start selector for atomic creation and activation. " +
|
|
9
9
|
"Use returned IDs after creation. Update drafts before start; only one complete self leaf executes locally. " +
|
|
10
|
-
"Done requires concrete acceptance evidence; worker exit alone is not acceptance."
|
|
10
|
+
"Done requires concrete acceptance evidence; worker exit alone is not acceptance. " +
|
|
11
|
+
"Keep content a short headline (aim under 60 characters, imperative, no trailing detail); " +
|
|
12
|
+
"put context, approach, or acceptance detail in the optional description (one or two sentences).";
|
|
11
13
|
|
|
12
14
|
export { workUnitGuidance };
|
package/src/index.ts
CHANGED
|
@@ -39,7 +39,7 @@ export default function piTodo(pi: TodoAPI): void {
|
|
|
39
39
|
provider.register();
|
|
40
40
|
registerGate(pi, provider);
|
|
41
41
|
pi.registerTool({
|
|
42
|
-
description: `Keep branch-local outcomes and executable contracts. Use returned IDs, not labels. Draft creation is pending. Start one complete self-assigned leaf; workers require their assigned profile through the executor. Update replaces pending contract fields. Done requires acceptance evidence. Parents require explicit integration review after children close. ${workUnitGuidance}`,
|
|
42
|
+
description: `Keep branch-local outcomes and executable contracts. Use returned IDs, not labels. Draft creation is pending. Start one complete self-assigned leaf; workers require their assigned profile through the executor. Update replaces pending contract fields and may set or clear an open item's description. Done requires acceptance evidence. Parents require explicit integration review after children close. ${workUnitGuidance}`,
|
|
43
43
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
44
44
|
const result = provider.run(params, ctx);
|
|
45
45
|
work.publish(ctx);
|
package/src/schema.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { StringEnum } from "@earendil-works/pi-ai";
|
|
2
2
|
import { Type } from "typebox";
|
|
3
3
|
|
|
4
|
-
const
|
|
4
|
+
const description = Type.String({
|
|
5
|
+
description:
|
|
6
|
+
"Optional detail behind the short content headline: context, approach, or acceptance in one or two sentences. Blank is none.",
|
|
7
|
+
}),
|
|
8
|
+
strings = Type.Immutable(Type.Array(Type.String())),
|
|
5
9
|
scope = Type.Immutable(
|
|
6
10
|
Type.Object(
|
|
7
11
|
{
|
|
@@ -43,6 +47,7 @@ const strings = Type.Immutable(Type.Array(Type.String())),
|
|
|
43
47
|
{
|
|
44
48
|
content: Type.String(),
|
|
45
49
|
contract: Type.Optional(contract),
|
|
50
|
+
description: Type.Optional(description),
|
|
46
51
|
key: Type.Optional(Type.String()),
|
|
47
52
|
},
|
|
48
53
|
{ additionalProperties: false },
|
|
@@ -51,7 +56,10 @@ const strings = Type.Immutable(Type.Array(Type.String())),
|
|
|
51
56
|
leaf = Type.Union([Type.String(), draft]),
|
|
52
57
|
subtasks = Type.Immutable(Type.Array(leaf)),
|
|
53
58
|
outcome = Type.Immutable(
|
|
54
|
-
Type.Object(
|
|
59
|
+
Type.Object(
|
|
60
|
+
{ content: Type.String(), description: Type.Optional(description), subtasks },
|
|
61
|
+
{ additionalProperties: false },
|
|
62
|
+
),
|
|
55
63
|
),
|
|
56
64
|
item = Type.Union([leaf, outcome]),
|
|
57
65
|
items = Type.Immutable(Type.Array(item)),
|
|
@@ -68,10 +76,15 @@ const strings = Type.Immutable(Type.Array(Type.String())),
|
|
|
68
76
|
description:
|
|
69
77
|
"Unit ID, or exact legacy content before migration. Children can use their ID without parent.",
|
|
70
78
|
}),
|
|
79
|
+
change = Type.String({
|
|
80
|
+
description:
|
|
81
|
+
"update only: set the open task or subtask description; blank clears it; omit to keep it. Never changes content.",
|
|
82
|
+
}),
|
|
71
83
|
parameters = Type.Immutable(
|
|
72
84
|
Type.Object(
|
|
73
85
|
{
|
|
74
86
|
contract: Type.Optional(contract),
|
|
87
|
+
description: Type.Optional(change),
|
|
75
88
|
evidence: Type.Optional(evidence),
|
|
76
89
|
items: Type.Optional(items),
|
|
77
90
|
op: StringEnum(["init", "start", "done", "drop", "append", "view", "update"] as const),
|
package/src/wasm.ts
CHANGED
|
@@ -25,6 +25,7 @@ export {
|
|
|
25
25
|
completion_reminder as completionReminder,
|
|
26
26
|
init,
|
|
27
27
|
parse,
|
|
28
|
+
sections,
|
|
28
29
|
view,
|
|
29
30
|
widget,
|
|
30
31
|
} from "./generated/todo_core.js";
|
|
@@ -51,10 +52,13 @@ export type {
|
|
|
51
52
|
Operation,
|
|
52
53
|
ReminderFact,
|
|
53
54
|
Request,
|
|
55
|
+
SectionChild,
|
|
56
|
+
SectionItem,
|
|
54
57
|
Status,
|
|
55
58
|
Subtask,
|
|
56
59
|
Task,
|
|
57
60
|
TodoList,
|
|
61
|
+
TodoSection,
|
|
58
62
|
WidgetKind,
|
|
59
63
|
WidgetRow,
|
|
60
64
|
} from "./generated/todo_core.js";
|
package/src/work.ts
CHANGED
|
@@ -12,7 +12,7 @@ interface WorkHost extends TodoHost {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
type WorkCommands = Readonly<Pick<ExtensionAPI, "registerCommand" | "registerShortcut">>;
|
|
15
|
-
const protocolVersion =
|
|
15
|
+
const protocolVersion = 3,
|
|
16
16
|
initialRevision = 0;
|
|
17
17
|
|
|
18
18
|
interface WorkContext extends TodoContext {
|