@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/mcp/index.js
CHANGED
|
@@ -4089,18 +4089,112 @@ var init_identity_mapping = __esm(() => {
|
|
|
4089
4089
|
});
|
|
4090
4090
|
});
|
|
4091
4091
|
|
|
4092
|
-
//
|
|
4093
|
-
import { existsSync as existsSync2, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
|
|
4092
|
+
// node_modules/.bun/@hasna+paths@0.1.0/node_modules/@hasna/paths/dist/index.js
|
|
4094
4093
|
import { homedir } from "os";
|
|
4095
4094
|
import { join } from "path";
|
|
4095
|
+
function assertApp(app) {
|
|
4096
|
+
if (typeof app !== "string" || app.length === 0) {
|
|
4097
|
+
throw new TypeError("paths: app must be a non-empty string");
|
|
4098
|
+
}
|
|
4099
|
+
if (!APP_SLUG_RE.test(app)) {
|
|
4100
|
+
throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
|
|
4101
|
+
}
|
|
4102
|
+
}
|
|
4103
|
+
function envOf(options) {
|
|
4104
|
+
return options.env ?? process.env;
|
|
4105
|
+
}
|
|
4106
|
+
function envValue(options, kind) {
|
|
4107
|
+
const value = envOf(options)[KIND_ENV[kind]];
|
|
4108
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
4109
|
+
}
|
|
4110
|
+
function isMacOS(platform) {
|
|
4111
|
+
return platform === "darwin";
|
|
4112
|
+
}
|
|
4113
|
+
function baseDir(kind, options) {
|
|
4114
|
+
const override = envValue(options, kind);
|
|
4115
|
+
if (override)
|
|
4116
|
+
return override;
|
|
4117
|
+
const home = options.home ?? homedir();
|
|
4118
|
+
const platform = options.platform ?? process.platform;
|
|
4119
|
+
if (isMacOS(platform)) {
|
|
4120
|
+
switch (kind) {
|
|
4121
|
+
case "config":
|
|
4122
|
+
case "data":
|
|
4123
|
+
return join(home, "Library", "Application Support", "Hasna");
|
|
4124
|
+
case "cache":
|
|
4125
|
+
return join(home, "Library", "Caches", "Hasna");
|
|
4126
|
+
case "state":
|
|
4127
|
+
return join(home, "Library", "Logs", "Hasna");
|
|
4128
|
+
}
|
|
4129
|
+
}
|
|
4130
|
+
switch (kind) {
|
|
4131
|
+
case "config":
|
|
4132
|
+
return join(home, ".config", "hasna");
|
|
4133
|
+
case "data":
|
|
4134
|
+
return join(home, ".local", "share", "hasna");
|
|
4135
|
+
case "state":
|
|
4136
|
+
return join(home, ".local", "state", "hasna");
|
|
4137
|
+
case "cache":
|
|
4138
|
+
return join(home, ".cache", "hasna");
|
|
4139
|
+
}
|
|
4140
|
+
}
|
|
4141
|
+
function resolvePath(kind, options) {
|
|
4142
|
+
assertApp(options.app);
|
|
4143
|
+
const appSegment = options.internal === true ? join("internal", options.app) : options.app;
|
|
4144
|
+
return join(baseDir(kind, options), appSegment);
|
|
4145
|
+
}
|
|
4146
|
+
function dataDir(options) {
|
|
4147
|
+
return resolvePath("data", options);
|
|
4148
|
+
}
|
|
4149
|
+
var KIND_ENV, APP_SLUG_RE;
|
|
4150
|
+
var init_dist = __esm(() => {
|
|
4151
|
+
KIND_ENV = {
|
|
4152
|
+
config: "HASNA_CONFIG_HOME",
|
|
4153
|
+
data: "HASNA_DATA_HOME",
|
|
4154
|
+
state: "HASNA_STATE_HOME",
|
|
4155
|
+
cache: "HASNA_CACHE_HOME"
|
|
4156
|
+
};
|
|
4157
|
+
APP_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
4158
|
+
});
|
|
4159
|
+
|
|
4160
|
+
// src/lib/paths.ts
|
|
4161
|
+
import { existsSync as existsSync2 } from "fs";
|
|
4162
|
+
import { homedir as homedir2 } from "os";
|
|
4163
|
+
import { join as join2, resolve as resolve2 } from "path";
|
|
4164
|
+
function effectiveHome(env = process.env) {
|
|
4165
|
+
return env.HOME || env.USERPROFILE || homedir2();
|
|
4166
|
+
}
|
|
4167
|
+
function legacyHomeDir(env = process.env) {
|
|
4168
|
+
return join2(effectiveHome(env), ".hasna", "todos");
|
|
4169
|
+
}
|
|
4170
|
+
function resolverHome(env = process.env) {
|
|
4171
|
+
return dataDir({ app: "todos", home: effectiveHome(env), env });
|
|
4172
|
+
}
|
|
4173
|
+
function adoptResolverHome(resolved, env = process.env) {
|
|
4174
|
+
const dataOverride = env.HASNA_DATA_HOME;
|
|
4175
|
+
if (typeof dataOverride === "string" && dataOverride.trim().length > 0)
|
|
4176
|
+
return true;
|
|
4177
|
+
return existsSync2(join2(resolved, "todos.db")) || existsSync2(join2(resolved, "config.json"));
|
|
4178
|
+
}
|
|
4179
|
+
function getTodosDir(env = process.env) {
|
|
4180
|
+
const resolved = resolverHome(env);
|
|
4181
|
+
return resolve2(adoptResolverHome(resolved, env) ? resolved : legacyHomeDir(env));
|
|
4182
|
+
}
|
|
4183
|
+
var init_paths = __esm(() => {
|
|
4184
|
+
init_dist();
|
|
4185
|
+
});
|
|
4186
|
+
|
|
4187
|
+
// src/lib/sync-utils.ts
|
|
4188
|
+
import { existsSync as existsSync3, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
|
|
4189
|
+
import { homedir as homedir3 } from "os";
|
|
4096
4190
|
function getHomeDir() {
|
|
4097
|
-
return process.env["HOME"] || process.env["USERPROFILE"] ||
|
|
4191
|
+
return process.env["HOME"] || process.env["USERPROFILE"] || homedir3();
|
|
4098
4192
|
}
|
|
4099
4193
|
function getTodosGlobalDir() {
|
|
4100
|
-
return
|
|
4194
|
+
return getTodosDir();
|
|
4101
4195
|
}
|
|
4102
4196
|
function ensureDir(dir) {
|
|
4103
|
-
if (!
|
|
4197
|
+
if (!existsSync3(dir))
|
|
4104
4198
|
mkdirSync(dir, { recursive: true });
|
|
4105
4199
|
}
|
|
4106
4200
|
function readJsonFile(path) {
|
|
@@ -4121,6 +4215,7 @@ function appendSyncConflict(metadata, conflict, limit = 5) {
|
|
|
4121
4215
|
}
|
|
4122
4216
|
var HOME;
|
|
4123
4217
|
var init_sync_utils = __esm(() => {
|
|
4218
|
+
init_paths();
|
|
4124
4219
|
HOME = getHomeDir();
|
|
4125
4220
|
});
|
|
4126
4221
|
|
|
@@ -4431,18 +4526,18 @@ __export(exports_database, {
|
|
|
4431
4526
|
LOCK_EXPIRY_MINUTES: () => LOCK_EXPIRY_MINUTES
|
|
4432
4527
|
});
|
|
4433
4528
|
import { Database } from "bun:sqlite";
|
|
4434
|
-
import { existsSync as
|
|
4435
|
-
import { dirname, join as
|
|
4529
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync2 } from "fs";
|
|
4530
|
+
import { dirname, join as join3, resolve as resolve3 } from "path";
|
|
4436
4531
|
function isInMemoryDb(path) {
|
|
4437
4532
|
return path === ":memory:" || path.startsWith("file::memory:");
|
|
4438
4533
|
}
|
|
4439
4534
|
function findNearestProjectDb(startDir) {
|
|
4440
4535
|
const gitRoot = findGitRoot(startDir);
|
|
4441
|
-
const stopAt = gitRoot ?
|
|
4442
|
-
let dir =
|
|
4536
|
+
const stopAt = gitRoot ? resolve3(gitRoot) : resolve3(startDir);
|
|
4537
|
+
let dir = resolve3(startDir);
|
|
4443
4538
|
while (true) {
|
|
4444
|
-
const candidate =
|
|
4445
|
-
if (
|
|
4539
|
+
const candidate = join3(dir, ".hasna", "todos", "todos.db");
|
|
4540
|
+
if (existsSync4(candidate))
|
|
4446
4541
|
return candidate;
|
|
4447
4542
|
if (dir === stopAt)
|
|
4448
4543
|
break;
|
|
@@ -4454,9 +4549,9 @@ function findNearestProjectDb(startDir) {
|
|
|
4454
4549
|
return null;
|
|
4455
4550
|
}
|
|
4456
4551
|
function findGitRoot(startDir) {
|
|
4457
|
-
let dir =
|
|
4552
|
+
let dir = resolve3(startDir);
|
|
4458
4553
|
while (true) {
|
|
4459
|
-
if (
|
|
4554
|
+
if (existsSync4(join3(dir, ".git")))
|
|
4460
4555
|
return dir;
|
|
4461
4556
|
const parent = dirname(dir);
|
|
4462
4557
|
if (parent === dir)
|
|
@@ -4466,7 +4561,7 @@ function findGitRoot(startDir) {
|
|
|
4466
4561
|
return null;
|
|
4467
4562
|
}
|
|
4468
4563
|
function getGlobalDbPath() {
|
|
4469
|
-
return
|
|
4564
|
+
return join3(getTodosGlobalDir(), "todos.db");
|
|
4470
4565
|
}
|
|
4471
4566
|
function hasExplicitProjectArg(args = process.argv.slice(2)) {
|
|
4472
4567
|
return args.some((arg) => arg === "--project" || arg.startsWith("--project="));
|
|
@@ -4504,7 +4599,7 @@ function getDbPath() {
|
|
|
4504
4599
|
if (process.env["TODOS_DB_SCOPE"] === "project") {
|
|
4505
4600
|
const gitRoot = findGitRoot(cwd);
|
|
4506
4601
|
if (gitRoot && canCreateScopedProjectDb()) {
|
|
4507
|
-
return
|
|
4602
|
+
return join3(gitRoot, ".hasna", "todos", "todos.db");
|
|
4508
4603
|
}
|
|
4509
4604
|
}
|
|
4510
4605
|
return getGlobalDbPath();
|
|
@@ -4515,8 +4610,8 @@ function getDatabasePath() {
|
|
|
4515
4610
|
function ensureDir2(filePath) {
|
|
4516
4611
|
if (isInMemoryDb(filePath))
|
|
4517
4612
|
return;
|
|
4518
|
-
const dir = dirname(
|
|
4519
|
-
if (!
|
|
4613
|
+
const dir = dirname(resolve3(filePath));
|
|
4614
|
+
if (!existsSync4(dir)) {
|
|
4520
4615
|
mkdirSync2(dir, { recursive: true });
|
|
4521
4616
|
}
|
|
4522
4617
|
}
|
|
@@ -9433,15 +9528,15 @@ var init_zod = __esm(() => {
|
|
|
9433
9528
|
});
|
|
9434
9529
|
|
|
9435
9530
|
// src/lib/config.ts
|
|
9436
|
-
import { existsSync as
|
|
9437
|
-
import { dirname as dirname2, join as
|
|
9531
|
+
import { existsSync as existsSync5, readFileSync as readFileSync2 } from "fs";
|
|
9532
|
+
import { dirname as dirname2, join as join4 } from "path";
|
|
9438
9533
|
function getConfigPath() {
|
|
9439
|
-
return
|
|
9534
|
+
return join4(getTodosGlobalDir(), "config.json");
|
|
9440
9535
|
}
|
|
9441
9536
|
function loadConfig() {
|
|
9442
9537
|
if (cached)
|
|
9443
9538
|
return cached;
|
|
9444
|
-
if (!
|
|
9539
|
+
if (!existsSync5(getConfigPath())) {
|
|
9445
9540
|
cached = {};
|
|
9446
9541
|
return cached;
|
|
9447
9542
|
}
|
|
@@ -10404,14 +10499,14 @@ var init_completion_guard = __esm(() => {
|
|
|
10404
10499
|
|
|
10405
10500
|
// src/lib/event-emission-safety.ts
|
|
10406
10501
|
import { tmpdir } from "os";
|
|
10407
|
-
import { resolve as
|
|
10502
|
+
import { resolve as resolve4, sep } from "path";
|
|
10408
10503
|
function envFlag(name) {
|
|
10409
10504
|
const value = process.env[name]?.trim().toLowerCase();
|
|
10410
10505
|
return value === "1" || value === "true" || value === "yes" || value === "on";
|
|
10411
10506
|
}
|
|
10412
10507
|
function isUnder(parent, child) {
|
|
10413
|
-
const normalizedParent =
|
|
10414
|
-
const normalizedChild =
|
|
10508
|
+
const normalizedParent = resolve4(parent);
|
|
10509
|
+
const normalizedChild = resolve4(child);
|
|
10415
10510
|
return normalizedChild === normalizedParent || normalizedChild.startsWith(`${normalizedParent}${sep}`);
|
|
10416
10511
|
}
|
|
10417
10512
|
function databasePathFromDatabase(db) {
|
|
@@ -10454,9 +10549,9 @@ var init_event_emission_safety = __esm(() => {
|
|
|
10454
10549
|
});
|
|
10455
10550
|
|
|
10456
10551
|
// src/lib/workspace-trust.ts
|
|
10457
|
-
import { relative, resolve as
|
|
10552
|
+
import { relative, resolve as resolve5 } from "path";
|
|
10458
10553
|
function normalizePath(path) {
|
|
10459
|
-
return
|
|
10554
|
+
return resolve5(path);
|
|
10460
10555
|
}
|
|
10461
10556
|
function unique2(values) {
|
|
10462
10557
|
return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));
|
|
@@ -10638,9 +10733,9 @@ var init_workspace_trust = __esm(() => {
|
|
|
10638
10733
|
});
|
|
10639
10734
|
|
|
10640
10735
|
// src/lib/runner-sandbox.ts
|
|
10641
|
-
import { relative as relative2, resolve as
|
|
10736
|
+
import { relative as relative2, resolve as resolve6 } from "path";
|
|
10642
10737
|
function normalizePath2(path) {
|
|
10643
|
-
return
|
|
10738
|
+
return resolve6(path);
|
|
10644
10739
|
}
|
|
10645
10740
|
function unique3(values) {
|
|
10646
10741
|
return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));
|
|
@@ -10830,7 +10925,7 @@ var init_runner_sandbox = __esm(() => {
|
|
|
10830
10925
|
// src/lib/event-hooks.ts
|
|
10831
10926
|
import { createHash, randomUUID } from "crypto";
|
|
10832
10927
|
import { appendFileSync, mkdirSync as mkdirSync3 } from "fs";
|
|
10833
|
-
import { dirname as dirname3, resolve as
|
|
10928
|
+
import { dirname as dirname3, resolve as resolve7 } from "path";
|
|
10834
10929
|
import { createConnection } from "net";
|
|
10835
10930
|
function safeName(name) {
|
|
10836
10931
|
const trimmed = name.trim();
|
|
@@ -10968,7 +11063,7 @@ async function deliverHook(hook, envelope) {
|
|
|
10968
11063
|
if (hook.target === "stdout") {
|
|
10969
11064
|
output = line.trim();
|
|
10970
11065
|
} else if (hook.target === "file") {
|
|
10971
|
-
const filePath =
|
|
11066
|
+
const filePath = resolve7(hook.file_path);
|
|
10972
11067
|
mkdirSync3(dirname3(filePath), { recursive: true });
|
|
10973
11068
|
appendFileSync(filePath, line);
|
|
10974
11069
|
} else if (hook.target === "socket") {
|
|
@@ -11089,9 +11184,9 @@ var init_event_hooks = __esm(() => {
|
|
|
11089
11184
|
// node_modules/.bun/@hasna+events@0.1.16/node_modules/@hasna/events/dist/index.js
|
|
11090
11185
|
import { chmod, mkdir, readFile, rename, writeFile } from "fs/promises";
|
|
11091
11186
|
import { Buffer as Buffer2 } from "buffer";
|
|
11092
|
-
import { existsSync as
|
|
11093
|
-
import { homedir as
|
|
11094
|
-
import { join as
|
|
11187
|
+
import { existsSync as existsSync6 } from "fs";
|
|
11188
|
+
import { homedir as homedir4 } from "os";
|
|
11189
|
+
import { join as join5 } from "path";
|
|
11095
11190
|
import { createHmac, timingSafeEqual } from "crypto";
|
|
11096
11191
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
11097
11192
|
import { spawn } from "child_process";
|
|
@@ -11192,7 +11287,7 @@ function channelMatchesEvent(channel, event) {
|
|
|
11192
11287
|
return channel.filters.some((filter) => eventMatchesFilter(event, filter));
|
|
11193
11288
|
}
|
|
11194
11289
|
function getEventsDataDir(override) {
|
|
11195
|
-
return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] ||
|
|
11290
|
+
return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join5(homedir4(), ".hasna", "events");
|
|
11196
11291
|
}
|
|
11197
11292
|
|
|
11198
11293
|
class JsonEventsStore {
|
|
@@ -11201,12 +11296,12 @@ class JsonEventsStore {
|
|
|
11201
11296
|
channelsPath;
|
|
11202
11297
|
eventsPath;
|
|
11203
11298
|
deliveriesPath;
|
|
11204
|
-
constructor(
|
|
11205
|
-
this.dataDir =
|
|
11206
|
-
this.runtime = localJsonRuntime(
|
|
11207
|
-
this.channelsPath =
|
|
11208
|
-
this.eventsPath =
|
|
11209
|
-
this.deliveriesPath =
|
|
11299
|
+
constructor(dataDir2 = getEventsDataDir()) {
|
|
11300
|
+
this.dataDir = dataDir2;
|
|
11301
|
+
this.runtime = localJsonRuntime(dataDir2);
|
|
11302
|
+
this.channelsPath = join5(dataDir2, "channels.json");
|
|
11303
|
+
this.eventsPath = join5(dataDir2, "events.json");
|
|
11304
|
+
this.deliveriesPath = join5(dataDir2, "deliveries.json");
|
|
11210
11305
|
}
|
|
11211
11306
|
async init() {
|
|
11212
11307
|
await mkdir(this.dataDir, { recursive: true, mode: 448 });
|
|
@@ -11323,7 +11418,7 @@ class JsonEventsStore {
|
|
|
11323
11418
|
};
|
|
11324
11419
|
}
|
|
11325
11420
|
async ensureArrayFile(path) {
|
|
11326
|
-
if (!
|
|
11421
|
+
if (!existsSync6(path)) {
|
|
11327
11422
|
await writeFile(path, `[]
|
|
11328
11423
|
`, { encoding: "utf-8", mode: 384 });
|
|
11329
11424
|
}
|
|
@@ -11353,7 +11448,7 @@ class JsonEventsStore {
|
|
|
11353
11448
|
});
|
|
11354
11449
|
}
|
|
11355
11450
|
}
|
|
11356
|
-
function localJsonRuntime(
|
|
11451
|
+
function localJsonRuntime(dataDir2 = getEventsDataDir()) {
|
|
11357
11452
|
return {
|
|
11358
11453
|
mode: "local-files",
|
|
11359
11454
|
name: "json-events-store",
|
|
@@ -11366,7 +11461,7 @@ function localJsonRuntime(dataDir = getEventsDataDir()) {
|
|
|
11366
11461
|
durable: true,
|
|
11367
11462
|
idempotency: "best-effort-local",
|
|
11368
11463
|
replayCursors: true,
|
|
11369
|
-
description: `Local JSON files in ${
|
|
11464
|
+
description: `Local JSON files in ${dataDir2}; no SQLite, Postgres, S3, or AWS runtime is configured by this store.`
|
|
11370
11465
|
};
|
|
11371
11466
|
}
|
|
11372
11467
|
function encodeLocalJsonEventCursor(offset, options = {}) {
|
|
@@ -11545,7 +11640,7 @@ async function dispatchCommand(event, channel) {
|
|
|
11545
11640
|
HASNA_EVENT_SCHEMA_VERSION: event.schemaVersion,
|
|
11546
11641
|
HASNA_EVENT_JSON: eventJson
|
|
11547
11642
|
};
|
|
11548
|
-
return new Promise((
|
|
11643
|
+
return new Promise((resolve8) => {
|
|
11549
11644
|
const child = spawn(channel.command.command, channel.command.args ?? [], {
|
|
11550
11645
|
cwd: channel.command.cwd,
|
|
11551
11646
|
env,
|
|
@@ -11563,7 +11658,7 @@ async function dispatchCommand(event, channel) {
|
|
|
11563
11658
|
});
|
|
11564
11659
|
child.on("error", (error) => {
|
|
11565
11660
|
clearTimeout(timeout);
|
|
11566
|
-
|
|
11661
|
+
resolve8({
|
|
11567
11662
|
attempt: 1,
|
|
11568
11663
|
status: "failed",
|
|
11569
11664
|
startedAt,
|
|
@@ -11576,7 +11671,7 @@ async function dispatchCommand(event, channel) {
|
|
|
11576
11671
|
child.on("close", (code, signal) => {
|
|
11577
11672
|
clearTimeout(timeout);
|
|
11578
11673
|
const success = code === 0;
|
|
11579
|
-
|
|
11674
|
+
resolve8({
|
|
11580
11675
|
attempt: 1,
|
|
11581
11676
|
status: success ? "success" : "failed",
|
|
11582
11677
|
startedAt,
|
|
@@ -11918,7 +12013,7 @@ function normalizeRetryPolicy(policy) {
|
|
|
11918
12013
|
};
|
|
11919
12014
|
}
|
|
11920
12015
|
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;
|
|
11921
|
-
var
|
|
12016
|
+
var init_dist2 = __esm(() => {
|
|
11922
12017
|
DEFAULT_SIGNATURE_TOLERANCE_MS = 5 * 60 * 1000;
|
|
11923
12018
|
EventValidationError = class EventValidationError extends Error {
|
|
11924
12019
|
eventType;
|
|
@@ -12338,7 +12433,7 @@ function emitSharedTaskEventQuiet(input) {
|
|
|
12338
12433
|
}
|
|
12339
12434
|
var SOURCE = "todos";
|
|
12340
12435
|
var init_shared_events = __esm(() => {
|
|
12341
|
-
|
|
12436
|
+
init_dist2();
|
|
12342
12437
|
init_database();
|
|
12343
12438
|
init_projects();
|
|
12344
12439
|
init_task_lists();
|
|
@@ -12882,14 +12977,14 @@ var init_task_parent_integrity = __esm(() => {
|
|
|
12882
12977
|
});
|
|
12883
12978
|
|
|
12884
12979
|
// src/lib/creator-identity.ts
|
|
12885
|
-
import { existsSync as
|
|
12886
|
-
import { join as
|
|
12980
|
+
import { existsSync as existsSync7, rmSync } from "fs";
|
|
12981
|
+
import { join as join6 } from "path";
|
|
12887
12982
|
function identityFilePath() {
|
|
12888
|
-
return
|
|
12983
|
+
return join6(getTodosGlobalDir(), "identity.json");
|
|
12889
12984
|
}
|
|
12890
12985
|
function readPersistedIdentity() {
|
|
12891
12986
|
const path = identityFilePath();
|
|
12892
|
-
if (!
|
|
12987
|
+
if (!existsSync7(path))
|
|
12893
12988
|
return null;
|
|
12894
12989
|
const parsed = readJsonFile(path);
|
|
12895
12990
|
if (!parsed || typeof parsed.agent_id !== "string" || !parsed.agent_id.trim())
|
|
@@ -14420,17 +14515,17 @@ function sanitizeCreateTaskInput(input) {
|
|
|
14420
14515
|
return {
|
|
14421
14516
|
...input,
|
|
14422
14517
|
title: sanitizePreWriteText(input.title, "task.title"),
|
|
14423
|
-
description: input.description
|
|
14518
|
+
description: input.description == null ? input.description : sanitizePreWriteText(input.description, "task.description"),
|
|
14424
14519
|
tags: input.tags !== undefined ? sanitizePreWriteValue(input.tags, "task.tags") : undefined,
|
|
14425
14520
|
metadata: input.metadata !== undefined ? sanitizePreWriteValue(input.metadata, "task.metadata") : undefined,
|
|
14426
|
-
reason: input.reason
|
|
14521
|
+
reason: input.reason == null ? input.reason : sanitizePreWriteText(input.reason, "task.reason")
|
|
14427
14522
|
};
|
|
14428
14523
|
}
|
|
14429
14524
|
function sanitizeUpdateTaskInput(input) {
|
|
14430
14525
|
return {
|
|
14431
14526
|
...input,
|
|
14432
14527
|
title: input.title !== undefined ? sanitizePreWriteText(input.title, "task.title") : undefined,
|
|
14433
|
-
description: input.description
|
|
14528
|
+
description: input.description == null ? input.description : sanitizePreWriteText(input.description, "task.description"),
|
|
14434
14529
|
tags: input.tags !== undefined ? sanitizePreWriteValue(input.tags, "task.tags") : undefined,
|
|
14435
14530
|
metadata: input.metadata !== undefined ? sanitizePreWriteValue(input.metadata, "task.metadata") : undefined
|
|
14436
14531
|
};
|
|
@@ -16427,28 +16522,28 @@ var init_boards = __esm(() => {
|
|
|
16427
16522
|
|
|
16428
16523
|
// src/lib/artifact-store.ts
|
|
16429
16524
|
import { createHash as createHash2 } from "crypto";
|
|
16430
|
-
import { existsSync as
|
|
16431
|
-
import { basename, dirname as dirname4, join as
|
|
16525
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync3, rmSync as rmSync2, statSync as statSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
16526
|
+
import { basename, dirname as dirname4, join as join7, resolve as resolve8 } from "path";
|
|
16432
16527
|
import { tmpdir as tmpdir2 } from "os";
|
|
16433
16528
|
function isInMemoryDb2(path) {
|
|
16434
16529
|
return path === ":memory:" || path.startsWith("file::memory:");
|
|
16435
16530
|
}
|
|
16436
16531
|
function artifactStoreRoot() {
|
|
16437
16532
|
if (process.env["HASNA_TODOS_ARTIFACTS_DIR"])
|
|
16438
|
-
return
|
|
16533
|
+
return resolve8(process.env["HASNA_TODOS_ARTIFACTS_DIR"]);
|
|
16439
16534
|
if (process.env["TODOS_ARTIFACTS_DIR"])
|
|
16440
|
-
return
|
|
16535
|
+
return resolve8(process.env["TODOS_ARTIFACTS_DIR"]);
|
|
16441
16536
|
const dbPath = getDatabasePath();
|
|
16442
16537
|
if (isInMemoryDb2(dbPath))
|
|
16443
|
-
return
|
|
16444
|
-
return
|
|
16538
|
+
return join7(tmpdir2(), "hasna-todos-artifacts");
|
|
16539
|
+
return join7(dirname4(resolve8(dbPath)), "artifacts");
|
|
16445
16540
|
}
|
|
16446
16541
|
function artifactStorePath(relativePath) {
|
|
16447
16542
|
const normalized = relativePath.replace(/\\/g, "/");
|
|
16448
16543
|
if (normalized.includes("..") || normalized.startsWith("/") || normalized.length === 0) {
|
|
16449
16544
|
throw new Error("Invalid artifact store path");
|
|
16450
16545
|
}
|
|
16451
|
-
return
|
|
16546
|
+
return join7(artifactStoreRoot(), normalized);
|
|
16452
16547
|
}
|
|
16453
16548
|
function sha256(buffer) {
|
|
16454
16549
|
return createHash2("sha256").update(buffer).digest("hex");
|
|
@@ -16488,8 +16583,8 @@ function mediaTypeFor(path, textLike) {
|
|
|
16488
16583
|
return "application/octet-stream";
|
|
16489
16584
|
}
|
|
16490
16585
|
function storeArtifactContent(input) {
|
|
16491
|
-
const sourcePath =
|
|
16492
|
-
if (!
|
|
16586
|
+
const sourcePath = resolve8(input.path);
|
|
16587
|
+
if (!existsSync8(sourcePath))
|
|
16493
16588
|
return null;
|
|
16494
16589
|
const sourceStat = statSync2(sourcePath);
|
|
16495
16590
|
if (!sourceStat.isFile())
|
|
@@ -16506,9 +16601,9 @@ function storeArtifactContent(input) {
|
|
|
16506
16601
|
redactionStatus = "redacted";
|
|
16507
16602
|
}
|
|
16508
16603
|
const storedSha = sha256(storedBuffer);
|
|
16509
|
-
const relativePath =
|
|
16604
|
+
const relativePath = join7("sha256", storedSha.slice(0, 2), storedSha).replace(/\\/g, "/");
|
|
16510
16605
|
const destination = artifactStorePath(relativePath);
|
|
16511
|
-
if (!
|
|
16606
|
+
if (!existsSync8(destination)) {
|
|
16512
16607
|
mkdirSync4(dirname4(destination), { recursive: true });
|
|
16513
16608
|
writeFileSync2(destination, storedBuffer);
|
|
16514
16609
|
}
|
|
@@ -16568,7 +16663,7 @@ function verifyStoredArtifact(input) {
|
|
|
16568
16663
|
};
|
|
16569
16664
|
}
|
|
16570
16665
|
const storedPath = artifactStorePath(store.relative_path);
|
|
16571
|
-
if (!
|
|
16666
|
+
if (!existsSync8(storedPath)) {
|
|
16572
16667
|
return {
|
|
16573
16668
|
id: input.id,
|
|
16574
16669
|
path: input.path,
|
|
@@ -19046,10 +19141,10 @@ var init_token_utils = __esm(() => {
|
|
|
19046
19141
|
|
|
19047
19142
|
// src/lib/assignee-validation.ts
|
|
19048
19143
|
import { readFileSync as readFileSync4 } from "fs";
|
|
19049
|
-
import { homedir as
|
|
19050
|
-
import { join as
|
|
19144
|
+
import { homedir as homedir5 } from "os";
|
|
19145
|
+
import { join as join8 } from "path";
|
|
19051
19146
|
function defaultSeatRosterPath() {
|
|
19052
|
-
return process.env["TODOS_SEAT_ROSTER_PATH"] ||
|
|
19147
|
+
return process.env["TODOS_SEAT_ROSTER_PATH"] || join8(homedir5(), ".hasna", "identities", "hasna-seats.roster.json");
|
|
19053
19148
|
}
|
|
19054
19149
|
function loadSeatSlugs(path = defaultSeatRosterPath()) {
|
|
19055
19150
|
try {
|
|
@@ -21518,7 +21613,7 @@ var init_page_validation = __esm(() => {
|
|
|
21518
21613
|
// src/cli/cloud-router.ts
|
|
21519
21614
|
import { resolveStorageClient } from "@hasna/contracts/client/storage";
|
|
21520
21615
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
21521
|
-
import { resolve as
|
|
21616
|
+
import { resolve as resolvePath2 } from "path";
|
|
21522
21617
|
function emitTodosLocalFallbackNotice(env) {
|
|
21523
21618
|
if (todosLocalFallbackNoticeEmitted)
|
|
21524
21619
|
return;
|
|
@@ -21578,15 +21673,23 @@ function normalizeRemoteAuthorityUrl(value) {
|
|
|
21578
21673
|
if (url.search || url.hash) {
|
|
21579
21674
|
throw new Error("REMOTE_API_URL_INVALID: HASNA_TODOS_API_URL must not contain a query or fragment; local SQLite fallback is disabled");
|
|
21580
21675
|
}
|
|
21581
|
-
|
|
21582
|
-
|
|
21676
|
+
const path = url.pathname.replace(/\/+$/, "");
|
|
21677
|
+
const segments = path.split("/").filter(Boolean);
|
|
21678
|
+
const reservedGatewaySegments = new Set(["api", "v1"]);
|
|
21679
|
+
const isRoot = path === "";
|
|
21680
|
+
const isV1Root = segments.length === 1 && segments[0] === "v1";
|
|
21681
|
+
const isAppRoot = segments.length === 1 && !reservedGatewaySegments.has(segments[0].toLowerCase());
|
|
21682
|
+
const isAppV1Root = segments.length === 2 && segments[1] === "v1" && !reservedGatewaySegments.has(segments[0].toLowerCase());
|
|
21683
|
+
if (!isRoot && !isV1Root && !isAppRoot && !isAppV1Root) {
|
|
21684
|
+
throw new Error("REMOTE_API_URL_INVALID: HASNA_TODOS_API_URL must be an authority root, /v1, or <app>[/v1], not /api/v1 or another path; " + "local SQLite fallback is disabled");
|
|
21583
21685
|
}
|
|
21584
21686
|
const hostname2 = url.hostname.toLowerCase();
|
|
21585
21687
|
const loopback = hostname2 === "localhost" || hostname2 === "::1" || hostname2 === "[::1]" || /^127(?:\.\d{1,3}){3}$/.test(hostname2);
|
|
21586
21688
|
if (url.protocol === "http:" && !loopback) {
|
|
21587
21689
|
throw new Error("REMOTE_API_URL_INVALID: plaintext HTTP is allowed only for loopback Todos authorities; local SQLite fallback is disabled");
|
|
21588
21690
|
}
|
|
21589
|
-
|
|
21691
|
+
const rootPath = isV1Root || isAppV1Root ? path.slice(0, -"/v1".length) : path;
|
|
21692
|
+
return rootPath ? `${url.origin}${rootPath}` : url.origin;
|
|
21590
21693
|
}
|
|
21591
21694
|
function getTodosRemoteAuthorityConfigStatus(env = process.env) {
|
|
21592
21695
|
let resolution;
|
|
@@ -22084,11 +22187,11 @@ function resolveCloudProjectRef(projects, ref) {
|
|
|
22084
22187
|
const input = ref.trim();
|
|
22085
22188
|
const normalizedRef = input.toLowerCase();
|
|
22086
22189
|
const pathLike = input.startsWith(".") || input.includes("/") || input.includes("\\");
|
|
22087
|
-
const normalizedPath = pathLike ?
|
|
22190
|
+
const normalizedPath = pathLike ? resolvePath2(input) : undefined;
|
|
22088
22191
|
const slug = cloudProjectSlug(pathLike ? cloudProjectPathBasename(input) : input);
|
|
22089
22192
|
const matchGroups = [
|
|
22090
22193
|
uniqueProjectMatches(projects, (project) => project.id.toLowerCase() === normalizedRef),
|
|
22091
|
-
uniqueProjectMatches(projects, (project) => project.path === input || normalizedPath !== undefined &&
|
|
22194
|
+
uniqueProjectMatches(projects, (project) => project.path === input || normalizedPath !== undefined && resolvePath2(project.path) === normalizedPath),
|
|
22092
22195
|
uniqueProjectMatches(projects, (project) => project.name.toLowerCase() === normalizedRef),
|
|
22093
22196
|
uniqueProjectMatches(projects, (project) => project.task_list_id === input || cloudProjectSlug(project.name) === slug || cloudProjectSlug(cloudProjectPathBasename(project.path)) === slug),
|
|
22094
22197
|
uniqueProjectMatches(projects, (project) => project.id.toLowerCase().startsWith(normalizedRef))
|
|
@@ -22671,8 +22774,8 @@ var init_task_crud2 = __esm(() => {
|
|
|
22671
22774
|
});
|
|
22672
22775
|
|
|
22673
22776
|
// src/lib/project-bootstrap.ts
|
|
22674
|
-
import { existsSync as
|
|
22675
|
-
import { basename as basename2, dirname as dirname5, resolve as
|
|
22777
|
+
import { existsSync as existsSync9, readFileSync as readFileSync5, statSync as statSync3 } from "fs";
|
|
22778
|
+
import { basename as basename2, dirname as dirname5, resolve as resolve9 } from "path";
|
|
22676
22779
|
function safeStat(path) {
|
|
22677
22780
|
try {
|
|
22678
22781
|
return statSync3(path);
|
|
@@ -22681,7 +22784,7 @@ function safeStat(path) {
|
|
|
22681
22784
|
}
|
|
22682
22785
|
}
|
|
22683
22786
|
function canonicalPath(input) {
|
|
22684
|
-
const resolved =
|
|
22787
|
+
const resolved = resolve9(input);
|
|
22685
22788
|
const stats = safeStat(resolved);
|
|
22686
22789
|
if (stats?.isFile())
|
|
22687
22790
|
return dirname5(resolved);
|
|
@@ -22690,7 +22793,7 @@ function canonicalPath(input) {
|
|
|
22690
22793
|
function findUp(start, marker) {
|
|
22691
22794
|
let current = canonicalPath(start);
|
|
22692
22795
|
while (true) {
|
|
22693
|
-
if (
|
|
22796
|
+
if (existsSync9(resolve9(current, marker)))
|
|
22694
22797
|
return current;
|
|
22695
22798
|
const parent = dirname5(current);
|
|
22696
22799
|
if (parent === current)
|
|
@@ -22701,8 +22804,8 @@ function findUp(start, marker) {
|
|
|
22701
22804
|
function readPackageJson(path) {
|
|
22702
22805
|
if (!path)
|
|
22703
22806
|
return null;
|
|
22704
|
-
const file =
|
|
22705
|
-
if (!
|
|
22807
|
+
const file = resolve9(path, "package.json");
|
|
22808
|
+
if (!existsSync9(file))
|
|
22706
22809
|
return null;
|
|
22707
22810
|
try {
|
|
22708
22811
|
const parsed = JSON.parse(readFileSync5(file, "utf-8"));
|
|
@@ -22724,7 +22827,7 @@ function workspaceMarker(root, rootPackage) {
|
|
|
22724
22827
|
if (rootPackage?.workspaces)
|
|
22725
22828
|
markers.push("package.json#workspaces");
|
|
22726
22829
|
for (const marker of ["pnpm-workspace.yaml", "turbo.json", "nx.json", "lerna.json", "rush.json", "bun.lock", "bun.lockb"]) {
|
|
22727
|
-
if (
|
|
22830
|
+
if (existsSync9(resolve9(root, marker)))
|
|
22728
22831
|
markers.push(marker);
|
|
22729
22832
|
}
|
|
22730
22833
|
const kind = markers.find((marker) => marker !== "bun.lock" && marker !== "bun.lockb") ?? null;
|
|
@@ -23037,7 +23140,7 @@ var init_tags = __esm(() => {
|
|
|
23037
23140
|
});
|
|
23038
23141
|
|
|
23039
23142
|
// src/lib/retention-cleanup.ts
|
|
23040
|
-
import { existsSync as
|
|
23143
|
+
import { existsSync as existsSync10, unlinkSync } from "fs";
|
|
23041
23144
|
function normalizeScopes(scopes) {
|
|
23042
23145
|
if (!scopes || scopes.length === 0)
|
|
23043
23146
|
return [...ALL_SCOPES];
|
|
@@ -23240,7 +23343,7 @@ function applyRetentionCleanup(input, db) {
|
|
|
23240
23343
|
for (const artifact of report.candidates.artifact_files) {
|
|
23241
23344
|
try {
|
|
23242
23345
|
const path = artifactStorePath(artifact.relative_path);
|
|
23243
|
-
if (!
|
|
23346
|
+
if (!existsSync10(path)) {
|
|
23244
23347
|
report.warnings.push(`stored artifact already missing: ${artifact.relative_path}`);
|
|
23245
23348
|
continue;
|
|
23246
23349
|
}
|
|
@@ -23267,8 +23370,8 @@ var init_retention_cleanup = __esm(() => {
|
|
|
23267
23370
|
});
|
|
23268
23371
|
|
|
23269
23372
|
// src/lib/mention-resolver.ts
|
|
23270
|
-
import { existsSync as
|
|
23271
|
-
import { basename as basename3, isAbsolute, join as
|
|
23373
|
+
import { existsSync as existsSync11, readdirSync as readdirSync2, readFileSync as readFileSync6, statSync as statSync4 } from "fs";
|
|
23374
|
+
import { basename as basename3, isAbsolute, join as join9, relative as relative3, resolve as resolve10, sep as sep2 } from "path";
|
|
23272
23375
|
function blankResolution(parsed) {
|
|
23273
23376
|
return {
|
|
23274
23377
|
input: parsed.input,
|
|
@@ -23291,7 +23394,7 @@ function backlink(kind, key, label, target = key) {
|
|
|
23291
23394
|
return { kind, key, label, target };
|
|
23292
23395
|
}
|
|
23293
23396
|
function normalizeWorkspace(workspace) {
|
|
23294
|
-
return
|
|
23397
|
+
return resolve10(workspace || process.cwd());
|
|
23295
23398
|
}
|
|
23296
23399
|
function isInside(root, absolutePath) {
|
|
23297
23400
|
const rel = relative3(root, absolutePath);
|
|
@@ -23359,14 +23462,14 @@ function resolveFile(parsed, workspace) {
|
|
|
23359
23462
|
resolution.warnings.push("path is empty or escapes the workspace");
|
|
23360
23463
|
return resolution;
|
|
23361
23464
|
}
|
|
23362
|
-
const absolutePath =
|
|
23465
|
+
const absolutePath = resolve10(workspace, relPath);
|
|
23363
23466
|
if (!isInside(workspace, absolutePath)) {
|
|
23364
23467
|
resolution.path = relPath;
|
|
23365
23468
|
resolution.warnings.push("path escapes the workspace");
|
|
23366
23469
|
return resolution;
|
|
23367
23470
|
}
|
|
23368
23471
|
resolution.path = relPath;
|
|
23369
|
-
if (!
|
|
23472
|
+
if (!existsSync11(absolutePath)) {
|
|
23370
23473
|
resolution.warnings.push("file does not exist in the local workspace");
|
|
23371
23474
|
return resolution;
|
|
23372
23475
|
}
|
|
@@ -23399,7 +23502,7 @@ function walkSourceFiles(root, current = root, files = []) {
|
|
|
23399
23502
|
if (SKIP_DIRS.has(entry.name))
|
|
23400
23503
|
continue;
|
|
23401
23504
|
}
|
|
23402
|
-
const absolutePath =
|
|
23505
|
+
const absolutePath = join9(current, entry.name);
|
|
23403
23506
|
if (entry.isDirectory()) {
|
|
23404
23507
|
if (!SKIP_DIRS.has(entry.name))
|
|
23405
23508
|
walkSourceFiles(root, absolutePath, files);
|
|
@@ -23704,9 +23807,9 @@ var init_mention_resolver = __esm(() => {
|
|
|
23704
23807
|
});
|
|
23705
23808
|
|
|
23706
23809
|
// src/lib/policy-packs.ts
|
|
23707
|
-
import { relative as relative4, resolve as
|
|
23810
|
+
import { relative as relative4, resolve as resolve11 } from "path";
|
|
23708
23811
|
function normalizePath3(path) {
|
|
23709
|
-
return
|
|
23812
|
+
return resolve11(path);
|
|
23710
23813
|
}
|
|
23711
23814
|
function unique4(values) {
|
|
23712
23815
|
return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));
|
|
@@ -23761,7 +23864,7 @@ function commandMatches(commands, pattern) {
|
|
|
23761
23864
|
}
|
|
23762
23865
|
function pathMatches(paths, pattern, root) {
|
|
23763
23866
|
return paths.filter((path) => {
|
|
23764
|
-
const candidate = path.startsWith("/") ? path :
|
|
23867
|
+
const candidate = path.startsWith("/") ? path : resolve11(root, path);
|
|
23765
23868
|
if (!isPathInside3(root, candidate))
|
|
23766
23869
|
return matchesPattern3(path, pattern);
|
|
23767
23870
|
return matchesPattern3(path, pattern) || matchesPattern3(relative4(root, candidate), pattern);
|
|
@@ -27140,7 +27243,7 @@ var init_audit_ledger = __esm(() => {
|
|
|
27140
27243
|
|
|
27141
27244
|
// src/lib/release-compatibility.ts
|
|
27142
27245
|
import { readFileSync as readFileSync7 } from "fs";
|
|
27143
|
-
import { join as
|
|
27246
|
+
import { join as join10, resolve as resolve12 } from "path";
|
|
27144
27247
|
import { Database as Database2 } from "bun:sqlite";
|
|
27145
27248
|
function pass(id, message, details) {
|
|
27146
27249
|
return { id, status: "passed", message, details };
|
|
@@ -27152,7 +27255,7 @@ function warn(id, message, details) {
|
|
|
27152
27255
|
return { id, status: "warning", message, details };
|
|
27153
27256
|
}
|
|
27154
27257
|
function readPackageJson2(root) {
|
|
27155
|
-
return JSON.parse(readFileSync7(
|
|
27258
|
+
return JSON.parse(readFileSync7(join10(root, "package.json"), "utf8"));
|
|
27156
27259
|
}
|
|
27157
27260
|
function sortedKeys(value) {
|
|
27158
27261
|
return Object.keys(value ?? {}).sort((left, right) => left.localeCompare(right));
|
|
@@ -27248,7 +27351,7 @@ function checkChangelog() {
|
|
|
27248
27351
|
];
|
|
27249
27352
|
}
|
|
27250
27353
|
function createReleaseCompatibilityReport(options = {}) {
|
|
27251
|
-
const root =
|
|
27354
|
+
const root = resolve12(options.root ?? process.cwd());
|
|
27252
27355
|
const packageJson = readPackageJson2(root);
|
|
27253
27356
|
const simulatedLevels = options.simulated_levels ?? defaultSimulationLevels();
|
|
27254
27357
|
const checks = [
|
|
@@ -31170,8 +31273,8 @@ var exports_doctor = {};
|
|
|
31170
31273
|
__export(exports_doctor, {
|
|
31171
31274
|
runTodosDoctor: () => runTodosDoctor
|
|
31172
31275
|
});
|
|
31173
|
-
import { chmodSync, copyFileSync, existsSync as
|
|
31174
|
-
import { basename as basename4, dirname as dirname6, join as
|
|
31276
|
+
import { chmodSync, copyFileSync, existsSync as existsSync12, mkdirSync as mkdirSync5, statSync as statSync5 } from "fs";
|
|
31277
|
+
import { basename as basename4, dirname as dirname6, join as join11 } from "path";
|
|
31175
31278
|
function tableExists2(db, table) {
|
|
31176
31279
|
return Boolean(db.query("SELECT name FROM sqlite_master WHERE type='table' AND name=?").get(table));
|
|
31177
31280
|
}
|
|
@@ -31265,7 +31368,7 @@ function findMissingProjectRoots(db) {
|
|
|
31265
31368
|
continue;
|
|
31266
31369
|
if (!row.path.startsWith("/"))
|
|
31267
31370
|
continue;
|
|
31268
|
-
if (!
|
|
31371
|
+
if (!existsSync12(row.path))
|
|
31269
31372
|
missing++;
|
|
31270
31373
|
}
|
|
31271
31374
|
return missing;
|
|
@@ -31325,16 +31428,16 @@ function databasePermissionsAreUnsafe(dbPath) {
|
|
|
31325
31428
|
function createBackup(dbPath) {
|
|
31326
31429
|
if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
|
|
31327
31430
|
return;
|
|
31328
|
-
if (!
|
|
31431
|
+
if (!existsSync12(dbPath))
|
|
31329
31432
|
return;
|
|
31330
31433
|
const stamp = now().replace(/[:.]/g, "-");
|
|
31331
|
-
const backupDir =
|
|
31434
|
+
const backupDir = join11(dirname6(dbPath), `${basename4(dbPath)}.backup-${stamp}`);
|
|
31332
31435
|
const files = [];
|
|
31333
31436
|
mkdirSync5(backupDir, { recursive: true });
|
|
31334
31437
|
for (const source of [dbPath, `${dbPath}-wal`, `${dbPath}-shm`]) {
|
|
31335
|
-
if (!
|
|
31438
|
+
if (!existsSync12(source))
|
|
31336
31439
|
continue;
|
|
31337
|
-
const target =
|
|
31440
|
+
const target = join11(backupDir, basename4(source));
|
|
31338
31441
|
copyFileSync(source, target);
|
|
31339
31442
|
files.push(target);
|
|
31340
31443
|
}
|
|
@@ -34095,7 +34198,7 @@ var init_agent_run_dispatcher = __esm(() => {
|
|
|
34095
34198
|
});
|
|
34096
34199
|
|
|
34097
34200
|
// src/lib/verification-providers.ts
|
|
34098
|
-
import { existsSync as
|
|
34201
|
+
import { existsSync as existsSync13, readFileSync as readFileSync8 } from "fs";
|
|
34099
34202
|
function normalizeName5(name) {
|
|
34100
34203
|
const normalized = name.trim().toLowerCase();
|
|
34101
34204
|
if (!/^[a-z0-9][a-z0-9_-]{0,63}$/.test(normalized)) {
|
|
@@ -34192,7 +34295,7 @@ function classifyLog(text) {
|
|
|
34192
34295
|
async function sleep2(ms) {
|
|
34193
34296
|
if (ms <= 0)
|
|
34194
34297
|
return;
|
|
34195
|
-
await new Promise((
|
|
34298
|
+
await new Promise((resolve13) => setTimeout(resolve13, ms));
|
|
34196
34299
|
}
|
|
34197
34300
|
async function runCommandProvider(provider, input) {
|
|
34198
34301
|
const commandTemplate = input.command || provider.command;
|
|
@@ -34247,7 +34350,7 @@ Timed out after ${provider.timeout_ms}ms`);
|
|
|
34247
34350
|
};
|
|
34248
34351
|
}
|
|
34249
34352
|
function runCiLogProvider(input) {
|
|
34250
|
-
const text = input.log_text ?? (input.log_path &&
|
|
34353
|
+
const text = input.log_text ?? (input.log_path && existsSync13(input.log_path) ? readFileSync8(input.log_path, "utf-8") : "");
|
|
34251
34354
|
return {
|
|
34252
34355
|
status: classifyLog(text),
|
|
34253
34356
|
attempts: 1,
|
|
@@ -34259,7 +34362,7 @@ function runBrowserProvider(input) {
|
|
|
34259
34362
|
if (!input.artifact_path) {
|
|
34260
34363
|
return { status: "unknown", attempts: 1, exit_code: null, output_summary: "browser provider needs a screenshot or artifact path" };
|
|
34261
34364
|
}
|
|
34262
|
-
if (!
|
|
34365
|
+
if (!existsSync13(input.artifact_path)) {
|
|
34263
34366
|
return { status: "failed", attempts: 1, exit_code: null, output_summary: `artifact not found: ${input.artifact_path}` };
|
|
34264
34367
|
}
|
|
34265
34368
|
return {
|
|
@@ -36417,7 +36520,7 @@ var package_default;
|
|
|
36417
36520
|
var init_package = __esm(() => {
|
|
36418
36521
|
package_default = {
|
|
36419
36522
|
name: "@hasna/todos",
|
|
36420
|
-
version: "0.15.
|
|
36523
|
+
version: "0.15.52",
|
|
36421
36524
|
description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
|
|
36422
36525
|
type: "module",
|
|
36423
36526
|
main: "dist/index.js",
|
|
@@ -36476,6 +36579,7 @@ var init_package = __esm(() => {
|
|
|
36476
36579
|
files: [
|
|
36477
36580
|
"dist",
|
|
36478
36581
|
"dashboard/dist",
|
|
36582
|
+
"postinstall.js",
|
|
36479
36583
|
"LICENSE",
|
|
36480
36584
|
"README.md"
|
|
36481
36585
|
],
|
|
@@ -36502,7 +36606,7 @@ var init_package = __esm(() => {
|
|
|
36502
36606
|
"test:attested-container-compatibility-vector": "bun test scripts/attested-container-compatibility-vector.test.ts",
|
|
36503
36607
|
"issue:release-review": "bun run scripts/issue-npm-release-agent-review.ts",
|
|
36504
36608
|
prepublishOnly: "bun run scripts/verify-public-release.ts --mode=publish",
|
|
36505
|
-
postinstall: "
|
|
36609
|
+
postinstall: "node postinstall.js"
|
|
36506
36610
|
},
|
|
36507
36611
|
keywords: [
|
|
36508
36612
|
"todos",
|
|
@@ -36536,13 +36640,15 @@ var init_package = __esm(() => {
|
|
|
36536
36640
|
author: "Andrei Hasna <andrei@hasna.com>",
|
|
36537
36641
|
license: "Apache-2.0",
|
|
36538
36642
|
dependencies: {
|
|
36539
|
-
"@hasna/contracts": "0.14.
|
|
36643
|
+
"@hasna/contracts": "0.14.2",
|
|
36540
36644
|
"@hasna/events": "^0.1.11",
|
|
36645
|
+
"@hasna/paths": "0.1.0",
|
|
36541
36646
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
36542
36647
|
chalk: "^5.4.1",
|
|
36543
36648
|
commander: "^13.1.0",
|
|
36544
36649
|
ink: "^5.2.0",
|
|
36545
36650
|
react: "^18.3.1",
|
|
36651
|
+
"signal-exit": "3.0.7",
|
|
36546
36652
|
zod: "3.25.76"
|
|
36547
36653
|
},
|
|
36548
36654
|
overrides: {
|
|
@@ -36551,7 +36657,7 @@ var init_package = __esm(() => {
|
|
|
36551
36657
|
zod: "3.25.76"
|
|
36552
36658
|
},
|
|
36553
36659
|
devDependencies: {
|
|
36554
|
-
"@types/bun": "
|
|
36660
|
+
"@types/bun": "1.3.14",
|
|
36555
36661
|
"@types/react": "^18.3.18",
|
|
36556
36662
|
"bun-types": "1.3.9",
|
|
36557
36663
|
"hasna-deployment-contracts": "npm:@hasna/contracts@0.10.4",
|
|
@@ -37149,7 +37255,7 @@ var init_local_bridge = __esm(() => {
|
|
|
37149
37255
|
// src/lib/local-backups.ts
|
|
37150
37256
|
import { createHash as createHash7 } from "crypto";
|
|
37151
37257
|
import { readFileSync as readFileSync9, writeFileSync as writeFileSync3 } from "fs";
|
|
37152
|
-
import { dirname as dirname7, resolve as
|
|
37258
|
+
import { dirname as dirname7, resolve as resolve13 } from "path";
|
|
37153
37259
|
import { mkdirSync as mkdirSync6 } from "fs";
|
|
37154
37260
|
function stableJson2(value) {
|
|
37155
37261
|
if (value === null || typeof value !== "object")
|
|
@@ -37251,14 +37357,14 @@ function createLocalBackup(options = {}, db) {
|
|
|
37251
37357
|
return backup;
|
|
37252
37358
|
}
|
|
37253
37359
|
function writeLocalBackupFile(backup, outputPath) {
|
|
37254
|
-
const path =
|
|
37360
|
+
const path = resolve13(outputPath);
|
|
37255
37361
|
mkdirSync6(dirname7(path), { recursive: true });
|
|
37256
37362
|
writeFileSync3(path, `${JSON.stringify(backup, null, 2)}
|
|
37257
37363
|
`);
|
|
37258
37364
|
return path;
|
|
37259
37365
|
}
|
|
37260
37366
|
function readLocalBackupFile(path) {
|
|
37261
|
-
return JSON.parse(readFileSync9(
|
|
37367
|
+
return JSON.parse(readFileSync9(resolve13(path), "utf-8"));
|
|
37262
37368
|
}
|
|
37263
37369
|
function verifyLocalBackup(value, options = {}, db) {
|
|
37264
37370
|
const verifiedAt = options.verified_at ?? now();
|
|
@@ -38710,8 +38816,8 @@ __export(exports_local_extensions, {
|
|
|
38710
38816
|
discoverLocalExtensions: () => discoverLocalExtensions
|
|
38711
38817
|
});
|
|
38712
38818
|
import { createHash as createHash10, createVerify } from "crypto";
|
|
38713
|
-
import { existsSync as
|
|
38714
|
-
import { basename as basename5, join as
|
|
38819
|
+
import { existsSync as existsSync14, readdirSync as readdirSync3, readFileSync as readFileSync10, statSync as statSync6 } from "fs";
|
|
38820
|
+
import { basename as basename5, join as join12, resolve as resolve14 } from "path";
|
|
38715
38821
|
function isObject2(value) {
|
|
38716
38822
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
38717
38823
|
}
|
|
@@ -38969,11 +39075,11 @@ function verifyExtensionSignature(input) {
|
|
|
38969
39075
|
return verifier.verify(input.public_key, decodeSignature(input.signature));
|
|
38970
39076
|
}
|
|
38971
39077
|
function inspectExtensionSource(source3) {
|
|
38972
|
-
const resolved =
|
|
38973
|
-
if (!
|
|
39078
|
+
const resolved = resolve14(source3);
|
|
39079
|
+
if (!existsSync14(resolved))
|
|
38974
39080
|
throw new Error(`extension source not found: ${source3}`);
|
|
38975
39081
|
const stat = statSync6(resolved);
|
|
38976
|
-
const manifestPath = stat.isDirectory() ? [
|
|
39082
|
+
const manifestPath = stat.isDirectory() ? [join12(resolved, "todos.extension.json"), join12(resolved, "extension.json")].find(existsSync14) : resolved;
|
|
38977
39083
|
if (!manifestPath)
|
|
38978
39084
|
throw new Error(`extension directory ${source3} is missing todos.extension.json`);
|
|
38979
39085
|
const raw = readFileSync10(manifestPath);
|
|
@@ -39067,26 +39173,26 @@ function testExtensionCompatibility(sourceOrManifest) {
|
|
|
39067
39173
|
function projectExtensionSources(projectPath) {
|
|
39068
39174
|
if (!projectPath)
|
|
39069
39175
|
return [];
|
|
39070
|
-
const root =
|
|
39176
|
+
const root = resolve14(projectPath);
|
|
39071
39177
|
const candidates = [
|
|
39072
|
-
|
|
39073
|
-
|
|
39178
|
+
join12(root, "todos.extension.json"),
|
|
39179
|
+
join12(root, ".todos", "todos.extension.json")
|
|
39074
39180
|
];
|
|
39075
|
-
const extensionDir =
|
|
39076
|
-
if (
|
|
39181
|
+
const extensionDir = join12(root, ".todos", "extensions");
|
|
39182
|
+
if (existsSync14(extensionDir)) {
|
|
39077
39183
|
for (const entry of readdirSync3(extensionDir)) {
|
|
39078
39184
|
if (entry.startsWith("."))
|
|
39079
39185
|
continue;
|
|
39080
|
-
const full =
|
|
39186
|
+
const full = join12(extensionDir, entry);
|
|
39081
39187
|
if (statSync6(full).isDirectory() || entry.endsWith(".json"))
|
|
39082
39188
|
candidates.push(full);
|
|
39083
39189
|
}
|
|
39084
39190
|
}
|
|
39085
|
-
return candidates.filter(
|
|
39191
|
+
return candidates.filter(existsSync14);
|
|
39086
39192
|
}
|
|
39087
39193
|
function discoverLocalExtensions(options = {}) {
|
|
39088
39194
|
const config = loadConfig();
|
|
39089
|
-
const projectPath = options.project_path ?
|
|
39195
|
+
const projectPath = options.project_path ? resolve14(options.project_path) : null;
|
|
39090
39196
|
const configuredSources = [
|
|
39091
39197
|
...config.extension_sources || [],
|
|
39092
39198
|
...projectPath ? config.project_overrides?.[projectPath]?.extension_sources || [] : []
|
|
@@ -39094,7 +39200,7 @@ function discoverLocalExtensions(options = {}) {
|
|
|
39094
39200
|
const sources = Array.from(new Set([
|
|
39095
39201
|
...configuredSources,
|
|
39096
39202
|
...projectExtensionSources(projectPath || undefined)
|
|
39097
|
-
])).map((source3) => projectPath && !source3.startsWith("/") ?
|
|
39203
|
+
])).map((source3) => projectPath && !source3.startsWith("/") ? resolve14(projectPath, source3) : resolve14(source3));
|
|
39098
39204
|
const warnings = [];
|
|
39099
39205
|
const discovered = [];
|
|
39100
39206
|
for (const source3 of sources) {
|
|
@@ -43489,9 +43595,9 @@ __export(exports_extract, {
|
|
|
43489
43595
|
buildCodebaseIndex: () => buildCodebaseIndex,
|
|
43490
43596
|
EXTRACT_TAGS: () => EXTRACT_TAGS
|
|
43491
43597
|
});
|
|
43492
|
-
import { existsSync as
|
|
43598
|
+
import { existsSync as existsSync15, readFileSync as readFileSync11, statSync as statSync7 } from "fs";
|
|
43493
43599
|
import { createHash as createHash12 } from "crypto";
|
|
43494
|
-
import { relative as relative5, resolve as
|
|
43600
|
+
import { relative as relative5, resolve as resolve15, join as join13 } from "path";
|
|
43495
43601
|
function stableHash(value) {
|
|
43496
43602
|
return createHash12("sha256").update(value).digest("hex");
|
|
43497
43603
|
}
|
|
@@ -43499,9 +43605,9 @@ function normalizePathForMatch(value) {
|
|
|
43499
43605
|
return value.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
43500
43606
|
}
|
|
43501
43607
|
function readGitignorePatterns(basePath) {
|
|
43502
|
-
const root = statSync7(basePath).isFile() ?
|
|
43503
|
-
const gitignorePath =
|
|
43504
|
-
if (!
|
|
43608
|
+
const root = statSync7(basePath).isFile() ? resolve15(basePath, "..") : basePath;
|
|
43609
|
+
const gitignorePath = join13(root, ".gitignore");
|
|
43610
|
+
if (!existsSync15(gitignorePath))
|
|
43505
43611
|
return [];
|
|
43506
43612
|
try {
|
|
43507
43613
|
return readFileSync11(gitignorePath, "utf-8").split(`
|
|
@@ -43635,7 +43741,7 @@ function collectFiles(basePath, extensions, excludes, respectGitignore) {
|
|
|
43635
43741
|
return files.sort();
|
|
43636
43742
|
}
|
|
43637
43743
|
function buildCodebaseIndex(options) {
|
|
43638
|
-
const basePath =
|
|
43744
|
+
const basePath = resolve15(options.path);
|
|
43639
43745
|
const tags = options.patterns || [...EXTRACT_TAGS];
|
|
43640
43746
|
const extensions = options.extensions ? new Set(options.extensions.map((e) => e.startsWith(".") ? e : `.${e}`)) : DEFAULT_EXTENSIONS;
|
|
43641
43747
|
const excludes = options.exclude || [];
|
|
@@ -43643,10 +43749,10 @@ function buildCodebaseIndex(options) {
|
|
|
43643
43749
|
const files = collectFiles(basePath, extensions, excludes, respectGitignore);
|
|
43644
43750
|
const indexed = [];
|
|
43645
43751
|
for (const file of files) {
|
|
43646
|
-
const fullPath = statSync7(basePath).isFile() ? basePath :
|
|
43752
|
+
const fullPath = statSync7(basePath).isFile() ? basePath : join13(basePath, file);
|
|
43647
43753
|
try {
|
|
43648
43754
|
const source3 = readFileSync11(fullPath, "utf-8");
|
|
43649
|
-
const relPath = statSync7(basePath).isFile() ? relative5(
|
|
43755
|
+
const relPath = statSync7(basePath).isFile() ? relative5(resolve15(basePath, ".."), fullPath) : file;
|
|
43650
43756
|
indexed.push({
|
|
43651
43757
|
file: relPath,
|
|
43652
43758
|
checksum: stableHash(source3).slice(0, 24),
|
|
@@ -43666,7 +43772,7 @@ function buildCodebaseIndex(options) {
|
|
|
43666
43772
|
};
|
|
43667
43773
|
}
|
|
43668
43774
|
function extractTodos(options, db) {
|
|
43669
|
-
const basePath =
|
|
43775
|
+
const basePath = resolve15(options.path);
|
|
43670
43776
|
const tags = options.patterns || [...EXTRACT_TAGS];
|
|
43671
43777
|
const extensions = options.extensions ? new Set(options.extensions.map((e) => e.startsWith(".") ? e : `.${e}`)) : DEFAULT_EXTENSIONS;
|
|
43672
43778
|
const excludes = options.exclude || [];
|
|
@@ -43674,10 +43780,10 @@ function extractTodos(options, db) {
|
|
|
43674
43780
|
const files = collectFiles(basePath, extensions, excludes, respectGitignore);
|
|
43675
43781
|
const allComments = [];
|
|
43676
43782
|
for (const file of files) {
|
|
43677
|
-
const fullPath = statSync7(basePath).isFile() ? basePath :
|
|
43783
|
+
const fullPath = statSync7(basePath).isFile() ? basePath : join13(basePath, file);
|
|
43678
43784
|
try {
|
|
43679
43785
|
const source3 = readFileSync11(fullPath, "utf-8");
|
|
43680
|
-
const relPath = statSync7(basePath).isFile() ? relative5(
|
|
43786
|
+
const relPath = statSync7(basePath).isFile() ? relative5(resolve15(basePath, ".."), fullPath) : file;
|
|
43681
43787
|
const comments = extractFromSource(source3, relPath, tags);
|
|
43682
43788
|
allComments.push(...comments);
|
|
43683
43789
|
} catch {}
|
|
@@ -43771,7 +43877,7 @@ async function watchSourceTodos(options, onRun) {
|
|
|
43771
43877
|
const interval = Math.max(100, options.interval_ms || 2000);
|
|
43772
43878
|
const once = options.once !== false && (!options.max_runs || options.max_runs <= 1);
|
|
43773
43879
|
const maxRuns = options.max_runs ?? (once ? 1 : Number.POSITIVE_INFINITY);
|
|
43774
|
-
const root =
|
|
43880
|
+
const root = resolve15(options.path);
|
|
43775
43881
|
const runs = [];
|
|
43776
43882
|
let previous = new Map;
|
|
43777
43883
|
for (let runNumber = 1;runNumber <= maxRuns; runNumber++) {
|
|
@@ -44330,7 +44436,7 @@ Last seen: ${agent.last_seen_at}`
|
|
|
44330
44436
|
`Suggested names: ${suggestions.slice(0, 8).join(", ")}`,
|
|
44331
44437
|
allActive.length > 0 ? `Active agents (avoid these names): ${allActive.map((a) => `${a.name} (seen ${Math.round((Date.now() - new Date(a.last_seen_at).getTime()) / 60000)}m ago)`).join(", ")}` : "No active agents.",
|
|
44332
44438
|
`
|
|
44333
|
-
To restrict names, configure agent_pool or project_pools in
|
|
44439
|
+
To restrict names, configure agent_pool or project_pools in the todos data home config file (default <data home>/config.json)`
|
|
44334
44440
|
];
|
|
44335
44441
|
return { content: [{ type: "text", text: lines2.join(`
|
|
44336
44442
|
`) }] };
|
|
@@ -44633,7 +44739,7 @@ __export(exports_builtin_templates, {
|
|
|
44633
44739
|
BUILTIN_TEMPLATES: () => BUILTIN_TEMPLATES
|
|
44634
44740
|
});
|
|
44635
44741
|
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
44636
|
-
import { join as
|
|
44742
|
+
import { join as join14 } from "path";
|
|
44637
44743
|
function templateMetadata(template) {
|
|
44638
44744
|
return {
|
|
44639
44745
|
source: BUILTIN_TEMPLATE_LIBRARY_SOURCE,
|
|
@@ -44692,7 +44798,7 @@ function writeBuiltinTemplateFiles(directory) {
|
|
|
44692
44798
|
mkdirSync7(directory, { recursive: true });
|
|
44693
44799
|
const files = [];
|
|
44694
44800
|
for (const entry of exportBuiltinTemplateFiles()) {
|
|
44695
|
-
const path =
|
|
44801
|
+
const path = join14(directory, entry.filename);
|
|
44696
44802
|
writeFileSync4(path, `${JSON.stringify(entry.template, null, 2)}
|
|
44697
44803
|
`, "utf-8");
|
|
44698
44804
|
files.push(path);
|
|
@@ -45218,16 +45324,16 @@ __export(exports_environment_snapshots, {
|
|
|
45218
45324
|
captureEnvironmentSnapshot: () => captureEnvironmentSnapshot
|
|
45219
45325
|
});
|
|
45220
45326
|
import { createHash as createHash13 } from "crypto";
|
|
45221
|
-
import { existsSync as
|
|
45327
|
+
import { existsSync as existsSync16, readFileSync as readFileSync12, statSync as statSync8 } from "fs";
|
|
45222
45328
|
import { hostname as hostname2, platform, arch } from "os";
|
|
45223
|
-
import { dirname as dirname8, join as
|
|
45329
|
+
import { dirname as dirname8, join as join15, resolve as resolve16 } from "path";
|
|
45224
45330
|
import { tmpdir as tmpdir3 } from "os";
|
|
45225
45331
|
function sha2567(value) {
|
|
45226
45332
|
return createHash13("sha256").update(value).digest("hex");
|
|
45227
45333
|
}
|
|
45228
45334
|
function fileRecord(root, relativePath) {
|
|
45229
|
-
const path =
|
|
45230
|
-
if (!
|
|
45335
|
+
const path = join15(root, relativePath);
|
|
45336
|
+
if (!existsSync16(path))
|
|
45231
45337
|
return null;
|
|
45232
45338
|
const stat = statSync8(path);
|
|
45233
45339
|
if (!stat.isFile())
|
|
@@ -45239,7 +45345,7 @@ function manifestRecord(root, relativePath) {
|
|
|
45239
45345
|
const base = fileRecord(root, relativePath);
|
|
45240
45346
|
if (!base)
|
|
45241
45347
|
return null;
|
|
45242
|
-
const parsed = readJsonFile(
|
|
45348
|
+
const parsed = readJsonFile(join15(root, relativePath));
|
|
45243
45349
|
if (!parsed)
|
|
45244
45350
|
return { ...base, redacted: {} };
|
|
45245
45351
|
const redacted = redactValue({
|
|
@@ -45334,15 +45440,15 @@ function commandEnv(env, includeValues) {
|
|
|
45334
45440
|
function defaultSnapshotDir() {
|
|
45335
45441
|
const dbPath = getDatabasePath();
|
|
45336
45442
|
if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
|
|
45337
|
-
return
|
|
45338
|
-
return
|
|
45443
|
+
return join15(tmpdir3(), "hasna-todos", "environment-snapshots");
|
|
45444
|
+
return join15(dirname8(resolve16(dbPath)), "environment-snapshots");
|
|
45339
45445
|
}
|
|
45340
45446
|
function snapshotWithId(snapshot) {
|
|
45341
45447
|
const digest = sha2567(JSON.stringify(snapshot)).slice(0, 24);
|
|
45342
45448
|
return { id: `env_${digest}`, ...snapshot };
|
|
45343
45449
|
}
|
|
45344
45450
|
function captureEnvironmentSnapshot(input = {}) {
|
|
45345
|
-
const root =
|
|
45451
|
+
const root = resolve16(input.root || process.cwd());
|
|
45346
45452
|
const env = input.env || process.env;
|
|
45347
45453
|
const warnings = [];
|
|
45348
45454
|
const manifests = MANIFEST_FILES.map((file) => manifestRecord(root, file)).filter((file) => Boolean(file));
|
|
@@ -45382,13 +45488,13 @@ function captureEnvironmentSnapshot(input = {}) {
|
|
|
45382
45488
|
});
|
|
45383
45489
|
}
|
|
45384
45490
|
function writeEnvironmentSnapshot(snapshot, outputPath) {
|
|
45385
|
-
const path = outputPath ?
|
|
45491
|
+
const path = outputPath ? resolve16(outputPath) : join15(defaultSnapshotDir(), `${snapshot.id}.json`);
|
|
45386
45492
|
ensureDir(dirname8(path));
|
|
45387
45493
|
writeJsonFile(path, snapshot);
|
|
45388
45494
|
return path;
|
|
45389
45495
|
}
|
|
45390
45496
|
function readEnvironmentSnapshot(path) {
|
|
45391
|
-
const snapshot = readJsonFile(
|
|
45497
|
+
const snapshot = readJsonFile(resolve16(path));
|
|
45392
45498
|
if (!snapshot || snapshot.schema_version !== 1 || typeof snapshot.id !== "string") {
|
|
45393
45499
|
throw new Error(`Invalid environment snapshot: ${path}`);
|
|
45394
45500
|
}
|
|
@@ -47360,7 +47466,7 @@ class TodosShadowOutbox {
|
|
|
47360
47466
|
const remaining = deadline - Date.now();
|
|
47361
47467
|
if (remaining <= 0)
|
|
47362
47468
|
break;
|
|
47363
|
-
await new Promise((
|
|
47469
|
+
await new Promise((resolve17) => setTimeout(resolve17, Math.min(200, remaining)));
|
|
47364
47470
|
}
|
|
47365
47471
|
}
|
|
47366
47472
|
return this.getStats();
|
|
@@ -50213,7 +50319,7 @@ async function retryOnTransientPostgresError(fn, attempts = 2, delayMs = 150) {
|
|
|
50213
50319
|
lastError = error;
|
|
50214
50320
|
if (!isTransientPostgresError(error) || attempt === attempts)
|
|
50215
50321
|
throw error;
|
|
50216
|
-
await new Promise((
|
|
50322
|
+
await new Promise((resolve17) => setTimeout(resolve17, delayMs * attempt));
|
|
50217
50323
|
}
|
|
50218
50324
|
}
|
|
50219
50325
|
throw lastError;
|
|
@@ -56648,7 +56754,7 @@ var init_headless_boundaries = __esm(() => {
|
|
|
56648
56754
|
});
|
|
56649
56755
|
|
|
56650
56756
|
// src/server/routes.ts
|
|
56651
|
-
import { join as
|
|
56757
|
+
import { join as join16, resolve as resolve17, sep as sep3 } from "path";
|
|
56652
56758
|
function parseFieldsParam(url) {
|
|
56653
56759
|
const fieldsParam = url.searchParams.get("fields");
|
|
56654
56760
|
return fieldsParam ? fieldsParam.split(",").map((f) => f.trim()).filter(Boolean) : undefined;
|
|
@@ -57485,9 +57591,9 @@ function handleStaticFiles(path, method, ctx, json5, serveStaticFile2) {
|
|
|
57485
57591
|
if (!ctx.dashboardExists || method !== "GET" && method !== "HEAD")
|
|
57486
57592
|
return null;
|
|
57487
57593
|
if (path !== "/") {
|
|
57488
|
-
const filePath =
|
|
57489
|
-
const resolvedFile =
|
|
57490
|
-
const resolvedBase =
|
|
57594
|
+
const filePath = join16(ctx.dashboardDir, path);
|
|
57595
|
+
const resolvedFile = resolve17(filePath);
|
|
57596
|
+
const resolvedBase = resolve17(ctx.dashboardDir);
|
|
57491
57597
|
if (!resolvedFile.startsWith(resolvedBase + sep3) && resolvedFile !== resolvedBase) {
|
|
57492
57598
|
return json5({ error: "Forbidden" }, 403);
|
|
57493
57599
|
}
|
|
@@ -57495,7 +57601,7 @@ function handleStaticFiles(path, method, ctx, json5, serveStaticFile2) {
|
|
|
57495
57601
|
if (res2)
|
|
57496
57602
|
return res2;
|
|
57497
57603
|
}
|
|
57498
|
-
const indexPath =
|
|
57604
|
+
const indexPath = join16(ctx.dashboardDir, "index.html");
|
|
57499
57605
|
const res = serveStaticFile2(indexPath);
|
|
57500
57606
|
if (res)
|
|
57501
57607
|
return res;
|
|
@@ -63476,8 +63582,8 @@ class SqlitePrGroupLedgerPersistence {
|
|
|
63476
63582
|
async transaction(fn) {
|
|
63477
63583
|
const previous = sqliteTransactionTails2.get(this.db) ?? Promise.resolve();
|
|
63478
63584
|
let release;
|
|
63479
|
-
const current = new Promise((
|
|
63480
|
-
release =
|
|
63585
|
+
const current = new Promise((resolve18) => {
|
|
63586
|
+
release = resolve18;
|
|
63481
63587
|
});
|
|
63482
63588
|
sqliteTransactionTails2.set(this.db, current);
|
|
63483
63589
|
await previous;
|
|
@@ -63575,27 +63681,27 @@ __export(exports_serve, {
|
|
|
63575
63681
|
SECURITY_HEADERS: () => SECURITY_HEADERS,
|
|
63576
63682
|
MIME_TYPES: () => MIME_TYPES
|
|
63577
63683
|
});
|
|
63578
|
-
import { existsSync as
|
|
63579
|
-
import { join as
|
|
63684
|
+
import { existsSync as existsSync17 } from "fs";
|
|
63685
|
+
import { join as join17, dirname as dirname9, extname } from "path";
|
|
63580
63686
|
import { fileURLToPath } from "url";
|
|
63581
63687
|
function resolveDashboardDir() {
|
|
63582
63688
|
const candidates = [];
|
|
63583
63689
|
try {
|
|
63584
63690
|
const scriptDir = dirname9(fileURLToPath(import.meta.url));
|
|
63585
|
-
candidates.push(
|
|
63586
|
-
candidates.push(
|
|
63691
|
+
candidates.push(join17(scriptDir, "..", "dashboard", "dist"));
|
|
63692
|
+
candidates.push(join17(scriptDir, "..", "..", "dashboard", "dist"));
|
|
63587
63693
|
} catch {}
|
|
63588
63694
|
if (process.argv[1]) {
|
|
63589
63695
|
const mainDir = dirname9(process.argv[1]);
|
|
63590
|
-
candidates.push(
|
|
63591
|
-
candidates.push(
|
|
63696
|
+
candidates.push(join17(mainDir, "..", "dashboard", "dist"));
|
|
63697
|
+
candidates.push(join17(mainDir, "..", "..", "dashboard", "dist"));
|
|
63592
63698
|
}
|
|
63593
|
-
candidates.push(
|
|
63699
|
+
candidates.push(join17(process.cwd(), "dashboard", "dist"));
|
|
63594
63700
|
for (const candidate of candidates) {
|
|
63595
|
-
if (
|
|
63701
|
+
if (existsSync17(candidate))
|
|
63596
63702
|
return candidate;
|
|
63597
63703
|
}
|
|
63598
|
-
return
|
|
63704
|
+
return join17(process.cwd(), "dashboard", "dist");
|
|
63599
63705
|
}
|
|
63600
63706
|
function getProvidedApiKey(req) {
|
|
63601
63707
|
const headerKey = req.headers.get("x-api-key");
|
|
@@ -63667,7 +63773,7 @@ function json4(data, status3 = 200, headers) {
|
|
|
63667
63773
|
});
|
|
63668
63774
|
}
|
|
63669
63775
|
function serveStaticFile(filePath) {
|
|
63670
|
-
if (!
|
|
63776
|
+
if (!existsSync17(filePath))
|
|
63671
63777
|
return null;
|
|
63672
63778
|
const ext = extname(filePath);
|
|
63673
63779
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
@@ -63768,7 +63874,7 @@ data: ${data}
|
|
|
63768
63874
|
filteredSseClients.delete(client);
|
|
63769
63875
|
}
|
|
63770
63876
|
const dashboardDir = resolveDashboardDir();
|
|
63771
|
-
const dashboardExists =
|
|
63877
|
+
const dashboardExists = existsSync17(dashboardDir);
|
|
63772
63878
|
if (!dashboardExists) {
|
|
63773
63879
|
console.error(`
|
|
63774
63880
|
Dashboard not found at: ${dashboardDir}`);
|