@hasna/todos 0.13.9 → 0.13.11
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/assignee-guard.d.ts +8 -1
- package/dist/cli/assignee-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/query-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 +224 -50
- 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/assignee-validation.d.ts +22 -0
- package/dist/lib/assignee-validation.d.ts.map +1 -1
- 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 -27
- package/dist/mcp.js +3 -3
- package/dist/registry.js +46 -10
- package/dist/release-provenance.json +5 -5
- package/dist/server/index.js +14015 -1225
- 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 = ?");
|
|
@@ -17958,10 +18012,11 @@ function validateAssignee(input, ctx) {
|
|
|
17958
18012
|
if (ctx.allowSeat) {
|
|
17959
18013
|
return { ok: true, assignee: byId ? byId.name : raw, agentId: byId?.id, isSeat: true };
|
|
17960
18014
|
}
|
|
18015
|
+
const hint = ctx.seatHint?.(raw);
|
|
17961
18016
|
return {
|
|
17962
18017
|
ok: false,
|
|
17963
18018
|
reason: "seat",
|
|
17964
|
-
message: `'${raw}' is a durable SEAT, and a task assigned to a seat is assigned to nobody \u2014 no session is watching that queue. ` + `Assign a specific agent, use --unassigned to file it with no owner on purpose, or
|
|
18019
|
+
message: `'${raw}' is a durable SEAT, and a task assigned to a seat is assigned to nobody \u2014 no session is watching that queue. ` + `Assign a specific agent, use --unassigned to file it with no owner on purpose, or repeat the command with --assign-seat added to confirm the seat is deliberate` + (hint ? `: ${hint}` : " (see --help for this command's exact form).")
|
|
17965
18020
|
};
|
|
17966
18021
|
}
|
|
17967
18022
|
if (byId) {
|
|
@@ -20410,6 +20465,16 @@ function classifyRemoteRequestError(baseUrl, route, error) {
|
|
|
20410
20465
|
if (status === 403) {
|
|
20411
20466
|
throw new Error(`REMOTE_API_FORBIDDEN: configured Todos authority ${baseUrl} denied ${route}; local SQLite fallback is disabled`, { cause: error });
|
|
20412
20467
|
}
|
|
20468
|
+
if (status === 409) {
|
|
20469
|
+
const body = error && typeof error === "object" ? error.body : undefined;
|
|
20470
|
+
if (body && typeof body === "object" && !Array.isArray(body)) {
|
|
20471
|
+
const remoteError = body;
|
|
20472
|
+
if (remoteError.code === "TASK_NOT_STARTABLE" && typeof remoteError.error === "string" && remoteError.error.length > 0) {
|
|
20473
|
+
throw new Error(`${remoteError.code}: ${remoteError.error}`, { cause: error });
|
|
20474
|
+
}
|
|
20475
|
+
}
|
|
20476
|
+
throw error;
|
|
20477
|
+
}
|
|
20413
20478
|
if (typeof status === "number" && status >= 300 && status < 400) {
|
|
20414
20479
|
throw new Error(`REMOTE_API_REDIRECT_REJECTED: configured Todos authority ${baseUrl} redirected ${route}; ` + "authenticated redirects are disabled to prevent credential leakage", { cause: error });
|
|
20415
20480
|
}
|
|
@@ -20607,7 +20672,10 @@ function resolveCloudProjectRef(projects, ref) {
|
|
|
20607
20672
|
if (matches.length > 1)
|
|
20608
20673
|
throw new Error(`Project reference is ambiguous: "${input}"`);
|
|
20609
20674
|
}
|
|
20610
|
-
|
|
20675
|
+
if (UUID_RE.test(input) || /^[0-9a-f]{4,}$/i.test(input)) {
|
|
20676
|
+
throw new Error(`Project not found: "${input}"`);
|
|
20677
|
+
}
|
|
20678
|
+
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
20679
|
}
|
|
20612
20680
|
async function cloudResolveProjectRef(client, ref) {
|
|
20613
20681
|
return resolveCloudProjectRef(await cloudListProjects(client), ref);
|
|
@@ -34775,7 +34843,7 @@ var package_default;
|
|
|
34775
34843
|
var init_package = __esm(() => {
|
|
34776
34844
|
package_default = {
|
|
34777
34845
|
name: "@hasna/todos",
|
|
34778
|
-
version: "0.13.
|
|
34846
|
+
version: "0.13.11",
|
|
34779
34847
|
description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
|
|
34780
34848
|
type: "module",
|
|
34781
34849
|
main: "dist/index.js",
|
|
@@ -34825,8 +34893,8 @@ var init_package = __esm(() => {
|
|
|
34825
34893
|
"README.md"
|
|
34826
34894
|
],
|
|
34827
34895
|
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
|
|
34896
|
+
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",
|
|
34897
|
+
"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
34898
|
migrate: "bun run src/server/index.ts migrate",
|
|
34831
34899
|
"backfill:comment-redaction": "bun run src/server/index.ts redact-comments",
|
|
34832
34900
|
"generate:sdk": "bun run scripts/generate-sdk.ts",
|
|
@@ -45719,7 +45787,16 @@ class PostgresJsonRecordStore {
|
|
|
45719
45787
|
updatedAt: stringValue2(row.updated_at) ?? new Date().toISOString()
|
|
45720
45788
|
}));
|
|
45721
45789
|
}
|
|
45722
|
-
|
|
45790
|
+
async resolveAssignedToAliases(ref) {
|
|
45791
|
+
const agent = await resolveAgentForAssignedFilter(ref, this);
|
|
45792
|
+
const aliases = new Set([ref]);
|
|
45793
|
+
if (agent) {
|
|
45794
|
+
aliases.add(agent.id);
|
|
45795
|
+
aliases.add(agent.name);
|
|
45796
|
+
}
|
|
45797
|
+
return [...aliases];
|
|
45798
|
+
}
|
|
45799
|
+
async buildTaskFilterSql(filter) {
|
|
45723
45800
|
const params = [this.service, "tasks"];
|
|
45724
45801
|
const conds = ["service = $1", "object_type = $2", "deleted_at IS NULL"];
|
|
45725
45802
|
const p = (value) => {
|
|
@@ -45745,8 +45822,10 @@ class PostgresJsonRecordStore {
|
|
|
45745
45822
|
conds.push(inClause("payload->>'status'", toFilterArray(filter.status)));
|
|
45746
45823
|
if (filter.priority !== undefined)
|
|
45747
45824
|
conds.push(inClause("payload->>'priority'", toFilterArray(filter.priority)));
|
|
45748
|
-
if (filter.assigned_to !== undefined)
|
|
45749
|
-
|
|
45825
|
+
if (filter.assigned_to !== undefined) {
|
|
45826
|
+
const aliases = [...new Set((await this.resolveAssignedToAliases(filter.assigned_to)).map((a) => a.toLowerCase()))];
|
|
45827
|
+
conds.push(inClause("LOWER(payload->>'assigned_to')", aliases));
|
|
45828
|
+
}
|
|
45750
45829
|
if (filter.agent_id !== undefined)
|
|
45751
45830
|
conds.push(`payload->>'agent_id' = ${p(filter.agent_id)}`);
|
|
45752
45831
|
if (filter.created_by !== undefined)
|
|
@@ -45780,7 +45859,7 @@ class PostgresJsonRecordStore {
|
|
|
45780
45859
|
}
|
|
45781
45860
|
async listTasks(filter) {
|
|
45782
45861
|
await this.ensureSchema();
|
|
45783
|
-
const { where, params, queryRef } = this.buildTaskFilterSql(filter);
|
|
45862
|
+
const { where, params, queryRef } = await this.buildTaskFilterSql(filter);
|
|
45784
45863
|
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
45864
|
let sql = `/* todos:list-tasks */ SELECT payload FROM ${this.tableName} WHERE ${where} ${orderBy}`;
|
|
45786
45865
|
if (filter.limit !== undefined) {
|
|
@@ -45840,7 +45919,7 @@ class PostgresJsonRecordStore {
|
|
|
45840
45919
|
}
|
|
45841
45920
|
async countTasks(filter) {
|
|
45842
45921
|
await this.ensureSchema();
|
|
45843
|
-
const { where, params } = this.buildTaskFilterSql(filter);
|
|
45922
|
+
const { where, params } = await this.buildTaskFilterSql(filter);
|
|
45844
45923
|
const sql = `/* todos:count-tasks */ SELECT COUNT(*)::int AS count FROM ${this.tableName} WHERE ${where}`;
|
|
45845
45924
|
const result = await this.options.client.query(sql, params);
|
|
45846
45925
|
return Number(result.rows[0]?.count ?? 0);
|
|
@@ -46001,9 +46080,13 @@ class PostgresJsonRecordStore {
|
|
|
46001
46080
|
} : {};
|
|
46002
46081
|
const hasEvidence = Object.keys(evidence).length > 0;
|
|
46003
46082
|
const hasConfidence = options?.confidence !== undefined;
|
|
46004
|
-
const
|
|
46083
|
+
const lockExpiryCutoff2 = new Date(new Date(operationTimestamp).getTime() - CLOUD_LOCK_EXPIRY_MINUTES * 60 * 1000).toISOString();
|
|
46084
|
+
const result = await this.options.client.query(`/* todos:complete-task-atomic todos:complete-task-lock-guard todos:complete-task-clears-lock */
|
|
46085
|
+
UPDATE ${this.tableName}
|
|
46005
46086
|
SET payload = payload || jsonb_build_object(
|
|
46006
46087
|
'status', 'completed',
|
|
46088
|
+
'locked_by', 'null'::jsonb,
|
|
46089
|
+
'locked_at', 'null'::jsonb,
|
|
46007
46090
|
'assigned_to', CASE
|
|
46008
46091
|
WHEN jsonb_typeof(payload->'assigned_to') = 'string' THEN payload->'assigned_to'
|
|
46009
46092
|
ELSE COALESCE(to_jsonb($3::text), 'null'::jsonb)
|
|
@@ -46031,6 +46114,16 @@ class PostgresJsonRecordStore {
|
|
|
46031
46114
|
updated_at = $9::timestamptz,
|
|
46032
46115
|
version = COALESCE(version, 0) + 1
|
|
46033
46116
|
WHERE service = $1 AND object_type = 'tasks' AND object_id = $2 AND deleted_at IS NULL
|
|
46117
|
+
AND (
|
|
46118
|
+
payload->>'locked_by' IS NULL
|
|
46119
|
+
OR BTRIM(payload->>'locked_by') = ''
|
|
46120
|
+
OR payload->>'locked_at' IS NULL
|
|
46121
|
+
OR payload->>'locked_at' < $10::text
|
|
46122
|
+
OR (
|
|
46123
|
+
$3::text IS NOT NULL
|
|
46124
|
+
AND LOWER(BTRIM(payload->>'locked_by')) = LOWER(BTRIM($3::text))
|
|
46125
|
+
)
|
|
46126
|
+
)
|
|
46034
46127
|
RETURNING payload`, [
|
|
46035
46128
|
this.service,
|
|
46036
46129
|
id,
|
|
@@ -46040,7 +46133,8 @@ class PostgresJsonRecordStore {
|
|
|
46040
46133
|
jsonbParam(evidence),
|
|
46041
46134
|
hasConfidence,
|
|
46042
46135
|
options?.confidence ?? null,
|
|
46043
|
-
operationTimestamp
|
|
46136
|
+
operationTimestamp,
|
|
46137
|
+
lockExpiryCutoff2
|
|
46044
46138
|
]);
|
|
46045
46139
|
return result.rows[0] ? payloadRecord2(result.rows[0].payload) : null;
|
|
46046
46140
|
}
|
|
@@ -46321,6 +46415,7 @@ async function updateTask2(id, input, store) {
|
|
|
46321
46415
|
if (existing.version !== input.version) {
|
|
46322
46416
|
throw new Error(`Task ${id} version conflict: expected ${existing.version}, got ${input.version}`);
|
|
46323
46417
|
}
|
|
46418
|
+
const reopened = existing.status === "completed" && input.status !== undefined && input.status !== "completed" && input.completed_at === undefined;
|
|
46324
46419
|
const task2 = {
|
|
46325
46420
|
...existing,
|
|
46326
46421
|
...definedPatch(input),
|
|
@@ -46330,7 +46425,8 @@ async function updateTask2(id, input, store) {
|
|
|
46330
46425
|
metadata: input.metadata ?? existing.metadata,
|
|
46331
46426
|
requires_approval: input.requires_approval ?? existing.requires_approval,
|
|
46332
46427
|
task_list_id: input.task_list_id !== undefined ? input.task_list_id : existing.task_list_id,
|
|
46333
|
-
created_by: existing.created_by
|
|
46428
|
+
created_by: existing.created_by,
|
|
46429
|
+
completed_at: reopened ? null : input.completed_at !== undefined ? input.completed_at : existing.completed_at
|
|
46334
46430
|
};
|
|
46335
46431
|
await store.upsert("tasks", task2);
|
|
46336
46432
|
return task2;
|
|
@@ -46338,11 +46434,11 @@ async function updateTask2(id, input, store) {
|
|
|
46338
46434
|
async function startTask2(id, agentId, store) {
|
|
46339
46435
|
const task2 = await requireRecord("tasks", id, store);
|
|
46340
46436
|
if (task2.status !== "pending" && task2.status !== "in_progress") {
|
|
46341
|
-
throw new
|
|
46437
|
+
throw new TaskNotStartableError(task2.id, task2.status, agentId);
|
|
46342
46438
|
}
|
|
46343
46439
|
const started = await patchTask(task2, {
|
|
46344
46440
|
status: "in_progress",
|
|
46345
|
-
assigned_to: task2.assigned_to
|
|
46441
|
+
assigned_to: task2.assigned_to || agentId,
|
|
46346
46442
|
agent_id: task2.agent_id ?? agentId,
|
|
46347
46443
|
locked_by: agentId,
|
|
46348
46444
|
locked_at: new Date().toISOString(),
|
|
@@ -46353,8 +46449,13 @@ async function startTask2(id, agentId, store) {
|
|
|
46353
46449
|
}
|
|
46354
46450
|
async function completeTask2(id, agentId, options, store) {
|
|
46355
46451
|
const task2 = await store.completeTask(id, agentId, options);
|
|
46356
|
-
if (!task2)
|
|
46452
|
+
if (!task2) {
|
|
46453
|
+
const current = await store.get("tasks", id);
|
|
46454
|
+
if (current?.locked_by && !cloudLockExpired(current.locked_at) && !sameCloudLockHolder(current.locked_by, agentId)) {
|
|
46455
|
+
throw new LockError(id, current.locked_by);
|
|
46456
|
+
}
|
|
46357
46457
|
throw new Error(`tasks record not found: ${id}`);
|
|
46458
|
+
}
|
|
46358
46459
|
return task2;
|
|
46359
46460
|
}
|
|
46360
46461
|
async function failTask2(id, agentId, reason, options, store) {
|
|
@@ -46395,6 +46496,11 @@ async function patchTask(task2, patch, store) {
|
|
|
46395
46496
|
await store.upsert("tasks", updated);
|
|
46396
46497
|
return updated;
|
|
46397
46498
|
}
|
|
46499
|
+
function sameCloudLockHolder(stored, incoming) {
|
|
46500
|
+
if (!stored || !incoming)
|
|
46501
|
+
return false;
|
|
46502
|
+
return canonicalAgentRef(stored) === canonicalAgentRef(incoming);
|
|
46503
|
+
}
|
|
46398
46504
|
function cloudLockExpired(lockedAt) {
|
|
46399
46505
|
if (!lockedAt)
|
|
46400
46506
|
return true;
|
|
@@ -46712,6 +46818,16 @@ async function resolveAgent3(idOrName, store) {
|
|
|
46712
46818
|
return byId;
|
|
46713
46819
|
return matchAgentByName(await store.list("agents"), idOrName);
|
|
46714
46820
|
}
|
|
46821
|
+
async function resolveAgentForAssignedFilter(idOrName, store) {
|
|
46822
|
+
const byId = await store.get("agents", idOrName);
|
|
46823
|
+
if (byId)
|
|
46824
|
+
return byId;
|
|
46825
|
+
const target = normalizeAgentNameInput(idOrName);
|
|
46826
|
+
if (!target)
|
|
46827
|
+
return null;
|
|
46828
|
+
const matches = (await store.list("agents")).filter((agent) => normalizeAgentNameInput(agent.name) === target);
|
|
46829
|
+
return matches.length === 1 ? matches[0] : null;
|
|
46830
|
+
}
|
|
46715
46831
|
async function heartbeatAgent(idOrName, store, context) {
|
|
46716
46832
|
const agent = await resolveAgent3(idOrName, store);
|
|
46717
46833
|
if (!agent)
|
|
@@ -47027,6 +47143,7 @@ function postgresConstraintName(error) {
|
|
|
47027
47143
|
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
47144
|
var init_postgres_adapter = __esm(() => {
|
|
47029
47145
|
init_types();
|
|
47146
|
+
init_creator_identity();
|
|
47030
47147
|
init_postgres_sync();
|
|
47031
47148
|
init_integrity();
|
|
47032
47149
|
init_redaction();
|
|
@@ -48048,7 +48165,10 @@ function mapTaskError(e, json2) {
|
|
|
48048
48165
|
retry_after: e.retryAfterSeconds ?? null
|
|
48049
48166
|
}, 409);
|
|
48050
48167
|
}
|
|
48051
|
-
if (e instanceof
|
|
48168
|
+
if (e instanceof TaskNotStartableError) {
|
|
48169
|
+
return json2({ error: e.message, code: TaskNotStartableError.code }, 409);
|
|
48170
|
+
}
|
|
48171
|
+
if (e instanceof Error && / is blocked by /.test(e.message)) {
|
|
48052
48172
|
return json2({ error: e.message, code: "TASK_NOT_STARTABLE" }, 409);
|
|
48053
48173
|
}
|
|
48054
48174
|
return null;
|
|
@@ -51682,6 +51802,9 @@ async function handleV1Request(req, url, dependencies = {}) {
|
|
|
51682
51802
|
}
|
|
51683
51803
|
if (e instanceof LockError)
|
|
51684
51804
|
return error(409, e.message, { code: LockError.code });
|
|
51805
|
+
if (e instanceof TaskNotStartableError) {
|
|
51806
|
+
return error(409, e.message, { code: TaskNotStartableError.code });
|
|
51807
|
+
}
|
|
51685
51808
|
if (e instanceof ResourceConflictError)
|
|
51686
51809
|
return error(409, e.message, { code: e.code, conflict: true });
|
|
51687
51810
|
if (e instanceof ProjectNotFoundError)
|
|
@@ -52508,6 +52631,8 @@ var init_serve = __esm(() => {
|
|
|
52508
52631
|
// src/mcp/index.ts
|
|
52509
52632
|
var exports_mcp = {};
|
|
52510
52633
|
__export(exports_mcp, {
|
|
52634
|
+
formatTaskDetail: () => formatTaskDetail,
|
|
52635
|
+
formatTask: () => formatTask,
|
|
52511
52636
|
buildServer: () => buildServer,
|
|
52512
52637
|
applyFocus: () => applyFocus
|
|
52513
52638
|
});
|
|
@@ -52656,7 +52781,8 @@ function resolveId(partialId, table = "tasks") {
|
|
|
52656
52781
|
function formatTask(task2) {
|
|
52657
52782
|
const id = task2.short_id || task2.id.slice(0, 8);
|
|
52658
52783
|
const assigned = task2.assigned_to ? ` -> ${task2.assigned_to}` : "";
|
|
52659
|
-
const
|
|
52784
|
+
const lockState = lockDisplayState(task2.locked_by, task2.locked_at);
|
|
52785
|
+
const lock = lockState.held ? ` [locked:${lockState.holder}]` : "";
|
|
52660
52786
|
const recur = task2.recurrence_rule ? ` [\u21BB]` : "";
|
|
52661
52787
|
return `${id} ${task2.status.padEnd(11)} ${task2.priority.padEnd(8)} ${task2.title}${assigned}${lock}${recur}`;
|
|
52662
52788
|
}
|
|
@@ -52675,8 +52801,11 @@ function formatTaskDetail(task2, maxDescriptionChars) {
|
|
|
52675
52801
|
parts.push(`Assigned to: ${task2.assigned_to}`);
|
|
52676
52802
|
if (task2.agent_id)
|
|
52677
52803
|
parts.push(`Agent: ${task2.agent_id}`);
|
|
52678
|
-
|
|
52679
|
-
|
|
52804
|
+
const detailLock = lockDisplayState(task2.locked_by, task2.locked_at);
|
|
52805
|
+
if (detailLock.held)
|
|
52806
|
+
parts.push(`Locked by: ${detailLock.holder}`);
|
|
52807
|
+
else if (detailLock.expired)
|
|
52808
|
+
parts.push(`Lock: ${formatExpiredLock(detailLock)}`);
|
|
52680
52809
|
if (task2.parent_id)
|
|
52681
52810
|
parts.push(`Parent: ${task2.parent_id}`);
|
|
52682
52811
|
if (task2.project_id)
|
|
@@ -52760,6 +52889,7 @@ var agentFocusMap, isDirectRun;
|
|
|
52760
52889
|
var init_mcp2 = __esm(() => {
|
|
52761
52890
|
init_agents();
|
|
52762
52891
|
init_database();
|
|
52892
|
+
init_lock_display();
|
|
52763
52893
|
init_types();
|
|
52764
52894
|
init_dispatch2();
|
|
52765
52895
|
init_task_crud2();
|
|
@@ -52802,6 +52932,8 @@ var init_mcp2 = __esm(() => {
|
|
|
52802
52932
|
init_mcp2();
|
|
52803
52933
|
|
|
52804
52934
|
export {
|
|
52935
|
+
formatTaskDetail,
|
|
52936
|
+
formatTask,
|
|
52805
52937
|
buildServer,
|
|
52806
52938
|
applyFocus
|
|
52807
52939
|
};
|
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.11",
|
|
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.11",
|
|
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.11",
|
|
4
4
|
"repository": "https://github.com/hasna/todos.git",
|
|
5
|
-
"gitCommit": "
|
|
6
|
-
"gitTree": "
|
|
7
|
-
"sourceTreeSha256": "
|
|
8
|
-
"generatedAt": "2026-08-
|
|
5
|
+
"gitCommit": "af551bd57da4ef1835d763232c1e3b3b8cee4f9f",
|
|
6
|
+
"gitTree": "23029d1f9a1afeecf519674e13746e615431ae8b",
|
|
7
|
+
"sourceTreeSha256": "b14e57ef9ec0cbd0e0142681b993aa34c941d59a18649ddd499f3ee1a62cfef9",
|
|
8
|
+
"generatedAt": "2026-08-02T06:21:53.000Z"
|
|
9
9
|
}
|