@hasna/todos 0.13.8 → 0.13.10
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/claim-guard.d.ts.map +1 -1
- package/dist/cli/cloud-router.d.ts +2 -0
- package/dist/cli/cloud-router.d.ts.map +1 -1
- package/dist/cli/commands/project-commands.d.ts.map +1 -1
- package/dist/cli/commands/task-commands.d.ts.map +1 -1
- package/dist/cli/components/TaskDetail.d.ts.map +1 -1
- package/dist/cli/components/TaskList.d.ts.map +1 -1
- package/dist/cli/helpers.d.ts.map +1 -1
- package/dist/cli/index.js +222 -48
- package/dist/cli/stage-a.d.ts.map +1 -1
- package/dist/contracts.js +46 -10
- package/dist/db/task-crud.d.ts.map +1 -1
- package/dist/db/task-lifecycle.d.ts.map +1 -1
- package/dist/index.js +106 -21
- package/dist/lib/lock-display.d.ts +52 -0
- package/dist/lib/lock-display.d.ts.map +1 -0
- package/dist/mcp/index.d.ts +5 -0
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +159 -28
- package/dist/mcp.js +3 -3
- package/dist/registry.js +46 -10
- package/dist/release-provenance.json +5 -5
- package/dist/server/index.js +14016 -1227
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/v1.d.ts.map +1 -1
- package/dist/storage/postgres-adapter.d.ts.map +1 -1
- package/dist/storage.js +103 -18
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/mcp/index.js
CHANGED
|
@@ -44,7 +44,7 @@ var __require = import.meta.require;
|
|
|
44
44
|
function isBlockingDependencyStatus(status) {
|
|
45
45
|
return status !== "completed" && status !== "cancelled";
|
|
46
46
|
}
|
|
47
|
-
var TASK_STATUSES, VersionConflictError, TaskNotFoundError, TaskReferenceAmbiguousError, ProjectNotFoundError, ResourceConflictError, PlanNotFoundError, LockError, AgentNotFoundError, IdentityAliasAmbiguousError, IdentityIdImmutableError, TaskListNotFoundError, DependencyCycleError, CompletionGuardError, DispatchNotFoundError;
|
|
47
|
+
var TASK_STATUSES, VersionConflictError, TaskNotFoundError, TaskNotStartableError, TaskReferenceAmbiguousError, ProjectNotFoundError, ResourceConflictError, PlanNotFoundError, LockError, AgentNotFoundError, IdentityAliasAmbiguousError, IdentityIdImmutableError, TaskListNotFoundError, DependencyCycleError, CompletionGuardError, DispatchNotFoundError;
|
|
48
48
|
var init_types = __esm(() => {
|
|
49
49
|
TASK_STATUSES = [
|
|
50
50
|
"pending",
|
|
@@ -77,6 +77,20 @@ var init_types = __esm(() => {
|
|
|
77
77
|
this.name = "TaskNotFoundError";
|
|
78
78
|
}
|
|
79
79
|
};
|
|
80
|
+
TaskNotStartableError = class TaskNotStartableError extends Error {
|
|
81
|
+
taskId;
|
|
82
|
+
status;
|
|
83
|
+
agentId;
|
|
84
|
+
static code = "TASK_NOT_STARTABLE";
|
|
85
|
+
static suggestion = "Reset the task status to pending before starting it again.";
|
|
86
|
+
constructor(taskId, status, agentId) {
|
|
87
|
+
super(`Task ${taskId} is ${status} and cannot be started by ${agentId}; ` + "reset the task status to pending before starting it again");
|
|
88
|
+
this.taskId = taskId;
|
|
89
|
+
this.status = status;
|
|
90
|
+
this.agentId = agentId;
|
|
91
|
+
this.name = "TaskNotStartableError";
|
|
92
|
+
}
|
|
93
|
+
};
|
|
80
94
|
TaskReferenceAmbiguousError = class TaskReferenceAmbiguousError extends Error {
|
|
81
95
|
reference;
|
|
82
96
|
static code = "TASK_REFERENCE_AMBIGUOUS";
|
|
@@ -5095,6 +5109,24 @@ var init_agents = __esm(() => {
|
|
|
5095
5109
|
init_agent_names();
|
|
5096
5110
|
});
|
|
5097
5111
|
|
|
5112
|
+
// src/lib/lock-display.ts
|
|
5113
|
+
function lockDisplayState(lockedBy, lockedAt, nowMs = Date.now()) {
|
|
5114
|
+
const holder = lockedBy ?? null;
|
|
5115
|
+
const at = lockedAt ?? null;
|
|
5116
|
+
if (!holder) {
|
|
5117
|
+
return { present: false, held: false, expired: false, holder: null, lockedAt: at };
|
|
5118
|
+
}
|
|
5119
|
+
const expired = isLockExpired(at, nowMs);
|
|
5120
|
+
return { present: true, held: !expired, expired, holder, lockedAt: at };
|
|
5121
|
+
}
|
|
5122
|
+
function formatExpiredLock(state) {
|
|
5123
|
+
const at = state.lockedAt ? ` at ${state.lockedAt}` : "";
|
|
5124
|
+
return `expired (last held by ${state.holder}${at})`;
|
|
5125
|
+
}
|
|
5126
|
+
var init_lock_display = __esm(() => {
|
|
5127
|
+
init_database();
|
|
5128
|
+
});
|
|
5129
|
+
|
|
5098
5130
|
// src/lib/logger.ts
|
|
5099
5131
|
async function logError(_message, _opts) {}
|
|
5100
5132
|
|
|
@@ -12865,7 +12897,7 @@ function assertStartable(task, agentId) {
|
|
|
12865
12897
|
return;
|
|
12866
12898
|
if (task.status === "in_progress")
|
|
12867
12899
|
return;
|
|
12868
|
-
throw new
|
|
12900
|
+
throw new TaskNotStartableError(task.id, task.status, agentId);
|
|
12869
12901
|
}
|
|
12870
12902
|
function getBlockingDeps(id, db) {
|
|
12871
12903
|
const d = db || getDatabase();
|
|
@@ -12936,7 +12968,7 @@ function completeTask(id, agentId, db, options) {
|
|
|
12936
12968
|
if (task.status === "cancelled") {
|
|
12937
12969
|
throw new Error(`Task ${id} is cancelled and cannot be completed`);
|
|
12938
12970
|
}
|
|
12939
|
-
if (
|
|
12971
|
+
if (task.locked_by && !sameHolder(task.locked_by, agentId) && !isLockExpired(task.locked_at)) {
|
|
12940
12972
|
throw new LockError(id, task.locked_by);
|
|
12941
12973
|
}
|
|
12942
12974
|
checkCompletionGuard(task, agentId || null, d);
|
|
@@ -13571,6 +13603,30 @@ function getTaskWithRelations(id, db) {
|
|
|
13571
13603
|
checklist
|
|
13572
13604
|
};
|
|
13573
13605
|
}
|
|
13606
|
+
function resolveAssignedToAliases(db, ref) {
|
|
13607
|
+
const aliases = new Set([ref]);
|
|
13608
|
+
let agentId;
|
|
13609
|
+
try {
|
|
13610
|
+
agentId = resolvePartialId(db, "agents", ref);
|
|
13611
|
+
} catch (err) {
|
|
13612
|
+
if (!(err instanceof IdentityAliasAmbiguousError))
|
|
13613
|
+
throw err;
|
|
13614
|
+
agentId = null;
|
|
13615
|
+
}
|
|
13616
|
+
if (agentId) {
|
|
13617
|
+
aliases.add(agentId);
|
|
13618
|
+
const row = db.query("SELECT name FROM agents WHERE id = ?").get(agentId);
|
|
13619
|
+
if (row?.name)
|
|
13620
|
+
aliases.add(row.name);
|
|
13621
|
+
}
|
|
13622
|
+
return [...aliases];
|
|
13623
|
+
}
|
|
13624
|
+
function lowerInClause(column, values, params) {
|
|
13625
|
+
if (values.length === 0)
|
|
13626
|
+
return "1=0";
|
|
13627
|
+
params.push(...values.map((v) => v.toLowerCase()));
|
|
13628
|
+
return `LOWER(${column}) IN (${values.map(() => "?").join(",")})`;
|
|
13629
|
+
}
|
|
13574
13630
|
function listTasks(filter = {}, db) {
|
|
13575
13631
|
const d = db || getDatabase();
|
|
13576
13632
|
const { clearExpiredLocks: clearExpiredLocks2 } = (init_database(), __toCommonJS(exports_database));
|
|
@@ -13612,8 +13668,7 @@ function listTasks(filter = {}, db) {
|
|
|
13612
13668
|
}
|
|
13613
13669
|
}
|
|
13614
13670
|
if (filter.assigned_to) {
|
|
13615
|
-
conditions.push("assigned_to
|
|
13616
|
-
params.push(filter.assigned_to);
|
|
13671
|
+
conditions.push(lowerInClause("assigned_to", resolveAssignedToAliases(d, filter.assigned_to), params));
|
|
13617
13672
|
}
|
|
13618
13673
|
if (filter.agent_id) {
|
|
13619
13674
|
conditions.push("agent_id = ?");
|
|
@@ -13773,8 +13828,7 @@ function countTasks(filter = {}, db) {
|
|
|
13773
13828
|
}
|
|
13774
13829
|
}
|
|
13775
13830
|
if (filter.assigned_to) {
|
|
13776
|
-
conditions.push("assigned_to
|
|
13777
|
-
params.push(filter.assigned_to);
|
|
13831
|
+
conditions.push(lowerInClause("assigned_to", resolveAssignedToAliases(d, filter.assigned_to), params));
|
|
13778
13832
|
}
|
|
13779
13833
|
if (filter.agent_id) {
|
|
13780
13834
|
conditions.push("agent_id = ?");
|
|
@@ -20410,6 +20464,16 @@ function classifyRemoteRequestError(baseUrl, route, error) {
|
|
|
20410
20464
|
if (status === 403) {
|
|
20411
20465
|
throw new Error(`REMOTE_API_FORBIDDEN: configured Todos authority ${baseUrl} denied ${route}; local SQLite fallback is disabled`, { cause: error });
|
|
20412
20466
|
}
|
|
20467
|
+
if (status === 409) {
|
|
20468
|
+
const body = error && typeof error === "object" ? error.body : undefined;
|
|
20469
|
+
if (body && typeof body === "object" && !Array.isArray(body)) {
|
|
20470
|
+
const remoteError = body;
|
|
20471
|
+
if (remoteError.code === "TASK_NOT_STARTABLE" && typeof remoteError.error === "string" && remoteError.error.length > 0) {
|
|
20472
|
+
throw new Error(`${remoteError.code}: ${remoteError.error}`, { cause: error });
|
|
20473
|
+
}
|
|
20474
|
+
}
|
|
20475
|
+
throw error;
|
|
20476
|
+
}
|
|
20413
20477
|
if (typeof status === "number" && status >= 300 && status < 400) {
|
|
20414
20478
|
throw new Error(`REMOTE_API_REDIRECT_REJECTED: configured Todos authority ${baseUrl} redirected ${route}; ` + "authenticated redirects are disabled to prevent credential leakage", { cause: error });
|
|
20415
20479
|
}
|
|
@@ -20607,7 +20671,10 @@ function resolveCloudProjectRef(projects, ref) {
|
|
|
20607
20671
|
if (matches.length > 1)
|
|
20608
20672
|
throw new Error(`Project reference is ambiguous: "${input}"`);
|
|
20609
20673
|
}
|
|
20610
|
-
|
|
20674
|
+
if (UUID_RE.test(input) || /^[0-9a-f]{4,}$/i.test(input)) {
|
|
20675
|
+
throw new Error(`Project not found: "${input}"`);
|
|
20676
|
+
}
|
|
20677
|
+
throw new Error(`Project not found: "${input}" \u2014 no project in todos's own project registry matches this ` + `name, path, or slug. This does not know about projects registered elsewhere (for example ` + `a Hasna Projects CLI workspace) \u2014 resolve it there first (e.g. "projects show ${input} ` + `--json") and pass the resulting id or task-list slug, or run "todos projects create" to ` + `register it here. Do not assume "${input}" has never been created.`);
|
|
20611
20678
|
}
|
|
20612
20679
|
async function cloudResolveProjectRef(client, ref) {
|
|
20613
20680
|
return resolveCloudProjectRef(await cloudListProjects(client), ref);
|
|
@@ -34775,7 +34842,7 @@ var package_default;
|
|
|
34775
34842
|
var init_package = __esm(() => {
|
|
34776
34843
|
package_default = {
|
|
34777
34844
|
name: "@hasna/todos",
|
|
34778
|
-
version: "0.13.
|
|
34845
|
+
version: "0.13.10",
|
|
34779
34846
|
description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
|
|
34780
34847
|
type: "module",
|
|
34781
34848
|
main: "dist/index.js",
|
|
@@ -34825,8 +34892,8 @@ var init_package = __esm(() => {
|
|
|
34825
34892
|
"README.md"
|
|
34826
34893
|
],
|
|
34827
34894
|
scripts: {
|
|
34828
|
-
build: "rm -rf dist dashboard/dist && cd dashboard && bun install --frozen-lockfile && bun run build && cd .. && bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/server/index.ts --outdir dist/server --target bun
|
|
34829
|
-
"build:server": "rm -rf dist && bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/server/index.ts --outdir dist/server --target bun
|
|
34895
|
+
build: "rm -rf dist dashboard/dist && cd dashboard && bun install --frozen-lockfile && bun run build && cd .. && bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/server/index.ts --outdir dist/server --target bun && bun build src/sdk/index.ts --outdir dist/sdk --target bun --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/index.ts src/mcp.ts src/registry.ts src/contracts.ts src/storage.ts src/testing.ts --outdir dist --target bun --external '@hasna/contracts' --external '@hasna/contracts/*' && tsc --emitDeclarationOnly --outDir dist",
|
|
34896
|
+
"build:server": "rm -rf dist && bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/server/index.ts --outdir dist/server --target bun && bun build src/sdk/index.ts --outdir dist/sdk --target bun --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/index.ts src/mcp.ts src/registry.ts src/contracts.ts src/storage.ts src/testing.ts --outdir dist --target bun --external '@hasna/contracts' --external '@hasna/contracts/*'",
|
|
34830
34897
|
migrate: "bun run src/server/index.ts migrate",
|
|
34831
34898
|
"backfill:comment-redaction": "bun run src/server/index.ts redact-comments",
|
|
34832
34899
|
"generate:sdk": "bun run scripts/generate-sdk.ts",
|
|
@@ -45719,7 +45786,16 @@ class PostgresJsonRecordStore {
|
|
|
45719
45786
|
updatedAt: stringValue2(row.updated_at) ?? new Date().toISOString()
|
|
45720
45787
|
}));
|
|
45721
45788
|
}
|
|
45722
|
-
|
|
45789
|
+
async resolveAssignedToAliases(ref) {
|
|
45790
|
+
const agent = await resolveAgentForAssignedFilter(ref, this);
|
|
45791
|
+
const aliases = new Set([ref]);
|
|
45792
|
+
if (agent) {
|
|
45793
|
+
aliases.add(agent.id);
|
|
45794
|
+
aliases.add(agent.name);
|
|
45795
|
+
}
|
|
45796
|
+
return [...aliases];
|
|
45797
|
+
}
|
|
45798
|
+
async buildTaskFilterSql(filter) {
|
|
45723
45799
|
const params = [this.service, "tasks"];
|
|
45724
45800
|
const conds = ["service = $1", "object_type = $2", "deleted_at IS NULL"];
|
|
45725
45801
|
const p = (value) => {
|
|
@@ -45745,8 +45821,10 @@ class PostgresJsonRecordStore {
|
|
|
45745
45821
|
conds.push(inClause("payload->>'status'", toFilterArray(filter.status)));
|
|
45746
45822
|
if (filter.priority !== undefined)
|
|
45747
45823
|
conds.push(inClause("payload->>'priority'", toFilterArray(filter.priority)));
|
|
45748
|
-
if (filter.assigned_to !== undefined)
|
|
45749
|
-
|
|
45824
|
+
if (filter.assigned_to !== undefined) {
|
|
45825
|
+
const aliases = [...new Set((await this.resolveAssignedToAliases(filter.assigned_to)).map((a) => a.toLowerCase()))];
|
|
45826
|
+
conds.push(inClause("LOWER(payload->>'assigned_to')", aliases));
|
|
45827
|
+
}
|
|
45750
45828
|
if (filter.agent_id !== undefined)
|
|
45751
45829
|
conds.push(`payload->>'agent_id' = ${p(filter.agent_id)}`);
|
|
45752
45830
|
if (filter.created_by !== undefined)
|
|
@@ -45780,7 +45858,7 @@ class PostgresJsonRecordStore {
|
|
|
45780
45858
|
}
|
|
45781
45859
|
async listTasks(filter) {
|
|
45782
45860
|
await this.ensureSchema();
|
|
45783
|
-
const { where, params, queryRef } = this.buildTaskFilterSql(filter);
|
|
45861
|
+
const { where, params, queryRef } = await this.buildTaskFilterSql(filter);
|
|
45784
45862
|
const orderBy = queryRef ? `ORDER BY ts_rank_cd(task_search_tsv, websearch_to_tsquery('simple', todos_immutable_unaccent(${queryRef}))) DESC, ${TASK_ORDER_TIEBREAK}` : TASK_ORDER_BY;
|
|
45785
45863
|
let sql = `/* todos:list-tasks */ SELECT payload FROM ${this.tableName} WHERE ${where} ${orderBy}`;
|
|
45786
45864
|
if (filter.limit !== undefined) {
|
|
@@ -45840,7 +45918,7 @@ class PostgresJsonRecordStore {
|
|
|
45840
45918
|
}
|
|
45841
45919
|
async countTasks(filter) {
|
|
45842
45920
|
await this.ensureSchema();
|
|
45843
|
-
const { where, params } = this.buildTaskFilterSql(filter);
|
|
45921
|
+
const { where, params } = await this.buildTaskFilterSql(filter);
|
|
45844
45922
|
const sql = `/* todos:count-tasks */ SELECT COUNT(*)::int AS count FROM ${this.tableName} WHERE ${where}`;
|
|
45845
45923
|
const result = await this.options.client.query(sql, params);
|
|
45846
45924
|
return Number(result.rows[0]?.count ?? 0);
|
|
@@ -46001,9 +46079,13 @@ class PostgresJsonRecordStore {
|
|
|
46001
46079
|
} : {};
|
|
46002
46080
|
const hasEvidence = Object.keys(evidence).length > 0;
|
|
46003
46081
|
const hasConfidence = options?.confidence !== undefined;
|
|
46004
|
-
const
|
|
46082
|
+
const lockExpiryCutoff2 = new Date(new Date(operationTimestamp).getTime() - CLOUD_LOCK_EXPIRY_MINUTES * 60 * 1000).toISOString();
|
|
46083
|
+
const result = await this.options.client.query(`/* todos:complete-task-atomic todos:complete-task-lock-guard todos:complete-task-clears-lock */
|
|
46084
|
+
UPDATE ${this.tableName}
|
|
46005
46085
|
SET payload = payload || jsonb_build_object(
|
|
46006
46086
|
'status', 'completed',
|
|
46087
|
+
'locked_by', 'null'::jsonb,
|
|
46088
|
+
'locked_at', 'null'::jsonb,
|
|
46007
46089
|
'assigned_to', CASE
|
|
46008
46090
|
WHEN jsonb_typeof(payload->'assigned_to') = 'string' THEN payload->'assigned_to'
|
|
46009
46091
|
ELSE COALESCE(to_jsonb($3::text), 'null'::jsonb)
|
|
@@ -46031,6 +46113,16 @@ class PostgresJsonRecordStore {
|
|
|
46031
46113
|
updated_at = $9::timestamptz,
|
|
46032
46114
|
version = COALESCE(version, 0) + 1
|
|
46033
46115
|
WHERE service = $1 AND object_type = 'tasks' AND object_id = $2 AND deleted_at IS NULL
|
|
46116
|
+
AND (
|
|
46117
|
+
payload->>'locked_by' IS NULL
|
|
46118
|
+
OR BTRIM(payload->>'locked_by') = ''
|
|
46119
|
+
OR payload->>'locked_at' IS NULL
|
|
46120
|
+
OR payload->>'locked_at' < $10::text
|
|
46121
|
+
OR (
|
|
46122
|
+
$3::text IS NOT NULL
|
|
46123
|
+
AND LOWER(BTRIM(payload->>'locked_by')) = LOWER(BTRIM($3::text))
|
|
46124
|
+
)
|
|
46125
|
+
)
|
|
46034
46126
|
RETURNING payload`, [
|
|
46035
46127
|
this.service,
|
|
46036
46128
|
id,
|
|
@@ -46040,7 +46132,8 @@ class PostgresJsonRecordStore {
|
|
|
46040
46132
|
jsonbParam(evidence),
|
|
46041
46133
|
hasConfidence,
|
|
46042
46134
|
options?.confidence ?? null,
|
|
46043
|
-
operationTimestamp
|
|
46135
|
+
operationTimestamp,
|
|
46136
|
+
lockExpiryCutoff2
|
|
46044
46137
|
]);
|
|
46045
46138
|
return result.rows[0] ? payloadRecord2(result.rows[0].payload) : null;
|
|
46046
46139
|
}
|
|
@@ -46321,6 +46414,7 @@ async function updateTask2(id, input, store) {
|
|
|
46321
46414
|
if (existing.version !== input.version) {
|
|
46322
46415
|
throw new Error(`Task ${id} version conflict: expected ${existing.version}, got ${input.version}`);
|
|
46323
46416
|
}
|
|
46417
|
+
const reopened = existing.status === "completed" && input.status !== undefined && input.status !== "completed" && input.completed_at === undefined;
|
|
46324
46418
|
const task2 = {
|
|
46325
46419
|
...existing,
|
|
46326
46420
|
...definedPatch(input),
|
|
@@ -46330,7 +46424,8 @@ async function updateTask2(id, input, store) {
|
|
|
46330
46424
|
metadata: input.metadata ?? existing.metadata,
|
|
46331
46425
|
requires_approval: input.requires_approval ?? existing.requires_approval,
|
|
46332
46426
|
task_list_id: input.task_list_id !== undefined ? input.task_list_id : existing.task_list_id,
|
|
46333
|
-
created_by: existing.created_by
|
|
46427
|
+
created_by: existing.created_by,
|
|
46428
|
+
completed_at: reopened ? null : input.completed_at !== undefined ? input.completed_at : existing.completed_at
|
|
46334
46429
|
};
|
|
46335
46430
|
await store.upsert("tasks", task2);
|
|
46336
46431
|
return task2;
|
|
@@ -46338,11 +46433,11 @@ async function updateTask2(id, input, store) {
|
|
|
46338
46433
|
async function startTask2(id, agentId, store) {
|
|
46339
46434
|
const task2 = await requireRecord("tasks", id, store);
|
|
46340
46435
|
if (task2.status !== "pending" && task2.status !== "in_progress") {
|
|
46341
|
-
throw new
|
|
46436
|
+
throw new TaskNotStartableError(task2.id, task2.status, agentId);
|
|
46342
46437
|
}
|
|
46343
46438
|
const started = await patchTask(task2, {
|
|
46344
46439
|
status: "in_progress",
|
|
46345
|
-
assigned_to: task2.assigned_to
|
|
46440
|
+
assigned_to: task2.assigned_to || agentId,
|
|
46346
46441
|
agent_id: task2.agent_id ?? agentId,
|
|
46347
46442
|
locked_by: agentId,
|
|
46348
46443
|
locked_at: new Date().toISOString(),
|
|
@@ -46353,8 +46448,13 @@ async function startTask2(id, agentId, store) {
|
|
|
46353
46448
|
}
|
|
46354
46449
|
async function completeTask2(id, agentId, options, store) {
|
|
46355
46450
|
const task2 = await store.completeTask(id, agentId, options);
|
|
46356
|
-
if (!task2)
|
|
46451
|
+
if (!task2) {
|
|
46452
|
+
const current = await store.get("tasks", id);
|
|
46453
|
+
if (current?.locked_by && !cloudLockExpired(current.locked_at) && !sameCloudLockHolder(current.locked_by, agentId)) {
|
|
46454
|
+
throw new LockError(id, current.locked_by);
|
|
46455
|
+
}
|
|
46357
46456
|
throw new Error(`tasks record not found: ${id}`);
|
|
46457
|
+
}
|
|
46358
46458
|
return task2;
|
|
46359
46459
|
}
|
|
46360
46460
|
async function failTask2(id, agentId, reason, options, store) {
|
|
@@ -46395,6 +46495,11 @@ async function patchTask(task2, patch, store) {
|
|
|
46395
46495
|
await store.upsert("tasks", updated);
|
|
46396
46496
|
return updated;
|
|
46397
46497
|
}
|
|
46498
|
+
function sameCloudLockHolder(stored, incoming) {
|
|
46499
|
+
if (!stored || !incoming)
|
|
46500
|
+
return false;
|
|
46501
|
+
return canonicalAgentRef(stored) === canonicalAgentRef(incoming);
|
|
46502
|
+
}
|
|
46398
46503
|
function cloudLockExpired(lockedAt) {
|
|
46399
46504
|
if (!lockedAt)
|
|
46400
46505
|
return true;
|
|
@@ -46712,6 +46817,16 @@ async function resolveAgent3(idOrName, store) {
|
|
|
46712
46817
|
return byId;
|
|
46713
46818
|
return matchAgentByName(await store.list("agents"), idOrName);
|
|
46714
46819
|
}
|
|
46820
|
+
async function resolveAgentForAssignedFilter(idOrName, store) {
|
|
46821
|
+
const byId = await store.get("agents", idOrName);
|
|
46822
|
+
if (byId)
|
|
46823
|
+
return byId;
|
|
46824
|
+
const target = normalizeAgentNameInput(idOrName);
|
|
46825
|
+
if (!target)
|
|
46826
|
+
return null;
|
|
46827
|
+
const matches = (await store.list("agents")).filter((agent) => normalizeAgentNameInput(agent.name) === target);
|
|
46828
|
+
return matches.length === 1 ? matches[0] : null;
|
|
46829
|
+
}
|
|
46715
46830
|
async function heartbeatAgent(idOrName, store, context) {
|
|
46716
46831
|
const agent = await resolveAgent3(idOrName, store);
|
|
46717
46832
|
if (!agent)
|
|
@@ -47027,6 +47142,7 @@ function postgresConstraintName(error) {
|
|
|
47027
47142
|
var CLOUD_LOCK_EXPIRY_MINUTES = 30, TASK_ORDER_TIEBREAK = "CASE payload->>'priority' WHEN 'critical' THEN 0 WHEN 'high' THEN 1 WHEN 'medium' THEN 2 WHEN 'low' THEN 3 ELSE 4 END ASC, payload->>'created_at' ASC, payload->>'id' ASC", TASK_ORDER_BY;
|
|
47028
47143
|
var init_postgres_adapter = __esm(() => {
|
|
47029
47144
|
init_types();
|
|
47145
|
+
init_creator_identity();
|
|
47030
47146
|
init_postgres_sync();
|
|
47031
47147
|
init_integrity();
|
|
47032
47148
|
init_redaction();
|
|
@@ -48048,7 +48164,10 @@ function mapTaskError(e, json2) {
|
|
|
48048
48164
|
retry_after: e.retryAfterSeconds ?? null
|
|
48049
48165
|
}, 409);
|
|
48050
48166
|
}
|
|
48051
|
-
if (e instanceof
|
|
48167
|
+
if (e instanceof TaskNotStartableError) {
|
|
48168
|
+
return json2({ error: e.message, code: TaskNotStartableError.code }, 409);
|
|
48169
|
+
}
|
|
48170
|
+
if (e instanceof Error && / is blocked by /.test(e.message)) {
|
|
48052
48171
|
return json2({ error: e.message, code: "TASK_NOT_STARTABLE" }, 409);
|
|
48053
48172
|
}
|
|
48054
48173
|
return null;
|
|
@@ -51111,10 +51230,10 @@ async function handleV1Request(req, url, dependencies = {}) {
|
|
|
51111
51230
|
const released2 = await store.tasks.unlock(id);
|
|
51112
51231
|
return json3({ success: released2 });
|
|
51113
51232
|
}
|
|
51114
|
-
if (body2.agent_id &&
|
|
51233
|
+
if (body2.agent_id && body2.agent_id !== principal.agent && !principal.scopes.includes("todos:*")) {
|
|
51115
51234
|
return error(403, "unlock agent_id must match the authenticated agent");
|
|
51116
51235
|
}
|
|
51117
|
-
const agentId2 =
|
|
51236
|
+
const agentId2 = body2.agent_id || principal.agent;
|
|
51118
51237
|
if (!agentId2)
|
|
51119
51238
|
return error(403, "unlock requires an agent-bound key or force=true");
|
|
51120
51239
|
const released = await store.tasks.unlock(id, agentId2);
|
|
@@ -51682,6 +51801,9 @@ async function handleV1Request(req, url, dependencies = {}) {
|
|
|
51682
51801
|
}
|
|
51683
51802
|
if (e instanceof LockError)
|
|
51684
51803
|
return error(409, e.message, { code: LockError.code });
|
|
51804
|
+
if (e instanceof TaskNotStartableError) {
|
|
51805
|
+
return error(409, e.message, { code: TaskNotStartableError.code });
|
|
51806
|
+
}
|
|
51685
51807
|
if (e instanceof ResourceConflictError)
|
|
51686
51808
|
return error(409, e.message, { code: e.code, conflict: true });
|
|
51687
51809
|
if (e instanceof ProjectNotFoundError)
|
|
@@ -52508,6 +52630,8 @@ var init_serve = __esm(() => {
|
|
|
52508
52630
|
// src/mcp/index.ts
|
|
52509
52631
|
var exports_mcp = {};
|
|
52510
52632
|
__export(exports_mcp, {
|
|
52633
|
+
formatTaskDetail: () => formatTaskDetail,
|
|
52634
|
+
formatTask: () => formatTask,
|
|
52511
52635
|
buildServer: () => buildServer,
|
|
52512
52636
|
applyFocus: () => applyFocus
|
|
52513
52637
|
});
|
|
@@ -52656,7 +52780,8 @@ function resolveId(partialId, table = "tasks") {
|
|
|
52656
52780
|
function formatTask(task2) {
|
|
52657
52781
|
const id = task2.short_id || task2.id.slice(0, 8);
|
|
52658
52782
|
const assigned = task2.assigned_to ? ` -> ${task2.assigned_to}` : "";
|
|
52659
|
-
const
|
|
52783
|
+
const lockState = lockDisplayState(task2.locked_by, task2.locked_at);
|
|
52784
|
+
const lock = lockState.held ? ` [locked:${lockState.holder}]` : "";
|
|
52660
52785
|
const recur = task2.recurrence_rule ? ` [\u21BB]` : "";
|
|
52661
52786
|
return `${id} ${task2.status.padEnd(11)} ${task2.priority.padEnd(8)} ${task2.title}${assigned}${lock}${recur}`;
|
|
52662
52787
|
}
|
|
@@ -52675,8 +52800,11 @@ function formatTaskDetail(task2, maxDescriptionChars) {
|
|
|
52675
52800
|
parts.push(`Assigned to: ${task2.assigned_to}`);
|
|
52676
52801
|
if (task2.agent_id)
|
|
52677
52802
|
parts.push(`Agent: ${task2.agent_id}`);
|
|
52678
|
-
|
|
52679
|
-
|
|
52803
|
+
const detailLock = lockDisplayState(task2.locked_by, task2.locked_at);
|
|
52804
|
+
if (detailLock.held)
|
|
52805
|
+
parts.push(`Locked by: ${detailLock.holder}`);
|
|
52806
|
+
else if (detailLock.expired)
|
|
52807
|
+
parts.push(`Lock: ${formatExpiredLock(detailLock)}`);
|
|
52680
52808
|
if (task2.parent_id)
|
|
52681
52809
|
parts.push(`Parent: ${task2.parent_id}`);
|
|
52682
52810
|
if (task2.project_id)
|
|
@@ -52760,6 +52888,7 @@ var agentFocusMap, isDirectRun;
|
|
|
52760
52888
|
var init_mcp2 = __esm(() => {
|
|
52761
52889
|
init_agents();
|
|
52762
52890
|
init_database();
|
|
52891
|
+
init_lock_display();
|
|
52763
52892
|
init_types();
|
|
52764
52893
|
init_dispatch2();
|
|
52765
52894
|
init_task_crud2();
|
|
@@ -52802,6 +52931,8 @@ var init_mcp2 = __esm(() => {
|
|
|
52802
52931
|
init_mcp2();
|
|
52803
52932
|
|
|
52804
52933
|
export {
|
|
52934
|
+
formatTaskDetail,
|
|
52935
|
+
formatTask,
|
|
52805
52936
|
buildServer,
|
|
52806
52937
|
applyFocus
|
|
52807
52938
|
};
|
package/dist/mcp.js
CHANGED
|
@@ -41,7 +41,7 @@ var __require = import.meta.require;
|
|
|
41
41
|
// package.json
|
|
42
42
|
var package_default = {
|
|
43
43
|
name: "@hasna/todos",
|
|
44
|
-
version: "0.13.
|
|
44
|
+
version: "0.13.10",
|
|
45
45
|
description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
|
|
46
46
|
type: "module",
|
|
47
47
|
main: "dist/index.js",
|
|
@@ -91,8 +91,8 @@ var package_default = {
|
|
|
91
91
|
"README.md"
|
|
92
92
|
],
|
|
93
93
|
scripts: {
|
|
94
|
-
build: "rm -rf dist dashboard/dist && cd dashboard && bun install --frozen-lockfile && bun run build && cd .. && bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/server/index.ts --outdir dist/server --target bun
|
|
95
|
-
"build:server": "rm -rf dist && bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/server/index.ts --outdir dist/server --target bun
|
|
94
|
+
build: "rm -rf dist dashboard/dist && cd dashboard && bun install --frozen-lockfile && bun run build && cd .. && bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/server/index.ts --outdir dist/server --target bun && bun build src/sdk/index.ts --outdir dist/sdk --target bun --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/index.ts src/mcp.ts src/registry.ts src/contracts.ts src/storage.ts src/testing.ts --outdir dist --target bun --external '@hasna/contracts' --external '@hasna/contracts/*' && tsc --emitDeclarationOnly --outDir dist",
|
|
95
|
+
"build:server": "rm -rf dist && bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/server/index.ts --outdir dist/server --target bun && bun build src/sdk/index.ts --outdir dist/sdk --target bun --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/index.ts src/mcp.ts src/registry.ts src/contracts.ts src/storage.ts src/testing.ts --outdir dist --target bun --external '@hasna/contracts' --external '@hasna/contracts/*'",
|
|
96
96
|
migrate: "bun run src/server/index.ts migrate",
|
|
97
97
|
"backfill:comment-redaction": "bun run src/server/index.ts redact-comments",
|
|
98
98
|
"generate:sdk": "bun run scripts/generate-sdk.ts",
|
package/dist/registry.js
CHANGED
|
@@ -3430,7 +3430,7 @@ var init_machines = __esm(() => {
|
|
|
3430
3430
|
function isBlockingDependencyStatus(status) {
|
|
3431
3431
|
return status !== "completed" && status !== "cancelled";
|
|
3432
3432
|
}
|
|
3433
|
-
var TASK_STATUSES, TASK_PRIORITIES, PLAN_STATUSES, VersionConflictError, TaskNotFoundError, TaskReferenceAmbiguousError, ProjectNotFoundError, ResourceConflictError, PlanNotFoundError, LockError, AgentNotFoundError, IdentityAliasAmbiguousError, IdentityIdImmutableError, TaskListNotFoundError, DependencyCycleError, CompletionGuardError, DISPATCH_STATUSES, DispatchNotFoundError;
|
|
3433
|
+
var TASK_STATUSES, TASK_PRIORITIES, PLAN_STATUSES, VersionConflictError, TaskNotFoundError, TaskNotStartableError, TaskReferenceAmbiguousError, ProjectNotFoundError, ResourceConflictError, PlanNotFoundError, LockError, AgentNotFoundError, IdentityAliasAmbiguousError, IdentityIdImmutableError, TaskListNotFoundError, DependencyCycleError, CompletionGuardError, DISPATCH_STATUSES, DispatchNotFoundError;
|
|
3434
3434
|
var init_types = __esm(() => {
|
|
3435
3435
|
TASK_STATUSES = [
|
|
3436
3436
|
"pending",
|
|
@@ -3470,6 +3470,20 @@ var init_types = __esm(() => {
|
|
|
3470
3470
|
this.name = "TaskNotFoundError";
|
|
3471
3471
|
}
|
|
3472
3472
|
};
|
|
3473
|
+
TaskNotStartableError = class TaskNotStartableError extends Error {
|
|
3474
|
+
taskId;
|
|
3475
|
+
status;
|
|
3476
|
+
agentId;
|
|
3477
|
+
static code = "TASK_NOT_STARTABLE";
|
|
3478
|
+
static suggestion = "Reset the task status to pending before starting it again.";
|
|
3479
|
+
constructor(taskId, status, agentId) {
|
|
3480
|
+
super(`Task ${taskId} is ${status} and cannot be started by ${agentId}; ` + "reset the task status to pending before starting it again");
|
|
3481
|
+
this.taskId = taskId;
|
|
3482
|
+
this.status = status;
|
|
3483
|
+
this.agentId = agentId;
|
|
3484
|
+
this.name = "TaskNotStartableError";
|
|
3485
|
+
}
|
|
3486
|
+
};
|
|
3473
3487
|
TaskReferenceAmbiguousError = class TaskReferenceAmbiguousError extends Error {
|
|
3474
3488
|
reference;
|
|
3475
3489
|
static code = "TASK_REFERENCE_AMBIGUOUS";
|
|
@@ -8242,7 +8256,7 @@ function assertStartable(task, agentId) {
|
|
|
8242
8256
|
return;
|
|
8243
8257
|
if (task.status === "in_progress")
|
|
8244
8258
|
return;
|
|
8245
|
-
throw new
|
|
8259
|
+
throw new TaskNotStartableError(task.id, task.status, agentId);
|
|
8246
8260
|
}
|
|
8247
8261
|
function getBlockingDeps(id, db) {
|
|
8248
8262
|
const d = db || getDatabase();
|
|
@@ -8313,7 +8327,7 @@ function completeTask(id, agentId, db, options) {
|
|
|
8313
8327
|
if (task.status === "cancelled") {
|
|
8314
8328
|
throw new Error(`Task ${id} is cancelled and cannot be completed`);
|
|
8315
8329
|
}
|
|
8316
|
-
if (
|
|
8330
|
+
if (task.locked_by && !sameHolder(task.locked_by, agentId) && !isLockExpired(task.locked_at)) {
|
|
8317
8331
|
throw new LockError(id, task.locked_by);
|
|
8318
8332
|
}
|
|
8319
8333
|
checkCompletionGuard(task, agentId || null, d);
|
|
@@ -8948,6 +8962,30 @@ function getTaskWithRelations(id, db) {
|
|
|
8948
8962
|
checklist
|
|
8949
8963
|
};
|
|
8950
8964
|
}
|
|
8965
|
+
function resolveAssignedToAliases(db, ref) {
|
|
8966
|
+
const aliases = new Set([ref]);
|
|
8967
|
+
let agentId;
|
|
8968
|
+
try {
|
|
8969
|
+
agentId = resolvePartialId(db, "agents", ref);
|
|
8970
|
+
} catch (err) {
|
|
8971
|
+
if (!(err instanceof IdentityAliasAmbiguousError))
|
|
8972
|
+
throw err;
|
|
8973
|
+
agentId = null;
|
|
8974
|
+
}
|
|
8975
|
+
if (agentId) {
|
|
8976
|
+
aliases.add(agentId);
|
|
8977
|
+
const row = db.query("SELECT name FROM agents WHERE id = ?").get(agentId);
|
|
8978
|
+
if (row?.name)
|
|
8979
|
+
aliases.add(row.name);
|
|
8980
|
+
}
|
|
8981
|
+
return [...aliases];
|
|
8982
|
+
}
|
|
8983
|
+
function lowerInClause(column, values, params) {
|
|
8984
|
+
if (values.length === 0)
|
|
8985
|
+
return "1=0";
|
|
8986
|
+
params.push(...values.map((v) => v.toLowerCase()));
|
|
8987
|
+
return `LOWER(${column}) IN (${values.map(() => "?").join(",")})`;
|
|
8988
|
+
}
|
|
8951
8989
|
function listTasks(filter = {}, db) {
|
|
8952
8990
|
const d = db || getDatabase();
|
|
8953
8991
|
const { clearExpiredLocks: clearExpiredLocks2 } = (init_database(), __toCommonJS(exports_database));
|
|
@@ -8989,8 +9027,7 @@ function listTasks(filter = {}, db) {
|
|
|
8989
9027
|
}
|
|
8990
9028
|
}
|
|
8991
9029
|
if (filter.assigned_to) {
|
|
8992
|
-
conditions.push("assigned_to
|
|
8993
|
-
params.push(filter.assigned_to);
|
|
9030
|
+
conditions.push(lowerInClause("assigned_to", resolveAssignedToAliases(d, filter.assigned_to), params));
|
|
8994
9031
|
}
|
|
8995
9032
|
if (filter.agent_id) {
|
|
8996
9033
|
conditions.push("agent_id = ?");
|
|
@@ -9150,8 +9187,7 @@ function countTasks(filter = {}, db) {
|
|
|
9150
9187
|
}
|
|
9151
9188
|
}
|
|
9152
9189
|
if (filter.assigned_to) {
|
|
9153
|
-
conditions.push("assigned_to
|
|
9154
|
-
params.push(filter.assigned_to);
|
|
9190
|
+
conditions.push(lowerInClause("assigned_to", resolveAssignedToAliases(d, filter.assigned_to), params));
|
|
9155
9191
|
}
|
|
9156
9192
|
if (filter.agent_id) {
|
|
9157
9193
|
conditions.push("agent_id = ?");
|
|
@@ -11973,7 +12009,7 @@ var init_tasks = __esm(() => {
|
|
|
11973
12009
|
// package.json
|
|
11974
12010
|
var package_default = {
|
|
11975
12011
|
name: "@hasna/todos",
|
|
11976
|
-
version: "0.13.
|
|
12012
|
+
version: "0.13.10",
|
|
11977
12013
|
description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
|
|
11978
12014
|
type: "module",
|
|
11979
12015
|
main: "dist/index.js",
|
|
@@ -12023,8 +12059,8 @@ var package_default = {
|
|
|
12023
12059
|
"README.md"
|
|
12024
12060
|
],
|
|
12025
12061
|
scripts: {
|
|
12026
|
-
build: "rm -rf dist dashboard/dist && cd dashboard && bun install --frozen-lockfile && bun run build && cd .. && bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/server/index.ts --outdir dist/server --target bun
|
|
12027
|
-
"build:server": "rm -rf dist && bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/server/index.ts --outdir dist/server --target bun
|
|
12062
|
+
build: "rm -rf dist dashboard/dist && cd dashboard && bun install --frozen-lockfile && bun run build && cd .. && bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/server/index.ts --outdir dist/server --target bun && bun build src/sdk/index.ts --outdir dist/sdk --target bun --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/index.ts src/mcp.ts src/registry.ts src/contracts.ts src/storage.ts src/testing.ts --outdir dist --target bun --external '@hasna/contracts' --external '@hasna/contracts/*' && tsc --emitDeclarationOnly --outDir dist",
|
|
12063
|
+
"build:server": "rm -rf dist && bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/server/index.ts --outdir dist/server --target bun && bun build src/sdk/index.ts --outdir dist/sdk --target bun --external '@hasna/contracts' --external '@hasna/contracts/*' && bun build src/index.ts src/mcp.ts src/registry.ts src/contracts.ts src/storage.ts src/testing.ts --outdir dist --target bun --external '@hasna/contracts' --external '@hasna/contracts/*'",
|
|
12028
12064
|
migrate: "bun run src/server/index.ts migrate",
|
|
12029
12065
|
"backfill:comment-redaction": "bun run src/server/index.ts redact-comments",
|
|
12030
12066
|
"generate:sdk": "bun run scripts/generate-sdk.ts",
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"packageName": "@hasna/todos",
|
|
3
|
-
"packageVersion": "0.13.
|
|
3
|
+
"packageVersion": "0.13.10",
|
|
4
4
|
"repository": "https://github.com/hasna/todos.git",
|
|
5
|
-
"gitCommit": "
|
|
6
|
-
"gitTree": "
|
|
7
|
-
"sourceTreeSha256": "
|
|
8
|
-
"generatedAt": "2026-08-
|
|
5
|
+
"gitCommit": "caef21b58b4e8d4cd7996e57bc922504c98ddee9",
|
|
6
|
+
"gitTree": "574134d0b7552948e8f31013b4b247fd8ec6d187",
|
|
7
|
+
"sourceTreeSha256": "eca04b82f06e0d20a8f744e7efc9091afa1f0606b4899d473ee1c44e0966769c",
|
|
8
|
+
"generatedAt": "2026-08-02T04:51:15.000Z"
|
|
9
9
|
}
|