@hasna/todos 0.15.49 → 0.15.51
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/commands/query-commands.d.ts.map +1 -1
- package/dist/cli/helpers.d.ts.map +1 -1
- package/dist/cli/index.js +482 -336
- package/dist/contracts.js +193 -94
- package/dist/db/task-crud.d.ts.map +1 -1
- package/dist/index.js +394 -295
- 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 +268 -170
- package/dist/mcp.js +6 -3
- package/dist/project-registration.js +191 -92
- package/dist/registry.js +193 -94
- package/dist/release-provenance.json +5 -5
- package/dist/sdk/index.js +100 -8
- package/dist/server/index.js +437 -216
- 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 +6 -3
- package/postinstall.js +34 -0
package/dist/server/index.js
CHANGED
|
@@ -70,7 +70,7 @@ var package_default;
|
|
|
70
70
|
var init_package = __esm(() => {
|
|
71
71
|
package_default = {
|
|
72
72
|
name: "@hasna/todos",
|
|
73
|
-
version: "0.15.
|
|
73
|
+
version: "0.15.51",
|
|
74
74
|
description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
|
|
75
75
|
type: "module",
|
|
76
76
|
main: "dist/index.js",
|
|
@@ -129,6 +129,7 @@ var init_package = __esm(() => {
|
|
|
129
129
|
files: [
|
|
130
130
|
"dist",
|
|
131
131
|
"dashboard/dist",
|
|
132
|
+
"postinstall.js",
|
|
132
133
|
"LICENSE",
|
|
133
134
|
"README.md"
|
|
134
135
|
],
|
|
@@ -155,7 +156,7 @@ var init_package = __esm(() => {
|
|
|
155
156
|
"test:attested-container-compatibility-vector": "bun test scripts/attested-container-compatibility-vector.test.ts",
|
|
156
157
|
"issue:release-review": "bun run scripts/issue-npm-release-agent-review.ts",
|
|
157
158
|
prepublishOnly: "bun run scripts/verify-public-release.ts --mode=publish",
|
|
158
|
-
postinstall: "
|
|
159
|
+
postinstall: "node postinstall.js"
|
|
159
160
|
},
|
|
160
161
|
keywords: [
|
|
161
162
|
"todos",
|
|
@@ -189,13 +190,15 @@ var init_package = __esm(() => {
|
|
|
189
190
|
author: "Andrei Hasna <andrei@hasna.com>",
|
|
190
191
|
license: "Apache-2.0",
|
|
191
192
|
dependencies: {
|
|
192
|
-
"@hasna/contracts": "0.14.
|
|
193
|
+
"@hasna/contracts": "0.14.2",
|
|
193
194
|
"@hasna/events": "^0.1.11",
|
|
195
|
+
"@hasna/paths": "0.1.0",
|
|
194
196
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
195
197
|
chalk: "^5.4.1",
|
|
196
198
|
commander: "^13.1.0",
|
|
197
199
|
ink: "^5.2.0",
|
|
198
200
|
react: "^18.3.1",
|
|
201
|
+
"signal-exit": "3.0.7",
|
|
199
202
|
zod: "3.25.76"
|
|
200
203
|
},
|
|
201
204
|
overrides: {
|
|
@@ -225,7 +228,7 @@ var init_package_version = __esm(() => {
|
|
|
225
228
|
init_package();
|
|
226
229
|
});
|
|
227
230
|
|
|
228
|
-
// node_modules/.bun/@hasna+contracts@0.14.
|
|
231
|
+
// node_modules/.bun/@hasna+contracts@0.14.2+a5fb9613d5af3331/node_modules/@hasna/contracts/dist/auth/index.js
|
|
229
232
|
import { createHash, createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
230
233
|
function isValidTenantId(value) {
|
|
231
234
|
return typeof value === "string" && TENANT_ID_PATTERN.test(value);
|
|
@@ -1308,18 +1311,112 @@ function normalizeAgentNameInput(name) {
|
|
|
1308
1311
|
return name.trim().toLowerCase();
|
|
1309
1312
|
}
|
|
1310
1313
|
|
|
1311
|
-
//
|
|
1312
|
-
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
|
|
1314
|
+
// node_modules/.bun/@hasna+paths@0.1.0/node_modules/@hasna/paths/dist/index.js
|
|
1313
1315
|
import { homedir } from "os";
|
|
1314
1316
|
import { join } from "path";
|
|
1317
|
+
function assertApp(app) {
|
|
1318
|
+
if (typeof app !== "string" || app.length === 0) {
|
|
1319
|
+
throw new TypeError("paths: app must be a non-empty string");
|
|
1320
|
+
}
|
|
1321
|
+
if (!APP_SLUG_RE.test(app)) {
|
|
1322
|
+
throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
function envOf(options) {
|
|
1326
|
+
return options.env ?? process.env;
|
|
1327
|
+
}
|
|
1328
|
+
function envValue(options, kind) {
|
|
1329
|
+
const value = envOf(options)[KIND_ENV[kind]];
|
|
1330
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
1331
|
+
}
|
|
1332
|
+
function isMacOS(platform) {
|
|
1333
|
+
return platform === "darwin";
|
|
1334
|
+
}
|
|
1335
|
+
function baseDir(kind, options) {
|
|
1336
|
+
const override = envValue(options, kind);
|
|
1337
|
+
if (override)
|
|
1338
|
+
return override;
|
|
1339
|
+
const home = options.home ?? homedir();
|
|
1340
|
+
const platform = options.platform ?? process.platform;
|
|
1341
|
+
if (isMacOS(platform)) {
|
|
1342
|
+
switch (kind) {
|
|
1343
|
+
case "config":
|
|
1344
|
+
case "data":
|
|
1345
|
+
return join(home, "Library", "Application Support", "Hasna");
|
|
1346
|
+
case "cache":
|
|
1347
|
+
return join(home, "Library", "Caches", "Hasna");
|
|
1348
|
+
case "state":
|
|
1349
|
+
return join(home, "Library", "Logs", "Hasna");
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
switch (kind) {
|
|
1353
|
+
case "config":
|
|
1354
|
+
return join(home, ".config", "hasna");
|
|
1355
|
+
case "data":
|
|
1356
|
+
return join(home, ".local", "share", "hasna");
|
|
1357
|
+
case "state":
|
|
1358
|
+
return join(home, ".local", "state", "hasna");
|
|
1359
|
+
case "cache":
|
|
1360
|
+
return join(home, ".cache", "hasna");
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
function resolvePath(kind, options) {
|
|
1364
|
+
assertApp(options.app);
|
|
1365
|
+
const appSegment = options.internal === true ? join("internal", options.app) : options.app;
|
|
1366
|
+
return join(baseDir(kind, options), appSegment);
|
|
1367
|
+
}
|
|
1368
|
+
function dataDir(options) {
|
|
1369
|
+
return resolvePath("data", options);
|
|
1370
|
+
}
|
|
1371
|
+
var KIND_ENV, APP_SLUG_RE;
|
|
1372
|
+
var init_dist = __esm(() => {
|
|
1373
|
+
KIND_ENV = {
|
|
1374
|
+
config: "HASNA_CONFIG_HOME",
|
|
1375
|
+
data: "HASNA_DATA_HOME",
|
|
1376
|
+
state: "HASNA_STATE_HOME",
|
|
1377
|
+
cache: "HASNA_CACHE_HOME"
|
|
1378
|
+
};
|
|
1379
|
+
APP_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
1380
|
+
});
|
|
1381
|
+
|
|
1382
|
+
// src/lib/paths.ts
|
|
1383
|
+
import { existsSync } from "fs";
|
|
1384
|
+
import { homedir as homedir2 } from "os";
|
|
1385
|
+
import { join as join2, resolve } from "path";
|
|
1386
|
+
function effectiveHome(env = process.env) {
|
|
1387
|
+
return env.HOME || env.USERPROFILE || homedir2();
|
|
1388
|
+
}
|
|
1389
|
+
function legacyHomeDir(env = process.env) {
|
|
1390
|
+
return join2(effectiveHome(env), ".hasna", "todos");
|
|
1391
|
+
}
|
|
1392
|
+
function resolverHome(env = process.env) {
|
|
1393
|
+
return dataDir({ app: "todos", home: effectiveHome(env), env });
|
|
1394
|
+
}
|
|
1395
|
+
function adoptResolverHome(resolved, env = process.env) {
|
|
1396
|
+
const dataOverride = env.HASNA_DATA_HOME;
|
|
1397
|
+
if (typeof dataOverride === "string" && dataOverride.trim().length > 0)
|
|
1398
|
+
return true;
|
|
1399
|
+
return existsSync(join2(resolved, "todos.db")) || existsSync(join2(resolved, "config.json"));
|
|
1400
|
+
}
|
|
1401
|
+
function getTodosDir(env = process.env) {
|
|
1402
|
+
const resolved = resolverHome(env);
|
|
1403
|
+
return resolve(adoptResolverHome(resolved, env) ? resolved : legacyHomeDir(env));
|
|
1404
|
+
}
|
|
1405
|
+
var init_paths = __esm(() => {
|
|
1406
|
+
init_dist();
|
|
1407
|
+
});
|
|
1408
|
+
|
|
1409
|
+
// src/lib/sync-utils.ts
|
|
1410
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
|
|
1411
|
+
import { homedir as homedir3 } from "os";
|
|
1315
1412
|
function getHomeDir() {
|
|
1316
|
-
return process.env["HOME"] || process.env["USERPROFILE"] ||
|
|
1413
|
+
return process.env["HOME"] || process.env["USERPROFILE"] || homedir3();
|
|
1317
1414
|
}
|
|
1318
1415
|
function getTodosGlobalDir() {
|
|
1319
|
-
return
|
|
1416
|
+
return getTodosDir();
|
|
1320
1417
|
}
|
|
1321
1418
|
function ensureDir(dir) {
|
|
1322
|
-
if (!
|
|
1419
|
+
if (!existsSync2(dir))
|
|
1323
1420
|
mkdirSync(dir, { recursive: true });
|
|
1324
1421
|
}
|
|
1325
1422
|
function readJsonFile(path) {
|
|
@@ -1340,18 +1437,19 @@ function appendSyncConflict(metadata, conflict, limit = 5) {
|
|
|
1340
1437
|
}
|
|
1341
1438
|
var HOME;
|
|
1342
1439
|
var init_sync_utils = __esm(() => {
|
|
1440
|
+
init_paths();
|
|
1343
1441
|
HOME = getHomeDir();
|
|
1344
1442
|
});
|
|
1345
1443
|
|
|
1346
1444
|
// src/lib/creator-identity.ts
|
|
1347
|
-
import { existsSync as
|
|
1348
|
-
import { join as
|
|
1445
|
+
import { existsSync as existsSync3, rmSync } from "fs";
|
|
1446
|
+
import { join as join3 } from "path";
|
|
1349
1447
|
function identityFilePath() {
|
|
1350
|
-
return
|
|
1448
|
+
return join3(getTodosGlobalDir(), "identity.json");
|
|
1351
1449
|
}
|
|
1352
1450
|
function readPersistedIdentity() {
|
|
1353
1451
|
const path = identityFilePath();
|
|
1354
|
-
if (!
|
|
1452
|
+
if (!existsSync3(path))
|
|
1355
1453
|
return null;
|
|
1356
1454
|
const parsed = readJsonFile(path);
|
|
1357
1455
|
if (!parsed || typeof parsed.agent_id !== "string" || !parsed.agent_id.trim())
|
|
@@ -1499,15 +1597,15 @@ var init_plan_project_link_contract = __esm(() => {
|
|
|
1499
1597
|
});
|
|
1500
1598
|
|
|
1501
1599
|
// src/lib/config.ts
|
|
1502
|
-
import { existsSync as
|
|
1503
|
-
import { dirname, join as
|
|
1600
|
+
import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
|
|
1601
|
+
import { dirname, join as join4 } from "path";
|
|
1504
1602
|
function getConfigPath() {
|
|
1505
|
-
return
|
|
1603
|
+
return join4(getTodosGlobalDir(), "config.json");
|
|
1506
1604
|
}
|
|
1507
1605
|
function loadConfig() {
|
|
1508
1606
|
if (cached)
|
|
1509
1607
|
return cached;
|
|
1510
|
-
if (!
|
|
1608
|
+
if (!existsSync4(getConfigPath())) {
|
|
1511
1609
|
cached = {};
|
|
1512
1610
|
return cached;
|
|
1513
1611
|
}
|
|
@@ -5357,7 +5455,7 @@ async function retryOnTransientPostgresError(fn, attempts = 2, delayMs = 150) {
|
|
|
5357
5455
|
lastError = error;
|
|
5358
5456
|
if (!isTransientPostgresError(error) || attempt === attempts)
|
|
5359
5457
|
throw error;
|
|
5360
|
-
await new Promise((
|
|
5458
|
+
await new Promise((resolve2) => setTimeout(resolve2, delayMs * attempt));
|
|
5361
5459
|
}
|
|
5362
5460
|
}
|
|
5363
5461
|
throw lastError;
|
|
@@ -11134,9 +11232,9 @@ var init_schema = __esm(() => {
|
|
|
11134
11232
|
});
|
|
11135
11233
|
|
|
11136
11234
|
// src/db/machines.ts
|
|
11137
|
-
import { existsSync as
|
|
11235
|
+
import { existsSync as existsSync5 } from "fs";
|
|
11138
11236
|
import { hostname as osHostname, platform as osPlatform, arch as osArch } from "os";
|
|
11139
|
-
import { resolve } from "path";
|
|
11237
|
+
import { resolve as resolve2 } from "path";
|
|
11140
11238
|
import { spawnSync } from "child_process";
|
|
11141
11239
|
function parseMetadata(value) {
|
|
11142
11240
|
if (!value)
|
|
@@ -11167,7 +11265,7 @@ function discoverGitRoot(workspacePath) {
|
|
|
11167
11265
|
}
|
|
11168
11266
|
function topologyMetadata(input, existing = {}) {
|
|
11169
11267
|
const next = { ...existing };
|
|
11170
|
-
const workspacePath = input.workspace_path ?
|
|
11268
|
+
const workspacePath = input.workspace_path ? resolve2(input.workspace_path) : undefined;
|
|
11171
11269
|
const entries = {
|
|
11172
11270
|
tailscale_name: input.tailscale_name,
|
|
11173
11271
|
tailscale_ip: input.tailscale_ip,
|
|
@@ -11341,7 +11439,7 @@ function getMachineTopologyDiagnostics(opts = {}, db, at = new Date) {
|
|
|
11341
11439
|
message: `${project.name} has ${distinctPaths.length} different machine-local paths`
|
|
11342
11440
|
});
|
|
11343
11441
|
}
|
|
11344
|
-
if (localRow && !
|
|
11442
|
+
if (localRow && !existsSync5(localRow.path)) {
|
|
11345
11443
|
pathIssues.push({
|
|
11346
11444
|
type: "path_missing",
|
|
11347
11445
|
project_id: project.id,
|
|
@@ -11352,7 +11450,7 @@ function getMachineTopologyDiagnostics(opts = {}, db, at = new Date) {
|
|
|
11352
11450
|
message: `Local path does not exist on this machine: ${localRow.path}`
|
|
11353
11451
|
});
|
|
11354
11452
|
}
|
|
11355
|
-
if (!localRow && project.path && machineById.has(localMachine.id) && !
|
|
11453
|
+
if (!localRow && project.path && machineById.has(localMachine.id) && !existsSync5(project.path)) {
|
|
11356
11454
|
pathIssues.push({
|
|
11357
11455
|
type: "path_missing",
|
|
11358
11456
|
project_id: project.id,
|
|
@@ -11729,18 +11827,18 @@ __export(exports_database, {
|
|
|
11729
11827
|
LOCK_EXPIRY_MINUTES: () => LOCK_EXPIRY_MINUTES
|
|
11730
11828
|
});
|
|
11731
11829
|
import { Database } from "bun:sqlite";
|
|
11732
|
-
import { existsSync as
|
|
11733
|
-
import { dirname as dirname2, join as
|
|
11830
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync2 } from "fs";
|
|
11831
|
+
import { dirname as dirname2, join as join5, resolve as resolve3 } from "path";
|
|
11734
11832
|
function isInMemoryDb(path) {
|
|
11735
11833
|
return path === ":memory:" || path.startsWith("file::memory:");
|
|
11736
11834
|
}
|
|
11737
11835
|
function findNearestProjectDb(startDir) {
|
|
11738
11836
|
const gitRoot = findGitRoot(startDir);
|
|
11739
|
-
const stopAt = gitRoot ?
|
|
11740
|
-
let dir =
|
|
11837
|
+
const stopAt = gitRoot ? resolve3(gitRoot) : resolve3(startDir);
|
|
11838
|
+
let dir = resolve3(startDir);
|
|
11741
11839
|
while (true) {
|
|
11742
|
-
const candidate =
|
|
11743
|
-
if (
|
|
11840
|
+
const candidate = join5(dir, ".hasna", "todos", "todos.db");
|
|
11841
|
+
if (existsSync6(candidate))
|
|
11744
11842
|
return candidate;
|
|
11745
11843
|
if (dir === stopAt)
|
|
11746
11844
|
break;
|
|
@@ -11752,9 +11850,9 @@ function findNearestProjectDb(startDir) {
|
|
|
11752
11850
|
return null;
|
|
11753
11851
|
}
|
|
11754
11852
|
function findGitRoot(startDir) {
|
|
11755
|
-
let dir =
|
|
11853
|
+
let dir = resolve3(startDir);
|
|
11756
11854
|
while (true) {
|
|
11757
|
-
if (
|
|
11855
|
+
if (existsSync6(join5(dir, ".git")))
|
|
11758
11856
|
return dir;
|
|
11759
11857
|
const parent = dirname2(dir);
|
|
11760
11858
|
if (parent === dir)
|
|
@@ -11764,7 +11862,7 @@ function findGitRoot(startDir) {
|
|
|
11764
11862
|
return null;
|
|
11765
11863
|
}
|
|
11766
11864
|
function getGlobalDbPath() {
|
|
11767
|
-
return
|
|
11865
|
+
return join5(getTodosGlobalDir(), "todos.db");
|
|
11768
11866
|
}
|
|
11769
11867
|
function hasExplicitProjectArg(args = process.argv.slice(2)) {
|
|
11770
11868
|
return args.some((arg) => arg === "--project" || arg.startsWith("--project="));
|
|
@@ -11802,7 +11900,7 @@ function getDbPath() {
|
|
|
11802
11900
|
if (process.env["TODOS_DB_SCOPE"] === "project") {
|
|
11803
11901
|
const gitRoot = findGitRoot(cwd);
|
|
11804
11902
|
if (gitRoot && canCreateScopedProjectDb()) {
|
|
11805
|
-
return
|
|
11903
|
+
return join5(gitRoot, ".hasna", "todos", "todos.db");
|
|
11806
11904
|
}
|
|
11807
11905
|
}
|
|
11808
11906
|
return getGlobalDbPath();
|
|
@@ -11813,8 +11911,8 @@ function getDatabasePath() {
|
|
|
11813
11911
|
function ensureDir2(filePath) {
|
|
11814
11912
|
if (isInMemoryDb(filePath))
|
|
11815
11913
|
return;
|
|
11816
|
-
const dir = dirname2(
|
|
11817
|
-
if (!
|
|
11914
|
+
const dir = dirname2(resolve3(filePath));
|
|
11915
|
+
if (!existsSync6(dir)) {
|
|
11818
11916
|
mkdirSync2(dir, { recursive: true });
|
|
11819
11917
|
}
|
|
11820
11918
|
}
|
|
@@ -12653,14 +12751,14 @@ var init_completion_guard = __esm(() => {
|
|
|
12653
12751
|
|
|
12654
12752
|
// src/lib/event-emission-safety.ts
|
|
12655
12753
|
import { tmpdir } from "os";
|
|
12656
|
-
import { resolve as
|
|
12754
|
+
import { resolve as resolve4, sep } from "path";
|
|
12657
12755
|
function envFlag(name) {
|
|
12658
12756
|
const value = process.env[name]?.trim().toLowerCase();
|
|
12659
12757
|
return value === "1" || value === "true" || value === "yes" || value === "on";
|
|
12660
12758
|
}
|
|
12661
12759
|
function isUnder(parent, child) {
|
|
12662
|
-
const normalizedParent =
|
|
12663
|
-
const normalizedChild =
|
|
12760
|
+
const normalizedParent = resolve4(parent);
|
|
12761
|
+
const normalizedChild = resolve4(child);
|
|
12664
12762
|
return normalizedChild === normalizedParent || normalizedChild.startsWith(`${normalizedParent}${sep}`);
|
|
12665
12763
|
}
|
|
12666
12764
|
function databasePathFromDatabase(db) {
|
|
@@ -12703,9 +12801,9 @@ var init_event_emission_safety = __esm(() => {
|
|
|
12703
12801
|
});
|
|
12704
12802
|
|
|
12705
12803
|
// src/lib/workspace-trust.ts
|
|
12706
|
-
import { relative, resolve as
|
|
12804
|
+
import { relative, resolve as resolve5 } from "path";
|
|
12707
12805
|
function normalizePath(path) {
|
|
12708
|
-
return
|
|
12806
|
+
return resolve5(path);
|
|
12709
12807
|
}
|
|
12710
12808
|
function unique2(values) {
|
|
12711
12809
|
return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));
|
|
@@ -12887,9 +12985,9 @@ var init_workspace_trust = __esm(() => {
|
|
|
12887
12985
|
});
|
|
12888
12986
|
|
|
12889
12987
|
// src/lib/runner-sandbox.ts
|
|
12890
|
-
import { relative as relative2, resolve as
|
|
12988
|
+
import { relative as relative2, resolve as resolve6 } from "path";
|
|
12891
12989
|
function normalizePath2(path) {
|
|
12892
|
-
return
|
|
12990
|
+
return resolve6(path);
|
|
12893
12991
|
}
|
|
12894
12992
|
function unique3(values) {
|
|
12895
12993
|
return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));
|
|
@@ -13079,7 +13177,7 @@ var init_runner_sandbox = __esm(() => {
|
|
|
13079
13177
|
// src/lib/event-hooks.ts
|
|
13080
13178
|
import { createHash as createHash5, randomUUID as randomUUID2 } from "crypto";
|
|
13081
13179
|
import { appendFileSync, mkdirSync as mkdirSync3 } from "fs";
|
|
13082
|
-
import { dirname as dirname3, resolve as
|
|
13180
|
+
import { dirname as dirname3, resolve as resolve7 } from "path";
|
|
13083
13181
|
import { createConnection } from "net";
|
|
13084
13182
|
function safeName(name) {
|
|
13085
13183
|
const trimmed = name.trim();
|
|
@@ -13217,7 +13315,7 @@ async function deliverHook(hook, envelope) {
|
|
|
13217
13315
|
if (hook.target === "stdout") {
|
|
13218
13316
|
output = line.trim();
|
|
13219
13317
|
} else if (hook.target === "file") {
|
|
13220
|
-
const filePath =
|
|
13318
|
+
const filePath = resolve7(hook.file_path);
|
|
13221
13319
|
mkdirSync3(dirname3(filePath), { recursive: true });
|
|
13222
13320
|
appendFileSync(filePath, line);
|
|
13223
13321
|
} else if (hook.target === "socket") {
|
|
@@ -13338,9 +13436,9 @@ var init_event_hooks = __esm(() => {
|
|
|
13338
13436
|
// node_modules/.bun/@hasna+events@0.1.16/node_modules/@hasna/events/dist/index.js
|
|
13339
13437
|
import { chmod, mkdir, readFile, rename, writeFile } from "fs/promises";
|
|
13340
13438
|
import { Buffer as Buffer2 } from "buffer";
|
|
13341
|
-
import { existsSync as
|
|
13342
|
-
import { homedir as
|
|
13343
|
-
import { join as
|
|
13439
|
+
import { existsSync as existsSync7 } from "fs";
|
|
13440
|
+
import { homedir as homedir4 } from "os";
|
|
13441
|
+
import { join as join6 } from "path";
|
|
13344
13442
|
import { createHmac as createHmac2, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
13345
13443
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
13346
13444
|
import { spawn } from "child_process";
|
|
@@ -13441,7 +13539,7 @@ function channelMatchesEvent(channel, event) {
|
|
|
13441
13539
|
return channel.filters.some((filter) => eventMatchesFilter(event, filter));
|
|
13442
13540
|
}
|
|
13443
13541
|
function getEventsDataDir(override) {
|
|
13444
|
-
return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] ||
|
|
13542
|
+
return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join6(homedir4(), ".hasna", "events");
|
|
13445
13543
|
}
|
|
13446
13544
|
|
|
13447
13545
|
class JsonEventsStore {
|
|
@@ -13450,12 +13548,12 @@ class JsonEventsStore {
|
|
|
13450
13548
|
channelsPath;
|
|
13451
13549
|
eventsPath;
|
|
13452
13550
|
deliveriesPath;
|
|
13453
|
-
constructor(
|
|
13454
|
-
this.dataDir =
|
|
13455
|
-
this.runtime = localJsonRuntime(
|
|
13456
|
-
this.channelsPath =
|
|
13457
|
-
this.eventsPath =
|
|
13458
|
-
this.deliveriesPath =
|
|
13551
|
+
constructor(dataDir2 = getEventsDataDir()) {
|
|
13552
|
+
this.dataDir = dataDir2;
|
|
13553
|
+
this.runtime = localJsonRuntime(dataDir2);
|
|
13554
|
+
this.channelsPath = join6(dataDir2, "channels.json");
|
|
13555
|
+
this.eventsPath = join6(dataDir2, "events.json");
|
|
13556
|
+
this.deliveriesPath = join6(dataDir2, "deliveries.json");
|
|
13459
13557
|
}
|
|
13460
13558
|
async init() {
|
|
13461
13559
|
await mkdir(this.dataDir, { recursive: true, mode: 448 });
|
|
@@ -13572,7 +13670,7 @@ class JsonEventsStore {
|
|
|
13572
13670
|
};
|
|
13573
13671
|
}
|
|
13574
13672
|
async ensureArrayFile(path) {
|
|
13575
|
-
if (!
|
|
13673
|
+
if (!existsSync7(path)) {
|
|
13576
13674
|
await writeFile(path, `[]
|
|
13577
13675
|
`, { encoding: "utf-8", mode: 384 });
|
|
13578
13676
|
}
|
|
@@ -13602,7 +13700,7 @@ class JsonEventsStore {
|
|
|
13602
13700
|
});
|
|
13603
13701
|
}
|
|
13604
13702
|
}
|
|
13605
|
-
function localJsonRuntime(
|
|
13703
|
+
function localJsonRuntime(dataDir2 = getEventsDataDir()) {
|
|
13606
13704
|
return {
|
|
13607
13705
|
mode: "local-files",
|
|
13608
13706
|
name: "json-events-store",
|
|
@@ -13615,7 +13713,7 @@ function localJsonRuntime(dataDir = getEventsDataDir()) {
|
|
|
13615
13713
|
durable: true,
|
|
13616
13714
|
idempotency: "best-effort-local",
|
|
13617
13715
|
replayCursors: true,
|
|
13618
|
-
description: `Local JSON files in ${
|
|
13716
|
+
description: `Local JSON files in ${dataDir2}; no SQLite, Postgres, S3, or AWS runtime is configured by this store.`
|
|
13619
13717
|
};
|
|
13620
13718
|
}
|
|
13621
13719
|
function encodeLocalJsonEventCursor(offset, options = {}) {
|
|
@@ -13794,7 +13892,7 @@ async function dispatchCommand(event, channel) {
|
|
|
13794
13892
|
HASNA_EVENT_SCHEMA_VERSION: event.schemaVersion,
|
|
13795
13893
|
HASNA_EVENT_JSON: eventJson
|
|
13796
13894
|
};
|
|
13797
|
-
return new Promise((
|
|
13895
|
+
return new Promise((resolve8) => {
|
|
13798
13896
|
const child = spawn(channel.command.command, channel.command.args ?? [], {
|
|
13799
13897
|
cwd: channel.command.cwd,
|
|
13800
13898
|
env,
|
|
@@ -13812,7 +13910,7 @@ async function dispatchCommand(event, channel) {
|
|
|
13812
13910
|
});
|
|
13813
13911
|
child.on("error", (error) => {
|
|
13814
13912
|
clearTimeout(timeout);
|
|
13815
|
-
|
|
13913
|
+
resolve8({
|
|
13816
13914
|
attempt: 1,
|
|
13817
13915
|
status: "failed",
|
|
13818
13916
|
startedAt,
|
|
@@ -13825,7 +13923,7 @@ async function dispatchCommand(event, channel) {
|
|
|
13825
13923
|
child.on("close", (code, signal) => {
|
|
13826
13924
|
clearTimeout(timeout);
|
|
13827
13925
|
const success = code === 0;
|
|
13828
|
-
|
|
13926
|
+
resolve8({
|
|
13829
13927
|
attempt: 1,
|
|
13830
13928
|
status: success ? "success" : "failed",
|
|
13831
13929
|
startedAt,
|
|
@@ -14167,7 +14265,7 @@ function normalizeRetryPolicy(policy) {
|
|
|
14167
14265
|
};
|
|
14168
14266
|
}
|
|
14169
14267
|
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;
|
|
14170
|
-
var
|
|
14268
|
+
var init_dist2 = __esm(() => {
|
|
14171
14269
|
DEFAULT_SIGNATURE_TOLERANCE_MS = 5 * 60 * 1000;
|
|
14172
14270
|
EventValidationError = class EventValidationError extends Error {
|
|
14173
14271
|
eventType;
|
|
@@ -14587,7 +14685,7 @@ function emitSharedTaskEventQuiet(input) {
|
|
|
14587
14685
|
}
|
|
14588
14686
|
var SOURCE = "todos";
|
|
14589
14687
|
var init_shared_events = __esm(() => {
|
|
14590
|
-
|
|
14688
|
+
init_dist2();
|
|
14591
14689
|
init_database();
|
|
14592
14690
|
init_projects();
|
|
14593
14691
|
init_task_lists();
|
|
@@ -16449,17 +16547,17 @@ function sanitizeCreateTaskInput(input) {
|
|
|
16449
16547
|
return {
|
|
16450
16548
|
...input,
|
|
16451
16549
|
title: sanitizePreWriteText(input.title, "task.title"),
|
|
16452
|
-
description: input.description
|
|
16550
|
+
description: input.description == null ? input.description : sanitizePreWriteText(input.description, "task.description"),
|
|
16453
16551
|
tags: input.tags !== undefined ? sanitizePreWriteValue(input.tags, "task.tags") : undefined,
|
|
16454
16552
|
metadata: input.metadata !== undefined ? sanitizePreWriteValue(input.metadata, "task.metadata") : undefined,
|
|
16455
|
-
reason: input.reason
|
|
16553
|
+
reason: input.reason == null ? input.reason : sanitizePreWriteText(input.reason, "task.reason")
|
|
16456
16554
|
};
|
|
16457
16555
|
}
|
|
16458
16556
|
function sanitizeUpdateTaskInput(input) {
|
|
16459
16557
|
return {
|
|
16460
16558
|
...input,
|
|
16461
16559
|
title: input.title !== undefined ? sanitizePreWriteText(input.title, "task.title") : undefined,
|
|
16462
|
-
description: input.description
|
|
16560
|
+
description: input.description == null ? input.description : sanitizePreWriteText(input.description, "task.description"),
|
|
16463
16561
|
tags: input.tags !== undefined ? sanitizePreWriteValue(input.tags, "task.tags") : undefined,
|
|
16464
16562
|
metadata: input.metadata !== undefined ? sanitizePreWriteValue(input.metadata, "task.metadata") : undefined
|
|
16465
16563
|
};
|
|
@@ -18456,28 +18554,28 @@ var init_boards = __esm(() => {
|
|
|
18456
18554
|
|
|
18457
18555
|
// src/lib/artifact-store.ts
|
|
18458
18556
|
import { createHash as createHash6 } from "crypto";
|
|
18459
|
-
import { existsSync as
|
|
18460
|
-
import { basename, dirname as dirname4, join as
|
|
18557
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync3, rmSync as rmSync2, statSync as statSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
18558
|
+
import { basename, dirname as dirname4, join as join7, resolve as resolve8 } from "path";
|
|
18461
18559
|
import { tmpdir as tmpdir2 } from "os";
|
|
18462
18560
|
function isInMemoryDb2(path) {
|
|
18463
18561
|
return path === ":memory:" || path.startsWith("file::memory:");
|
|
18464
18562
|
}
|
|
18465
18563
|
function artifactStoreRoot() {
|
|
18466
18564
|
if (process.env["HASNA_TODOS_ARTIFACTS_DIR"])
|
|
18467
|
-
return
|
|
18565
|
+
return resolve8(process.env["HASNA_TODOS_ARTIFACTS_DIR"]);
|
|
18468
18566
|
if (process.env["TODOS_ARTIFACTS_DIR"])
|
|
18469
|
-
return
|
|
18567
|
+
return resolve8(process.env["TODOS_ARTIFACTS_DIR"]);
|
|
18470
18568
|
const dbPath = getDatabasePath();
|
|
18471
18569
|
if (isInMemoryDb2(dbPath))
|
|
18472
|
-
return
|
|
18473
|
-
return
|
|
18570
|
+
return join7(tmpdir2(), "hasna-todos-artifacts");
|
|
18571
|
+
return join7(dirname4(resolve8(dbPath)), "artifacts");
|
|
18474
18572
|
}
|
|
18475
18573
|
function artifactStorePath(relativePath) {
|
|
18476
18574
|
const normalized = relativePath.replace(/\\/g, "/");
|
|
18477
18575
|
if (normalized.includes("..") || normalized.startsWith("/") || normalized.length === 0) {
|
|
18478
18576
|
throw new Error("Invalid artifact store path");
|
|
18479
18577
|
}
|
|
18480
|
-
return
|
|
18578
|
+
return join7(artifactStoreRoot(), normalized);
|
|
18481
18579
|
}
|
|
18482
18580
|
function sha2562(buffer) {
|
|
18483
18581
|
return createHash6("sha256").update(buffer).digest("hex");
|
|
@@ -18517,8 +18615,8 @@ function mediaTypeFor(path, textLike) {
|
|
|
18517
18615
|
return "application/octet-stream";
|
|
18518
18616
|
}
|
|
18519
18617
|
function storeArtifactContent(input) {
|
|
18520
|
-
const sourcePath =
|
|
18521
|
-
if (!
|
|
18618
|
+
const sourcePath = resolve8(input.path);
|
|
18619
|
+
if (!existsSync8(sourcePath))
|
|
18522
18620
|
return null;
|
|
18523
18621
|
const sourceStat = statSync2(sourcePath);
|
|
18524
18622
|
if (!sourceStat.isFile())
|
|
@@ -18535,9 +18633,9 @@ function storeArtifactContent(input) {
|
|
|
18535
18633
|
redactionStatus = "redacted";
|
|
18536
18634
|
}
|
|
18537
18635
|
const storedSha = sha2562(storedBuffer);
|
|
18538
|
-
const relativePath =
|
|
18636
|
+
const relativePath = join7("sha256", storedSha.slice(0, 2), storedSha).replace(/\\/g, "/");
|
|
18539
18637
|
const destination = artifactStorePath(relativePath);
|
|
18540
|
-
if (!
|
|
18638
|
+
if (!existsSync8(destination)) {
|
|
18541
18639
|
mkdirSync4(dirname4(destination), { recursive: true });
|
|
18542
18640
|
writeFileSync2(destination, storedBuffer);
|
|
18543
18641
|
}
|
|
@@ -18597,7 +18695,7 @@ function verifyStoredArtifact(input) {
|
|
|
18597
18695
|
};
|
|
18598
18696
|
}
|
|
18599
18697
|
const storedPath = artifactStorePath(store.relative_path);
|
|
18600
|
-
if (!
|
|
18698
|
+
if (!existsSync8(storedPath)) {
|
|
18601
18699
|
return {
|
|
18602
18700
|
id: input.id,
|
|
18603
18701
|
path: input.path,
|
|
@@ -31161,8 +31259,8 @@ var exports_doctor = {};
|
|
|
31161
31259
|
__export(exports_doctor, {
|
|
31162
31260
|
runTodosDoctor: () => runTodosDoctor
|
|
31163
31261
|
});
|
|
31164
|
-
import { chmodSync, copyFileSync, existsSync as
|
|
31165
|
-
import { basename as basename2, dirname as dirname5, join as
|
|
31262
|
+
import { chmodSync, copyFileSync, existsSync as existsSync9, mkdirSync as mkdirSync5, statSync as statSync3 } from "fs";
|
|
31263
|
+
import { basename as basename2, dirname as dirname5, join as join8 } from "path";
|
|
31166
31264
|
function tableExists2(db, table) {
|
|
31167
31265
|
return Boolean(db.query("SELECT name FROM sqlite_master WHERE type='table' AND name=?").get(table));
|
|
31168
31266
|
}
|
|
@@ -31256,7 +31354,7 @@ function findMissingProjectRoots(db) {
|
|
|
31256
31354
|
continue;
|
|
31257
31355
|
if (!row.path.startsWith("/"))
|
|
31258
31356
|
continue;
|
|
31259
|
-
if (!
|
|
31357
|
+
if (!existsSync9(row.path))
|
|
31260
31358
|
missing++;
|
|
31261
31359
|
}
|
|
31262
31360
|
return missing;
|
|
@@ -31316,16 +31414,16 @@ function databasePermissionsAreUnsafe(dbPath) {
|
|
|
31316
31414
|
function createBackup(dbPath) {
|
|
31317
31415
|
if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
|
|
31318
31416
|
return;
|
|
31319
|
-
if (!
|
|
31417
|
+
if (!existsSync9(dbPath))
|
|
31320
31418
|
return;
|
|
31321
31419
|
const stamp = now().replace(/[:.]/g, "-");
|
|
31322
|
-
const backupDir =
|
|
31420
|
+
const backupDir = join8(dirname5(dbPath), `${basename2(dbPath)}.backup-${stamp}`);
|
|
31323
31421
|
const files = [];
|
|
31324
31422
|
mkdirSync5(backupDir, { recursive: true });
|
|
31325
31423
|
for (const source of [dbPath, `${dbPath}-wal`, `${dbPath}-shm`]) {
|
|
31326
|
-
if (!
|
|
31424
|
+
if (!existsSync9(source))
|
|
31327
31425
|
continue;
|
|
31328
|
-
const target =
|
|
31426
|
+
const target = join8(backupDir, basename2(source));
|
|
31329
31427
|
copyFileSync(source, target);
|
|
31330
31428
|
files.push(target);
|
|
31331
31429
|
}
|
|
@@ -31584,7 +31682,7 @@ var init_doctor = __esm(() => {
|
|
|
31584
31682
|
});
|
|
31585
31683
|
|
|
31586
31684
|
// src/server/routes.ts
|
|
31587
|
-
import { join as
|
|
31685
|
+
import { join as join9, resolve as resolve9, sep as sep2 } from "path";
|
|
31588
31686
|
function parseFieldsParam(url) {
|
|
31589
31687
|
const fieldsParam = url.searchParams.get("fields");
|
|
31590
31688
|
return fieldsParam ? fieldsParam.split(",").map((f) => f.trim()).filter(Boolean) : undefined;
|
|
@@ -32421,9 +32519,9 @@ function handleStaticFiles(path, method, ctx, json5, serveStaticFile2) {
|
|
|
32421
32519
|
if (!ctx.dashboardExists || method !== "GET" && method !== "HEAD")
|
|
32422
32520
|
return null;
|
|
32423
32521
|
if (path !== "/") {
|
|
32424
|
-
const filePath =
|
|
32425
|
-
const resolvedFile =
|
|
32426
|
-
const resolvedBase =
|
|
32522
|
+
const filePath = join9(ctx.dashboardDir, path);
|
|
32523
|
+
const resolvedFile = resolve9(filePath);
|
|
32524
|
+
const resolvedBase = resolve9(ctx.dashboardDir);
|
|
32427
32525
|
if (!resolvedFile.startsWith(resolvedBase + sep2) && resolvedFile !== resolvedBase) {
|
|
32428
32526
|
return json5({ error: "Forbidden" }, 403);
|
|
32429
32527
|
}
|
|
@@ -32431,7 +32529,7 @@ function handleStaticFiles(path, method, ctx, json5, serveStaticFile2) {
|
|
|
32431
32529
|
if (res2)
|
|
32432
32530
|
return res2;
|
|
32433
32531
|
}
|
|
32434
|
-
const indexPath =
|
|
32532
|
+
const indexPath = join9(ctx.dashboardDir, "index.html");
|
|
32435
32533
|
const res = serveStaticFile2(indexPath);
|
|
32436
32534
|
if (res)
|
|
32437
32535
|
return res;
|
|
@@ -32538,7 +32636,7 @@ class TodosShadowOutbox {
|
|
|
32538
32636
|
const remaining = deadline - Date.now();
|
|
32539
32637
|
if (remaining <= 0)
|
|
32540
32638
|
break;
|
|
32541
|
-
await new Promise((
|
|
32639
|
+
await new Promise((resolve10) => setTimeout(resolve10, Math.min(200, remaining)));
|
|
32542
32640
|
}
|
|
32543
32641
|
}
|
|
32544
32642
|
return this.getStats();
|
|
@@ -44573,9 +44671,9 @@ data:
|
|
|
44573
44671
|
const initRequest = messages.find((m) => isInitializeRequest(m));
|
|
44574
44672
|
const clientProtocolVersion = initRequest ? initRequest.params.protocolVersion : req.headers.get("mcp-protocol-version") ?? DEFAULT_NEGOTIATED_PROTOCOL_VERSION;
|
|
44575
44673
|
if (this._enableJsonResponse) {
|
|
44576
|
-
return new Promise((
|
|
44674
|
+
return new Promise((resolve10) => {
|
|
44577
44675
|
this._streamMapping.set(streamId, {
|
|
44578
|
-
resolveJson:
|
|
44676
|
+
resolveJson: resolve10,
|
|
44579
44677
|
cleanup: () => {
|
|
44580
44678
|
this._streamMapping.delete(streamId);
|
|
44581
44679
|
}
|
|
@@ -47002,7 +47100,7 @@ class Protocol {
|
|
|
47002
47100
|
return;
|
|
47003
47101
|
}
|
|
47004
47102
|
const pollInterval = task3.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1000;
|
|
47005
|
-
await new Promise((
|
|
47103
|
+
await new Promise((resolve10) => setTimeout(resolve10, pollInterval));
|
|
47006
47104
|
options?.signal?.throwIfAborted();
|
|
47007
47105
|
}
|
|
47008
47106
|
} catch (error3) {
|
|
@@ -47014,7 +47112,7 @@ class Protocol {
|
|
|
47014
47112
|
}
|
|
47015
47113
|
request(request, resultSchema, options) {
|
|
47016
47114
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task: task2, relatedTask } = options ?? {};
|
|
47017
|
-
return new Promise((
|
|
47115
|
+
return new Promise((resolve10, reject) => {
|
|
47018
47116
|
const earlyReject = (error3) => {
|
|
47019
47117
|
reject(error3);
|
|
47020
47118
|
};
|
|
@@ -47092,7 +47190,7 @@ class Protocol {
|
|
|
47092
47190
|
if (!parseResult.success) {
|
|
47093
47191
|
reject(parseResult.error);
|
|
47094
47192
|
} else {
|
|
47095
|
-
|
|
47193
|
+
resolve10(parseResult.data);
|
|
47096
47194
|
}
|
|
47097
47195
|
} catch (error3) {
|
|
47098
47196
|
reject(error3);
|
|
@@ -47283,12 +47381,12 @@ class Protocol {
|
|
|
47283
47381
|
interval = task2.pollInterval;
|
|
47284
47382
|
}
|
|
47285
47383
|
} catch {}
|
|
47286
|
-
return new Promise((
|
|
47384
|
+
return new Promise((resolve10, reject) => {
|
|
47287
47385
|
if (signal.aborted) {
|
|
47288
47386
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
47289
47387
|
return;
|
|
47290
47388
|
}
|
|
47291
|
-
const timeoutId = setTimeout(
|
|
47389
|
+
const timeoutId = setTimeout(resolve10, interval);
|
|
47292
47390
|
signal.addEventListener("abort", () => {
|
|
47293
47391
|
clearTimeout(timeoutId);
|
|
47294
47392
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -50273,7 +50371,7 @@ var require_compile = __commonJS((exports) => {
|
|
|
50273
50371
|
const schOrFunc = root.refs[ref];
|
|
50274
50372
|
if (schOrFunc)
|
|
50275
50373
|
return schOrFunc;
|
|
50276
|
-
let _sch =
|
|
50374
|
+
let _sch = resolve10.call(this, root, ref);
|
|
50277
50375
|
if (_sch === undefined) {
|
|
50278
50376
|
const schema2 = (_a = root.localRefs) === null || _a === undefined ? undefined : _a[ref];
|
|
50279
50377
|
const { schemaId } = this.opts;
|
|
@@ -50300,7 +50398,7 @@ var require_compile = __commonJS((exports) => {
|
|
|
50300
50398
|
function sameSchemaEnv(s1, s2) {
|
|
50301
50399
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
50302
50400
|
}
|
|
50303
|
-
function
|
|
50401
|
+
function resolve10(root, ref) {
|
|
50304
50402
|
let sch;
|
|
50305
50403
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
50306
50404
|
ref = sch;
|
|
@@ -50886,7 +50984,7 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
50886
50984
|
}
|
|
50887
50985
|
return uri;
|
|
50888
50986
|
}
|
|
50889
|
-
function
|
|
50987
|
+
function resolve10(baseURI, relativeURI, options) {
|
|
50890
50988
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
50891
50989
|
const resolved = resolveComponent(parse6(baseURI, schemelessOptions), parse6(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
50892
50990
|
schemelessOptions.skipEscape = true;
|
|
@@ -51145,7 +51243,7 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
51145
51243
|
var fastUri = {
|
|
51146
51244
|
SCHEMES,
|
|
51147
51245
|
normalize: normalize2,
|
|
51148
|
-
resolve:
|
|
51246
|
+
resolve: resolve10,
|
|
51149
51247
|
resolveComponent,
|
|
51150
51248
|
equal,
|
|
51151
51249
|
serialize,
|
|
@@ -54716,7 +54814,7 @@ class McpServer {
|
|
|
54716
54814
|
let task2 = createTaskResult.task;
|
|
54717
54815
|
const pollInterval = task2.pollInterval ?? 5000;
|
|
54718
54816
|
while (task2.status !== "completed" && task2.status !== "failed" && task2.status !== "cancelled") {
|
|
54719
|
-
await new Promise((
|
|
54817
|
+
await new Promise((resolve10) => setTimeout(resolve10, pollInterval));
|
|
54720
54818
|
const updatedTask = await extra.taskStore.getTask(taskId);
|
|
54721
54819
|
if (!updatedTask) {
|
|
54722
54820
|
throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`);
|
|
@@ -55361,12 +55459,12 @@ class StdioServerTransport {
|
|
|
55361
55459
|
this.onclose?.();
|
|
55362
55460
|
}
|
|
55363
55461
|
send(message) {
|
|
55364
|
-
return new Promise((
|
|
55462
|
+
return new Promise((resolve10) => {
|
|
55365
55463
|
const json7 = serializeMessage(message);
|
|
55366
55464
|
if (this._stdout.write(json7)) {
|
|
55367
|
-
|
|
55465
|
+
resolve10();
|
|
55368
55466
|
} else {
|
|
55369
|
-
this._stdout.once("drain",
|
|
55467
|
+
this._stdout.once("drain", resolve10);
|
|
55370
55468
|
}
|
|
55371
55469
|
});
|
|
55372
55470
|
}
|
|
@@ -56515,10 +56613,10 @@ var init_token_utils = __esm(() => {
|
|
|
56515
56613
|
|
|
56516
56614
|
// src/lib/assignee-validation.ts
|
|
56517
56615
|
import { readFileSync as readFileSync4 } from "fs";
|
|
56518
|
-
import { homedir as
|
|
56519
|
-
import { join as
|
|
56616
|
+
import { homedir as homedir5 } from "os";
|
|
56617
|
+
import { join as join10 } from "path";
|
|
56520
56618
|
function defaultSeatRosterPath() {
|
|
56521
|
-
return process.env["TODOS_SEAT_ROSTER_PATH"] ||
|
|
56619
|
+
return process.env["TODOS_SEAT_ROSTER_PATH"] || join10(homedir5(), ".hasna", "identities", "hasna-seats.roster.json");
|
|
56522
56620
|
}
|
|
56523
56621
|
function loadSeatSlugs(path = defaultSeatRosterPath()) {
|
|
56524
56622
|
try {
|
|
@@ -56608,10 +56706,11 @@ var init_assignee_context = __esm(() => {
|
|
|
56608
56706
|
init_assignee_validation();
|
|
56609
56707
|
});
|
|
56610
56708
|
|
|
56611
|
-
// node_modules/.bun/@hasna+contracts@0.14.
|
|
56709
|
+
// node_modules/.bun/@hasna+contracts@0.14.2+a5fb9613d5af3331/node_modules/@hasna/contracts/dist/client/storage.js
|
|
56612
56710
|
import { isIP } from "net";
|
|
56613
56711
|
import { readFileSync as readFileSync5, statSync as statSync4 } from "fs";
|
|
56614
|
-
import {
|
|
56712
|
+
import { createRequire } from "module";
|
|
56713
|
+
import { join as join11 } from "path";
|
|
56615
56714
|
function envToken(name) {
|
|
56616
56715
|
return name.toUpperCase().replace(/-/g, "_");
|
|
56617
56716
|
}
|
|
@@ -56625,24 +56724,48 @@ function clientTransportEnvKeys(name) {
|
|
|
56625
56724
|
function credentialOverrideEnvKey(name) {
|
|
56626
56725
|
return `HASNA_${envToken(name)}_API_KEY_OVERRIDE`;
|
|
56627
56726
|
}
|
|
56727
|
+
function credentialPointerEnvKey(name) {
|
|
56728
|
+
return `HASNA_${envToken(name)}_API_KEY_REF`;
|
|
56729
|
+
}
|
|
56628
56730
|
function homeDir(env) {
|
|
56629
56731
|
const home = env.HOME?.trim();
|
|
56630
56732
|
return home ? home : null;
|
|
56631
56733
|
}
|
|
56632
|
-
function
|
|
56633
|
-
return profileDiskSources(name, env, null);
|
|
56634
|
-
}
|
|
56635
|
-
function profileDiskSources(name, env, profile) {
|
|
56734
|
+
function credentialDiskSourceList(name, env, profile = null) {
|
|
56636
56735
|
const home = homeDir(env);
|
|
56637
56736
|
if (!home || !SAFE_APP_SLUG.test(name))
|
|
56638
56737
|
return [];
|
|
56639
56738
|
const stem = profile ? `${name}.${profile}` : name;
|
|
56640
56739
|
const configStem = profile ? `${name}-${profile}` : name;
|
|
56641
56740
|
return [
|
|
56642
|
-
|
|
56643
|
-
|
|
56741
|
+
{
|
|
56742
|
+
path: join11(home, HASNA_STATE_DIR, FLEET_CREDENTIAL_DIR, `${stem}.env`),
|
|
56743
|
+
tier: "fleet-env",
|
|
56744
|
+
deprecated: false
|
|
56745
|
+
},
|
|
56746
|
+
{
|
|
56747
|
+
path: join11(home, HASNA_STATE_DIR, LEGACY_CLOUD_DIR, `${stem}.env`),
|
|
56748
|
+
tier: "legacy-cloud",
|
|
56749
|
+
deprecated: true
|
|
56750
|
+
},
|
|
56751
|
+
{
|
|
56752
|
+
path: join11(home, CONFIG_DIR, CONFIG_NAMESPACE, `${configStem}.env`),
|
|
56753
|
+
tier: "config",
|
|
56754
|
+
deprecated: false
|
|
56755
|
+
},
|
|
56756
|
+
{
|
|
56757
|
+
path: join11(home, CONFIG_DIR, CONFIG_NAMESPACE, `${configStem}-cloud.env`),
|
|
56758
|
+
tier: "config-legacy",
|
|
56759
|
+
deprecated: true
|
|
56760
|
+
}
|
|
56644
56761
|
];
|
|
56645
56762
|
}
|
|
56763
|
+
function credentialDiskSources(name, env) {
|
|
56764
|
+
return credentialDiskSourceList(name, env, null).map((s) => s.path);
|
|
56765
|
+
}
|
|
56766
|
+
function profileDiskSources(name, env, profile) {
|
|
56767
|
+
return credentialDiskSourceList(name, env, profile).map((s) => s.path);
|
|
56768
|
+
}
|
|
56646
56769
|
function parseEnvFile(text) {
|
|
56647
56770
|
const values = new Map;
|
|
56648
56771
|
for (const rawLine of text.split(/\r?\n/)) {
|
|
@@ -56709,6 +56832,9 @@ function appConfigDiskValue(name, env, keys) {
|
|
|
56709
56832
|
return null;
|
|
56710
56833
|
}
|
|
56711
56834
|
function assertUsableCredential(appName, source, value) {
|
|
56835
|
+
if (VAULT_POINTER_SHAPE.test(value)) {
|
|
56836
|
+
throw new CredentialResolutionError(appName, `The credential from ${source} looks like a secrets-vault pointer (a path-shaped reference like ` + `'namespace/app/live/api_key'). A vault path is NEVER accepted as a literal API key. ` + `Use ${credentialPointerEnvKey(appName)} to resolve the key through the vault, or provide the actual key value.`, [source]);
|
|
56837
|
+
}
|
|
56712
56838
|
if (!ILLEGAL_IN_HEADER_VALUE.test(value))
|
|
56713
56839
|
return;
|
|
56714
56840
|
throw new CredentialResolutionError(appName, `The credential from ${source} contains characters that cannot be sent in an HTTP header ` + `(a control character or non-ASCII byte). A file written with CR-only line endings is the usual ` + `cause. Rewrite that credential file with one LF-terminated KEY=value line. ` + `The value is not shown here, and is deliberately never logged.`, [source]);
|
|
@@ -56730,6 +56856,14 @@ function sealCredential(fields) {
|
|
|
56730
56856
|
writable: false,
|
|
56731
56857
|
configurable: false
|
|
56732
56858
|
});
|
|
56859
|
+
if (fields.pointerVaultKey !== undefined) {
|
|
56860
|
+
Object.defineProperty(sealed, "pointerVaultKey", {
|
|
56861
|
+
value: fields.pointerVaultKey,
|
|
56862
|
+
enumerable: false,
|
|
56863
|
+
writable: false,
|
|
56864
|
+
configurable: false
|
|
56865
|
+
});
|
|
56866
|
+
}
|
|
56733
56867
|
Object.defineProperty(sealed, INSPECT_CUSTOM, {
|
|
56734
56868
|
value: () => ({ ...visible, apiKey: "[redacted]" }),
|
|
56735
56869
|
enumerable: false,
|
|
@@ -56781,7 +56915,8 @@ function validateAndSealResolvedCredential(appName, credential) {
|
|
|
56781
56915
|
deliberate: credential.deliberate,
|
|
56782
56916
|
deprecated: credential.deprecated,
|
|
56783
56917
|
diskCandidates: credential.diskCandidates,
|
|
56784
|
-
warning: credential.warning
|
|
56918
|
+
warning: credential.warning,
|
|
56919
|
+
...credential.pointerVaultKey !== undefined ? { pointerVaultKey: credential.pointerVaultKey } : {}
|
|
56785
56920
|
});
|
|
56786
56921
|
}
|
|
56787
56922
|
function firstEnvValue(env, keys) {
|
|
@@ -56841,6 +56976,27 @@ function resolveCredential(name, env, options = {}) {
|
|
|
56841
56976
|
warning: null
|
|
56842
56977
|
});
|
|
56843
56978
|
}
|
|
56979
|
+
const pointerKeyName = credentialPointerEnvKey(name);
|
|
56980
|
+
const pointerRaw = env[pointerKeyName];
|
|
56981
|
+
if (pointerRaw !== undefined) {
|
|
56982
|
+
const pointer = pointerRaw.trim();
|
|
56983
|
+
if (!pointer) {
|
|
56984
|
+
throw new CredentialResolutionError(name, `${pointerKeyName} is set but empty. It is a deliberate vault pointer, so it is not resolved around: ` + `either give it a vault item key or unset it to fall back to the credential on disk.`, [pointerKeyName]);
|
|
56985
|
+
}
|
|
56986
|
+
if (!VAULT_POINTER_SHAPE.test(pointer)) {
|
|
56987
|
+
throw new CredentialResolutionError(name, `${pointerKeyName} must name a vault ITEM KEY (a path-shaped reference like ` + `'namespace/app/live/api_key'), not a credential value. A pointer that carries a literal is refused.`, [pointerKeyName]);
|
|
56988
|
+
}
|
|
56989
|
+
return sealCredential({
|
|
56990
|
+
apiKey: "",
|
|
56991
|
+
pointerVaultKey: pointer,
|
|
56992
|
+
tier: "pointer",
|
|
56993
|
+
source: pointerKeyName,
|
|
56994
|
+
deliberate: true,
|
|
56995
|
+
deprecated: false,
|
|
56996
|
+
diskCandidates: diskPaths,
|
|
56997
|
+
warning: null
|
|
56998
|
+
});
|
|
56999
|
+
}
|
|
56844
57000
|
const profile = options.profile?.trim() || env[CREDENTIAL_PROFILE_ENV_KEY]?.trim();
|
|
56845
57001
|
if (profile) {
|
|
56846
57002
|
const profileSource = options.profile?.trim() ? "explicit profile argument" : CREDENTIAL_PROFILE_ENV_KEY;
|
|
@@ -56865,26 +57021,42 @@ function resolveCredential(name, env, options = {}) {
|
|
|
56865
57021
|
}
|
|
56866
57022
|
throw new CredentialResolutionError(name, `Profile '${profile}' (from ${profileSource}) has no ${apiKeyKeys[0]} for '${name}'. ` + `Looked in: ${paths.join(", ") || "<no HOME in this environment>"}. ` + `A profile names WHICH identity to use, so it is never resolved around \u2014 ` + `create the profile's credential file or unset ${CREDENTIAL_PROFILE_ENV_KEY}.`, paths);
|
|
56867
57023
|
}
|
|
56868
|
-
const
|
|
57024
|
+
const diskSourceList = credentialDiskSourceList(name, env, null);
|
|
57025
|
+
const diskHits = diskSourceList.map((src) => ({ src, value: readCredentialFile(src.path, apiKeyKeys) })).filter((hit) => hit.value !== null);
|
|
56869
57026
|
if (diskHits.length > 0) {
|
|
56870
57027
|
const winner = diskHits[0];
|
|
56871
|
-
assertUsableCredential(name, winner.path, winner.value);
|
|
57028
|
+
assertUsableCredential(name, winner.src.path, winner.value);
|
|
56872
57029
|
const divergentSources = [
|
|
56873
|
-
...diskHits.slice(1).filter((hit) => hit.value !== winner.value).map((hit) => hit.path),
|
|
57030
|
+
...diskHits.slice(1).filter((hit) => hit.value !== winner.value).map((hit) => hit.src.path),
|
|
56874
57031
|
...(() => {
|
|
56875
57032
|
const legacyHit = firstEnvValue(env, apiKeyKeys);
|
|
56876
57033
|
return legacyHit && legacyHit.value !== winner.value ? [legacyHit.key] : [];
|
|
56877
57034
|
})()
|
|
56878
57035
|
];
|
|
56879
|
-
const warning = divergentSources.length > 0 ? `Credential sources disagree for '${name}': ${winner.path} and ` + `${divergentSources.join(", ")} hold different keys. ${winner.path} wins, because a file on ` + `disk is re-read on every call while an environment variable is a snapshot. Reconcile them \u2014 ` + `a rotation that updated only one leaves the other to fail 401 wherever it is loaded first.` : null;
|
|
57036
|
+
const warning = divergentSources.length > 0 ? `Credential sources disagree for '${name}': ${winner.src.path} and ` + `${divergentSources.join(", ")} hold different keys. ${winner.src.path} wins, because a file on ` + `disk is re-read on every call while an environment variable is a snapshot. Reconcile them \u2014 ` + `a rotation that updated only one leaves the other to fail 401 wherever it is loaded first.` : null;
|
|
57037
|
+
let deprecated = winner.src.deprecated;
|
|
57038
|
+
let finalWarning = warning;
|
|
57039
|
+
if (winner.src.deprecated) {
|
|
57040
|
+
deprecated = true;
|
|
57041
|
+
const sink = options.onDeprecation ?? defaultDeprecationSink;
|
|
57042
|
+
const notified = deprecationNotified();
|
|
57043
|
+
const noticeKey = `${name}:${winner.src.path}`;
|
|
57044
|
+
if (!notified.has(noticeKey)) {
|
|
57045
|
+
notified.add(noticeKey);
|
|
57046
|
+
const target = diskSourceList[0]?.path ?? "<none>";
|
|
57047
|
+
const message = `[${name}] DEPRECATED: the API key came from ${winner.src.path} \u2014 a legacy credential location. ` + `The primary location is ${target} (~/.hasna/fleet-env/<app>.env). The legacy 'cloud' tiers are ` + `removed after ${LEGACY_CLOUD_REMOVAL_DEADLINE}. Migrate the key to the primary location.`;
|
|
57048
|
+
sink(message);
|
|
57049
|
+
}
|
|
57050
|
+
finalWarning = [warning, `Legacy credential source: ${winner.src.path}. Removed after ${LEGACY_CLOUD_REMOVAL_DEADLINE}.`].filter(Boolean).join(" ") || null;
|
|
57051
|
+
}
|
|
56880
57052
|
return sealCredential({
|
|
56881
57053
|
apiKey: winner.value,
|
|
56882
|
-
tier:
|
|
56883
|
-
source: winner.path,
|
|
57054
|
+
tier: winner.src.tier,
|
|
57055
|
+
source: winner.src.path,
|
|
56884
57056
|
deliberate: false,
|
|
56885
|
-
deprecated
|
|
57057
|
+
deprecated,
|
|
56886
57058
|
diskCandidates: diskPaths,
|
|
56887
|
-
warning
|
|
57059
|
+
warning: finalWarning
|
|
56888
57060
|
});
|
|
56889
57061
|
}
|
|
56890
57062
|
const legacy = firstEnvValue(env, apiKeyKeys);
|
|
@@ -56910,6 +57082,45 @@ function resolveCredential(name, env, options = {}) {
|
|
|
56910
57082
|
}
|
|
56911
57083
|
return null;
|
|
56912
57084
|
}
|
|
57085
|
+
async function completePointerCredential(name, pointerResolution, env = process.env) {
|
|
57086
|
+
const vaultKey = pointerResolution.pointerVaultKey;
|
|
57087
|
+
const pointerEnvKey = pointerResolution.source;
|
|
57088
|
+
if (!vaultKey) {
|
|
57089
|
+
throw new CredentialResolutionError(name, `Pointer resolution from ${pointerEnvKey} carries no vault item key; this is a defect in the resolver.`, [pointerEnvKey]);
|
|
57090
|
+
}
|
|
57091
|
+
let secretsSdk;
|
|
57092
|
+
try {
|
|
57093
|
+
secretsSdk = requireSecretsSdk(SECRETS_PACKAGE_SPECIFIER);
|
|
57094
|
+
} catch {
|
|
57095
|
+
throw new CredentialResolutionError(name, `${pointerEnvKey} names vault item '${vaultKey}', but the secrets SDK (@hasna/secrets) is not installed ` + `in this process. A vault pointer is TERMINAL: install @hasna/secrets to resolve it, or unset ${pointerEnvKey}.`, [pointerEnvKey]);
|
|
57096
|
+
}
|
|
57097
|
+
let client;
|
|
57098
|
+
try {
|
|
57099
|
+
client = secretsSdk.createSecretsClientFromEnv(env);
|
|
57100
|
+
} catch {
|
|
57101
|
+
throw new CredentialResolutionError(name, `${pointerEnvKey} names vault item '${vaultKey}', but the secrets client could not be configured from this ` + `environment (the secrets service URL and key env are missing or invalid). A vault pointer is TERMINAL and ` + `never falls through to a literal or disk credential.`, [pointerEnvKey]);
|
|
57102
|
+
}
|
|
57103
|
+
let secret;
|
|
57104
|
+
try {
|
|
57105
|
+
secret = await client.getSecret({ key: vaultKey });
|
|
57106
|
+
} catch {
|
|
57107
|
+
throw new CredentialResolutionError(name, `${pointerEnvKey} names vault item '${vaultKey}', but the vault could not be reached or the item is ` + `unavailable. A vault pointer is TERMINAL and never falls through to a literal or disk credential.`, [pointerEnvKey]);
|
|
57108
|
+
}
|
|
57109
|
+
const value = secret.value;
|
|
57110
|
+
if (!value) {
|
|
57111
|
+
throw new CredentialResolutionError(name, `${pointerEnvKey} resolved vault item '${vaultKey}', but it holds no value. A vault pointer is TERMINAL.`, [pointerEnvKey]);
|
|
57112
|
+
}
|
|
57113
|
+
assertUsableCredential(name, `${pointerEnvKey} -> vault:${vaultKey}`, value);
|
|
57114
|
+
return sealCredential({
|
|
57115
|
+
apiKey: value,
|
|
57116
|
+
tier: "pointer",
|
|
57117
|
+
source: `${pointerEnvKey} -> vault:${vaultKey}`,
|
|
57118
|
+
deliberate: true,
|
|
57119
|
+
deprecated: false,
|
|
57120
|
+
diskCandidates: pointerResolution.diskCandidates,
|
|
57121
|
+
warning: null
|
|
57122
|
+
});
|
|
57123
|
+
}
|
|
56913
57124
|
function isValidDnsDomain(value) {
|
|
56914
57125
|
if (value.length === 0 || value.length > 253 || ASCII_CONTROL_PATTERN.test(value) || /[^\x00-\x7f]/.test(value)) {
|
|
56915
57126
|
return false;
|
|
@@ -57133,6 +57344,13 @@ function currentCredential(name, apiKey) {
|
|
|
57133
57344
|
}
|
|
57134
57345
|
return explicitCredential(name, apiKey);
|
|
57135
57346
|
}
|
|
57347
|
+
async function resolveRequestCredential(name, apiKey, env = process.env) {
|
|
57348
|
+
const resolved = currentCredential(name, apiKey);
|
|
57349
|
+
if (resolved.tier === "pointer") {
|
|
57350
|
+
return completePointerCredential(name, resolved, env);
|
|
57351
|
+
}
|
|
57352
|
+
return resolved;
|
|
57353
|
+
}
|
|
57136
57354
|
function authFailureGuidance(credential) {
|
|
57137
57355
|
const origin = `The API key for this request came from ${credential.source}`;
|
|
57138
57356
|
if (credential.deliberate) {
|
|
@@ -57278,7 +57496,7 @@ function createHasnaHttpTransport(options) {
|
|
|
57278
57496
|
const retry = resolveRetry(opts.retry);
|
|
57279
57497
|
const methodRetryable = IDEMPOTENT_METHODS.has(upper) || Boolean(opts.idempotencyKey);
|
|
57280
57498
|
const maxAttempts = retry && methodRetryable ? retry.retries + 1 : 1;
|
|
57281
|
-
const credential =
|
|
57499
|
+
const credential = await resolveRequestCredential(options.name, options.apiKey);
|
|
57282
57500
|
let last = null;
|
|
57283
57501
|
for (let attempt = 1;attempt <= maxAttempts; attempt++) {
|
|
57284
57502
|
const result = await once(upper, rel, url, body2, opts, credential);
|
|
@@ -57441,7 +57659,7 @@ function resolveStorageClient(name, env = process.env, overrides) {
|
|
|
57441
57659
|
}
|
|
57442
57660
|
return { transport: "sqlite", client: null };
|
|
57443
57661
|
}
|
|
57444
|
-
var CREDENTIAL_PROFILE_ENV_KEY = "HASNA_PROFILE", CredentialResolutionError, HASNA_STATE_DIR = ".hasna", FLEET_CREDENTIAL_DIR = "cloud", CONFIG_DIR = ".config", CONFIG_NAMESPACE = "hasna", MAX_CREDENTIAL_FILE_BYTES, SAFE_APP_SLUG, SAFE_PROFILE, ILLEGAL_IN_HEADER_VALUE, CREDENTIAL_SHAPED_KEY, INSPECT_CUSTOM, CREDENTIAL_SEAL, CALLER_SUPPLIED_CREDENTIAL_PROVIDER_SOURCE = "caller-supplied CredentialProvider", DEPRECATION_REGISTRY, ASCII_CONTROL_PATTERN, DNS_LABEL_PATTERN, HasnaHttpError, DEFAULT_RETRY_STATUSES, IDEMPOTENT_METHODS, AUTHORITY_OVERRIDE_HEADERS, defaultSleep = (ms) => new Promise((
|
|
57662
|
+
var CREDENTIAL_PROFILE_ENV_KEY = "HASNA_PROFILE", CredentialResolutionError, HASNA_STATE_DIR = ".hasna", FLEET_CREDENTIAL_DIR = "fleet-env", LEGACY_CLOUD_DIR = "cloud", CONFIG_DIR = ".config", CONFIG_NAMESPACE = "hasna", LEGACY_CLOUD_REMOVAL_DEADLINE = "2026-10-01", MAX_CREDENTIAL_FILE_BYTES, SAFE_APP_SLUG, SAFE_PROFILE, ILLEGAL_IN_HEADER_VALUE, VAULT_POINTER_SHAPE, CREDENTIAL_SHAPED_KEY, INSPECT_CUSTOM, CREDENTIAL_SEAL, CALLER_SUPPLIED_CREDENTIAL_PROVIDER_SOURCE = "caller-supplied CredentialProvider", DEPRECATION_REGISTRY, SECRETS_PACKAGE_SPECIFIER, requireSecretsSdk, ASCII_CONTROL_PATTERN, DNS_LABEL_PATTERN, HasnaHttpError, DEFAULT_RETRY_STATUSES, IDEMPOTENT_METHODS, AUTHORITY_OVERRIDE_HEADERS, defaultSleep = (ms) => new Promise((resolve10) => setTimeout(resolve10, ms));
|
|
57445
57663
|
var init_storage = __esm(() => {
|
|
57446
57664
|
CredentialResolutionError = class CredentialResolutionError extends Error {
|
|
57447
57665
|
appName;
|
|
@@ -57457,10 +57675,13 @@ var init_storage = __esm(() => {
|
|
|
57457
57675
|
SAFE_APP_SLUG = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
57458
57676
|
SAFE_PROFILE = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;
|
|
57459
57677
|
ILLEGAL_IN_HEADER_VALUE = /[^\t\x20-\x7e]/;
|
|
57678
|
+
VAULT_POINTER_SHAPE = /^[a-z0-9][a-z0-9-]*(?:\/[a-z0-9][a-z0-9-_.]*){2,}$/;
|
|
57460
57679
|
CREDENTIAL_SHAPED_KEY = /(?:^|_)(?:API_KEY|KEY|TOKEN|SECRET|PASSWORD|PASSWD|CREDENTIAL|AUTH)(?:_|$)/;
|
|
57461
57680
|
INSPECT_CUSTOM = Symbol.for("nodejs.util.inspect.custom");
|
|
57462
57681
|
CREDENTIAL_SEAL = Symbol.for("hasna:contracts:sealedCredential");
|
|
57463
57682
|
DEPRECATION_REGISTRY = Symbol.for("hasna:contracts:credentialDeprecationNotices");
|
|
57683
|
+
SECRETS_PACKAGE_SPECIFIER = "@hasna/" + "secrets";
|
|
57684
|
+
requireSecretsSdk = createRequire(import.meta.url);
|
|
57464
57685
|
ASCII_CONTROL_PATTERN = /[\u0000-\u001f\u007f]/;
|
|
57465
57686
|
DNS_LABEL_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
57466
57687
|
HasnaHttpError = class HasnaHttpError extends Error {
|
|
@@ -58339,7 +58560,7 @@ var init_page_validation = __esm(() => {
|
|
|
58339
58560
|
|
|
58340
58561
|
// src/cli/cloud-router.ts
|
|
58341
58562
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
58342
|
-
import { resolve as
|
|
58563
|
+
import { resolve as resolvePath2 } from "path";
|
|
58343
58564
|
function emitTodosLocalFallbackNotice(env) {
|
|
58344
58565
|
if (todosLocalFallbackNoticeEmitted)
|
|
58345
58566
|
return;
|
|
@@ -58905,11 +59126,11 @@ function resolveCloudProjectRef(projects, ref) {
|
|
|
58905
59126
|
const input = ref.trim();
|
|
58906
59127
|
const normalizedRef = input.toLowerCase();
|
|
58907
59128
|
const pathLike = input.startsWith(".") || input.includes("/") || input.includes("\\");
|
|
58908
|
-
const normalizedPath = pathLike ?
|
|
59129
|
+
const normalizedPath = pathLike ? resolvePath2(input) : undefined;
|
|
58909
59130
|
const slug = cloudProjectSlug(pathLike ? cloudProjectPathBasename(input) : input);
|
|
58910
59131
|
const matchGroups = [
|
|
58911
59132
|
uniqueProjectMatches(projects, (project) => project.id.toLowerCase() === normalizedRef),
|
|
58912
|
-
uniqueProjectMatches(projects, (project) => project.path === input || normalizedPath !== undefined &&
|
|
59133
|
+
uniqueProjectMatches(projects, (project) => project.path === input || normalizedPath !== undefined && resolvePath2(project.path) === normalizedPath),
|
|
58913
59134
|
uniqueProjectMatches(projects, (project) => project.name.toLowerCase() === normalizedRef),
|
|
58914
59135
|
uniqueProjectMatches(projects, (project) => project.task_list_id === input || cloudProjectSlug(project.name) === slug || cloudProjectSlug(cloudProjectPathBasename(project.path)) === slug),
|
|
58915
59136
|
uniqueProjectMatches(projects, (project) => project.id.toLowerCase().startsWith(normalizedRef))
|
|
@@ -59493,8 +59714,8 @@ var init_task_crud2 = __esm(() => {
|
|
|
59493
59714
|
});
|
|
59494
59715
|
|
|
59495
59716
|
// src/lib/project-bootstrap.ts
|
|
59496
|
-
import { existsSync as
|
|
59497
|
-
import { basename as basename3, dirname as dirname6, resolve as
|
|
59717
|
+
import { existsSync as existsSync10, readFileSync as readFileSync6, statSync as statSync5 } from "fs";
|
|
59718
|
+
import { basename as basename3, dirname as dirname6, resolve as resolve10 } from "path";
|
|
59498
59719
|
function safeStat(path) {
|
|
59499
59720
|
try {
|
|
59500
59721
|
return statSync5(path);
|
|
@@ -59503,7 +59724,7 @@ function safeStat(path) {
|
|
|
59503
59724
|
}
|
|
59504
59725
|
}
|
|
59505
59726
|
function canonicalPath(input) {
|
|
59506
|
-
const resolved =
|
|
59727
|
+
const resolved = resolve10(input);
|
|
59507
59728
|
const stats = safeStat(resolved);
|
|
59508
59729
|
if (stats?.isFile())
|
|
59509
59730
|
return dirname6(resolved);
|
|
@@ -59512,7 +59733,7 @@ function canonicalPath(input) {
|
|
|
59512
59733
|
function findUp(start, marker) {
|
|
59513
59734
|
let current = canonicalPath(start);
|
|
59514
59735
|
while (true) {
|
|
59515
|
-
if (
|
|
59736
|
+
if (existsSync10(resolve10(current, marker)))
|
|
59516
59737
|
return current;
|
|
59517
59738
|
const parent = dirname6(current);
|
|
59518
59739
|
if (parent === current)
|
|
@@ -59523,8 +59744,8 @@ function findUp(start, marker) {
|
|
|
59523
59744
|
function readPackageJson(path) {
|
|
59524
59745
|
if (!path)
|
|
59525
59746
|
return null;
|
|
59526
|
-
const file =
|
|
59527
|
-
if (!
|
|
59747
|
+
const file = resolve10(path, "package.json");
|
|
59748
|
+
if (!existsSync10(file))
|
|
59528
59749
|
return null;
|
|
59529
59750
|
try {
|
|
59530
59751
|
const parsed = JSON.parse(readFileSync6(file, "utf-8"));
|
|
@@ -59546,7 +59767,7 @@ function workspaceMarker(root, rootPackage) {
|
|
|
59546
59767
|
if (rootPackage?.workspaces)
|
|
59547
59768
|
markers.push("package.json#workspaces");
|
|
59548
59769
|
for (const marker of ["pnpm-workspace.yaml", "turbo.json", "nx.json", "lerna.json", "rush.json", "bun.lock", "bun.lockb"]) {
|
|
59549
|
-
if (
|
|
59770
|
+
if (existsSync10(resolve10(root, marker)))
|
|
59550
59771
|
markers.push(marker);
|
|
59551
59772
|
}
|
|
59552
59773
|
const kind = markers.find((marker) => marker !== "bun.lock" && marker !== "bun.lockb") ?? null;
|
|
@@ -59859,7 +60080,7 @@ var init_tags = __esm(() => {
|
|
|
59859
60080
|
});
|
|
59860
60081
|
|
|
59861
60082
|
// src/lib/retention-cleanup.ts
|
|
59862
|
-
import { existsSync as
|
|
60083
|
+
import { existsSync as existsSync11, unlinkSync } from "fs";
|
|
59863
60084
|
function normalizeScopes(scopes) {
|
|
59864
60085
|
if (!scopes || scopes.length === 0)
|
|
59865
60086
|
return [...ALL_SCOPES];
|
|
@@ -60062,7 +60283,7 @@ function applyRetentionCleanup(input, db) {
|
|
|
60062
60283
|
for (const artifact of report.candidates.artifact_files) {
|
|
60063
60284
|
try {
|
|
60064
60285
|
const path = artifactStorePath(artifact.relative_path);
|
|
60065
|
-
if (!
|
|
60286
|
+
if (!existsSync11(path)) {
|
|
60066
60287
|
report.warnings.push(`stored artifact already missing: ${artifact.relative_path}`);
|
|
60067
60288
|
continue;
|
|
60068
60289
|
}
|
|
@@ -60089,8 +60310,8 @@ var init_retention_cleanup = __esm(() => {
|
|
|
60089
60310
|
});
|
|
60090
60311
|
|
|
60091
60312
|
// src/lib/mention-resolver.ts
|
|
60092
|
-
import { existsSync as
|
|
60093
|
-
import { basename as basename4, isAbsolute, join as
|
|
60313
|
+
import { existsSync as existsSync12, readdirSync as readdirSync2, readFileSync as readFileSync7, statSync as statSync6 } from "fs";
|
|
60314
|
+
import { basename as basename4, isAbsolute, join as join12, relative as relative3, resolve as resolve11, sep as sep3 } from "path";
|
|
60094
60315
|
function blankResolution(parsed) {
|
|
60095
60316
|
return {
|
|
60096
60317
|
input: parsed.input,
|
|
@@ -60113,7 +60334,7 @@ function backlink(kind, key2, label, target = key2) {
|
|
|
60113
60334
|
return { kind, key: key2, label, target };
|
|
60114
60335
|
}
|
|
60115
60336
|
function normalizeWorkspace(workspace) {
|
|
60116
|
-
return
|
|
60337
|
+
return resolve11(workspace || process.cwd());
|
|
60117
60338
|
}
|
|
60118
60339
|
function isInside(root, absolutePath) {
|
|
60119
60340
|
const rel = relative3(root, absolutePath);
|
|
@@ -60181,14 +60402,14 @@ function resolveFile(parsed, workspace) {
|
|
|
60181
60402
|
resolution.warnings.push("path is empty or escapes the workspace");
|
|
60182
60403
|
return resolution;
|
|
60183
60404
|
}
|
|
60184
|
-
const absolutePath =
|
|
60405
|
+
const absolutePath = resolve11(workspace, relPath);
|
|
60185
60406
|
if (!isInside(workspace, absolutePath)) {
|
|
60186
60407
|
resolution.path = relPath;
|
|
60187
60408
|
resolution.warnings.push("path escapes the workspace");
|
|
60188
60409
|
return resolution;
|
|
60189
60410
|
}
|
|
60190
60411
|
resolution.path = relPath;
|
|
60191
|
-
if (!
|
|
60412
|
+
if (!existsSync12(absolutePath)) {
|
|
60192
60413
|
resolution.warnings.push("file does not exist in the local workspace");
|
|
60193
60414
|
return resolution;
|
|
60194
60415
|
}
|
|
@@ -60221,7 +60442,7 @@ function walkSourceFiles(root, current = root, files = []) {
|
|
|
60221
60442
|
if (SKIP_DIRS.has(entry2.name))
|
|
60222
60443
|
continue;
|
|
60223
60444
|
}
|
|
60224
|
-
const absolutePath =
|
|
60445
|
+
const absolutePath = join12(current, entry2.name);
|
|
60225
60446
|
if (entry2.isDirectory()) {
|
|
60226
60447
|
if (!SKIP_DIRS.has(entry2.name))
|
|
60227
60448
|
walkSourceFiles(root, absolutePath, files);
|
|
@@ -60526,9 +60747,9 @@ var init_mention_resolver = __esm(() => {
|
|
|
60526
60747
|
});
|
|
60527
60748
|
|
|
60528
60749
|
// src/lib/policy-packs.ts
|
|
60529
|
-
import { relative as relative4, resolve as
|
|
60750
|
+
import { relative as relative4, resolve as resolve12 } from "path";
|
|
60530
60751
|
function normalizePath3(path) {
|
|
60531
|
-
return
|
|
60752
|
+
return resolve12(path);
|
|
60532
60753
|
}
|
|
60533
60754
|
function unique4(values) {
|
|
60534
60755
|
return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));
|
|
@@ -60583,7 +60804,7 @@ function commandMatches(commands, pattern) {
|
|
|
60583
60804
|
}
|
|
60584
60805
|
function pathMatches(paths, pattern, root) {
|
|
60585
60806
|
return paths.filter((path) => {
|
|
60586
|
-
const candidate = path.startsWith("/") ? path :
|
|
60807
|
+
const candidate = path.startsWith("/") ? path : resolve12(root, path);
|
|
60587
60808
|
if (!isPathInside3(root, candidate))
|
|
60588
60809
|
return matchesPattern3(path, pattern);
|
|
60589
60810
|
return matchesPattern3(path, pattern) || matchesPattern3(relative4(root, candidate), pattern);
|
|
@@ -63962,7 +64183,7 @@ var init_audit_ledger = __esm(() => {
|
|
|
63962
64183
|
|
|
63963
64184
|
// src/lib/release-compatibility.ts
|
|
63964
64185
|
import { readFileSync as readFileSync8 } from "fs";
|
|
63965
|
-
import { join as
|
|
64186
|
+
import { join as join13, resolve as resolve13 } from "path";
|
|
63966
64187
|
import { Database as Database2 } from "bun:sqlite";
|
|
63967
64188
|
function pass(id, message, details) {
|
|
63968
64189
|
return { id, status: "passed", message, details };
|
|
@@ -63974,7 +64195,7 @@ function warn(id, message, details) {
|
|
|
63974
64195
|
return { id, status: "warning", message, details };
|
|
63975
64196
|
}
|
|
63976
64197
|
function readPackageJson2(root) {
|
|
63977
|
-
return JSON.parse(readFileSync8(
|
|
64198
|
+
return JSON.parse(readFileSync8(join13(root, "package.json"), "utf8"));
|
|
63978
64199
|
}
|
|
63979
64200
|
function sortedKeys(value) {
|
|
63980
64201
|
return Object.keys(value ?? {}).sort((left, right) => left.localeCompare(right));
|
|
@@ -64070,7 +64291,7 @@ function checkChangelog() {
|
|
|
64070
64291
|
];
|
|
64071
64292
|
}
|
|
64072
64293
|
function createReleaseCompatibilityReport(options = {}) {
|
|
64073
|
-
const root =
|
|
64294
|
+
const root = resolve13(options.root ?? process.cwd());
|
|
64074
64295
|
const packageJson = readPackageJson2(root);
|
|
64075
64296
|
const simulatedLevels = options.simulated_levels ?? defaultSimulationLevels();
|
|
64076
64297
|
const checks4 = [
|
|
@@ -91181,7 +91402,7 @@ var require_protocol = __commonJS((exports) => {
|
|
|
91181
91402
|
return;
|
|
91182
91403
|
}
|
|
91183
91404
|
const pollInterval = task3.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1000;
|
|
91184
|
-
await new Promise((
|
|
91405
|
+
await new Promise((resolve14) => setTimeout(resolve14, pollInterval));
|
|
91185
91406
|
options?.signal?.throwIfAborted();
|
|
91186
91407
|
}
|
|
91187
91408
|
} catch (error3) {
|
|
@@ -91193,7 +91414,7 @@ var require_protocol = __commonJS((exports) => {
|
|
|
91193
91414
|
}
|
|
91194
91415
|
request(request, resultSchema, options) {
|
|
91195
91416
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task: task2, relatedTask } = options ?? {};
|
|
91196
|
-
return new Promise((
|
|
91417
|
+
return new Promise((resolve14, reject) => {
|
|
91197
91418
|
const earlyReject = (error3) => {
|
|
91198
91419
|
reject(error3);
|
|
91199
91420
|
};
|
|
@@ -91271,7 +91492,7 @@ var require_protocol = __commonJS((exports) => {
|
|
|
91271
91492
|
if (!parseResult.success) {
|
|
91272
91493
|
reject(parseResult.error);
|
|
91273
91494
|
} else {
|
|
91274
|
-
|
|
91495
|
+
resolve14(parseResult.data);
|
|
91275
91496
|
}
|
|
91276
91497
|
} catch (error3) {
|
|
91277
91498
|
reject(error3);
|
|
@@ -91462,12 +91683,12 @@ var require_protocol = __commonJS((exports) => {
|
|
|
91462
91683
|
interval = task2.pollInterval;
|
|
91463
91684
|
}
|
|
91464
91685
|
} catch {}
|
|
91465
|
-
return new Promise((
|
|
91686
|
+
return new Promise((resolve14, reject) => {
|
|
91466
91687
|
if (signal.aborted) {
|
|
91467
91688
|
reject(new types_js_1.McpError(types_js_1.ErrorCode.InvalidRequest, "Request cancelled"));
|
|
91468
91689
|
return;
|
|
91469
91690
|
}
|
|
91470
|
-
const timeoutId = setTimeout(
|
|
91691
|
+
const timeoutId = setTimeout(resolve14, interval);
|
|
91471
91692
|
signal.addEventListener("abort", () => {
|
|
91472
91693
|
clearTimeout(timeoutId);
|
|
91473
91694
|
reject(new types_js_1.McpError(types_js_1.ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -92661,7 +92882,7 @@ var require_mcp = __commonJS((exports) => {
|
|
|
92661
92882
|
let task2 = createTaskResult.task;
|
|
92662
92883
|
const pollInterval = task2.pollInterval ?? 5000;
|
|
92663
92884
|
while (task2.status !== "completed" && task2.status !== "failed" && task2.status !== "cancelled") {
|
|
92664
|
-
await new Promise((
|
|
92885
|
+
await new Promise((resolve14) => setTimeout(resolve14, pollInterval));
|
|
92665
92886
|
const updatedTask = await extra.taskStore.getTask(taskId);
|
|
92666
92887
|
if (!updatedTask) {
|
|
92667
92888
|
throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Task ${taskId} not found during polling`);
|
|
@@ -93980,7 +94201,7 @@ var init_agent_run_dispatcher = __esm(() => {
|
|
|
93980
94201
|
});
|
|
93981
94202
|
|
|
93982
94203
|
// src/lib/verification-providers.ts
|
|
93983
|
-
import { existsSync as
|
|
94204
|
+
import { existsSync as existsSync13, readFileSync as readFileSync9 } from "fs";
|
|
93984
94205
|
function normalizeName5(name) {
|
|
93985
94206
|
const normalized = name.trim().toLowerCase();
|
|
93986
94207
|
if (!/^[a-z0-9][a-z0-9_-]{0,63}$/.test(normalized)) {
|
|
@@ -94077,7 +94298,7 @@ function classifyLog(text) {
|
|
|
94077
94298
|
async function sleep2(ms) {
|
|
94078
94299
|
if (ms <= 0)
|
|
94079
94300
|
return;
|
|
94080
|
-
await new Promise((
|
|
94301
|
+
await new Promise((resolve14) => setTimeout(resolve14, ms));
|
|
94081
94302
|
}
|
|
94082
94303
|
async function runCommandProvider(provider, input) {
|
|
94083
94304
|
const commandTemplate = input.command || provider.command;
|
|
@@ -94132,7 +94353,7 @@ Timed out after ${provider.timeout_ms}ms`);
|
|
|
94132
94353
|
};
|
|
94133
94354
|
}
|
|
94134
94355
|
function runCiLogProvider(input) {
|
|
94135
|
-
const text = input.log_text ?? (input.log_path &&
|
|
94356
|
+
const text = input.log_text ?? (input.log_path && existsSync13(input.log_path) ? readFileSync9(input.log_path, "utf-8") : "");
|
|
94136
94357
|
return {
|
|
94137
94358
|
status: classifyLog(text),
|
|
94138
94359
|
attempts: 1,
|
|
@@ -94144,7 +94365,7 @@ function runBrowserProvider(input) {
|
|
|
94144
94365
|
if (!input.artifact_path) {
|
|
94145
94366
|
return { status: "unknown", attempts: 1, exit_code: null, output_summary: "browser provider needs a screenshot or artifact path" };
|
|
94146
94367
|
}
|
|
94147
|
-
if (!
|
|
94368
|
+
if (!existsSync13(input.artifact_path)) {
|
|
94148
94369
|
return { status: "failed", attempts: 1, exit_code: null, output_summary: `artifact not found: ${input.artifact_path}` };
|
|
94149
94370
|
}
|
|
94150
94371
|
return {
|
|
@@ -96874,7 +97095,7 @@ var init_local_bridge = __esm(() => {
|
|
|
96874
97095
|
// src/lib/local-backups.ts
|
|
96875
97096
|
import { createHash as createHash12 } from "crypto";
|
|
96876
97097
|
import { readFileSync as readFileSync10, writeFileSync as writeFileSync3 } from "fs";
|
|
96877
|
-
import { dirname as dirname7, resolve as
|
|
97098
|
+
import { dirname as dirname7, resolve as resolve14 } from "path";
|
|
96878
97099
|
import { mkdirSync as mkdirSync6 } from "fs";
|
|
96879
97100
|
function stableJson2(value) {
|
|
96880
97101
|
if (value === null || typeof value !== "object")
|
|
@@ -96976,14 +97197,14 @@ function createLocalBackup(options = {}, db) {
|
|
|
96976
97197
|
return backup;
|
|
96977
97198
|
}
|
|
96978
97199
|
function writeLocalBackupFile(backup, outputPath) {
|
|
96979
|
-
const path =
|
|
97200
|
+
const path = resolve14(outputPath);
|
|
96980
97201
|
mkdirSync6(dirname7(path), { recursive: true });
|
|
96981
97202
|
writeFileSync3(path, `${JSON.stringify(backup, null, 2)}
|
|
96982
97203
|
`);
|
|
96983
97204
|
return path;
|
|
96984
97205
|
}
|
|
96985
97206
|
function readLocalBackupFile(path) {
|
|
96986
|
-
return JSON.parse(readFileSync10(
|
|
97207
|
+
return JSON.parse(readFileSync10(resolve14(path), "utf-8"));
|
|
96987
97208
|
}
|
|
96988
97209
|
function verifyLocalBackup(value, options = {}, db) {
|
|
96989
97210
|
const verifiedAt = options.verified_at ?? now();
|
|
@@ -98435,8 +98656,8 @@ __export(exports_local_extensions, {
|
|
|
98435
98656
|
discoverLocalExtensions: () => discoverLocalExtensions
|
|
98436
98657
|
});
|
|
98437
98658
|
import { createHash as createHash15, createVerify } from "crypto";
|
|
98438
|
-
import { existsSync as
|
|
98439
|
-
import { basename as basename5, join as
|
|
98659
|
+
import { existsSync as existsSync14, readdirSync as readdirSync3, readFileSync as readFileSync11, statSync as statSync7 } from "fs";
|
|
98660
|
+
import { basename as basename5, join as join14, resolve as resolve15 } from "path";
|
|
98440
98661
|
function isObject3(value) {
|
|
98441
98662
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
98442
98663
|
}
|
|
@@ -98694,11 +98915,11 @@ function verifyExtensionSignature(input) {
|
|
|
98694
98915
|
return verifier.verify(input.public_key, decodeSignature(input.signature));
|
|
98695
98916
|
}
|
|
98696
98917
|
function inspectExtensionSource(source3) {
|
|
98697
|
-
const resolved =
|
|
98698
|
-
if (!
|
|
98918
|
+
const resolved = resolve15(source3);
|
|
98919
|
+
if (!existsSync14(resolved))
|
|
98699
98920
|
throw new Error(`extension source not found: ${source3}`);
|
|
98700
98921
|
const stat = statSync7(resolved);
|
|
98701
|
-
const manifestPath = stat.isDirectory() ? [
|
|
98922
|
+
const manifestPath = stat.isDirectory() ? [join14(resolved, "todos.extension.json"), join14(resolved, "extension.json")].find(existsSync14) : resolved;
|
|
98702
98923
|
if (!manifestPath)
|
|
98703
98924
|
throw new Error(`extension directory ${source3} is missing todos.extension.json`);
|
|
98704
98925
|
const raw = readFileSync11(manifestPath);
|
|
@@ -98792,26 +99013,26 @@ function testExtensionCompatibility(sourceOrManifest) {
|
|
|
98792
99013
|
function projectExtensionSources(projectPath) {
|
|
98793
99014
|
if (!projectPath)
|
|
98794
99015
|
return [];
|
|
98795
|
-
const root =
|
|
99016
|
+
const root = resolve15(projectPath);
|
|
98796
99017
|
const candidates = [
|
|
98797
|
-
|
|
98798
|
-
|
|
99018
|
+
join14(root, "todos.extension.json"),
|
|
99019
|
+
join14(root, ".todos", "todos.extension.json")
|
|
98799
99020
|
];
|
|
98800
|
-
const extensionDir =
|
|
98801
|
-
if (
|
|
99021
|
+
const extensionDir = join14(root, ".todos", "extensions");
|
|
99022
|
+
if (existsSync14(extensionDir)) {
|
|
98802
99023
|
for (const entry2 of readdirSync3(extensionDir)) {
|
|
98803
99024
|
if (entry2.startsWith("."))
|
|
98804
99025
|
continue;
|
|
98805
|
-
const full =
|
|
99026
|
+
const full = join14(extensionDir, entry2);
|
|
98806
99027
|
if (statSync7(full).isDirectory() || entry2.endsWith(".json"))
|
|
98807
99028
|
candidates.push(full);
|
|
98808
99029
|
}
|
|
98809
99030
|
}
|
|
98810
|
-
return candidates.filter(
|
|
99031
|
+
return candidates.filter(existsSync14);
|
|
98811
99032
|
}
|
|
98812
99033
|
function discoverLocalExtensions(options = {}) {
|
|
98813
99034
|
const config2 = loadConfig();
|
|
98814
|
-
const projectPath = options.project_path ?
|
|
99035
|
+
const projectPath = options.project_path ? resolve15(options.project_path) : null;
|
|
98815
99036
|
const configuredSources = [
|
|
98816
99037
|
...config2.extension_sources || [],
|
|
98817
99038
|
...projectPath ? config2.project_overrides?.[projectPath]?.extension_sources || [] : []
|
|
@@ -98819,7 +99040,7 @@ function discoverLocalExtensions(options = {}) {
|
|
|
98819
99040
|
const sources = Array.from(new Set([
|
|
98820
99041
|
...configuredSources,
|
|
98821
99042
|
...projectExtensionSources(projectPath || undefined)
|
|
98822
|
-
])).map((source3) => projectPath && !source3.startsWith("/") ?
|
|
99043
|
+
])).map((source3) => projectPath && !source3.startsWith("/") ? resolve15(projectPath, source3) : resolve15(source3));
|
|
98823
99044
|
const warnings = [];
|
|
98824
99045
|
const discovered = [];
|
|
98825
99046
|
for (const source3 of sources) {
|
|
@@ -103214,9 +103435,9 @@ __export(exports_extract, {
|
|
|
103214
103435
|
buildCodebaseIndex: () => buildCodebaseIndex,
|
|
103215
103436
|
EXTRACT_TAGS: () => EXTRACT_TAGS
|
|
103216
103437
|
});
|
|
103217
|
-
import { existsSync as
|
|
103438
|
+
import { existsSync as existsSync15, readFileSync as readFileSync12, statSync as statSync8 } from "fs";
|
|
103218
103439
|
import { createHash as createHash17 } from "crypto";
|
|
103219
|
-
import { relative as relative5, resolve as
|
|
103440
|
+
import { relative as relative5, resolve as resolve16, join as join15 } from "path";
|
|
103220
103441
|
function stableHash(value) {
|
|
103221
103442
|
return createHash17("sha256").update(value).digest("hex");
|
|
103222
103443
|
}
|
|
@@ -103224,9 +103445,9 @@ function normalizePathForMatch(value) {
|
|
|
103224
103445
|
return value.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
103225
103446
|
}
|
|
103226
103447
|
function readGitignorePatterns(basePath) {
|
|
103227
|
-
const root = statSync8(basePath).isFile() ?
|
|
103228
|
-
const gitignorePath =
|
|
103229
|
-
if (!
|
|
103448
|
+
const root = statSync8(basePath).isFile() ? resolve16(basePath, "..") : basePath;
|
|
103449
|
+
const gitignorePath = join15(root, ".gitignore");
|
|
103450
|
+
if (!existsSync15(gitignorePath))
|
|
103230
103451
|
return [];
|
|
103231
103452
|
try {
|
|
103232
103453
|
return readFileSync12(gitignorePath, "utf-8").split(`
|
|
@@ -103360,7 +103581,7 @@ function collectFiles(basePath, extensions, excludes, respectGitignore) {
|
|
|
103360
103581
|
return files.sort();
|
|
103361
103582
|
}
|
|
103362
103583
|
function buildCodebaseIndex(options) {
|
|
103363
|
-
const basePath =
|
|
103584
|
+
const basePath = resolve16(options.path);
|
|
103364
103585
|
const tags = options.patterns || [...EXTRACT_TAGS];
|
|
103365
103586
|
const extensions = options.extensions ? new Set(options.extensions.map((e) => e.startsWith(".") ? e : `.${e}`)) : DEFAULT_EXTENSIONS;
|
|
103366
103587
|
const excludes = options.exclude || [];
|
|
@@ -103368,10 +103589,10 @@ function buildCodebaseIndex(options) {
|
|
|
103368
103589
|
const files = collectFiles(basePath, extensions, excludes, respectGitignore);
|
|
103369
103590
|
const indexed = [];
|
|
103370
103591
|
for (const file of files) {
|
|
103371
|
-
const fullPath = statSync8(basePath).isFile() ? basePath :
|
|
103592
|
+
const fullPath = statSync8(basePath).isFile() ? basePath : join15(basePath, file);
|
|
103372
103593
|
try {
|
|
103373
103594
|
const source3 = readFileSync12(fullPath, "utf-8");
|
|
103374
|
-
const relPath = statSync8(basePath).isFile() ? relative5(
|
|
103595
|
+
const relPath = statSync8(basePath).isFile() ? relative5(resolve16(basePath, ".."), fullPath) : file;
|
|
103375
103596
|
indexed.push({
|
|
103376
103597
|
file: relPath,
|
|
103377
103598
|
checksum: stableHash(source3).slice(0, 24),
|
|
@@ -103391,7 +103612,7 @@ function buildCodebaseIndex(options) {
|
|
|
103391
103612
|
};
|
|
103392
103613
|
}
|
|
103393
103614
|
function extractTodos(options, db) {
|
|
103394
|
-
const basePath =
|
|
103615
|
+
const basePath = resolve16(options.path);
|
|
103395
103616
|
const tags = options.patterns || [...EXTRACT_TAGS];
|
|
103396
103617
|
const extensions = options.extensions ? new Set(options.extensions.map((e) => e.startsWith(".") ? e : `.${e}`)) : DEFAULT_EXTENSIONS;
|
|
103397
103618
|
const excludes = options.exclude || [];
|
|
@@ -103399,10 +103620,10 @@ function extractTodos(options, db) {
|
|
|
103399
103620
|
const files = collectFiles(basePath, extensions, excludes, respectGitignore);
|
|
103400
103621
|
const allComments = [];
|
|
103401
103622
|
for (const file of files) {
|
|
103402
|
-
const fullPath = statSync8(basePath).isFile() ? basePath :
|
|
103623
|
+
const fullPath = statSync8(basePath).isFile() ? basePath : join15(basePath, file);
|
|
103403
103624
|
try {
|
|
103404
103625
|
const source3 = readFileSync12(fullPath, "utf-8");
|
|
103405
|
-
const relPath = statSync8(basePath).isFile() ? relative5(
|
|
103626
|
+
const relPath = statSync8(basePath).isFile() ? relative5(resolve16(basePath, ".."), fullPath) : file;
|
|
103406
103627
|
const comments = extractFromSource(source3, relPath, tags);
|
|
103407
103628
|
allComments.push(...comments);
|
|
103408
103629
|
} catch {}
|
|
@@ -103496,7 +103717,7 @@ async function watchSourceTodos(options, onRun) {
|
|
|
103496
103717
|
const interval = Math.max(100, options.interval_ms || 2000);
|
|
103497
103718
|
const once = options.once !== false && (!options.max_runs || options.max_runs <= 1);
|
|
103498
103719
|
const maxRuns = options.max_runs ?? (once ? 1 : Number.POSITIVE_INFINITY);
|
|
103499
|
-
const root =
|
|
103720
|
+
const root = resolve16(options.path);
|
|
103500
103721
|
const runs = [];
|
|
103501
103722
|
let previous = new Map;
|
|
103502
103723
|
for (let runNumber = 1;runNumber <= maxRuns; runNumber++) {
|
|
@@ -104055,7 +104276,7 @@ Last seen: ${agent.last_seen_at}`
|
|
|
104055
104276
|
`Suggested names: ${suggestions.slice(0, 8).join(", ")}`,
|
|
104056
104277
|
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.",
|
|
104057
104278
|
`
|
|
104058
|
-
To restrict names, configure agent_pool or project_pools in
|
|
104279
|
+
To restrict names, configure agent_pool or project_pools in the todos data home config file (default <data home>/config.json)`
|
|
104059
104280
|
];
|
|
104060
104281
|
return { content: [{ type: "text", text: lines2.join(`
|
|
104061
104282
|
`) }] };
|
|
@@ -104358,7 +104579,7 @@ __export(exports_builtin_templates, {
|
|
|
104358
104579
|
BUILTIN_TEMPLATES: () => BUILTIN_TEMPLATES
|
|
104359
104580
|
});
|
|
104360
104581
|
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
104361
|
-
import { join as
|
|
104582
|
+
import { join as join16 } from "path";
|
|
104362
104583
|
function templateMetadata(template) {
|
|
104363
104584
|
return {
|
|
104364
104585
|
source: BUILTIN_TEMPLATE_LIBRARY_SOURCE,
|
|
@@ -104417,7 +104638,7 @@ function writeBuiltinTemplateFiles(directory) {
|
|
|
104417
104638
|
mkdirSync7(directory, { recursive: true });
|
|
104418
104639
|
const files = [];
|
|
104419
104640
|
for (const entry2 of exportBuiltinTemplateFiles()) {
|
|
104420
|
-
const path =
|
|
104641
|
+
const path = join16(directory, entry2.filename);
|
|
104421
104642
|
writeFileSync4(path, `${JSON.stringify(entry2.template, null, 2)}
|
|
104422
104643
|
`, "utf-8");
|
|
104423
104644
|
files.push(path);
|
|
@@ -104943,16 +105164,16 @@ __export(exports_environment_snapshots, {
|
|
|
104943
105164
|
captureEnvironmentSnapshot: () => captureEnvironmentSnapshot
|
|
104944
105165
|
});
|
|
104945
105166
|
import { createHash as createHash18 } from "crypto";
|
|
104946
|
-
import { existsSync as
|
|
105167
|
+
import { existsSync as existsSync16, readFileSync as readFileSync13, statSync as statSync9 } from "fs";
|
|
104947
105168
|
import { hostname as hostname3, platform, arch } from "os";
|
|
104948
|
-
import { dirname as dirname8, join as
|
|
105169
|
+
import { dirname as dirname8, join as join17, resolve as resolve17 } from "path";
|
|
104949
105170
|
import { tmpdir as tmpdir3 } from "os";
|
|
104950
105171
|
function sha2567(value) {
|
|
104951
105172
|
return createHash18("sha256").update(value).digest("hex");
|
|
104952
105173
|
}
|
|
104953
105174
|
function fileRecord(root, relativePath) {
|
|
104954
|
-
const path =
|
|
104955
|
-
if (!
|
|
105175
|
+
const path = join17(root, relativePath);
|
|
105176
|
+
if (!existsSync16(path))
|
|
104956
105177
|
return null;
|
|
104957
105178
|
const stat = statSync9(path);
|
|
104958
105179
|
if (!stat.isFile())
|
|
@@ -104964,7 +105185,7 @@ function manifestRecord(root, relativePath) {
|
|
|
104964
105185
|
const base = fileRecord(root, relativePath);
|
|
104965
105186
|
if (!base)
|
|
104966
105187
|
return null;
|
|
104967
|
-
const parsed = readJsonFile(
|
|
105188
|
+
const parsed = readJsonFile(join17(root, relativePath));
|
|
104968
105189
|
if (!parsed)
|
|
104969
105190
|
return { ...base, redacted: {} };
|
|
104970
105191
|
const redacted = redactValue({
|
|
@@ -105059,15 +105280,15 @@ function commandEnv(env, includeValues) {
|
|
|
105059
105280
|
function defaultSnapshotDir() {
|
|
105060
105281
|
const dbPath = getDatabasePath();
|
|
105061
105282
|
if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
|
|
105062
|
-
return
|
|
105063
|
-
return
|
|
105283
|
+
return join17(tmpdir3(), "hasna-todos", "environment-snapshots");
|
|
105284
|
+
return join17(dirname8(resolve17(dbPath)), "environment-snapshots");
|
|
105064
105285
|
}
|
|
105065
105286
|
function snapshotWithId(snapshot) {
|
|
105066
105287
|
const digest4 = sha2567(JSON.stringify(snapshot)).slice(0, 24);
|
|
105067
105288
|
return { id: `env_${digest4}`, ...snapshot };
|
|
105068
105289
|
}
|
|
105069
105290
|
function captureEnvironmentSnapshot(input = {}) {
|
|
105070
|
-
const root =
|
|
105291
|
+
const root = resolve17(input.root || process.cwd());
|
|
105071
105292
|
const env = input.env || process.env;
|
|
105072
105293
|
const warnings = [];
|
|
105073
105294
|
const manifests = MANIFEST_FILES.map((file) => manifestRecord(root, file)).filter((file) => Boolean(file));
|
|
@@ -105107,13 +105328,13 @@ function captureEnvironmentSnapshot(input = {}) {
|
|
|
105107
105328
|
});
|
|
105108
105329
|
}
|
|
105109
105330
|
function writeEnvironmentSnapshot(snapshot, outputPath) {
|
|
105110
|
-
const path = outputPath ?
|
|
105331
|
+
const path = outputPath ? resolve17(outputPath) : join17(defaultSnapshotDir(), `${snapshot.id}.json`);
|
|
105111
105332
|
ensureDir(dirname8(path));
|
|
105112
105333
|
writeJsonFile(path, snapshot);
|
|
105113
105334
|
return path;
|
|
105114
105335
|
}
|
|
105115
105336
|
function readEnvironmentSnapshot(path) {
|
|
105116
|
-
const snapshot = readJsonFile(
|
|
105337
|
+
const snapshot = readJsonFile(resolve17(path));
|
|
105117
105338
|
if (!snapshot || snapshot.schema_version !== 1 || typeof snapshot.id !== "string") {
|
|
105118
105339
|
throw new Error(`Invalid environment snapshot: ${path}`);
|
|
105119
105340
|
}
|
|
@@ -105939,8 +106160,8 @@ class SqlitePrGroupLedgerPersistence {
|
|
|
105939
106160
|
async transaction(fn) {
|
|
105940
106161
|
const previous = sqliteTransactionTails2.get(this.db) ?? Promise.resolve();
|
|
105941
106162
|
let release;
|
|
105942
|
-
const current = new Promise((
|
|
105943
|
-
release =
|
|
106163
|
+
const current = new Promise((resolve18) => {
|
|
106164
|
+
release = resolve18;
|
|
105944
106165
|
});
|
|
105945
106166
|
sqliteTransactionTails2.set(this.db, current);
|
|
105946
106167
|
await previous;
|
|
@@ -106038,27 +106259,27 @@ __export(exports_serve, {
|
|
|
106038
106259
|
SECURITY_HEADERS: () => SECURITY_HEADERS,
|
|
106039
106260
|
MIME_TYPES: () => MIME_TYPES
|
|
106040
106261
|
});
|
|
106041
|
-
import { existsSync as
|
|
106042
|
-
import { join as
|
|
106262
|
+
import { existsSync as existsSync17 } from "fs";
|
|
106263
|
+
import { join as join18, dirname as dirname9, extname } from "path";
|
|
106043
106264
|
import { fileURLToPath } from "url";
|
|
106044
106265
|
function resolveDashboardDir() {
|
|
106045
106266
|
const candidates = [];
|
|
106046
106267
|
try {
|
|
106047
106268
|
const scriptDir = dirname9(fileURLToPath(import.meta.url));
|
|
106048
|
-
candidates.push(
|
|
106049
|
-
candidates.push(
|
|
106269
|
+
candidates.push(join18(scriptDir, "..", "dashboard", "dist"));
|
|
106270
|
+
candidates.push(join18(scriptDir, "..", "..", "dashboard", "dist"));
|
|
106050
106271
|
} catch {}
|
|
106051
106272
|
if (process.argv[1]) {
|
|
106052
106273
|
const mainDir = dirname9(process.argv[1]);
|
|
106053
|
-
candidates.push(
|
|
106054
|
-
candidates.push(
|
|
106274
|
+
candidates.push(join18(mainDir, "..", "dashboard", "dist"));
|
|
106275
|
+
candidates.push(join18(mainDir, "..", "..", "dashboard", "dist"));
|
|
106055
106276
|
}
|
|
106056
|
-
candidates.push(
|
|
106277
|
+
candidates.push(join18(process.cwd(), "dashboard", "dist"));
|
|
106057
106278
|
for (const candidate of candidates) {
|
|
106058
|
-
if (
|
|
106279
|
+
if (existsSync17(candidate))
|
|
106059
106280
|
return candidate;
|
|
106060
106281
|
}
|
|
106061
|
-
return
|
|
106282
|
+
return join18(process.cwd(), "dashboard", "dist");
|
|
106062
106283
|
}
|
|
106063
106284
|
function getProvidedApiKey(req) {
|
|
106064
106285
|
const headerKey = req.headers.get("x-api-key");
|
|
@@ -106130,7 +106351,7 @@ function json4(data, status3 = 200, headers) {
|
|
|
106130
106351
|
});
|
|
106131
106352
|
}
|
|
106132
106353
|
function serveStaticFile(filePath) {
|
|
106133
|
-
if (!
|
|
106354
|
+
if (!existsSync17(filePath))
|
|
106134
106355
|
return null;
|
|
106135
106356
|
const ext = extname(filePath);
|
|
106136
106357
|
const contentType2 = MIME_TYPES[ext] || "application/octet-stream";
|
|
@@ -106231,7 +106452,7 @@ data: ${data}
|
|
|
106231
106452
|
filteredSseClients.delete(client);
|
|
106232
106453
|
}
|
|
106233
106454
|
const dashboardDir = resolveDashboardDir();
|
|
106234
|
-
const dashboardExists =
|
|
106455
|
+
const dashboardExists = existsSync17(dashboardDir);
|
|
106235
106456
|
if (!dashboardExists) {
|
|
106236
106457
|
console.error(`
|
|
106237
106458
|
Dashboard not found at: ${dashboardDir}`);
|