@hasna/todos 0.15.50 → 0.15.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/cloud-router.d.ts.map +1 -1
- package/dist/cli/commands/project-commands.d.ts +15 -0
- 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/helpers.d.ts.map +1 -1
- package/dist/cli/index.js +521 -342
- package/dist/contracts.js +194 -95
- package/dist/db/task-crud.d.ts.map +1 -1
- package/dist/index.js +406 -299
- package/dist/lib/model-config.d.ts +2 -1
- package/dist/lib/model-config.d.ts.map +1 -1
- package/dist/lib/paths.d.ts +40 -0
- package/dist/lib/paths.d.ts.map +1 -0
- package/dist/lib/sync-utils.d.ts +7 -0
- package/dist/lib/sync-utils.d.ts.map +1 -1
- package/dist/mcp/index.js +280 -174
- package/dist/mcp.js +7 -4
- package/dist/project-registration.js +192 -93
- package/dist/registry.js +194 -95
- package/dist/release-provenance.json +5 -5
- package/dist/sdk/index.js +100 -8
- package/dist/server/index.js +449 -220
- package/dist/storage.js +183 -87
- package/dist/task-manifest.js +113 -17
- package/dist/testing.d.ts +10 -9
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +2 -2
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +7 -4
- package/postinstall.js +34 -0
package/dist/registry.js
CHANGED
|
@@ -4075,23 +4075,118 @@ var init_identity_mapping = __esm(() => {
|
|
|
4075
4075
|
});
|
|
4076
4076
|
});
|
|
4077
4077
|
|
|
4078
|
-
//
|
|
4079
|
-
import { existsSync as existsSync2, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
|
|
4080
|
-
import { createHash } from "crypto";
|
|
4078
|
+
// node_modules/.bun/@hasna+paths@0.1.0/node_modules/@hasna/paths/dist/index.js
|
|
4081
4079
|
import { homedir } from "os";
|
|
4082
4080
|
import { join } from "path";
|
|
4081
|
+
function assertApp(app) {
|
|
4082
|
+
if (typeof app !== "string" || app.length === 0) {
|
|
4083
|
+
throw new TypeError("paths: app must be a non-empty string");
|
|
4084
|
+
}
|
|
4085
|
+
if (!APP_SLUG_RE.test(app)) {
|
|
4086
|
+
throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
|
|
4087
|
+
}
|
|
4088
|
+
}
|
|
4089
|
+
function envOf(options) {
|
|
4090
|
+
return options.env ?? process.env;
|
|
4091
|
+
}
|
|
4092
|
+
function envValue(options, kind) {
|
|
4093
|
+
const value = envOf(options)[KIND_ENV[kind]];
|
|
4094
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
4095
|
+
}
|
|
4096
|
+
function isMacOS(platform) {
|
|
4097
|
+
return platform === "darwin";
|
|
4098
|
+
}
|
|
4099
|
+
function baseDir(kind, options) {
|
|
4100
|
+
const override = envValue(options, kind);
|
|
4101
|
+
if (override)
|
|
4102
|
+
return override;
|
|
4103
|
+
const home = options.home ?? homedir();
|
|
4104
|
+
const platform = options.platform ?? process.platform;
|
|
4105
|
+
if (isMacOS(platform)) {
|
|
4106
|
+
switch (kind) {
|
|
4107
|
+
case "config":
|
|
4108
|
+
case "data":
|
|
4109
|
+
return join(home, "Library", "Application Support", "Hasna");
|
|
4110
|
+
case "cache":
|
|
4111
|
+
return join(home, "Library", "Caches", "Hasna");
|
|
4112
|
+
case "state":
|
|
4113
|
+
return join(home, "Library", "Logs", "Hasna");
|
|
4114
|
+
}
|
|
4115
|
+
}
|
|
4116
|
+
switch (kind) {
|
|
4117
|
+
case "config":
|
|
4118
|
+
return join(home, ".config", "hasna");
|
|
4119
|
+
case "data":
|
|
4120
|
+
return join(home, ".local", "share", "hasna");
|
|
4121
|
+
case "state":
|
|
4122
|
+
return join(home, ".local", "state", "hasna");
|
|
4123
|
+
case "cache":
|
|
4124
|
+
return join(home, ".cache", "hasna");
|
|
4125
|
+
}
|
|
4126
|
+
}
|
|
4127
|
+
function resolvePath(kind, options) {
|
|
4128
|
+
assertApp(options.app);
|
|
4129
|
+
const appSegment = options.internal === true ? join("internal", options.app) : options.app;
|
|
4130
|
+
return join(baseDir(kind, options), appSegment);
|
|
4131
|
+
}
|
|
4132
|
+
function dataDir(options) {
|
|
4133
|
+
return resolvePath("data", options);
|
|
4134
|
+
}
|
|
4135
|
+
var KIND_ENV, APP_SLUG_RE;
|
|
4136
|
+
var init_dist = __esm(() => {
|
|
4137
|
+
KIND_ENV = {
|
|
4138
|
+
config: "HASNA_CONFIG_HOME",
|
|
4139
|
+
data: "HASNA_DATA_HOME",
|
|
4140
|
+
state: "HASNA_STATE_HOME",
|
|
4141
|
+
cache: "HASNA_CACHE_HOME"
|
|
4142
|
+
};
|
|
4143
|
+
APP_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
4144
|
+
});
|
|
4145
|
+
|
|
4146
|
+
// src/lib/paths.ts
|
|
4147
|
+
import { existsSync as existsSync2 } from "fs";
|
|
4148
|
+
import { homedir as homedir2 } from "os";
|
|
4149
|
+
import { join as join2, resolve as resolve2 } from "path";
|
|
4150
|
+
function effectiveHome(env = process.env) {
|
|
4151
|
+
return env.HOME || env.USERPROFILE || homedir2();
|
|
4152
|
+
}
|
|
4153
|
+
function legacyHomeDir(env = process.env) {
|
|
4154
|
+
return join2(effectiveHome(env), ".hasna", "todos");
|
|
4155
|
+
}
|
|
4156
|
+
function resolverHome(env = process.env) {
|
|
4157
|
+
return dataDir({ app: "todos", home: effectiveHome(env), env });
|
|
4158
|
+
}
|
|
4159
|
+
function adoptResolverHome(resolved, env = process.env) {
|
|
4160
|
+
const dataOverride = env.HASNA_DATA_HOME;
|
|
4161
|
+
if (typeof dataOverride === "string" && dataOverride.trim().length > 0)
|
|
4162
|
+
return true;
|
|
4163
|
+
return existsSync2(join2(resolved, "todos.db")) || existsSync2(join2(resolved, "config.json"));
|
|
4164
|
+
}
|
|
4165
|
+
function getTodosDir(env = process.env) {
|
|
4166
|
+
const resolved = resolverHome(env);
|
|
4167
|
+
return resolve2(adoptResolverHome(resolved, env) ? resolved : legacyHomeDir(env));
|
|
4168
|
+
}
|
|
4169
|
+
var init_paths = __esm(() => {
|
|
4170
|
+
init_dist();
|
|
4171
|
+
});
|
|
4172
|
+
|
|
4173
|
+
// src/lib/sync-utils.ts
|
|
4174
|
+
import { existsSync as existsSync3, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
|
|
4175
|
+
import { createHash } from "crypto";
|
|
4176
|
+
import { homedir as homedir3 } from "os";
|
|
4177
|
+
import { join as join3 } from "path";
|
|
4083
4178
|
function getHomeDir() {
|
|
4084
|
-
return process.env["HOME"] || process.env["USERPROFILE"] ||
|
|
4179
|
+
return process.env["HOME"] || process.env["USERPROFILE"] || homedir3();
|
|
4085
4180
|
}
|
|
4086
4181
|
function getTodosGlobalDir() {
|
|
4087
|
-
return
|
|
4182
|
+
return getTodosDir();
|
|
4088
4183
|
}
|
|
4089
4184
|
function ensureDir(dir) {
|
|
4090
|
-
if (!
|
|
4185
|
+
if (!existsSync3(dir))
|
|
4091
4186
|
mkdirSync(dir, { recursive: true });
|
|
4092
4187
|
}
|
|
4093
4188
|
function listJsonFiles(dir) {
|
|
4094
|
-
if (!
|
|
4189
|
+
if (!existsSync3(dir))
|
|
4095
4190
|
return [];
|
|
4096
4191
|
return readdirSync(dir).filter((f) => f.endsWith(".json"));
|
|
4097
4192
|
}
|
|
@@ -4107,14 +4202,14 @@ function writeJsonFile(path, data) {
|
|
|
4107
4202
|
`);
|
|
4108
4203
|
}
|
|
4109
4204
|
function readHighWaterMark(dir) {
|
|
4110
|
-
const path =
|
|
4111
|
-
if (!
|
|
4205
|
+
const path = join3(dir, ".highwatermark");
|
|
4206
|
+
if (!existsSync3(path))
|
|
4112
4207
|
return 1;
|
|
4113
4208
|
const val = parseInt(readFileSync(path, "utf-8").trim(), 10);
|
|
4114
4209
|
return isNaN(val) ? 1 : val;
|
|
4115
4210
|
}
|
|
4116
4211
|
function writeHighWaterMark(dir, value) {
|
|
4117
|
-
writeFileSync(
|
|
4212
|
+
writeFileSync(join3(dir, ".highwatermark"), String(value));
|
|
4118
4213
|
}
|
|
4119
4214
|
function getFileMtimeMs(path) {
|
|
4120
4215
|
try {
|
|
@@ -4169,6 +4264,7 @@ function hasSyncFingerprintChanged(record) {
|
|
|
4169
4264
|
}
|
|
4170
4265
|
var TODO_SYNC_FINGERPRINT_KEY = "todos_sync_fingerprint", HOME;
|
|
4171
4266
|
var init_sync_utils = __esm(() => {
|
|
4267
|
+
init_paths();
|
|
4172
4268
|
HOME = getHomeDir();
|
|
4173
4269
|
});
|
|
4174
4270
|
|
|
@@ -4479,18 +4575,18 @@ __export(exports_database, {
|
|
|
4479
4575
|
LOCK_EXPIRY_MINUTES: () => LOCK_EXPIRY_MINUTES
|
|
4480
4576
|
});
|
|
4481
4577
|
import { Database } from "bun:sqlite";
|
|
4482
|
-
import { existsSync as
|
|
4483
|
-
import { dirname, join as
|
|
4578
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync2 } from "fs";
|
|
4579
|
+
import { dirname, join as join4, resolve as resolve3 } from "path";
|
|
4484
4580
|
function isInMemoryDb(path) {
|
|
4485
4581
|
return path === ":memory:" || path.startsWith("file::memory:");
|
|
4486
4582
|
}
|
|
4487
4583
|
function findNearestProjectDb(startDir) {
|
|
4488
4584
|
const gitRoot = findGitRoot(startDir);
|
|
4489
|
-
const stopAt = gitRoot ?
|
|
4490
|
-
let dir =
|
|
4585
|
+
const stopAt = gitRoot ? resolve3(gitRoot) : resolve3(startDir);
|
|
4586
|
+
let dir = resolve3(startDir);
|
|
4491
4587
|
while (true) {
|
|
4492
|
-
const candidate =
|
|
4493
|
-
if (
|
|
4588
|
+
const candidate = join4(dir, ".hasna", "todos", "todos.db");
|
|
4589
|
+
if (existsSync4(candidate))
|
|
4494
4590
|
return candidate;
|
|
4495
4591
|
if (dir === stopAt)
|
|
4496
4592
|
break;
|
|
@@ -4502,9 +4598,9 @@ function findNearestProjectDb(startDir) {
|
|
|
4502
4598
|
return null;
|
|
4503
4599
|
}
|
|
4504
4600
|
function findGitRoot(startDir) {
|
|
4505
|
-
let dir =
|
|
4601
|
+
let dir = resolve3(startDir);
|
|
4506
4602
|
while (true) {
|
|
4507
|
-
if (
|
|
4603
|
+
if (existsSync4(join4(dir, ".git")))
|
|
4508
4604
|
return dir;
|
|
4509
4605
|
const parent = dirname(dir);
|
|
4510
4606
|
if (parent === dir)
|
|
@@ -4514,7 +4610,7 @@ function findGitRoot(startDir) {
|
|
|
4514
4610
|
return null;
|
|
4515
4611
|
}
|
|
4516
4612
|
function getGlobalDbPath() {
|
|
4517
|
-
return
|
|
4613
|
+
return join4(getTodosGlobalDir(), "todos.db");
|
|
4518
4614
|
}
|
|
4519
4615
|
function hasExplicitProjectArg(args = process.argv.slice(2)) {
|
|
4520
4616
|
return args.some((arg) => arg === "--project" || arg.startsWith("--project="));
|
|
@@ -4552,7 +4648,7 @@ function getDbPath() {
|
|
|
4552
4648
|
if (process.env["TODOS_DB_SCOPE"] === "project") {
|
|
4553
4649
|
const gitRoot = findGitRoot(cwd);
|
|
4554
4650
|
if (gitRoot && canCreateScopedProjectDb()) {
|
|
4555
|
-
return
|
|
4651
|
+
return join4(gitRoot, ".hasna", "todos", "todos.db");
|
|
4556
4652
|
}
|
|
4557
4653
|
}
|
|
4558
4654
|
return getGlobalDbPath();
|
|
@@ -4563,8 +4659,8 @@ function getDatabasePath() {
|
|
|
4563
4659
|
function ensureDir2(filePath) {
|
|
4564
4660
|
if (isInMemoryDb(filePath))
|
|
4565
4661
|
return;
|
|
4566
|
-
const dir = dirname(
|
|
4567
|
-
if (!
|
|
4662
|
+
const dir = dirname(resolve3(filePath));
|
|
4663
|
+
if (!existsSync4(dir)) {
|
|
4568
4664
|
mkdirSync2(dir, { recursive: true });
|
|
4569
4665
|
}
|
|
4570
4666
|
}
|
|
@@ -4741,10 +4837,10 @@ var init_database = __esm(() => {
|
|
|
4741
4837
|
});
|
|
4742
4838
|
|
|
4743
4839
|
// src/lib/config.ts
|
|
4744
|
-
import { existsSync as
|
|
4745
|
-
import { dirname as dirname2, join as
|
|
4840
|
+
import { existsSync as existsSync5, readFileSync as readFileSync2 } from "fs";
|
|
4841
|
+
import { dirname as dirname2, join as join5 } from "path";
|
|
4746
4842
|
function getConfigPath() {
|
|
4747
|
-
return
|
|
4843
|
+
return join5(getTodosGlobalDir(), "config.json");
|
|
4748
4844
|
}
|
|
4749
4845
|
function normalizeAgent(agent) {
|
|
4750
4846
|
return agent.trim().toLowerCase();
|
|
@@ -4752,7 +4848,7 @@ function normalizeAgent(agent) {
|
|
|
4752
4848
|
function loadConfig() {
|
|
4753
4849
|
if (cached)
|
|
4754
4850
|
return cached;
|
|
4755
|
-
if (!
|
|
4851
|
+
if (!existsSync5(getConfigPath())) {
|
|
4756
4852
|
cached = {};
|
|
4757
4853
|
return cached;
|
|
4758
4854
|
}
|
|
@@ -4775,7 +4871,7 @@ function updateConfig(patch) {
|
|
|
4775
4871
|
}
|
|
4776
4872
|
function getTodosAiConfig() {
|
|
4777
4873
|
const configPath = getConfigPath();
|
|
4778
|
-
if (!
|
|
4874
|
+
if (!existsSync5(configPath))
|
|
4779
4875
|
return {};
|
|
4780
4876
|
const parsed = JSON.parse(readFileSync2(configPath, "utf8"));
|
|
4781
4877
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
@@ -5393,14 +5489,14 @@ var init_completion_guard = __esm(() => {
|
|
|
5393
5489
|
|
|
5394
5490
|
// src/lib/event-emission-safety.ts
|
|
5395
5491
|
import { tmpdir } from "os";
|
|
5396
|
-
import { resolve as
|
|
5492
|
+
import { resolve as resolve4, sep } from "path";
|
|
5397
5493
|
function envFlag(name) {
|
|
5398
5494
|
const value = process.env[name]?.trim().toLowerCase();
|
|
5399
5495
|
return value === "1" || value === "true" || value === "yes" || value === "on";
|
|
5400
5496
|
}
|
|
5401
5497
|
function isUnder(parent, child) {
|
|
5402
|
-
const normalizedParent =
|
|
5403
|
-
const normalizedChild =
|
|
5498
|
+
const normalizedParent = resolve4(parent);
|
|
5499
|
+
const normalizedChild = resolve4(child);
|
|
5404
5500
|
return normalizedChild === normalizedParent || normalizedChild.startsWith(`${normalizedParent}${sep}`);
|
|
5405
5501
|
}
|
|
5406
5502
|
function databasePathFromDatabase(db) {
|
|
@@ -5561,9 +5657,9 @@ var init_redaction = __esm(() => {
|
|
|
5561
5657
|
});
|
|
5562
5658
|
|
|
5563
5659
|
// src/lib/workspace-trust.ts
|
|
5564
|
-
import { relative, resolve as
|
|
5660
|
+
import { relative, resolve as resolve5 } from "path";
|
|
5565
5661
|
function normalizePath(path) {
|
|
5566
|
-
return
|
|
5662
|
+
return resolve5(path);
|
|
5567
5663
|
}
|
|
5568
5664
|
function unique2(values) {
|
|
5569
5665
|
return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));
|
|
@@ -5745,9 +5841,9 @@ var init_workspace_trust = __esm(() => {
|
|
|
5745
5841
|
});
|
|
5746
5842
|
|
|
5747
5843
|
// src/lib/runner-sandbox.ts
|
|
5748
|
-
import { relative as relative2, resolve as
|
|
5844
|
+
import { relative as relative2, resolve as resolve6 } from "path";
|
|
5749
5845
|
function normalizePath2(path) {
|
|
5750
|
-
return
|
|
5846
|
+
return resolve6(path);
|
|
5751
5847
|
}
|
|
5752
5848
|
function unique3(values) {
|
|
5753
5849
|
return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));
|
|
@@ -5940,7 +6036,7 @@ var init_runner_sandbox = __esm(() => {
|
|
|
5940
6036
|
// src/lib/event-hooks.ts
|
|
5941
6037
|
import { createHash as createHash2, randomUUID } from "crypto";
|
|
5942
6038
|
import { appendFileSync, mkdirSync as mkdirSync3 } from "fs";
|
|
5943
|
-
import { dirname as dirname3, resolve as
|
|
6039
|
+
import { dirname as dirname3, resolve as resolve7 } from "path";
|
|
5944
6040
|
import { createConnection } from "net";
|
|
5945
6041
|
function safeName(name) {
|
|
5946
6042
|
const trimmed = name.trim();
|
|
@@ -6078,7 +6174,7 @@ async function deliverHook(hook, envelope) {
|
|
|
6078
6174
|
if (hook.target === "stdout") {
|
|
6079
6175
|
output = line.trim();
|
|
6080
6176
|
} else if (hook.target === "file") {
|
|
6081
|
-
const filePath =
|
|
6177
|
+
const filePath = resolve7(hook.file_path);
|
|
6082
6178
|
mkdirSync3(dirname3(filePath), { recursive: true });
|
|
6083
6179
|
appendFileSync(filePath, line);
|
|
6084
6180
|
} else if (hook.target === "socket") {
|
|
@@ -6199,9 +6295,9 @@ var init_event_hooks = __esm(() => {
|
|
|
6199
6295
|
// node_modules/.bun/@hasna+events@0.1.16/node_modules/@hasna/events/dist/index.js
|
|
6200
6296
|
import { chmod, mkdir, readFile, rename, writeFile } from "fs/promises";
|
|
6201
6297
|
import { Buffer as Buffer2 } from "buffer";
|
|
6202
|
-
import { existsSync as
|
|
6203
|
-
import { homedir as
|
|
6204
|
-
import { join as
|
|
6298
|
+
import { existsSync as existsSync6 } from "fs";
|
|
6299
|
+
import { homedir as homedir4 } from "os";
|
|
6300
|
+
import { join as join6 } from "path";
|
|
6205
6301
|
import { createHmac, timingSafeEqual } from "crypto";
|
|
6206
6302
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
6207
6303
|
import { spawn } from "child_process";
|
|
@@ -6302,7 +6398,7 @@ function channelMatchesEvent(channel, event) {
|
|
|
6302
6398
|
return channel.filters.some((filter) => eventMatchesFilter(event, filter));
|
|
6303
6399
|
}
|
|
6304
6400
|
function getEventsDataDir(override) {
|
|
6305
|
-
return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] ||
|
|
6401
|
+
return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join6(homedir4(), ".hasna", "events");
|
|
6306
6402
|
}
|
|
6307
6403
|
|
|
6308
6404
|
class JsonEventsStore {
|
|
@@ -6311,12 +6407,12 @@ class JsonEventsStore {
|
|
|
6311
6407
|
channelsPath;
|
|
6312
6408
|
eventsPath;
|
|
6313
6409
|
deliveriesPath;
|
|
6314
|
-
constructor(
|
|
6315
|
-
this.dataDir =
|
|
6316
|
-
this.runtime = localJsonRuntime(
|
|
6317
|
-
this.channelsPath =
|
|
6318
|
-
this.eventsPath =
|
|
6319
|
-
this.deliveriesPath =
|
|
6410
|
+
constructor(dataDir2 = getEventsDataDir()) {
|
|
6411
|
+
this.dataDir = dataDir2;
|
|
6412
|
+
this.runtime = localJsonRuntime(dataDir2);
|
|
6413
|
+
this.channelsPath = join6(dataDir2, "channels.json");
|
|
6414
|
+
this.eventsPath = join6(dataDir2, "events.json");
|
|
6415
|
+
this.deliveriesPath = join6(dataDir2, "deliveries.json");
|
|
6320
6416
|
}
|
|
6321
6417
|
async init() {
|
|
6322
6418
|
await mkdir(this.dataDir, { recursive: true, mode: 448 });
|
|
@@ -6433,7 +6529,7 @@ class JsonEventsStore {
|
|
|
6433
6529
|
};
|
|
6434
6530
|
}
|
|
6435
6531
|
async ensureArrayFile(path) {
|
|
6436
|
-
if (!
|
|
6532
|
+
if (!existsSync6(path)) {
|
|
6437
6533
|
await writeFile(path, `[]
|
|
6438
6534
|
`, { encoding: "utf-8", mode: 384 });
|
|
6439
6535
|
}
|
|
@@ -6463,7 +6559,7 @@ class JsonEventsStore {
|
|
|
6463
6559
|
});
|
|
6464
6560
|
}
|
|
6465
6561
|
}
|
|
6466
|
-
function localJsonRuntime(
|
|
6562
|
+
function localJsonRuntime(dataDir2 = getEventsDataDir()) {
|
|
6467
6563
|
return {
|
|
6468
6564
|
mode: "local-files",
|
|
6469
6565
|
name: "json-events-store",
|
|
@@ -6476,7 +6572,7 @@ function localJsonRuntime(dataDir = getEventsDataDir()) {
|
|
|
6476
6572
|
durable: true,
|
|
6477
6573
|
idempotency: "best-effort-local",
|
|
6478
6574
|
replayCursors: true,
|
|
6479
|
-
description: `Local JSON files in ${
|
|
6575
|
+
description: `Local JSON files in ${dataDir2}; no SQLite, Postgres, S3, or AWS runtime is configured by this store.`
|
|
6480
6576
|
};
|
|
6481
6577
|
}
|
|
6482
6578
|
function encodeLocalJsonEventCursor(offset, options = {}) {
|
|
@@ -6655,7 +6751,7 @@ async function dispatchCommand(event, channel) {
|
|
|
6655
6751
|
HASNA_EVENT_SCHEMA_VERSION: event.schemaVersion,
|
|
6656
6752
|
HASNA_EVENT_JSON: eventJson
|
|
6657
6753
|
};
|
|
6658
|
-
return new Promise((
|
|
6754
|
+
return new Promise((resolve8) => {
|
|
6659
6755
|
const child = spawn(channel.command.command, channel.command.args ?? [], {
|
|
6660
6756
|
cwd: channel.command.cwd,
|
|
6661
6757
|
env,
|
|
@@ -6673,7 +6769,7 @@ async function dispatchCommand(event, channel) {
|
|
|
6673
6769
|
});
|
|
6674
6770
|
child.on("error", (error) => {
|
|
6675
6771
|
clearTimeout(timeout);
|
|
6676
|
-
|
|
6772
|
+
resolve8({
|
|
6677
6773
|
attempt: 1,
|
|
6678
6774
|
status: "failed",
|
|
6679
6775
|
startedAt,
|
|
@@ -6686,7 +6782,7 @@ async function dispatchCommand(event, channel) {
|
|
|
6686
6782
|
child.on("close", (code, signal) => {
|
|
6687
6783
|
clearTimeout(timeout);
|
|
6688
6784
|
const success = code === 0;
|
|
6689
|
-
|
|
6785
|
+
resolve8({
|
|
6690
6786
|
attempt: 1,
|
|
6691
6787
|
status: success ? "success" : "failed",
|
|
6692
6788
|
startedAt,
|
|
@@ -7028,7 +7124,7 @@ function normalizeRetryPolicy(policy) {
|
|
|
7028
7124
|
};
|
|
7029
7125
|
}
|
|
7030
7126
|
var HASNA_EVENTS_DIR_ENV = "HASNA_EVENTS_DIR", HASNA_EVENTS_HOME_ENV = "HASNA_EVENTS_HOME", LOCAL_JSON_EVENT_CURSOR_PREFIX = "local-json-v1:", DEFAULT_EVENT_PAGE_LIMIT = 100, MAX_EVENT_PAGE_LIMIT = 1000, DEFAULT_SIGNATURE_TOLERANCE_MS, EventValidationError, defaultEventTypeCatalog, APP_EVENT_V1_MAX_DATA_BYTES;
|
|
7031
|
-
var
|
|
7127
|
+
var init_dist2 = __esm(() => {
|
|
7032
7128
|
DEFAULT_SIGNATURE_TOLERANCE_MS = 5 * 60 * 1000;
|
|
7033
7129
|
EventValidationError = class EventValidationError extends Error {
|
|
7034
7130
|
eventType;
|
|
@@ -7451,7 +7547,7 @@ function emitSharedTaskEventQuiet(input) {
|
|
|
7451
7547
|
}
|
|
7452
7548
|
var SOURCE = "todos";
|
|
7453
7549
|
var init_shared_events = __esm(() => {
|
|
7454
|
-
|
|
7550
|
+
init_dist2();
|
|
7455
7551
|
init_database();
|
|
7456
7552
|
init_projects();
|
|
7457
7553
|
init_task_lists();
|
|
@@ -7459,7 +7555,7 @@ var init_shared_events = __esm(() => {
|
|
|
7459
7555
|
});
|
|
7460
7556
|
|
|
7461
7557
|
// src/lib/secret-redaction.ts
|
|
7462
|
-
import { readFileSync as readFileSync3, existsSync as
|
|
7558
|
+
import { readFileSync as readFileSync3, existsSync as existsSync7 } from "fs";
|
|
7463
7559
|
function registerCustomRedactor(fn) {
|
|
7464
7560
|
customRedactors.push(fn);
|
|
7465
7561
|
}
|
|
@@ -7524,7 +7620,7 @@ function scanAndRedactText(text, options = {}) {
|
|
|
7524
7620
|
};
|
|
7525
7621
|
}
|
|
7526
7622
|
function scanFileForSecrets(path, options = {}) {
|
|
7527
|
-
if (!
|
|
7623
|
+
if (!existsSync7(path))
|
|
7528
7624
|
throw new Error(`File not found: ${path}`);
|
|
7529
7625
|
const content = readFileSync3(path, "utf8");
|
|
7530
7626
|
return scanAndRedactText(content, options);
|
|
@@ -9782,17 +9878,17 @@ function sanitizeCreateTaskInput(input) {
|
|
|
9782
9878
|
return {
|
|
9783
9879
|
...input,
|
|
9784
9880
|
title: sanitizePreWriteText(input.title, "task.title"),
|
|
9785
|
-
description: input.description
|
|
9881
|
+
description: input.description == null ? input.description : sanitizePreWriteText(input.description, "task.description"),
|
|
9786
9882
|
tags: input.tags !== undefined ? sanitizePreWriteValue(input.tags, "task.tags") : undefined,
|
|
9787
9883
|
metadata: input.metadata !== undefined ? sanitizePreWriteValue(input.metadata, "task.metadata") : undefined,
|
|
9788
|
-
reason: input.reason
|
|
9884
|
+
reason: input.reason == null ? input.reason : sanitizePreWriteText(input.reason, "task.reason")
|
|
9789
9885
|
};
|
|
9790
9886
|
}
|
|
9791
9887
|
function sanitizeUpdateTaskInput(input) {
|
|
9792
9888
|
return {
|
|
9793
9889
|
...input,
|
|
9794
9890
|
title: input.title !== undefined ? sanitizePreWriteText(input.title, "task.title") : undefined,
|
|
9795
|
-
description: input.description
|
|
9891
|
+
description: input.description == null ? input.description : sanitizePreWriteText(input.description, "task.description"),
|
|
9796
9892
|
tags: input.tags !== undefined ? sanitizePreWriteValue(input.tags, "task.tags") : undefined,
|
|
9797
9893
|
metadata: input.metadata !== undefined ? sanitizePreWriteValue(input.metadata, "task.metadata") : undefined
|
|
9798
9894
|
};
|
|
@@ -11646,28 +11742,28 @@ var init_boards = __esm(() => {
|
|
|
11646
11742
|
|
|
11647
11743
|
// src/lib/artifact-store.ts
|
|
11648
11744
|
import { createHash as createHash3 } from "crypto";
|
|
11649
|
-
import { existsSync as
|
|
11650
|
-
import { basename, dirname as dirname4, join as
|
|
11745
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync4, rmSync, statSync as statSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
11746
|
+
import { basename, dirname as dirname4, join as join7, resolve as resolve8 } from "path";
|
|
11651
11747
|
import { tmpdir as tmpdir2 } from "os";
|
|
11652
11748
|
function isInMemoryDb2(path) {
|
|
11653
11749
|
return path === ":memory:" || path.startsWith("file::memory:");
|
|
11654
11750
|
}
|
|
11655
11751
|
function artifactStoreRoot() {
|
|
11656
11752
|
if (process.env["HASNA_TODOS_ARTIFACTS_DIR"])
|
|
11657
|
-
return
|
|
11753
|
+
return resolve8(process.env["HASNA_TODOS_ARTIFACTS_DIR"]);
|
|
11658
11754
|
if (process.env["TODOS_ARTIFACTS_DIR"])
|
|
11659
|
-
return
|
|
11755
|
+
return resolve8(process.env["TODOS_ARTIFACTS_DIR"]);
|
|
11660
11756
|
const dbPath = getDatabasePath();
|
|
11661
11757
|
if (isInMemoryDb2(dbPath))
|
|
11662
|
-
return
|
|
11663
|
-
return
|
|
11758
|
+
return join7(tmpdir2(), "hasna-todos-artifacts");
|
|
11759
|
+
return join7(dirname4(resolve8(dbPath)), "artifacts");
|
|
11664
11760
|
}
|
|
11665
11761
|
function artifactStorePath(relativePath) {
|
|
11666
11762
|
const normalized = relativePath.replace(/\\/g, "/");
|
|
11667
11763
|
if (normalized.includes("..") || normalized.startsWith("/") || normalized.length === 0) {
|
|
11668
11764
|
throw new Error("Invalid artifact store path");
|
|
11669
11765
|
}
|
|
11670
|
-
return
|
|
11766
|
+
return join7(artifactStoreRoot(), normalized);
|
|
11671
11767
|
}
|
|
11672
11768
|
function sha256(buffer) {
|
|
11673
11769
|
return createHash3("sha256").update(buffer).digest("hex");
|
|
@@ -11707,8 +11803,8 @@ function mediaTypeFor(path, textLike) {
|
|
|
11707
11803
|
return "application/octet-stream";
|
|
11708
11804
|
}
|
|
11709
11805
|
function storeArtifactContent(input) {
|
|
11710
|
-
const sourcePath =
|
|
11711
|
-
if (!
|
|
11806
|
+
const sourcePath = resolve8(input.path);
|
|
11807
|
+
if (!existsSync8(sourcePath))
|
|
11712
11808
|
return null;
|
|
11713
11809
|
const sourceStat = statSync2(sourcePath);
|
|
11714
11810
|
if (!sourceStat.isFile())
|
|
@@ -11725,9 +11821,9 @@ function storeArtifactContent(input) {
|
|
|
11725
11821
|
redactionStatus = "redacted";
|
|
11726
11822
|
}
|
|
11727
11823
|
const storedSha = sha256(storedBuffer);
|
|
11728
|
-
const relativePath =
|
|
11824
|
+
const relativePath = join7("sha256", storedSha.slice(0, 2), storedSha).replace(/\\/g, "/");
|
|
11729
11825
|
const destination = artifactStorePath(relativePath);
|
|
11730
|
-
if (!
|
|
11826
|
+
if (!existsSync8(destination)) {
|
|
11731
11827
|
mkdirSync4(dirname4(destination), { recursive: true });
|
|
11732
11828
|
writeFileSync2(destination, storedBuffer);
|
|
11733
11829
|
}
|
|
@@ -11787,7 +11883,7 @@ function verifyStoredArtifact(input) {
|
|
|
11787
11883
|
};
|
|
11788
11884
|
}
|
|
11789
11885
|
const storedPath = artifactStorePath(store.relative_path);
|
|
11790
|
-
if (!
|
|
11886
|
+
if (!existsSync8(storedPath)) {
|
|
11791
11887
|
return {
|
|
11792
11888
|
id: input.id,
|
|
11793
11889
|
path: input.path,
|
|
@@ -11862,20 +11958,20 @@ function importStoredArtifactContent(content) {
|
|
|
11862
11958
|
}
|
|
11863
11959
|
function getArtifactStoreRoot(dbPath) {
|
|
11864
11960
|
if (process.env["HASNA_TODOS_ARTIFACTS_DIR"])
|
|
11865
|
-
return
|
|
11961
|
+
return resolve8(process.env["HASNA_TODOS_ARTIFACTS_DIR"]);
|
|
11866
11962
|
if (process.env["TODOS_ARTIFACTS_DIR"])
|
|
11867
|
-
return
|
|
11963
|
+
return resolve8(process.env["TODOS_ARTIFACTS_DIR"]);
|
|
11868
11964
|
const path = dbPath ?? getDatabasePath();
|
|
11869
11965
|
if (isInMemoryDb2(path))
|
|
11870
|
-
return
|
|
11871
|
-
return
|
|
11966
|
+
return join7(tmpdir2(), "hasna-todos-artifacts");
|
|
11967
|
+
return join7(dirname4(resolve8(path)), "artifacts");
|
|
11872
11968
|
}
|
|
11873
11969
|
function computeContentHash(path) {
|
|
11874
|
-
return sha256(readFileSync4(
|
|
11970
|
+
return sha256(readFileSync4(resolve8(path)));
|
|
11875
11971
|
}
|
|
11876
11972
|
function storeArtifactFile(input) {
|
|
11877
|
-
const sourcePath =
|
|
11878
|
-
if (!
|
|
11973
|
+
const sourcePath = resolve8(input.sourcePath);
|
|
11974
|
+
if (!existsSync8(sourcePath)) {
|
|
11879
11975
|
throw new Error(`Source file not found: ${input.sourcePath}`);
|
|
11880
11976
|
}
|
|
11881
11977
|
if (!statSync2(sourcePath).isFile()) {
|
|
@@ -11888,7 +11984,7 @@ function storeArtifactFile(input) {
|
|
|
11888
11984
|
let localPath = sourcePath;
|
|
11889
11985
|
if (storageMode === "copy") {
|
|
11890
11986
|
const fileName = input.name && input.name.trim().length > 0 ? basename(input.name) : basename(sourcePath);
|
|
11891
|
-
const destination =
|
|
11987
|
+
const destination = join7(getArtifactStoreRoot(input.dbPath), input.artifactId, fileName);
|
|
11892
11988
|
mkdirSync4(dirname4(destination), { recursive: true });
|
|
11893
11989
|
writeFileSync2(destination, buffer);
|
|
11894
11990
|
localPath = destination;
|
|
@@ -11898,7 +11994,7 @@ function storeArtifactFile(input) {
|
|
|
11898
11994
|
function deleteStoredArtifactFile(localPath, storageMode, _dbPath2) {
|
|
11899
11995
|
if (storageMode === "reference")
|
|
11900
11996
|
return false;
|
|
11901
|
-
if (!localPath || !
|
|
11997
|
+
if (!localPath || !existsSync8(localPath))
|
|
11902
11998
|
return false;
|
|
11903
11999
|
rmSync(localPath, { force: true });
|
|
11904
12000
|
try {
|
|
@@ -11923,7 +12019,7 @@ function buildArtifactExportManifest(artifacts, dbPath) {
|
|
|
11923
12019
|
};
|
|
11924
12020
|
}
|
|
11925
12021
|
function writeArtifactExportManifest(manifest, outputPath) {
|
|
11926
|
-
const destination =
|
|
12022
|
+
const destination = resolve8(outputPath);
|
|
11927
12023
|
mkdirSync4(dirname4(destination), { recursive: true });
|
|
11928
12024
|
writeFileSync2(destination, `${JSON.stringify(manifest, null, 2)}
|
|
11929
12025
|
`);
|
|
@@ -13080,7 +13176,7 @@ var init_tasks = __esm(() => {
|
|
|
13080
13176
|
// package.json
|
|
13081
13177
|
var package_default = {
|
|
13082
13178
|
name: "@hasna/todos",
|
|
13083
|
-
version: "0.15.
|
|
13179
|
+
version: "0.15.52",
|
|
13084
13180
|
description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
|
|
13085
13181
|
type: "module",
|
|
13086
13182
|
main: "dist/index.js",
|
|
@@ -13139,6 +13235,7 @@ var package_default = {
|
|
|
13139
13235
|
files: [
|
|
13140
13236
|
"dist",
|
|
13141
13237
|
"dashboard/dist",
|
|
13238
|
+
"postinstall.js",
|
|
13142
13239
|
"LICENSE",
|
|
13143
13240
|
"README.md"
|
|
13144
13241
|
],
|
|
@@ -13165,7 +13262,7 @@ var package_default = {
|
|
|
13165
13262
|
"test:attested-container-compatibility-vector": "bun test scripts/attested-container-compatibility-vector.test.ts",
|
|
13166
13263
|
"issue:release-review": "bun run scripts/issue-npm-release-agent-review.ts",
|
|
13167
13264
|
prepublishOnly: "bun run scripts/verify-public-release.ts --mode=publish",
|
|
13168
|
-
postinstall: "
|
|
13265
|
+
postinstall: "node postinstall.js"
|
|
13169
13266
|
},
|
|
13170
13267
|
keywords: [
|
|
13171
13268
|
"todos",
|
|
@@ -13199,13 +13296,15 @@ var package_default = {
|
|
|
13199
13296
|
author: "Andrei Hasna <andrei@hasna.com>",
|
|
13200
13297
|
license: "Apache-2.0",
|
|
13201
13298
|
dependencies: {
|
|
13202
|
-
"@hasna/contracts": "0.14.
|
|
13299
|
+
"@hasna/contracts": "0.14.2",
|
|
13203
13300
|
"@hasna/events": "^0.1.11",
|
|
13301
|
+
"@hasna/paths": "0.1.0",
|
|
13204
13302
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
13205
13303
|
chalk: "^5.4.1",
|
|
13206
13304
|
commander: "^13.1.0",
|
|
13207
13305
|
ink: "^5.2.0",
|
|
13208
13306
|
react: "^18.3.1",
|
|
13307
|
+
"signal-exit": "3.0.7",
|
|
13209
13308
|
zod: "3.25.76"
|
|
13210
13309
|
},
|
|
13211
13310
|
overrides: {
|
|
@@ -13214,7 +13313,7 @@ var package_default = {
|
|
|
13214
13313
|
zod: "3.25.76"
|
|
13215
13314
|
},
|
|
13216
13315
|
devDependencies: {
|
|
13217
|
-
"@types/bun": "
|
|
13316
|
+
"@types/bun": "1.3.14",
|
|
13218
13317
|
"@types/react": "^18.3.18",
|
|
13219
13318
|
"bun-types": "1.3.9",
|
|
13220
13319
|
"hasna-deployment-contracts": "npm:@hasna/contracts@0.10.4",
|
|
@@ -16440,7 +16539,7 @@ function todosAiExitCodeForResult(result) {
|
|
|
16440
16539
|
}
|
|
16441
16540
|
// src/lib/onboarding-fixtures.ts
|
|
16442
16541
|
import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
16443
|
-
import { join as
|
|
16542
|
+
import { join as join8 } from "path";
|
|
16444
16543
|
|
|
16445
16544
|
// src/lib/local-bridge.ts
|
|
16446
16545
|
init_database();
|
|
@@ -17377,7 +17476,7 @@ function writeOnboardingFixtureFiles(directory) {
|
|
|
17377
17476
|
mkdirSync5(directory, { recursive: true });
|
|
17378
17477
|
const files = [];
|
|
17379
17478
|
for (const fixture of allFixtures()) {
|
|
17380
|
-
const path =
|
|
17479
|
+
const path = join8(directory, `${fixture.summary.name}.bridge.json`);
|
|
17381
17480
|
writeFileSync3(path, `${JSON.stringify(fixture.bundle, null, 2)}
|
|
17382
17481
|
`, "utf-8");
|
|
17383
17482
|
files.push(path);
|
|
@@ -17395,7 +17494,7 @@ function importOnboardingFixture(options = {}) {
|
|
|
17395
17494
|
init_database();
|
|
17396
17495
|
import { createHash as createHash4 } from "crypto";
|
|
17397
17496
|
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
17398
|
-
import { dirname as dirname5, resolve as
|
|
17497
|
+
import { dirname as dirname5, resolve as resolve9 } from "path";
|
|
17399
17498
|
import { mkdirSync as mkdirSync6 } from "fs";
|
|
17400
17499
|
var TODOS_LOCAL_BACKUP_KIND = "hasna.todos.local-backup";
|
|
17401
17500
|
var TODOS_LOCAL_BACKUP_SCHEMA_VERSION = 1;
|
|
@@ -17502,14 +17601,14 @@ function createLocalBackup(options = {}, db) {
|
|
|
17502
17601
|
return backup;
|
|
17503
17602
|
}
|
|
17504
17603
|
function writeLocalBackupFile(backup, outputPath) {
|
|
17505
|
-
const path =
|
|
17604
|
+
const path = resolve9(outputPath);
|
|
17506
17605
|
mkdirSync6(dirname5(path), { recursive: true });
|
|
17507
17606
|
writeFileSync4(path, `${JSON.stringify(backup, null, 2)}
|
|
17508
17607
|
`);
|
|
17509
17608
|
return path;
|
|
17510
17609
|
}
|
|
17511
17610
|
function readLocalBackupFile(path) {
|
|
17512
|
-
return JSON.parse(readFileSync5(
|
|
17611
|
+
return JSON.parse(readFileSync5(resolve9(path), "utf-8"));
|
|
17513
17612
|
}
|
|
17514
17613
|
function verifyLocalBackup(value, options = {}, db) {
|
|
17515
17614
|
const verifiedAt = options.verified_at ?? now();
|
|
@@ -18203,7 +18302,7 @@ function renderLocalSnapshotMarkdown(snapshot) {
|
|
|
18203
18302
|
}
|
|
18204
18303
|
// src/lib/sdk-integration-fixtures.ts
|
|
18205
18304
|
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync5 } from "fs";
|
|
18206
|
-
import { join as
|
|
18305
|
+
import { join as join9 } from "path";
|
|
18207
18306
|
|
|
18208
18307
|
// src/cli-mcp-parity.ts
|
|
18209
18308
|
function source4(version) {
|
|
@@ -20174,7 +20273,7 @@ function writeSdkIntegrationFixtures(directory, options = {}) {
|
|
|
20174
20273
|
];
|
|
20175
20274
|
const written = [];
|
|
20176
20275
|
for (const [name, payload] of files) {
|
|
20177
|
-
const file =
|
|
20276
|
+
const file = join9(directory, name);
|
|
20178
20277
|
writeFileSync5(file, `${JSON.stringify(payload, null, 2)}
|
|
20179
20278
|
`, "utf-8");
|
|
20180
20279
|
written.push(file);
|
|
@@ -21457,7 +21556,7 @@ function renderLocalAuditLedgerMarkdown(ledger) {
|
|
|
21457
21556
|
init_migrations();
|
|
21458
21557
|
init_schema();
|
|
21459
21558
|
import { readFileSync as readFileSync6 } from "fs";
|
|
21460
|
-
import { join as
|
|
21559
|
+
import { join as join10, resolve as resolve10 } from "path";
|
|
21461
21560
|
import { Database as Database2 } from "bun:sqlite";
|
|
21462
21561
|
var LOCAL_RELEASE_COMPATIBILITY_SCHEMA_VERSION = 1;
|
|
21463
21562
|
var EXPECTED_PACKAGE_NAME = "@hasna/todos";
|
|
@@ -21503,7 +21602,7 @@ function warn(id, message, details) {
|
|
|
21503
21602
|
return { id, status: "warning", message, details };
|
|
21504
21603
|
}
|
|
21505
21604
|
function readPackageJson(root) {
|
|
21506
|
-
return JSON.parse(readFileSync6(
|
|
21605
|
+
return JSON.parse(readFileSync6(join10(root, "package.json"), "utf8"));
|
|
21507
21606
|
}
|
|
21508
21607
|
function sortedKeys(value) {
|
|
21509
21608
|
return Object.keys(value ?? {}).sort((left, right) => left.localeCompare(right));
|
|
@@ -21599,7 +21698,7 @@ function checkChangelog() {
|
|
|
21599
21698
|
];
|
|
21600
21699
|
}
|
|
21601
21700
|
function createReleaseCompatibilityReport(options = {}) {
|
|
21602
|
-
const root =
|
|
21701
|
+
const root = resolve10(options.root ?? process.cwd());
|
|
21603
21702
|
const packageJson = readPackageJson(root);
|
|
21604
21703
|
const simulatedLevels = options.simulated_levels ?? defaultSimulationLevels();
|
|
21605
21704
|
const checks = [
|