@hasna/todos 0.15.41 → 0.15.46
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/dist/cli/cloud-router.d.ts.map +1 -1
- package/dist/cli/index.js +139 -39
- package/dist/contracts.js +6 -6
- package/dist/db/task-graph.d.ts.map +1 -1
- package/dist/db/task-lifecycle.d.ts.map +1 -1
- package/dist/index.js +118 -33
- package/dist/lib/instant-compare.d.ts +35 -0
- package/dist/lib/instant-compare.d.ts.map +1 -0
- package/dist/mcp/index.js +138 -38
- package/dist/mcp.js +2 -2
- package/dist/pr-groups/postgres.d.ts.map +1 -1
- package/dist/project-registration/postgres.d.ts.map +1 -1
- package/dist/project-registration.js +85 -20
- package/dist/registry.js +6 -6
- package/dist/release-provenance.json +5 -5
- package/dist/server/cloud.d.ts.map +1 -1
- package/dist/server/index.js +142 -42
- package/dist/storage/local-sqlite.d.ts.map +1 -1
- package/dist/storage/postgres-adapter.d.ts.map +1 -1
- package/dist/storage.js +69 -11
- package/dist/task-manifest/postgres.d.ts.map +1 -1
- package/dist/task-manifest.js +15 -6
- package/dist/task-subtree-transfer/postgres.d.ts.map +1 -1
- package/dist/task-subtree-transfer.js +15 -6
- package/package.json +2 -2
|
@@ -8787,7 +8787,7 @@ function getTaskGraph(taskId, direction = "both", db) {
|
|
|
8787
8787
|
const deps = getTaskDependencies(t.id, d);
|
|
8788
8788
|
const hasUnfinishedDeps = deps.some((dep) => {
|
|
8789
8789
|
const depTask = getTask(dep.depends_on, d);
|
|
8790
|
-
return depTask && depTask.status
|
|
8790
|
+
return depTask && isBlockingDependencyStatus(depTask.status);
|
|
8791
8791
|
});
|
|
8792
8792
|
return { id: t.id, short_id: t.short_id, title: t.title, status: t.status, priority: t.priority, is_blocked: hasUnfinishedDeps };
|
|
8793
8793
|
}
|
|
@@ -8911,7 +8911,7 @@ function getBlockingDeps(id, db) {
|
|
|
8911
8911
|
const blocking = [];
|
|
8912
8912
|
for (const dep of deps) {
|
|
8913
8913
|
const task = getTask(dep.depends_on, d);
|
|
8914
|
-
if (task && task.status
|
|
8914
|
+
if (task && isBlockingDependencyStatus(task.status))
|
|
8915
8915
|
blocking.push(task);
|
|
8916
8916
|
}
|
|
8917
8917
|
return blocking;
|
|
@@ -9235,7 +9235,7 @@ function getNextTask2(agentId, filters, db) {
|
|
|
9235
9235
|
conditions.push(`id IN (SELECT task_id FROM task_tags WHERE tag IN (${placeholders}))`);
|
|
9236
9236
|
params.push(...filters.tags);
|
|
9237
9237
|
}
|
|
9238
|
-
conditions.push("id NOT IN (SELECT td.task_id FROM task_dependencies td JOIN tasks dep ON dep.id = td.depends_on WHERE dep.status
|
|
9238
|
+
conditions.push("id NOT IN (SELECT td.task_id FROM task_dependencies td JOIN tasks dep ON dep.id = td.depends_on WHERE dep.status NOT IN ('completed', 'cancelled'))");
|
|
9239
9239
|
const where = conditions.join(" AND ");
|
|
9240
9240
|
let recentProjectIds = [];
|
|
9241
9241
|
const assignedAliasParams = [];
|
|
@@ -9279,7 +9279,7 @@ function getActiveWork2(filters, db) {
|
|
|
9279
9279
|
}
|
|
9280
9280
|
function getTasksChangedSince(since, filters, db) {
|
|
9281
9281
|
const d = db || getDatabase();
|
|
9282
|
-
const conditions = ["updated_at > ?"];
|
|
9282
|
+
const conditions = ["(julianday(updated_at) IS NULL OR julianday(updated_at) > julianday(?))"];
|
|
9283
9283
|
const params = [since];
|
|
9284
9284
|
if (filters?.project_id) {
|
|
9285
9285
|
conditions.push("project_id = ?");
|
|
@@ -12812,7 +12812,7 @@ import { createHash as createHash7 } from "crypto";
|
|
|
12812
12812
|
// package.json
|
|
12813
12813
|
var package_default = {
|
|
12814
12814
|
name: "@hasna/todos",
|
|
12815
|
-
version: "0.15.
|
|
12815
|
+
version: "0.15.46",
|
|
12816
12816
|
description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
|
|
12817
12817
|
type: "module",
|
|
12818
12818
|
main: "dist/index.js",
|
|
@@ -12930,7 +12930,7 @@ var package_default = {
|
|
|
12930
12930
|
author: "Andrei Hasna <andrei@hasna.com>",
|
|
12931
12931
|
license: "Apache-2.0",
|
|
12932
12932
|
dependencies: {
|
|
12933
|
-
"@hasna/contracts": "0.13.
|
|
12933
|
+
"@hasna/contracts": "0.13.4",
|
|
12934
12934
|
"@hasna/events": "^0.1.11",
|
|
12935
12935
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
12936
12936
|
chalk: "^5.4.1",
|
|
@@ -12968,6 +12968,57 @@ function normalizeAgentNameInput(name) {
|
|
|
12968
12968
|
// src/storage/postgres-adapter.ts
|
|
12969
12969
|
init_creator_identity();
|
|
12970
12970
|
|
|
12971
|
+
// src/lib/instant-compare.ts
|
|
12972
|
+
var SQLITE_STAMP = /^(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d+))?)?(?:Z|([+-])(\d{2}):(\d{2}))?)?$/;
|
|
12973
|
+
var DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
12974
|
+
function isLeapYear(year) {
|
|
12975
|
+
return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
|
|
12976
|
+
}
|
|
12977
|
+
function sqliteJulianDay(value) {
|
|
12978
|
+
const m = SQLITE_STAMP.exec(value);
|
|
12979
|
+
if (!m)
|
|
12980
|
+
return null;
|
|
12981
|
+
const year = Number(m[1]);
|
|
12982
|
+
const month = Number(m[2]);
|
|
12983
|
+
const day = Number(m[3]);
|
|
12984
|
+
const hour = m[4] === undefined ? 0 : Number(m[4]);
|
|
12985
|
+
const minute = m[5] === undefined ? 0 : Number(m[5]);
|
|
12986
|
+
const second = m[6] === undefined ? 0 : Number(m[6]);
|
|
12987
|
+
const frac = m[7];
|
|
12988
|
+
const sign = m[8];
|
|
12989
|
+
const offsetHour = m[9];
|
|
12990
|
+
const offsetMinute = m[10];
|
|
12991
|
+
if (month < 1 || month > 12)
|
|
12992
|
+
return null;
|
|
12993
|
+
if (hour > 23 || minute > 59 || second > 59)
|
|
12994
|
+
return null;
|
|
12995
|
+
const maxDay = (DAYS_IN_MONTH[month - 1] ?? 0) + (month === 2 && isLeapYear(year) ? 1 : 0);
|
|
12996
|
+
if (day < 1 || day > maxDay)
|
|
12997
|
+
return null;
|
|
12998
|
+
let offsetMinutes = 0;
|
|
12999
|
+
if (sign !== undefined) {
|
|
13000
|
+
const oh = Number(offsetHour ?? "0");
|
|
13001
|
+
const om = Number(offsetMinute ?? "0");
|
|
13002
|
+
if (oh > 23 || om > 59)
|
|
13003
|
+
return null;
|
|
13004
|
+
offsetMinutes = oh * 60 + om;
|
|
13005
|
+
if (sign === "-")
|
|
13006
|
+
offsetMinutes = -offsetMinutes;
|
|
13007
|
+
}
|
|
13008
|
+
const micros = frac === undefined ? 0 : Number((frac + "000000").slice(0, 6));
|
|
13009
|
+
const ms = Date.UTC(year, month - 1, day, hour, minute, second);
|
|
13010
|
+
return (ms + micros / 1000) / 86400000 + 2440587.5 - offsetMinutes / 1440;
|
|
13011
|
+
}
|
|
13012
|
+
function changedSinceStampNewer(stamp, since) {
|
|
13013
|
+
const stampJd = sqliteJulianDay(stamp);
|
|
13014
|
+
if (stampJd === null)
|
|
13015
|
+
return true;
|
|
13016
|
+
const sinceJd = sqliteJulianDay(since);
|
|
13017
|
+
if (sinceJd === null)
|
|
13018
|
+
return false;
|
|
13019
|
+
return stampJd > sinceJd;
|
|
13020
|
+
}
|
|
13021
|
+
|
|
12971
13022
|
// src/lib/plan-project-link-contract.ts
|
|
12972
13023
|
init_types();
|
|
12973
13024
|
import { createHash as createHash2 } from "crypto";
|
|
@@ -13904,11 +13955,16 @@ class PostgresJsonRecordStore {
|
|
|
13904
13955
|
return context?.requestId ?? this.sourceMachineId ?? null;
|
|
13905
13956
|
}
|
|
13906
13957
|
async ensureSchema() {
|
|
13907
|
-
this.schemaReady
|
|
13908
|
-
|
|
13909
|
-
|
|
13910
|
-
|
|
13911
|
-
|
|
13958
|
+
if (!this.schemaReady) {
|
|
13959
|
+
this.schemaReady = (async () => {
|
|
13960
|
+
for (const sql of postgresTodosSyncSchemaSql(this.tableName, this.cursorTableName)) {
|
|
13961
|
+
await this.options.client.query(sql);
|
|
13962
|
+
}
|
|
13963
|
+
})().catch((error) => {
|
|
13964
|
+
this.schemaReady = null;
|
|
13965
|
+
throw error;
|
|
13966
|
+
});
|
|
13967
|
+
}
|
|
13912
13968
|
await this.schemaReady;
|
|
13913
13969
|
}
|
|
13914
13970
|
async get(type, id) {
|
|
@@ -15673,7 +15729,7 @@ async function getActiveWork(filters, store) {
|
|
|
15673
15729
|
}));
|
|
15674
15730
|
}
|
|
15675
15731
|
async function getChangedSince(since, filters, store) {
|
|
15676
|
-
return (await listTasks(filters ?? {}, store)).filter((task) => task.updated_at
|
|
15732
|
+
return (await listTasks(filters ?? {}, store)).filter((task) => changedSinceStampNewer(task.updated_at ?? "", since));
|
|
15677
15733
|
}
|
|
15678
15734
|
async function createProject(input, store, context) {
|
|
15679
15735
|
const timestamp = new Date().toISOString();
|
|
@@ -16604,14 +16660,23 @@ class PostgresTodosProjectRegistrationBackend {
|
|
|
16604
16660
|
this.cursorTableName = safeIdentifier(options.cursorTableName ?? "todos_sync_cursors", "cursorTableName");
|
|
16605
16661
|
}
|
|
16606
16662
|
async ensureSchema() {
|
|
16607
|
-
this.schemaReady
|
|
16608
|
-
|
|
16609
|
-
|
|
16610
|
-
|
|
16611
|
-
|
|
16612
|
-
|
|
16663
|
+
if (this.schemaReady === null) {
|
|
16664
|
+
const attempt = (async () => {
|
|
16665
|
+
for (const statement of postgresTodosSyncSchemaSql(this.tableName, this.cursorTableName)) {
|
|
16666
|
+
await this.client.query(statement);
|
|
16667
|
+
}
|
|
16668
|
+
for (const statement of postgresTodosProjectRegistrationSchemaSql()) {
|
|
16669
|
+
await this.client.query(statement);
|
|
16670
|
+
}
|
|
16671
|
+
})();
|
|
16672
|
+
this.schemaReady = attempt;
|
|
16673
|
+
try {
|
|
16674
|
+
await attempt;
|
|
16675
|
+
} catch (error) {
|
|
16676
|
+
this.schemaReady = null;
|
|
16677
|
+
throw error;
|
|
16613
16678
|
}
|
|
16614
|
-
}
|
|
16679
|
+
}
|
|
16615
16680
|
await this.schemaReady;
|
|
16616
16681
|
}
|
|
16617
16682
|
async transaction(fn) {
|
|
@@ -18293,7 +18358,7 @@ function matchesExtraFilters(task, filter) {
|
|
|
18293
18358
|
}
|
|
18294
18359
|
if (filter.tags?.length) {
|
|
18295
18360
|
const taskTags = new Set(task.tags ?? []);
|
|
18296
|
-
if (!filter.tags.
|
|
18361
|
+
if (!filter.tags.some((tag) => taskTags.has(tag)))
|
|
18297
18362
|
return false;
|
|
18298
18363
|
}
|
|
18299
18364
|
if (filter.include_subtasks !== true && filter.parent_id === undefined && task.parent_id)
|
package/dist/registry.js
CHANGED
|
@@ -8651,7 +8651,7 @@ function getTaskGraph(taskId, direction = "both", db) {
|
|
|
8651
8651
|
const deps = getTaskDependencies(t.id, d);
|
|
8652
8652
|
const hasUnfinishedDeps = deps.some((dep) => {
|
|
8653
8653
|
const depTask = getTask(dep.depends_on, d);
|
|
8654
|
-
return depTask && depTask.status
|
|
8654
|
+
return depTask && isBlockingDependencyStatus(depTask.status);
|
|
8655
8655
|
});
|
|
8656
8656
|
return { id: t.id, short_id: t.short_id, title: t.title, status: t.status, priority: t.priority, is_blocked: hasUnfinishedDeps };
|
|
8657
8657
|
}
|
|
@@ -8911,7 +8911,7 @@ function getBlockingDeps(id, db) {
|
|
|
8911
8911
|
const blocking = [];
|
|
8912
8912
|
for (const dep of deps) {
|
|
8913
8913
|
const task = getTask(dep.depends_on, d);
|
|
8914
|
-
if (task && task.status
|
|
8914
|
+
if (task && isBlockingDependencyStatus(task.status))
|
|
8915
8915
|
blocking.push(task);
|
|
8916
8916
|
}
|
|
8917
8917
|
return blocking;
|
|
@@ -9235,7 +9235,7 @@ function getNextTask(agentId, filters, db) {
|
|
|
9235
9235
|
conditions.push(`id IN (SELECT task_id FROM task_tags WHERE tag IN (${placeholders}))`);
|
|
9236
9236
|
params.push(...filters.tags);
|
|
9237
9237
|
}
|
|
9238
|
-
conditions.push("id NOT IN (SELECT td.task_id FROM task_dependencies td JOIN tasks dep ON dep.id = td.depends_on WHERE dep.status
|
|
9238
|
+
conditions.push("id NOT IN (SELECT td.task_id FROM task_dependencies td JOIN tasks dep ON dep.id = td.depends_on WHERE dep.status NOT IN ('completed', 'cancelled'))");
|
|
9239
9239
|
const where = conditions.join(" AND ");
|
|
9240
9240
|
let recentProjectIds = [];
|
|
9241
9241
|
const assignedAliasParams = [];
|
|
@@ -9279,7 +9279,7 @@ function getActiveWork(filters, db) {
|
|
|
9279
9279
|
}
|
|
9280
9280
|
function getTasksChangedSince(since, filters, db) {
|
|
9281
9281
|
const d = db || getDatabase();
|
|
9282
|
-
const conditions = ["updated_at > ?"];
|
|
9282
|
+
const conditions = ["(julianday(updated_at) IS NULL OR julianday(updated_at) > julianday(?))"];
|
|
9283
9283
|
const params = [since];
|
|
9284
9284
|
if (filters?.project_id) {
|
|
9285
9285
|
conditions.push("project_id = ?");
|
|
@@ -12809,7 +12809,7 @@ var init_tasks = __esm(() => {
|
|
|
12809
12809
|
// package.json
|
|
12810
12810
|
var package_default = {
|
|
12811
12811
|
name: "@hasna/todos",
|
|
12812
|
-
version: "0.15.
|
|
12812
|
+
version: "0.15.46",
|
|
12813
12813
|
description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
|
|
12814
12814
|
type: "module",
|
|
12815
12815
|
main: "dist/index.js",
|
|
@@ -12927,7 +12927,7 @@ var package_default = {
|
|
|
12927
12927
|
author: "Andrei Hasna <andrei@hasna.com>",
|
|
12928
12928
|
license: "Apache-2.0",
|
|
12929
12929
|
dependencies: {
|
|
12930
|
-
"@hasna/contracts": "0.13.
|
|
12930
|
+
"@hasna/contracts": "0.13.4",
|
|
12931
12931
|
"@hasna/events": "^0.1.11",
|
|
12932
12932
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
12933
12933
|
chalk: "^5.4.1",
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"packageName": "@hasna/todos",
|
|
3
|
-
"packageVersion": "0.15.
|
|
3
|
+
"packageVersion": "0.15.46",
|
|
4
4
|
"repository": "https://github.com/hasna/todos.git",
|
|
5
|
-
"gitCommit": "
|
|
6
|
-
"gitTree": "
|
|
7
|
-
"sourceTreeSha256": "
|
|
8
|
-
"generatedAt": "2026-08-
|
|
5
|
+
"gitCommit": "c80f00ce94d3a8a18c6c3810127cf4a7bb7b2353",
|
|
6
|
+
"gitTree": "744ca8f8d9f3b8c2afff7f9c92df419dc8a64ad8",
|
|
7
|
+
"sourceTreeSha256": "60f8de83b04c4b91fbcf564f95f0f9cb5998683b8e35512a4bd42577c1edd8ba",
|
|
8
|
+
"generatedAt": "2026-08-22T22:48:59.000Z"
|
|
9
9
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloud.d.ts","sourceRoot":"","sources":["../../src/server/cloud.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAwB,MAAM,uBAAuB,CAAC;AAG1E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAKvD,OAAO,EAGL,KAAK,iCAAiC,EACvC,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAGL,KAAK,0BAA0B,EAChC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAGL,KAAK,iCAAiC,EACvC,MAAM,mCAAmC,CAAC;AAQ3C,OAAO,EAEL,KAAK,+BAA+B,EACpC,KAAK,8BAA8B,EACpC,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAEL,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAC7B,MAAM,kCAAkC,CAAC;AAE1C,eAAO,MAAM,cAAc,UAAU,CAAC;AAEtC,uFAAuF;AACvF,wBAAgB,uBAAuB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,GAAG,SAAS,CAOhG;AAED,+DAA+D;AAC/D,wBAAgB,oBAAoB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,GAAG,SAAS,CAO7F;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAEzF;AA4BD,4EAA4E;AAC5E,wBAAgB,sBAAsB,IAAI,mBAAmB,CAK5D;AAED,gFAAgF;AAChF,wBAAgB,qBAAqB,IAAI,aAAa,CAIrD;AAED,iFAAiF;AACjF,wBAAgB,oCAAoC,IAAI,iCAAiC,CAYxF;AAED,gFAAgF;AAChF,wBAAgB,6BAA6B,IAAI,0BAA0B,CAO1E;AAED,wFAAwF;AACxF,wBAAgB,oCAAoC,IAAI,iCAAiC,CAOxF;AAuBD,wBAAgB,cAAc,IAAI,WAAW,CAI5C;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,cAAc,CAoBjD;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"cloud.d.ts","sourceRoot":"","sources":["../../src/server/cloud.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAwB,MAAM,uBAAuB,CAAC;AAG1E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAKvD,OAAO,EAGL,KAAK,iCAAiC,EACvC,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAGL,KAAK,0BAA0B,EAChC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAGL,KAAK,iCAAiC,EACvC,MAAM,mCAAmC,CAAC;AAQ3C,OAAO,EAEL,KAAK,+BAA+B,EACpC,KAAK,8BAA8B,EACpC,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAEL,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAC7B,MAAM,kCAAkC,CAAC;AAE1C,eAAO,MAAM,cAAc,UAAU,CAAC;AAEtC,uFAAuF;AACvF,wBAAgB,uBAAuB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,GAAG,SAAS,CAOhG;AAED,+DAA+D;AAC/D,wBAAgB,oBAAoB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,GAAG,SAAS,CAO7F;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAEzF;AA4BD,4EAA4E;AAC5E,wBAAgB,sBAAsB,IAAI,mBAAmB,CAK5D;AAED,gFAAgF;AAChF,wBAAgB,qBAAqB,IAAI,aAAa,CAIrD;AAED,iFAAiF;AACjF,wBAAgB,oCAAoC,IAAI,iCAAiC,CAYxF;AAED,gFAAgF;AAChF,wBAAgB,6BAA6B,IAAI,0BAA0B,CAO1E;AAED,wFAAwF;AACxF,wBAAgB,oCAAoC,IAAI,iCAAiC,CAOxF;AAuBD,wBAAgB,cAAc,IAAI,WAAW,CAI5C;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,cAAc,CAoBjD;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAkCvD;AAED;;;;GAIG;AACH,wBAAsB,6BAA6B,IAAI,OAAO,CAAC,IAAI,CAAC,CAEnE;AAED;;;GAGG;AACH,wBAAsB,2BAA2B,IAAI,OAAO,CAAC,IAAI,CAAC,CAEjE;AAED;;;GAGG;AACH,wBAAsB,4BAA4B,IAAI,OAAO,CAAC,IAAI,CAAC,CAElE;AAED,uFAAuF;AACvF,wBAAsB,kCAAkC,IAAI,OAAO,CAAC,IAAI,CAAC,CAExE;AAED;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,MAAM,CAAC,CAS9D;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,GAAE,+BAAoC,GAC5C,OAAO,CAAC,8BAA8B,CAAC,CAEzC;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,uBAAuB,CAAC,CAElC;AAED,iEAAiE;AACjE,wBAAsB,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC,CAIlD;AAED,4BAA4B;AAC5B,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAWhD"}
|
package/dist/server/index.js
CHANGED
|
@@ -70,7 +70,7 @@ var package_default;
|
|
|
70
70
|
var init_package = __esm(() => {
|
|
71
71
|
package_default = {
|
|
72
72
|
name: "@hasna/todos",
|
|
73
|
-
version: "0.15.
|
|
73
|
+
version: "0.15.46",
|
|
74
74
|
description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
|
|
75
75
|
type: "module",
|
|
76
76
|
main: "dist/index.js",
|
|
@@ -188,7 +188,7 @@ var init_package = __esm(() => {
|
|
|
188
188
|
author: "Andrei Hasna <andrei@hasna.com>",
|
|
189
189
|
license: "Apache-2.0",
|
|
190
190
|
dependencies: {
|
|
191
|
-
"@hasna/contracts": "0.13.
|
|
191
|
+
"@hasna/contracts": "0.13.4",
|
|
192
192
|
"@hasna/events": "^0.1.11",
|
|
193
193
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
194
194
|
chalk: "^5.4.1",
|
|
@@ -223,7 +223,7 @@ var init_package_version = __esm(() => {
|
|
|
223
223
|
init_package();
|
|
224
224
|
});
|
|
225
225
|
|
|
226
|
-
// node_modules/.bun/@hasna+contracts@0.13.
|
|
226
|
+
// node_modules/.bun/@hasna+contracts@0.13.4+ad7b1171e6eea7eb/node_modules/@hasna/contracts/dist/auth/index.js
|
|
227
227
|
import { createHash, createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
228
228
|
function isValidTenantId(value) {
|
|
229
229
|
return typeof value === "string" && TENANT_ID_PATTERN.test(value);
|
|
@@ -1385,6 +1385,60 @@ var init_creator_identity = __esm(() => {
|
|
|
1385
1385
|
init_sync_utils();
|
|
1386
1386
|
});
|
|
1387
1387
|
|
|
1388
|
+
// src/lib/instant-compare.ts
|
|
1389
|
+
function isLeapYear(year) {
|
|
1390
|
+
return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
|
|
1391
|
+
}
|
|
1392
|
+
function sqliteJulianDay(value) {
|
|
1393
|
+
const m = SQLITE_STAMP.exec(value);
|
|
1394
|
+
if (!m)
|
|
1395
|
+
return null;
|
|
1396
|
+
const year = Number(m[1]);
|
|
1397
|
+
const month = Number(m[2]);
|
|
1398
|
+
const day = Number(m[3]);
|
|
1399
|
+
const hour = m[4] === undefined ? 0 : Number(m[4]);
|
|
1400
|
+
const minute = m[5] === undefined ? 0 : Number(m[5]);
|
|
1401
|
+
const second = m[6] === undefined ? 0 : Number(m[6]);
|
|
1402
|
+
const frac = m[7];
|
|
1403
|
+
const sign = m[8];
|
|
1404
|
+
const offsetHour = m[9];
|
|
1405
|
+
const offsetMinute = m[10];
|
|
1406
|
+
if (month < 1 || month > 12)
|
|
1407
|
+
return null;
|
|
1408
|
+
if (hour > 23 || minute > 59 || second > 59)
|
|
1409
|
+
return null;
|
|
1410
|
+
const maxDay = (DAYS_IN_MONTH[month - 1] ?? 0) + (month === 2 && isLeapYear(year) ? 1 : 0);
|
|
1411
|
+
if (day < 1 || day > maxDay)
|
|
1412
|
+
return null;
|
|
1413
|
+
let offsetMinutes = 0;
|
|
1414
|
+
if (sign !== undefined) {
|
|
1415
|
+
const oh = Number(offsetHour ?? "0");
|
|
1416
|
+
const om = Number(offsetMinute ?? "0");
|
|
1417
|
+
if (oh > 23 || om > 59)
|
|
1418
|
+
return null;
|
|
1419
|
+
offsetMinutes = oh * 60 + om;
|
|
1420
|
+
if (sign === "-")
|
|
1421
|
+
offsetMinutes = -offsetMinutes;
|
|
1422
|
+
}
|
|
1423
|
+
const micros = frac === undefined ? 0 : Number((frac + "000000").slice(0, 6));
|
|
1424
|
+
const ms = Date.UTC(year, month - 1, day, hour, minute, second);
|
|
1425
|
+
return (ms + micros / 1000) / 86400000 + 2440587.5 - offsetMinutes / 1440;
|
|
1426
|
+
}
|
|
1427
|
+
function changedSinceStampNewer(stamp, since) {
|
|
1428
|
+
const stampJd = sqliteJulianDay(stamp);
|
|
1429
|
+
if (stampJd === null)
|
|
1430
|
+
return true;
|
|
1431
|
+
const sinceJd = sqliteJulianDay(since);
|
|
1432
|
+
if (sinceJd === null)
|
|
1433
|
+
return false;
|
|
1434
|
+
return stampJd > sinceJd;
|
|
1435
|
+
}
|
|
1436
|
+
var SQLITE_STAMP, DAYS_IN_MONTH;
|
|
1437
|
+
var init_instant_compare = __esm(() => {
|
|
1438
|
+
SQLITE_STAMP = /^(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d+))?)?(?:Z|([+-])(\d{2}):(\d{2}))?)?$/;
|
|
1439
|
+
DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
1440
|
+
});
|
|
1441
|
+
|
|
1388
1442
|
// src/lib/plan-project-link-contract.ts
|
|
1389
1443
|
import { createHash as createHash2 } from "crypto";
|
|
1390
1444
|
function canonicalPlanProjectLinkJson(value) {
|
|
@@ -2898,11 +2952,16 @@ class PostgresJsonRecordStore {
|
|
|
2898
2952
|
return context?.requestId ?? this.sourceMachineId ?? null;
|
|
2899
2953
|
}
|
|
2900
2954
|
async ensureSchema() {
|
|
2901
|
-
this.schemaReady
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2955
|
+
if (!this.schemaReady) {
|
|
2956
|
+
this.schemaReady = (async () => {
|
|
2957
|
+
for (const sql of postgresTodosSyncSchemaSql(this.tableName, this.cursorTableName)) {
|
|
2958
|
+
await this.options.client.query(sql);
|
|
2959
|
+
}
|
|
2960
|
+
})().catch((error) => {
|
|
2961
|
+
this.schemaReady = null;
|
|
2962
|
+
throw error;
|
|
2963
|
+
});
|
|
2964
|
+
}
|
|
2906
2965
|
await this.schemaReady;
|
|
2907
2966
|
}
|
|
2908
2967
|
async get(type, id) {
|
|
@@ -4664,7 +4723,7 @@ async function getActiveWork(filters, store) {
|
|
|
4664
4723
|
}));
|
|
4665
4724
|
}
|
|
4666
4725
|
async function getChangedSince(since, filters, store) {
|
|
4667
|
-
return (await listTasks(filters ?? {}, store)).filter((task) => task.updated_at
|
|
4726
|
+
return (await listTasks(filters ?? {}, store)).filter((task) => changedSinceStampNewer(task.updated_at ?? "", since));
|
|
4668
4727
|
}
|
|
4669
4728
|
async function createProject(input, store, context) {
|
|
4670
4729
|
const timestamp = new Date().toISOString();
|
|
@@ -5223,6 +5282,7 @@ var CLOUD_LOCK_EXPIRY_MINUTES = 30, TASK_ORDER_TIEBREAK = "CASE payload->>'prior
|
|
|
5223
5282
|
var init_postgres_adapter = __esm(() => {
|
|
5224
5283
|
init_types();
|
|
5225
5284
|
init_creator_identity();
|
|
5285
|
+
init_instant_compare();
|
|
5226
5286
|
init_plan_project_link_contract();
|
|
5227
5287
|
init_stale_lock_handoff();
|
|
5228
5288
|
init_postgres_sync();
|
|
@@ -7054,10 +7114,19 @@ class PostgresPrGroupLedgerPersistence {
|
|
|
7054
7114
|
this.client = client;
|
|
7055
7115
|
}
|
|
7056
7116
|
async ensureSchema() {
|
|
7057
|
-
this.schemaReady
|
|
7058
|
-
|
|
7059
|
-
|
|
7060
|
-
|
|
7117
|
+
if (this.schemaReady === null) {
|
|
7118
|
+
const attempt = (async () => {
|
|
7119
|
+
for (const statement of postgresPrGroupSchemaSql())
|
|
7120
|
+
await this.client.query(statement);
|
|
7121
|
+
})();
|
|
7122
|
+
this.schemaReady = attempt;
|
|
7123
|
+
try {
|
|
7124
|
+
await attempt;
|
|
7125
|
+
} catch (error) {
|
|
7126
|
+
this.schemaReady = null;
|
|
7127
|
+
throw error;
|
|
7128
|
+
}
|
|
7129
|
+
}
|
|
7061
7130
|
return this.schemaReady;
|
|
7062
7131
|
}
|
|
7063
7132
|
async transaction(fn) {
|
|
@@ -7702,14 +7771,23 @@ class PostgresTodosProjectRegistrationBackend {
|
|
|
7702
7771
|
this.cursorTableName = safeIdentifier(options.cursorTableName ?? "todos_sync_cursors", "cursorTableName");
|
|
7703
7772
|
}
|
|
7704
7773
|
async ensureSchema() {
|
|
7705
|
-
this.schemaReady
|
|
7706
|
-
|
|
7707
|
-
|
|
7708
|
-
|
|
7709
|
-
|
|
7710
|
-
|
|
7774
|
+
if (this.schemaReady === null) {
|
|
7775
|
+
const attempt = (async () => {
|
|
7776
|
+
for (const statement of postgresTodosSyncSchemaSql(this.tableName, this.cursorTableName)) {
|
|
7777
|
+
await this.client.query(statement);
|
|
7778
|
+
}
|
|
7779
|
+
for (const statement of postgresTodosProjectRegistrationSchemaSql()) {
|
|
7780
|
+
await this.client.query(statement);
|
|
7781
|
+
}
|
|
7782
|
+
})();
|
|
7783
|
+
this.schemaReady = attempt;
|
|
7784
|
+
try {
|
|
7785
|
+
await attempt;
|
|
7786
|
+
} catch (error) {
|
|
7787
|
+
this.schemaReady = null;
|
|
7788
|
+
throw error;
|
|
7711
7789
|
}
|
|
7712
|
-
}
|
|
7790
|
+
}
|
|
7713
7791
|
await this.schemaReady;
|
|
7714
7792
|
}
|
|
7715
7793
|
async transaction(fn) {
|
|
@@ -15288,7 +15366,7 @@ function getTaskGraph(taskId, direction = "both", db) {
|
|
|
15288
15366
|
const deps = getTaskDependencies(t.id, d);
|
|
15289
15367
|
const hasUnfinishedDeps = deps.some((dep) => {
|
|
15290
15368
|
const depTask = getTask(dep.depends_on, d);
|
|
15291
|
-
return depTask && depTask.status
|
|
15369
|
+
return depTask && isBlockingDependencyStatus(depTask.status);
|
|
15292
15370
|
});
|
|
15293
15371
|
return { id: t.id, short_id: t.short_id, title: t.title, status: t.status, priority: t.priority, is_blocked: hasUnfinishedDeps };
|
|
15294
15372
|
}
|
|
@@ -15412,7 +15490,7 @@ function getBlockingDeps(id, db) {
|
|
|
15412
15490
|
const blocking = [];
|
|
15413
15491
|
for (const dep of deps) {
|
|
15414
15492
|
const task = getTask(dep.depends_on, d);
|
|
15415
|
-
if (task && task.status
|
|
15493
|
+
if (task && isBlockingDependencyStatus(task.status))
|
|
15416
15494
|
blocking.push(task);
|
|
15417
15495
|
}
|
|
15418
15496
|
return blocking;
|
|
@@ -15736,7 +15814,7 @@ function getNextTask2(agentId, filters, db) {
|
|
|
15736
15814
|
conditions.push(`id IN (SELECT task_id FROM task_tags WHERE tag IN (${placeholders}))`);
|
|
15737
15815
|
params.push(...filters.tags);
|
|
15738
15816
|
}
|
|
15739
|
-
conditions.push("id NOT IN (SELECT td.task_id FROM task_dependencies td JOIN tasks dep ON dep.id = td.depends_on WHERE dep.status
|
|
15817
|
+
conditions.push("id NOT IN (SELECT td.task_id FROM task_dependencies td JOIN tasks dep ON dep.id = td.depends_on WHERE dep.status NOT IN ('completed', 'cancelled'))");
|
|
15740
15818
|
const where = conditions.join(" AND ");
|
|
15741
15819
|
let recentProjectIds = [];
|
|
15742
15820
|
const assignedAliasParams = [];
|
|
@@ -15780,7 +15858,7 @@ function getActiveWork2(filters, db) {
|
|
|
15780
15858
|
}
|
|
15781
15859
|
function getTasksChangedSince(since, filters, db) {
|
|
15782
15860
|
const d = db || getDatabase();
|
|
15783
|
-
const conditions = ["updated_at > ?"];
|
|
15861
|
+
const conditions = ["(julianday(updated_at) IS NULL OR julianday(updated_at) > julianday(?))"];
|
|
15784
15862
|
const params = [since];
|
|
15785
15863
|
if (filters?.project_id) {
|
|
15786
15864
|
conditions.push("project_id = ?");
|
|
@@ -21078,7 +21156,7 @@ function matchesExtraFilters(task, filter) {
|
|
|
21078
21156
|
}
|
|
21079
21157
|
if (filter.tags?.length) {
|
|
21080
21158
|
const taskTags = new Set(task.tags ?? []);
|
|
21081
|
-
if (!filter.tags.
|
|
21159
|
+
if (!filter.tags.some((tag) => taskTags.has(tag)))
|
|
21082
21160
|
return false;
|
|
21083
21161
|
}
|
|
21084
21162
|
if (filter.include_subtasks !== true && filter.parent_id === undefined && task.parent_id)
|
|
@@ -27812,12 +27890,21 @@ class PostgresTodosTaskManifestBackend {
|
|
|
27812
27890
|
this.tenantId = options.tenantId ?? "default";
|
|
27813
27891
|
}
|
|
27814
27892
|
async ensureSchema() {
|
|
27815
|
-
this.schemaReady
|
|
27816
|
-
|
|
27817
|
-
|
|
27818
|
-
|
|
27819
|
-
|
|
27820
|
-
|
|
27893
|
+
if (this.schemaReady === null) {
|
|
27894
|
+
const attempt = (async () => {
|
|
27895
|
+
for (const sql of postgresTodosSyncSchemaSql(this.tableName))
|
|
27896
|
+
await this.client.query(sql);
|
|
27897
|
+
for (const sql of postgresTodosTaskManifestSchemaSql(this.tenantId))
|
|
27898
|
+
await this.client.query(sql);
|
|
27899
|
+
})();
|
|
27900
|
+
this.schemaReady = attempt;
|
|
27901
|
+
try {
|
|
27902
|
+
await attempt;
|
|
27903
|
+
} catch (error) {
|
|
27904
|
+
this.schemaReady = null;
|
|
27905
|
+
throw error;
|
|
27906
|
+
}
|
|
27907
|
+
}
|
|
27821
27908
|
await this.schemaReady;
|
|
27822
27909
|
}
|
|
27823
27910
|
async insertSync(tx, objectType2, objectId, payload, now3) {
|
|
@@ -29117,12 +29204,21 @@ class PostgresTodosTaskSubtreeTransferBackend {
|
|
|
29117
29204
|
this.tenantId = options.tenantId ?? "default";
|
|
29118
29205
|
}
|
|
29119
29206
|
async ensureSchema() {
|
|
29120
|
-
this.schemaReady
|
|
29121
|
-
|
|
29122
|
-
|
|
29123
|
-
|
|
29124
|
-
|
|
29125
|
-
|
|
29207
|
+
if (this.schemaReady === null) {
|
|
29208
|
+
const attempt = (async () => {
|
|
29209
|
+
for (const sql of postgresTodosSyncSchemaSql(this.tableName))
|
|
29210
|
+
await this.client.query(sql);
|
|
29211
|
+
for (const sql of postgresTodosTaskSubtreeTransferSchemaSql())
|
|
29212
|
+
await this.client.query(sql);
|
|
29213
|
+
})();
|
|
29214
|
+
this.schemaReady = attempt;
|
|
29215
|
+
try {
|
|
29216
|
+
await attempt;
|
|
29217
|
+
} catch (error) {
|
|
29218
|
+
this.schemaReady = null;
|
|
29219
|
+
throw error;
|
|
29220
|
+
}
|
|
29221
|
+
}
|
|
29126
29222
|
await this.schemaReady;
|
|
29127
29223
|
}
|
|
29128
29224
|
async snapshot(client, input, forUpdate = false) {
|
|
@@ -30221,7 +30317,10 @@ async function ensureCloudSchema() {
|
|
|
30221
30317
|
await client.query(sql);
|
|
30222
30318
|
}
|
|
30223
30319
|
await getApiKeyStore().ensureSchema();
|
|
30224
|
-
})()
|
|
30320
|
+
})().catch((error) => {
|
|
30321
|
+
schemaEnsured = null;
|
|
30322
|
+
throw error;
|
|
30323
|
+
});
|
|
30225
30324
|
return schemaEnsured;
|
|
30226
30325
|
}
|
|
30227
30326
|
async function ensureCloudCommentCursorIndex() {
|
|
@@ -52868,7 +52967,7 @@ var require_formats = __commonJS((exports) => {
|
|
|
52868
52967
|
email: /^[a-z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/i
|
|
52869
52968
|
};
|
|
52870
52969
|
exports.formatNames = Object.keys(exports.fullFormats);
|
|
52871
|
-
function
|
|
52970
|
+
function isLeapYear2(year) {
|
|
52872
52971
|
return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
|
|
52873
52972
|
}
|
|
52874
52973
|
var DATE = /^(\d\d\d\d)-(\d\d)-(\d\d)$/;
|
|
@@ -52880,7 +52979,7 @@ var require_formats = __commonJS((exports) => {
|
|
|
52880
52979
|
const year = +matches[1];
|
|
52881
52980
|
const month = +matches[2];
|
|
52882
52981
|
const day = +matches[3];
|
|
52883
|
-
return month >= 1 && month <= 12 && day >= 1 && day <= (month === 2 &&
|
|
52982
|
+
return month >= 1 && month <= 12 && day >= 1 && day <= (month === 2 && isLeapYear2(year) ? 29 : DAYS[month]);
|
|
52884
52983
|
}
|
|
52885
52984
|
function compareDate(d1, d2) {
|
|
52886
52985
|
if (!(d1 && d2))
|
|
@@ -55696,7 +55795,7 @@ var init_assignee_context = __esm(() => {
|
|
|
55696
55795
|
init_assignee_validation();
|
|
55697
55796
|
});
|
|
55698
55797
|
|
|
55699
|
-
// node_modules/.bun/@hasna+contracts@0.13.
|
|
55798
|
+
// node_modules/.bun/@hasna+contracts@0.13.4+ad7b1171e6eea7eb/node_modules/@hasna/contracts/dist/client/storage.js
|
|
55700
55799
|
import { isIP } from "net";
|
|
55701
55800
|
import { readFileSync as readFileSync5, statSync as statSync4 } from "fs";
|
|
55702
55801
|
import { join as join10 } from "path";
|
|
@@ -58156,6 +58255,7 @@ var init_cloud_router = __esm(() => {
|
|
|
58156
58255
|
init_storage();
|
|
58157
58256
|
init_types();
|
|
58158
58257
|
init_redaction();
|
|
58258
|
+
init_instant_compare();
|
|
58159
58259
|
init_plan_project_link_contract();
|
|
58160
58260
|
init_http_client();
|
|
58161
58261
|
init_adoption_validation();
|
|
@@ -93943,7 +94043,7 @@ function scoreHealth(scope, scopeId, db) {
|
|
|
93943
94043
|
const blockers = d.query(`SELECT dep.id, dep.short_id, dep.title, dep.status
|
|
93944
94044
|
FROM task_dependencies td
|
|
93945
94045
|
JOIN tasks dep ON dep.id = td.depends_on
|
|
93946
|
-
WHERE td.task_id = ? AND dep.status
|
|
94046
|
+
WHERE td.task_id = ? AND dep.status NOT IN ('completed', 'cancelled')`).all(task2.id);
|
|
93947
94047
|
return { id: task2.id, short_id: task2.short_id, title: redactEvidenceText(task2.title), blockers };
|
|
93948
94048
|
}).filter((entry2) => entry2.blockers.length > 0);
|
|
93949
94049
|
const overdue = tasks.filter((task2) => activeTaskIds.has(task2.id) && Boolean(task2.due_at && task2.due_at < generatedAt)).map((task2) => ({ id: task2.id, short_id: task2.short_id, title: redactEvidenceText(task2.title), due_at: task2.due_at }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-sqlite.d.ts","sourceRoot":"","sources":["../../src/storage/local-sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAgF3C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAM3D,MAAM,WAAW,2CAA2C;IAC1D,EAAE,CAAC,EAAE,QAAQ,CAAC;CACf;
|
|
1
|
+
{"version":3,"file":"local-sqlite.d.ts","sourceRoot":"","sources":["../../src/storage/local-sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAgF3C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAM3D,MAAM,WAAW,2CAA2C;IAC1D,EAAE,CAAC,EAAE,QAAQ,CAAC;CACf;AAqGD,wBAAgB,oCAAoC,CAClD,OAAO,GAAE,2CAAgD,GACxD,mBAAmB,CA2JrB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres-adapter.d.ts","sourceRoot":"","sources":["../../src/storage/postgres-adapter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"postgres-adapter.d.ts","sourceRoot":"","sources":["../../src/storage/postgres-adapter.ts"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EAcV,mBAAmB,EAYpB,MAAM,iBAAiB,CAAC;AAczB,OAAO,EAIL,KAAK,wBAAwB,EAE9B,MAAM,oBAAoB,CAAC;AA4B5B,MAAM,WAAW,wCAAwC;IACvD,MAAM,EAAE,wBAAwB,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAuBD,wBAAgB,iCAAiC,CAC/C,OAAO,EAAE,wCAAwC,GAChD,mBAAmB,CAiLrB"}
|