@hasna/todos 0.15.50 → 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/cli/index.js
CHANGED
|
@@ -2123,7 +2123,7 @@ var package_default;
|
|
|
2123
2123
|
var init_package = __esm(() => {
|
|
2124
2124
|
package_default = {
|
|
2125
2125
|
name: "@hasna/todos",
|
|
2126
|
-
version: "0.15.
|
|
2126
|
+
version: "0.15.51",
|
|
2127
2127
|
description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
|
|
2128
2128
|
type: "module",
|
|
2129
2129
|
main: "dist/index.js",
|
|
@@ -2182,6 +2182,7 @@ var init_package = __esm(() => {
|
|
|
2182
2182
|
files: [
|
|
2183
2183
|
"dist",
|
|
2184
2184
|
"dashboard/dist",
|
|
2185
|
+
"postinstall.js",
|
|
2185
2186
|
"LICENSE",
|
|
2186
2187
|
"README.md"
|
|
2187
2188
|
],
|
|
@@ -2208,7 +2209,7 @@ var init_package = __esm(() => {
|
|
|
2208
2209
|
"test:attested-container-compatibility-vector": "bun test scripts/attested-container-compatibility-vector.test.ts",
|
|
2209
2210
|
"issue:release-review": "bun run scripts/issue-npm-release-agent-review.ts",
|
|
2210
2211
|
prepublishOnly: "bun run scripts/verify-public-release.ts --mode=publish",
|
|
2211
|
-
postinstall: "
|
|
2212
|
+
postinstall: "node postinstall.js"
|
|
2212
2213
|
},
|
|
2213
2214
|
keywords: [
|
|
2214
2215
|
"todos",
|
|
@@ -2242,13 +2243,15 @@ var init_package = __esm(() => {
|
|
|
2242
2243
|
author: "Andrei Hasna <andrei@hasna.com>",
|
|
2243
2244
|
license: "Apache-2.0",
|
|
2244
2245
|
dependencies: {
|
|
2245
|
-
"@hasna/contracts": "0.14.
|
|
2246
|
+
"@hasna/contracts": "0.14.2",
|
|
2246
2247
|
"@hasna/events": "^0.1.11",
|
|
2248
|
+
"@hasna/paths": "0.1.0",
|
|
2247
2249
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
2248
2250
|
chalk: "^5.4.1",
|
|
2249
2251
|
commander: "^13.1.0",
|
|
2250
2252
|
ink: "^5.2.0",
|
|
2251
2253
|
react: "^18.3.1",
|
|
2254
|
+
"signal-exit": "3.0.7",
|
|
2252
2255
|
zod: "3.25.76"
|
|
2253
2256
|
},
|
|
2254
2257
|
overrides: {
|
|
@@ -2491,6 +2494,101 @@ var init_types = __esm(() => {
|
|
|
2491
2494
|
};
|
|
2492
2495
|
});
|
|
2493
2496
|
|
|
2497
|
+
// node_modules/.bun/@hasna+paths@0.1.0/node_modules/@hasna/paths/dist/index.js
|
|
2498
|
+
import { homedir } from "os";
|
|
2499
|
+
import { join } from "path";
|
|
2500
|
+
function assertApp(app) {
|
|
2501
|
+
if (typeof app !== "string" || app.length === 0) {
|
|
2502
|
+
throw new TypeError("paths: app must be a non-empty string");
|
|
2503
|
+
}
|
|
2504
|
+
if (!APP_SLUG_RE.test(app)) {
|
|
2505
|
+
throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
|
|
2506
|
+
}
|
|
2507
|
+
}
|
|
2508
|
+
function envOf(options) {
|
|
2509
|
+
return options.env ?? process.env;
|
|
2510
|
+
}
|
|
2511
|
+
function envValue(options, kind) {
|
|
2512
|
+
const value = envOf(options)[KIND_ENV[kind]];
|
|
2513
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
2514
|
+
}
|
|
2515
|
+
function isMacOS(platform) {
|
|
2516
|
+
return platform === "darwin";
|
|
2517
|
+
}
|
|
2518
|
+
function baseDir(kind, options) {
|
|
2519
|
+
const override = envValue(options, kind);
|
|
2520
|
+
if (override)
|
|
2521
|
+
return override;
|
|
2522
|
+
const home = options.home ?? homedir();
|
|
2523
|
+
const platform = options.platform ?? process.platform;
|
|
2524
|
+
if (isMacOS(platform)) {
|
|
2525
|
+
switch (kind) {
|
|
2526
|
+
case "config":
|
|
2527
|
+
case "data":
|
|
2528
|
+
return join(home, "Library", "Application Support", "Hasna");
|
|
2529
|
+
case "cache":
|
|
2530
|
+
return join(home, "Library", "Caches", "Hasna");
|
|
2531
|
+
case "state":
|
|
2532
|
+
return join(home, "Library", "Logs", "Hasna");
|
|
2533
|
+
}
|
|
2534
|
+
}
|
|
2535
|
+
switch (kind) {
|
|
2536
|
+
case "config":
|
|
2537
|
+
return join(home, ".config", "hasna");
|
|
2538
|
+
case "data":
|
|
2539
|
+
return join(home, ".local", "share", "hasna");
|
|
2540
|
+
case "state":
|
|
2541
|
+
return join(home, ".local", "state", "hasna");
|
|
2542
|
+
case "cache":
|
|
2543
|
+
return join(home, ".cache", "hasna");
|
|
2544
|
+
}
|
|
2545
|
+
}
|
|
2546
|
+
function resolvePath(kind, options) {
|
|
2547
|
+
assertApp(options.app);
|
|
2548
|
+
const appSegment = options.internal === true ? join("internal", options.app) : options.app;
|
|
2549
|
+
return join(baseDir(kind, options), appSegment);
|
|
2550
|
+
}
|
|
2551
|
+
function dataDir(options) {
|
|
2552
|
+
return resolvePath("data", options);
|
|
2553
|
+
}
|
|
2554
|
+
var KIND_ENV, APP_SLUG_RE;
|
|
2555
|
+
var init_dist = __esm(() => {
|
|
2556
|
+
KIND_ENV = {
|
|
2557
|
+
config: "HASNA_CONFIG_HOME",
|
|
2558
|
+
data: "HASNA_DATA_HOME",
|
|
2559
|
+
state: "HASNA_STATE_HOME",
|
|
2560
|
+
cache: "HASNA_CACHE_HOME"
|
|
2561
|
+
};
|
|
2562
|
+
APP_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
2563
|
+
});
|
|
2564
|
+
|
|
2565
|
+
// src/lib/paths.ts
|
|
2566
|
+
import { existsSync } from "fs";
|
|
2567
|
+
import { homedir as homedir2 } from "os";
|
|
2568
|
+
import { join as join2, resolve } from "path";
|
|
2569
|
+
function effectiveHome(env = process.env) {
|
|
2570
|
+
return env.HOME || env.USERPROFILE || homedir2();
|
|
2571
|
+
}
|
|
2572
|
+
function legacyHomeDir(env = process.env) {
|
|
2573
|
+
return join2(effectiveHome(env), ".hasna", "todos");
|
|
2574
|
+
}
|
|
2575
|
+
function resolverHome(env = process.env) {
|
|
2576
|
+
return dataDir({ app: "todos", home: effectiveHome(env), env });
|
|
2577
|
+
}
|
|
2578
|
+
function adoptResolverHome(resolved, env = process.env) {
|
|
2579
|
+
const dataOverride = env.HASNA_DATA_HOME;
|
|
2580
|
+
if (typeof dataOverride === "string" && dataOverride.trim().length > 0)
|
|
2581
|
+
return true;
|
|
2582
|
+
return existsSync(join2(resolved, "todos.db")) || existsSync(join2(resolved, "config.json"));
|
|
2583
|
+
}
|
|
2584
|
+
function getTodosDir(env = process.env) {
|
|
2585
|
+
const resolved = resolverHome(env);
|
|
2586
|
+
return resolve(adoptResolverHome(resolved, env) ? resolved : legacyHomeDir(env));
|
|
2587
|
+
}
|
|
2588
|
+
var init_paths = __esm(() => {
|
|
2589
|
+
init_dist();
|
|
2590
|
+
});
|
|
2591
|
+
|
|
2494
2592
|
// src/lib/sync-utils.ts
|
|
2495
2593
|
var exports_sync_utils = {};
|
|
2496
2594
|
__export(exports_sync_utils, {
|
|
@@ -2510,22 +2608,22 @@ __export(exports_sync_utils, {
|
|
|
2510
2608
|
TODO_SYNC_FINGERPRINT_KEY: () => TODO_SYNC_FINGERPRINT_KEY,
|
|
2511
2609
|
HOME: () => HOME
|
|
2512
2610
|
});
|
|
2513
|
-
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
|
|
2611
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
|
|
2514
2612
|
import { createHash } from "crypto";
|
|
2515
|
-
import { homedir } from "os";
|
|
2516
|
-
import { join } from "path";
|
|
2613
|
+
import { homedir as homedir3 } from "os";
|
|
2614
|
+
import { join as join3 } from "path";
|
|
2517
2615
|
function getHomeDir() {
|
|
2518
|
-
return process.env["HOME"] || process.env["USERPROFILE"] ||
|
|
2616
|
+
return process.env["HOME"] || process.env["USERPROFILE"] || homedir3();
|
|
2519
2617
|
}
|
|
2520
2618
|
function getTodosGlobalDir() {
|
|
2521
|
-
return
|
|
2619
|
+
return getTodosDir();
|
|
2522
2620
|
}
|
|
2523
2621
|
function ensureDir(dir) {
|
|
2524
|
-
if (!
|
|
2622
|
+
if (!existsSync2(dir))
|
|
2525
2623
|
mkdirSync(dir, { recursive: true });
|
|
2526
2624
|
}
|
|
2527
2625
|
function listJsonFiles(dir) {
|
|
2528
|
-
if (!
|
|
2626
|
+
if (!existsSync2(dir))
|
|
2529
2627
|
return [];
|
|
2530
2628
|
return readdirSync(dir).filter((f) => f.endsWith(".json"));
|
|
2531
2629
|
}
|
|
@@ -2541,14 +2639,14 @@ function writeJsonFile(path, data) {
|
|
|
2541
2639
|
`);
|
|
2542
2640
|
}
|
|
2543
2641
|
function readHighWaterMark(dir) {
|
|
2544
|
-
const path =
|
|
2545
|
-
if (!
|
|
2642
|
+
const path = join3(dir, ".highwatermark");
|
|
2643
|
+
if (!existsSync2(path))
|
|
2546
2644
|
return 1;
|
|
2547
2645
|
const val = parseInt(readFileSync(path, "utf-8").trim(), 10);
|
|
2548
2646
|
return isNaN(val) ? 1 : val;
|
|
2549
2647
|
}
|
|
2550
2648
|
function writeHighWaterMark(dir, value) {
|
|
2551
|
-
writeFileSync(
|
|
2649
|
+
writeFileSync(join3(dir, ".highwatermark"), String(value));
|
|
2552
2650
|
}
|
|
2553
2651
|
function getFileMtimeMs(path) {
|
|
2554
2652
|
try {
|
|
@@ -2603,6 +2701,7 @@ function hasSyncFingerprintChanged(record) {
|
|
|
2603
2701
|
}
|
|
2604
2702
|
var TODO_SYNC_FINGERPRINT_KEY = "todos_sync_fingerprint", HOME;
|
|
2605
2703
|
var init_sync_utils = __esm(() => {
|
|
2704
|
+
init_paths();
|
|
2606
2705
|
HOME = getHomeDir();
|
|
2607
2706
|
});
|
|
2608
2707
|
|
|
@@ -2624,10 +2723,10 @@ __export(exports_config, {
|
|
|
2624
2723
|
getAgentTaskListId: () => getAgentTaskListId,
|
|
2625
2724
|
getAgentPoolForProject: () => getAgentPoolForProject
|
|
2626
2725
|
});
|
|
2627
|
-
import { existsSync as
|
|
2628
|
-
import { dirname, join as
|
|
2726
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
2727
|
+
import { dirname, join as join4 } from "path";
|
|
2629
2728
|
function getConfigPath() {
|
|
2630
|
-
return
|
|
2729
|
+
return join4(getTodosGlobalDir(), "config.json");
|
|
2631
2730
|
}
|
|
2632
2731
|
function resetConfig() {
|
|
2633
2732
|
cached = null;
|
|
@@ -2638,7 +2737,7 @@ function normalizeAgent(agent) {
|
|
|
2638
2737
|
function loadConfig() {
|
|
2639
2738
|
if (cached)
|
|
2640
2739
|
return cached;
|
|
2641
|
-
if (!
|
|
2740
|
+
if (!existsSync3(getConfigPath())) {
|
|
2642
2741
|
cached = {};
|
|
2643
2742
|
return cached;
|
|
2644
2743
|
}
|
|
@@ -2661,7 +2760,7 @@ function updateConfig(patch) {
|
|
|
2661
2760
|
}
|
|
2662
2761
|
function getTodosAiConfig() {
|
|
2663
2762
|
const configPath = getConfigPath();
|
|
2664
|
-
if (!
|
|
2763
|
+
if (!existsSync3(configPath))
|
|
2665
2764
|
return {};
|
|
2666
2765
|
const parsed = JSON.parse(readFileSync2(configPath, "utf8"));
|
|
2667
2766
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
@@ -5721,7 +5820,7 @@ var init_page_validation = __esm(() => {
|
|
|
5721
5820
|
// src/cli/cloud-router.ts
|
|
5722
5821
|
import { resolveStorageClient } from "@hasna/contracts/client/storage";
|
|
5723
5822
|
import { randomUUID } from "crypto";
|
|
5724
|
-
import { resolve as
|
|
5823
|
+
import { resolve as resolvePath2 } from "path";
|
|
5725
5824
|
function emitTodosLocalFallbackNotice(env) {
|
|
5726
5825
|
if (todosLocalFallbackNoticeEmitted)
|
|
5727
5826
|
return;
|
|
@@ -6707,11 +6806,11 @@ function resolveCloudProjectRef(projects, ref) {
|
|
|
6707
6806
|
const input = ref.trim();
|
|
6708
6807
|
const normalizedRef = input.toLowerCase();
|
|
6709
6808
|
const pathLike = input.startsWith(".") || input.includes("/") || input.includes("\\");
|
|
6710
|
-
const normalizedPath = pathLike ?
|
|
6809
|
+
const normalizedPath = pathLike ? resolvePath2(input) : undefined;
|
|
6711
6810
|
const slug = cloudProjectSlug(pathLike ? cloudProjectPathBasename(input) : input);
|
|
6712
6811
|
const matchGroups = [
|
|
6713
6812
|
uniqueProjectMatches(projects, (project) => project.id.toLowerCase() === normalizedRef),
|
|
6714
|
-
uniqueProjectMatches(projects, (project) => project.path === input || normalizedPath !== undefined &&
|
|
6813
|
+
uniqueProjectMatches(projects, (project) => project.path === input || normalizedPath !== undefined && resolvePath2(project.path) === normalizedPath),
|
|
6715
6814
|
uniqueProjectMatches(projects, (project) => project.name.toLowerCase() === normalizedRef),
|
|
6716
6815
|
uniqueProjectMatches(projects, (project) => project.task_list_id === input || cloudProjectSlug(project.name) === slug || cloudProjectSlug(cloudProjectPathBasename(project.path)) === slug),
|
|
6717
6816
|
uniqueProjectMatches(projects, (project) => project.id.toLowerCase().startsWith(normalizedRef))
|
|
@@ -11718,9 +11817,9 @@ var init_schema = __esm(() => {
|
|
|
11718
11817
|
});
|
|
11719
11818
|
|
|
11720
11819
|
// src/db/machines.ts
|
|
11721
|
-
import { existsSync as
|
|
11820
|
+
import { existsSync as existsSync4 } from "fs";
|
|
11722
11821
|
import { hostname as osHostname, platform as osPlatform, arch as osArch } from "os";
|
|
11723
|
-
import { resolve } from "path";
|
|
11822
|
+
import { resolve as resolve2 } from "path";
|
|
11724
11823
|
import { spawnSync } from "child_process";
|
|
11725
11824
|
function parseMetadata(value) {
|
|
11726
11825
|
if (!value)
|
|
@@ -11751,7 +11850,7 @@ function discoverGitRoot(workspacePath) {
|
|
|
11751
11850
|
}
|
|
11752
11851
|
function topologyMetadata(input, existing = {}) {
|
|
11753
11852
|
const next = { ...existing };
|
|
11754
|
-
const workspacePath = input.workspace_path ?
|
|
11853
|
+
const workspacePath = input.workspace_path ? resolve2(input.workspace_path) : undefined;
|
|
11755
11854
|
const entries = {
|
|
11756
11855
|
tailscale_name: input.tailscale_name,
|
|
11757
11856
|
tailscale_ip: input.tailscale_ip,
|
|
@@ -11925,7 +12024,7 @@ function getMachineTopologyDiagnostics(opts = {}, db, at = new Date) {
|
|
|
11925
12024
|
message: `${project.name} has ${distinctPaths.length} different machine-local paths`
|
|
11926
12025
|
});
|
|
11927
12026
|
}
|
|
11928
|
-
if (localRow && !
|
|
12027
|
+
if (localRow && !existsSync4(localRow.path)) {
|
|
11929
12028
|
pathIssues.push({
|
|
11930
12029
|
type: "path_missing",
|
|
11931
12030
|
project_id: project.id,
|
|
@@ -11936,7 +12035,7 @@ function getMachineTopologyDiagnostics(opts = {}, db, at = new Date) {
|
|
|
11936
12035
|
message: `Local path does not exist on this machine: ${localRow.path}`
|
|
11937
12036
|
});
|
|
11938
12037
|
}
|
|
11939
|
-
if (!localRow && project.path && machineById.has(localMachine.id) && !
|
|
12038
|
+
if (!localRow && project.path && machineById.has(localMachine.id) && !existsSync4(project.path)) {
|
|
11940
12039
|
pathIssues.push({
|
|
11941
12040
|
type: "path_missing",
|
|
11942
12041
|
project_id: project.id,
|
|
@@ -12525,18 +12624,18 @@ __export(exports_database, {
|
|
|
12525
12624
|
LOCK_EXPIRY_MINUTES: () => LOCK_EXPIRY_MINUTES
|
|
12526
12625
|
});
|
|
12527
12626
|
import { Database } from "bun:sqlite";
|
|
12528
|
-
import { existsSync as
|
|
12529
|
-
import { dirname as dirname2, join as
|
|
12627
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
|
|
12628
|
+
import { dirname as dirname2, join as join5, resolve as resolve3 } from "path";
|
|
12530
12629
|
function isInMemoryDb(path) {
|
|
12531
12630
|
return path === ":memory:" || path.startsWith("file::memory:");
|
|
12532
12631
|
}
|
|
12533
12632
|
function findNearestProjectDb(startDir) {
|
|
12534
12633
|
const gitRoot = findGitRoot(startDir);
|
|
12535
|
-
const stopAt = gitRoot ?
|
|
12536
|
-
let dir =
|
|
12634
|
+
const stopAt = gitRoot ? resolve3(gitRoot) : resolve3(startDir);
|
|
12635
|
+
let dir = resolve3(startDir);
|
|
12537
12636
|
while (true) {
|
|
12538
|
-
const candidate =
|
|
12539
|
-
if (
|
|
12637
|
+
const candidate = join5(dir, ".hasna", "todos", "todos.db");
|
|
12638
|
+
if (existsSync5(candidate))
|
|
12540
12639
|
return candidate;
|
|
12541
12640
|
if (dir === stopAt)
|
|
12542
12641
|
break;
|
|
@@ -12548,9 +12647,9 @@ function findNearestProjectDb(startDir) {
|
|
|
12548
12647
|
return null;
|
|
12549
12648
|
}
|
|
12550
12649
|
function findGitRoot(startDir) {
|
|
12551
|
-
let dir =
|
|
12650
|
+
let dir = resolve3(startDir);
|
|
12552
12651
|
while (true) {
|
|
12553
|
-
if (
|
|
12652
|
+
if (existsSync5(join5(dir, ".git")))
|
|
12554
12653
|
return dir;
|
|
12555
12654
|
const parent = dirname2(dir);
|
|
12556
12655
|
if (parent === dir)
|
|
@@ -12560,7 +12659,7 @@ function findGitRoot(startDir) {
|
|
|
12560
12659
|
return null;
|
|
12561
12660
|
}
|
|
12562
12661
|
function getGlobalDbPath() {
|
|
12563
|
-
return
|
|
12662
|
+
return join5(getTodosGlobalDir(), "todos.db");
|
|
12564
12663
|
}
|
|
12565
12664
|
function hasExplicitProjectArg(args = process.argv.slice(2)) {
|
|
12566
12665
|
return args.some((arg) => arg === "--project" || arg.startsWith("--project="));
|
|
@@ -12598,7 +12697,7 @@ function getDbPath() {
|
|
|
12598
12697
|
if (process.env["TODOS_DB_SCOPE"] === "project") {
|
|
12599
12698
|
const gitRoot = findGitRoot(cwd);
|
|
12600
12699
|
if (gitRoot && canCreateScopedProjectDb()) {
|
|
12601
|
-
return
|
|
12700
|
+
return join5(gitRoot, ".hasna", "todos", "todos.db");
|
|
12602
12701
|
}
|
|
12603
12702
|
}
|
|
12604
12703
|
return getGlobalDbPath();
|
|
@@ -12609,8 +12708,8 @@ function getDatabasePath() {
|
|
|
12609
12708
|
function ensureDir2(filePath) {
|
|
12610
12709
|
if (isInMemoryDb(filePath))
|
|
12611
12710
|
return;
|
|
12612
|
-
const dir = dirname2(
|
|
12613
|
-
if (!
|
|
12711
|
+
const dir = dirname2(resolve3(filePath));
|
|
12712
|
+
if (!existsSync5(dir)) {
|
|
12614
12713
|
mkdirSync2(dir, { recursive: true });
|
|
12615
12714
|
}
|
|
12616
12715
|
}
|
|
@@ -13453,9 +13552,9 @@ __export(exports_helpers, {
|
|
|
13453
13552
|
});
|
|
13454
13553
|
import chalk from "chalk";
|
|
13455
13554
|
import { execSync } from "child_process";
|
|
13456
|
-
import { existsSync as
|
|
13555
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2, writeSync } from "fs";
|
|
13457
13556
|
import { tmpdir } from "os";
|
|
13458
|
-
import { dirname as dirname3, join as
|
|
13557
|
+
import { dirname as dirname3, join as join6, resolve as resolve4, sep } from "path";
|
|
13459
13558
|
function jsonModeRequested(argv = process.argv) {
|
|
13460
13559
|
return argv.some((arg) => arg === "--json" || /^-[a-z]+$/i.test(arg) && arg.includes("j"));
|
|
13461
13560
|
}
|
|
@@ -13527,11 +13626,13 @@ async function resolveTaskIdForCommand(input, cloud = getTodosCloudClient()) {
|
|
|
13527
13626
|
}
|
|
13528
13627
|
function cloudTaskIdCachePath() {
|
|
13529
13628
|
const home = process.env["HOME"] || process.env["USERPROFILE"];
|
|
13530
|
-
|
|
13629
|
+
if (!home)
|
|
13630
|
+
return null;
|
|
13631
|
+
return join6(getTodosGlobalDir(), "cloud-task-id-cache.json");
|
|
13531
13632
|
}
|
|
13532
13633
|
function readCloudTaskIdCache() {
|
|
13533
13634
|
const path = cloudTaskIdCachePath();
|
|
13534
|
-
if (!path || !
|
|
13635
|
+
if (!path || !existsSync6(path))
|
|
13535
13636
|
return { version: 1, tasks: [] };
|
|
13536
13637
|
try {
|
|
13537
13638
|
const parsed = JSON.parse(readFileSync3(path, "utf8"));
|
|
@@ -13595,12 +13696,12 @@ function detectGitRoot() {
|
|
|
13595
13696
|
}
|
|
13596
13697
|
}
|
|
13597
13698
|
function isPathWithin(child, parent) {
|
|
13598
|
-
const normalizedChild =
|
|
13599
|
-
const normalizedParent =
|
|
13699
|
+
const normalizedChild = resolve4(child);
|
|
13700
|
+
const normalizedParent = resolve4(parent);
|
|
13600
13701
|
return normalizedChild === normalizedParent || normalizedChild.startsWith(`${normalizedParent}${sep}`);
|
|
13601
13702
|
}
|
|
13602
13703
|
function shouldSkipAutoProjectForGitRoot(gitRoot) {
|
|
13603
|
-
const normalized =
|
|
13704
|
+
const normalized = resolve4(gitRoot);
|
|
13604
13705
|
if (process.platform !== "win32" && (normalized === "/tmp" || normalized.startsWith("/tmp/"))) {
|
|
13605
13706
|
return true;
|
|
13606
13707
|
}
|
|
@@ -13608,7 +13709,7 @@ function shouldSkipAutoProjectForGitRoot(gitRoot) {
|
|
|
13608
13709
|
}
|
|
13609
13710
|
function resolveExplicitProject(input) {
|
|
13610
13711
|
const db = getDatabase();
|
|
13611
|
-
const byPath = getProjectByPath(
|
|
13712
|
+
const byPath = getProjectByPath(resolve4(input), db);
|
|
13612
13713
|
if (byPath)
|
|
13613
13714
|
return byPath;
|
|
13614
13715
|
const id = resolvePartialId(db, "projects", input);
|
|
@@ -13780,6 +13881,7 @@ var init_helpers = __esm(() => {
|
|
|
13780
13881
|
init_projects();
|
|
13781
13882
|
init_lock_display();
|
|
13782
13883
|
init_package_version();
|
|
13884
|
+
init_sync_utils();
|
|
13783
13885
|
init_types();
|
|
13784
13886
|
stdoutRetryBuffer = new SharedArrayBuffer(4);
|
|
13785
13887
|
stdoutRetrySignal = new Int32Array(stdoutRetryBuffer);
|
|
@@ -13869,14 +13971,14 @@ var init_completion_guard = __esm(() => {
|
|
|
13869
13971
|
|
|
13870
13972
|
// src/lib/event-emission-safety.ts
|
|
13871
13973
|
import { tmpdir as tmpdir2 } from "os";
|
|
13872
|
-
import { resolve as
|
|
13974
|
+
import { resolve as resolve5, sep as sep2 } from "path";
|
|
13873
13975
|
function envFlag(name) {
|
|
13874
13976
|
const value = process.env[name]?.trim().toLowerCase();
|
|
13875
13977
|
return value === "1" || value === "true" || value === "yes" || value === "on";
|
|
13876
13978
|
}
|
|
13877
13979
|
function isUnder(parent, child) {
|
|
13878
|
-
const normalizedParent =
|
|
13879
|
-
const normalizedChild =
|
|
13980
|
+
const normalizedParent = resolve5(parent);
|
|
13981
|
+
const normalizedChild = resolve5(child);
|
|
13880
13982
|
return normalizedChild === normalizedParent || normalizedChild.startsWith(`${normalizedParent}${sep2}`);
|
|
13881
13983
|
}
|
|
13882
13984
|
function databasePathFromDatabase(db) {
|
|
@@ -13927,9 +14029,9 @@ __export(exports_workspace_trust, {
|
|
|
13927
14029
|
getWorkspaceTrustStatus: () => getWorkspaceTrustStatus,
|
|
13928
14030
|
checkWorkspacePermission: () => checkWorkspacePermission
|
|
13929
14031
|
});
|
|
13930
|
-
import { relative, resolve as
|
|
14032
|
+
import { relative, resolve as resolve6 } from "path";
|
|
13931
14033
|
function normalizePath(path) {
|
|
13932
|
-
return
|
|
14034
|
+
return resolve6(path);
|
|
13933
14035
|
}
|
|
13934
14036
|
function unique2(values) {
|
|
13935
14037
|
return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));
|
|
@@ -14120,9 +14222,9 @@ __export(exports_runner_sandbox, {
|
|
|
14120
14222
|
explainRunnerSandbox: () => explainRunnerSandbox,
|
|
14121
14223
|
checkRunnerSandbox: () => checkRunnerSandbox
|
|
14122
14224
|
});
|
|
14123
|
-
import { relative as relative2, resolve as
|
|
14225
|
+
import { relative as relative2, resolve as resolve7 } from "path";
|
|
14124
14226
|
function normalizePath2(path) {
|
|
14125
|
-
return
|
|
14227
|
+
return resolve7(path);
|
|
14126
14228
|
}
|
|
14127
14229
|
function unique3(values) {
|
|
14128
14230
|
return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));
|
|
@@ -14326,7 +14428,7 @@ __export(exports_event_hooks, {
|
|
|
14326
14428
|
});
|
|
14327
14429
|
import { createHash as createHash4, randomUUID as randomUUID2 } from "crypto";
|
|
14328
14430
|
import { appendFileSync, mkdirSync as mkdirSync4 } from "fs";
|
|
14329
|
-
import { dirname as dirname4, resolve as
|
|
14431
|
+
import { dirname as dirname4, resolve as resolve8 } from "path";
|
|
14330
14432
|
import { createConnection } from "net";
|
|
14331
14433
|
function safeName(name) {
|
|
14332
14434
|
const trimmed = name.trim();
|
|
@@ -14464,7 +14566,7 @@ async function deliverHook(hook, envelope) {
|
|
|
14464
14566
|
if (hook.target === "stdout") {
|
|
14465
14567
|
output2 = line.trim();
|
|
14466
14568
|
} else if (hook.target === "file") {
|
|
14467
|
-
const filePath =
|
|
14569
|
+
const filePath = resolve8(hook.file_path);
|
|
14468
14570
|
mkdirSync4(dirname4(filePath), { recursive: true });
|
|
14469
14571
|
appendFileSync(filePath, line);
|
|
14470
14572
|
} else if (hook.target === "socket") {
|
|
@@ -14585,9 +14687,9 @@ var init_event_hooks = __esm(() => {
|
|
|
14585
14687
|
// node_modules/.bun/@hasna+events@0.1.16/node_modules/@hasna/events/dist/index.js
|
|
14586
14688
|
import { chmod, mkdir, readFile, rename, writeFile } from "fs/promises";
|
|
14587
14689
|
import { Buffer as Buffer2 } from "buffer";
|
|
14588
|
-
import { existsSync as
|
|
14589
|
-
import { homedir as
|
|
14590
|
-
import { join as
|
|
14690
|
+
import { existsSync as existsSync7 } from "fs";
|
|
14691
|
+
import { homedir as homedir4 } from "os";
|
|
14692
|
+
import { join as join7 } from "path";
|
|
14591
14693
|
import { createHmac, timingSafeEqual } from "crypto";
|
|
14592
14694
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
14593
14695
|
import { spawn } from "child_process";
|
|
@@ -14688,7 +14790,7 @@ function channelMatchesEvent(channel, event) {
|
|
|
14688
14790
|
return channel.filters.some((filter) => eventMatchesFilter(event, filter));
|
|
14689
14791
|
}
|
|
14690
14792
|
function getEventsDataDir(override) {
|
|
14691
|
-
return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] ||
|
|
14793
|
+
return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join7(homedir4(), ".hasna", "events");
|
|
14692
14794
|
}
|
|
14693
14795
|
|
|
14694
14796
|
class JsonEventsStore {
|
|
@@ -14697,12 +14799,12 @@ class JsonEventsStore {
|
|
|
14697
14799
|
channelsPath;
|
|
14698
14800
|
eventsPath;
|
|
14699
14801
|
deliveriesPath;
|
|
14700
|
-
constructor(
|
|
14701
|
-
this.dataDir =
|
|
14702
|
-
this.runtime = localJsonRuntime(
|
|
14703
|
-
this.channelsPath =
|
|
14704
|
-
this.eventsPath =
|
|
14705
|
-
this.deliveriesPath =
|
|
14802
|
+
constructor(dataDir2 = getEventsDataDir()) {
|
|
14803
|
+
this.dataDir = dataDir2;
|
|
14804
|
+
this.runtime = localJsonRuntime(dataDir2);
|
|
14805
|
+
this.channelsPath = join7(dataDir2, "channels.json");
|
|
14806
|
+
this.eventsPath = join7(dataDir2, "events.json");
|
|
14807
|
+
this.deliveriesPath = join7(dataDir2, "deliveries.json");
|
|
14706
14808
|
}
|
|
14707
14809
|
async init() {
|
|
14708
14810
|
await mkdir(this.dataDir, { recursive: true, mode: 448 });
|
|
@@ -14819,7 +14921,7 @@ class JsonEventsStore {
|
|
|
14819
14921
|
};
|
|
14820
14922
|
}
|
|
14821
14923
|
async ensureArrayFile(path) {
|
|
14822
|
-
if (!
|
|
14924
|
+
if (!existsSync7(path)) {
|
|
14823
14925
|
await writeFile(path, `[]
|
|
14824
14926
|
`, { encoding: "utf-8", mode: 384 });
|
|
14825
14927
|
}
|
|
@@ -14849,7 +14951,7 @@ class JsonEventsStore {
|
|
|
14849
14951
|
});
|
|
14850
14952
|
}
|
|
14851
14953
|
}
|
|
14852
|
-
function localJsonRuntime(
|
|
14954
|
+
function localJsonRuntime(dataDir2 = getEventsDataDir()) {
|
|
14853
14955
|
return {
|
|
14854
14956
|
mode: "local-files",
|
|
14855
14957
|
name: "json-events-store",
|
|
@@ -14862,7 +14964,7 @@ function localJsonRuntime(dataDir = getEventsDataDir()) {
|
|
|
14862
14964
|
durable: true,
|
|
14863
14965
|
idempotency: "best-effort-local",
|
|
14864
14966
|
replayCursors: true,
|
|
14865
|
-
description: `Local JSON files in ${
|
|
14967
|
+
description: `Local JSON files in ${dataDir2}; no SQLite, Postgres, S3, or AWS runtime is configured by this store.`
|
|
14866
14968
|
};
|
|
14867
14969
|
}
|
|
14868
14970
|
function encodeLocalJsonEventCursor(offset, options = {}) {
|
|
@@ -15041,7 +15143,7 @@ async function dispatchCommand(event, channel) {
|
|
|
15041
15143
|
HASNA_EVENT_SCHEMA_VERSION: event.schemaVersion,
|
|
15042
15144
|
HASNA_EVENT_JSON: eventJson
|
|
15043
15145
|
};
|
|
15044
|
-
return new Promise((
|
|
15146
|
+
return new Promise((resolve9) => {
|
|
15045
15147
|
const child = spawn(channel.command.command, channel.command.args ?? [], {
|
|
15046
15148
|
cwd: channel.command.cwd,
|
|
15047
15149
|
env,
|
|
@@ -15059,7 +15161,7 @@ async function dispatchCommand(event, channel) {
|
|
|
15059
15161
|
});
|
|
15060
15162
|
child.on("error", (error) => {
|
|
15061
15163
|
clearTimeout(timeout);
|
|
15062
|
-
|
|
15164
|
+
resolve9({
|
|
15063
15165
|
attempt: 1,
|
|
15064
15166
|
status: "failed",
|
|
15065
15167
|
startedAt,
|
|
@@ -15072,7 +15174,7 @@ async function dispatchCommand(event, channel) {
|
|
|
15072
15174
|
child.on("close", (code, signal) => {
|
|
15073
15175
|
clearTimeout(timeout);
|
|
15074
15176
|
const success = code === 0;
|
|
15075
|
-
|
|
15177
|
+
resolve9({
|
|
15076
15178
|
attempt: 1,
|
|
15077
15179
|
status: success ? "success" : "failed",
|
|
15078
15180
|
startedAt,
|
|
@@ -15414,7 +15516,7 @@ function normalizeRetryPolicy(policy) {
|
|
|
15414
15516
|
};
|
|
15415
15517
|
}
|
|
15416
15518
|
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;
|
|
15417
|
-
var
|
|
15519
|
+
var init_dist2 = __esm(() => {
|
|
15418
15520
|
DEFAULT_SIGNATURE_TOLERANCE_MS = 5 * 60 * 1000;
|
|
15419
15521
|
EventValidationError = class EventValidationError extends Error {
|
|
15420
15522
|
eventType;
|
|
@@ -15837,7 +15939,7 @@ function emitSharedTaskEventQuiet(input) {
|
|
|
15837
15939
|
}
|
|
15838
15940
|
var SOURCE = "todos";
|
|
15839
15941
|
var init_shared_events = __esm(() => {
|
|
15840
|
-
|
|
15942
|
+
init_dist2();
|
|
15841
15943
|
init_database();
|
|
15842
15944
|
init_projects();
|
|
15843
15945
|
init_task_lists();
|
|
@@ -16594,14 +16696,14 @@ var init_task_parent_integrity = __esm(() => {
|
|
|
16594
16696
|
});
|
|
16595
16697
|
|
|
16596
16698
|
// src/lib/creator-identity.ts
|
|
16597
|
-
import { existsSync as
|
|
16598
|
-
import { join as
|
|
16699
|
+
import { existsSync as existsSync8, rmSync } from "fs";
|
|
16700
|
+
import { join as join8 } from "path";
|
|
16599
16701
|
function identityFilePath() {
|
|
16600
|
-
return
|
|
16702
|
+
return join8(getTodosGlobalDir(), "identity.json");
|
|
16601
16703
|
}
|
|
16602
16704
|
function readPersistedIdentity() {
|
|
16603
16705
|
const path = identityFilePath();
|
|
16604
|
-
if (!
|
|
16706
|
+
if (!existsSync8(path))
|
|
16605
16707
|
return null;
|
|
16606
16708
|
const parsed = readJsonFile(path);
|
|
16607
16709
|
if (!parsed || typeof parsed.agent_id !== "string" || !parsed.agent_id.trim())
|
|
@@ -16631,7 +16733,7 @@ function persistIdentity(identity) {
|
|
|
16631
16733
|
}
|
|
16632
16734
|
function clearPersistedIdentity() {
|
|
16633
16735
|
const path = identityFilePath();
|
|
16634
|
-
if (!
|
|
16736
|
+
if (!existsSync8(path))
|
|
16635
16737
|
return false;
|
|
16636
16738
|
try {
|
|
16637
16739
|
rmSync(path);
|
|
@@ -18164,17 +18266,17 @@ function sanitizeCreateTaskInput(input) {
|
|
|
18164
18266
|
return {
|
|
18165
18267
|
...input,
|
|
18166
18268
|
title: sanitizePreWriteText(input.title, "task.title"),
|
|
18167
|
-
description: input.description
|
|
18269
|
+
description: input.description == null ? input.description : sanitizePreWriteText(input.description, "task.description"),
|
|
18168
18270
|
tags: input.tags !== undefined ? sanitizePreWriteValue(input.tags, "task.tags") : undefined,
|
|
18169
18271
|
metadata: input.metadata !== undefined ? sanitizePreWriteValue(input.metadata, "task.metadata") : undefined,
|
|
18170
|
-
reason: input.reason
|
|
18272
|
+
reason: input.reason == null ? input.reason : sanitizePreWriteText(input.reason, "task.reason")
|
|
18171
18273
|
};
|
|
18172
18274
|
}
|
|
18173
18275
|
function sanitizeUpdateTaskInput(input) {
|
|
18174
18276
|
return {
|
|
18175
18277
|
...input,
|
|
18176
18278
|
title: input.title !== undefined ? sanitizePreWriteText(input.title, "task.title") : undefined,
|
|
18177
|
-
description: input.description
|
|
18279
|
+
description: input.description == null ? input.description : sanitizePreWriteText(input.description, "task.description"),
|
|
18178
18280
|
tags: input.tags !== undefined ? sanitizePreWriteValue(input.tags, "task.tags") : undefined,
|
|
18179
18281
|
metadata: input.metadata !== undefined ? sanitizePreWriteValue(input.metadata, "task.metadata") : undefined
|
|
18180
18282
|
};
|
|
@@ -20188,28 +20290,28 @@ var init_boards = __esm(() => {
|
|
|
20188
20290
|
|
|
20189
20291
|
// src/lib/artifact-store.ts
|
|
20190
20292
|
import { createHash as createHash5 } from "crypto";
|
|
20191
|
-
import { existsSync as
|
|
20192
|
-
import { basename as basename2, dirname as dirname5, join as
|
|
20293
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync4, rmSync as rmSync2, statSync as statSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
20294
|
+
import { basename as basename2, dirname as dirname5, join as join9, resolve as resolve9 } from "path";
|
|
20193
20295
|
import { tmpdir as tmpdir3 } from "os";
|
|
20194
20296
|
function isInMemoryDb2(path) {
|
|
20195
20297
|
return path === ":memory:" || path.startsWith("file::memory:");
|
|
20196
20298
|
}
|
|
20197
20299
|
function artifactStoreRoot() {
|
|
20198
20300
|
if (process.env["HASNA_TODOS_ARTIFACTS_DIR"])
|
|
20199
|
-
return
|
|
20301
|
+
return resolve9(process.env["HASNA_TODOS_ARTIFACTS_DIR"]);
|
|
20200
20302
|
if (process.env["TODOS_ARTIFACTS_DIR"])
|
|
20201
|
-
return
|
|
20303
|
+
return resolve9(process.env["TODOS_ARTIFACTS_DIR"]);
|
|
20202
20304
|
const dbPath = getDatabasePath();
|
|
20203
20305
|
if (isInMemoryDb2(dbPath))
|
|
20204
|
-
return
|
|
20205
|
-
return
|
|
20306
|
+
return join9(tmpdir3(), "hasna-todos-artifacts");
|
|
20307
|
+
return join9(dirname5(resolve9(dbPath)), "artifacts");
|
|
20206
20308
|
}
|
|
20207
20309
|
function artifactStorePath(relativePath) {
|
|
20208
20310
|
const normalized = relativePath.replace(/\\/g, "/");
|
|
20209
20311
|
if (normalized.includes("..") || normalized.startsWith("/") || normalized.length === 0) {
|
|
20210
20312
|
throw new Error("Invalid artifact store path");
|
|
20211
20313
|
}
|
|
20212
|
-
return
|
|
20314
|
+
return join9(artifactStoreRoot(), normalized);
|
|
20213
20315
|
}
|
|
20214
20316
|
function sha2562(buffer) {
|
|
20215
20317
|
return createHash5("sha256").update(buffer).digest("hex");
|
|
@@ -20249,8 +20351,8 @@ function mediaTypeFor(path, textLike) {
|
|
|
20249
20351
|
return "application/octet-stream";
|
|
20250
20352
|
}
|
|
20251
20353
|
function storeArtifactContent(input) {
|
|
20252
|
-
const sourcePath =
|
|
20253
|
-
if (!
|
|
20354
|
+
const sourcePath = resolve9(input.path);
|
|
20355
|
+
if (!existsSync9(sourcePath))
|
|
20254
20356
|
return null;
|
|
20255
20357
|
const sourceStat = statSync2(sourcePath);
|
|
20256
20358
|
if (!sourceStat.isFile())
|
|
@@ -20267,9 +20369,9 @@ function storeArtifactContent(input) {
|
|
|
20267
20369
|
redactionStatus = "redacted";
|
|
20268
20370
|
}
|
|
20269
20371
|
const storedSha = sha2562(storedBuffer);
|
|
20270
|
-
const relativePath =
|
|
20372
|
+
const relativePath = join9("sha256", storedSha.slice(0, 2), storedSha).replace(/\\/g, "/");
|
|
20271
20373
|
const destination = artifactStorePath(relativePath);
|
|
20272
|
-
if (!
|
|
20374
|
+
if (!existsSync9(destination)) {
|
|
20273
20375
|
mkdirSync5(dirname5(destination), { recursive: true });
|
|
20274
20376
|
writeFileSync3(destination, storedBuffer);
|
|
20275
20377
|
}
|
|
@@ -20329,7 +20431,7 @@ function verifyStoredArtifact(input) {
|
|
|
20329
20431
|
};
|
|
20330
20432
|
}
|
|
20331
20433
|
const storedPath = artifactStorePath(store.relative_path);
|
|
20332
|
-
if (!
|
|
20434
|
+
if (!existsSync9(storedPath)) {
|
|
20333
20435
|
return {
|
|
20334
20436
|
id: input.id,
|
|
20335
20437
|
path: input.path,
|
|
@@ -21930,8 +22032,8 @@ function normalizeAgentNameInput(name) {
|
|
|
21930
22032
|
|
|
21931
22033
|
// src/lib/assignee-validation.ts
|
|
21932
22034
|
import { readFileSync as readFileSync5 } from "fs";
|
|
21933
|
-
import { homedir as
|
|
21934
|
-
import { join as
|
|
22035
|
+
import { homedir as homedir5 } from "os";
|
|
22036
|
+
import { join as join10 } from "path";
|
|
21935
22037
|
function describeAssigneeFilter(input, ctx) {
|
|
21936
22038
|
const raw = input.trim();
|
|
21937
22039
|
const normalized = normalizeAgentNameInput(raw);
|
|
@@ -21950,7 +22052,7 @@ function describeAssigneeFilter(input, ctx) {
|
|
|
21950
22052
|
};
|
|
21951
22053
|
}
|
|
21952
22054
|
function defaultSeatRosterPath() {
|
|
21953
|
-
return process.env["TODOS_SEAT_ROSTER_PATH"] ||
|
|
22055
|
+
return process.env["TODOS_SEAT_ROSTER_PATH"] || join10(homedir5(), ".hasna", "identities", "hasna-seats.roster.json");
|
|
21954
22056
|
}
|
|
21955
22057
|
function loadSeatSlugs(path = defaultSeatRosterPath()) {
|
|
21956
22058
|
try {
|
|
@@ -22756,7 +22858,7 @@ __export(exports_task_routing, {
|
|
|
22756
22858
|
setTaskWorkflowPointers: () => setTaskWorkflowPointers,
|
|
22757
22859
|
getTaskRouteState: () => getTaskRouteState
|
|
22758
22860
|
});
|
|
22759
|
-
import { existsSync as
|
|
22861
|
+
import { existsSync as existsSync10, statSync as statSync3 } from "fs";
|
|
22760
22862
|
function machineLocalPath(project, db) {
|
|
22761
22863
|
const machineId = process.env["TODOS_MACHINE_ID"];
|
|
22762
22864
|
if (!machineId)
|
|
@@ -22796,7 +22898,7 @@ function routeConcurrencyKey(task, project, taskList, projectPath) {
|
|
|
22796
22898
|
}
|
|
22797
22899
|
function directoryExists(path) {
|
|
22798
22900
|
try {
|
|
22799
|
-
return
|
|
22901
|
+
return existsSync10(path) && statSync3(path).isDirectory();
|
|
22800
22902
|
} catch {
|
|
22801
22903
|
return false;
|
|
22802
22904
|
}
|
|
@@ -23025,7 +23127,7 @@ __export(exports_task_commands, {
|
|
|
23025
23127
|
escapeTerminalControls: () => escapeTerminalControls
|
|
23026
23128
|
});
|
|
23027
23129
|
import chalk3 from "chalk";
|
|
23028
|
-
import { basename as basename3, resolve as
|
|
23130
|
+
import { basename as basename3, resolve as resolve10 } from "path";
|
|
23029
23131
|
function escapeTerminalControls(value) {
|
|
23030
23132
|
return value.replace(/[\u0000-\u001f\u007f-\u009f]/g, (character) => {
|
|
23031
23133
|
const code = character.charCodeAt(0);
|
|
@@ -23068,11 +23170,11 @@ async function cloudDetailGitRefs(cloud, id) {
|
|
|
23068
23170
|
function resolveProjectIdOrSlug(input) {
|
|
23069
23171
|
const db = getDatabase();
|
|
23070
23172
|
if (isPathLike(input)) {
|
|
23071
|
-
const projectPath =
|
|
23173
|
+
const projectPath = resolve10(input);
|
|
23072
23174
|
const byPath2 = getProjectByPath(projectPath, db);
|
|
23073
23175
|
return (byPath2 ?? ensureProject(basename3(projectPath), projectPath, db)).id;
|
|
23074
23176
|
}
|
|
23075
|
-
const byPath = getProjectByPath(
|
|
23177
|
+
const byPath = getProjectByPath(resolve10(input), db);
|
|
23076
23178
|
if (byPath)
|
|
23077
23179
|
return byPath.id;
|
|
23078
23180
|
const byId = getProject(input, db);
|
|
@@ -23481,7 +23583,7 @@ function registerTaskCommands(program2) {
|
|
|
23481
23583
|
task_list_id: taskListId2,
|
|
23482
23584
|
tags: parseTags(opts.tags),
|
|
23483
23585
|
metadata: buildExpectationMetadata(opts),
|
|
23484
|
-
working_dir: opts.workingDir ?
|
|
23586
|
+
working_dir: opts.workingDir ? resolve10(opts.workingDir) : process.cwd(),
|
|
23485
23587
|
project_id: projectId2,
|
|
23486
23588
|
assigned_to: opts.assign,
|
|
23487
23589
|
plan_id: plan?.id
|
|
@@ -23518,7 +23620,7 @@ function registerTaskCommands(program2) {
|
|
|
23518
23620
|
task_list_id: taskListId,
|
|
23519
23621
|
tags: parseTags(opts.tags),
|
|
23520
23622
|
metadata: buildExpectationMetadata(opts),
|
|
23521
|
-
working_dir: opts.workingDir ?
|
|
23623
|
+
working_dir: opts.workingDir ? resolve10(opts.workingDir) : process.cwd(),
|
|
23522
23624
|
project_id: projectId,
|
|
23523
23625
|
assigned_to: opts.assign,
|
|
23524
23626
|
plan_id: planId,
|
|
@@ -24264,7 +24366,7 @@ ${chalk3.cyan(sid)} ${statusColor(task2.status)} ${prioColor(task2.priority)} ${
|
|
|
24264
24366
|
tags: opts.tags ? opts.tags.split(",").map((t) => t.trim()) : undefined,
|
|
24265
24367
|
plan_id: plan?.id ?? (opts.clearPlan ? null : undefined),
|
|
24266
24368
|
...reparent2,
|
|
24267
|
-
working_dir: opts.workingDir ?
|
|
24369
|
+
working_dir: opts.workingDir ? resolve10(opts.workingDir) : opts.clearWorkingDir ? null : undefined,
|
|
24268
24370
|
estimated_minutes: opts.estimated !== undefined ? parseIntOption(opts.estimated, "--estimated") : undefined,
|
|
24269
24371
|
sla_minutes: opts.slaMinutes !== undefined || opts.sla !== undefined ? parseIntOption(opts.slaMinutes ?? opts.sla, "--sla-minutes") : undefined,
|
|
24270
24372
|
due_at: opts.due !== undefined ? opts.due === "" ? null : opts.due.length === 10 ? opts.due + "T00:00:00.000Z" : opts.due : undefined,
|
|
@@ -24309,7 +24411,7 @@ ${chalk3.cyan(sid)} ${statusColor(task2.status)} ${prioColor(task2.priority)} ${
|
|
|
24309
24411
|
tags: opts.tags ? opts.tags.split(",").map((t) => t.trim()) : undefined,
|
|
24310
24412
|
plan_id: planId,
|
|
24311
24413
|
...reparent,
|
|
24312
|
-
working_dir: opts.workingDir ?
|
|
24414
|
+
working_dir: opts.workingDir ? resolve10(opts.workingDir) : opts.clearWorkingDir ? null : undefined,
|
|
24313
24415
|
estimated_minutes: opts.estimated !== undefined ? parseIntOption(opts.estimated, "--estimated") : undefined,
|
|
24314
24416
|
sla_minutes: opts.slaMinutes !== undefined || opts.sla !== undefined ? parseIntOption(opts.slaMinutes ?? opts.sla, "--sla-minutes") : undefined,
|
|
24315
24417
|
due_at: opts.due !== undefined ? opts.due === "" ? null : opts.due.length === 10 ? opts.due + "T00:00:00.000Z" : opts.due : undefined,
|
|
@@ -24827,8 +24929,8 @@ var init_plan_comments = __esm(() => {
|
|
|
24827
24929
|
});
|
|
24828
24930
|
|
|
24829
24931
|
// src/lib/plan-artifacts.ts
|
|
24830
|
-
import { existsSync as
|
|
24831
|
-
import { join as
|
|
24932
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
24933
|
+
import { join as join11, resolve as resolve11 } from "path";
|
|
24832
24934
|
function assertSafePathSegment(value, label) {
|
|
24833
24935
|
const trimmed = value.trim();
|
|
24834
24936
|
if (!trimmed || trimmed === "." || trimmed === ".." || trimmed.includes("/") || trimmed.includes("\\")) {
|
|
@@ -24871,7 +24973,7 @@ function resolvePlanArtifactProject(input) {
|
|
|
24871
24973
|
const ref = input.project_id || input.project_ref;
|
|
24872
24974
|
if (!ref)
|
|
24873
24975
|
throw new Error("Plan artifacts require a project id or project reference");
|
|
24874
|
-
const byPath = getProjectByPath(
|
|
24976
|
+
const byPath = getProjectByPath(resolve11(ref), db);
|
|
24875
24977
|
if (byPath)
|
|
24876
24978
|
return byPath;
|
|
24877
24979
|
const resolvedId = resolvePartialId(db, "projects", ref);
|
|
@@ -24888,8 +24990,8 @@ function resolvePlanArtifactProject(input) {
|
|
|
24888
24990
|
function resolvePlanArtifactPaths(input) {
|
|
24889
24991
|
const project = resolvePlanArtifactProject(input);
|
|
24890
24992
|
const projectId = assertSafePathSegment(project.id, "project id");
|
|
24891
|
-
const projectRoot =
|
|
24892
|
-
const directory =
|
|
24993
|
+
const projectRoot = resolve11(project.path);
|
|
24994
|
+
const directory = join11(projectRoot, ".hasna", "todos", "plans", projectId);
|
|
24893
24995
|
const planId = input.plan_id ? assertSafePathSegment(input.plan_id, "plan id") : null;
|
|
24894
24996
|
const planSlug = input.plan_slug ? assertSafePathSegment(slugify(input.plan_slug), "plan slug") : null;
|
|
24895
24997
|
const fileName = planId ? planSlug ? `${planSlug}--${planId.slice(0, 8)}.md` : `${planId}.md` : null;
|
|
@@ -24897,7 +24999,7 @@ function resolvePlanArtifactPaths(input) {
|
|
|
24897
24999
|
project_id: project.id,
|
|
24898
25000
|
project_root: projectRoot,
|
|
24899
25001
|
directory,
|
|
24900
|
-
file_path: fileName ?
|
|
25002
|
+
file_path: fileName ? join11(directory, fileName) : directory
|
|
24901
25003
|
};
|
|
24902
25004
|
}
|
|
24903
25005
|
function resolvePlanArtifactCandidatePaths(plan, db) {
|
|
@@ -25063,7 +25165,7 @@ function readPlanArtifact(plan, db) {
|
|
|
25063
25165
|
return null;
|
|
25064
25166
|
const d = db || getDatabase();
|
|
25065
25167
|
const paths = resolvePlanArtifactCandidatePaths(plan, d);
|
|
25066
|
-
const path =
|
|
25168
|
+
const path = existsSync11(paths.primary.file_path) ? paths.primary.file_path : existsSync11(paths.legacy.file_path) ? paths.legacy.file_path : null;
|
|
25067
25169
|
if (!path)
|
|
25068
25170
|
return null;
|
|
25069
25171
|
const markdown = readFileSync6(path, "utf8");
|
|
@@ -25078,7 +25180,7 @@ function inspectPlanArtifact(plan, db) {
|
|
|
25078
25180
|
return null;
|
|
25079
25181
|
const d = db || getDatabase();
|
|
25080
25182
|
const paths = resolvePlanArtifactCandidatePaths(plan, d);
|
|
25081
|
-
const path =
|
|
25183
|
+
const path = existsSync11(paths.primary.file_path) ? paths.primary.file_path : existsSync11(paths.legacy.file_path) ? paths.legacy.file_path : null;
|
|
25082
25184
|
if (!path) {
|
|
25083
25185
|
return {
|
|
25084
25186
|
path: paths.primary.file_path,
|
|
@@ -26554,7 +26656,7 @@ __export(exports_builtin_templates, {
|
|
|
26554
26656
|
BUILTIN_TEMPLATES: () => BUILTIN_TEMPLATES
|
|
26555
26657
|
});
|
|
26556
26658
|
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync5 } from "fs";
|
|
26557
|
-
import { join as
|
|
26659
|
+
import { join as join12 } from "path";
|
|
26558
26660
|
function templateMetadata(template) {
|
|
26559
26661
|
return {
|
|
26560
26662
|
source: BUILTIN_TEMPLATE_LIBRARY_SOURCE,
|
|
@@ -26613,7 +26715,7 @@ function writeBuiltinTemplateFiles(directory) {
|
|
|
26613
26715
|
mkdirSync7(directory, { recursive: true });
|
|
26614
26716
|
const files = [];
|
|
26615
26717
|
for (const entry of exportBuiltinTemplateFiles()) {
|
|
26616
|
-
const path =
|
|
26718
|
+
const path = join12(directory, entry.filename);
|
|
26617
26719
|
writeFileSync5(path, `${JSON.stringify(entry.template, null, 2)}
|
|
26618
26720
|
`, "utf-8");
|
|
26619
26721
|
files.push(path);
|
|
@@ -28305,16 +28407,16 @@ var init_saved_search_views = __esm(() => {
|
|
|
28305
28407
|
});
|
|
28306
28408
|
|
|
28307
28409
|
// src/lib/claude-tasks.ts
|
|
28308
|
-
import { existsSync as
|
|
28309
|
-
import { join as
|
|
28410
|
+
import { existsSync as existsSync12, readFileSync as readFileSync7, readdirSync as readdirSync2, writeFileSync as writeFileSync6 } from "fs";
|
|
28411
|
+
import { join as join13 } from "path";
|
|
28310
28412
|
function getTaskListDir(taskListId) {
|
|
28311
|
-
return
|
|
28413
|
+
return join13(HOME, ".claude", "tasks", taskListId);
|
|
28312
28414
|
}
|
|
28313
28415
|
function readClaudeTask(dir, filename) {
|
|
28314
|
-
return readJsonFile(
|
|
28416
|
+
return readJsonFile(join13(dir, filename));
|
|
28315
28417
|
}
|
|
28316
28418
|
function writeClaudeTask(dir, task) {
|
|
28317
|
-
writeJsonFile(
|
|
28419
|
+
writeJsonFile(join13(dir, `${task.id}.json`), task);
|
|
28318
28420
|
}
|
|
28319
28421
|
function toClaudeStatus(status) {
|
|
28320
28422
|
if (status === "pending" || status === "in_progress" || status === "completed") {
|
|
@@ -28326,14 +28428,14 @@ function toSqliteStatus(status) {
|
|
|
28326
28428
|
return status;
|
|
28327
28429
|
}
|
|
28328
28430
|
function readPrefixCounter(dir) {
|
|
28329
|
-
const path =
|
|
28330
|
-
if (!
|
|
28431
|
+
const path = join13(dir, ".prefix-counter");
|
|
28432
|
+
if (!existsSync12(path))
|
|
28331
28433
|
return 0;
|
|
28332
28434
|
const val = parseInt(readFileSync7(path, "utf-8").trim(), 10);
|
|
28333
28435
|
return isNaN(val) ? 0 : val;
|
|
28334
28436
|
}
|
|
28335
28437
|
function writePrefixCounter(dir, value) {
|
|
28336
|
-
writeFileSync6(
|
|
28438
|
+
writeFileSync6(join13(dir, ".prefix-counter"), String(value));
|
|
28337
28439
|
}
|
|
28338
28440
|
function formatPrefixedSubject(title, prefix, counter) {
|
|
28339
28441
|
const padded = String(counter).padStart(5, "0");
|
|
@@ -28360,7 +28462,7 @@ function taskToClaudeTask(task, claudeTaskId, existingMeta) {
|
|
|
28360
28462
|
}
|
|
28361
28463
|
function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
28362
28464
|
const dir = getTaskListDir(taskListId);
|
|
28363
|
-
if (!
|
|
28465
|
+
if (!existsSync12(dir))
|
|
28364
28466
|
ensureDir(dir);
|
|
28365
28467
|
const filter = {};
|
|
28366
28468
|
if (projectId)
|
|
@@ -28369,7 +28471,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
28369
28471
|
const existingByTodosId = new Map;
|
|
28370
28472
|
const files = listJsonFiles(dir);
|
|
28371
28473
|
for (const f of files) {
|
|
28372
|
-
const path =
|
|
28474
|
+
const path = join13(dir, f);
|
|
28373
28475
|
const ct = readClaudeTask(dir, f);
|
|
28374
28476
|
if (ct?.metadata?.["todos_id"]) {
|
|
28375
28477
|
existingByTodosId.set(ct.metadata["todos_id"], { task: ct, mtimeMs: getFileMtimeMs(path) });
|
|
@@ -28458,7 +28560,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
28458
28560
|
}
|
|
28459
28561
|
function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
|
|
28460
28562
|
const dir = getTaskListDir(taskListId);
|
|
28461
|
-
if (!
|
|
28563
|
+
if (!existsSync12(dir)) {
|
|
28462
28564
|
return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
|
|
28463
28565
|
}
|
|
28464
28566
|
const files = readdirSync2(dir).filter((f) => f.endsWith(".json"));
|
|
@@ -28478,7 +28580,7 @@ function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
28478
28580
|
}
|
|
28479
28581
|
for (const f of files) {
|
|
28480
28582
|
try {
|
|
28481
|
-
const filePath =
|
|
28583
|
+
const filePath = join13(dir, f);
|
|
28482
28584
|
const ct = readClaudeTask(dir, f);
|
|
28483
28585
|
if (!ct)
|
|
28484
28586
|
continue;
|
|
@@ -28551,20 +28653,20 @@ var init_claude_tasks = __esm(() => {
|
|
|
28551
28653
|
});
|
|
28552
28654
|
|
|
28553
28655
|
// src/lib/agent-tasks.ts
|
|
28554
|
-
import { existsSync as
|
|
28555
|
-
import { join as
|
|
28656
|
+
import { existsSync as existsSync13 } from "fs";
|
|
28657
|
+
import { join as join14 } from "path";
|
|
28556
28658
|
function agentBaseDir(agent) {
|
|
28557
28659
|
const key = `TODOS_${agent.toUpperCase()}_TASKS_DIR`;
|
|
28558
|
-
return process.env[key] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] ||
|
|
28660
|
+
return process.env[key] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] || join14(getTodosGlobalDir(), "agents");
|
|
28559
28661
|
}
|
|
28560
28662
|
function getTaskListDir2(agent, taskListId) {
|
|
28561
|
-
return
|
|
28663
|
+
return join14(agentBaseDir(agent), agent, taskListId);
|
|
28562
28664
|
}
|
|
28563
28665
|
function readAgentTask(dir, filename) {
|
|
28564
|
-
return readJsonFile(
|
|
28666
|
+
return readJsonFile(join14(dir, filename));
|
|
28565
28667
|
}
|
|
28566
28668
|
function writeAgentTask(dir, task) {
|
|
28567
|
-
writeJsonFile(
|
|
28669
|
+
writeJsonFile(join14(dir, `${task.id}.json`), task);
|
|
28568
28670
|
}
|
|
28569
28671
|
function taskToAgentTask(task, externalId, existingMeta) {
|
|
28570
28672
|
return withSyncFingerprint({
|
|
@@ -28589,7 +28691,7 @@ function metadataKey(agent) {
|
|
|
28589
28691
|
}
|
|
28590
28692
|
function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
28591
28693
|
const dir = getTaskListDir2(agent, taskListId);
|
|
28592
|
-
if (!
|
|
28694
|
+
if (!existsSync13(dir))
|
|
28593
28695
|
ensureDir(dir);
|
|
28594
28696
|
const filter = {};
|
|
28595
28697
|
if (projectId)
|
|
@@ -28598,7 +28700,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
|
28598
28700
|
const existingByTodosId = new Map;
|
|
28599
28701
|
const files = listJsonFiles(dir);
|
|
28600
28702
|
for (const f of files) {
|
|
28601
|
-
const path =
|
|
28703
|
+
const path = join14(dir, f);
|
|
28602
28704
|
const at = readAgentTask(dir, f);
|
|
28603
28705
|
if (at?.metadata?.["todos_id"]) {
|
|
28604
28706
|
existingByTodosId.set(at.metadata["todos_id"], { task: at, mtimeMs: getFileMtimeMs(path) });
|
|
@@ -28674,7 +28776,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
|
28674
28776
|
}
|
|
28675
28777
|
function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
28676
28778
|
const dir = getTaskListDir2(agent, taskListId);
|
|
28677
|
-
if (!
|
|
28779
|
+
if (!existsSync13(dir)) {
|
|
28678
28780
|
return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
|
|
28679
28781
|
}
|
|
28680
28782
|
const files = listJsonFiles(dir);
|
|
@@ -28693,7 +28795,7 @@ function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
|
28693
28795
|
}
|
|
28694
28796
|
for (const f of files) {
|
|
28695
28797
|
try {
|
|
28696
|
-
const filePath =
|
|
28798
|
+
const filePath = join14(dir, f);
|
|
28697
28799
|
const at = readAgentTask(dir, f);
|
|
28698
28800
|
if (!at)
|
|
28699
28801
|
continue;
|
|
@@ -29101,8 +29203,8 @@ __export(exports_project_bootstrap, {
|
|
|
29101
29203
|
discoverProjectWorkspace: () => discoverProjectWorkspace,
|
|
29102
29204
|
bootstrapProject: () => bootstrapProject
|
|
29103
29205
|
});
|
|
29104
|
-
import { existsSync as
|
|
29105
|
-
import { basename as basename4, dirname as dirname6, resolve as
|
|
29206
|
+
import { existsSync as existsSync14, readFileSync as readFileSync8, statSync as statSync4 } from "fs";
|
|
29207
|
+
import { basename as basename4, dirname as dirname6, resolve as resolve12 } from "path";
|
|
29106
29208
|
function safeStat(path) {
|
|
29107
29209
|
try {
|
|
29108
29210
|
return statSync4(path);
|
|
@@ -29111,7 +29213,7 @@ function safeStat(path) {
|
|
|
29111
29213
|
}
|
|
29112
29214
|
}
|
|
29113
29215
|
function canonicalPath(input) {
|
|
29114
|
-
const resolved =
|
|
29216
|
+
const resolved = resolve12(input);
|
|
29115
29217
|
const stats = safeStat(resolved);
|
|
29116
29218
|
if (stats?.isFile())
|
|
29117
29219
|
return dirname6(resolved);
|
|
@@ -29120,7 +29222,7 @@ function canonicalPath(input) {
|
|
|
29120
29222
|
function findUp(start, marker) {
|
|
29121
29223
|
let current = canonicalPath(start);
|
|
29122
29224
|
while (true) {
|
|
29123
|
-
if (
|
|
29225
|
+
if (existsSync14(resolve12(current, marker)))
|
|
29124
29226
|
return current;
|
|
29125
29227
|
const parent = dirname6(current);
|
|
29126
29228
|
if (parent === current)
|
|
@@ -29131,8 +29233,8 @@ function findUp(start, marker) {
|
|
|
29131
29233
|
function readPackageJson(path) {
|
|
29132
29234
|
if (!path)
|
|
29133
29235
|
return null;
|
|
29134
|
-
const file =
|
|
29135
|
-
if (!
|
|
29236
|
+
const file = resolve12(path, "package.json");
|
|
29237
|
+
if (!existsSync14(file))
|
|
29136
29238
|
return null;
|
|
29137
29239
|
try {
|
|
29138
29240
|
const parsed = JSON.parse(readFileSync8(file, "utf-8"));
|
|
@@ -29154,7 +29256,7 @@ function workspaceMarker(root, rootPackage) {
|
|
|
29154
29256
|
if (rootPackage?.workspaces)
|
|
29155
29257
|
markers.push("package.json#workspaces");
|
|
29156
29258
|
for (const marker of ["pnpm-workspace.yaml", "turbo.json", "nx.json", "lerna.json", "rush.json", "bun.lock", "bun.lockb"]) {
|
|
29157
|
-
if (
|
|
29259
|
+
if (existsSync14(resolve12(root, marker)))
|
|
29158
29260
|
markers.push(marker);
|
|
29159
29261
|
}
|
|
29160
29262
|
const kind = markers.find((marker) => marker !== "bun.lock" && marker !== "bun.lockb") ?? null;
|
|
@@ -29488,9 +29590,9 @@ __export(exports_extract, {
|
|
|
29488
29590
|
buildCodebaseIndex: () => buildCodebaseIndex,
|
|
29489
29591
|
EXTRACT_TAGS: () => EXTRACT_TAGS
|
|
29490
29592
|
});
|
|
29491
|
-
import { existsSync as
|
|
29593
|
+
import { existsSync as existsSync15, readFileSync as readFileSync9, statSync as statSync5 } from "fs";
|
|
29492
29594
|
import { createHash as createHash7 } from "crypto";
|
|
29493
|
-
import { relative as relative3, resolve as
|
|
29595
|
+
import { relative as relative3, resolve as resolve13, join as join15 } from "path";
|
|
29494
29596
|
function stableHash(value) {
|
|
29495
29597
|
return createHash7("sha256").update(value).digest("hex");
|
|
29496
29598
|
}
|
|
@@ -29498,9 +29600,9 @@ function normalizePathForMatch(value) {
|
|
|
29498
29600
|
return value.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
29499
29601
|
}
|
|
29500
29602
|
function readGitignorePatterns(basePath) {
|
|
29501
|
-
const root = statSync5(basePath).isFile() ?
|
|
29502
|
-
const gitignorePath =
|
|
29503
|
-
if (!
|
|
29603
|
+
const root = statSync5(basePath).isFile() ? resolve13(basePath, "..") : basePath;
|
|
29604
|
+
const gitignorePath = join15(root, ".gitignore");
|
|
29605
|
+
if (!existsSync15(gitignorePath))
|
|
29504
29606
|
return [];
|
|
29505
29607
|
try {
|
|
29506
29608
|
return readFileSync9(gitignorePath, "utf-8").split(`
|
|
@@ -29634,7 +29736,7 @@ function collectFiles(basePath, extensions, excludes, respectGitignore) {
|
|
|
29634
29736
|
return files.sort();
|
|
29635
29737
|
}
|
|
29636
29738
|
function buildCodebaseIndex(options) {
|
|
29637
|
-
const basePath =
|
|
29739
|
+
const basePath = resolve13(options.path);
|
|
29638
29740
|
const tags = options.patterns || [...EXTRACT_TAGS];
|
|
29639
29741
|
const extensions = options.extensions ? new Set(options.extensions.map((e) => e.startsWith(".") ? e : `.${e}`)) : DEFAULT_EXTENSIONS;
|
|
29640
29742
|
const excludes = options.exclude || [];
|
|
@@ -29642,10 +29744,10 @@ function buildCodebaseIndex(options) {
|
|
|
29642
29744
|
const files = collectFiles(basePath, extensions, excludes, respectGitignore);
|
|
29643
29745
|
const indexed = [];
|
|
29644
29746
|
for (const file of files) {
|
|
29645
|
-
const fullPath = statSync5(basePath).isFile() ? basePath :
|
|
29747
|
+
const fullPath = statSync5(basePath).isFile() ? basePath : join15(basePath, file);
|
|
29646
29748
|
try {
|
|
29647
29749
|
const source = readFileSync9(fullPath, "utf-8");
|
|
29648
|
-
const relPath = statSync5(basePath).isFile() ? relative3(
|
|
29750
|
+
const relPath = statSync5(basePath).isFile() ? relative3(resolve13(basePath, ".."), fullPath) : file;
|
|
29649
29751
|
indexed.push({
|
|
29650
29752
|
file: relPath,
|
|
29651
29753
|
checksum: stableHash(source).slice(0, 24),
|
|
@@ -29665,7 +29767,7 @@ function buildCodebaseIndex(options) {
|
|
|
29665
29767
|
};
|
|
29666
29768
|
}
|
|
29667
29769
|
function extractTodos(options, db) {
|
|
29668
|
-
const basePath =
|
|
29770
|
+
const basePath = resolve13(options.path);
|
|
29669
29771
|
const tags = options.patterns || [...EXTRACT_TAGS];
|
|
29670
29772
|
const extensions = options.extensions ? new Set(options.extensions.map((e) => e.startsWith(".") ? e : `.${e}`)) : DEFAULT_EXTENSIONS;
|
|
29671
29773
|
const excludes = options.exclude || [];
|
|
@@ -29673,10 +29775,10 @@ function extractTodos(options, db) {
|
|
|
29673
29775
|
const files = collectFiles(basePath, extensions, excludes, respectGitignore);
|
|
29674
29776
|
const allComments = [];
|
|
29675
29777
|
for (const file of files) {
|
|
29676
|
-
const fullPath = statSync5(basePath).isFile() ? basePath :
|
|
29778
|
+
const fullPath = statSync5(basePath).isFile() ? basePath : join15(basePath, file);
|
|
29677
29779
|
try {
|
|
29678
29780
|
const source = readFileSync9(fullPath, "utf-8");
|
|
29679
|
-
const relPath = statSync5(basePath).isFile() ? relative3(
|
|
29781
|
+
const relPath = statSync5(basePath).isFile() ? relative3(resolve13(basePath, ".."), fullPath) : file;
|
|
29680
29782
|
const comments = extractFromSource(source, relPath, tags);
|
|
29681
29783
|
allComments.push(...comments);
|
|
29682
29784
|
} catch {}
|
|
@@ -29770,7 +29872,7 @@ async function watchSourceTodos(options, onRun) {
|
|
|
29770
29872
|
const interval = Math.max(100, options.interval_ms || 2000);
|
|
29771
29873
|
const once = options.once !== false && (!options.max_runs || options.max_runs <= 1);
|
|
29772
29874
|
const maxRuns = options.max_runs ?? (once ? 1 : Number.POSITIVE_INFINITY);
|
|
29773
|
-
const root =
|
|
29875
|
+
const root = resolve13(options.path);
|
|
29774
29876
|
const runs = [];
|
|
29775
29877
|
let previous = new Map;
|
|
29776
29878
|
for (let runNumber = 1;runNumber <= maxRuns; runNumber++) {
|
|
@@ -31006,7 +31108,7 @@ __export(exports_project_commands, {
|
|
|
31006
31108
|
});
|
|
31007
31109
|
import chalk5 from "chalk";
|
|
31008
31110
|
import { readFileSync as readFileSync10, statSync as statSync6 } from "fs";
|
|
31009
|
-
import { basename as basename5, resolve as
|
|
31111
|
+
import { basename as basename5, resolve as resolve14, sep as sep3 } from "path";
|
|
31010
31112
|
function collectOption(value, previous = []) {
|
|
31011
31113
|
return [...previous, value];
|
|
31012
31114
|
}
|
|
@@ -31085,8 +31187,8 @@ function countTasksForDeregistration(tasks) {
|
|
|
31085
31187
|
};
|
|
31086
31188
|
}
|
|
31087
31189
|
function pathIsWithinPrefix(projectPath, prefix) {
|
|
31088
|
-
const normalizedPath =
|
|
31089
|
-
const normalizedPrefix =
|
|
31190
|
+
const normalizedPath = resolve14(projectPath);
|
|
31191
|
+
const normalizedPrefix = resolve14(prefix);
|
|
31090
31192
|
return normalizedPath === normalizedPrefix || normalizedPath.startsWith(`${normalizedPrefix}${sep3}`);
|
|
31091
31193
|
}
|
|
31092
31194
|
function resolveTaskListFilter(input, projectId) {
|
|
@@ -31298,7 +31400,7 @@ function registerProjectCommands(program2) {
|
|
|
31298
31400
|
}
|
|
31299
31401
|
let content;
|
|
31300
31402
|
if (opts.file !== undefined) {
|
|
31301
|
-
const commentFilePath =
|
|
31403
|
+
const commentFilePath = resolve14(opts.file);
|
|
31302
31404
|
let isRegularFile = false;
|
|
31303
31405
|
try {
|
|
31304
31406
|
isRegularFile = statSync6(commentFilePath).isFile();
|
|
@@ -31723,7 +31825,7 @@ function registerProjectCommands(program2) {
|
|
|
31723
31825
|
if (opts.update) {
|
|
31724
31826
|
const patch = {
|
|
31725
31827
|
...opts.name !== undefined ? { name: opts.name } : {},
|
|
31726
|
-
...opts.path !== undefined ? { path:
|
|
31828
|
+
...opts.path !== undefined ? { path: resolve14(opts.path) } : {},
|
|
31727
31829
|
...opts.description !== undefined ? { description: opts.description } : {}
|
|
31728
31830
|
};
|
|
31729
31831
|
if (Object.keys(patch).length === 0) {
|
|
@@ -31767,7 +31869,7 @@ function registerProjectCommands(program2) {
|
|
|
31767
31869
|
return;
|
|
31768
31870
|
}
|
|
31769
31871
|
if (opts.add) {
|
|
31770
|
-
const projectPath =
|
|
31872
|
+
const projectPath = resolve14(opts.add);
|
|
31771
31873
|
const name = opts.name || basename5(projectPath);
|
|
31772
31874
|
let parentId;
|
|
31773
31875
|
if (opts.parent !== undefined) {
|
|
@@ -31896,7 +31998,7 @@ function registerProjectCommands(program2) {
|
|
|
31896
31998
|
if (!resolved) {
|
|
31897
31999
|
handleError(new Error(`Project not found: ${projectId}`));
|
|
31898
32000
|
}
|
|
31899
|
-
const entry = setMachineLocalPath2(resolved,
|
|
32001
|
+
const entry = setMachineLocalPath2(resolved, resolve14(projectPath));
|
|
31900
32002
|
if (useJson) {
|
|
31901
32003
|
output(entry, true);
|
|
31902
32004
|
} else {
|
|
@@ -31958,7 +32060,7 @@ function registerProjectCommands(program2) {
|
|
|
31958
32060
|
const patterns = opts.pattern ? opts.pattern.split(",").map((t) => t.trim().toUpperCase()) : undefined;
|
|
31959
32061
|
const taskListId = opts.list ? resolveTaskListId(opts.list) : undefined;
|
|
31960
32062
|
const result = extractTodos2({
|
|
31961
|
-
path:
|
|
32063
|
+
path: resolve14(scanPath),
|
|
31962
32064
|
patterns,
|
|
31963
32065
|
project_id: projectId,
|
|
31964
32066
|
task_list_id: taskListId,
|
|
@@ -32019,7 +32121,7 @@ Indexed ${result.index.files.length} file(s), ${result.index.total_symbols} symb
|
|
|
32019
32121
|
const taskListId = opts.list ? resolveTaskListId(opts.list) : undefined;
|
|
32020
32122
|
const maxRuns = opts.maxRuns ? parseInt(opts.maxRuns, 10) : 1;
|
|
32021
32123
|
const result = await watchSourceTodos2({
|
|
32022
|
-
path:
|
|
32124
|
+
path: resolve14(scanPath),
|
|
32023
32125
|
patterns,
|
|
32024
32126
|
project_id: projectId,
|
|
32025
32127
|
task_list_id: taskListId,
|
|
@@ -32057,7 +32159,7 @@ Indexed ${result.index.files.length} file(s), ${result.index.total_symbols} symb
|
|
|
32057
32159
|
const writeOutput = async (content) => {
|
|
32058
32160
|
if (opts.output) {
|
|
32059
32161
|
const { writeFileSync: writeFileSync7 } = await import("fs");
|
|
32060
|
-
writeFileSync7(
|
|
32162
|
+
writeFileSync7(resolve14(opts.output), content.endsWith(`
|
|
32061
32163
|
`) ? content : `${content}
|
|
32062
32164
|
`);
|
|
32063
32165
|
} else {
|
|
@@ -32075,12 +32177,12 @@ Indexed ${result.index.files.length} file(s), ${result.index.total_symbols} symb
|
|
|
32075
32177
|
const exported = opts.encrypt ? createEncryptedBridgeBundle2(bundle, { profile: opts.encryptionProfile }) : bundle;
|
|
32076
32178
|
const json = JSON.stringify(exported, null, 2);
|
|
32077
32179
|
await writeOutput(json);
|
|
32078
|
-
emitLocalEventHooksQuiet3({ type: "export.finished", payload: { format: "bridge", encrypted: Boolean(opts.encrypt), project_id: projectId, output: opts.output ?
|
|
32180
|
+
emitLocalEventHooksQuiet3({ type: "export.finished", payload: { format: "bridge", encrypted: Boolean(opts.encrypt), project_id: projectId, output: opts.output ? resolve14(opts.output) : null, stats: bundle.stats } });
|
|
32079
32181
|
if (!opts.encrypt && !opts.allowPlaintextSensitive) {
|
|
32080
32182
|
console.error(chalk5.dim("Bridge export redacted sensitive fields. Use --encrypt for an encrypted local bundle when a lossless legacy snapshot is required."));
|
|
32081
32183
|
}
|
|
32082
32184
|
if (opts.output && !globalOpts.json) {
|
|
32083
|
-
console.log(chalk5.green(`${opts.encrypt ? "Encrypted bridge export" : "Bridge export"} written to ${
|
|
32185
|
+
console.log(chalk5.green(`${opts.encrypt ? "Encrypted bridge export" : "Bridge export"} written to ${resolve14(opts.output)}`));
|
|
32084
32186
|
}
|
|
32085
32187
|
return;
|
|
32086
32188
|
}
|
|
@@ -32093,7 +32195,7 @@ Indexed ${result.index.files.length} file(s), ${result.index.total_symbols} symb
|
|
|
32093
32195
|
await writeOutput(JSON.stringify(tasks, null, 2));
|
|
32094
32196
|
}
|
|
32095
32197
|
const { emitLocalEventHooksQuiet: emitLocalEventHooksQuiet2 } = await Promise.resolve().then(() => (init_event_hooks(), exports_event_hooks));
|
|
32096
|
-
emitLocalEventHooksQuiet2({ type: "export.finished", payload: { format: opts.format, project_id: projectId, output: opts.output ?
|
|
32198
|
+
emitLocalEventHooksQuiet2({ type: "export.finished", payload: { format: opts.format, project_id: projectId, output: opts.output ? resolve14(opts.output) : null, count: exportedCount } });
|
|
32097
32199
|
});
|
|
32098
32200
|
program2.command("bridge-import <file>").description("Dry-run or apply a local hasna/todos bridge export bundle").option("--apply", "Apply the import. Defaults to dry-run.").option("--decrypt", "Decrypt an encrypted bridge export before importing").option("--resolve-conflicts", "Safely merge existing local tasks by filling blank fields, unioning tags, and recording unresolved divergences").action(async (file, opts) => {
|
|
32099
32201
|
const globalOpts = program2.opts();
|
|
@@ -32101,13 +32203,13 @@ Indexed ${result.index.files.length} file(s), ${result.index.total_symbols} symb
|
|
|
32101
32203
|
const { readFileSync: readFileSync11 } = await import("fs");
|
|
32102
32204
|
const { importLocalBridgeBundle: importLocalBridgeBundle2 } = await Promise.resolve().then(() => (init_local_bridge(), exports_local_bridge));
|
|
32103
32205
|
const { decryptBridgeBundle: decryptBridgeBundle2, isEncryptedBridgeBundle: isEncryptedBridgeBundle2 } = await Promise.resolve().then(() => (init_local_encryption(), exports_local_encryption));
|
|
32104
|
-
const parsed = JSON.parse(readFileSync11(
|
|
32206
|
+
const parsed = JSON.parse(readFileSync11(resolve14(file), "utf-8"));
|
|
32105
32207
|
const bundle = isEncryptedBridgeBundle2(parsed) ? opts.decrypt ? decryptBridgeBundle2(parsed) : (() => {
|
|
32106
32208
|
throw new Error("Bridge bundle is encrypted. Re-run with --decrypt and the configured key environment variable set.");
|
|
32107
32209
|
})() : parsed;
|
|
32108
32210
|
const result = importLocalBridgeBundle2(bundle, { dryRun: !opts.apply, conflictStrategy: opts.resolveConflicts ? "safe_merge" : "skip" });
|
|
32109
32211
|
const { emitLocalEventHooksQuiet: emitLocalEventHooksQuiet2 } = await Promise.resolve().then(() => (init_event_hooks(), exports_event_hooks));
|
|
32110
|
-
emitLocalEventHooksQuiet2({ type: "import.finished", payload: { file:
|
|
32212
|
+
emitLocalEventHooksQuiet2({ type: "import.finished", payload: { file: resolve14(file), dry_run: result.dry_run, ok: result.ok, inserted: result.inserted, skipped: result.skipped, conflicts: result.conflicts.length, issues: result.issues.length } });
|
|
32111
32213
|
if (globalOpts.json) {
|
|
32112
32214
|
output(result, true);
|
|
32113
32215
|
return;
|
|
@@ -32137,9 +32239,9 @@ Indexed ${result.index.files.length} file(s), ${result.index.total_symbols} symb
|
|
|
32137
32239
|
try {
|
|
32138
32240
|
const { readFileSync: readFileSync11 } = await import("fs");
|
|
32139
32241
|
const { importTodosMarkdown: importTodosMarkdown2 } = await Promise.resolve().then(() => (init_todos_md(), exports_todos_md));
|
|
32140
|
-
const result = importTodosMarkdown2(readFileSync11(
|
|
32242
|
+
const result = importTodosMarkdown2(readFileSync11(resolve14(file), "utf-8"), { dryRun: !opts.apply, conflictStrategy: opts.resolveConflicts ? "safe_merge" : "skip" });
|
|
32141
32243
|
const { emitLocalEventHooksQuiet: emitLocalEventHooksQuiet2 } = await Promise.resolve().then(() => (init_event_hooks(), exports_event_hooks));
|
|
32142
|
-
emitLocalEventHooksQuiet2({ type: "import.finished", payload: { file:
|
|
32244
|
+
emitLocalEventHooksQuiet2({ type: "import.finished", payload: { file: resolve14(file), format: "todos.md", dry_run: result.dry_run, ok: result.ok, inserted: result.inserted, skipped: result.skipped, issues: result.issues.length } });
|
|
32143
32245
|
if (globalOpts.json) {
|
|
32144
32246
|
output(result, true);
|
|
32145
32247
|
return;
|
|
@@ -35272,7 +35374,7 @@ async function retryOnTransientPostgresError(fn, attempts = 2, delayMs = 150) {
|
|
|
35272
35374
|
lastError = error;
|
|
35273
35375
|
if (!isTransientPostgresError(error) || attempt === attempts)
|
|
35274
35376
|
throw error;
|
|
35275
|
-
await new Promise((
|
|
35377
|
+
await new Promise((resolve15) => setTimeout(resolve15, delayMs * attempt));
|
|
35276
35378
|
}
|
|
35277
35379
|
}
|
|
35278
35380
|
throw lastError;
|
|
@@ -36401,8 +36503,8 @@ class SqliteTodosProjectRegistrationBackend {
|
|
|
36401
36503
|
async transaction(fn) {
|
|
36402
36504
|
const previous = sqliteTransactionTails.get(this.db) ?? Promise.resolve();
|
|
36403
36505
|
let release;
|
|
36404
|
-
const current = new Promise((
|
|
36405
|
-
release =
|
|
36506
|
+
const current = new Promise((resolve15) => {
|
|
36507
|
+
release = resolve15;
|
|
36406
36508
|
});
|
|
36407
36509
|
sqliteTransactionTails.set(this.db, current);
|
|
36408
36510
|
await previous;
|
|
@@ -39165,8 +39267,8 @@ var init_ai = __esm(() => {
|
|
|
39165
39267
|
});
|
|
39166
39268
|
|
|
39167
39269
|
// src/lib/access-profiles.ts
|
|
39168
|
-
function resolveAccessProfile(
|
|
39169
|
-
const raw = (
|
|
39270
|
+
function resolveAccessProfile(envValue2) {
|
|
39271
|
+
const raw = (envValue2 ?? process.env["TODOS_PROFILE"] ?? "full").toLowerCase();
|
|
39170
39272
|
if (ACCESS_PROFILES.includes(raw))
|
|
39171
39273
|
return raw;
|
|
39172
39274
|
if (raw === "readonly")
|
|
@@ -40791,7 +40893,7 @@ function errorResult(runId, error) {
|
|
|
40791
40893
|
return createTodosAiFailureResult(runId, "internal_error", "optional AI runtime failed");
|
|
40792
40894
|
}
|
|
40793
40895
|
async function withLoadDeadline(operation, controller, timeoutMs) {
|
|
40794
|
-
return new Promise((
|
|
40896
|
+
return new Promise((resolve15, reject) => {
|
|
40795
40897
|
let settled = false;
|
|
40796
40898
|
const settle = (callback) => {
|
|
40797
40899
|
if (settled)
|
|
@@ -40805,11 +40907,11 @@ async function withLoadDeadline(operation, controller, timeoutMs) {
|
|
|
40805
40907
|
controller.abort(error);
|
|
40806
40908
|
settle(() => reject(error));
|
|
40807
40909
|
}, timeoutMs);
|
|
40808
|
-
Promise.resolve().then(operation).then((value) => settle(() =>
|
|
40910
|
+
Promise.resolve().then(operation).then((value) => settle(() => resolve15(value)), (error) => settle(() => reject(error)));
|
|
40809
40911
|
});
|
|
40810
40912
|
}
|
|
40811
40913
|
async function withInterrupt(operation, controller) {
|
|
40812
|
-
return new Promise((
|
|
40914
|
+
return new Promise((resolve15, reject) => {
|
|
40813
40915
|
let settled = false;
|
|
40814
40916
|
const settle = (callback) => {
|
|
40815
40917
|
if (settled)
|
|
@@ -40824,7 +40926,7 @@ async function withInterrupt(operation, controller) {
|
|
|
40824
40926
|
settle(() => reject(error));
|
|
40825
40927
|
};
|
|
40826
40928
|
process.once("SIGINT", onInterrupt);
|
|
40827
|
-
Promise.resolve().then(operation).then((value) => settle(() =>
|
|
40929
|
+
Promise.resolve().then(operation).then((value) => settle(() => resolve15(value)), (error) => settle(() => reject(error)));
|
|
40828
40930
|
});
|
|
40829
40931
|
}
|
|
40830
40932
|
function throwIfAborted(signal) {
|
|
@@ -41112,14 +41214,14 @@ async function findFreePort(start) {
|
|
|
41112
41214
|
var DEFAULT_PORT = 19427;
|
|
41113
41215
|
|
|
41114
41216
|
// src/lib/db-backup.ts
|
|
41115
|
-
import { existsSync as
|
|
41116
|
-
import { dirname as dirname7, join as
|
|
41217
|
+
import { existsSync as existsSync16, copyFileSync, mkdirSync as mkdirSync8, readFileSync as readFileSync12, renameSync, statSync as statSync7, writeFileSync as writeFileSync7, unlinkSync } from "fs";
|
|
41218
|
+
import { dirname as dirname7, join as join16, resolve as resolve15 } from "path";
|
|
41117
41219
|
import { Database as Database2 } from "bun:sqlite";
|
|
41118
41220
|
function resolveDbPath(dbPath) {
|
|
41119
41221
|
if (dbPath)
|
|
41120
|
-
return
|
|
41222
|
+
return resolve15(dbPath);
|
|
41121
41223
|
if (process.env["TODOS_DB_PATH"] && process.env["TODOS_DB_PATH"] !== ":memory:") {
|
|
41122
|
-
return
|
|
41224
|
+
return resolve15(process.env["TODOS_DB_PATH"]);
|
|
41123
41225
|
}
|
|
41124
41226
|
const db = getDatabase();
|
|
41125
41227
|
const filename = db.filename;
|
|
@@ -41129,7 +41231,7 @@ function resolveDbPath(dbPath) {
|
|
|
41129
41231
|
}
|
|
41130
41232
|
function backupDatabase(outputPath, sourcePath) {
|
|
41131
41233
|
const source = resolveDbPath(sourcePath);
|
|
41132
|
-
if (!
|
|
41234
|
+
if (!existsSync16(source))
|
|
41133
41235
|
throw new Error(`Database not found: ${source}`);
|
|
41134
41236
|
mkdirSync8(dirname7(outputPath), { recursive: true });
|
|
41135
41237
|
closeDatabase();
|
|
@@ -41152,9 +41254,9 @@ function backupDatabase(outputPath, sourcePath) {
|
|
|
41152
41254
|
};
|
|
41153
41255
|
}
|
|
41154
41256
|
function checkDatabaseIntegrity(dbPath) {
|
|
41155
|
-
const path = dbPath ?
|
|
41257
|
+
const path = dbPath ? resolve15(dbPath) : resolveDbPath();
|
|
41156
41258
|
const errors = [];
|
|
41157
|
-
if (!
|
|
41259
|
+
if (!existsSync16(path)) {
|
|
41158
41260
|
return {
|
|
41159
41261
|
schema_version: DB_BACKUP_SCHEMA,
|
|
41160
41262
|
path,
|
|
@@ -41217,9 +41319,9 @@ function checkDatabaseIntegrity(dbPath) {
|
|
|
41217
41319
|
};
|
|
41218
41320
|
}
|
|
41219
41321
|
function defaultBackupPath(dbPath) {
|
|
41220
|
-
const base = dbPath ? dirname7(
|
|
41322
|
+
const base = dbPath ? dirname7(resolve15(dbPath)) : dirname7(resolveDbPath());
|
|
41221
41323
|
const stamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
41222
|
-
return
|
|
41324
|
+
return join16(base, "backups", `todos-${stamp}.db`);
|
|
41223
41325
|
}
|
|
41224
41326
|
var DB_BACKUP_SCHEMA = "todos.db_backup.v1";
|
|
41225
41327
|
var init_db_backup = __esm(() => {
|
|
@@ -41236,7 +41338,7 @@ __export(exports_evidence_redaction, {
|
|
|
41236
41338
|
TODOS_EVIDENCE_REDACTION_CONFIRM: () => TODOS_EVIDENCE_REDACTION_CONFIRM
|
|
41237
41339
|
});
|
|
41238
41340
|
import { chmodSync } from "fs";
|
|
41239
|
-
import { join as
|
|
41341
|
+
import { join as join17 } from "path";
|
|
41240
41342
|
function unique4(values) {
|
|
41241
41343
|
return Array.from(new Set((values ?? []).map((value) => value.trim()).filter(Boolean)));
|
|
41242
41344
|
}
|
|
@@ -41583,7 +41685,7 @@ function redactEvidenceRows(options, db) {
|
|
|
41583
41685
|
}
|
|
41584
41686
|
function defaultEvidenceRedactionBackupPath(dbPath) {
|
|
41585
41687
|
const base = defaultBackupPath(dbPath);
|
|
41586
|
-
return
|
|
41688
|
+
return join17(base.replace(/\.db$/, ""), "pre-redaction.db");
|
|
41587
41689
|
}
|
|
41588
41690
|
var TODOS_EVIDENCE_REDACTION_SCHEMA = "todos.evidence_redaction.v1", TODOS_EVIDENCE_REDACTION_CONFIRM = "REDACT_TODOS_EVIDENCE";
|
|
41589
41691
|
var init_evidence_redaction = __esm(() => {
|
|
@@ -41599,7 +41701,7 @@ __export(exports_retention_cleanup, {
|
|
|
41599
41701
|
applyRetentionCleanup: () => applyRetentionCleanup,
|
|
41600
41702
|
RETENTION_CLEANUP_CONFIRMATION: () => RETENTION_CLEANUP_CONFIRMATION
|
|
41601
41703
|
});
|
|
41602
|
-
import { existsSync as
|
|
41704
|
+
import { existsSync as existsSync17, unlinkSync as unlinkSync2 } from "fs";
|
|
41603
41705
|
function normalizeScopes(scopes) {
|
|
41604
41706
|
if (!scopes || scopes.length === 0)
|
|
41605
41707
|
return [...ALL_SCOPES];
|
|
@@ -41802,7 +41904,7 @@ function applyRetentionCleanup(input, db) {
|
|
|
41802
41904
|
for (const artifact of report.candidates.artifact_files) {
|
|
41803
41905
|
try {
|
|
41804
41906
|
const path = artifactStorePath(artifact.relative_path);
|
|
41805
|
-
if (!
|
|
41907
|
+
if (!existsSync17(path)) {
|
|
41806
41908
|
report.warnings.push(`stored artifact already missing: ${artifact.relative_path}`);
|
|
41807
41909
|
continue;
|
|
41808
41910
|
}
|
|
@@ -42478,8 +42580,8 @@ __export(exports_local_extensions, {
|
|
|
42478
42580
|
discoverLocalExtensions: () => discoverLocalExtensions
|
|
42479
42581
|
});
|
|
42480
42582
|
import { createHash as createHash13, createVerify } from "crypto";
|
|
42481
|
-
import { existsSync as
|
|
42482
|
-
import { basename as basename6, join as
|
|
42583
|
+
import { existsSync as existsSync18, readdirSync as readdirSync3, readFileSync as readFileSync13, statSync as statSync8 } from "fs";
|
|
42584
|
+
import { basename as basename6, join as join18, resolve as resolve16 } from "path";
|
|
42483
42585
|
function isObject(value) {
|
|
42484
42586
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
42485
42587
|
}
|
|
@@ -42737,11 +42839,11 @@ function verifyExtensionSignature(input) {
|
|
|
42737
42839
|
return verifier.verify(input.public_key, decodeSignature(input.signature));
|
|
42738
42840
|
}
|
|
42739
42841
|
function inspectExtensionSource(source2) {
|
|
42740
|
-
const resolved =
|
|
42741
|
-
if (!
|
|
42842
|
+
const resolved = resolve16(source2);
|
|
42843
|
+
if (!existsSync18(resolved))
|
|
42742
42844
|
throw new Error(`extension source not found: ${source2}`);
|
|
42743
42845
|
const stat = statSync8(resolved);
|
|
42744
|
-
const manifestPath = stat.isDirectory() ? [
|
|
42846
|
+
const manifestPath = stat.isDirectory() ? [join18(resolved, "todos.extension.json"), join18(resolved, "extension.json")].find(existsSync18) : resolved;
|
|
42745
42847
|
if (!manifestPath)
|
|
42746
42848
|
throw new Error(`extension directory ${source2} is missing todos.extension.json`);
|
|
42747
42849
|
const raw = readFileSync13(manifestPath);
|
|
@@ -42835,26 +42937,26 @@ function testExtensionCompatibility(sourceOrManifest) {
|
|
|
42835
42937
|
function projectExtensionSources(projectPath) {
|
|
42836
42938
|
if (!projectPath)
|
|
42837
42939
|
return [];
|
|
42838
|
-
const root =
|
|
42940
|
+
const root = resolve16(projectPath);
|
|
42839
42941
|
const candidates = [
|
|
42840
|
-
|
|
42841
|
-
|
|
42942
|
+
join18(root, "todos.extension.json"),
|
|
42943
|
+
join18(root, ".todos", "todos.extension.json")
|
|
42842
42944
|
];
|
|
42843
|
-
const extensionDir =
|
|
42844
|
-
if (
|
|
42945
|
+
const extensionDir = join18(root, ".todos", "extensions");
|
|
42946
|
+
if (existsSync18(extensionDir)) {
|
|
42845
42947
|
for (const entry2 of readdirSync3(extensionDir)) {
|
|
42846
42948
|
if (entry2.startsWith("."))
|
|
42847
42949
|
continue;
|
|
42848
|
-
const full =
|
|
42950
|
+
const full = join18(extensionDir, entry2);
|
|
42849
42951
|
if (statSync8(full).isDirectory() || entry2.endsWith(".json"))
|
|
42850
42952
|
candidates.push(full);
|
|
42851
42953
|
}
|
|
42852
42954
|
}
|
|
42853
|
-
return candidates.filter(
|
|
42955
|
+
return candidates.filter(existsSync18);
|
|
42854
42956
|
}
|
|
42855
42957
|
function discoverLocalExtensions(options = {}) {
|
|
42856
42958
|
const config = loadConfig();
|
|
42857
|
-
const projectPath = options.project_path ?
|
|
42959
|
+
const projectPath = options.project_path ? resolve16(options.project_path) : null;
|
|
42858
42960
|
const configuredSources = [
|
|
42859
42961
|
...config.extension_sources || [],
|
|
42860
42962
|
...projectPath ? config.project_overrides?.[projectPath]?.extension_sources || [] : []
|
|
@@ -42862,7 +42964,7 @@ function discoverLocalExtensions(options = {}) {
|
|
|
42862
42964
|
const sources = Array.from(new Set([
|
|
42863
42965
|
...configuredSources,
|
|
42864
42966
|
...projectExtensionSources(projectPath || undefined)
|
|
42865
|
-
])).map((source2) => projectPath && !source2.startsWith("/") ?
|
|
42967
|
+
])).map((source2) => projectPath && !source2.startsWith("/") ? resolve16(projectPath, source2) : resolve16(source2));
|
|
42866
42968
|
const warnings = [];
|
|
42867
42969
|
const discovered = [];
|
|
42868
42970
|
for (const source2 of sources) {
|
|
@@ -43122,9 +43224,9 @@ __export(exports_policy_packs, {
|
|
|
43122
43224
|
getPolicyPack: () => getPolicyPack,
|
|
43123
43225
|
explainPolicyPack: () => explainPolicyPack
|
|
43124
43226
|
});
|
|
43125
|
-
import { relative as relative4, resolve as
|
|
43227
|
+
import { relative as relative4, resolve as resolve17 } from "path";
|
|
43126
43228
|
function normalizePath3(path) {
|
|
43127
|
-
return
|
|
43229
|
+
return resolve17(path);
|
|
43128
43230
|
}
|
|
43129
43231
|
function unique6(values) {
|
|
43130
43232
|
return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));
|
|
@@ -43179,7 +43281,7 @@ function commandMatches(commands, pattern) {
|
|
|
43179
43281
|
}
|
|
43180
43282
|
function pathMatches(paths, pattern, root) {
|
|
43181
43283
|
return paths.filter((path) => {
|
|
43182
|
-
const candidate = path.startsWith("/") ? path :
|
|
43284
|
+
const candidate = path.startsWith("/") ? path : resolve17(root, path);
|
|
43183
43285
|
if (!isPathInside3(root, candidate))
|
|
43184
43286
|
return matchesPattern3(path, pattern);
|
|
43185
43287
|
return matchesPattern3(path, pattern) || matchesPattern3(relative4(root, candidate), pattern);
|
|
@@ -48923,8 +49025,8 @@ class SqliteTodosTaskManifestBackend {
|
|
|
48923
49025
|
async serialized(run) {
|
|
48924
49026
|
const previous = sqliteTails.get(this.db) ?? Promise.resolve();
|
|
48925
49027
|
let release;
|
|
48926
|
-
const current = new Promise((
|
|
48927
|
-
release =
|
|
49028
|
+
const current = new Promise((resolve18) => {
|
|
49029
|
+
release = resolve18;
|
|
48928
49030
|
});
|
|
48929
49031
|
const tail = previous.then(() => current);
|
|
48930
49032
|
sqliteTails.set(this.db, tail);
|
|
@@ -51267,8 +51369,8 @@ class SqliteTodosTaskSubtreeTransferBackend {
|
|
|
51267
51369
|
async serialized(run) {
|
|
51268
51370
|
const previous = sqliteTails2.get(this.db) ?? Promise.resolve();
|
|
51269
51371
|
let release;
|
|
51270
|
-
const current = new Promise((
|
|
51271
|
-
release =
|
|
51372
|
+
const current = new Promise((resolve18) => {
|
|
51373
|
+
release = resolve18;
|
|
51272
51374
|
});
|
|
51273
51375
|
const tail = previous.then(() => current);
|
|
51274
51376
|
sqliteTails2.set(this.db, tail);
|
|
@@ -52703,8 +52805,8 @@ var exports_doctor = {};
|
|
|
52703
52805
|
__export(exports_doctor, {
|
|
52704
52806
|
runTodosDoctor: () => runTodosDoctor
|
|
52705
52807
|
});
|
|
52706
|
-
import { chmodSync as chmodSync2, copyFileSync as copyFileSync2, existsSync as
|
|
52707
|
-
import { basename as basename7, dirname as dirname8, join as
|
|
52808
|
+
import { chmodSync as chmodSync2, copyFileSync as copyFileSync2, existsSync as existsSync19, mkdirSync as mkdirSync9, statSync as statSync9 } from "fs";
|
|
52809
|
+
import { basename as basename7, dirname as dirname8, join as join19 } from "path";
|
|
52708
52810
|
function tableExists3(db, table) {
|
|
52709
52811
|
return Boolean(db.query("SELECT name FROM sqlite_master WHERE type='table' AND name=?").get(table));
|
|
52710
52812
|
}
|
|
@@ -52798,7 +52900,7 @@ function findMissingProjectRoots(db) {
|
|
|
52798
52900
|
continue;
|
|
52799
52901
|
if (!row.path.startsWith("/"))
|
|
52800
52902
|
continue;
|
|
52801
|
-
if (!
|
|
52903
|
+
if (!existsSync19(row.path))
|
|
52802
52904
|
missing++;
|
|
52803
52905
|
}
|
|
52804
52906
|
return missing;
|
|
@@ -52858,16 +52960,16 @@ function databasePermissionsAreUnsafe(dbPath) {
|
|
|
52858
52960
|
function createBackup(dbPath) {
|
|
52859
52961
|
if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
|
|
52860
52962
|
return;
|
|
52861
|
-
if (!
|
|
52963
|
+
if (!existsSync19(dbPath))
|
|
52862
52964
|
return;
|
|
52863
52965
|
const stamp = now().replace(/[:.]/g, "-");
|
|
52864
|
-
const backupDir =
|
|
52966
|
+
const backupDir = join19(dirname8(dbPath), `${basename7(dbPath)}.backup-${stamp}`);
|
|
52865
52967
|
const files = [];
|
|
52866
52968
|
mkdirSync9(backupDir, { recursive: true });
|
|
52867
52969
|
for (const source2 of [dbPath, `${dbPath}-wal`, `${dbPath}-shm`]) {
|
|
52868
|
-
if (!
|
|
52970
|
+
if (!existsSync19(source2))
|
|
52869
52971
|
continue;
|
|
52870
|
-
const target =
|
|
52972
|
+
const target = join19(backupDir, basename7(source2));
|
|
52871
52973
|
copyFileSync2(source2, target);
|
|
52872
52974
|
files.push(target);
|
|
52873
52975
|
}
|
|
@@ -53126,7 +53228,7 @@ var init_doctor = __esm(() => {
|
|
|
53126
53228
|
});
|
|
53127
53229
|
|
|
53128
53230
|
// src/server/routes.ts
|
|
53129
|
-
import { join as
|
|
53231
|
+
import { join as join20, resolve as resolve18, sep as sep4 } from "path";
|
|
53130
53232
|
function parseFieldsParam(url) {
|
|
53131
53233
|
const fieldsParam = url.searchParams.get("fields");
|
|
53132
53234
|
return fieldsParam ? fieldsParam.split(",").map((f) => f.trim()).filter(Boolean) : undefined;
|
|
@@ -53963,9 +54065,9 @@ function handleStaticFiles(path, method, ctx, json5, serveStaticFile2) {
|
|
|
53963
54065
|
if (!ctx.dashboardExists || method !== "GET" && method !== "HEAD")
|
|
53964
54066
|
return null;
|
|
53965
54067
|
if (path !== "/") {
|
|
53966
|
-
const filePath =
|
|
53967
|
-
const resolvedFile =
|
|
53968
|
-
const resolvedBase =
|
|
54068
|
+
const filePath = join20(ctx.dashboardDir, path);
|
|
54069
|
+
const resolvedFile = resolve18(filePath);
|
|
54070
|
+
const resolvedBase = resolve18(ctx.dashboardDir);
|
|
53969
54071
|
if (!resolvedFile.startsWith(resolvedBase + sep4) && resolvedFile !== resolvedBase) {
|
|
53970
54072
|
return json5({ error: "Forbidden" }, 403);
|
|
53971
54073
|
}
|
|
@@ -53973,7 +54075,7 @@ function handleStaticFiles(path, method, ctx, json5, serveStaticFile2) {
|
|
|
53973
54075
|
if (res2)
|
|
53974
54076
|
return res2;
|
|
53975
54077
|
}
|
|
53976
|
-
const indexPath =
|
|
54078
|
+
const indexPath = join20(ctx.dashboardDir, "index.html");
|
|
53977
54079
|
const res = serveStaticFile2(indexPath);
|
|
53978
54080
|
if (res)
|
|
53979
54081
|
return res;
|
|
@@ -54080,7 +54182,7 @@ class TodosShadowOutbox {
|
|
|
54080
54182
|
const remaining = deadline - Date.now();
|
|
54081
54183
|
if (remaining <= 0)
|
|
54082
54184
|
break;
|
|
54083
|
-
await new Promise((
|
|
54185
|
+
await new Promise((resolve19) => setTimeout(resolve19, Math.min(200, remaining)));
|
|
54084
54186
|
}
|
|
54085
54187
|
}
|
|
54086
54188
|
return this.getStats();
|
|
@@ -60972,8 +61074,8 @@ var exports_mention_resolver = {};
|
|
|
60972
61074
|
__export(exports_mention_resolver, {
|
|
60973
61075
|
resolveMentions: () => resolveMentions
|
|
60974
61076
|
});
|
|
60975
|
-
import { existsSync as
|
|
60976
|
-
import { basename as basename8, isAbsolute, join as
|
|
61077
|
+
import { existsSync as existsSync20, readdirSync as readdirSync4, readFileSync as readFileSync14, statSync as statSync10 } from "fs";
|
|
61078
|
+
import { basename as basename8, isAbsolute, join as join21, relative as relative5, resolve as resolve19, sep as sep5 } from "path";
|
|
60977
61079
|
function blankResolution(parsed) {
|
|
60978
61080
|
return {
|
|
60979
61081
|
input: parsed.input,
|
|
@@ -60996,7 +61098,7 @@ function backlink(kind, key2, label, target = key2) {
|
|
|
60996
61098
|
return { kind, key: key2, label, target };
|
|
60997
61099
|
}
|
|
60998
61100
|
function normalizeWorkspace(workspace) {
|
|
60999
|
-
return
|
|
61101
|
+
return resolve19(workspace || process.cwd());
|
|
61000
61102
|
}
|
|
61001
61103
|
function isInside(root, absolutePath) {
|
|
61002
61104
|
const rel = relative5(root, absolutePath);
|
|
@@ -61064,14 +61166,14 @@ function resolveFile(parsed, workspace) {
|
|
|
61064
61166
|
resolution.warnings.push("path is empty or escapes the workspace");
|
|
61065
61167
|
return resolution;
|
|
61066
61168
|
}
|
|
61067
|
-
const absolutePath =
|
|
61169
|
+
const absolutePath = resolve19(workspace, relPath);
|
|
61068
61170
|
if (!isInside(workspace, absolutePath)) {
|
|
61069
61171
|
resolution.path = relPath;
|
|
61070
61172
|
resolution.warnings.push("path escapes the workspace");
|
|
61071
61173
|
return resolution;
|
|
61072
61174
|
}
|
|
61073
61175
|
resolution.path = relPath;
|
|
61074
|
-
if (!
|
|
61176
|
+
if (!existsSync20(absolutePath)) {
|
|
61075
61177
|
resolution.warnings.push("file does not exist in the local workspace");
|
|
61076
61178
|
return resolution;
|
|
61077
61179
|
}
|
|
@@ -61104,7 +61206,7 @@ function walkSourceFiles(root, current = root, files = []) {
|
|
|
61104
61206
|
if (SKIP_DIRS2.has(entry2.name))
|
|
61105
61207
|
continue;
|
|
61106
61208
|
}
|
|
61107
|
-
const absolutePath =
|
|
61209
|
+
const absolutePath = join21(current, entry2.name);
|
|
61108
61210
|
if (entry2.isDirectory()) {
|
|
61109
61211
|
if (!SKIP_DIRS2.has(entry2.name))
|
|
61110
61212
|
walkSourceFiles(root, absolutePath, files);
|
|
@@ -63920,7 +64022,7 @@ __export(exports_release_compatibility, {
|
|
|
63920
64022
|
LOCAL_RELEASE_COMPATIBILITY_SCHEMA_VERSION: () => LOCAL_RELEASE_COMPATIBILITY_SCHEMA_VERSION
|
|
63921
64023
|
});
|
|
63922
64024
|
import { readFileSync as readFileSync15 } from "fs";
|
|
63923
|
-
import { join as
|
|
64025
|
+
import { join as join22, resolve as resolve20 } from "path";
|
|
63924
64026
|
import { Database as Database3 } from "bun:sqlite";
|
|
63925
64027
|
function pass(id, message, details) {
|
|
63926
64028
|
return { id, status: "passed", message, details };
|
|
@@ -63932,7 +64034,7 @@ function warn(id, message, details) {
|
|
|
63932
64034
|
return { id, status: "warning", message, details };
|
|
63933
64035
|
}
|
|
63934
64036
|
function readPackageJson2(root) {
|
|
63935
|
-
return JSON.parse(readFileSync15(
|
|
64037
|
+
return JSON.parse(readFileSync15(join22(root, "package.json"), "utf8"));
|
|
63936
64038
|
}
|
|
63937
64039
|
function sortedKeys(value) {
|
|
63938
64040
|
return Object.keys(value ?? {}).sort((left, right) => left.localeCompare(right));
|
|
@@ -64028,7 +64130,7 @@ function checkChangelog() {
|
|
|
64028
64130
|
];
|
|
64029
64131
|
}
|
|
64030
64132
|
function createReleaseCompatibilityReport(options = {}) {
|
|
64031
|
-
const root =
|
|
64133
|
+
const root = resolve20(options.root ?? process.cwd());
|
|
64032
64134
|
const packageJson = readPackageJson2(root);
|
|
64033
64135
|
const simulatedLevels = options.simulated_levels ?? defaultSimulationLevels();
|
|
64034
64136
|
const checks = [
|
|
@@ -69903,7 +70005,7 @@ __export(exports_verification_providers, {
|
|
|
69903
70005
|
getVerificationRecord: () => getVerificationRecord,
|
|
69904
70006
|
discoverVerificationProviderCapabilities: () => discoverVerificationProviderCapabilities
|
|
69905
70007
|
});
|
|
69906
|
-
import { existsSync as
|
|
70008
|
+
import { existsSync as existsSync21, readFileSync as readFileSync16 } from "fs";
|
|
69907
70009
|
function normalizeName6(name) {
|
|
69908
70010
|
const normalized = name.trim().toLowerCase();
|
|
69909
70011
|
if (!/^[a-z0-9][a-z0-9_-]{0,63}$/.test(normalized)) {
|
|
@@ -70000,7 +70102,7 @@ function classifyLog(text) {
|
|
|
70000
70102
|
async function sleep3(ms) {
|
|
70001
70103
|
if (ms <= 0)
|
|
70002
70104
|
return;
|
|
70003
|
-
await new Promise((
|
|
70105
|
+
await new Promise((resolve21) => setTimeout(resolve21, ms));
|
|
70004
70106
|
}
|
|
70005
70107
|
async function runCommandProvider(provider, input) {
|
|
70006
70108
|
const commandTemplate = input.command || provider.command;
|
|
@@ -70055,7 +70157,7 @@ Timed out after ${provider.timeout_ms}ms`);
|
|
|
70055
70157
|
};
|
|
70056
70158
|
}
|
|
70057
70159
|
function runCiLogProvider(input) {
|
|
70058
|
-
const text = input.log_text ?? (input.log_path &&
|
|
70160
|
+
const text = input.log_text ?? (input.log_path && existsSync21(input.log_path) ? readFileSync16(input.log_path, "utf-8") : "");
|
|
70059
70161
|
return {
|
|
70060
70162
|
status: classifyLog(text),
|
|
70061
70163
|
attempts: 1,
|
|
@@ -70067,7 +70169,7 @@ function runBrowserProvider(input) {
|
|
|
70067
70169
|
if (!input.artifact_path) {
|
|
70068
70170
|
return { status: "unknown", attempts: 1, exit_code: null, output_summary: "browser provider needs a screenshot or artifact path" };
|
|
70069
70171
|
}
|
|
70070
|
-
if (!
|
|
70172
|
+
if (!existsSync21(input.artifact_path)) {
|
|
70071
70173
|
return { status: "failed", attempts: 1, exit_code: null, output_summary: `artifact not found: ${input.artifact_path}` };
|
|
70072
70174
|
}
|
|
70073
70175
|
return {
|
|
@@ -72359,7 +72461,7 @@ __export(exports_local_backups, {
|
|
|
72359
72461
|
});
|
|
72360
72462
|
import { createHash as createHash16 } from "crypto";
|
|
72361
72463
|
import { readFileSync as readFileSync17, writeFileSync as writeFileSync8 } from "fs";
|
|
72362
|
-
import { dirname as dirname9, resolve as
|
|
72464
|
+
import { dirname as dirname9, resolve as resolve21 } from "path";
|
|
72363
72465
|
import { mkdirSync as mkdirSync10 } from "fs";
|
|
72364
72466
|
function stableJson2(value) {
|
|
72365
72467
|
if (value === null || typeof value !== "object")
|
|
@@ -72461,14 +72563,14 @@ function createLocalBackup(options = {}, db) {
|
|
|
72461
72563
|
return backup;
|
|
72462
72564
|
}
|
|
72463
72565
|
function writeLocalBackupFile(backup, outputPath) {
|
|
72464
|
-
const path =
|
|
72566
|
+
const path = resolve21(outputPath);
|
|
72465
72567
|
mkdirSync10(dirname9(path), { recursive: true });
|
|
72466
72568
|
writeFileSync8(path, `${JSON.stringify(backup, null, 2)}
|
|
72467
72569
|
`);
|
|
72468
72570
|
return path;
|
|
72469
72571
|
}
|
|
72470
72572
|
function readLocalBackupFile(path) {
|
|
72471
|
-
return JSON.parse(readFileSync17(
|
|
72573
|
+
return JSON.parse(readFileSync17(resolve21(path), "utf-8"));
|
|
72472
72574
|
}
|
|
72473
72575
|
function verifyLocalBackup(value, options = {}, db) {
|
|
72474
72576
|
const verifiedAt = options.verified_at ?? now();
|
|
@@ -72665,7 +72767,7 @@ __export(exports_onboarding_fixtures, {
|
|
|
72665
72767
|
TODOS_ONBOARDING_FIXTURE_LIBRARY_VERSION: () => TODOS_ONBOARDING_FIXTURE_LIBRARY_VERSION
|
|
72666
72768
|
});
|
|
72667
72769
|
import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync9 } from "fs";
|
|
72668
|
-
import { join as
|
|
72770
|
+
import { join as join23 } from "path";
|
|
72669
72771
|
function emptyData() {
|
|
72670
72772
|
return {
|
|
72671
72773
|
projects: [],
|
|
@@ -73001,7 +73103,7 @@ function writeOnboardingFixtureFiles(directory) {
|
|
|
73001
73103
|
mkdirSync11(directory, { recursive: true });
|
|
73002
73104
|
const files = [];
|
|
73003
73105
|
for (const fixture of allFixtures()) {
|
|
73004
|
-
const path =
|
|
73106
|
+
const path = join23(directory, `${fixture.summary.name}.bridge.json`);
|
|
73005
73107
|
writeFileSync9(path, `${JSON.stringify(fixture.bundle, null, 2)}
|
|
73006
73108
|
`, "utf-8");
|
|
73007
73109
|
files.push(path);
|
|
@@ -78669,7 +78771,7 @@ Last seen: ${agent.last_seen_at}`
|
|
|
78669
78771
|
`Suggested names: ${suggestions.slice(0, 8).join(", ")}`,
|
|
78670
78772
|
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.",
|
|
78671
78773
|
`
|
|
78672
|
-
To restrict names, configure agent_pool or project_pools in
|
|
78774
|
+
To restrict names, configure agent_pool or project_pools in the todos data home config file (default <data home>/config.json)`
|
|
78673
78775
|
];
|
|
78674
78776
|
return { content: [{ type: "text", text: lines2.join(`
|
|
78675
78777
|
`) }] };
|
|
@@ -79221,16 +79323,16 @@ __export(exports_environment_snapshots, {
|
|
|
79221
79323
|
captureEnvironmentSnapshot: () => captureEnvironmentSnapshot
|
|
79222
79324
|
});
|
|
79223
79325
|
import { createHash as createHash20 } from "crypto";
|
|
79224
|
-
import { existsSync as
|
|
79326
|
+
import { existsSync as existsSync22, readFileSync as readFileSync19, statSync as statSync11 } from "fs";
|
|
79225
79327
|
import { hostname as hostname2, platform, arch } from "os";
|
|
79226
|
-
import { dirname as dirname10, join as
|
|
79328
|
+
import { dirname as dirname10, join as join24, resolve as resolve22 } from "path";
|
|
79227
79329
|
import { tmpdir as tmpdir4 } from "os";
|
|
79228
79330
|
function sha2567(value) {
|
|
79229
79331
|
return createHash20("sha256").update(value).digest("hex");
|
|
79230
79332
|
}
|
|
79231
79333
|
function fileRecord(root, relativePath) {
|
|
79232
|
-
const path =
|
|
79233
|
-
if (!
|
|
79334
|
+
const path = join24(root, relativePath);
|
|
79335
|
+
if (!existsSync22(path))
|
|
79234
79336
|
return null;
|
|
79235
79337
|
const stat = statSync11(path);
|
|
79236
79338
|
if (!stat.isFile())
|
|
@@ -79242,7 +79344,7 @@ function manifestRecord(root, relativePath) {
|
|
|
79242
79344
|
const base = fileRecord(root, relativePath);
|
|
79243
79345
|
if (!base)
|
|
79244
79346
|
return null;
|
|
79245
|
-
const parsed = readJsonFile(
|
|
79347
|
+
const parsed = readJsonFile(join24(root, relativePath));
|
|
79246
79348
|
if (!parsed)
|
|
79247
79349
|
return { ...base, redacted: {} };
|
|
79248
79350
|
const redacted = redactValue({
|
|
@@ -79337,15 +79439,15 @@ function commandEnv(env, includeValues) {
|
|
|
79337
79439
|
function defaultSnapshotDir() {
|
|
79338
79440
|
const dbPath = getDatabasePath();
|
|
79339
79441
|
if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
|
|
79340
|
-
return
|
|
79341
|
-
return
|
|
79442
|
+
return join24(tmpdir4(), "hasna-todos", "environment-snapshots");
|
|
79443
|
+
return join24(dirname10(resolve22(dbPath)), "environment-snapshots");
|
|
79342
79444
|
}
|
|
79343
79445
|
function snapshotWithId(snapshot) {
|
|
79344
79446
|
const digest4 = sha2567(JSON.stringify(snapshot)).slice(0, 24);
|
|
79345
79447
|
return { id: `env_${digest4}`, ...snapshot };
|
|
79346
79448
|
}
|
|
79347
79449
|
function captureEnvironmentSnapshot(input = {}) {
|
|
79348
|
-
const root =
|
|
79450
|
+
const root = resolve22(input.root || process.cwd());
|
|
79349
79451
|
const env = input.env || process.env;
|
|
79350
79452
|
const warnings = [];
|
|
79351
79453
|
const manifests = MANIFEST_FILES.map((file) => manifestRecord(root, file)).filter((file) => Boolean(file));
|
|
@@ -79385,13 +79487,13 @@ function captureEnvironmentSnapshot(input = {}) {
|
|
|
79385
79487
|
});
|
|
79386
79488
|
}
|
|
79387
79489
|
function writeEnvironmentSnapshot(snapshot, outputPath) {
|
|
79388
|
-
const path = outputPath ?
|
|
79490
|
+
const path = outputPath ? resolve22(outputPath) : join24(defaultSnapshotDir(), `${snapshot.id}.json`);
|
|
79389
79491
|
ensureDir(dirname10(path));
|
|
79390
79492
|
writeJsonFile(path, snapshot);
|
|
79391
79493
|
return path;
|
|
79392
79494
|
}
|
|
79393
79495
|
function readEnvironmentSnapshot(path) {
|
|
79394
|
-
const snapshot = readJsonFile(
|
|
79496
|
+
const snapshot = readJsonFile(resolve22(path));
|
|
79395
79497
|
if (!snapshot || snapshot.schema_version !== 1 || typeof snapshot.id !== "string") {
|
|
79396
79498
|
throw new Error(`Invalid environment snapshot: ${path}`);
|
|
79397
79499
|
}
|
|
@@ -80102,8 +80204,8 @@ class SqlitePrGroupLedgerPersistence {
|
|
|
80102
80204
|
async transaction(fn) {
|
|
80103
80205
|
const previous = sqliteTransactionTails2.get(this.db) ?? Promise.resolve();
|
|
80104
80206
|
let release;
|
|
80105
|
-
const current = new Promise((
|
|
80106
|
-
release =
|
|
80207
|
+
const current = new Promise((resolve23) => {
|
|
80208
|
+
release = resolve23;
|
|
80107
80209
|
});
|
|
80108
80210
|
sqliteTransactionTails2.set(this.db, current);
|
|
80109
80211
|
await previous;
|
|
@@ -80201,27 +80303,27 @@ __export(exports_serve, {
|
|
|
80201
80303
|
SECURITY_HEADERS: () => SECURITY_HEADERS,
|
|
80202
80304
|
MIME_TYPES: () => MIME_TYPES
|
|
80203
80305
|
});
|
|
80204
|
-
import { existsSync as
|
|
80205
|
-
import { join as
|
|
80306
|
+
import { existsSync as existsSync23 } from "fs";
|
|
80307
|
+
import { join as join25, dirname as dirname11, extname } from "path";
|
|
80206
80308
|
import { fileURLToPath } from "url";
|
|
80207
80309
|
function resolveDashboardDir() {
|
|
80208
80310
|
const candidates = [];
|
|
80209
80311
|
try {
|
|
80210
80312
|
const scriptDir = dirname11(fileURLToPath(import.meta.url));
|
|
80211
|
-
candidates.push(
|
|
80212
|
-
candidates.push(
|
|
80313
|
+
candidates.push(join25(scriptDir, "..", "dashboard", "dist"));
|
|
80314
|
+
candidates.push(join25(scriptDir, "..", "..", "dashboard", "dist"));
|
|
80213
80315
|
} catch {}
|
|
80214
80316
|
if (process.argv[1]) {
|
|
80215
80317
|
const mainDir = dirname11(process.argv[1]);
|
|
80216
|
-
candidates.push(
|
|
80217
|
-
candidates.push(
|
|
80318
|
+
candidates.push(join25(mainDir, "..", "dashboard", "dist"));
|
|
80319
|
+
candidates.push(join25(mainDir, "..", "..", "dashboard", "dist"));
|
|
80218
80320
|
}
|
|
80219
|
-
candidates.push(
|
|
80321
|
+
candidates.push(join25(process.cwd(), "dashboard", "dist"));
|
|
80220
80322
|
for (const candidate of candidates) {
|
|
80221
|
-
if (
|
|
80323
|
+
if (existsSync23(candidate))
|
|
80222
80324
|
return candidate;
|
|
80223
80325
|
}
|
|
80224
|
-
return
|
|
80326
|
+
return join25(process.cwd(), "dashboard", "dist");
|
|
80225
80327
|
}
|
|
80226
80328
|
function getProvidedApiKey(req) {
|
|
80227
80329
|
const headerKey = req.headers.get("x-api-key");
|
|
@@ -80293,7 +80395,7 @@ function json4(data, status3 = 200, headers) {
|
|
|
80293
80395
|
});
|
|
80294
80396
|
}
|
|
80295
80397
|
function serveStaticFile(filePath) {
|
|
80296
|
-
if (!
|
|
80398
|
+
if (!existsSync23(filePath))
|
|
80297
80399
|
return null;
|
|
80298
80400
|
const ext = extname(filePath);
|
|
80299
80401
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
@@ -80394,7 +80496,7 @@ data: ${data}
|
|
|
80394
80496
|
filteredSseClients.delete(client);
|
|
80395
80497
|
}
|
|
80396
80498
|
const dashboardDir = resolveDashboardDir();
|
|
80397
|
-
const dashboardExists =
|
|
80499
|
+
const dashboardExists = existsSync23(dashboardDir);
|
|
80398
80500
|
if (!dashboardExists) {
|
|
80399
80501
|
console.error(`
|
|
80400
80502
|
Dashboard not found at: ${dashboardDir}`);
|
|
@@ -82281,12 +82383,12 @@ __export(exports_config_serve_commands, {
|
|
|
82281
82383
|
registerConfigServeCommands: () => registerConfigServeCommands
|
|
82282
82384
|
});
|
|
82283
82385
|
import chalk7 from "chalk";
|
|
82284
|
-
import { existsSync as
|
|
82285
|
-
import { dirname as dirname12, join as
|
|
82386
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync12, readFileSync as readFileSync20, writeFileSync as writeFileSync10 } from "fs";
|
|
82387
|
+
import { dirname as dirname12, join as join26 } from "path";
|
|
82286
82388
|
function registerConfigServeCommands(program2) {
|
|
82287
82389
|
program2.command("config").description("View or update configuration").option("--get <key>", "Get a config value").option("--set <key=value>", "Set a config value (e.g. completion_guard.enabled=true)").action((opts) => {
|
|
82288
82390
|
const globalOpts = program2.opts();
|
|
82289
|
-
const configPath =
|
|
82391
|
+
const configPath = join26(getTodosGlobalDir(), "config.json");
|
|
82290
82392
|
if (opts.get) {
|
|
82291
82393
|
const config2 = loadConfig();
|
|
82292
82394
|
const keys = opts.get.split(".");
|
|
@@ -82323,7 +82425,7 @@ function registerConfigServeCommands(program2) {
|
|
|
82323
82425
|
}
|
|
82324
82426
|
obj[keys[keys.length - 1]] = parsedValue;
|
|
82325
82427
|
const dir = dirname12(configPath);
|
|
82326
|
-
if (!
|
|
82428
|
+
if (!existsSync24(dir))
|
|
82327
82429
|
mkdirSync12(dir, { recursive: true });
|
|
82328
82430
|
writeFileSync10(configPath, JSON.stringify(config2, null, 2));
|
|
82329
82431
|
if (globalOpts.json) {
|
|
@@ -83503,8 +83605,8 @@ __export(exports_routing_doctor, {
|
|
|
83503
83605
|
classifyTaskRouting: () => classifyTaskRouting,
|
|
83504
83606
|
TODOS_ROUTING_DOCTOR_SCHEMA_VERSION: () => TODOS_ROUTING_DOCTOR_SCHEMA_VERSION
|
|
83505
83607
|
});
|
|
83506
|
-
import { copyFileSync as copyFileSync3, existsSync as
|
|
83507
|
-
import { basename as basename9, dirname as dirname13, join as
|
|
83608
|
+
import { copyFileSync as copyFileSync3, existsSync as existsSync25, mkdirSync as mkdirSync13, writeFileSync as writeFileSync11 } from "fs";
|
|
83609
|
+
import { basename as basename9, dirname as dirname13, join as join27 } from "path";
|
|
83508
83610
|
function normalizePath5(path) {
|
|
83509
83611
|
if (!path)
|
|
83510
83612
|
return null;
|
|
@@ -83806,16 +83908,16 @@ function evaluateTaskRouting(ctx) {
|
|
|
83806
83908
|
function createBackup2(dbPath, generatedAt) {
|
|
83807
83909
|
if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
|
|
83808
83910
|
return;
|
|
83809
|
-
if (!
|
|
83911
|
+
if (!existsSync25(dbPath))
|
|
83810
83912
|
return;
|
|
83811
83913
|
const stamp = generatedAt.replace(/[:.]/g, "-");
|
|
83812
|
-
const backupDir =
|
|
83914
|
+
const backupDir = join27(dirname13(dbPath), `${basename9(dbPath)}.routing-doctor-backup-${stamp}`);
|
|
83813
83915
|
const files = [];
|
|
83814
83916
|
mkdirSync13(backupDir, { recursive: true });
|
|
83815
83917
|
for (const source3 of [dbPath, `${dbPath}-wal`, `${dbPath}-shm`]) {
|
|
83816
|
-
if (!
|
|
83918
|
+
if (!existsSync25(source3))
|
|
83817
83919
|
continue;
|
|
83818
|
-
const target =
|
|
83920
|
+
const target = join27(backupDir, basename9(source3));
|
|
83819
83921
|
copyFileSync3(source3, target);
|
|
83820
83922
|
files.push(target);
|
|
83821
83923
|
}
|
|
@@ -83919,7 +84021,7 @@ function runRoutingDoctor(options = {}) {
|
|
|
83919
84021
|
}
|
|
83920
84022
|
const applied = repairs.filter((r) => r.applied);
|
|
83921
84023
|
if (applied.length > 0) {
|
|
83922
|
-
const undoPath = options.undoRecordPath ??
|
|
84024
|
+
const undoPath = options.undoRecordPath ?? join27(process.cwd(), `todos-routing-doctor-undo-${generatedAt.replace(/[:.]/g, "-")}.json`);
|
|
83923
84025
|
const undoRecord = {
|
|
83924
84026
|
schema_version: TODOS_ROUTING_DOCTOR_SCHEMA_VERSION,
|
|
83925
84027
|
purpose: "Undo record for routing-doctor --apply. Restore each field with the prior value below.",
|
|
@@ -84018,10 +84120,10 @@ __export(exports_task_route_sources, {
|
|
|
84018
84120
|
});
|
|
84019
84121
|
import { Database as Database4 } from "bun:sqlite";
|
|
84020
84122
|
import { createHash as createHash21 } from "crypto";
|
|
84021
|
-
import { existsSync as
|
|
84022
|
-
import { basename as basename10, dirname as dirname14, join as
|
|
84123
|
+
import { existsSync as existsSync26, readdirSync as readdirSync5, statSync as statSync12 } from "fs";
|
|
84124
|
+
import { basename as basename10, dirname as dirname14, join as join28, resolve as resolve23 } from "path";
|
|
84023
84125
|
function normalizePath6(input) {
|
|
84024
|
-
return
|
|
84126
|
+
return resolve23(input);
|
|
84025
84127
|
}
|
|
84026
84128
|
function sourceStoreId(sourceDbPath) {
|
|
84027
84129
|
const digest4 = createHash21("sha256").update(sourceDbPath).digest("hex").slice(0, 16);
|
|
@@ -84083,8 +84185,8 @@ function discoverStoresUnderRoot(sourceRoot) {
|
|
|
84083
84185
|
const rootPath = normalizePath6(sourceRoot);
|
|
84084
84186
|
const errors2 = [];
|
|
84085
84187
|
const stores = [];
|
|
84086
|
-
if (!
|
|
84087
|
-
const ref = createStoreRef(
|
|
84188
|
+
if (!existsSync26(rootPath)) {
|
|
84189
|
+
const ref = createStoreRef(join28(rootPath, TODO_STORE_RELATIVE_PATH));
|
|
84088
84190
|
errors2.push({
|
|
84089
84191
|
...ref,
|
|
84090
84192
|
code: "SOURCE_ROOT_MISSING",
|
|
@@ -84096,7 +84198,7 @@ function discoverStoresUnderRoot(sourceRoot) {
|
|
|
84096
84198
|
try {
|
|
84097
84199
|
rootStat = statSync12(rootPath);
|
|
84098
84200
|
} catch (error2) {
|
|
84099
|
-
const ref = createStoreRef(
|
|
84201
|
+
const ref = createStoreRef(join28(rootPath, TODO_STORE_RELATIVE_PATH));
|
|
84100
84202
|
errors2.push({
|
|
84101
84203
|
...ref,
|
|
84102
84204
|
code: "SOURCE_ROOT_UNREADABLE",
|
|
@@ -84109,8 +84211,8 @@ function discoverStoresUnderRoot(sourceRoot) {
|
|
|
84109
84211
|
return { stores, errors: errors2 };
|
|
84110
84212
|
}
|
|
84111
84213
|
function scanDirectory(dir, depth) {
|
|
84112
|
-
const candidate =
|
|
84113
|
-
if (
|
|
84214
|
+
const candidate = join28(dir, TODO_STORE_RELATIVE_PATH);
|
|
84215
|
+
if (existsSync26(candidate)) {
|
|
84114
84216
|
stores.push(createStoreRef(candidate));
|
|
84115
84217
|
}
|
|
84116
84218
|
if (depth >= ROOT_SCAN_MAX_DEPTH)
|
|
@@ -84130,7 +84232,7 @@ function discoverStoresUnderRoot(sourceRoot) {
|
|
|
84130
84232
|
for (const entry2 of entries) {
|
|
84131
84233
|
if (!entry2.isDirectory() || SKIPPED_SCAN_DIRS.has(entry2.name))
|
|
84132
84234
|
continue;
|
|
84133
|
-
scanDirectory(
|
|
84235
|
+
scanDirectory(join28(dir, entry2.name), depth + 1);
|
|
84134
84236
|
}
|
|
84135
84237
|
}
|
|
84136
84238
|
scanDirectory(rootPath, 0);
|
|
@@ -84156,7 +84258,7 @@ function collectStoreRefs(input) {
|
|
|
84156
84258
|
};
|
|
84157
84259
|
}
|
|
84158
84260
|
function openReadonlyStore(ref) {
|
|
84159
|
-
if (!
|
|
84261
|
+
if (!existsSync26(ref.source_db_path)) {
|
|
84160
84262
|
throw Object.assign(new Error(`Store does not exist: ${ref.source_db_path}`), { code: "STORE_MISSING" });
|
|
84161
84263
|
}
|
|
84162
84264
|
return new Database4(ref.source_db_path, { readonly: true, create: false });
|
|
@@ -84330,7 +84432,7 @@ var init_task_route_sources = __esm(() => {
|
|
|
84330
84432
|
init_task_crud();
|
|
84331
84433
|
init_redaction();
|
|
84332
84434
|
init_task_routing();
|
|
84333
|
-
TODO_STORE_RELATIVE_PATH =
|
|
84435
|
+
TODO_STORE_RELATIVE_PATH = join28(".hasna", "todos", "todos.db");
|
|
84334
84436
|
SKIPPED_SCAN_DIRS = new Set([
|
|
84335
84437
|
".git",
|
|
84336
84438
|
".hg",
|
|
@@ -85301,9 +85403,14 @@ Blocked:`));
|
|
|
85301
85403
|
const globalOpts = program2.opts();
|
|
85302
85404
|
const json7 = opts.json || globalOpts.json;
|
|
85303
85405
|
const filters = {};
|
|
85304
|
-
|
|
85305
|
-
|
|
85406
|
+
const projectRef = opts.project ?? globalOpts.project;
|
|
85407
|
+
if (typeof projectRef === "string" && projectRef.trim() === "") {
|
|
85408
|
+
handleError(new Error("--project requires a non-empty project reference"));
|
|
85409
|
+
}
|
|
85306
85410
|
const cloud = getTodosCloudClient();
|
|
85411
|
+
if (projectRef) {
|
|
85412
|
+
filters.project_id = cloud ? await cloudResolveProjectRef(cloud, projectRef) : resolveExplicitProject(projectRef).id;
|
|
85413
|
+
}
|
|
85307
85414
|
const work = cloud ? await cloudActiveWork(cloud, Object.keys(filters).length ? filters : {}) : getActiveWork(Object.keys(filters).length ? filters : undefined, getDatabase());
|
|
85308
85415
|
if (json7) {
|
|
85309
85416
|
console.log(JSON.stringify(work, null, 2));
|
|
@@ -85869,9 +85976,9 @@ Findings`));
|
|
|
85869
85976
|
const db = getDatabase();
|
|
85870
85977
|
const row = db.query("SELECT COUNT(*) as count FROM tasks").get();
|
|
85871
85978
|
const { statSync: statSync13 } = await import("fs");
|
|
85872
|
-
const { join:
|
|
85873
|
-
const {
|
|
85874
|
-
const dbPath = process.env["HASNA_TODOS_DB_PATH"] || process.env["TODOS_DB_PATH"] ||
|
|
85979
|
+
const { join: join29 } = await import("path");
|
|
85980
|
+
const { getTodosGlobalDir: getTodosGlobalDir2 } = await Promise.resolve().then(() => (init_sync_utils(), exports_sync_utils));
|
|
85981
|
+
const dbPath = process.env["HASNA_TODOS_DB_PATH"] || process.env["TODOS_DB_PATH"] || join29(getTodosGlobalDir2(), "todos.db");
|
|
85875
85982
|
let size = "unknown";
|
|
85876
85983
|
try {
|
|
85877
85984
|
size = `${(statSync13(dbPath).size / 1024 / 1024).toFixed(1)} MB`;
|
|
@@ -88029,21 +88136,21 @@ __export(exports_mcp_hooks_commands, {
|
|
|
88029
88136
|
});
|
|
88030
88137
|
import chalk10 from "chalk";
|
|
88031
88138
|
import { execSync as execSync3 } from "child_process";
|
|
88032
|
-
import { existsSync as
|
|
88033
|
-
import { dirname as dirname15, join as
|
|
88139
|
+
import { existsSync as existsSync27, readFileSync as readFileSync22, writeFileSync as writeFileSync13, mkdirSync as mkdirSync14, chmodSync as chmodSync3 } from "fs";
|
|
88140
|
+
import { dirname as dirname15, join as join29 } from "path";
|
|
88034
88141
|
function getMcpBinaryPath() {
|
|
88035
88142
|
try {
|
|
88036
88143
|
const p = execSync3("which todos-mcp", { encoding: "utf-8" }).trim();
|
|
88037
88144
|
if (p)
|
|
88038
88145
|
return p;
|
|
88039
88146
|
} catch {}
|
|
88040
|
-
const bunBin =
|
|
88041
|
-
if (
|
|
88147
|
+
const bunBin = join29(HOME2, ".bun", "bin", "todos-mcp");
|
|
88148
|
+
if (existsSync27(bunBin))
|
|
88042
88149
|
return bunBin;
|
|
88043
88150
|
return "todos-mcp";
|
|
88044
88151
|
}
|
|
88045
88152
|
function readJsonFile2(path) {
|
|
88046
|
-
if (!
|
|
88153
|
+
if (!existsSync27(path))
|
|
88047
88154
|
return {};
|
|
88048
88155
|
try {
|
|
88049
88156
|
return JSON.parse(readFileSync22(path, "utf-8"));
|
|
@@ -88053,19 +88160,19 @@ function readJsonFile2(path) {
|
|
|
88053
88160
|
}
|
|
88054
88161
|
function writeJsonFile2(path, data) {
|
|
88055
88162
|
const dir = dirname15(path);
|
|
88056
|
-
if (!
|
|
88163
|
+
if (!existsSync27(dir))
|
|
88057
88164
|
mkdirSync14(dir, { recursive: true });
|
|
88058
88165
|
writeFileSync13(path, JSON.stringify(data, null, 2) + `
|
|
88059
88166
|
`);
|
|
88060
88167
|
}
|
|
88061
88168
|
function readTomlFile(path) {
|
|
88062
|
-
if (!
|
|
88169
|
+
if (!existsSync27(path))
|
|
88063
88170
|
return "";
|
|
88064
88171
|
return readFileSync22(path, "utf-8");
|
|
88065
88172
|
}
|
|
88066
88173
|
function writeTomlFile(path, content) {
|
|
88067
88174
|
const dir = dirname15(path);
|
|
88068
|
-
if (!
|
|
88175
|
+
if (!existsSync27(dir))
|
|
88069
88176
|
mkdirSync14(dir, { recursive: true });
|
|
88070
88177
|
writeFileSync13(path, content);
|
|
88071
88178
|
}
|
|
@@ -88130,7 +88237,7 @@ function unregisterClaude(_global) {
|
|
|
88130
88237
|
}
|
|
88131
88238
|
}
|
|
88132
88239
|
function registerCodex(binPath) {
|
|
88133
|
-
const configPath =
|
|
88240
|
+
const configPath = join29(HOME2, ".codex", "config.toml");
|
|
88134
88241
|
let content = readTomlFile(configPath);
|
|
88135
88242
|
content = removeTomlBlock(content, "mcp_servers.todos");
|
|
88136
88243
|
const block = `
|
|
@@ -88144,7 +88251,7 @@ args = ["--stdio"]
|
|
|
88144
88251
|
console.log(chalk10.green(`Codex CLI: registered in ${configPath}`));
|
|
88145
88252
|
}
|
|
88146
88253
|
function unregisterCodex() {
|
|
88147
|
-
const configPath =
|
|
88254
|
+
const configPath = join29(HOME2, ".codex", "config.toml");
|
|
88148
88255
|
let content = readTomlFile(configPath);
|
|
88149
88256
|
if (!content.includes("[mcp_servers.todos]")) {
|
|
88150
88257
|
console.log(chalk10.dim(`Codex CLI: todos not found in ${configPath}`));
|
|
@@ -88156,7 +88263,7 @@ function unregisterCodex() {
|
|
|
88156
88263
|
console.log(chalk10.green(`Codex CLI: unregistered from ${configPath}`));
|
|
88157
88264
|
}
|
|
88158
88265
|
function registerGemini(binPath) {
|
|
88159
|
-
const configPath =
|
|
88266
|
+
const configPath = join29(HOME2, ".gemini", "settings.json");
|
|
88160
88267
|
const config = readJsonFile2(configPath);
|
|
88161
88268
|
if (!config["mcpServers"]) {
|
|
88162
88269
|
config["mcpServers"] = {};
|
|
@@ -88170,7 +88277,7 @@ function registerGemini(binPath) {
|
|
|
88170
88277
|
console.log(chalk10.green(`Gemini CLI: registered in ${configPath}`));
|
|
88171
88278
|
}
|
|
88172
88279
|
function unregisterGemini() {
|
|
88173
|
-
const configPath =
|
|
88280
|
+
const configPath = join29(HOME2, ".gemini", "settings.json");
|
|
88174
88281
|
const config = readJsonFile2(configPath);
|
|
88175
88282
|
const servers = config["mcpServers"];
|
|
88176
88283
|
if (!servers || !("todos" in servers)) {
|
|
@@ -88204,7 +88311,7 @@ function unregisterTakumi(global) {
|
|
|
88204
88311
|
}
|
|
88205
88312
|
}
|
|
88206
88313
|
function cursorConfigPath(global) {
|
|
88207
|
-
return global ?
|
|
88314
|
+
return global ? join29(HOME2, ".cursor", "mcp.json") : join29(process.cwd(), ".cursor", "mcp.json");
|
|
88208
88315
|
}
|
|
88209
88316
|
function registerCursor(binPath, global) {
|
|
88210
88317
|
const configPath = cursorConfigPath(global);
|
|
@@ -88290,8 +88397,8 @@ function registerMcpHooksCommands(program2) {
|
|
|
88290
88397
|
if (p)
|
|
88291
88398
|
todosBin = p;
|
|
88292
88399
|
} catch {}
|
|
88293
|
-
const hooksDir =
|
|
88294
|
-
if (!
|
|
88400
|
+
const hooksDir = join29(process.cwd(), ".claude", "hooks");
|
|
88401
|
+
if (!existsSync27(hooksDir))
|
|
88295
88402
|
mkdirSync14(hooksDir, { recursive: true });
|
|
88296
88403
|
const hookScript = `#!/usr/bin/env bash
|
|
88297
88404
|
# Auto-generated by: todos hooks install
|
|
@@ -88316,11 +88423,11 @@ esac
|
|
|
88316
88423
|
|
|
88317
88424
|
exit 0
|
|
88318
88425
|
`;
|
|
88319
|
-
const hookPath =
|
|
88426
|
+
const hookPath = join29(hooksDir, "todos-sync.sh");
|
|
88320
88427
|
writeFileSync13(hookPath, hookScript);
|
|
88321
88428
|
execSync3(`chmod +x "${hookPath}"`);
|
|
88322
88429
|
console.log(chalk10.green(`Hook script created: ${hookPath}`));
|
|
88323
|
-
const settingsPath =
|
|
88430
|
+
const settingsPath = join29(process.cwd(), ".claude", "settings.json");
|
|
88324
88431
|
const settings = readJsonFile2(settingsPath);
|
|
88325
88432
|
if (!settings["hooks"]) {
|
|
88326
88433
|
settings["hooks"] = {};
|
|
@@ -89251,7 +89358,7 @@ Artifacts:`));
|
|
|
89251
89358
|
const gitDir = execSync3("git rev-parse --git-dir", { encoding: "utf-8" }).trim();
|
|
89252
89359
|
const hookPath = `${gitDir}/hooks/post-commit`;
|
|
89253
89360
|
const marker = "# todos-auto-link";
|
|
89254
|
-
if (
|
|
89361
|
+
if (existsSync27(hookPath)) {
|
|
89255
89362
|
const existing = readFileSync22(hookPath, "utf-8");
|
|
89256
89363
|
if (existing.includes(marker)) {
|
|
89257
89364
|
console.log(chalk10.yellow("Hook already installed."));
|
|
@@ -89278,7 +89385,7 @@ $(dirname "$0")/../../scripts/post-commit-hook.sh
|
|
|
89278
89385
|
const gitDir = execSync3("git rev-parse --git-dir", { encoding: "utf-8" }).trim();
|
|
89279
89386
|
const hookPath = `${gitDir}/hooks/post-commit`;
|
|
89280
89387
|
const marker = "# todos-auto-link";
|
|
89281
|
-
if (!
|
|
89388
|
+
if (!existsSync27(hookPath)) {
|
|
89282
89389
|
console.log(chalk10.dim("No post-commit hook found."));
|
|
89283
89390
|
return;
|
|
89284
89391
|
}
|
|
@@ -89534,10 +89641,10 @@ var init_delegation_brief = () => {};
|
|
|
89534
89641
|
|
|
89535
89642
|
// src/lib/delegation-policy.ts
|
|
89536
89643
|
import { readFileSync as readFileSync23 } from "fs";
|
|
89537
|
-
import { homedir as
|
|
89538
|
-
import { join as
|
|
89644
|
+
import { homedir as homedir6 } from "os";
|
|
89645
|
+
import { join as join30 } from "path";
|
|
89539
89646
|
function defaultDelegationEmbargoPath() {
|
|
89540
|
-
return process.env["TODOS_DELEGATION_EMBARGO_PATH"] ||
|
|
89647
|
+
return process.env["TODOS_DELEGATION_EMBARGO_PATH"] || join30(homedir6(), ".hasna", "identities", "delegation-embargo.json");
|
|
89541
89648
|
}
|
|
89542
89649
|
function loadDelegationEmbargo(path = defaultDelegationEmbargoPath()) {
|
|
89543
89650
|
try {
|
|
@@ -89882,7 +89989,7 @@ import chalk13 from "chalk";
|
|
|
89882
89989
|
import { execSync as execSync4 } from "child_process";
|
|
89883
89990
|
import { readFileSync as readFileSync25, unlinkSync as unlinkSync3, writeFileSync as writeFileSync14 } from "fs";
|
|
89884
89991
|
import { tmpdir as tmpdir5 } from "os";
|
|
89885
|
-
import { join as
|
|
89992
|
+
import { join as join31 } from "path";
|
|
89886
89993
|
function getOrCreateLocalMachineName() {
|
|
89887
89994
|
return process.env["TODOS_MACHINE_NAME"] || __require("os").hostname() || "unknown";
|
|
89888
89995
|
}
|
|
@@ -89920,7 +90027,7 @@ function remoteTempPath(sshAddress) {
|
|
|
89920
90027
|
}
|
|
89921
90028
|
function readRemoteBridgeBundle(sshAddress) {
|
|
89922
90029
|
const remotePath = remoteTempPath(sshAddress);
|
|
89923
|
-
const localPath =
|
|
90030
|
+
const localPath = join31(tmpdir5(), `todos-bridge-pull-${uuid()}.json`);
|
|
89924
90031
|
try {
|
|
89925
90032
|
runSsh(sshAddress, `todos export --format bridge --allow-plaintext-sensitive --output ${shellQuote(remotePath)}`, 120000);
|
|
89926
90033
|
scpFromRemote(sshAddress, remotePath, localPath);
|
|
@@ -89935,7 +90042,7 @@ function readRemoteBridgeBundle(sshAddress) {
|
|
|
89935
90042
|
}
|
|
89936
90043
|
}
|
|
89937
90044
|
function writeLocalBridgeBundle() {
|
|
89938
|
-
const localPath =
|
|
90045
|
+
const localPath = join31(tmpdir5(), `todos-bridge-push-${uuid()}.json`);
|
|
89939
90046
|
writeFileSync14(localPath, JSON.stringify(createLocalBridgeBundle(), null, 2));
|
|
89940
90047
|
return localPath;
|
|
89941
90048
|
}
|
|
@@ -90994,7 +91101,7 @@ __export(exports_onboarding_commands, {
|
|
|
90994
91101
|
registerOnboardingCommands: () => registerOnboardingCommands
|
|
90995
91102
|
});
|
|
90996
91103
|
import chalk20 from "chalk";
|
|
90997
|
-
import { resolve as
|
|
91104
|
+
import { resolve as resolve24 } from "path";
|
|
90998
91105
|
function registerOnboardingCommands(program2) {
|
|
90999
91106
|
program2.command("onboarding").alias("demo-fixtures").description("List, show, write, or import bundled local onboarding fixtures").option("--show <name>", "Show one fixture bridge bundle as JSON").option("--write <dir>", "Write all bundled fixture bridge bundles to a directory").option("--import <name>", "Dry-run or apply an onboarding fixture import").option("--apply", "Apply an onboarding fixture import. Defaults to dry-run.").option("--resolve-conflicts", "Safely merge existing local tasks while preserving divergent fields").action(async (opts) => {
|
|
91000
91107
|
const globalOpts = program2.opts();
|
|
@@ -91010,7 +91117,7 @@ function registerOnboardingCommands(program2) {
|
|
|
91010
91117
|
return;
|
|
91011
91118
|
}
|
|
91012
91119
|
if (opts.write) {
|
|
91013
|
-
const result = writeOnboardingFixtureFiles2(
|
|
91120
|
+
const result = writeOnboardingFixtureFiles2(resolve24(opts.write));
|
|
91014
91121
|
if (globalOpts.json) {
|
|
91015
91122
|
output(result, true);
|
|
91016
91123
|
return;
|
|
@@ -94511,7 +94618,7 @@ __export(exports_sdk_integration_fixtures, {
|
|
|
94511
94618
|
TODOS_SDK_INTEGRATION_FIXTURE_GENERATED_AT: () => TODOS_SDK_INTEGRATION_FIXTURE_GENERATED_AT
|
|
94512
94619
|
});
|
|
94513
94620
|
import { mkdirSync as mkdirSync15, writeFileSync as writeFileSync15 } from "fs";
|
|
94514
|
-
import { join as
|
|
94621
|
+
import { join as join32 } from "path";
|
|
94515
94622
|
function source5(version) {
|
|
94516
94623
|
return {
|
|
94517
94624
|
packageName: "@hasna/todos",
|
|
@@ -94618,7 +94725,7 @@ function writeSdkIntegrationFixtures(directory, options = {}) {
|
|
|
94618
94725
|
];
|
|
94619
94726
|
const written = [];
|
|
94620
94727
|
for (const [name, payload] of files) {
|
|
94621
|
-
const file =
|
|
94728
|
+
const file = join32(directory, name);
|
|
94622
94729
|
writeFileSync15(file, `${JSON.stringify(payload, null, 2)}
|
|
94623
94730
|
`, "utf-8");
|
|
94624
94731
|
written.push(file);
|
|
@@ -94642,7 +94749,7 @@ __export(exports_sdk_fixture_commands, {
|
|
|
94642
94749
|
registerSdkFixtureCommands: () => registerSdkFixtureCommands
|
|
94643
94750
|
});
|
|
94644
94751
|
import chalk22 from "chalk";
|
|
94645
|
-
import { resolve as
|
|
94752
|
+
import { resolve as resolve25 } from "path";
|
|
94646
94753
|
function registerSdkFixtureCommands(program2) {
|
|
94647
94754
|
program2.command("sdk-fixtures").description("List, show, or write local SDK integration fixtures").option("--show", "Print the full fixture pack JSON").option("--write <dir>", "Write fixture pack, bridge fixture, contract snapshots, and example index to a directory").action(async (opts) => {
|
|
94648
94755
|
const globalOpts = program2.opts();
|
|
@@ -94653,7 +94760,7 @@ function registerSdkFixtureCommands(program2) {
|
|
|
94653
94760
|
writeSdkIntegrationFixtures: writeSdkIntegrationFixtures2
|
|
94654
94761
|
} = await Promise.resolve().then(() => (init_sdk_integration_fixtures(), exports_sdk_integration_fixtures));
|
|
94655
94762
|
if (opts.write) {
|
|
94656
|
-
const result = writeSdkIntegrationFixtures2(
|
|
94763
|
+
const result = writeSdkIntegrationFixtures2(resolve25(opts.write));
|
|
94657
94764
|
if (globalOpts.json) {
|
|
94658
94765
|
console.log(JSON.stringify(result));
|
|
94659
94766
|
return;
|
|
@@ -95472,7 +95579,7 @@ __export(exports_local_backup_commands, {
|
|
|
95472
95579
|
registerLocalBackupCommands: () => registerLocalBackupCommands
|
|
95473
95580
|
});
|
|
95474
95581
|
import chalk28 from "chalk";
|
|
95475
|
-
import { resolve as
|
|
95582
|
+
import { resolve as resolve26 } from "path";
|
|
95476
95583
|
function globalOptions8(program2) {
|
|
95477
95584
|
const command = program2;
|
|
95478
95585
|
return command.optsWithGlobals?.() ?? program2.opts();
|
|
@@ -95494,10 +95601,10 @@ function registerLocalBackupCommands(program2) {
|
|
|
95494
95601
|
const projectId = opts.projectId ?? autoProject(globalOpts);
|
|
95495
95602
|
const backupBundle = createLocalBackup2({
|
|
95496
95603
|
project_id: projectId,
|
|
95497
|
-
output_path: opts.output ?
|
|
95604
|
+
output_path: opts.output ? resolve26(opts.output) : undefined
|
|
95498
95605
|
});
|
|
95499
95606
|
const result = {
|
|
95500
|
-
output_path: opts.output ?
|
|
95607
|
+
output_path: opts.output ? resolve26(opts.output) : null,
|
|
95501
95608
|
backup: backupBundle
|
|
95502
95609
|
};
|
|
95503
95610
|
if (opts.json || globalOpts.json) {
|
|
@@ -95668,8 +95775,8 @@ class TodosShadowMirror {
|
|
|
95668
95775
|
async flush() {
|
|
95669
95776
|
if (this.idle())
|
|
95670
95777
|
return;
|
|
95671
|
-
await new Promise((
|
|
95672
|
-
this.idleResolvers.push(
|
|
95778
|
+
await new Promise((resolve27) => {
|
|
95779
|
+
this.idleResolvers.push(resolve27);
|
|
95673
95780
|
this.pump();
|
|
95674
95781
|
});
|
|
95675
95782
|
}
|
|
@@ -95681,8 +95788,8 @@ class TodosShadowMirror {
|
|
|
95681
95788
|
return;
|
|
95682
95789
|
const resolvers = this.idleResolvers;
|
|
95683
95790
|
this.idleResolvers = [];
|
|
95684
|
-
for (const
|
|
95685
|
-
|
|
95791
|
+
for (const resolve27 of resolvers)
|
|
95792
|
+
resolve27();
|
|
95686
95793
|
}
|
|
95687
95794
|
pump() {
|
|
95688
95795
|
if (this.pumping)
|
|
@@ -98192,6 +98299,41 @@ async function registerOptionalEventsCommands(program3) {
|
|
|
98192
98299
|
}
|
|
98193
98300
|
registerUnavailableEventsCommands(program3);
|
|
98194
98301
|
}
|
|
98302
|
+
function commandForArgs(root, args) {
|
|
98303
|
+
let command = root;
|
|
98304
|
+
for (let index = 0;index < args.length; index += 1) {
|
|
98305
|
+
const arg = args[index];
|
|
98306
|
+
if (arg.startsWith("-")) {
|
|
98307
|
+
const exact = command.options.find((candidate) => candidate.long === arg || candidate.short === arg);
|
|
98308
|
+
const inline = command.options.find((candidate) => candidate.long !== undefined && arg.startsWith(`${candidate.long}=`) || candidate.short !== undefined && arg.startsWith(`${candidate.short}=`));
|
|
98309
|
+
const option = exact ?? inline;
|
|
98310
|
+
if (option?.required || option?.optional) {
|
|
98311
|
+
if (exact)
|
|
98312
|
+
index += 1;
|
|
98313
|
+
} else if (!option && !arg.includes("=")) {
|
|
98314
|
+
const next = args[index + 1];
|
|
98315
|
+
const nextIsCommand = next !== undefined && !next.startsWith("-") && command.commands.some((candidate) => candidate.name() === next || candidate.aliases().includes(next));
|
|
98316
|
+
if (next !== undefined && !next.startsWith("-") && !nextIsCommand)
|
|
98317
|
+
index += 1;
|
|
98318
|
+
}
|
|
98319
|
+
continue;
|
|
98320
|
+
}
|
|
98321
|
+
const child = command.commands.find((candidate) => candidate.name() === arg || candidate.aliases().includes(arg));
|
|
98322
|
+
if (!child)
|
|
98323
|
+
break;
|
|
98324
|
+
command = child;
|
|
98325
|
+
}
|
|
98326
|
+
return command;
|
|
98327
|
+
}
|
|
98328
|
+
function unsupportedActiveFormatOption(command, args) {
|
|
98329
|
+
if (command.name() !== "active")
|
|
98330
|
+
return null;
|
|
98331
|
+
const activeIndex = args.indexOf("active");
|
|
98332
|
+
if (activeIndex < 0)
|
|
98333
|
+
return null;
|
|
98334
|
+
const format = (arg) => arg === "--format" || arg.startsWith("--format=");
|
|
98335
|
+
return args.slice(activeIndex + 1).find(format) ?? args.slice(0, activeIndex).find(format) ?? null;
|
|
98336
|
+
}
|
|
98195
98337
|
program2.name("todos").description("Universal task management for AI coding agents").version(getPackageVersion()).option("--project <path>", "Project path").option("-j, --json", "Output as JSON").option("--agent <name>", "Agent name").option("--session <id>", "Session ID");
|
|
98196
98338
|
var authority;
|
|
98197
98339
|
try {
|
|
@@ -98323,6 +98465,10 @@ await registerOptionalEventsCommands(program2);
|
|
|
98323
98465
|
registerHelpCommands2(program2, authority.route, remoteCommandCapabilities);
|
|
98324
98466
|
applyTodosCliHelpVisibility(program2, authority.route, remoteCommandCapabilities);
|
|
98325
98467
|
try {
|
|
98468
|
+
const activeFormat = unsupportedActiveFormatOption(commandForArgs(program2, process.argv.slice(2)), process.argv.slice(2));
|
|
98469
|
+
if (activeFormat) {
|
|
98470
|
+
throw new Error(`ACTIVE_FORMAT_UNSUPPORTED: ${activeFormat} is not supported by todos active; use --json for machine-readable output`);
|
|
98471
|
+
}
|
|
98326
98472
|
if (metadataRequested) {
|
|
98327
98473
|
const unavailableCommand = getUnavailableTodosCliRemoteMetadataCommand(authority.route, remoteCommandCapabilities, process.argv.slice(2));
|
|
98328
98474
|
if (unavailableCommand) {
|