@openacme/tasks 0.4.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.
@@ -0,0 +1,156 @@
1
+ /**
2
+ * File-backed task store. One markdown file per task at
3
+ * `<tasksDir>/<id>.md` — YAML frontmatter for structured fields, body
4
+ * for the agent-readable description and accumulated notes.
5
+ *
6
+ * Concurrency: per-task in-process async mutex serializes
7
+ * read-modify-write of a single id. Each operation only acquires one
8
+ * mutex at a time — fan-out paths (`unblockDependents`, `delete --force`)
9
+ * iterate sequentially without holding multiple locks, so there's no
10
+ * deadlock surface.
11
+ *
12
+ * The store enforces:
13
+ * - cycle-free `depends_on` graph (DFS on write).
14
+ * - status auto-transition between `open` and `blocked` based on deps.
15
+ * - at most one `in_progress` per `session_id`.
16
+ * - inputs validated against the frontmatter schema at the write
17
+ * boundary so a bad input can't land malformed YAML on disk.
18
+ *
19
+ * Status state machine (legal transitions only — anything else is a bug):
20
+ *
21
+ * open ─────► in_progress (assignee claims via update; requires deps satisfied)
22
+ * open ─────► blocked (auto, when deps regress)
23
+ * open ─────► done/canceled (terminal)
24
+ *
25
+ * in_progress ──► blocked (via TaskStore.park, by scheduler on
26
+ * timeout/error or watchdog)
27
+ * in_progress ──► done/canceled (terminal; assignee or human)
28
+ *
29
+ * blocked ──► open (auto, when deps satisfy via unblockDependents)
30
+ * blocked ──► done/canceled (terminal; bypasses in_progress)
31
+ *
32
+ * done ────► open (ONLY for recurring tasks — self-reset
33
+ * to next fire. Non-recurring done is
34
+ * terminal.)
35
+ * canceled ──► (nothing) (kill switch; never resets, even for recurring)
36
+ *
37
+ * Adding a new status: extend `TASK_STATUSES`, then audit `computeAutoStatus`,
38
+ * the closing branches in `update()`, the recurring self-reset, scheduler's
39
+ * `park` / `watchdogPark`, `hasAnyActive`, and prompt rendering.
40
+ */
41
+ import { type Task, type TaskCreate, type TaskListFilter, type TaskUpdate } from "./types.js";
42
+ import type { Comment, CommentInput, CommentListOptions, CommentStorePort, EventStorePort, TaskEvent } from "./ports.js";
43
+ export declare class TaskStoreError extends Error {
44
+ readonly code: string;
45
+ constructor(code: string, message: string);
46
+ }
47
+ export type OnChangeFn = () => void;
48
+ export interface TaskStoreOptions {
49
+ /** Optional: discussion thread store. If absent, comment methods no-op. */
50
+ commentStore?: CommentStorePort;
51
+ /** Optional: event log store. If absent, no events emitted. */
52
+ eventStore?: EventStorePort;
53
+ /** Optional: session existence check. When provided, create/update
54
+ * reject task bindings to a session id the check returns false for —
55
+ * prevents agents from hallucinating session uuids that would become
56
+ * scheduler zombies. */
57
+ validateSession?: (id: string) => boolean;
58
+ }
59
+ export declare class TaskStore {
60
+ readonly tasksDir: string;
61
+ private readonly inFlight;
62
+ private onChange;
63
+ private readonly commentStore;
64
+ private readonly eventStore;
65
+ private readonly validateSession;
66
+ constructor(tasksDir: string, options?: TaskStoreOptions);
67
+ setOnChange(fn: OnChangeFn | null): void;
68
+ filePath(id: string): string;
69
+ get(id: string): Task | null;
70
+ list(filter?: TaskListFilter): Task[];
71
+ byAssignee(agentId: string): Task[];
72
+ byCreator(agentId: string): Task[];
73
+ byParent(parentId: string): Task[];
74
+ dependentsOf(id: string): Task[];
75
+ /** Tasks bound to `sessionId` in queue order (deps + start_at + created_at). */
76
+ queueFor(sessionId: string, now?: Date): Task[];
77
+ /** Top of `queueFor` excluding already in_progress / done / canceled. */
78
+ nextEligibleFor(sessionId: string, now?: Date): Task | null;
79
+ create(input: TaskCreate): Promise<Task>;
80
+ update(id: string, patch: TaskUpdate, opts?: {
81
+ actor?: string | null;
82
+ }): Promise<Task>;
83
+ delete(id: string, opts?: {
84
+ force?: boolean;
85
+ actor?: string | null;
86
+ }): Promise<void>;
87
+ /**
88
+ * Restart sweep: any task `in_progress` whose `updated_at` is older
89
+ * than the staleness threshold is reset to `open`. Returns the ids
90
+ * that were reset.
91
+ */
92
+ /**
93
+ * Park a task: flip to `blocked` with a future `start_at` and append
94
+ * a `system:scheduler` comment explaining why. The scheduler uses this
95
+ * for both failure attribution (`parkInProgress`) and watchdog stalls
96
+ * (`watchdogPark`). Single helper means the "blocked + back-off +
97
+ * system note" pattern lives in one place.
98
+ */
99
+ park(input: {
100
+ id: string;
101
+ retryAt: Date;
102
+ reason: string;
103
+ }): Promise<void>;
104
+ sweepStale(now?: Date): Promise<string[]>;
105
+ /**
106
+ * System-prompt block for an agent. `sessionExistsFn` lets the caller
107
+ * treat tasks bound to a deleted session as if they were unbound.
108
+ */
109
+ renderForPrompt(agentId: string, currentSessionId: string, sessionExistsFn: (sid: string) => boolean, now?: Date): string;
110
+ private latestNonSystemComment;
111
+ private assertDepsExist;
112
+ private assertNoCycle;
113
+ private writeFile;
114
+ private withMutex;
115
+ private fireOnChange;
116
+ private emitEvent;
117
+ /**
118
+ * Append a comment to the task's discussion thread. Authorship gates
119
+ * (assignee-only for `kind: "result"`, system-only for `kind: "system"`)
120
+ * live in the tool layer; the store accepts whatever it's given so
121
+ * automation paths can write system entries directly.
122
+ */
123
+ addComment(input: CommentInput): Promise<Comment | null>;
124
+ listComments(taskId: string, opts?: CommentListOptions): Comment[];
125
+ latestResult(taskId: string): Comment | null;
126
+ commentCounts(taskIds: string[]): Map<string, number>;
127
+ /**
128
+ * Tasks this session is "involved with" — bound to the session, plus
129
+ * the agent's assigned/created tasks that have no session yet (those
130
+ * land here when they get a fresh session). Plus tasks the agent
131
+ * created and assigned to OTHERS — without this, the agent loses
132
+ * the event feed for delegated work the moment its assignee picks
133
+ * it up and the task gets bound to a different session.
134
+ */
135
+ involvedTaskIds(sessionId: string, agentId: string): string[];
136
+ /**
137
+ * Fetch recent events for the given session's involvement set, since
138
+ * `sinceTs` (unix seconds). Empty array if no event store wired.
139
+ * `excludeActor` filters out events caused by that actor — used by
140
+ * the mid-turn injection path so the cursor and the rendered set
141
+ * always match (otherwise self-events get re-shown on every step).
142
+ */
143
+ recentEventsForSession(sessionId: string, agentId: string, sinceTs: number, opts?: {
144
+ limit?: number;
145
+ excludeActor?: string;
146
+ }): TaskEvent[];
147
+ /**
148
+ * Format the events feed as a markdown section for the system prompt.
149
+ * Returns "" when there are no events to render.
150
+ */
151
+ renderRecentActivity(sessionId: string, agentId: string, sinceTs: number, now?: Date, opts?: {
152
+ limit?: number;
153
+ excludeActor?: string;
154
+ }): string;
155
+ }
156
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}