@dreki-gg/pi-plan-mode 0.26.0 → 0.26.1
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/CHANGELOG.md +12 -0
- package/extensions/plan-mode/__tests__/initiative-status.test.ts +5 -5
- package/extensions/plan-mode/__tests__/plan-references-context.test.ts +4 -4
- package/extensions/plan-mode/__tests__/reconcile-plans.test.ts +3 -3
- package/extensions/plan-mode/__tests__/resolve-plan.test.ts +4 -4
- package/extensions/plan-mode/__tests__/revise-plan.test.ts +4 -4
- package/extensions/plan-mode/__tests__/submit-initiative.test.ts +2 -2
- package/extensions/plan-mode/__tests__/submit-plan.test.ts +3 -3
- package/extensions/plan-mode/__tests__/update-initiative.test.ts +2 -2
- package/extensions/plan-mode/__tests__/update-plan.test.ts +2 -2
- package/extensions/plan-mode/__tests__/utils.test.ts +2 -1
- package/extensions/plan-mode/commands/list-initiatives.ts +19 -109
- package/extensions/plan-mode/commands/list-plans.ts +21 -168
- package/extensions/plan-mode/exec-pending.ts +59 -0
- package/extensions/plan-mode/index.ts +8 -7
- package/extensions/plan-mode/references/context.ts +5 -5
- package/extensions/plan-mode/references/plan-index.ts +1 -1
- package/extensions/plan-mode/resolve-plan.ts +4 -4
- package/extensions/plan-mode/resume.ts +6 -5
- package/extensions/plan-mode/tools/add-task.ts +1 -1
- package/extensions/plan-mode/tools/initiative-status.ts +6 -6
- package/extensions/plan-mode/tools/preview-prototype.ts +3 -3
- package/extensions/plan-mode/tools/reconcile-plans.ts +2 -2
- package/extensions/plan-mode/tools/revise-plan.ts +7 -7
- package/extensions/plan-mode/tools/submit-initiative.ts +4 -4
- package/extensions/plan-mode/tools/submit-plan.ts +7 -7
- package/extensions/plan-mode/tools/update-initiative.ts +2 -2
- package/extensions/plan-mode/tools/update-plan.ts +3 -3
- package/extensions/plan-mode/types.ts +17 -59
- package/extensions/plan-mode/utils.ts +2 -29
- package/package.json +2 -1
- package/extensions/plan-mode/__tests__/atomic-write.test.ts +0 -45
- package/extensions/plan-mode/__tests__/concurrent-writes.test.ts +0 -85
- package/extensions/plan-mode/__tests__/initiative-readiness.test.ts +0 -159
- package/extensions/plan-mode/__tests__/initiatives-manifest.test.ts +0 -89
- package/extensions/plan-mode/__tests__/list-initiatives.test.ts +0 -59
- package/extensions/plan-mode/__tests__/list-plans.test.ts +0 -253
- package/extensions/plan-mode/__tests__/plan-storage.test.ts +0 -57
- package/extensions/plan-mode/__tests__/plans-manifest.test.ts +0 -120
- package/extensions/plan-mode/__tests__/reconcile.test.ts +0 -188
- package/extensions/plan-mode/__tests__/schema.test.ts +0 -334
- package/extensions/plan-mode/__tests__/task-status.test.ts +0 -74
- package/extensions/plan-mode/__tests__/task-storage.test.ts +0 -101
- package/extensions/plan-mode/effects/filesystem.ts +0 -65
- package/extensions/plan-mode/effects/runtime.ts +0 -24
- package/extensions/plan-mode/errors.ts +0 -105
- package/extensions/plan-mode/initiative.ts +0 -172
- package/extensions/plan-mode/plan-storage.ts +0 -6
- package/extensions/plan-mode/reconcile.ts +0 -235
- package/extensions/plan-mode/schema.ts +0 -99
- package/extensions/plan-mode/storage/atomic-write.ts +0 -75
- package/extensions/plan-mode/storage/file-lock.ts +0 -49
- package/extensions/plan-mode/storage/initiatives-manifest.ts +0 -154
- package/extensions/plan-mode/storage/plan-storage.ts +0 -88
- package/extensions/plan-mode/storage/plans-manifest.ts +0 -174
- package/extensions/plan-mode/storage/task-storage.ts +0 -111
- package/extensions/plan-mode/task-status.ts +0 -46
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import { Effect, Either, Option } from 'effect';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
import { FileSystem } from '../effects/filesystem.js';
|
|
4
|
-
import {
|
|
5
|
-
JsonlParseError,
|
|
6
|
-
JsonlValidationError,
|
|
7
|
-
MissingMetaRecord,
|
|
8
|
-
PlanWriteError,
|
|
9
|
-
TaskNotFound,
|
|
10
|
-
TasksFileNotFound,
|
|
11
|
-
} from '../errors.js';
|
|
12
|
-
import { decodeTasksLine } from '../schema.js';
|
|
13
|
-
import type { TaskMeta, TaskRecord } from '../types.js';
|
|
14
|
-
import { withFileLock } from './file-lock.js';
|
|
15
|
-
|
|
16
|
-
const TASKS_FILE = 'tasks.jsonl';
|
|
17
|
-
|
|
18
|
-
export interface TasksSnapshot {
|
|
19
|
-
meta: TaskMeta;
|
|
20
|
-
tasks: TaskRecord[];
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
type ReadError = JsonlParseError | JsonlValidationError | MissingMetaRecord;
|
|
24
|
-
|
|
25
|
-
export function readTasksJsonl(
|
|
26
|
-
planDir: string,
|
|
27
|
-
): Effect.Effect<TasksSnapshot | undefined, ReadError, FileSystem> {
|
|
28
|
-
const path = join(planDir, TASKS_FILE);
|
|
29
|
-
return Effect.gen(function* () {
|
|
30
|
-
const fs = yield* FileSystem;
|
|
31
|
-
// A read failure (missing or unreadable file) is treated as "no snapshot".
|
|
32
|
-
const maybeText = yield* Effect.option(fs.readFileString(path));
|
|
33
|
-
if (Option.isNone(maybeText)) return undefined;
|
|
34
|
-
|
|
35
|
-
const text = maybeText.value;
|
|
36
|
-
if (!text.trim()) return yield* Effect.fail(new MissingMetaRecord({ path }));
|
|
37
|
-
|
|
38
|
-
let meta: TaskMeta | undefined;
|
|
39
|
-
const tasks: TaskRecord[] = [];
|
|
40
|
-
for (const [index, raw] of text.split(/\r?\n/).entries()) {
|
|
41
|
-
if (!raw.trim()) continue;
|
|
42
|
-
const line = index + 1;
|
|
43
|
-
|
|
44
|
-
let parsed: unknown;
|
|
45
|
-
try {
|
|
46
|
-
parsed = JSON.parse(raw);
|
|
47
|
-
} catch (cause) {
|
|
48
|
-
return yield* Effect.fail(new JsonlParseError({ path, line, cause }));
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const decoded = decodeTasksLine(parsed);
|
|
52
|
-
if (Either.isLeft(decoded)) {
|
|
53
|
-
return yield* Effect.fail(
|
|
54
|
-
new JsonlValidationError({ path, line, reason: decoded.left.message }),
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const record = decoded.right;
|
|
59
|
-
if (record._type === 'meta') meta = record;
|
|
60
|
-
else tasks.push(record);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (!meta) return yield* Effect.fail(new MissingMetaRecord({ path }));
|
|
64
|
-
return { meta, tasks };
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export function writeTasksJsonl(
|
|
69
|
-
planDir: string,
|
|
70
|
-
meta: TaskMeta,
|
|
71
|
-
tasks: TaskRecord[],
|
|
72
|
-
): Effect.Effect<void, PlanWriteError, FileSystem> {
|
|
73
|
-
return Effect.gen(function* () {
|
|
74
|
-
const fs = yield* FileSystem;
|
|
75
|
-
yield* fs.makeDir(planDir);
|
|
76
|
-
const content = [meta, ...tasks].map((record) => JSON.stringify(record)).join('\n') + '\n';
|
|
77
|
-
yield* fs.writeFileAtomic(join(planDir, TASKS_FILE), content);
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export function updateTask(
|
|
82
|
-
planDir: string,
|
|
83
|
-
taskId: string,
|
|
84
|
-
updates: Partial<Omit<TaskRecord, '_type' | 'id' | 'created_at'>>,
|
|
85
|
-
): Effect.Effect<
|
|
86
|
-
TaskRecord,
|
|
87
|
-
ReadError | PlanWriteError | TasksFileNotFound | TaskNotFound,
|
|
88
|
-
FileSystem
|
|
89
|
-
> {
|
|
90
|
-
// Serialize the read-modify-write so concurrent task updates to the same plan
|
|
91
|
-
// (e.g. parallel update_task / update_tasks calls) cannot clobber each other.
|
|
92
|
-
return withFileLock(
|
|
93
|
-
join(planDir, TASKS_FILE),
|
|
94
|
-
Effect.gen(function* () {
|
|
95
|
-
const snapshot = yield* readTasksJsonl(planDir);
|
|
96
|
-
if (!snapshot) return yield* Effect.fail(new TasksFileNotFound({ planDir }));
|
|
97
|
-
|
|
98
|
-
const index = snapshot.tasks.findIndex((task) => task.id === taskId);
|
|
99
|
-
if (index === -1) return yield* Effect.fail(new TaskNotFound({ planDir, taskId }));
|
|
100
|
-
|
|
101
|
-
const updated: TaskRecord = {
|
|
102
|
-
...snapshot.tasks[index],
|
|
103
|
-
...updates,
|
|
104
|
-
updated_at: new Date().toISOString(),
|
|
105
|
-
};
|
|
106
|
-
snapshot.tasks[index] = updated;
|
|
107
|
-
yield* writeTasksJsonl(planDir, snapshot.meta, snapshot.tasks);
|
|
108
|
-
return updated;
|
|
109
|
-
}),
|
|
110
|
-
);
|
|
111
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pure helpers for reasoning about task status at execution checkpoints.
|
|
3
|
-
*
|
|
4
|
-
* `deferred` tasks are discovered follow-ups kept out of the active queue, so
|
|
5
|
-
* they are excluded from "resolved" checks but block plan finalization.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { TaskRecord } from './types.js';
|
|
9
|
-
|
|
10
|
-
export function deferredTasks(tasks: readonly TaskRecord[]): TaskRecord[] {
|
|
11
|
-
return tasks.filter((task) => task.status === 'deferred');
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* True when no active work remains — every task is done, skipped, or deferred
|
|
16
|
-
* (nothing pending or blocked).
|
|
17
|
-
*/
|
|
18
|
-
export function activeTasksResolved(tasks: readonly TaskRecord[]): boolean {
|
|
19
|
-
return tasks.every(
|
|
20
|
-
(task) => task.status === 'done' || task.status === 'skipped' || task.status === 'deferred',
|
|
21
|
-
);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* True when the plan can be marked complete: active work is resolved AND there
|
|
26
|
-
* are no deferred follow-ups awaiting the user's decision.
|
|
27
|
-
*/
|
|
28
|
-
export function isPlanFinalizable(tasks: readonly TaskRecord[]): boolean {
|
|
29
|
-
return activeTasksResolved(tasks) && !tasks.some((task) => task.status === 'deferred');
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Reactivate tasks for a resumed run: blocked tasks and deferred follow-ups
|
|
34
|
-
* become pending (mutated in place). Returns true if anything changed.
|
|
35
|
-
*/
|
|
36
|
-
export function reactivateForExecution(tasks: TaskRecord[], timestamp: string): boolean {
|
|
37
|
-
let changed = false;
|
|
38
|
-
for (const task of tasks) {
|
|
39
|
-
if (task.status === 'blocked' || task.status === 'deferred') {
|
|
40
|
-
task.status = 'pending';
|
|
41
|
-
task.updated_at = timestamp;
|
|
42
|
-
changed = true;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return changed;
|
|
46
|
-
}
|