@hasna/todos 0.13.12 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/cli/commands/agent-commands.d.ts +39 -0
- package/dist/cli/commands/agent-commands.d.ts.map +1 -1
- package/dist/cli/commands/config-serve-commands.d.ts.map +1 -1
- package/dist/cli/commands/dispatch.d.ts.map +1 -1
- package/dist/cli/commands/mcp-hooks-commands.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/helpers.d.ts +64 -2
- package/dist/cli/helpers.d.ts.map +1 -1
- package/dist/cli/index.js +624 -98
- package/dist/cli/stage-a.d.ts.map +1 -1
- package/dist/contracts.js +123 -116
- package/dist/db/database.d.ts.map +1 -1
- package/dist/db/task-crud.d.ts.map +1 -1
- package/dist/index.js +135 -127
- package/dist/lib/bulk-tags.d.ts +57 -0
- package/dist/lib/bulk-tags.d.ts.map +1 -0
- package/dist/lib/enum-vocabulary.d.ts +72 -0
- package/dist/lib/enum-vocabulary.d.ts.map +1 -0
- package/dist/lib/run-records.d.ts.map +1 -1
- package/dist/lib/sandbox-profiles.d.ts.map +1 -1
- package/dist/lib/saved-search-views.d.ts +12 -1
- package/dist/lib/saved-search-views.d.ts.map +1 -1
- package/dist/lib/sync-utils.d.ts +1 -1
- package/dist/lib/sync-utils.d.ts.map +1 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +289 -82
- package/dist/mcp/tools/agents.d.ts.map +1 -1
- package/dist/mcp/tools/task-auto-tools.d.ts.map +1 -1
- package/dist/mcp/tools/task-crud.d.ts +1 -0
- package/dist/mcp/tools/task-crud.d.ts.map +1 -1
- package/dist/mcp.js +1 -1
- package/dist/registry.js +123 -116
- package/dist/release-provenance.json +5 -5
- package/dist/sdk/index.js +3 -2
- package/dist/sdk/v1.generated.d.ts +2 -2
- package/dist/sdk/v1.generated.d.ts.map +1 -1
- package/dist/server/index.js +245 -38
- package/dist/server/openapi.d.ts +58 -0
- package/dist/server/openapi.d.ts.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/v1.d.ts.map +1 -1
- package/dist/storage.js +124 -115
- package/dist/types/index.d.ts +11 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stage-a.d.ts","sourceRoot":"","sources":["../../src/cli/stage-a.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAQ,MAAM,WAAW,CAAC;AAO1C,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAE9C,MAAM,MAAM,+BAA+B,GACvC;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,IAAI,CAAA;CAAE,GACrC;IAAE,KAAK,EAAE,mBAAmB,CAAC;IAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC1D;IAAE,KAAK,EAAE,aAAa,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC;AAElD,MAAM,MAAM,oBAAoB,GAAG,YAAY,GAAG,aAAa,GAAG,YAAY,CAAC;AAyB/E,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;CA8BgB,CAAC;
|
|
1
|
+
{"version":3,"file":"stage-a.d.ts","sourceRoot":"","sources":["../../src/cli/stage-a.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAQ,MAAM,WAAW,CAAC;AAO1C,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAE9C,MAAM,MAAM,+BAA+B,GACvC;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,IAAI,CAAA;CAAE,GACrC;IAAE,KAAK,EAAE,mBAAmB,CAAC;IAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC1D;IAAE,KAAK,EAAE,aAAa,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC;AAElD,MAAM,MAAM,oBAAoB,GAAG,YAAY,GAAG,aAAa,GAAG,YAAY,CAAC;AAyB/E,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;CA8BgB,CAAC;AAoEvD,wBAAgB,kCAAkC,IAAI,WAAW,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAE9F;AAED;;;;;;;GAOG;AACH,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,+BAA+B,CAAC,OAAO,CAAC,GAC9C,OAAO,CAKT;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,+BAA+B,CAAC,OAAO,CAAC,GAAG,IAAI,CASnH;AAuWD;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,GAAE,MAAM,EAA0B,EACtC,GAAG,GAAE,GAAwB,GAC5B,+BAA+B,CAgBjC"}
|
package/dist/contracts.js
CHANGED
|
@@ -3430,6 +3430,9 @@ var init_machines = __esm(() => {
|
|
|
3430
3430
|
function isBlockingDependencyStatus(status) {
|
|
3431
3431
|
return status !== "completed" && status !== "cancelled";
|
|
3432
3432
|
}
|
|
3433
|
+
function isTerminalStatus(status) {
|
|
3434
|
+
return status === "completed" || status === "failed" || status === "cancelled";
|
|
3435
|
+
}
|
|
3433
3436
|
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
3437
|
var init_types = __esm(() => {
|
|
3435
3438
|
TASK_STATUSES = [
|
|
@@ -3787,6 +3790,103 @@ var init_identity_mapping = __esm(() => {
|
|
|
3787
3790
|
});
|
|
3788
3791
|
});
|
|
3789
3792
|
|
|
3793
|
+
// src/lib/sync-utils.ts
|
|
3794
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
|
|
3795
|
+
import { createHash } from "crypto";
|
|
3796
|
+
import { homedir } from "os";
|
|
3797
|
+
import { join } from "path";
|
|
3798
|
+
function getHomeDir() {
|
|
3799
|
+
return process.env["HOME"] || process.env["USERPROFILE"] || homedir();
|
|
3800
|
+
}
|
|
3801
|
+
function getTodosGlobalDir() {
|
|
3802
|
+
return join(getHomeDir(), ".hasna", "todos");
|
|
3803
|
+
}
|
|
3804
|
+
function ensureDir(dir) {
|
|
3805
|
+
if (!existsSync2(dir))
|
|
3806
|
+
mkdirSync(dir, { recursive: true });
|
|
3807
|
+
}
|
|
3808
|
+
function listJsonFiles(dir) {
|
|
3809
|
+
if (!existsSync2(dir))
|
|
3810
|
+
return [];
|
|
3811
|
+
return readdirSync(dir).filter((f) => f.endsWith(".json"));
|
|
3812
|
+
}
|
|
3813
|
+
function readJsonFile(path) {
|
|
3814
|
+
try {
|
|
3815
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
3816
|
+
} catch {
|
|
3817
|
+
return null;
|
|
3818
|
+
}
|
|
3819
|
+
}
|
|
3820
|
+
function writeJsonFile(path, data) {
|
|
3821
|
+
writeFileSync(path, JSON.stringify(data, null, 2) + `
|
|
3822
|
+
`);
|
|
3823
|
+
}
|
|
3824
|
+
function readHighWaterMark(dir) {
|
|
3825
|
+
const path = join(dir, ".highwatermark");
|
|
3826
|
+
if (!existsSync2(path))
|
|
3827
|
+
return 1;
|
|
3828
|
+
const val = parseInt(readFileSync(path, "utf-8").trim(), 10);
|
|
3829
|
+
return isNaN(val) ? 1 : val;
|
|
3830
|
+
}
|
|
3831
|
+
function writeHighWaterMark(dir, value) {
|
|
3832
|
+
writeFileSync(join(dir, ".highwatermark"), String(value));
|
|
3833
|
+
}
|
|
3834
|
+
function getFileMtimeMs(path) {
|
|
3835
|
+
try {
|
|
3836
|
+
return statSync(path).mtimeMs;
|
|
3837
|
+
} catch {
|
|
3838
|
+
return null;
|
|
3839
|
+
}
|
|
3840
|
+
}
|
|
3841
|
+
function parseTimestamp(value) {
|
|
3842
|
+
if (typeof value !== "string")
|
|
3843
|
+
return null;
|
|
3844
|
+
const parsed = Date.parse(value);
|
|
3845
|
+
return Number.isNaN(parsed) ? null : parsed;
|
|
3846
|
+
}
|
|
3847
|
+
function appendSyncConflict(metadata, conflict, limit = 5) {
|
|
3848
|
+
const current = Array.isArray(metadata["sync_conflicts"]) ? metadata["sync_conflicts"] : [];
|
|
3849
|
+
const next = [conflict, ...current].slice(0, limit);
|
|
3850
|
+
return { ...metadata, sync_conflicts: next };
|
|
3851
|
+
}
|
|
3852
|
+
function canonicalize(value) {
|
|
3853
|
+
if (Array.isArray(value))
|
|
3854
|
+
return value.map(canonicalize);
|
|
3855
|
+
if (!value || typeof value !== "object")
|
|
3856
|
+
return value;
|
|
3857
|
+
const entries = Object.entries(value).filter(([, entryValue]) => entryValue !== undefined).sort(([a], [b]) => a.localeCompare(b));
|
|
3858
|
+
return Object.fromEntries(entries.map(([key, entryValue]) => [key, canonicalize(entryValue)]));
|
|
3859
|
+
}
|
|
3860
|
+
function withoutSyncFingerprintMetadata(metadata) {
|
|
3861
|
+
const { [TODO_SYNC_FINGERPRINT_KEY]: _fingerprint, ...rest } = metadata;
|
|
3862
|
+
return rest;
|
|
3863
|
+
}
|
|
3864
|
+
function syncFingerprint(record) {
|
|
3865
|
+
const metadata = withoutSyncFingerprintMetadata(record.metadata || {});
|
|
3866
|
+
const canonical = canonicalize({ ...record, metadata });
|
|
3867
|
+
return `sha256:${createHash("sha256").update(JSON.stringify(canonical)).digest("hex")}`;
|
|
3868
|
+
}
|
|
3869
|
+
function withSyncFingerprint(record) {
|
|
3870
|
+
const metadata = withoutSyncFingerprintMetadata(record.metadata);
|
|
3871
|
+
return {
|
|
3872
|
+
...record,
|
|
3873
|
+
metadata: {
|
|
3874
|
+
...metadata,
|
|
3875
|
+
[TODO_SYNC_FINGERPRINT_KEY]: syncFingerprint({ ...record, metadata })
|
|
3876
|
+
}
|
|
3877
|
+
};
|
|
3878
|
+
}
|
|
3879
|
+
function hasSyncFingerprintChanged(record) {
|
|
3880
|
+
const stored = record.metadata?.[TODO_SYNC_FINGERPRINT_KEY];
|
|
3881
|
+
if (typeof stored !== "string" || stored.length === 0)
|
|
3882
|
+
return null;
|
|
3883
|
+
return stored !== syncFingerprint(record);
|
|
3884
|
+
}
|
|
3885
|
+
var TODO_SYNC_FINGERPRINT_KEY = "todos_sync_fingerprint", HOME;
|
|
3886
|
+
var init_sync_utils = __esm(() => {
|
|
3887
|
+
HOME = getHomeDir();
|
|
3888
|
+
});
|
|
3889
|
+
|
|
3790
3890
|
// src/storage/config.ts
|
|
3791
3891
|
var exports_config = {};
|
|
3792
3892
|
__export(exports_config, {
|
|
@@ -4117,8 +4217,8 @@ __export(exports_database, {
|
|
|
4117
4217
|
LOCK_EXPIRY_MINUTES: () => LOCK_EXPIRY_MINUTES
|
|
4118
4218
|
});
|
|
4119
4219
|
import { Database } from "bun:sqlite";
|
|
4120
|
-
import { existsSync as
|
|
4121
|
-
import { dirname, join, resolve as resolve2 } from "path";
|
|
4220
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
4221
|
+
import { dirname, join as join2, resolve as resolve2 } from "path";
|
|
4122
4222
|
function isInMemoryDb(path) {
|
|
4123
4223
|
return path === ":memory:" || path.startsWith("file::memory:");
|
|
4124
4224
|
}
|
|
@@ -4127,8 +4227,8 @@ function findNearestProjectDb(startDir) {
|
|
|
4127
4227
|
const stopAt = gitRoot ? resolve2(gitRoot) : resolve2(startDir);
|
|
4128
4228
|
let dir = resolve2(startDir);
|
|
4129
4229
|
while (true) {
|
|
4130
|
-
const candidate =
|
|
4131
|
-
if (
|
|
4230
|
+
const candidate = join2(dir, ".hasna", "todos", "todos.db");
|
|
4231
|
+
if (existsSync3(candidate))
|
|
4132
4232
|
return candidate;
|
|
4133
4233
|
if (dir === stopAt)
|
|
4134
4234
|
break;
|
|
@@ -4142,7 +4242,7 @@ function findNearestProjectDb(startDir) {
|
|
|
4142
4242
|
function findGitRoot(startDir) {
|
|
4143
4243
|
let dir = resolve2(startDir);
|
|
4144
4244
|
while (true) {
|
|
4145
|
-
if (
|
|
4245
|
+
if (existsSync3(join2(dir, ".git")))
|
|
4146
4246
|
return dir;
|
|
4147
4247
|
const parent = dirname(dir);
|
|
4148
4248
|
if (parent === dir)
|
|
@@ -4152,8 +4252,7 @@ function findGitRoot(startDir) {
|
|
|
4152
4252
|
return null;
|
|
4153
4253
|
}
|
|
4154
4254
|
function getGlobalDbPath() {
|
|
4155
|
-
|
|
4156
|
-
return join(home, ".hasna", "todos", "todos.db");
|
|
4255
|
+
return join2(getHomeDir(), ".hasna", "todos", "todos.db");
|
|
4157
4256
|
}
|
|
4158
4257
|
function hasExplicitProjectArg(args = process.argv.slice(2)) {
|
|
4159
4258
|
return args.some((arg) => arg === "--project" || arg.startsWith("--project="));
|
|
@@ -4191,7 +4290,7 @@ function getDbPath() {
|
|
|
4191
4290
|
if (process.env["TODOS_DB_SCOPE"] === "project") {
|
|
4192
4291
|
const gitRoot = findGitRoot(cwd);
|
|
4193
4292
|
if (gitRoot && canCreateScopedProjectDb()) {
|
|
4194
|
-
return
|
|
4293
|
+
return join2(gitRoot, ".hasna", "todos", "todos.db");
|
|
4195
4294
|
}
|
|
4196
4295
|
}
|
|
4197
4296
|
return getGlobalDbPath();
|
|
@@ -4199,16 +4298,16 @@ function getDbPath() {
|
|
|
4199
4298
|
function getDatabasePath() {
|
|
4200
4299
|
return getDbPath();
|
|
4201
4300
|
}
|
|
4202
|
-
function
|
|
4301
|
+
function ensureDir2(filePath) {
|
|
4203
4302
|
if (isInMemoryDb(filePath))
|
|
4204
4303
|
return;
|
|
4205
4304
|
const dir = dirname(resolve2(filePath));
|
|
4206
|
-
if (!
|
|
4207
|
-
|
|
4305
|
+
if (!existsSync3(dir)) {
|
|
4306
|
+
mkdirSync2(dir, { recursive: true });
|
|
4208
4307
|
}
|
|
4209
4308
|
}
|
|
4210
4309
|
function openDatabase(path) {
|
|
4211
|
-
|
|
4310
|
+
ensureDir2(path);
|
|
4212
4311
|
const db = new Database(path);
|
|
4213
4312
|
db.run("PRAGMA busy_timeout = 5000");
|
|
4214
4313
|
db.run("PRAGMA journal_mode = WAL");
|
|
@@ -4375,105 +4474,10 @@ var init_database = __esm(() => {
|
|
|
4375
4474
|
init_machines();
|
|
4376
4475
|
init_identity_mapping();
|
|
4377
4476
|
init_types();
|
|
4477
|
+
init_sync_utils();
|
|
4378
4478
|
ALLOWED_TABLES = new Set(["tasks", "projects", "agents", "plans", "task_lists", "task_templates", "project_knowledge_records", "project_risks", "local_retrospectives"]);
|
|
4379
4479
|
});
|
|
4380
4480
|
|
|
4381
|
-
// src/lib/sync-utils.ts
|
|
4382
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
|
|
4383
|
-
import { createHash } from "crypto";
|
|
4384
|
-
import { join as join2 } from "path";
|
|
4385
|
-
function getHomeDir() {
|
|
4386
|
-
return process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
4387
|
-
}
|
|
4388
|
-
function getTodosGlobalDir() {
|
|
4389
|
-
return join2(getHomeDir(), ".hasna", "todos");
|
|
4390
|
-
}
|
|
4391
|
-
function ensureDir2(dir) {
|
|
4392
|
-
if (!existsSync3(dir))
|
|
4393
|
-
mkdirSync2(dir, { recursive: true });
|
|
4394
|
-
}
|
|
4395
|
-
function listJsonFiles(dir) {
|
|
4396
|
-
if (!existsSync3(dir))
|
|
4397
|
-
return [];
|
|
4398
|
-
return readdirSync(dir).filter((f) => f.endsWith(".json"));
|
|
4399
|
-
}
|
|
4400
|
-
function readJsonFile(path) {
|
|
4401
|
-
try {
|
|
4402
|
-
return JSON.parse(readFileSync(path, "utf-8"));
|
|
4403
|
-
} catch {
|
|
4404
|
-
return null;
|
|
4405
|
-
}
|
|
4406
|
-
}
|
|
4407
|
-
function writeJsonFile(path, data) {
|
|
4408
|
-
writeFileSync(path, JSON.stringify(data, null, 2) + `
|
|
4409
|
-
`);
|
|
4410
|
-
}
|
|
4411
|
-
function readHighWaterMark(dir) {
|
|
4412
|
-
const path = join2(dir, ".highwatermark");
|
|
4413
|
-
if (!existsSync3(path))
|
|
4414
|
-
return 1;
|
|
4415
|
-
const val = parseInt(readFileSync(path, "utf-8").trim(), 10);
|
|
4416
|
-
return isNaN(val) ? 1 : val;
|
|
4417
|
-
}
|
|
4418
|
-
function writeHighWaterMark(dir, value) {
|
|
4419
|
-
writeFileSync(join2(dir, ".highwatermark"), String(value));
|
|
4420
|
-
}
|
|
4421
|
-
function getFileMtimeMs(path) {
|
|
4422
|
-
try {
|
|
4423
|
-
return statSync(path).mtimeMs;
|
|
4424
|
-
} catch {
|
|
4425
|
-
return null;
|
|
4426
|
-
}
|
|
4427
|
-
}
|
|
4428
|
-
function parseTimestamp(value) {
|
|
4429
|
-
if (typeof value !== "string")
|
|
4430
|
-
return null;
|
|
4431
|
-
const parsed = Date.parse(value);
|
|
4432
|
-
return Number.isNaN(parsed) ? null : parsed;
|
|
4433
|
-
}
|
|
4434
|
-
function appendSyncConflict(metadata, conflict, limit = 5) {
|
|
4435
|
-
const current = Array.isArray(metadata["sync_conflicts"]) ? metadata["sync_conflicts"] : [];
|
|
4436
|
-
const next = [conflict, ...current].slice(0, limit);
|
|
4437
|
-
return { ...metadata, sync_conflicts: next };
|
|
4438
|
-
}
|
|
4439
|
-
function canonicalize(value) {
|
|
4440
|
-
if (Array.isArray(value))
|
|
4441
|
-
return value.map(canonicalize);
|
|
4442
|
-
if (!value || typeof value !== "object")
|
|
4443
|
-
return value;
|
|
4444
|
-
const entries = Object.entries(value).filter(([, entryValue]) => entryValue !== undefined).sort(([a], [b]) => a.localeCompare(b));
|
|
4445
|
-
return Object.fromEntries(entries.map(([key, entryValue]) => [key, canonicalize(entryValue)]));
|
|
4446
|
-
}
|
|
4447
|
-
function withoutSyncFingerprintMetadata(metadata) {
|
|
4448
|
-
const { [TODO_SYNC_FINGERPRINT_KEY]: _fingerprint, ...rest } = metadata;
|
|
4449
|
-
return rest;
|
|
4450
|
-
}
|
|
4451
|
-
function syncFingerprint(record) {
|
|
4452
|
-
const metadata = withoutSyncFingerprintMetadata(record.metadata || {});
|
|
4453
|
-
const canonical = canonicalize({ ...record, metadata });
|
|
4454
|
-
return `sha256:${createHash("sha256").update(JSON.stringify(canonical)).digest("hex")}`;
|
|
4455
|
-
}
|
|
4456
|
-
function withSyncFingerprint(record) {
|
|
4457
|
-
const metadata = withoutSyncFingerprintMetadata(record.metadata);
|
|
4458
|
-
return {
|
|
4459
|
-
...record,
|
|
4460
|
-
metadata: {
|
|
4461
|
-
...metadata,
|
|
4462
|
-
[TODO_SYNC_FINGERPRINT_KEY]: syncFingerprint({ ...record, metadata })
|
|
4463
|
-
}
|
|
4464
|
-
};
|
|
4465
|
-
}
|
|
4466
|
-
function hasSyncFingerprintChanged(record) {
|
|
4467
|
-
const stored = record.metadata?.[TODO_SYNC_FINGERPRINT_KEY];
|
|
4468
|
-
if (typeof stored !== "string" || stored.length === 0)
|
|
4469
|
-
return null;
|
|
4470
|
-
return stored !== syncFingerprint(record);
|
|
4471
|
-
}
|
|
4472
|
-
var TODO_SYNC_FINGERPRINT_KEY = "todos_sync_fingerprint", HOME;
|
|
4473
|
-
var init_sync_utils = __esm(() => {
|
|
4474
|
-
HOME = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
4475
|
-
});
|
|
4476
|
-
|
|
4477
4481
|
// src/lib/config.ts
|
|
4478
4482
|
import { existsSync as existsSync4 } from "fs";
|
|
4479
4483
|
import { dirname as dirname2, join as join3 } from "path";
|
|
@@ -4499,7 +4503,7 @@ function loadConfig() {
|
|
|
4499
4503
|
}
|
|
4500
4504
|
function saveConfig(config) {
|
|
4501
4505
|
const configPath = getConfigPath();
|
|
4502
|
-
|
|
4506
|
+
ensureDir(dirname2(configPath));
|
|
4503
4507
|
writeJsonFile(configPath, config);
|
|
4504
4508
|
cached = config;
|
|
4505
4509
|
return config;
|
|
@@ -5844,7 +5848,7 @@ var init_event_hooks = __esm(() => {
|
|
|
5844
5848
|
// node_modules/.bun/@hasna+events@0.1.11/node_modules/@hasna/events/dist/index.js
|
|
5845
5849
|
import { chmod, mkdir, readFile, rename, writeFile } from "fs/promises";
|
|
5846
5850
|
import { existsSync as existsSync5 } from "fs";
|
|
5847
|
-
import { homedir } from "os";
|
|
5851
|
+
import { homedir as homedir2 } from "os";
|
|
5848
5852
|
import { join as join4 } from "path";
|
|
5849
5853
|
import { createHmac, timingSafeEqual } from "crypto";
|
|
5850
5854
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
@@ -5946,7 +5950,7 @@ function channelMatchesEvent(channel, event) {
|
|
|
5946
5950
|
return channel.filters.some((filter) => eventMatchesFilter(event, filter));
|
|
5947
5951
|
}
|
|
5948
5952
|
function getEventsDataDir(override) {
|
|
5949
|
-
return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join4(
|
|
5953
|
+
return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join4(homedir2(), ".hasna", "events");
|
|
5950
5954
|
}
|
|
5951
5955
|
|
|
5952
5956
|
class JsonEventsStore {
|
|
@@ -9286,11 +9290,13 @@ function updateTask(id, input, db) {
|
|
|
9286
9290
|
}
|
|
9287
9291
|
sets.push("status = ?");
|
|
9288
9292
|
params.push(input.status);
|
|
9293
|
+
if (isTerminalStatus(input.status)) {
|
|
9294
|
+
sets.push("locked_by = NULL");
|
|
9295
|
+
sets.push("locked_at = NULL");
|
|
9296
|
+
}
|
|
9289
9297
|
if (input.status === "completed") {
|
|
9290
9298
|
sets.push("completed_at = ?");
|
|
9291
9299
|
params.push(completionTimestamp);
|
|
9292
|
-
sets.push("locked_by = NULL");
|
|
9293
|
-
sets.push("locked_at = NULL");
|
|
9294
9300
|
} else if (task.status === "completed" && input.completed_at === undefined) {
|
|
9295
9301
|
sets.push("completed_at = NULL");
|
|
9296
9302
|
}
|
|
@@ -9414,6 +9420,7 @@ function updateTask(id, input, db) {
|
|
|
9414
9420
|
logTaskChange(id, "approve", "approved_by", null, input.approved_by, agentId, d);
|
|
9415
9421
|
const reopened = input.status !== undefined && input.status !== "completed" && task.status === "completed" && input.completed_at === undefined;
|
|
9416
9422
|
const completedNow = input.status === "completed";
|
|
9423
|
+
const terminalNow = input.status !== undefined && isTerminalStatus(input.status);
|
|
9417
9424
|
const updatedTask = {
|
|
9418
9425
|
...task,
|
|
9419
9426
|
...Object.fromEntries(Object.entries(input).filter(([, v]) => v !== undefined)),
|
|
@@ -9421,8 +9428,8 @@ function updateTask(id, input, db) {
|
|
|
9421
9428
|
metadata: input.metadata ?? task.metadata,
|
|
9422
9429
|
version: task.version + 1,
|
|
9423
9430
|
updated_at: timestamp2,
|
|
9424
|
-
locked_by:
|
|
9425
|
-
locked_at:
|
|
9431
|
+
locked_by: terminalNow ? null : task.locked_by,
|
|
9432
|
+
locked_at: terminalNow ? null : task.locked_at,
|
|
9426
9433
|
completed_at: completedNow ? completionTimestamp : reopened ? null : input.completed_at !== undefined ? input.completed_at : task.completed_at,
|
|
9427
9434
|
sla_minutes: input.sla_minutes !== undefined ? input.sla_minutes : task.sla_minutes,
|
|
9428
9435
|
actual_minutes: input.actual_minutes ?? task.actual_minutes,
|
|
@@ -12025,7 +12032,7 @@ var init_tasks = __esm(() => {
|
|
|
12025
12032
|
// package.json
|
|
12026
12033
|
var package_default = {
|
|
12027
12034
|
name: "@hasna/todos",
|
|
12028
|
-
version: "0.
|
|
12035
|
+
version: "0.15.1",
|
|
12029
12036
|
description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
|
|
12030
12037
|
type: "module",
|
|
12031
12038
|
main: "dist/index.js",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAStC,eAAO,MAAM,mBAAmB,KAAK,CAAC;AA4FtC,wBAAgB,eAAe,IAAI,MAAM,CAExC;AA2DD,wBAAgB,WAAW,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAarD;AAED,wBAAgB,aAAa,IAAI,IAAI,CAMpC;AAED,wBAAgB,aAAa,IAAI,IAAI,CAQpC;AAED,wBAAgB,GAAG,IAAI,MAAM,CAE5B;AAED,wBAAgB,IAAI,IAAI,MAAM,CAE7B;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,SAAa,GAAG,OAAO,CAKlF;AAED,wBAAgB,gBAAgB,CAAC,KAAK,SAAa,GAAG,MAAM,CAG3D;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAGpD;AAQD,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA8E9F;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAe5E;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAEzE;AAED,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,CAIlG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-crud.d.ts","sourceRoot":"","sources":["../../src/db/task-crud.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAoB,MAAM,YAAY,CAAC;AAC7D,OAAO,KAAK,EACV,eAAe,EACf,IAAI,EACJ,UAAU,EACV,OAAO,EACP,iBAAiB,EACjB,eAAe,EACf,4BAA4B,EAC5B,6BAA6B,EAC9B,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"task-crud.d.ts","sourceRoot":"","sources":["../../src/db/task-crud.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAoB,MAAM,YAAY,CAAC;AAC7D,OAAO,KAAK,EACV,eAAe,EACf,IAAI,EACJ,UAAU,EACV,OAAO,EACP,iBAAiB,EACjB,eAAe,EACf,4BAA4B,EAC5B,6BAA6B,EAC9B,MAAM,mBAAmB,CAAC;AAQ3B,OAAO,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAY5F,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAS5C;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,GAAG,IAAI,CAMjF;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,GAAG,IAAI,CAGlF;AAwCD,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,IAAI,CAwFtE;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,IAAI,CAK9D;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,MAAM,EACV,EAAE,CAAC,EAAE,QAAQ,GACZ,iBAAiB,GAAG,IAAI,CA4D1B;AAQD,wBAAgB,SAAS,CAAC,MAAM,GAAE,UAAe,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,IAAI,EAAE,CA0JxE;AAED,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EACnB,EAAE,CAAC,EAAE,QAAQ,GACZ,IAAI,GAAG,IAAI,CAKb;AAcD,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,4BAA4B,EACnC,EAAE,CAAC,EAAE,QAAQ,GACZ,6BAA6B,CAmD/B;AAED,wBAAgB,UAAU,CAAC,MAAM,GAAE,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,QAAQ,CAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,MAAM,CA0HnG;AAED,wBAAgB,UAAU,CACxB,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,eAAe,EACtB,EAAE,CAAC,EAAE,QAAQ,GACZ,IAAI,CA8PN;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAY7D"}
|