@pi-orca/tasks 0.0.2-dev.20260413162335

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 ADDED
@@ -0,0 +1,43 @@
1
+ # pi-orca-tasks
2
+
3
+ **Task Management**
4
+
5
+ Version: 0.0.1 (Phase 0 - Stub)
6
+ License: MIT
7
+
8
+ ## Overview
9
+
10
+ File-backed task DAG with locking, dependency validation, and state machine.
11
+
12
+ **Status:** Phase 0 scaffold complete. Full implementation pending.
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install pi-orca-tasks
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ This package is currently in stub mode. Tools and commands are registered but return "Not implemented yet" messages.
23
+
24
+ ## Development Status
25
+
26
+ - [x] Package scaffold
27
+ - [x] TypeScript configuration
28
+ - [x] Tool registration (stub)
29
+ - [x] Command registration (stub)
30
+ - [x] Event emission (ready signal)
31
+ - [ ] Full implementation (pending)
32
+
33
+ ## Dependencies
34
+
35
+ - `pi-orca-core` — Shared types and utilities
36
+
37
+ ## Documentation
38
+
39
+ See the [Pi Orca specification](../../docs/spec-v0.3.0.md) for the complete design.
40
+
41
+ ## License
42
+
43
+ MIT License — see [LICENSE](../../LICENSE) for details.
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Slash command implementations for pi-orca-tasks.
3
+ * Spec: §3.10 — Slash Commands
4
+ */
5
+ /**
6
+ * /task (no args) — return widget string for display
7
+ */
8
+ export declare function cmdTaskToggle(projectSlug?: string): Promise<string>;
9
+ /**
10
+ * /task list [status] — list tasks
11
+ */
12
+ export declare function cmdTaskList(statusFilter?: string, projectSlug?: string): Promise<string>;
13
+ /**
14
+ * /task stuck — scan for stuck tasks
15
+ */
16
+ export declare function cmdTaskStuck(projectSlug?: string): Promise<string>;
17
+ /**
18
+ * /task unlock <id> — force-release a stuck lock
19
+ */
20
+ export declare function cmdTaskUnlock(taskId: string, projectSlug?: string): Promise<string>;
21
+ /**
22
+ * /task deps <id> — show dependency graph for a task
23
+ */
24
+ export declare function cmdTaskDeps(taskId: string, projectSlug?: string): Promise<string>;
25
+ /**
26
+ * /task validate [id] — validate task files
27
+ */
28
+ export declare function cmdTaskValidate(taskId?: string, projectSlug?: string): Promise<string>;
29
+ //# sourceMappingURL=commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AAAA;;;GAGG;AASH;;GAEG;AACH,wBAAsB,aAAa,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAEzE;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA4B9F;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAwDxE;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAOzF;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAgDvF;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,MAAM,CAAC,EAAE,MAAM,EACf,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,CAAC,CAmDjB"}
@@ -0,0 +1,213 @@
1
+ /**
2
+ * Slash command implementations for pi-orca-tasks.
3
+ * Spec: §3.10 — Slash Commands
4
+ */
5
+ import { listTasks, readTask, getTaskLockPath } from "./engine/crud.js";
6
+ import { renderTaskWidget } from "./widget.js";
7
+ import { readLock, isPidAlive, getOrcaTasksDir } from "@pi-orca/core";
8
+ import { readdir } from "fs/promises";
9
+ import { existsSync } from "fs";
10
+ import { join } from "path";
11
+ /**
12
+ * /task (no args) — return widget string for display
13
+ */
14
+ export async function cmdTaskToggle(projectSlug) {
15
+ return renderTaskWidget(projectSlug);
16
+ }
17
+ /**
18
+ * /task list [status] — list tasks
19
+ */
20
+ export async function cmdTaskList(statusFilter, projectSlug) {
21
+ const tasks = await listTasks({
22
+ status: statusFilter,
23
+ projectSlug,
24
+ });
25
+ if (tasks.length === 0) {
26
+ return statusFilter
27
+ ? `No tasks with status '${statusFilter}'.`
28
+ : "No tasks found. Use /task create <title> to create one.";
29
+ }
30
+ const STATUS_ICONS = {
31
+ completed: "✓",
32
+ in_progress: "◉",
33
+ pending: "○",
34
+ failed: "✗",
35
+ blocked: "⊘",
36
+ abandoned: "—",
37
+ };
38
+ const lines = tasks.map((t) => {
39
+ const icon = STATUS_ICONS[t.task.status] ?? "?";
40
+ const assignee = t.task.status === "in_progress" ? ` [${t.task.assignedTo?.slice(0, 8)}]` : "";
41
+ return ` ${icon} ${t.task.id} ${t.task.title}${assignee}`;
42
+ });
43
+ return `Tasks (${tasks.length}):\n${lines.join("\n")}`;
44
+ }
45
+ /**
46
+ * /task stuck — scan for stuck tasks
47
+ */
48
+ export async function cmdTaskStuck(projectSlug) {
49
+ const tasksDir = getOrcaTasksDir(projectSlug);
50
+ if (!existsSync(tasksDir)) {
51
+ return "No tasks directory found.";
52
+ }
53
+ let entries;
54
+ try {
55
+ entries = await readdir(tasksDir);
56
+ }
57
+ catch {
58
+ return "Could not read tasks directory.";
59
+ }
60
+ const lockFiles = entries.filter((e) => e.endsWith(".lock"));
61
+ if (lockFiles.length === 0) {
62
+ return "No locked tasks found.";
63
+ }
64
+ const stuck = [];
65
+ const alive = [];
66
+ for (const lockFile of lockFiles) {
67
+ const taskId = lockFile.replace(".lock", "");
68
+ const lockPath = join(tasksDir, lockFile);
69
+ const lockInfo = await readLock(lockPath);
70
+ if (!lockInfo) {
71
+ stuck.push(`${taskId} (unreadable lock file)`);
72
+ continue;
73
+ }
74
+ if (!isPidAlive(lockInfo.pid)) {
75
+ stuck.push(`${taskId} (PID ${lockInfo.pid} dead, locked by session ${lockInfo.sessionId})`);
76
+ }
77
+ else {
78
+ alive.push(`${taskId} (PID ${lockInfo.pid} alive, held by session ${lockInfo.sessionId})`);
79
+ }
80
+ }
81
+ const lines = [];
82
+ if (stuck.length > 0) {
83
+ lines.push(`⚠ Stuck tasks (${stuck.length}):`);
84
+ stuck.forEach((s) => lines.push(` ${s}`));
85
+ lines.push("");
86
+ lines.push("Run /task unlock <id> to release a stuck lock.");
87
+ }
88
+ if (alive.length > 0) {
89
+ lines.push(`Active locks (${alive.length}):`);
90
+ alive.forEach((a) => lines.push(` ${a}`));
91
+ }
92
+ if (lines.length === 0) {
93
+ return "No stuck tasks found.";
94
+ }
95
+ return lines.join("\n");
96
+ }
97
+ /**
98
+ * /task unlock <id> — force-release a stuck lock
99
+ */
100
+ export async function cmdTaskUnlock(taskId, projectSlug) {
101
+ const { unlockTask } = await import("./engine/state-machine.js");
102
+ const result = await unlockTask(taskId, projectSlug);
103
+ if (result.success) {
104
+ return result.message ?? `Unlocked task ${taskId}`;
105
+ }
106
+ return `Error: ${result.error}`;
107
+ }
108
+ /**
109
+ * /task deps <id> — show dependency graph for a task
110
+ */
111
+ export async function cmdTaskDeps(taskId, projectSlug) {
112
+ const taskFile = await readTask(taskId, projectSlug);
113
+ if (!taskFile) {
114
+ return `Task ${taskId} not found.`;
115
+ }
116
+ const STATUS_ICONS = {
117
+ completed: "✓",
118
+ in_progress: "◉",
119
+ pending: "○",
120
+ failed: "✗",
121
+ blocked: "⊘",
122
+ abandoned: "—",
123
+ };
124
+ const lines = [`${taskId}: ${taskFile.task.title} [${taskFile.task.status}]`];
125
+ if ((taskFile.task.dependencies ?? []).length > 0) {
126
+ lines.push(" Dependencies (must complete before this task):");
127
+ for (const depId of taskFile.task.dependencies) {
128
+ const dep = await readTask(depId, projectSlug);
129
+ if (dep) {
130
+ const icon = STATUS_ICONS[dep.task.status] ?? "?";
131
+ lines.push(` ${icon} ${depId}: ${dep.task.title}`);
132
+ }
133
+ else {
134
+ lines.push(` ? ${depId}: (not found)`);
135
+ }
136
+ }
137
+ }
138
+ else {
139
+ lines.push(" Dependencies: none");
140
+ }
141
+ if ((taskFile.task.dependents ?? []).length > 0) {
142
+ lines.push(" Dependents (tasks that depend on this one):");
143
+ for (const depId of taskFile.task.dependents) {
144
+ const dep = await readTask(depId, projectSlug);
145
+ if (dep) {
146
+ const icon = STATUS_ICONS[dep.task.status] ?? "?";
147
+ lines.push(` ${icon} ${depId}: ${dep.task.title}`);
148
+ }
149
+ else {
150
+ lines.push(` ? ${depId}: (not found)`);
151
+ }
152
+ }
153
+ }
154
+ else {
155
+ lines.push(" Dependents: none");
156
+ }
157
+ return lines.join("\n");
158
+ }
159
+ /**
160
+ * /task validate [id] — validate task files
161
+ */
162
+ export async function cmdTaskValidate(taskId, projectSlug) {
163
+ const tasks = taskId
164
+ ? [await readTask(taskId, projectSlug)].filter(Boolean)
165
+ : await listTasks({ projectSlug });
166
+ const errors = [];
167
+ const warnings = [];
168
+ for (const t of tasks) {
169
+ if (!t)
170
+ continue;
171
+ const { task } = t;
172
+ if (!task.id)
173
+ errors.push(`${task.id ?? "?"}: missing id`);
174
+ if (!task.title)
175
+ errors.push(`${task.id}: missing title`);
176
+ if (!task.status)
177
+ errors.push(`${task.id}: missing status`);
178
+ if (!task.createdAt)
179
+ warnings.push(`${task.id}: missing createdAt`);
180
+ // Check deps exist
181
+ for (const dep of task.dependencies ?? []) {
182
+ const depFile = await readTask(dep, projectSlug);
183
+ if (!depFile) {
184
+ errors.push(`${task.id}: dependency ${dep} does not exist`);
185
+ }
186
+ }
187
+ // Check lock file consistency
188
+ const lockPath = getTaskLockPath(task.id, projectSlug);
189
+ const lockInfo = await readLock(lockPath);
190
+ if (lockInfo && task.status !== "in_progress") {
191
+ warnings.push(`${task.id}: has lock file but status is '${task.status}'`);
192
+ }
193
+ if (!lockInfo && task.status === "in_progress") {
194
+ warnings.push(`${task.id}: status is 'in_progress' but has no lock file`);
195
+ }
196
+ }
197
+ const lines = [];
198
+ if (errors.length === 0 && warnings.length === 0) {
199
+ lines.push(`✓ Validated ${tasks.length} task(s) — no issues found`);
200
+ }
201
+ else {
202
+ if (errors.length > 0) {
203
+ lines.push(`✗ Errors (${errors.length}):`);
204
+ errors.forEach((e) => lines.push(` ${e}`));
205
+ }
206
+ if (warnings.length > 0) {
207
+ lines.push(`⚠ Warnings (${warnings.length}):`);
208
+ warnings.forEach((w) => lines.push(` ${w}`));
209
+ }
210
+ }
211
+ return lines.join("\n");
212
+ }
213
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,WAAoB;IACtD,OAAO,gBAAgB,CAAC,WAAW,CAAC,CAAC;AACvC,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,YAAqB,EAAE,WAAoB;IAC3E,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC;QAC5B,MAAM,EAAE,YAAmB;QAC3B,WAAW;KACZ,CAAC,CAAC;IAEH,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,YAAY;YACjB,CAAC,CAAC,yBAAyB,YAAY,IAAI;YAC3C,CAAC,CAAC,yDAAyD,CAAC;IAChE,CAAC;IAED,MAAM,YAAY,GAA2B;QAC3C,SAAS,EAAE,GAAG;QACd,WAAW,EAAE,GAAG;QAChB,OAAO,EAAE,GAAG;QACZ,MAAM,EAAE,GAAG;QACX,OAAO,EAAE,GAAG;QACZ,SAAS,EAAE,GAAG;KACf,CAAC;IAEF,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAC5B,MAAM,IAAI,GAAG,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC;QAChD,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,KAAK,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/F,OAAO,KAAK,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,QAAQ,EAAE,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,OAAO,UAAU,KAAK,CAAC,MAAM,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AACzD,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,WAAoB;IACrD,MAAM,QAAQ,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IAE9C,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,OAAO,2BAA2B,CAAC;IACrC,CAAC;IAED,IAAI,OAAiB,CAAC;IACtB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,iCAAiC,CAAC;IAC3C,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IAC7D,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,wBAAwB,CAAC;IAClC,CAAC;IAED,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC1C,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAE1C,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,yBAAyB,CAAC,CAAC;YAC/C,SAAS;QACX,CAAC;QAED,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,SAAS,QAAQ,CAAC,GAAG,4BAA4B,QAAQ,CAAC,SAAS,GAAG,CAAC,CAAC;QAC9F,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,SAAS,QAAQ,CAAC,GAAG,2BAA2B,QAAQ,CAAC,SAAS,GAAG,CAAC,CAAC;QAC7F,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,KAAK,CAAC,IAAI,CAAC,kBAAkB,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC;QAC/C,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3C,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC;IAC/D,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,KAAK,CAAC,IAAI,CAAC,iBAAiB,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC;QAC9C,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,uBAAuB,CAAC;IACjC,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAc,EAAE,WAAoB;IACtE,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,2BAA2B,CAAC,CAAC;IACjE,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACrD,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,OAAO,MAAM,CAAC,OAAO,IAAI,iBAAiB,MAAM,EAAE,CAAC;IACrD,CAAC;IACD,OAAO,UAAU,MAAM,CAAC,KAAK,EAAE,CAAC;AAClC,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAAc,EAAE,WAAoB;IACpE,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACrD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,QAAQ,MAAM,aAAa,CAAC;IACrC,CAAC;IAED,MAAM,YAAY,GAA2B;QAC3C,SAAS,EAAE,GAAG;QACd,WAAW,EAAE,GAAG;QAChB,OAAO,EAAE,GAAG;QACZ,MAAM,EAAE,GAAG;QACX,OAAO,EAAE,GAAG;QACZ,SAAS,EAAE,GAAG;KACf,CAAC;IAEF,MAAM,KAAK,GAAa,CAAC,GAAG,MAAM,KAAK,QAAQ,CAAC,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IAExF,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClD,KAAK,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC;QAC/D,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YAC/C,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;YAC/C,IAAI,GAAG,EAAE,CAAC;gBACR,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC;gBAClD,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,KAAK,KAAK,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;YACxD,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,IAAI,CAAC,SAAS,KAAK,eAAe,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;IACH,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACrC,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChD,KAAK,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC;QAC5D,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YAC7C,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;YAC/C,IAAI,GAAG,EAAE,CAAC;gBACR,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC;gBAClD,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,KAAK,KAAK,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;YACxD,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,IAAI,CAAC,SAAS,KAAK,eAAe,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;IACH,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IACnC,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAAe,EACf,WAAoB;IAEpB,MAAM,KAAK,GAAG,MAAM;QAClB,CAAC,CAAC,CAAC,MAAM,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;QACvD,CAAC,CAAC,MAAM,SAAS,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC;IAErC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,CAAC;YAAE,SAAS;QACjB,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;QAEnB,IAAI,CAAC,IAAI,CAAC,EAAE;YAAE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE,IAAI,GAAG,cAAc,CAAC,CAAC;QAC3D,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE,iBAAiB,CAAC,CAAC;QAC1D,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE,kBAAkB,CAAC,CAAC;QAC5D,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE,qBAAqB,CAAC,CAAC;QAEpE,mBAAmB;QACnB,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,YAAY,IAAI,EAAE,EAAE,CAAC;YAC1C,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;YACjD,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE,gBAAgB,GAAG,iBAAiB,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC;QAED,8BAA8B;QAC9B,MAAM,QAAQ,GAAG,eAAe,CAAC,IAAI,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC;QACvD,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC1C,IAAI,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,aAAa,EAAE,CAAC;YAC9C,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE,kCAAkC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QAC5E,CAAC;QACD,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,aAAa,EAAE,CAAC;YAC/C,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE,gDAAgD,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjD,KAAK,CAAC,IAAI,CAAC,eAAe,KAAK,CAAC,MAAM,4BAA4B,CAAC,CAAC;IACtE,CAAC;SAAM,CAAC;QACN,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,KAAK,CAAC,IAAI,CAAC,aAAa,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;YAC3C,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;QAC9C,CAAC;QACD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,KAAK,CAAC,IAAI,CAAC,eAAe,QAAQ,CAAC,MAAM,IAAI,CAAC,CAAC;YAC/C,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Task file CRUD operations.
3
+ * Spec: §3.3 — Task File Schema, §3.4 — Lock File Schema
4
+ */
5
+ import { Task, TaskStatus, Labels } from "@pi-orca/core";
6
+ export interface CreateTaskParams {
7
+ title: string;
8
+ description?: string;
9
+ dependencies?: string[];
10
+ labels?: Labels;
11
+ projectSlug?: string;
12
+ }
13
+ export interface UpdateTaskParams {
14
+ title?: string;
15
+ dependencies?: string[];
16
+ labels?: Labels;
17
+ projectSlug?: string;
18
+ }
19
+ export interface ListTasksFilter {
20
+ status?: TaskStatus | TaskStatus[];
21
+ labels?: Labels;
22
+ includeArchived?: boolean;
23
+ projectSlug?: string;
24
+ }
25
+ /**
26
+ * Task file with its path on disk.
27
+ */
28
+ export interface TaskFile {
29
+ task: Task;
30
+ filePath: string;
31
+ body: string;
32
+ }
33
+ /**
34
+ * Generate the next sequential task ID.
35
+ */
36
+ export declare function generateTaskId(tasksDir: string): Promise<string>;
37
+ /**
38
+ * Get full path to a task file.
39
+ */
40
+ export declare function getTaskFilePath(taskId: string, projectSlug?: string): string;
41
+ /**
42
+ * Get full path to a task lock file.
43
+ */
44
+ export declare function getTaskLockPath(taskId: string, projectSlug?: string): string;
45
+ /**
46
+ * Create a new task file.
47
+ * Spec: §2.1.1
48
+ */
49
+ export declare function createTask(params: CreateTaskParams): Promise<TaskFile>;
50
+ /**
51
+ * Read a task file from disk.
52
+ * Spec: §2.1.2
53
+ */
54
+ export declare function readTask(taskId: string, projectSlug?: string): Promise<TaskFile | null>;
55
+ /**
56
+ * Write a task file to disk (replaces content).
57
+ */
58
+ export declare function writeTask(taskFile: TaskFile): Promise<void>;
59
+ /**
60
+ * Update task frontmatter fields.
61
+ * Spec: §2.1.3
62
+ */
63
+ export declare function updateTask(taskId: string, patch: Partial<Task>, projectSlug?: string): Promise<TaskFile | null>;
64
+ /**
65
+ * List tasks with optional filters.
66
+ * Spec: §2.1.4
67
+ */
68
+ export declare function listTasks(filter?: ListTasksFilter): Promise<TaskFile[]>;
69
+ /**
70
+ * Build dependency map from all task files.
71
+ * Returns { dependencies: task→deps[], dependents: task→dependents[] }
72
+ */
73
+ export declare function buildDependencyMaps(projectSlug?: string): Promise<{
74
+ dependencies: Map<string, string[]>;
75
+ dependents: Map<string, string[]>;
76
+ }>;
77
+ /**
78
+ * Update reverse dependency (dependents) links when a task's dependencies change.
79
+ */
80
+ export declare function syncDependentLinks(taskId: string, oldDeps: string[], newDeps: string[], projectSlug?: string): Promise<void>;
81
+ //# sourceMappingURL=crud.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crud.d.ts","sourceRoot":"","sources":["../../src/engine/crud.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EACL,IAAI,EACJ,UAAU,EAQV,MAAM,EACP,MAAM,eAAe,CAAC;AAEvB,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,UAAU,GAAG,UAAU,EAAE,CAAC;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,IAAI,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAsBtE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAE5E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAE5E;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAiC5E;AAED;;;GAGG;AACH,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,MAAM,EACd,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAO1B;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAGjE;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,EACpB,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAY1B;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,MAAM,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAoD7E;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC;IACT,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACpC,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACnC,CAAC,CAmBD;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,EAAE,MAAM,EAAE,EACjB,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAyBf"}
@@ -0,0 +1,214 @@
1
+ /**
2
+ * Task file CRUD operations.
3
+ * Spec: §3.3 — Task File Schema, §3.4 — Lock File Schema
4
+ */
5
+ import { readdir } from "fs/promises";
6
+ import { existsSync } from "fs";
7
+ import { join } from "path";
8
+ import { parseFrontmatter, serializeFrontmatter, atomicWrite, ensureDir, readFileIfExists, matchLabels, getOrcaTasksDir, } from "@pi-orca/core";
9
+ /**
10
+ * Generate the next sequential task ID.
11
+ */
12
+ export async function generateTaskId(tasksDir) {
13
+ await ensureDir(tasksDir);
14
+ if (!existsSync(tasksDir)) {
15
+ return "task-001";
16
+ }
17
+ let entries;
18
+ try {
19
+ entries = await readdir(tasksDir);
20
+ }
21
+ catch {
22
+ return "task-001";
23
+ }
24
+ // Find highest existing task number
25
+ const taskNums = entries
26
+ .filter((e) => /^task-\d+\.md$/.test(e))
27
+ .map((e) => parseInt(e.replace("task-", "").replace(".md", ""), 10))
28
+ .filter((n) => !isNaN(n));
29
+ const max = taskNums.length > 0 ? Math.max(...taskNums) : 0;
30
+ return `task-${String(max + 1).padStart(3, "0")}`;
31
+ }
32
+ /**
33
+ * Get full path to a task file.
34
+ */
35
+ export function getTaskFilePath(taskId, projectSlug) {
36
+ return join(getOrcaTasksDir(projectSlug), `${taskId}.md`);
37
+ }
38
+ /**
39
+ * Get full path to a task lock file.
40
+ */
41
+ export function getTaskLockPath(taskId, projectSlug) {
42
+ return join(getOrcaTasksDir(projectSlug), `${taskId}.lock`);
43
+ }
44
+ /**
45
+ * Create a new task file.
46
+ * Spec: §2.1.1
47
+ */
48
+ export async function createTask(params) {
49
+ const tasksDir = getOrcaTasksDir(params.projectSlug);
50
+ await ensureDir(tasksDir);
51
+ const taskId = await generateTaskId(tasksDir);
52
+ const now = new Date().toISOString();
53
+ const task = {
54
+ id: taskId,
55
+ title: params.title,
56
+ status: "pending",
57
+ createdAt: now,
58
+ updatedAt: now,
59
+ completedAt: "",
60
+ assignedTo: "",
61
+ assignedSessionPath: "",
62
+ dependencies: params.dependencies ?? [],
63
+ dependents: [],
64
+ blockedReason: "",
65
+ retryCount: 0,
66
+ labels: params.labels ?? {},
67
+ archivable: false,
68
+ };
69
+ const body = params.description
70
+ ? `## Description\n\n${params.description}\n`
71
+ : `## Description\n\n_No description provided._\n`;
72
+ const content = serializeFrontmatter(task, body);
73
+ const filePath = getTaskFilePath(taskId, params.projectSlug);
74
+ await atomicWrite(filePath, content);
75
+ return { task, filePath, body };
76
+ }
77
+ /**
78
+ * Read a task file from disk.
79
+ * Spec: §2.1.2
80
+ */
81
+ export async function readTask(taskId, projectSlug) {
82
+ const filePath = getTaskFilePath(taskId, projectSlug);
83
+ const content = await readFileIfExists(filePath);
84
+ if (!content)
85
+ return null;
86
+ const { frontmatter, body } = parseFrontmatter(content);
87
+ return { task: frontmatter, filePath, body };
88
+ }
89
+ /**
90
+ * Write a task file to disk (replaces content).
91
+ */
92
+ export async function writeTask(taskFile) {
93
+ const content = serializeFrontmatter(taskFile.task, taskFile.body);
94
+ await atomicWrite(taskFile.filePath, content);
95
+ }
96
+ /**
97
+ * Update task frontmatter fields.
98
+ * Spec: §2.1.3
99
+ */
100
+ export async function updateTask(taskId, patch, projectSlug) {
101
+ const taskFile = await readTask(taskId, projectSlug);
102
+ if (!taskFile)
103
+ return null;
104
+ taskFile.task = {
105
+ ...taskFile.task,
106
+ ...patch,
107
+ updatedAt: new Date().toISOString(),
108
+ };
109
+ await writeTask(taskFile);
110
+ return taskFile;
111
+ }
112
+ /**
113
+ * List tasks with optional filters.
114
+ * Spec: §2.1.4
115
+ */
116
+ export async function listTasks(filter) {
117
+ const tasksDir = getOrcaTasksDir(filter?.projectSlug);
118
+ await ensureDir(tasksDir);
119
+ let entries;
120
+ try {
121
+ entries = await readdir(tasksDir);
122
+ }
123
+ catch {
124
+ return [];
125
+ }
126
+ const results = [];
127
+ for (const entry of entries) {
128
+ // Skip archived, lock files, non-md files
129
+ if (!entry.endsWith(".md"))
130
+ continue;
131
+ if (entry.startsWith("archived"))
132
+ continue;
133
+ const filePath = join(tasksDir, entry);
134
+ const content = await readFileIfExists(filePath);
135
+ if (!content)
136
+ continue;
137
+ try {
138
+ const { frontmatter, body } = parseFrontmatter(content);
139
+ // Filter by status
140
+ if (filter?.status) {
141
+ const statuses = Array.isArray(filter.status) ? filter.status : [filter.status];
142
+ if (!statuses.includes(frontmatter.status))
143
+ continue;
144
+ }
145
+ // Filter by labels
146
+ if (filter?.labels && Object.keys(filter.labels).length > 0) {
147
+ if (!matchLabels(frontmatter.labels ?? {}, filter.labels))
148
+ continue;
149
+ }
150
+ // Filter archived (unless includeArchived)
151
+ if (!filter?.includeArchived && frontmatter.archivable) {
152
+ // Still include — archivable just marks eligible for sweep
153
+ // Actually archivable=true items can still be listed; only skip if in archived/ folder
154
+ }
155
+ results.push({ task: frontmatter, filePath, body });
156
+ }
157
+ catch {
158
+ // Skip malformed files
159
+ }
160
+ }
161
+ // Sort by task ID (e.g., task-001, task-002)
162
+ results.sort((a, b) => a.task.id.localeCompare(b.task.id));
163
+ return results;
164
+ }
165
+ /**
166
+ * Build dependency map from all task files.
167
+ * Returns { dependencies: task→deps[], dependents: task→dependents[] }
168
+ */
169
+ export async function buildDependencyMaps(projectSlug) {
170
+ const tasks = await listTasks({ projectSlug });
171
+ const dependencies = new Map();
172
+ const dependents = new Map();
173
+ for (const { task } of tasks) {
174
+ dependencies.set(task.id, task.dependencies ?? []);
175
+ if (!dependents.has(task.id)) {
176
+ dependents.set(task.id, []);
177
+ }
178
+ for (const dep of task.dependencies ?? []) {
179
+ if (!dependents.has(dep)) {
180
+ dependents.set(dep, []);
181
+ }
182
+ dependents.get(dep).push(task.id);
183
+ }
184
+ }
185
+ return { dependencies, dependents };
186
+ }
187
+ /**
188
+ * Update reverse dependency (dependents) links when a task's dependencies change.
189
+ */
190
+ export async function syncDependentLinks(taskId, oldDeps, newDeps, projectSlug) {
191
+ // Remove taskId from dependents of removed deps
192
+ const removed = oldDeps.filter((d) => !newDeps.includes(d));
193
+ const added = newDeps.filter((d) => !oldDeps.includes(d));
194
+ for (const depId of removed) {
195
+ const depFile = await readTask(depId, projectSlug);
196
+ if (depFile) {
197
+ depFile.task.dependents = (depFile.task.dependents ?? []).filter((id) => id !== taskId);
198
+ depFile.task.updatedAt = new Date().toISOString();
199
+ await writeTask(depFile);
200
+ }
201
+ }
202
+ for (const depId of added) {
203
+ const depFile = await readTask(depId, projectSlug);
204
+ if (depFile) {
205
+ const deps = depFile.task.dependents ?? [];
206
+ if (!deps.includes(taskId)) {
207
+ depFile.task.dependents = [...deps, taskId];
208
+ depFile.task.updatedAt = new Date().toISOString();
209
+ await writeTask(depFile);
210
+ }
211
+ }
212
+ }
213
+ }
214
+ //# sourceMappingURL=crud.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crud.js","sourceRoot":"","sources":["../../src/engine/crud.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * DAG validation and cascading for tasks.
3
+ * Spec: §3.5 — Dependency Validation
4
+ */
5
+ /**
6
+ * Validate that adding a dependency does not create a cycle.
7
+ * Returns cycle path string if cycle found, null if safe.
8
+ * Spec: §3.5 — Cycle Detection
9
+ */
10
+ export declare function validateNoCycle(taskId: string, newDependency: string, projectSlug?: string): Promise<string | null>;
11
+ /**
12
+ * Validate all new dependencies for a task do not create cycles.
13
+ * Returns error message if any cycle found, null if all safe.
14
+ */
15
+ export declare function validateDependencies(taskId: string, newDependencies: string[], projectSlug?: string): Promise<string | null>;
16
+ /**
17
+ * Cascade failure to all transitive dependents.
18
+ * When a task fails, all tasks that depend on it (directly or transitively)
19
+ * are blocked with blockedReason pointing to the root failed task.
20
+ * Spec: §3.5 — Failure Cascading
21
+ */
22
+ export declare function cascadeFailure(failedTaskId: string, projectSlug?: string): Promise<void>;
23
+ /**
24
+ * Re-evaluate and unblock dependents after a task's failure is resolved.
25
+ * When a failed task is retried and completes, all dependents whose
26
+ * blockedReason traced back to this task are re-evaluated.
27
+ * Spec: §3.5 — Unblock Cascading
28
+ */
29
+ export declare function cascadeUnblock(resolvedTaskId: string, projectSlug?: string): Promise<void>;
30
+ //# sourceMappingURL=dag.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dag.d.ts","sourceRoot":"","sources":["../../src/engine/dag.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EACrB,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAOxB;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,MAAM,EACd,eAAe,EAAE,MAAM,EAAE,EACzB,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAMxB;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,YAAY,EAAE,MAAM,EACpB,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAoBf;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,cAAc,EAAE,MAAM,EACtB,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAwCf"}