@trevonistrevon/pi-loop 0.4.11 → 0.5.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.
Files changed (87) hide show
  1. package/README.md +20 -9
  2. package/dist/commands/loop-command.d.ts +22 -0
  3. package/dist/commands/loop-command.js +148 -0
  4. package/dist/commands/tasks-command.d.ts +15 -0
  5. package/dist/commands/tasks-command.js +117 -0
  6. package/dist/coordinator.d.ts +35 -0
  7. package/dist/coordinator.js +56 -0
  8. package/dist/goal-coordinator.d.ts +22 -0
  9. package/dist/goal-coordinator.js +28 -0
  10. package/dist/goal-reducer.d.ts +89 -0
  11. package/dist/goal-reducer.js +181 -0
  12. package/dist/goal-store.d.ts +31 -0
  13. package/dist/goal-store.js +298 -0
  14. package/dist/goal-types.d.ts +82 -0
  15. package/dist/goal-types.js +1 -0
  16. package/dist/goal-verifier.d.ts +20 -0
  17. package/dist/goal-verifier.js +198 -0
  18. package/dist/index.js +130 -1087
  19. package/dist/loop-reducer.d.ts +63 -0
  20. package/dist/loop-reducer.js +67 -0
  21. package/dist/monitor-completion-coordinator.d.ts +10 -0
  22. package/dist/monitor-completion-coordinator.js +13 -0
  23. package/dist/monitor-manager.d.ts +2 -0
  24. package/dist/monitor-manager.js +107 -29
  25. package/dist/monitor-reducer.d.ts +82 -0
  26. package/dist/monitor-reducer.js +69 -0
  27. package/dist/notification-reducer.d.ts +81 -0
  28. package/dist/notification-reducer.js +65 -0
  29. package/dist/runtime/monitor-ondone-runtime.d.ts +13 -0
  30. package/dist/runtime/monitor-ondone-runtime.js +49 -0
  31. package/dist/runtime/notification-runtime.d.ts +34 -0
  32. package/dist/runtime/notification-runtime.js +152 -0
  33. package/dist/runtime/scope.d.ts +8 -0
  34. package/dist/runtime/scope.js +33 -0
  35. package/dist/runtime/session-runtime.d.ts +39 -0
  36. package/dist/runtime/session-runtime.js +110 -0
  37. package/dist/runtime/task-backlog-runtime.d.ts +36 -0
  38. package/dist/runtime/task-backlog-runtime.js +105 -0
  39. package/dist/runtime/task-rpc.d.ts +19 -0
  40. package/dist/runtime/task-rpc.js +118 -0
  41. package/dist/store.d.ts +7 -4
  42. package/dist/store.js +129 -49
  43. package/dist/task-backlog-coordinator.d.ts +12 -0
  44. package/dist/task-backlog-coordinator.js +22 -0
  45. package/dist/task-reducer.d.ts +66 -0
  46. package/dist/task-reducer.js +76 -0
  47. package/dist/task-store.d.ts +8 -4
  48. package/dist/task-store.js +102 -33
  49. package/dist/tools/loop-tools.d.ts +41 -0
  50. package/dist/tools/loop-tools.js +241 -0
  51. package/dist/tools/monitor-tools.d.ts +25 -0
  52. package/dist/tools/monitor-tools.js +110 -0
  53. package/dist/tools/native-task-tools.d.ts +15 -0
  54. package/dist/tools/native-task-tools.js +127 -0
  55. package/docs/architecture/goal-state-schema.md +505 -0
  56. package/docs/architecture/state-machine-migration.md +546 -0
  57. package/docs/architecture/state-machine-reducer-event-model.md +823 -0
  58. package/docs/architecture/state-machine-test-matrix.md +249 -0
  59. package/docs/architecture/state-machine-transition-map.md +436 -0
  60. package/package.json +1 -1
  61. package/src/commands/loop-command.ts +184 -0
  62. package/src/commands/tasks-command.ts +135 -0
  63. package/src/coordinator.ts +115 -0
  64. package/src/goal-coordinator.ts +58 -0
  65. package/src/goal-reducer.ts +280 -0
  66. package/src/goal-store.ts +315 -0
  67. package/src/goal-types.ts +104 -0
  68. package/src/goal-verifier.ts +241 -0
  69. package/src/index.ts +134 -1147
  70. package/src/loop-reducer.ts +148 -0
  71. package/src/monitor-completion-coordinator.ts +24 -0
  72. package/src/monitor-manager.ts +115 -27
  73. package/src/monitor-reducer.ts +166 -0
  74. package/src/notification-reducer.ts +155 -0
  75. package/src/runtime/monitor-ondone-runtime.ts +75 -0
  76. package/src/runtime/notification-runtime.ts +212 -0
  77. package/src/runtime/scope.ts +37 -0
  78. package/src/runtime/session-runtime.ts +168 -0
  79. package/src/runtime/task-backlog-runtime.ts +163 -0
  80. package/src/runtime/task-rpc.ts +150 -0
  81. package/src/store.ts +132 -50
  82. package/src/task-backlog-coordinator.ts +32 -0
  83. package/src/task-reducer.ts +152 -0
  84. package/src/task-store.ts +103 -31
  85. package/src/tools/loop-tools.ts +304 -0
  86. package/src/tools/monitor-tools.ts +145 -0
  87. package/src/tools/native-task-tools.ts +144 -0
@@ -0,0 +1,181 @@
1
+ function cloneState(state) {
2
+ return {
3
+ nextId: state.nextId,
4
+ goalsById: { ...state.goalsById },
5
+ };
6
+ }
7
+ function emptyProgress() {
8
+ return {
9
+ totalTasks: 0,
10
+ pendingTasks: 0,
11
+ inProgressTasks: 0,
12
+ completedTasks: 0,
13
+ activeLoops: 0,
14
+ pausedLoops: 0,
15
+ runningMonitors: 0,
16
+ completedMonitors: 0,
17
+ erroredMonitors: 0,
18
+ stoppedMonitors: 0,
19
+ };
20
+ }
21
+ function emptyVerification() {
22
+ return {
23
+ attempts: 0,
24
+ passes: 0,
25
+ failures: 0,
26
+ };
27
+ }
28
+ function persist(goal) {
29
+ return {
30
+ type: "PERSIST_GOAL",
31
+ entityType: "goal",
32
+ entityId: goal.id,
33
+ payload: { goal },
34
+ };
35
+ }
36
+ function isTerminal(goal) {
37
+ return goal.status === "satisfied" || goal.status === "failed" || goal.status === "archived";
38
+ }
39
+ export function reduceGoalState(state, event) {
40
+ if (event.type === "GOAL_CREATED") {
41
+ const next = cloneState(state);
42
+ const id = String(next.nextId++);
43
+ const goal = {
44
+ id,
45
+ title: event.payload.title,
46
+ description: event.payload.description,
47
+ status: "pending",
48
+ verificationStatus: "unknown",
49
+ createdAt: event.at,
50
+ updatedAt: event.at,
51
+ scope: event.payload.scope,
52
+ criteria: event.payload.criteria,
53
+ progress: emptyProgress(),
54
+ verification: emptyVerification(),
55
+ metadata: event.payload.metadata,
56
+ };
57
+ next.goalsById[id] = goal;
58
+ return {
59
+ state: next,
60
+ effects: [persist(goal)],
61
+ };
62
+ }
63
+ const id = event.payload.id;
64
+ const current = state.goalsById[id];
65
+ if (!current)
66
+ return { state, effects: [] };
67
+ if (isTerminal(current) && event.type !== "GOAL_ARCHIVED")
68
+ return { state, effects: [] };
69
+ const next = cloneState(state);
70
+ const goal = {
71
+ ...current,
72
+ progress: { ...current.progress },
73
+ verification: { ...current.verification },
74
+ };
75
+ let extraEffects = [];
76
+ if (event.type === "GOAL_ACTIVATED") {
77
+ goal.status = "active";
78
+ goal.activatedAt ??= event.at;
79
+ goal.updatedAt = event.at;
80
+ extraEffects = [{
81
+ type: "REQUEST_GOAL_VERIFICATION",
82
+ entityType: "goal",
83
+ entityId: id,
84
+ payload: { id },
85
+ }];
86
+ }
87
+ if (event.type === "GOAL_PROGRESS_RECORDED") {
88
+ goal.progress = event.payload.progress;
89
+ goal.updatedAt = event.at;
90
+ }
91
+ if (event.type === "GOAL_VERIFICATION_STARTED") {
92
+ goal.verificationStatus = "checking";
93
+ goal.verification.attempts += 1;
94
+ goal.verification.lastCheckedAt = event.at;
95
+ goal.updatedAt = event.at;
96
+ }
97
+ if (event.type === "GOAL_VERIFICATION_PASSED") {
98
+ if (event.payload.progress)
99
+ goal.progress = event.payload.progress;
100
+ goal.status = "satisfied";
101
+ goal.verificationStatus = "verified";
102
+ goal.verification.passes += 1;
103
+ goal.verification.lastPassedAt = event.at;
104
+ goal.verification.lastCheckedAt = event.at;
105
+ goal.verification.lastReason = event.payload.reason;
106
+ goal.resolvedAt = event.at;
107
+ goal.updatedAt = event.at;
108
+ }
109
+ if (event.type === "GOAL_VERIFICATION_FAILED") {
110
+ if (event.payload.progress)
111
+ goal.progress = event.payload.progress;
112
+ goal.verificationStatus = "unverified";
113
+ goal.verification.failures += 1;
114
+ goal.verification.lastFailedAt = event.at;
115
+ goal.verification.lastCheckedAt = event.at;
116
+ goal.verification.lastReason = event.payload.reason;
117
+ if (goal.status === "pending")
118
+ goal.status = "active";
119
+ goal.updatedAt = event.at;
120
+ }
121
+ if (event.type === "GOAL_BLOCKED") {
122
+ if (event.payload.progress)
123
+ goal.progress = event.payload.progress;
124
+ goal.status = "blocked";
125
+ goal.verificationStatus = "inconclusive";
126
+ goal.verification.failures += 1;
127
+ goal.verification.lastFailedAt = event.at;
128
+ goal.verification.lastCheckedAt = event.at;
129
+ goal.verification.lastReason = event.payload.reason;
130
+ goal.updatedAt = event.at;
131
+ }
132
+ if (event.type === "GOAL_UNBLOCKED") {
133
+ goal.status = "active";
134
+ goal.updatedAt = event.at;
135
+ }
136
+ if (event.type === "GOAL_SATISFIED") {
137
+ goal.status = "satisfied";
138
+ goal.verificationStatus = "verified";
139
+ goal.verification.lastReason = event.payload.reason ?? goal.verification.lastReason;
140
+ goal.resolvedAt = event.at;
141
+ goal.updatedAt = event.at;
142
+ }
143
+ if (event.type === "GOAL_FAILED") {
144
+ if (event.payload.progress)
145
+ goal.progress = event.payload.progress;
146
+ goal.status = "failed";
147
+ goal.verificationStatus = "unverified";
148
+ goal.verification.failures += 1;
149
+ goal.verification.lastFailedAt = event.at;
150
+ goal.verification.lastCheckedAt = event.at;
151
+ goal.verification.lastReason = event.payload.reason;
152
+ goal.resolvedAt = event.at;
153
+ goal.updatedAt = event.at;
154
+ }
155
+ if (event.type === "GOAL_ARCHIVED") {
156
+ goal.status = "archived";
157
+ goal.resolvedAt = event.at;
158
+ goal.updatedAt = event.at;
159
+ if (event.payload.reason !== undefined) {
160
+ goal.verification.lastReason = event.payload.reason;
161
+ }
162
+ }
163
+ if (event.type === "GOAL_UPDATED") {
164
+ if (event.payload.title !== undefined)
165
+ goal.title = event.payload.title;
166
+ if (event.payload.description !== undefined)
167
+ goal.description = event.payload.description;
168
+ if (event.payload.scope !== undefined)
169
+ goal.scope = event.payload.scope;
170
+ if (event.payload.criteria !== undefined)
171
+ goal.criteria = event.payload.criteria;
172
+ if (event.payload.metadata !== undefined)
173
+ goal.metadata = event.payload.metadata;
174
+ goal.updatedAt = event.at;
175
+ }
176
+ next.goalsById[id] = goal;
177
+ return {
178
+ state: next,
179
+ effects: [persist(goal), ...extraEffects],
180
+ };
181
+ }
@@ -0,0 +1,31 @@
1
+ import type { GoalCriteria, GoalEntry, GoalProgressSnapshot, GoalScope } from "./goal-types.js";
2
+ export declare class GoalStore {
3
+ private filePath;
4
+ private lockPath;
5
+ private nextId;
6
+ private goals;
7
+ constructor(listIdOrPath?: string);
8
+ private load;
9
+ private save;
10
+ private withLock;
11
+ private toReducerState;
12
+ private applyReducerEvent;
13
+ create(title: string, description: string, scope: GoalScope, criteria: GoalCriteria, metadata?: Record<string, unknown>): GoalEntry;
14
+ get(id: string): GoalEntry | undefined;
15
+ list(): GoalEntry[];
16
+ activate(id: string): GoalEntry | undefined;
17
+ recordProgress(id: string, progress: GoalProgressSnapshot): GoalEntry | undefined;
18
+ markVerificationStarted(id: string): GoalEntry | undefined;
19
+ markVerified(id: string, reason: string, progress?: GoalProgressSnapshot): GoalEntry | undefined;
20
+ markFailed(id: string, reason: string, progress?: GoalProgressSnapshot): GoalEntry | undefined;
21
+ markBlocked(id: string, reason: string, progress?: GoalProgressSnapshot): GoalEntry | undefined;
22
+ unblock(id: string): GoalEntry | undefined;
23
+ updateDetails(id: string, fields: {
24
+ title?: string;
25
+ description?: string;
26
+ scope?: GoalScope;
27
+ criteria?: GoalCriteria;
28
+ metadata?: Record<string, unknown>;
29
+ }): GoalEntry | undefined;
30
+ archive(id: string, reason?: string): GoalEntry | undefined;
31
+ }
@@ -0,0 +1,298 @@
1
+ import { existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { dirname, isAbsolute, join } from "node:path";
4
+ import { reduceGoalState } from "./goal-reducer.js";
5
+ const GOALS_DIR = join(homedir(), ".pi", "goals");
6
+ const LOCK_RETRY_MS = 50;
7
+ const LOCK_MAX_RETRIES = 100;
8
+ const MAX_GOALS = 200;
9
+ function acquireLock(lockPath) {
10
+ for (let i = 0; i < LOCK_MAX_RETRIES; i++) {
11
+ try {
12
+ writeFileSync(lockPath, `${process.pid}`, { flag: "wx" });
13
+ return;
14
+ }
15
+ catch (e) {
16
+ if (e.code === "EEXIST") {
17
+ try {
18
+ const pid = parseInt(readFileSync(lockPath, "utf-8"), 10);
19
+ if (!pid || !isProcessRunning(pid)) {
20
+ try {
21
+ unlinkSync(lockPath);
22
+ }
23
+ catch { /* ignore */ }
24
+ continue;
25
+ }
26
+ }
27
+ catch { /* ignore read errors */ }
28
+ const start = Date.now();
29
+ while (Date.now() - start < LOCK_RETRY_MS) { /* busy wait */ }
30
+ continue;
31
+ }
32
+ throw e;
33
+ }
34
+ }
35
+ throw new Error(`Failed to acquire lock: ${lockPath}`);
36
+ }
37
+ function releaseLock(lockPath) {
38
+ try {
39
+ unlinkSync(lockPath);
40
+ }
41
+ catch { /* ignore */ }
42
+ }
43
+ function isProcessRunning(pid) {
44
+ try {
45
+ process.kill(pid, 0);
46
+ return true;
47
+ }
48
+ catch {
49
+ return false;
50
+ }
51
+ }
52
+ export class GoalStore {
53
+ filePath;
54
+ lockPath;
55
+ nextId = 1;
56
+ goals = new Map();
57
+ constructor(listIdOrPath) {
58
+ if (!listIdOrPath)
59
+ return;
60
+ const isAbsPath = isAbsolute(listIdOrPath);
61
+ const filePath = isAbsPath ? listIdOrPath : join(GOALS_DIR, `${listIdOrPath}.json`);
62
+ mkdirSync(dirname(filePath), { recursive: true });
63
+ this.filePath = filePath;
64
+ this.lockPath = filePath + ".lock";
65
+ this.load();
66
+ }
67
+ load() {
68
+ if (!this.filePath)
69
+ return;
70
+ if (!existsSync(this.filePath))
71
+ return;
72
+ try {
73
+ const data = JSON.parse(readFileSync(this.filePath, "utf-8"));
74
+ this.nextId = data.nextId;
75
+ this.goals.clear();
76
+ for (const goal of data.goals) {
77
+ this.goals.set(goal.id, goal);
78
+ }
79
+ }
80
+ catch { /* corrupt file — start fresh */ }
81
+ }
82
+ save() {
83
+ if (!this.filePath)
84
+ return;
85
+ const data = {
86
+ nextId: this.nextId,
87
+ goals: Array.from(this.goals.values()),
88
+ };
89
+ const tmpPath = this.filePath + ".tmp";
90
+ writeFileSync(tmpPath, JSON.stringify(data, null, 2));
91
+ renameSync(tmpPath, this.filePath);
92
+ }
93
+ withLock(fn) {
94
+ if (!this.lockPath)
95
+ return fn();
96
+ acquireLock(this.lockPath);
97
+ try {
98
+ this.load();
99
+ const result = fn();
100
+ this.save();
101
+ return result;
102
+ }
103
+ finally {
104
+ releaseLock(this.lockPath);
105
+ }
106
+ }
107
+ toReducerState() {
108
+ return {
109
+ nextId: this.nextId,
110
+ goalsById: Object.fromEntries(this.goals.entries()),
111
+ };
112
+ }
113
+ applyReducerEvent(event) {
114
+ const result = reduceGoalState(this.toReducerState(), event);
115
+ this.nextId = result.state.nextId;
116
+ this.goals = new Map(Object.entries(result.state.goalsById));
117
+ }
118
+ create(title, description, scope, criteria, metadata) {
119
+ return this.withLock(() => {
120
+ if (this.goals.size >= MAX_GOALS) {
121
+ throw new Error(`Maximum of ${MAX_GOALS} goals reached. Archive some before creating new ones.`);
122
+ }
123
+ this.applyReducerEvent({
124
+ type: "GOAL_CREATED",
125
+ at: Date.now(),
126
+ source: "tool",
127
+ entityType: "goal",
128
+ payload: {
129
+ title,
130
+ description,
131
+ scope,
132
+ criteria,
133
+ metadata,
134
+ },
135
+ });
136
+ return this.goals.get(String(this.nextId - 1));
137
+ });
138
+ }
139
+ get(id) {
140
+ if (this.filePath)
141
+ this.load();
142
+ return this.goals.get(id);
143
+ }
144
+ list() {
145
+ if (this.filePath)
146
+ this.load();
147
+ return Array.from(this.goals.values()).sort((a, b) => Number(a.id) - Number(b.id));
148
+ }
149
+ activate(id) {
150
+ return this.withLock(() => {
151
+ if (!this.goals.has(id))
152
+ return undefined;
153
+ this.applyReducerEvent({
154
+ type: "GOAL_ACTIVATED",
155
+ at: Date.now(),
156
+ source: "tool",
157
+ entityType: "goal",
158
+ entityId: id,
159
+ payload: { id },
160
+ });
161
+ return this.goals.get(id);
162
+ });
163
+ }
164
+ recordProgress(id, progress) {
165
+ return this.withLock(() => {
166
+ if (!this.goals.has(id))
167
+ return undefined;
168
+ this.applyReducerEvent({
169
+ type: "GOAL_PROGRESS_RECORDED",
170
+ at: Date.now(),
171
+ source: "coordinator",
172
+ entityType: "goal",
173
+ entityId: id,
174
+ payload: { id, progress },
175
+ });
176
+ return this.goals.get(id);
177
+ });
178
+ }
179
+ markVerificationStarted(id) {
180
+ return this.withLock(() => {
181
+ if (!this.goals.has(id))
182
+ return undefined;
183
+ this.applyReducerEvent({
184
+ type: "GOAL_VERIFICATION_STARTED",
185
+ at: Date.now(),
186
+ source: "coordinator",
187
+ entityType: "goal",
188
+ entityId: id,
189
+ payload: { id },
190
+ });
191
+ return this.goals.get(id);
192
+ });
193
+ }
194
+ markVerified(id, reason, progress) {
195
+ return this.withLock(() => {
196
+ if (!this.goals.has(id))
197
+ return undefined;
198
+ this.applyReducerEvent({
199
+ type: "GOAL_VERIFICATION_PASSED",
200
+ at: Date.now(),
201
+ source: "coordinator",
202
+ entityType: "goal",
203
+ entityId: id,
204
+ payload: { id, reason, progress },
205
+ });
206
+ return this.goals.get(id);
207
+ });
208
+ }
209
+ markFailed(id, reason, progress) {
210
+ return this.withLock(() => {
211
+ if (!this.goals.has(id))
212
+ return undefined;
213
+ this.applyReducerEvent({
214
+ type: "GOAL_FAILED",
215
+ at: Date.now(),
216
+ source: "coordinator",
217
+ entityType: "goal",
218
+ entityId: id,
219
+ payload: { id, reason, progress },
220
+ });
221
+ return this.goals.get(id);
222
+ });
223
+ }
224
+ markBlocked(id, reason, progress) {
225
+ return this.withLock(() => {
226
+ if (!this.goals.has(id))
227
+ return undefined;
228
+ this.applyReducerEvent({
229
+ type: "GOAL_BLOCKED",
230
+ at: Date.now(),
231
+ source: "coordinator",
232
+ entityType: "goal",
233
+ entityId: id,
234
+ payload: { id, reason, progress },
235
+ });
236
+ return this.goals.get(id);
237
+ });
238
+ }
239
+ unblock(id) {
240
+ return this.withLock(() => {
241
+ if (!this.goals.has(id))
242
+ return undefined;
243
+ this.applyReducerEvent({
244
+ type: "GOAL_UNBLOCKED",
245
+ at: Date.now(),
246
+ source: "coordinator",
247
+ entityType: "goal",
248
+ entityId: id,
249
+ payload: { id },
250
+ });
251
+ return this.goals.get(id);
252
+ });
253
+ }
254
+ updateDetails(id, fields) {
255
+ return this.withLock(() => {
256
+ if (!this.goals.has(id))
257
+ return undefined;
258
+ if (fields.title === undefined
259
+ && fields.description === undefined
260
+ && fields.scope === undefined
261
+ && fields.criteria === undefined
262
+ && fields.metadata === undefined) {
263
+ return this.goals.get(id);
264
+ }
265
+ this.applyReducerEvent({
266
+ type: "GOAL_UPDATED",
267
+ at: Date.now(),
268
+ source: "tool",
269
+ entityType: "goal",
270
+ entityId: id,
271
+ payload: {
272
+ id,
273
+ title: fields.title,
274
+ description: fields.description,
275
+ scope: fields.scope,
276
+ criteria: fields.criteria,
277
+ metadata: fields.metadata,
278
+ },
279
+ });
280
+ return this.goals.get(id);
281
+ });
282
+ }
283
+ archive(id, reason) {
284
+ return this.withLock(() => {
285
+ if (!this.goals.has(id))
286
+ return undefined;
287
+ this.applyReducerEvent({
288
+ type: "GOAL_ARCHIVED",
289
+ at: Date.now(),
290
+ source: "tool",
291
+ entityType: "goal",
292
+ entityId: id,
293
+ payload: { id, reason },
294
+ });
295
+ return this.goals.get(id);
296
+ });
297
+ }
298
+ }
@@ -0,0 +1,82 @@
1
+ export type GoalStatus = "pending" | "active" | "satisfied" | "blocked" | "failed" | "archived";
2
+ export type GoalVerificationStatus = "unknown" | "checking" | "verified" | "unverified" | "inconclusive";
3
+ export interface GoalScope {
4
+ taskIds?: string[];
5
+ loopIds?: string[];
6
+ monitorIds?: string[];
7
+ tags?: string[];
8
+ subjectPrefixes?: string[];
9
+ includeFutureMatchingTasks?: boolean;
10
+ includeFutureMatchingLoops?: boolean;
11
+ includeFutureMatchingMonitors?: boolean;
12
+ }
13
+ export interface GoalSuccessCriteria {
14
+ minCompletedTasks?: number;
15
+ requiredTaskIds?: string[];
16
+ requiredMonitorIdsCompleted?: string[];
17
+ requiredLoopIdsPresent?: string[];
18
+ requireNoPendingTasksInScope?: boolean;
19
+ requireLatestVerificationPass?: boolean;
20
+ }
21
+ export interface GoalFailureCriteria {
22
+ anyMonitorIdsErrored?: string[];
23
+ maxVerificationFailures?: number;
24
+ failIfTaskIdsDeleted?: string[];
25
+ }
26
+ export interface GoalBlockedCriteria {
27
+ blockedIfAllTasksCompletedButVerificationFails?: boolean;
28
+ blockedIfNoScopedProgressSinceMs?: number;
29
+ blockedIfRequiredLoopMissing?: boolean;
30
+ }
31
+ export interface GoalCriteria {
32
+ success: GoalSuccessCriteria;
33
+ failure?: GoalFailureCriteria;
34
+ blocked?: GoalBlockedCriteria;
35
+ }
36
+ export interface GoalProgressSnapshot {
37
+ totalTasks: number;
38
+ pendingTasks: number;
39
+ inProgressTasks: number;
40
+ completedTasks: number;
41
+ activeLoops: number;
42
+ pausedLoops: number;
43
+ runningMonitors: number;
44
+ completedMonitors: number;
45
+ erroredMonitors: number;
46
+ stoppedMonitors: number;
47
+ lastProgressAt?: number;
48
+ }
49
+ export interface GoalVerificationState {
50
+ attempts: number;
51
+ passes: number;
52
+ failures: number;
53
+ lastCheckedAt?: number;
54
+ lastPassedAt?: number;
55
+ lastFailedAt?: number;
56
+ lastReason?: string;
57
+ nextCheckAfter?: number;
58
+ }
59
+ export interface GoalEntry {
60
+ id: string;
61
+ title: string;
62
+ description: string;
63
+ status: GoalStatus;
64
+ verificationStatus: GoalVerificationStatus;
65
+ createdAt: number;
66
+ updatedAt: number;
67
+ activatedAt?: number;
68
+ resolvedAt?: number;
69
+ scope: GoalScope;
70
+ criteria: GoalCriteria;
71
+ progress: GoalProgressSnapshot;
72
+ verification: GoalVerificationState;
73
+ metadata?: Record<string, unknown>;
74
+ }
75
+ export interface GoalReducerState {
76
+ nextId: number;
77
+ goalsById: Record<string, GoalEntry>;
78
+ }
79
+ export interface GoalStoreData {
80
+ nextId: number;
81
+ goals: GoalEntry[];
82
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,20 @@
1
+ import type { ReducerEffect } from "./coordinator.js";
2
+ import type { GoalEntry, GoalProgressSnapshot } from "./goal-types.js";
3
+ import type { LoopReducerState } from "./loop-reducer.js";
4
+ import type { MonitorReducerState } from "./monitor-reducer.js";
5
+ import type { TaskReducerState } from "./task-reducer.js";
6
+ export interface GoalVerifierInput {
7
+ goal: GoalEntry;
8
+ taskState: TaskReducerState;
9
+ loopState: LoopReducerState;
10
+ monitorState: MonitorReducerState;
11
+ at: number;
12
+ }
13
+ export interface GoalVerifierResult {
14
+ progress: GoalProgressSnapshot;
15
+ verdict: "passed" | "failed" | "blocked";
16
+ reason: string;
17
+ effects: ReducerEffect[];
18
+ }
19
+ export declare function projectGoalProgress(goal: GoalEntry, taskState: TaskReducerState, loopState: LoopReducerState, monitorState: MonitorReducerState): GoalProgressSnapshot;
20
+ export declare function verifyGoal(input: GoalVerifierInput): GoalVerifierResult;