@hasna/todos 0.15.49 → 0.15.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/query-commands.d.ts.map +1 -1
- package/dist/cli/helpers.d.ts.map +1 -1
- package/dist/cli/index.js +482 -336
- package/dist/contracts.js +193 -94
- package/dist/db/task-crud.d.ts.map +1 -1
- package/dist/index.js +394 -295
- package/dist/lib/model-config.d.ts +2 -1
- package/dist/lib/model-config.d.ts.map +1 -1
- package/dist/lib/paths.d.ts +40 -0
- package/dist/lib/paths.d.ts.map +1 -0
- package/dist/lib/sync-utils.d.ts +7 -0
- package/dist/lib/sync-utils.d.ts.map +1 -1
- package/dist/mcp/index.js +268 -170
- package/dist/mcp.js +6 -3
- package/dist/project-registration.js +191 -92
- package/dist/registry.js +193 -94
- package/dist/release-provenance.json +5 -5
- package/dist/sdk/index.js +100 -8
- package/dist/server/index.js +437 -216
- package/dist/storage.js +183 -87
- package/dist/task-manifest.js +113 -17
- package/dist/testing.d.ts +10 -9
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +2 -2
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +6 -3
- package/postinstall.js +34 -0
package/dist/index.js
CHANGED
|
@@ -4075,23 +4075,118 @@ var init_identity_mapping = __esm(() => {
|
|
|
4075
4075
|
});
|
|
4076
4076
|
});
|
|
4077
4077
|
|
|
4078
|
-
//
|
|
4079
|
-
import { existsSync as existsSync2, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
|
|
4080
|
-
import { createHash } from "crypto";
|
|
4078
|
+
// node_modules/.bun/@hasna+paths@0.1.0/node_modules/@hasna/paths/dist/index.js
|
|
4081
4079
|
import { homedir } from "os";
|
|
4082
4080
|
import { join } from "path";
|
|
4081
|
+
function assertApp(app) {
|
|
4082
|
+
if (typeof app !== "string" || app.length === 0) {
|
|
4083
|
+
throw new TypeError("paths: app must be a non-empty string");
|
|
4084
|
+
}
|
|
4085
|
+
if (!APP_SLUG_RE.test(app)) {
|
|
4086
|
+
throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
|
|
4087
|
+
}
|
|
4088
|
+
}
|
|
4089
|
+
function envOf(options) {
|
|
4090
|
+
return options.env ?? process.env;
|
|
4091
|
+
}
|
|
4092
|
+
function envValue(options, kind) {
|
|
4093
|
+
const value = envOf(options)[KIND_ENV[kind]];
|
|
4094
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
4095
|
+
}
|
|
4096
|
+
function isMacOS(platform) {
|
|
4097
|
+
return platform === "darwin";
|
|
4098
|
+
}
|
|
4099
|
+
function baseDir(kind, options) {
|
|
4100
|
+
const override = envValue(options, kind);
|
|
4101
|
+
if (override)
|
|
4102
|
+
return override;
|
|
4103
|
+
const home = options.home ?? homedir();
|
|
4104
|
+
const platform = options.platform ?? process.platform;
|
|
4105
|
+
if (isMacOS(platform)) {
|
|
4106
|
+
switch (kind) {
|
|
4107
|
+
case "config":
|
|
4108
|
+
case "data":
|
|
4109
|
+
return join(home, "Library", "Application Support", "Hasna");
|
|
4110
|
+
case "cache":
|
|
4111
|
+
return join(home, "Library", "Caches", "Hasna");
|
|
4112
|
+
case "state":
|
|
4113
|
+
return join(home, "Library", "Logs", "Hasna");
|
|
4114
|
+
}
|
|
4115
|
+
}
|
|
4116
|
+
switch (kind) {
|
|
4117
|
+
case "config":
|
|
4118
|
+
return join(home, ".config", "hasna");
|
|
4119
|
+
case "data":
|
|
4120
|
+
return join(home, ".local", "share", "hasna");
|
|
4121
|
+
case "state":
|
|
4122
|
+
return join(home, ".local", "state", "hasna");
|
|
4123
|
+
case "cache":
|
|
4124
|
+
return join(home, ".cache", "hasna");
|
|
4125
|
+
}
|
|
4126
|
+
}
|
|
4127
|
+
function resolvePath(kind, options) {
|
|
4128
|
+
assertApp(options.app);
|
|
4129
|
+
const appSegment = options.internal === true ? join("internal", options.app) : options.app;
|
|
4130
|
+
return join(baseDir(kind, options), appSegment);
|
|
4131
|
+
}
|
|
4132
|
+
function dataDir(options) {
|
|
4133
|
+
return resolvePath("data", options);
|
|
4134
|
+
}
|
|
4135
|
+
var KIND_ENV, APP_SLUG_RE;
|
|
4136
|
+
var init_dist = __esm(() => {
|
|
4137
|
+
KIND_ENV = {
|
|
4138
|
+
config: "HASNA_CONFIG_HOME",
|
|
4139
|
+
data: "HASNA_DATA_HOME",
|
|
4140
|
+
state: "HASNA_STATE_HOME",
|
|
4141
|
+
cache: "HASNA_CACHE_HOME"
|
|
4142
|
+
};
|
|
4143
|
+
APP_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
4144
|
+
});
|
|
4145
|
+
|
|
4146
|
+
// src/lib/paths.ts
|
|
4147
|
+
import { existsSync as existsSync2 } from "fs";
|
|
4148
|
+
import { homedir as homedir2 } from "os";
|
|
4149
|
+
import { join as join2, resolve as resolve2 } from "path";
|
|
4150
|
+
function effectiveHome(env = process.env) {
|
|
4151
|
+
return env.HOME || env.USERPROFILE || homedir2();
|
|
4152
|
+
}
|
|
4153
|
+
function legacyHomeDir(env = process.env) {
|
|
4154
|
+
return join2(effectiveHome(env), ".hasna", "todos");
|
|
4155
|
+
}
|
|
4156
|
+
function resolverHome(env = process.env) {
|
|
4157
|
+
return dataDir({ app: "todos", home: effectiveHome(env), env });
|
|
4158
|
+
}
|
|
4159
|
+
function adoptResolverHome(resolved, env = process.env) {
|
|
4160
|
+
const dataOverride = env.HASNA_DATA_HOME;
|
|
4161
|
+
if (typeof dataOverride === "string" && dataOverride.trim().length > 0)
|
|
4162
|
+
return true;
|
|
4163
|
+
return existsSync2(join2(resolved, "todos.db")) || existsSync2(join2(resolved, "config.json"));
|
|
4164
|
+
}
|
|
4165
|
+
function getTodosDir(env = process.env) {
|
|
4166
|
+
const resolved = resolverHome(env);
|
|
4167
|
+
return resolve2(adoptResolverHome(resolved, env) ? resolved : legacyHomeDir(env));
|
|
4168
|
+
}
|
|
4169
|
+
var init_paths = __esm(() => {
|
|
4170
|
+
init_dist();
|
|
4171
|
+
});
|
|
4172
|
+
|
|
4173
|
+
// src/lib/sync-utils.ts
|
|
4174
|
+
import { existsSync as existsSync3, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
|
|
4175
|
+
import { createHash } from "crypto";
|
|
4176
|
+
import { homedir as homedir3 } from "os";
|
|
4177
|
+
import { join as join3 } from "path";
|
|
4083
4178
|
function getHomeDir() {
|
|
4084
|
-
return process.env["HOME"] || process.env["USERPROFILE"] ||
|
|
4179
|
+
return process.env["HOME"] || process.env["USERPROFILE"] || homedir3();
|
|
4085
4180
|
}
|
|
4086
4181
|
function getTodosGlobalDir() {
|
|
4087
|
-
return
|
|
4182
|
+
return getTodosDir();
|
|
4088
4183
|
}
|
|
4089
4184
|
function ensureDir(dir) {
|
|
4090
|
-
if (!
|
|
4185
|
+
if (!existsSync3(dir))
|
|
4091
4186
|
mkdirSync(dir, { recursive: true });
|
|
4092
4187
|
}
|
|
4093
4188
|
function listJsonFiles(dir) {
|
|
4094
|
-
if (!
|
|
4189
|
+
if (!existsSync3(dir))
|
|
4095
4190
|
return [];
|
|
4096
4191
|
return readdirSync(dir).filter((f) => f.endsWith(".json"));
|
|
4097
4192
|
}
|
|
@@ -4107,14 +4202,14 @@ function writeJsonFile(path, data) {
|
|
|
4107
4202
|
`);
|
|
4108
4203
|
}
|
|
4109
4204
|
function readHighWaterMark(dir) {
|
|
4110
|
-
const path =
|
|
4111
|
-
if (!
|
|
4205
|
+
const path = join3(dir, ".highwatermark");
|
|
4206
|
+
if (!existsSync3(path))
|
|
4112
4207
|
return 1;
|
|
4113
4208
|
const val = parseInt(readFileSync(path, "utf-8").trim(), 10);
|
|
4114
4209
|
return isNaN(val) ? 1 : val;
|
|
4115
4210
|
}
|
|
4116
4211
|
function writeHighWaterMark(dir, value) {
|
|
4117
|
-
writeFileSync(
|
|
4212
|
+
writeFileSync(join3(dir, ".highwatermark"), String(value));
|
|
4118
4213
|
}
|
|
4119
4214
|
function getFileMtimeMs(path) {
|
|
4120
4215
|
try {
|
|
@@ -4169,6 +4264,7 @@ function hasSyncFingerprintChanged(record) {
|
|
|
4169
4264
|
}
|
|
4170
4265
|
var TODO_SYNC_FINGERPRINT_KEY = "todos_sync_fingerprint", HOME;
|
|
4171
4266
|
var init_sync_utils = __esm(() => {
|
|
4267
|
+
init_paths();
|
|
4172
4268
|
HOME = getHomeDir();
|
|
4173
4269
|
});
|
|
4174
4270
|
|
|
@@ -4479,18 +4575,18 @@ __export(exports_database, {
|
|
|
4479
4575
|
LOCK_EXPIRY_MINUTES: () => LOCK_EXPIRY_MINUTES
|
|
4480
4576
|
});
|
|
4481
4577
|
import { Database } from "bun:sqlite";
|
|
4482
|
-
import { existsSync as
|
|
4483
|
-
import { dirname, join as
|
|
4578
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync2 } from "fs";
|
|
4579
|
+
import { dirname, join as join4, resolve as resolve3 } from "path";
|
|
4484
4580
|
function isInMemoryDb(path) {
|
|
4485
4581
|
return path === ":memory:" || path.startsWith("file::memory:");
|
|
4486
4582
|
}
|
|
4487
4583
|
function findNearestProjectDb(startDir) {
|
|
4488
4584
|
const gitRoot = findGitRoot(startDir);
|
|
4489
|
-
const stopAt = gitRoot ?
|
|
4490
|
-
let dir =
|
|
4585
|
+
const stopAt = gitRoot ? resolve3(gitRoot) : resolve3(startDir);
|
|
4586
|
+
let dir = resolve3(startDir);
|
|
4491
4587
|
while (true) {
|
|
4492
|
-
const candidate =
|
|
4493
|
-
if (
|
|
4588
|
+
const candidate = join4(dir, ".hasna", "todos", "todos.db");
|
|
4589
|
+
if (existsSync4(candidate))
|
|
4494
4590
|
return candidate;
|
|
4495
4591
|
if (dir === stopAt)
|
|
4496
4592
|
break;
|
|
@@ -4502,9 +4598,9 @@ function findNearestProjectDb(startDir) {
|
|
|
4502
4598
|
return null;
|
|
4503
4599
|
}
|
|
4504
4600
|
function findGitRoot(startDir) {
|
|
4505
|
-
let dir =
|
|
4601
|
+
let dir = resolve3(startDir);
|
|
4506
4602
|
while (true) {
|
|
4507
|
-
if (
|
|
4603
|
+
if (existsSync4(join4(dir, ".git")))
|
|
4508
4604
|
return dir;
|
|
4509
4605
|
const parent = dirname(dir);
|
|
4510
4606
|
if (parent === dir)
|
|
@@ -4514,7 +4610,7 @@ function findGitRoot(startDir) {
|
|
|
4514
4610
|
return null;
|
|
4515
4611
|
}
|
|
4516
4612
|
function getGlobalDbPath() {
|
|
4517
|
-
return
|
|
4613
|
+
return join4(getTodosGlobalDir(), "todos.db");
|
|
4518
4614
|
}
|
|
4519
4615
|
function hasExplicitProjectArg(args = process.argv.slice(2)) {
|
|
4520
4616
|
return args.some((arg) => arg === "--project" || arg.startsWith("--project="));
|
|
@@ -4552,7 +4648,7 @@ function getDbPath() {
|
|
|
4552
4648
|
if (process.env["TODOS_DB_SCOPE"] === "project") {
|
|
4553
4649
|
const gitRoot = findGitRoot(cwd);
|
|
4554
4650
|
if (gitRoot && canCreateScopedProjectDb()) {
|
|
4555
|
-
return
|
|
4651
|
+
return join4(gitRoot, ".hasna", "todos", "todos.db");
|
|
4556
4652
|
}
|
|
4557
4653
|
}
|
|
4558
4654
|
return getGlobalDbPath();
|
|
@@ -4563,8 +4659,8 @@ function getDatabasePath() {
|
|
|
4563
4659
|
function ensureDir2(filePath) {
|
|
4564
4660
|
if (isInMemoryDb(filePath))
|
|
4565
4661
|
return;
|
|
4566
|
-
const dir = dirname(
|
|
4567
|
-
if (!
|
|
4662
|
+
const dir = dirname(resolve3(filePath));
|
|
4663
|
+
if (!existsSync4(dir)) {
|
|
4568
4664
|
mkdirSync2(dir, { recursive: true });
|
|
4569
4665
|
}
|
|
4570
4666
|
}
|
|
@@ -4741,10 +4837,10 @@ var init_database = __esm(() => {
|
|
|
4741
4837
|
});
|
|
4742
4838
|
|
|
4743
4839
|
// src/lib/config.ts
|
|
4744
|
-
import { existsSync as
|
|
4745
|
-
import { dirname as dirname2, join as
|
|
4840
|
+
import { existsSync as existsSync5, readFileSync as readFileSync2 } from "fs";
|
|
4841
|
+
import { dirname as dirname2, join as join5 } from "path";
|
|
4746
4842
|
function getConfigPath() {
|
|
4747
|
-
return
|
|
4843
|
+
return join5(getTodosGlobalDir(), "config.json");
|
|
4748
4844
|
}
|
|
4749
4845
|
function normalizeAgent(agent) {
|
|
4750
4846
|
return agent.trim().toLowerCase();
|
|
@@ -4752,7 +4848,7 @@ function normalizeAgent(agent) {
|
|
|
4752
4848
|
function loadConfig() {
|
|
4753
4849
|
if (cached)
|
|
4754
4850
|
return cached;
|
|
4755
|
-
if (!
|
|
4851
|
+
if (!existsSync5(getConfigPath())) {
|
|
4756
4852
|
cached = {};
|
|
4757
4853
|
return cached;
|
|
4758
4854
|
}
|
|
@@ -4775,7 +4871,7 @@ function updateConfig(patch) {
|
|
|
4775
4871
|
}
|
|
4776
4872
|
function getTodosAiConfig() {
|
|
4777
4873
|
const configPath = getConfigPath();
|
|
4778
|
-
if (!
|
|
4874
|
+
if (!existsSync5(configPath))
|
|
4779
4875
|
return {};
|
|
4780
4876
|
const parsed = JSON.parse(readFileSync2(configPath, "utf8"));
|
|
4781
4877
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
@@ -5393,14 +5489,14 @@ var init_completion_guard = __esm(() => {
|
|
|
5393
5489
|
|
|
5394
5490
|
// src/lib/event-emission-safety.ts
|
|
5395
5491
|
import { tmpdir } from "os";
|
|
5396
|
-
import { resolve as
|
|
5492
|
+
import { resolve as resolve4, sep } from "path";
|
|
5397
5493
|
function envFlag(name) {
|
|
5398
5494
|
const value = process.env[name]?.trim().toLowerCase();
|
|
5399
5495
|
return value === "1" || value === "true" || value === "yes" || value === "on";
|
|
5400
5496
|
}
|
|
5401
5497
|
function isUnder(parent, child) {
|
|
5402
|
-
const normalizedParent =
|
|
5403
|
-
const normalizedChild =
|
|
5498
|
+
const normalizedParent = resolve4(parent);
|
|
5499
|
+
const normalizedChild = resolve4(child);
|
|
5404
5500
|
return normalizedChild === normalizedParent || normalizedChild.startsWith(`${normalizedParent}${sep}`);
|
|
5405
5501
|
}
|
|
5406
5502
|
function databasePathFromDatabase(db) {
|
|
@@ -5561,9 +5657,9 @@ var init_redaction = __esm(() => {
|
|
|
5561
5657
|
});
|
|
5562
5658
|
|
|
5563
5659
|
// src/lib/workspace-trust.ts
|
|
5564
|
-
import { relative, resolve as
|
|
5660
|
+
import { relative, resolve as resolve5 } from "path";
|
|
5565
5661
|
function normalizePath(path) {
|
|
5566
|
-
return
|
|
5662
|
+
return resolve5(path);
|
|
5567
5663
|
}
|
|
5568
5664
|
function unique2(values) {
|
|
5569
5665
|
return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));
|
|
@@ -5745,9 +5841,9 @@ var init_workspace_trust = __esm(() => {
|
|
|
5745
5841
|
});
|
|
5746
5842
|
|
|
5747
5843
|
// src/lib/runner-sandbox.ts
|
|
5748
|
-
import { relative as relative2, resolve as
|
|
5844
|
+
import { relative as relative2, resolve as resolve6 } from "path";
|
|
5749
5845
|
function normalizePath2(path) {
|
|
5750
|
-
return
|
|
5846
|
+
return resolve6(path);
|
|
5751
5847
|
}
|
|
5752
5848
|
function unique3(values) {
|
|
5753
5849
|
return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));
|
|
@@ -5940,7 +6036,7 @@ var init_runner_sandbox = __esm(() => {
|
|
|
5940
6036
|
// src/lib/event-hooks.ts
|
|
5941
6037
|
import { createHash as createHash2, randomUUID } from "crypto";
|
|
5942
6038
|
import { appendFileSync, mkdirSync as mkdirSync3 } from "fs";
|
|
5943
|
-
import { dirname as dirname3, resolve as
|
|
6039
|
+
import { dirname as dirname3, resolve as resolve7 } from "path";
|
|
5944
6040
|
import { createConnection } from "net";
|
|
5945
6041
|
function safeName(name) {
|
|
5946
6042
|
const trimmed = name.trim();
|
|
@@ -6078,7 +6174,7 @@ async function deliverHook(hook, envelope) {
|
|
|
6078
6174
|
if (hook.target === "stdout") {
|
|
6079
6175
|
output = line.trim();
|
|
6080
6176
|
} else if (hook.target === "file") {
|
|
6081
|
-
const filePath =
|
|
6177
|
+
const filePath = resolve7(hook.file_path);
|
|
6082
6178
|
mkdirSync3(dirname3(filePath), { recursive: true });
|
|
6083
6179
|
appendFileSync(filePath, line);
|
|
6084
6180
|
} else if (hook.target === "socket") {
|
|
@@ -6199,9 +6295,9 @@ var init_event_hooks = __esm(() => {
|
|
|
6199
6295
|
// node_modules/.bun/@hasna+events@0.1.16/node_modules/@hasna/events/dist/index.js
|
|
6200
6296
|
import { chmod, mkdir, readFile, rename, writeFile } from "fs/promises";
|
|
6201
6297
|
import { Buffer as Buffer2 } from "buffer";
|
|
6202
|
-
import { existsSync as
|
|
6203
|
-
import { homedir as
|
|
6204
|
-
import { join as
|
|
6298
|
+
import { existsSync as existsSync6 } from "fs";
|
|
6299
|
+
import { homedir as homedir4 } from "os";
|
|
6300
|
+
import { join as join6 } from "path";
|
|
6205
6301
|
import { createHmac, timingSafeEqual } from "crypto";
|
|
6206
6302
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
6207
6303
|
import { spawn } from "child_process";
|
|
@@ -6302,7 +6398,7 @@ function channelMatchesEvent(channel, event) {
|
|
|
6302
6398
|
return channel.filters.some((filter) => eventMatchesFilter(event, filter));
|
|
6303
6399
|
}
|
|
6304
6400
|
function getEventsDataDir(override) {
|
|
6305
|
-
return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] ||
|
|
6401
|
+
return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join6(homedir4(), ".hasna", "events");
|
|
6306
6402
|
}
|
|
6307
6403
|
|
|
6308
6404
|
class JsonEventsStore {
|
|
@@ -6311,12 +6407,12 @@ class JsonEventsStore {
|
|
|
6311
6407
|
channelsPath;
|
|
6312
6408
|
eventsPath;
|
|
6313
6409
|
deliveriesPath;
|
|
6314
|
-
constructor(
|
|
6315
|
-
this.dataDir =
|
|
6316
|
-
this.runtime = localJsonRuntime(
|
|
6317
|
-
this.channelsPath =
|
|
6318
|
-
this.eventsPath =
|
|
6319
|
-
this.deliveriesPath =
|
|
6410
|
+
constructor(dataDir2 = getEventsDataDir()) {
|
|
6411
|
+
this.dataDir = dataDir2;
|
|
6412
|
+
this.runtime = localJsonRuntime(dataDir2);
|
|
6413
|
+
this.channelsPath = join6(dataDir2, "channels.json");
|
|
6414
|
+
this.eventsPath = join6(dataDir2, "events.json");
|
|
6415
|
+
this.deliveriesPath = join6(dataDir2, "deliveries.json");
|
|
6320
6416
|
}
|
|
6321
6417
|
async init() {
|
|
6322
6418
|
await mkdir(this.dataDir, { recursive: true, mode: 448 });
|
|
@@ -6433,7 +6529,7 @@ class JsonEventsStore {
|
|
|
6433
6529
|
};
|
|
6434
6530
|
}
|
|
6435
6531
|
async ensureArrayFile(path) {
|
|
6436
|
-
if (!
|
|
6532
|
+
if (!existsSync6(path)) {
|
|
6437
6533
|
await writeFile(path, `[]
|
|
6438
6534
|
`, { encoding: "utf-8", mode: 384 });
|
|
6439
6535
|
}
|
|
@@ -6463,7 +6559,7 @@ class JsonEventsStore {
|
|
|
6463
6559
|
});
|
|
6464
6560
|
}
|
|
6465
6561
|
}
|
|
6466
|
-
function localJsonRuntime(
|
|
6562
|
+
function localJsonRuntime(dataDir2 = getEventsDataDir()) {
|
|
6467
6563
|
return {
|
|
6468
6564
|
mode: "local-files",
|
|
6469
6565
|
name: "json-events-store",
|
|
@@ -6476,7 +6572,7 @@ function localJsonRuntime(dataDir = getEventsDataDir()) {
|
|
|
6476
6572
|
durable: true,
|
|
6477
6573
|
idempotency: "best-effort-local",
|
|
6478
6574
|
replayCursors: true,
|
|
6479
|
-
description: `Local JSON files in ${
|
|
6575
|
+
description: `Local JSON files in ${dataDir2}; no SQLite, Postgres, S3, or AWS runtime is configured by this store.`
|
|
6480
6576
|
};
|
|
6481
6577
|
}
|
|
6482
6578
|
function encodeLocalJsonEventCursor(offset, options = {}) {
|
|
@@ -6655,7 +6751,7 @@ async function dispatchCommand(event, channel) {
|
|
|
6655
6751
|
HASNA_EVENT_SCHEMA_VERSION: event.schemaVersion,
|
|
6656
6752
|
HASNA_EVENT_JSON: eventJson
|
|
6657
6753
|
};
|
|
6658
|
-
return new Promise((
|
|
6754
|
+
return new Promise((resolve8) => {
|
|
6659
6755
|
const child = spawn(channel.command.command, channel.command.args ?? [], {
|
|
6660
6756
|
cwd: channel.command.cwd,
|
|
6661
6757
|
env,
|
|
@@ -6673,7 +6769,7 @@ async function dispatchCommand(event, channel) {
|
|
|
6673
6769
|
});
|
|
6674
6770
|
child.on("error", (error) => {
|
|
6675
6771
|
clearTimeout(timeout);
|
|
6676
|
-
|
|
6772
|
+
resolve8({
|
|
6677
6773
|
attempt: 1,
|
|
6678
6774
|
status: "failed",
|
|
6679
6775
|
startedAt,
|
|
@@ -6686,7 +6782,7 @@ async function dispatchCommand(event, channel) {
|
|
|
6686
6782
|
child.on("close", (code, signal) => {
|
|
6687
6783
|
clearTimeout(timeout);
|
|
6688
6784
|
const success = code === 0;
|
|
6689
|
-
|
|
6785
|
+
resolve8({
|
|
6690
6786
|
attempt: 1,
|
|
6691
6787
|
status: success ? "success" : "failed",
|
|
6692
6788
|
startedAt,
|
|
@@ -7028,7 +7124,7 @@ function normalizeRetryPolicy(policy) {
|
|
|
7028
7124
|
};
|
|
7029
7125
|
}
|
|
7030
7126
|
var HASNA_EVENTS_DIR_ENV = "HASNA_EVENTS_DIR", HASNA_EVENTS_HOME_ENV = "HASNA_EVENTS_HOME", LOCAL_JSON_EVENT_CURSOR_PREFIX = "local-json-v1:", DEFAULT_EVENT_PAGE_LIMIT = 100, MAX_EVENT_PAGE_LIMIT = 1000, DEFAULT_SIGNATURE_TOLERANCE_MS, EventValidationError, defaultEventTypeCatalog, APP_EVENT_V1_MAX_DATA_BYTES;
|
|
7031
|
-
var
|
|
7127
|
+
var init_dist2 = __esm(() => {
|
|
7032
7128
|
DEFAULT_SIGNATURE_TOLERANCE_MS = 5 * 60 * 1000;
|
|
7033
7129
|
EventValidationError = class EventValidationError extends Error {
|
|
7034
7130
|
eventType;
|
|
@@ -7451,7 +7547,7 @@ function emitSharedTaskEventQuiet(input) {
|
|
|
7451
7547
|
}
|
|
7452
7548
|
var SOURCE = "todos";
|
|
7453
7549
|
var init_shared_events = __esm(() => {
|
|
7454
|
-
|
|
7550
|
+
init_dist2();
|
|
7455
7551
|
init_database();
|
|
7456
7552
|
init_projects();
|
|
7457
7553
|
init_task_lists();
|
|
@@ -7459,7 +7555,7 @@ var init_shared_events = __esm(() => {
|
|
|
7459
7555
|
});
|
|
7460
7556
|
|
|
7461
7557
|
// src/lib/secret-redaction.ts
|
|
7462
|
-
import { readFileSync as readFileSync3, existsSync as
|
|
7558
|
+
import { readFileSync as readFileSync3, existsSync as existsSync7 } from "fs";
|
|
7463
7559
|
function registerCustomRedactor(fn) {
|
|
7464
7560
|
customRedactors.push(fn);
|
|
7465
7561
|
}
|
|
@@ -7524,7 +7620,7 @@ function scanAndRedactText(text, options = {}) {
|
|
|
7524
7620
|
};
|
|
7525
7621
|
}
|
|
7526
7622
|
function scanFileForSecrets(path, options = {}) {
|
|
7527
|
-
if (!
|
|
7623
|
+
if (!existsSync7(path))
|
|
7528
7624
|
throw new Error(`File not found: ${path}`);
|
|
7529
7625
|
const content = readFileSync3(path, "utf8");
|
|
7530
7626
|
return scanAndRedactText(content, options);
|
|
@@ -9782,17 +9878,17 @@ function sanitizeCreateTaskInput(input) {
|
|
|
9782
9878
|
return {
|
|
9783
9879
|
...input,
|
|
9784
9880
|
title: sanitizePreWriteText(input.title, "task.title"),
|
|
9785
|
-
description: input.description
|
|
9881
|
+
description: input.description == null ? input.description : sanitizePreWriteText(input.description, "task.description"),
|
|
9786
9882
|
tags: input.tags !== undefined ? sanitizePreWriteValue(input.tags, "task.tags") : undefined,
|
|
9787
9883
|
metadata: input.metadata !== undefined ? sanitizePreWriteValue(input.metadata, "task.metadata") : undefined,
|
|
9788
|
-
reason: input.reason
|
|
9884
|
+
reason: input.reason == null ? input.reason : sanitizePreWriteText(input.reason, "task.reason")
|
|
9789
9885
|
};
|
|
9790
9886
|
}
|
|
9791
9887
|
function sanitizeUpdateTaskInput(input) {
|
|
9792
9888
|
return {
|
|
9793
9889
|
...input,
|
|
9794
9890
|
title: input.title !== undefined ? sanitizePreWriteText(input.title, "task.title") : undefined,
|
|
9795
|
-
description: input.description
|
|
9891
|
+
description: input.description == null ? input.description : sanitizePreWriteText(input.description, "task.description"),
|
|
9796
9892
|
tags: input.tags !== undefined ? sanitizePreWriteValue(input.tags, "task.tags") : undefined,
|
|
9797
9893
|
metadata: input.metadata !== undefined ? sanitizePreWriteValue(input.metadata, "task.metadata") : undefined
|
|
9798
9894
|
};
|
|
@@ -11646,28 +11742,28 @@ var init_boards = __esm(() => {
|
|
|
11646
11742
|
|
|
11647
11743
|
// src/lib/artifact-store.ts
|
|
11648
11744
|
import { createHash as createHash3 } from "crypto";
|
|
11649
|
-
import { existsSync as
|
|
11650
|
-
import { basename, dirname as dirname4, join as
|
|
11745
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync4, rmSync, statSync as statSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
11746
|
+
import { basename, dirname as dirname4, join as join7, resolve as resolve8 } from "path";
|
|
11651
11747
|
import { tmpdir as tmpdir2 } from "os";
|
|
11652
11748
|
function isInMemoryDb2(path) {
|
|
11653
11749
|
return path === ":memory:" || path.startsWith("file::memory:");
|
|
11654
11750
|
}
|
|
11655
11751
|
function artifactStoreRoot() {
|
|
11656
11752
|
if (process.env["HASNA_TODOS_ARTIFACTS_DIR"])
|
|
11657
|
-
return
|
|
11753
|
+
return resolve8(process.env["HASNA_TODOS_ARTIFACTS_DIR"]);
|
|
11658
11754
|
if (process.env["TODOS_ARTIFACTS_DIR"])
|
|
11659
|
-
return
|
|
11755
|
+
return resolve8(process.env["TODOS_ARTIFACTS_DIR"]);
|
|
11660
11756
|
const dbPath = getDatabasePath();
|
|
11661
11757
|
if (isInMemoryDb2(dbPath))
|
|
11662
|
-
return
|
|
11663
|
-
return
|
|
11758
|
+
return join7(tmpdir2(), "hasna-todos-artifacts");
|
|
11759
|
+
return join7(dirname4(resolve8(dbPath)), "artifacts");
|
|
11664
11760
|
}
|
|
11665
11761
|
function artifactStorePath(relativePath) {
|
|
11666
11762
|
const normalized = relativePath.replace(/\\/g, "/");
|
|
11667
11763
|
if (normalized.includes("..") || normalized.startsWith("/") || normalized.length === 0) {
|
|
11668
11764
|
throw new Error("Invalid artifact store path");
|
|
11669
11765
|
}
|
|
11670
|
-
return
|
|
11766
|
+
return join7(artifactStoreRoot(), normalized);
|
|
11671
11767
|
}
|
|
11672
11768
|
function sha256(buffer) {
|
|
11673
11769
|
return createHash3("sha256").update(buffer).digest("hex");
|
|
@@ -11707,8 +11803,8 @@ function mediaTypeFor(path, textLike) {
|
|
|
11707
11803
|
return "application/octet-stream";
|
|
11708
11804
|
}
|
|
11709
11805
|
function storeArtifactContent(input) {
|
|
11710
|
-
const sourcePath =
|
|
11711
|
-
if (!
|
|
11806
|
+
const sourcePath = resolve8(input.path);
|
|
11807
|
+
if (!existsSync8(sourcePath))
|
|
11712
11808
|
return null;
|
|
11713
11809
|
const sourceStat = statSync2(sourcePath);
|
|
11714
11810
|
if (!sourceStat.isFile())
|
|
@@ -11725,9 +11821,9 @@ function storeArtifactContent(input) {
|
|
|
11725
11821
|
redactionStatus = "redacted";
|
|
11726
11822
|
}
|
|
11727
11823
|
const storedSha = sha256(storedBuffer);
|
|
11728
|
-
const relativePath =
|
|
11824
|
+
const relativePath = join7("sha256", storedSha.slice(0, 2), storedSha).replace(/\\/g, "/");
|
|
11729
11825
|
const destination = artifactStorePath(relativePath);
|
|
11730
|
-
if (!
|
|
11826
|
+
if (!existsSync8(destination)) {
|
|
11731
11827
|
mkdirSync4(dirname4(destination), { recursive: true });
|
|
11732
11828
|
writeFileSync2(destination, storedBuffer);
|
|
11733
11829
|
}
|
|
@@ -11787,7 +11883,7 @@ function verifyStoredArtifact(input) {
|
|
|
11787
11883
|
};
|
|
11788
11884
|
}
|
|
11789
11885
|
const storedPath = artifactStorePath(store.relative_path);
|
|
11790
|
-
if (!
|
|
11886
|
+
if (!existsSync8(storedPath)) {
|
|
11791
11887
|
return {
|
|
11792
11888
|
id: input.id,
|
|
11793
11889
|
path: input.path,
|
|
@@ -11862,20 +11958,20 @@ function importStoredArtifactContent(content) {
|
|
|
11862
11958
|
}
|
|
11863
11959
|
function getArtifactStoreRoot(dbPath) {
|
|
11864
11960
|
if (process.env["HASNA_TODOS_ARTIFACTS_DIR"])
|
|
11865
|
-
return
|
|
11961
|
+
return resolve8(process.env["HASNA_TODOS_ARTIFACTS_DIR"]);
|
|
11866
11962
|
if (process.env["TODOS_ARTIFACTS_DIR"])
|
|
11867
|
-
return
|
|
11963
|
+
return resolve8(process.env["TODOS_ARTIFACTS_DIR"]);
|
|
11868
11964
|
const path = dbPath ?? getDatabasePath();
|
|
11869
11965
|
if (isInMemoryDb2(path))
|
|
11870
|
-
return
|
|
11871
|
-
return
|
|
11966
|
+
return join7(tmpdir2(), "hasna-todos-artifacts");
|
|
11967
|
+
return join7(dirname4(resolve8(path)), "artifacts");
|
|
11872
11968
|
}
|
|
11873
11969
|
function computeContentHash(path) {
|
|
11874
|
-
return sha256(readFileSync4(
|
|
11970
|
+
return sha256(readFileSync4(resolve8(path)));
|
|
11875
11971
|
}
|
|
11876
11972
|
function storeArtifactFile(input) {
|
|
11877
|
-
const sourcePath =
|
|
11878
|
-
if (!
|
|
11973
|
+
const sourcePath = resolve8(input.sourcePath);
|
|
11974
|
+
if (!existsSync8(sourcePath)) {
|
|
11879
11975
|
throw new Error(`Source file not found: ${input.sourcePath}`);
|
|
11880
11976
|
}
|
|
11881
11977
|
if (!statSync2(sourcePath).isFile()) {
|
|
@@ -11888,7 +11984,7 @@ function storeArtifactFile(input) {
|
|
|
11888
11984
|
let localPath = sourcePath;
|
|
11889
11985
|
if (storageMode === "copy") {
|
|
11890
11986
|
const fileName = input.name && input.name.trim().length > 0 ? basename(input.name) : basename(sourcePath);
|
|
11891
|
-
const destination =
|
|
11987
|
+
const destination = join7(getArtifactStoreRoot(input.dbPath), input.artifactId, fileName);
|
|
11892
11988
|
mkdirSync4(dirname4(destination), { recursive: true });
|
|
11893
11989
|
writeFileSync2(destination, buffer);
|
|
11894
11990
|
localPath = destination;
|
|
@@ -11898,7 +11994,7 @@ function storeArtifactFile(input) {
|
|
|
11898
11994
|
function deleteStoredArtifactFile(localPath, storageMode, _dbPath2) {
|
|
11899
11995
|
if (storageMode === "reference")
|
|
11900
11996
|
return false;
|
|
11901
|
-
if (!localPath || !
|
|
11997
|
+
if (!localPath || !existsSync8(localPath))
|
|
11902
11998
|
return false;
|
|
11903
11999
|
rmSync(localPath, { force: true });
|
|
11904
12000
|
try {
|
|
@@ -11923,7 +12019,7 @@ function buildArtifactExportManifest(artifacts, dbPath) {
|
|
|
11923
12019
|
};
|
|
11924
12020
|
}
|
|
11925
12021
|
function writeArtifactExportManifest(manifest, outputPath) {
|
|
11926
|
-
const destination =
|
|
12022
|
+
const destination = resolve8(outputPath);
|
|
11927
12023
|
mkdirSync4(dirname4(destination), { recursive: true });
|
|
11928
12024
|
writeFileSync2(destination, `${JSON.stringify(manifest, null, 2)}
|
|
11929
12025
|
`);
|
|
@@ -13193,7 +13289,7 @@ var init_dispatches = __esm(() => {
|
|
|
13193
13289
|
// package.json
|
|
13194
13290
|
var package_default = {
|
|
13195
13291
|
name: "@hasna/todos",
|
|
13196
|
-
version: "0.15.
|
|
13292
|
+
version: "0.15.51",
|
|
13197
13293
|
description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
|
|
13198
13294
|
type: "module",
|
|
13199
13295
|
main: "dist/index.js",
|
|
@@ -13252,6 +13348,7 @@ var package_default = {
|
|
|
13252
13348
|
files: [
|
|
13253
13349
|
"dist",
|
|
13254
13350
|
"dashboard/dist",
|
|
13351
|
+
"postinstall.js",
|
|
13255
13352
|
"LICENSE",
|
|
13256
13353
|
"README.md"
|
|
13257
13354
|
],
|
|
@@ -13278,7 +13375,7 @@ var package_default = {
|
|
|
13278
13375
|
"test:attested-container-compatibility-vector": "bun test scripts/attested-container-compatibility-vector.test.ts",
|
|
13279
13376
|
"issue:release-review": "bun run scripts/issue-npm-release-agent-review.ts",
|
|
13280
13377
|
prepublishOnly: "bun run scripts/verify-public-release.ts --mode=publish",
|
|
13281
|
-
postinstall: "
|
|
13378
|
+
postinstall: "node postinstall.js"
|
|
13282
13379
|
},
|
|
13283
13380
|
keywords: [
|
|
13284
13381
|
"todos",
|
|
@@ -13312,13 +13409,15 @@ var package_default = {
|
|
|
13312
13409
|
author: "Andrei Hasna <andrei@hasna.com>",
|
|
13313
13410
|
license: "Apache-2.0",
|
|
13314
13411
|
dependencies: {
|
|
13315
|
-
"@hasna/contracts": "0.14.
|
|
13412
|
+
"@hasna/contracts": "0.14.2",
|
|
13316
13413
|
"@hasna/events": "^0.1.11",
|
|
13414
|
+
"@hasna/paths": "0.1.0",
|
|
13317
13415
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
13318
13416
|
chalk: "^5.4.1",
|
|
13319
13417
|
commander: "^13.1.0",
|
|
13320
13418
|
ink: "^5.2.0",
|
|
13321
13419
|
react: "^18.3.1",
|
|
13420
|
+
"signal-exit": "3.0.7",
|
|
13322
13421
|
zod: "3.25.76"
|
|
13323
13422
|
},
|
|
13324
13423
|
overrides: {
|
|
@@ -16553,7 +16652,7 @@ function todosAiExitCodeForResult(result) {
|
|
|
16553
16652
|
}
|
|
16554
16653
|
// src/lib/onboarding-fixtures.ts
|
|
16555
16654
|
import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
16556
|
-
import { join as
|
|
16655
|
+
import { join as join8 } from "path";
|
|
16557
16656
|
|
|
16558
16657
|
// src/lib/local-bridge.ts
|
|
16559
16658
|
init_database();
|
|
@@ -17490,7 +17589,7 @@ function writeOnboardingFixtureFiles(directory) {
|
|
|
17490
17589
|
mkdirSync5(directory, { recursive: true });
|
|
17491
17590
|
const files = [];
|
|
17492
17591
|
for (const fixture of allFixtures()) {
|
|
17493
|
-
const path =
|
|
17592
|
+
const path = join8(directory, `${fixture.summary.name}.bridge.json`);
|
|
17494
17593
|
writeFileSync3(path, `${JSON.stringify(fixture.bundle, null, 2)}
|
|
17495
17594
|
`, "utf-8");
|
|
17496
17595
|
files.push(path);
|
|
@@ -17508,7 +17607,7 @@ function importOnboardingFixture(options = {}) {
|
|
|
17508
17607
|
init_database();
|
|
17509
17608
|
import { createHash as createHash4 } from "crypto";
|
|
17510
17609
|
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
17511
|
-
import { dirname as dirname5, resolve as
|
|
17610
|
+
import { dirname as dirname5, resolve as resolve9 } from "path";
|
|
17512
17611
|
import { mkdirSync as mkdirSync6 } from "fs";
|
|
17513
17612
|
var TODOS_LOCAL_BACKUP_KIND = "hasna.todos.local-backup";
|
|
17514
17613
|
var TODOS_LOCAL_BACKUP_SCHEMA_VERSION = 1;
|
|
@@ -17615,14 +17714,14 @@ function createLocalBackup(options = {}, db) {
|
|
|
17615
17714
|
return backup;
|
|
17616
17715
|
}
|
|
17617
17716
|
function writeLocalBackupFile(backup, outputPath) {
|
|
17618
|
-
const path =
|
|
17717
|
+
const path = resolve9(outputPath);
|
|
17619
17718
|
mkdirSync6(dirname5(path), { recursive: true });
|
|
17620
17719
|
writeFileSync4(path, `${JSON.stringify(backup, null, 2)}
|
|
17621
17720
|
`);
|
|
17622
17721
|
return path;
|
|
17623
17722
|
}
|
|
17624
17723
|
function readLocalBackupFile(path) {
|
|
17625
|
-
return JSON.parse(readFileSync5(
|
|
17724
|
+
return JSON.parse(readFileSync5(resolve9(path), "utf-8"));
|
|
17626
17725
|
}
|
|
17627
17726
|
function verifyLocalBackup(value, options = {}, db) {
|
|
17628
17727
|
const verifiedAt = options.verified_at ?? now();
|
|
@@ -18316,7 +18415,7 @@ function renderLocalSnapshotMarkdown(snapshot) {
|
|
|
18316
18415
|
}
|
|
18317
18416
|
// src/lib/sdk-integration-fixtures.ts
|
|
18318
18417
|
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync5 } from "fs";
|
|
18319
|
-
import { join as
|
|
18418
|
+
import { join as join9 } from "path";
|
|
18320
18419
|
|
|
18321
18420
|
// src/cli-mcp-parity.ts
|
|
18322
18421
|
function source4(version) {
|
|
@@ -20287,7 +20386,7 @@ function writeSdkIntegrationFixtures(directory, options = {}) {
|
|
|
20287
20386
|
];
|
|
20288
20387
|
const written = [];
|
|
20289
20388
|
for (const [name, payload] of files) {
|
|
20290
|
-
const file =
|
|
20389
|
+
const file = join9(directory, name);
|
|
20291
20390
|
writeFileSync5(file, `${JSON.stringify(payload, null, 2)}
|
|
20292
20391
|
`, "utf-8");
|
|
20293
20392
|
written.push(file);
|
|
@@ -21570,7 +21669,7 @@ function renderLocalAuditLedgerMarkdown(ledger) {
|
|
|
21570
21669
|
init_migrations();
|
|
21571
21670
|
init_schema();
|
|
21572
21671
|
import { readFileSync as readFileSync6 } from "fs";
|
|
21573
|
-
import { join as
|
|
21672
|
+
import { join as join10, resolve as resolve10 } from "path";
|
|
21574
21673
|
import { Database as Database2 } from "bun:sqlite";
|
|
21575
21674
|
var LOCAL_RELEASE_COMPATIBILITY_SCHEMA_VERSION = 1;
|
|
21576
21675
|
var EXPECTED_PACKAGE_NAME = "@hasna/todos";
|
|
@@ -21616,7 +21715,7 @@ function warn(id, message, details) {
|
|
|
21616
21715
|
return { id, status: "warning", message, details };
|
|
21617
21716
|
}
|
|
21618
21717
|
function readPackageJson(root) {
|
|
21619
|
-
return JSON.parse(readFileSync6(
|
|
21718
|
+
return JSON.parse(readFileSync6(join10(root, "package.json"), "utf8"));
|
|
21620
21719
|
}
|
|
21621
21720
|
function sortedKeys(value) {
|
|
21622
21721
|
return Object.keys(value ?? {}).sort((left, right) => left.localeCompare(right));
|
|
@@ -21712,7 +21811,7 @@ function checkChangelog() {
|
|
|
21712
21811
|
];
|
|
21713
21812
|
}
|
|
21714
21813
|
function createReleaseCompatibilityReport(options = {}) {
|
|
21715
|
-
const root =
|
|
21814
|
+
const root = resolve10(options.root ?? process.cwd());
|
|
21716
21815
|
const packageJson = readPackageJson(root);
|
|
21717
21816
|
const simulatedLevels = options.simulated_levels ?? defaultSimulationLevels();
|
|
21718
21817
|
const checks = [
|
|
@@ -30707,7 +30806,7 @@ async function retryOnTransientPostgresError(fn, attempts = 2, delayMs = 150) {
|
|
|
30707
30806
|
lastError = error;
|
|
30708
30807
|
if (!isTransientPostgresError(error) || attempt === attempts)
|
|
30709
30808
|
throw error;
|
|
30710
|
-
await new Promise((
|
|
30809
|
+
await new Promise((resolve11) => setTimeout(resolve11, delayMs * attempt));
|
|
30711
30810
|
}
|
|
30712
30811
|
}
|
|
30713
30812
|
throw lastError;
|
|
@@ -30808,8 +30907,8 @@ class TodosShadowMirror {
|
|
|
30808
30907
|
async flush() {
|
|
30809
30908
|
if (this.idle())
|
|
30810
30909
|
return;
|
|
30811
|
-
await new Promise((
|
|
30812
|
-
this.idleResolvers.push(
|
|
30910
|
+
await new Promise((resolve11) => {
|
|
30911
|
+
this.idleResolvers.push(resolve11);
|
|
30813
30912
|
this.pump();
|
|
30814
30913
|
});
|
|
30815
30914
|
}
|
|
@@ -30821,8 +30920,8 @@ class TodosShadowMirror {
|
|
|
30821
30920
|
return;
|
|
30822
30921
|
const resolvers = this.idleResolvers;
|
|
30823
30922
|
this.idleResolvers = [];
|
|
30824
|
-
for (const
|
|
30825
|
-
|
|
30923
|
+
for (const resolve11 of resolvers)
|
|
30924
|
+
resolve11();
|
|
30826
30925
|
}
|
|
30827
30926
|
pump() {
|
|
30828
30927
|
if (this.pumping)
|
|
@@ -31301,7 +31400,7 @@ class TodosShadowOutbox {
|
|
|
31301
31400
|
const remaining = deadline - Date.now();
|
|
31302
31401
|
if (remaining <= 0)
|
|
31303
31402
|
break;
|
|
31304
|
-
await new Promise((
|
|
31403
|
+
await new Promise((resolve11) => setTimeout(resolve11, Math.min(200, remaining)));
|
|
31305
31404
|
}
|
|
31306
31405
|
}
|
|
31307
31406
|
return this.getStats();
|
|
@@ -32605,7 +32704,7 @@ class TodosClient {
|
|
|
32605
32704
|
return this._fetchWithRetry(path, { method: "DELETE" });
|
|
32606
32705
|
}
|
|
32607
32706
|
_sleep(ms) {
|
|
32608
|
-
return new Promise((
|
|
32707
|
+
return new Promise((resolve11) => setTimeout(resolve11, ms));
|
|
32609
32708
|
}
|
|
32610
32709
|
async getHealth() {
|
|
32611
32710
|
return this._get("/api/health");
|
|
@@ -34262,8 +34361,8 @@ class SqlitePrGroupLedgerPersistence {
|
|
|
34262
34361
|
async transaction(fn) {
|
|
34263
34362
|
const previous = sqliteTransactionTails.get(this.db) ?? Promise.resolve();
|
|
34264
34363
|
let release;
|
|
34265
|
-
const current = new Promise((
|
|
34266
|
-
release =
|
|
34364
|
+
const current = new Promise((resolve11) => {
|
|
34365
|
+
release = resolve11;
|
|
34267
34366
|
});
|
|
34268
34367
|
sqliteTransactionTails.set(this.db, current);
|
|
34269
34368
|
await previous;
|
|
@@ -36281,8 +36380,8 @@ class SqliteTodosProjectRegistrationBackend {
|
|
|
36281
36380
|
async transaction(fn) {
|
|
36282
36381
|
const previous = sqliteTransactionTails2.get(this.db) ?? Promise.resolve();
|
|
36283
36382
|
let release;
|
|
36284
|
-
const current = new Promise((
|
|
36285
|
-
release =
|
|
36383
|
+
const current = new Promise((resolve11) => {
|
|
36384
|
+
release = resolve11;
|
|
36286
36385
|
});
|
|
36287
36386
|
sqliteTransactionTails2.set(this.db, current);
|
|
36288
36387
|
await previous;
|
|
@@ -42561,8 +42660,8 @@ class SqliteTodosTaskManifestBackend {
|
|
|
42561
42660
|
async serialized(run) {
|
|
42562
42661
|
const previous = sqliteTails.get(this.db) ?? Promise.resolve();
|
|
42563
42662
|
let release;
|
|
42564
|
-
const current = new Promise((
|
|
42565
|
-
release =
|
|
42663
|
+
const current = new Promise((resolve11) => {
|
|
42664
|
+
release = resolve11;
|
|
42566
42665
|
});
|
|
42567
42666
|
const tail = previous.then(() => current);
|
|
42568
42667
|
sqliteTails.set(this.db, tail);
|
|
@@ -44903,8 +45002,8 @@ class SqliteTodosTaskSubtreeTransferBackend {
|
|
|
44903
45002
|
async serialized(run) {
|
|
44904
45003
|
const previous = sqliteTails2.get(this.db) ?? Promise.resolve();
|
|
44905
45004
|
let release;
|
|
44906
|
-
const current = new Promise((
|
|
44907
|
-
release =
|
|
45005
|
+
const current = new Promise((resolve11) => {
|
|
45006
|
+
release = resolve11;
|
|
44908
45007
|
});
|
|
44909
45008
|
const tail = previous.then(() => current);
|
|
44910
45009
|
sqliteTails2.set(this.db, tail);
|
|
@@ -46217,8 +46316,8 @@ var DANGEROUS_TOOLS = new Set([
|
|
|
46217
46316
|
"merge_tasks",
|
|
46218
46317
|
"cancel_agent_run"
|
|
46219
46318
|
]);
|
|
46220
|
-
function resolveAccessProfile(
|
|
46221
|
-
const raw = (
|
|
46319
|
+
function resolveAccessProfile(envValue2) {
|
|
46320
|
+
const raw = (envValue2 ?? process.env["TODOS_PROFILE"] ?? "full").toLowerCase();
|
|
46222
46321
|
if (ACCESS_PROFILES.includes(raw))
|
|
46223
46322
|
return raw;
|
|
46224
46323
|
if (raw === "readonly")
|
|
@@ -47761,8 +47860,8 @@ init_task_crud();
|
|
|
47761
47860
|
init_redaction();
|
|
47762
47861
|
import { Database as Database3 } from "bun:sqlite";
|
|
47763
47862
|
import { createHash as createHash17 } from "crypto";
|
|
47764
|
-
import { existsSync as
|
|
47765
|
-
import { basename as basename2, dirname as dirname6, join as
|
|
47863
|
+
import { existsSync as existsSync10, readdirSync as readdirSync2, statSync as statSync4 } from "fs";
|
|
47864
|
+
import { basename as basename2, dirname as dirname6, join as join11, resolve as resolve11 } from "path";
|
|
47766
47865
|
|
|
47767
47866
|
// src/lib/task-routing.ts
|
|
47768
47867
|
init_database();
|
|
@@ -47770,7 +47869,7 @@ init_projects();
|
|
|
47770
47869
|
init_task_crud();
|
|
47771
47870
|
init_task_lifecycle();
|
|
47772
47871
|
init_task_lists();
|
|
47773
|
-
import { existsSync as
|
|
47872
|
+
import { existsSync as existsSync9, statSync as statSync3 } from "fs";
|
|
47774
47873
|
var DEFAULT_STALE_IN_PROGRESS_MS = 3 * 24 * 60 * 60 * 1000;
|
|
47775
47874
|
var TERMINAL_WORKFLOW_STATES = new Set([
|
|
47776
47875
|
"failed",
|
|
@@ -47825,7 +47924,7 @@ function routeConcurrencyKey(task3, project, taskList, projectPath) {
|
|
|
47825
47924
|
}
|
|
47826
47925
|
function directoryExists(path) {
|
|
47827
47926
|
try {
|
|
47828
|
-
return
|
|
47927
|
+
return existsSync9(path) && statSync3(path).isDirectory();
|
|
47829
47928
|
} catch {
|
|
47830
47929
|
return false;
|
|
47831
47930
|
}
|
|
@@ -48026,7 +48125,7 @@ function pointerPatch(previous, input, key2) {
|
|
|
48026
48125
|
|
|
48027
48126
|
// src/lib/task-route-sources.ts
|
|
48028
48127
|
var TASK_ROUTE_SOURCE_DISCOVERY_SCHEMA_VERSION = "todos.task_route_sources.v1";
|
|
48029
|
-
var TODO_STORE_RELATIVE_PATH =
|
|
48128
|
+
var TODO_STORE_RELATIVE_PATH = join11(".hasna", "todos", "todos.db");
|
|
48030
48129
|
var ROOT_SCAN_MAX_DEPTH = 5;
|
|
48031
48130
|
var SKIPPED_SCAN_DIRS = new Set([
|
|
48032
48131
|
".git",
|
|
@@ -48040,7 +48139,7 @@ var SKIPPED_SCAN_DIRS = new Set([
|
|
|
48040
48139
|
".cache"
|
|
48041
48140
|
]);
|
|
48042
48141
|
function normalizePath3(input) {
|
|
48043
|
-
return
|
|
48142
|
+
return resolve11(input);
|
|
48044
48143
|
}
|
|
48045
48144
|
function sourceStoreId(sourceDbPath) {
|
|
48046
48145
|
const digest3 = createHash17("sha256").update(sourceDbPath).digest("hex").slice(0, 16);
|
|
@@ -48102,8 +48201,8 @@ function discoverStoresUnderRoot(sourceRoot) {
|
|
|
48102
48201
|
const rootPath = normalizePath3(sourceRoot);
|
|
48103
48202
|
const errors2 = [];
|
|
48104
48203
|
const stores = [];
|
|
48105
|
-
if (!
|
|
48106
|
-
const ref = createStoreRef(
|
|
48204
|
+
if (!existsSync10(rootPath)) {
|
|
48205
|
+
const ref = createStoreRef(join11(rootPath, TODO_STORE_RELATIVE_PATH));
|
|
48107
48206
|
errors2.push({
|
|
48108
48207
|
...ref,
|
|
48109
48208
|
code: "SOURCE_ROOT_MISSING",
|
|
@@ -48115,7 +48214,7 @@ function discoverStoresUnderRoot(sourceRoot) {
|
|
|
48115
48214
|
try {
|
|
48116
48215
|
rootStat = statSync4(rootPath);
|
|
48117
48216
|
} catch (error) {
|
|
48118
|
-
const ref = createStoreRef(
|
|
48217
|
+
const ref = createStoreRef(join11(rootPath, TODO_STORE_RELATIVE_PATH));
|
|
48119
48218
|
errors2.push({
|
|
48120
48219
|
...ref,
|
|
48121
48220
|
code: "SOURCE_ROOT_UNREADABLE",
|
|
@@ -48128,8 +48227,8 @@ function discoverStoresUnderRoot(sourceRoot) {
|
|
|
48128
48227
|
return { stores, errors: errors2 };
|
|
48129
48228
|
}
|
|
48130
48229
|
function scanDirectory(dir, depth) {
|
|
48131
|
-
const candidate =
|
|
48132
|
-
if (
|
|
48230
|
+
const candidate = join11(dir, TODO_STORE_RELATIVE_PATH);
|
|
48231
|
+
if (existsSync10(candidate)) {
|
|
48133
48232
|
stores.push(createStoreRef(candidate));
|
|
48134
48233
|
}
|
|
48135
48234
|
if (depth >= ROOT_SCAN_MAX_DEPTH)
|
|
@@ -48149,7 +48248,7 @@ function discoverStoresUnderRoot(sourceRoot) {
|
|
|
48149
48248
|
for (const entry2 of entries) {
|
|
48150
48249
|
if (!entry2.isDirectory() || SKIPPED_SCAN_DIRS.has(entry2.name))
|
|
48151
48250
|
continue;
|
|
48152
|
-
scanDirectory(
|
|
48251
|
+
scanDirectory(join11(dir, entry2.name), depth + 1);
|
|
48153
48252
|
}
|
|
48154
48253
|
}
|
|
48155
48254
|
scanDirectory(rootPath, 0);
|
|
@@ -48175,7 +48274,7 @@ function collectStoreRefs(input) {
|
|
|
48175
48274
|
};
|
|
48176
48275
|
}
|
|
48177
48276
|
function openReadonlyStore(ref) {
|
|
48178
|
-
if (!
|
|
48277
|
+
if (!existsSync10(ref.source_db_path)) {
|
|
48179
48278
|
throw Object.assign(new Error(`Store does not exist: ${ref.source_db_path}`), { code: "STORE_MISSING" });
|
|
48180
48279
|
}
|
|
48181
48280
|
return new Database3(ref.source_db_path, { readonly: true, create: false });
|
|
@@ -48487,8 +48586,8 @@ init_plans();
|
|
|
48487
48586
|
init_database();
|
|
48488
48587
|
init_projects();
|
|
48489
48588
|
init_tasks();
|
|
48490
|
-
import { existsSync as
|
|
48491
|
-
import { join as
|
|
48589
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
|
|
48590
|
+
import { join as join12, resolve as resolve12 } from "path";
|
|
48492
48591
|
var PLAN_MARKDOWN_SCHEMA = "hasna.todos.plan/v1";
|
|
48493
48592
|
function assertSafePathSegment(value, label) {
|
|
48494
48593
|
const trimmed = value.trim();
|
|
@@ -48532,7 +48631,7 @@ function resolvePlanArtifactProject(input) {
|
|
|
48532
48631
|
const ref = input.project_id || input.project_ref;
|
|
48533
48632
|
if (!ref)
|
|
48534
48633
|
throw new Error("Plan artifacts require a project id or project reference");
|
|
48535
|
-
const byPath = getProjectByPath(
|
|
48634
|
+
const byPath = getProjectByPath(resolve12(ref), db);
|
|
48536
48635
|
if (byPath)
|
|
48537
48636
|
return byPath;
|
|
48538
48637
|
const resolvedId = resolvePartialId(db, "projects", ref);
|
|
@@ -48549,8 +48648,8 @@ function resolvePlanArtifactProject(input) {
|
|
|
48549
48648
|
function resolvePlanArtifactPaths(input) {
|
|
48550
48649
|
const project = resolvePlanArtifactProject(input);
|
|
48551
48650
|
const projectId = assertSafePathSegment(project.id, "project id");
|
|
48552
|
-
const projectRoot =
|
|
48553
|
-
const directory =
|
|
48651
|
+
const projectRoot = resolve12(project.path);
|
|
48652
|
+
const directory = join12(projectRoot, ".hasna", "todos", "plans", projectId);
|
|
48554
48653
|
const planId = input.plan_id ? assertSafePathSegment(input.plan_id, "plan id") : null;
|
|
48555
48654
|
const planSlug = input.plan_slug ? assertSafePathSegment(slugify(input.plan_slug), "plan slug") : null;
|
|
48556
48655
|
const fileName = planId ? planSlug ? `${planSlug}--${planId.slice(0, 8)}.md` : `${planId}.md` : null;
|
|
@@ -48558,7 +48657,7 @@ function resolvePlanArtifactPaths(input) {
|
|
|
48558
48657
|
project_id: project.id,
|
|
48559
48658
|
project_root: projectRoot,
|
|
48560
48659
|
directory,
|
|
48561
|
-
file_path: fileName ?
|
|
48660
|
+
file_path: fileName ? join12(directory, fileName) : directory
|
|
48562
48661
|
};
|
|
48563
48662
|
}
|
|
48564
48663
|
function resolvePlanArtifactCandidatePaths(plan, db) {
|
|
@@ -48724,7 +48823,7 @@ function readPlanArtifact(plan, db) {
|
|
|
48724
48823
|
return null;
|
|
48725
48824
|
const d = db || getDatabase();
|
|
48726
48825
|
const paths = resolvePlanArtifactCandidatePaths(plan, d);
|
|
48727
|
-
const path =
|
|
48826
|
+
const path = existsSync11(paths.primary.file_path) ? paths.primary.file_path : existsSync11(paths.legacy.file_path) ? paths.legacy.file_path : null;
|
|
48728
48827
|
if (!path)
|
|
48729
48828
|
return null;
|
|
48730
48829
|
const markdown = readFileSync7(path, "utf8");
|
|
@@ -48739,7 +48838,7 @@ function inspectPlanArtifact(plan, db) {
|
|
|
48739
48838
|
return null;
|
|
48740
48839
|
const d = db || getDatabase();
|
|
48741
48840
|
const paths = resolvePlanArtifactCandidatePaths(plan, d);
|
|
48742
|
-
const path =
|
|
48841
|
+
const path = existsSync11(paths.primary.file_path) ? paths.primary.file_path : existsSync11(paths.legacy.file_path) ? paths.legacy.file_path : null;
|
|
48743
48842
|
if (!path) {
|
|
48744
48843
|
return {
|
|
48745
48844
|
path: paths.primary.file_path,
|
|
@@ -49828,8 +49927,8 @@ function renderRetrospectiveMarkdown(record) {
|
|
|
49828
49927
|
init_database();
|
|
49829
49928
|
init_projects();
|
|
49830
49929
|
init_task_lists();
|
|
49831
|
-
import { existsSync as
|
|
49832
|
-
import { basename as basename3, dirname as dirname7, resolve as
|
|
49930
|
+
import { existsSync as existsSync12, readFileSync as readFileSync8, statSync as statSync5 } from "fs";
|
|
49931
|
+
import { basename as basename3, dirname as dirname7, resolve as resolve13 } from "path";
|
|
49833
49932
|
function safeStat(path) {
|
|
49834
49933
|
try {
|
|
49835
49934
|
return statSync5(path);
|
|
@@ -49838,7 +49937,7 @@ function safeStat(path) {
|
|
|
49838
49937
|
}
|
|
49839
49938
|
}
|
|
49840
49939
|
function canonicalPath(input) {
|
|
49841
|
-
const resolved =
|
|
49940
|
+
const resolved = resolve13(input);
|
|
49842
49941
|
const stats2 = safeStat(resolved);
|
|
49843
49942
|
if (stats2?.isFile())
|
|
49844
49943
|
return dirname7(resolved);
|
|
@@ -49847,7 +49946,7 @@ function canonicalPath(input) {
|
|
|
49847
49946
|
function findUp(start, marker) {
|
|
49848
49947
|
let current = canonicalPath(start);
|
|
49849
49948
|
while (true) {
|
|
49850
|
-
if (
|
|
49949
|
+
if (existsSync12(resolve13(current, marker)))
|
|
49851
49950
|
return current;
|
|
49852
49951
|
const parent = dirname7(current);
|
|
49853
49952
|
if (parent === current)
|
|
@@ -49858,8 +49957,8 @@ function findUp(start, marker) {
|
|
|
49858
49957
|
function readPackageJson2(path) {
|
|
49859
49958
|
if (!path)
|
|
49860
49959
|
return null;
|
|
49861
|
-
const file =
|
|
49862
|
-
if (!
|
|
49960
|
+
const file = resolve13(path, "package.json");
|
|
49961
|
+
if (!existsSync12(file))
|
|
49863
49962
|
return null;
|
|
49864
49963
|
try {
|
|
49865
49964
|
const parsed = JSON.parse(readFileSync8(file, "utf-8"));
|
|
@@ -49881,7 +49980,7 @@ function workspaceMarker(root, rootPackage) {
|
|
|
49881
49980
|
if (rootPackage?.workspaces)
|
|
49882
49981
|
markers.push("package.json#workspaces");
|
|
49883
49982
|
for (const marker of ["pnpm-workspace.yaml", "turbo.json", "nx.json", "lerna.json", "rush.json", "bun.lock", "bun.lockb"]) {
|
|
49884
|
-
if (
|
|
49983
|
+
if (existsSync12(resolve13(root, marker)))
|
|
49885
49984
|
markers.push(marker);
|
|
49886
49985
|
}
|
|
49887
49986
|
const kind = markers.find((marker) => marker !== "bun.lock" && marker !== "bun.lockb") ?? null;
|
|
@@ -50219,18 +50318,18 @@ var gatherTrainingData = async (options = {}) => {
|
|
|
50219
50318
|
};
|
|
50220
50319
|
// src/lib/model-config.ts
|
|
50221
50320
|
init_sync_utils();
|
|
50222
|
-
import { existsSync as
|
|
50223
|
-
import { join as
|
|
50321
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync9, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
|
|
50322
|
+
import { join as join13 } from "path";
|
|
50224
50323
|
var DEFAULT_MODEL = "gpt-4o-mini";
|
|
50225
50324
|
function getConfigDir() {
|
|
50226
50325
|
return getTodosGlobalDir();
|
|
50227
50326
|
}
|
|
50228
50327
|
function getConfigPath2() {
|
|
50229
|
-
return
|
|
50328
|
+
return join13(getConfigDir(), "config.json");
|
|
50230
50329
|
}
|
|
50231
50330
|
function readConfig() {
|
|
50232
50331
|
const configPath = getConfigPath2();
|
|
50233
|
-
if (!
|
|
50332
|
+
if (!existsSync13(configPath))
|
|
50234
50333
|
return {};
|
|
50235
50334
|
try {
|
|
50236
50335
|
const raw = readFileSync9(configPath, "utf-8");
|
|
@@ -50241,7 +50340,7 @@ function readConfig() {
|
|
|
50241
50340
|
}
|
|
50242
50341
|
function writeConfig(config) {
|
|
50243
50342
|
const configDir = getConfigDir();
|
|
50244
|
-
if (!
|
|
50343
|
+
if (!existsSync13(configDir)) {
|
|
50245
50344
|
mkdirSync9(configDir, { recursive: true });
|
|
50246
50345
|
}
|
|
50247
50346
|
writeFileSync7(getConfigPath2(), JSON.stringify(config, null, 2) + `
|
|
@@ -50989,7 +51088,7 @@ init_database();
|
|
|
50989
51088
|
init_tasks();
|
|
50990
51089
|
init_config2();
|
|
50991
51090
|
init_redaction();
|
|
50992
|
-
import { existsSync as
|
|
51091
|
+
import { existsSync as existsSync14, readFileSync as readFileSync10 } from "fs";
|
|
50993
51092
|
var DEFAULT_RETRY = {
|
|
50994
51093
|
attempts: 1,
|
|
50995
51094
|
backoff_ms: 0
|
|
@@ -51097,7 +51196,7 @@ function classifyLog(text) {
|
|
|
51097
51196
|
async function sleep2(ms) {
|
|
51098
51197
|
if (ms <= 0)
|
|
51099
51198
|
return;
|
|
51100
|
-
await new Promise((
|
|
51199
|
+
await new Promise((resolve14) => setTimeout(resolve14, ms));
|
|
51101
51200
|
}
|
|
51102
51201
|
async function runCommandProvider(provider, input) {
|
|
51103
51202
|
const commandTemplate = input.command || provider.command;
|
|
@@ -51152,7 +51251,7 @@ Timed out after ${provider.timeout_ms}ms`);
|
|
|
51152
51251
|
};
|
|
51153
51252
|
}
|
|
51154
51253
|
function runCiLogProvider(input) {
|
|
51155
|
-
const text = input.log_text ?? (input.log_path &&
|
|
51254
|
+
const text = input.log_text ?? (input.log_path && existsSync14(input.log_path) ? readFileSync10(input.log_path, "utf-8") : "");
|
|
51156
51255
|
return {
|
|
51157
51256
|
status: classifyLog(text),
|
|
51158
51257
|
attempts: 1,
|
|
@@ -51164,7 +51263,7 @@ function runBrowserProvider(input) {
|
|
|
51164
51263
|
if (!input.artifact_path) {
|
|
51165
51264
|
return { status: "unknown", attempts: 1, exit_code: null, output_summary: "browser provider needs a screenshot or artifact path" };
|
|
51166
51265
|
}
|
|
51167
|
-
if (!
|
|
51266
|
+
if (!existsSync14(input.artifact_path)) {
|
|
51168
51267
|
return { status: "failed", attempts: 1, exit_code: null, output_summary: `artifact not found: ${input.artifact_path}` };
|
|
51169
51268
|
}
|
|
51170
51269
|
return {
|
|
@@ -51458,9 +51557,9 @@ init_database();
|
|
|
51458
51557
|
init_tasks();
|
|
51459
51558
|
init_task_runs();
|
|
51460
51559
|
init_config2();
|
|
51461
|
-
import { relative as relative3, resolve as
|
|
51560
|
+
import { relative as relative3, resolve as resolve14 } from "path";
|
|
51462
51561
|
function normalizePath4(path) {
|
|
51463
|
-
return
|
|
51562
|
+
return resolve14(path);
|
|
51464
51563
|
}
|
|
51465
51564
|
function unique4(values) {
|
|
51466
51565
|
return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));
|
|
@@ -51515,7 +51614,7 @@ function commandMatches(commands, pattern) {
|
|
|
51515
51614
|
}
|
|
51516
51615
|
function pathMatches(paths, pattern, root) {
|
|
51517
51616
|
return paths.filter((path) => {
|
|
51518
|
-
const candidate = path.startsWith("/") ? path :
|
|
51617
|
+
const candidate = path.startsWith("/") ? path : resolve14(root, path);
|
|
51519
51618
|
if (!isPathInside3(root, candidate))
|
|
51520
51619
|
return matchesPattern4(path, pattern);
|
|
51521
51620
|
return matchesPattern4(path, pattern) || matchesPattern4(relative3(root, candidate), pattern);
|
|
@@ -51810,20 +51909,20 @@ function resourceDiagnostics() {
|
|
|
51810
51909
|
}
|
|
51811
51910
|
// src/lib/sandbox-profiles.ts
|
|
51812
51911
|
init_sync_utils();
|
|
51813
|
-
import { existsSync as
|
|
51814
|
-
import { join as
|
|
51912
|
+
import { existsSync as existsSync15, readFileSync as readFileSync11, writeFileSync as writeFileSync9, mkdirSync as mkdirSync11 } from "fs";
|
|
51913
|
+
import { join as join14, dirname as dirname9 } from "path";
|
|
51815
51914
|
var SANDBOX_PROFILE_VERSION = "todos.sandbox-profile.v1";
|
|
51816
51915
|
function getProfilesPath() {
|
|
51817
51916
|
if (process.env["TODOS_SANDBOX_PROFILES_PATH"]) {
|
|
51818
51917
|
return process.env["TODOS_SANDBOX_PROFILES_PATH"];
|
|
51819
51918
|
}
|
|
51820
|
-
const localDir =
|
|
51821
|
-
const local =
|
|
51822
|
-
if (
|
|
51919
|
+
const localDir = join14(process.cwd(), ".todos");
|
|
51920
|
+
const local = join14(localDir, "sandbox-profiles.json");
|
|
51921
|
+
if (existsSync15(localDir))
|
|
51823
51922
|
return local;
|
|
51824
|
-
if (
|
|
51923
|
+
if (existsSync15(local))
|
|
51825
51924
|
return local;
|
|
51826
|
-
return
|
|
51925
|
+
return join14(getTodosGlobalDir(), "sandbox-profiles.json");
|
|
51827
51926
|
}
|
|
51828
51927
|
var cached2 = null;
|
|
51829
51928
|
function resetSandboxProfileCache() {
|
|
@@ -51855,7 +51954,7 @@ function loadSandboxProfiles() {
|
|
|
51855
51954
|
if (cached2)
|
|
51856
51955
|
return cached2;
|
|
51857
51956
|
const path = getProfilesPath();
|
|
51858
|
-
if (!
|
|
51957
|
+
if (!existsSync15(path)) {
|
|
51859
51958
|
cached2 = getDefaultSandboxProfiles();
|
|
51860
51959
|
return cached2;
|
|
51861
51960
|
}
|
|
@@ -52235,9 +52334,9 @@ init_task_commits();
|
|
|
52235
52334
|
|
|
52236
52335
|
// src/lib/git-traceability.ts
|
|
52237
52336
|
init_task_commits();
|
|
52238
|
-
import { existsSync as
|
|
52337
|
+
import { existsSync as existsSync16, readFileSync as readFileSync12 } from "fs";
|
|
52239
52338
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
52240
|
-
import { resolve as
|
|
52339
|
+
import { resolve as resolve15 } from "path";
|
|
52241
52340
|
var GIT_TRACEABILITY_SCHEMA_VERSION = "todos.git_traceability.v1";
|
|
52242
52341
|
function runGit(args, cwd) {
|
|
52243
52342
|
const result = spawnSync2("git", args, { cwd, encoding: "utf8" });
|
|
@@ -52280,8 +52379,8 @@ function inspectGitCommit(sha, cwd) {
|
|
|
52280
52379
|
};
|
|
52281
52380
|
}
|
|
52282
52381
|
function loadCiSnapshot(path) {
|
|
52283
|
-
const target = path ?
|
|
52284
|
-
if (!
|
|
52382
|
+
const target = path ? resolve15(path) : resolve15(process.cwd(), ".todos", "ci-snapshot.json");
|
|
52383
|
+
if (!existsSync16(target))
|
|
52285
52384
|
return null;
|
|
52286
52385
|
try {
|
|
52287
52386
|
const parsed = JSON.parse(readFileSync12(target, "utf8"));
|
|
@@ -52377,8 +52476,8 @@ function formatTraceabilityReport(report) {
|
|
|
52377
52476
|
`);
|
|
52378
52477
|
}
|
|
52379
52478
|
// src/lib/mention-resolver.ts
|
|
52380
|
-
import { existsSync as
|
|
52381
|
-
import { basename as basename4, isAbsolute, join as
|
|
52479
|
+
import { existsSync as existsSync17, readdirSync as readdirSync3, readFileSync as readFileSync13, statSync as statSync6 } from "fs";
|
|
52480
|
+
import { basename as basename4, isAbsolute, join as join15, relative as relative4, resolve as resolve16, sep as sep2 } from "path";
|
|
52382
52481
|
init_database();
|
|
52383
52482
|
init_plans();
|
|
52384
52483
|
init_task_runs();
|
|
@@ -52457,7 +52556,7 @@ function backlink(kind, key2, label, target = key2) {
|
|
|
52457
52556
|
return { kind, key: key2, label, target };
|
|
52458
52557
|
}
|
|
52459
52558
|
function normalizeWorkspace(workspace) {
|
|
52460
|
-
return
|
|
52559
|
+
return resolve16(workspace || process.cwd());
|
|
52461
52560
|
}
|
|
52462
52561
|
function isInside(root, absolutePath) {
|
|
52463
52562
|
const rel = relative4(root, absolutePath);
|
|
@@ -52525,14 +52624,14 @@ function resolveFile(parsed, workspace) {
|
|
|
52525
52624
|
resolution.warnings.push("path is empty or escapes the workspace");
|
|
52526
52625
|
return resolution;
|
|
52527
52626
|
}
|
|
52528
|
-
const absolutePath =
|
|
52627
|
+
const absolutePath = resolve16(workspace, relPath);
|
|
52529
52628
|
if (!isInside(workspace, absolutePath)) {
|
|
52530
52629
|
resolution.path = relPath;
|
|
52531
52630
|
resolution.warnings.push("path escapes the workspace");
|
|
52532
52631
|
return resolution;
|
|
52533
52632
|
}
|
|
52534
52633
|
resolution.path = relPath;
|
|
52535
|
-
if (!
|
|
52634
|
+
if (!existsSync17(absolutePath)) {
|
|
52536
52635
|
resolution.warnings.push("file does not exist in the local workspace");
|
|
52537
52636
|
return resolution;
|
|
52538
52637
|
}
|
|
@@ -52565,7 +52664,7 @@ function walkSourceFiles(root, current = root, files = []) {
|
|
|
52565
52664
|
if (SKIP_DIRS.has(entry2.name))
|
|
52566
52665
|
continue;
|
|
52567
52666
|
}
|
|
52568
|
-
const absolutePath =
|
|
52667
|
+
const absolutePath = join15(current, entry2.name);
|
|
52569
52668
|
if (entry2.isDirectory()) {
|
|
52570
52669
|
if (!SKIP_DIRS.has(entry2.name))
|
|
52571
52670
|
walkSourceFiles(root, absolutePath, files);
|
|
@@ -53918,7 +54017,7 @@ function getAdapterDocsFingerprint() {
|
|
|
53918
54017
|
// src/lib/inbox-intake.ts
|
|
53919
54018
|
init_database();
|
|
53920
54019
|
init_tasks();
|
|
53921
|
-
import { existsSync as
|
|
54020
|
+
import { existsSync as existsSync18, readFileSync as readFileSync14 } from "fs";
|
|
53922
54021
|
import { basename as basename5 } from "path";
|
|
53923
54022
|
import { createHash as createHash19 } from "crypto";
|
|
53924
54023
|
init_secret_redaction();
|
|
@@ -53964,7 +54063,7 @@ function loadRawContent(input) {
|
|
|
53964
54063
|
}
|
|
53965
54064
|
}
|
|
53966
54065
|
if (input.file_path) {
|
|
53967
|
-
if (!
|
|
54066
|
+
if (!existsSync18(input.file_path))
|
|
53968
54067
|
throw new Error(`File not found: ${input.file_path}`);
|
|
53969
54068
|
const raw = readFileSync14(input.file_path, "utf8");
|
|
53970
54069
|
const name = basename5(input.file_path).toLowerCase();
|
|
@@ -54585,7 +54684,7 @@ function formatNlIntakePreviewText(preview) {
|
|
|
54585
54684
|
// src/lib/issue-importers.ts
|
|
54586
54685
|
init_database();
|
|
54587
54686
|
init_tasks();
|
|
54588
|
-
import { existsSync as
|
|
54687
|
+
import { existsSync as existsSync19, readFileSync as readFileSync15 } from "fs";
|
|
54589
54688
|
var ISSUE_IMPORT_SCHEMA = "todos.issue_import.v1";
|
|
54590
54689
|
var ISSUE_SOURCES = ["github", "linear", "jira", "auto"];
|
|
54591
54690
|
var GITHUB_LABEL_PRIORITY = {
|
|
@@ -54804,7 +54903,7 @@ function parseIssueExport(data, source9 = "auto") {
|
|
|
54804
54903
|
return normalized;
|
|
54805
54904
|
}
|
|
54806
54905
|
function loadIssueExportFromFile(path) {
|
|
54807
|
-
if (!
|
|
54906
|
+
if (!existsSync19(path))
|
|
54808
54907
|
throw new Error(`File not found: ${path}`);
|
|
54809
54908
|
return JSON.parse(readFileSync15(path, "utf8"));
|
|
54810
54909
|
}
|
|
@@ -54965,8 +55064,8 @@ todos import issues ./linear.json --source linear --dry-run
|
|
|
54965
55064
|
init_sync_utils();
|
|
54966
55065
|
init_database();
|
|
54967
55066
|
init_secret_redaction();
|
|
54968
|
-
import { existsSync as
|
|
54969
|
-
import { join as
|
|
55067
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync12, writeFileSync as writeFileSync10 } from "fs";
|
|
55068
|
+
import { join as join16, dirname as dirname10 } from "path";
|
|
54970
55069
|
var RUN_RECORD_SCHEMA = "todos.run_record.v1";
|
|
54971
55070
|
var RUN_RECORD_STATUSES = ["active", "completed", "failed", "archived"];
|
|
54972
55071
|
function parseJsonArray3(raw, fallback = []) {
|
|
@@ -55159,7 +55258,7 @@ function buildRunReplayBundle(id, db) {
|
|
|
55159
55258
|
}
|
|
55160
55259
|
function exportRunReplay(id, outputPath, db) {
|
|
55161
55260
|
const bundle = buildRunReplayBundle(id, db);
|
|
55162
|
-
const path = outputPath ??
|
|
55261
|
+
const path = outputPath ?? join16(process.cwd(), ".todos", "replays", `${id.slice(0, 8)}.json`);
|
|
55163
55262
|
mkdirSync12(dirname10(path), { recursive: true });
|
|
55164
55263
|
writeFileSync10(path, JSON.stringify(bundle, null, 2));
|
|
55165
55264
|
const d = db || getDatabase();
|
|
@@ -55199,15 +55298,15 @@ function formatRunRecordMarkdown(record) {
|
|
|
55199
55298
|
`;
|
|
55200
55299
|
}
|
|
55201
55300
|
function getDefaultReplayDir() {
|
|
55202
|
-
const local =
|
|
55203
|
-
if (
|
|
55301
|
+
const local = join16(process.cwd(), ".todos", "replays");
|
|
55302
|
+
if (existsSync20(join16(process.cwd(), ".todos")))
|
|
55204
55303
|
return local;
|
|
55205
|
-
return
|
|
55304
|
+
return join16(getTodosGlobalDir(), "replays");
|
|
55206
55305
|
}
|
|
55207
55306
|
// src/lib/release-checks.ts
|
|
55208
55307
|
init_secret_redaction();
|
|
55209
|
-
import { existsSync as
|
|
55210
|
-
import { join as
|
|
55308
|
+
import { existsSync as existsSync21, readFileSync as readFileSync16, readdirSync as readdirSync4, statSync as statSync7 } from "fs";
|
|
55309
|
+
import { join as join17, relative as relative5 } from "path";
|
|
55211
55310
|
var RELEASE_CHECK_SCHEMA = "todos.release_check.v1";
|
|
55212
55311
|
var FORBIDDEN_DIST_PATTERNS = [
|
|
55213
55312
|
{
|
|
@@ -55220,16 +55319,16 @@ var FORBIDDEN_DIST_PATTERNS = [
|
|
|
55220
55319
|
];
|
|
55221
55320
|
var REQUIRED_BINS = ["todos", "todos-mcp", "todos-serve"];
|
|
55222
55321
|
function readPackageJson3(root) {
|
|
55223
|
-
const path =
|
|
55224
|
-
if (!
|
|
55322
|
+
const path = join17(root, "package.json");
|
|
55323
|
+
if (!existsSync21(path))
|
|
55225
55324
|
throw new Error(`package.json not found in ${root}`);
|
|
55226
55325
|
return JSON.parse(readFileSync16(path, "utf8"));
|
|
55227
55326
|
}
|
|
55228
55327
|
function walkFiles(dir, acc = []) {
|
|
55229
|
-
if (!
|
|
55328
|
+
if (!existsSync21(dir))
|
|
55230
55329
|
return acc;
|
|
55231
55330
|
for (const entry2 of readdirSync4(dir)) {
|
|
55232
|
-
const full =
|
|
55331
|
+
const full = join17(dir, entry2);
|
|
55233
55332
|
const st = statSync7(full);
|
|
55234
55333
|
if (st.isDirectory())
|
|
55235
55334
|
walkFiles(full, acc);
|
|
@@ -55247,8 +55346,8 @@ function auditPackageContents(root) {
|
|
|
55247
55346
|
checks.push({ id: "files_dist", severity: "error", message: "package.json files must include dist" });
|
|
55248
55347
|
}
|
|
55249
55348
|
for (const pattern of files) {
|
|
55250
|
-
const target =
|
|
55251
|
-
if (!
|
|
55349
|
+
const target = join17(root, pattern);
|
|
55350
|
+
if (!existsSync21(target)) {
|
|
55252
55351
|
checks.push({ id: `files_missing_${pattern}`, severity: "error", message: `Published file path missing: ${pattern}` });
|
|
55253
55352
|
}
|
|
55254
55353
|
}
|
|
@@ -55262,8 +55361,8 @@ function auditPackageContents(root) {
|
|
|
55262
55361
|
checks.push({ id: `bin_${name}`, severity: "error", message: `Missing bin entry: ${name}` });
|
|
55263
55362
|
continue;
|
|
55264
55363
|
}
|
|
55265
|
-
const binPath =
|
|
55266
|
-
if (!
|
|
55364
|
+
const binPath = join17(root, rel);
|
|
55365
|
+
if (!existsSync21(binPath)) {
|
|
55267
55366
|
checks.push({ id: `bin_path_${name}`, severity: "error", message: `Bin file missing: ${rel}` });
|
|
55268
55367
|
} else {
|
|
55269
55368
|
checks.push({ id: `bin_ok_${name}`, severity: "info", message: `Bin present: ${name} \u2192 ${rel}` });
|
|
@@ -55280,8 +55379,8 @@ function auditPackageContents(root) {
|
|
|
55280
55379
|
}
|
|
55281
55380
|
function scanDistArtifacts(root) {
|
|
55282
55381
|
const checks = [];
|
|
55283
|
-
const distDir =
|
|
55284
|
-
if (!
|
|
55382
|
+
const distDir = join17(root, "dist");
|
|
55383
|
+
if (!existsSync21(distDir)) {
|
|
55285
55384
|
checks.push({ id: "dist_missing", severity: "error", message: "dist/ directory not found \u2014 run bun run build" });
|
|
55286
55385
|
return checks;
|
|
55287
55386
|
}
|
|
@@ -55591,15 +55690,15 @@ function renderReleaseNotesMarkdown(document) {
|
|
|
55591
55690
|
// src/lib/db-backup.ts
|
|
55592
55691
|
init_database();
|
|
55593
55692
|
init_migrations();
|
|
55594
|
-
import { existsSync as
|
|
55595
|
-
import { dirname as dirname11, join as
|
|
55693
|
+
import { existsSync as existsSync22, copyFileSync, mkdirSync as mkdirSync13, readFileSync as readFileSync17, renameSync, statSync as statSync8, writeFileSync as writeFileSync11, unlinkSync } from "fs";
|
|
55694
|
+
import { dirname as dirname11, join as join18, resolve as resolve17 } from "path";
|
|
55596
55695
|
import { Database as Database4 } from "bun:sqlite";
|
|
55597
55696
|
var DB_BACKUP_SCHEMA = "todos.db_backup.v1";
|
|
55598
55697
|
function resolveDbPath(dbPath) {
|
|
55599
55698
|
if (dbPath)
|
|
55600
|
-
return
|
|
55699
|
+
return resolve17(dbPath);
|
|
55601
55700
|
if (process.env["TODOS_DB_PATH"] && process.env["TODOS_DB_PATH"] !== ":memory:") {
|
|
55602
|
-
return
|
|
55701
|
+
return resolve17(process.env["TODOS_DB_PATH"]);
|
|
55603
55702
|
}
|
|
55604
55703
|
const db = getDatabase();
|
|
55605
55704
|
const filename = db.filename;
|
|
@@ -55609,7 +55708,7 @@ function resolveDbPath(dbPath) {
|
|
|
55609
55708
|
}
|
|
55610
55709
|
function backupDatabase(outputPath, sourcePath) {
|
|
55611
55710
|
const source9 = resolveDbPath(sourcePath);
|
|
55612
|
-
if (!
|
|
55711
|
+
if (!existsSync22(source9))
|
|
55613
55712
|
throw new Error(`Database not found: ${source9}`);
|
|
55614
55713
|
mkdirSync13(dirname11(outputPath), { recursive: true });
|
|
55615
55714
|
closeDatabase();
|
|
@@ -55632,13 +55731,13 @@ function backupDatabase(outputPath, sourcePath) {
|
|
|
55632
55731
|
};
|
|
55633
55732
|
}
|
|
55634
55733
|
function restoreDatabase(backupPath, targetPath) {
|
|
55635
|
-
if (!
|
|
55734
|
+
if (!existsSync22(backupPath))
|
|
55636
55735
|
throw new Error(`Backup not found: ${backupPath}`);
|
|
55637
55736
|
const integrity = checkDatabaseIntegrity(backupPath);
|
|
55638
55737
|
if (!integrity.ok) {
|
|
55639
55738
|
throw new Error(`Backup failed integrity check: ${integrity.errors.join("; ")}`);
|
|
55640
55739
|
}
|
|
55641
|
-
const target = targetPath ?
|
|
55740
|
+
const target = targetPath ? resolve17(targetPath) : resolveDbPath();
|
|
55642
55741
|
mkdirSync13(dirname11(target), { recursive: true });
|
|
55643
55742
|
closeDatabase();
|
|
55644
55743
|
const staging = `${target}.restore.tmp`;
|
|
@@ -55648,7 +55747,7 @@ function restoreDatabase(backupPath, targetPath) {
|
|
|
55648
55747
|
copyFileSync(backupPath, staging);
|
|
55649
55748
|
for (const sidecar of [`${target}-wal`, `${target}-shm`]) {
|
|
55650
55749
|
try {
|
|
55651
|
-
if (
|
|
55750
|
+
if (existsSync22(sidecar))
|
|
55652
55751
|
unlinkSync(sidecar);
|
|
55653
55752
|
} catch {}
|
|
55654
55753
|
}
|
|
@@ -55663,9 +55762,9 @@ function restoreDatabase(backupPath, targetPath) {
|
|
|
55663
55762
|
};
|
|
55664
55763
|
}
|
|
55665
55764
|
function checkDatabaseIntegrity(dbPath) {
|
|
55666
|
-
const path = dbPath ?
|
|
55765
|
+
const path = dbPath ? resolve17(dbPath) : resolveDbPath();
|
|
55667
55766
|
const errors2 = [];
|
|
55668
|
-
if (!
|
|
55767
|
+
if (!existsSync22(path)) {
|
|
55669
55768
|
return {
|
|
55670
55769
|
schema_version: DB_BACKUP_SCHEMA,
|
|
55671
55770
|
path,
|
|
@@ -55728,7 +55827,7 @@ function checkDatabaseIntegrity(dbPath) {
|
|
|
55728
55827
|
};
|
|
55729
55828
|
}
|
|
55730
55829
|
function compactDatabase(dbPath) {
|
|
55731
|
-
const path = dbPath ?
|
|
55830
|
+
const path = dbPath ? resolve17(dbPath) : resolveDbPath();
|
|
55732
55831
|
const before = statSync8(path).size;
|
|
55733
55832
|
const db = new Database4(path);
|
|
55734
55833
|
db.exec("VACUUM");
|
|
@@ -55738,7 +55837,7 @@ function compactDatabase(dbPath) {
|
|
|
55738
55837
|
return { path, bytes_before: before, bytes_after: after };
|
|
55739
55838
|
}
|
|
55740
55839
|
function migrationDryRun(dbPath) {
|
|
55741
|
-
const path = dbPath ?
|
|
55840
|
+
const path = dbPath ? resolve17(dbPath) : resolveDbPath();
|
|
55742
55841
|
const db = new Database4(path, { readonly: true });
|
|
55743
55842
|
let current = 0;
|
|
55744
55843
|
try {
|
|
@@ -55762,13 +55861,13 @@ function migrationDryRun(dbPath) {
|
|
|
55762
55861
|
};
|
|
55763
55862
|
}
|
|
55764
55863
|
function defaultBackupPath(dbPath) {
|
|
55765
|
-
const base = dbPath ? dirname11(
|
|
55864
|
+
const base = dbPath ? dirname11(resolve17(dbPath)) : dirname11(resolveDbPath());
|
|
55766
55865
|
const stamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
55767
|
-
return
|
|
55866
|
+
return join18(base, "backups", `todos-${stamp}.db`);
|
|
55768
55867
|
}
|
|
55769
55868
|
function readBackupManifest(backupPath) {
|
|
55770
55869
|
const manifestPath = `${backupPath}.json`;
|
|
55771
|
-
if (!
|
|
55870
|
+
if (!existsSync22(manifestPath))
|
|
55772
55871
|
return null;
|
|
55773
55872
|
try {
|
|
55774
55873
|
return JSON.parse(readFileSync17(manifestPath, "utf8"));
|
|
@@ -56289,15 +56388,15 @@ ${SCHEMA_ENTITIES.map((e) => `- **${e}**: \`${JSON_SCHEMAS[e].schema_version}\``
|
|
|
56289
56388
|
}
|
|
56290
56389
|
function exportSchemasToDirectory(dir) {
|
|
56291
56390
|
const { mkdirSync: mkdirSync14, writeFileSync: writeFileSync12 } = __require("fs");
|
|
56292
|
-
const { join:
|
|
56391
|
+
const { join: join19 } = __require("path");
|
|
56293
56392
|
mkdirSync14(dir, { recursive: true });
|
|
56294
56393
|
const written = [];
|
|
56295
56394
|
for (const entity of SCHEMA_ENTITIES) {
|
|
56296
|
-
const path =
|
|
56395
|
+
const path = join19(dir, `${entity}.${JSON_SCHEMAS[entity].schema_version.replace(/\./g, "-")}.json`);
|
|
56297
56396
|
writeFileSync12(path, JSON.stringify(JSON_SCHEMAS[entity], null, 2));
|
|
56298
56397
|
written.push(path);
|
|
56299
56398
|
}
|
|
56300
|
-
const catalogPath =
|
|
56399
|
+
const catalogPath = join19(dir, "catalog.json");
|
|
56301
56400
|
writeFileSync12(catalogPath, JSON.stringify({
|
|
56302
56401
|
catalog_version: JSON_SCHEMA_CATALOG_VERSION,
|
|
56303
56402
|
semver: SCHEMA_SEMVER,
|
|
@@ -58832,7 +58931,7 @@ init_templates();
|
|
|
58832
58931
|
init_database();
|
|
58833
58932
|
init_templates();
|
|
58834
58933
|
import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync14 } from "fs";
|
|
58835
|
-
import { join as
|
|
58934
|
+
import { join as join19 } from "path";
|
|
58836
58935
|
var BUILTIN_TEMPLATE_LIBRARY_VERSION = "2026-05-21";
|
|
58837
58936
|
var BUILTIN_TEMPLATE_LIBRARY_SOURCE = "bundled-local-template-library";
|
|
58838
58937
|
var TEMPLATE_LIBRARY_SCHEMA = "todos.template_library.v1";
|
|
@@ -59108,7 +59207,7 @@ function writeBuiltinTemplateFiles(directory) {
|
|
|
59108
59207
|
mkdirSync16(directory, { recursive: true });
|
|
59109
59208
|
const files = [];
|
|
59110
59209
|
for (const entry2 of exportBuiltinTemplateFiles()) {
|
|
59111
|
-
const path =
|
|
59210
|
+
const path = join19(directory, entry2.filename);
|
|
59112
59211
|
writeFileSync14(path, `${JSON.stringify(entry2.template, null, 2)}
|
|
59113
59212
|
`, "utf-8");
|
|
59114
59213
|
files.push(path);
|
|
@@ -59400,9 +59499,9 @@ init_tasks();
|
|
|
59400
59499
|
init_redaction();
|
|
59401
59500
|
init_sync_utils();
|
|
59402
59501
|
import { createHash as createHash20 } from "crypto";
|
|
59403
|
-
import { existsSync as
|
|
59502
|
+
import { existsSync as existsSync23, readFileSync as readFileSync20, statSync as statSync9 } from "fs";
|
|
59404
59503
|
import { hostname as hostname3, platform, arch } from "os";
|
|
59405
|
-
import { dirname as dirname15, join as
|
|
59504
|
+
import { dirname as dirname15, join as join20, resolve as resolve18 } from "path";
|
|
59406
59505
|
import { tmpdir as tmpdir3 } from "os";
|
|
59407
59506
|
var MANIFEST_FILES = ["package.json", "dashboard/package.json", "sdk/package.json"];
|
|
59408
59507
|
var LOCKFILES = ["bun.lock", "bun.lockb", "package-lock.json", "npm-shrinkwrap.json"];
|
|
@@ -59424,8 +59523,8 @@ function sha2566(value) {
|
|
|
59424
59523
|
return createHash20("sha256").update(value).digest("hex");
|
|
59425
59524
|
}
|
|
59426
59525
|
function fileRecord(root, relativePath) {
|
|
59427
|
-
const path =
|
|
59428
|
-
if (!
|
|
59526
|
+
const path = join20(root, relativePath);
|
|
59527
|
+
if (!existsSync23(path))
|
|
59429
59528
|
return null;
|
|
59430
59529
|
const stat = statSync9(path);
|
|
59431
59530
|
if (!stat.isFile())
|
|
@@ -59437,7 +59536,7 @@ function manifestRecord(root, relativePath) {
|
|
|
59437
59536
|
const base = fileRecord(root, relativePath);
|
|
59438
59537
|
if (!base)
|
|
59439
59538
|
return null;
|
|
59440
|
-
const parsed = readJsonFile(
|
|
59539
|
+
const parsed = readJsonFile(join20(root, relativePath));
|
|
59441
59540
|
if (!parsed)
|
|
59442
59541
|
return { ...base, redacted: {} };
|
|
59443
59542
|
const redacted = redactValue({
|
|
@@ -59532,15 +59631,15 @@ function commandEnv(env, includeValues) {
|
|
|
59532
59631
|
function defaultSnapshotDir() {
|
|
59533
59632
|
const dbPath = getDatabasePath();
|
|
59534
59633
|
if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
|
|
59535
|
-
return
|
|
59536
|
-
return
|
|
59634
|
+
return join20(tmpdir3(), "hasna-todos", "environment-snapshots");
|
|
59635
|
+
return join20(dirname15(resolve18(dbPath)), "environment-snapshots");
|
|
59537
59636
|
}
|
|
59538
59637
|
function snapshotWithId(snapshot) {
|
|
59539
59638
|
const digest3 = sha2566(JSON.stringify(snapshot)).slice(0, 24);
|
|
59540
59639
|
return { id: `env_${digest3}`, ...snapshot };
|
|
59541
59640
|
}
|
|
59542
59641
|
function captureEnvironmentSnapshot(input = {}) {
|
|
59543
|
-
const root =
|
|
59642
|
+
const root = resolve18(input.root || process.cwd());
|
|
59544
59643
|
const env = input.env || process.env;
|
|
59545
59644
|
const warnings = [];
|
|
59546
59645
|
const manifests = MANIFEST_FILES.map((file) => manifestRecord(root, file)).filter((file) => Boolean(file));
|
|
@@ -59580,13 +59679,13 @@ function captureEnvironmentSnapshot(input = {}) {
|
|
|
59580
59679
|
});
|
|
59581
59680
|
}
|
|
59582
59681
|
function writeEnvironmentSnapshot(snapshot, outputPath) {
|
|
59583
|
-
const path = outputPath ?
|
|
59682
|
+
const path = outputPath ? resolve18(outputPath) : join20(defaultSnapshotDir(), `${snapshot.id}.json`);
|
|
59584
59683
|
ensureDir(dirname15(path));
|
|
59585
59684
|
writeJsonFile(path, snapshot);
|
|
59586
59685
|
return path;
|
|
59587
59686
|
}
|
|
59588
59687
|
function readEnvironmentSnapshot(path) {
|
|
59589
|
-
const snapshot = readJsonFile(
|
|
59688
|
+
const snapshot = readJsonFile(resolve18(path));
|
|
59590
59689
|
if (!snapshot || snapshot.schema_version !== 1 || typeof snapshot.id !== "string") {
|
|
59591
59690
|
throw new Error(`Invalid environment snapshot: ${path}`);
|
|
59592
59691
|
}
|
|
@@ -59675,7 +59774,7 @@ init_projects();
|
|
|
59675
59774
|
init_plans();
|
|
59676
59775
|
import { createHash as createHash21 } from "crypto";
|
|
59677
59776
|
import { mkdirSync as mkdirSync18, writeFileSync as writeFileSync16 } from "fs";
|
|
59678
|
-
import { dirname as dirname16, join as
|
|
59777
|
+
import { dirname as dirname16, join as join21 } from "path";
|
|
59679
59778
|
var DECISION_RECORD_SCHEMA = "todos.decision_record.v1";
|
|
59680
59779
|
var KNOWLEDGE_SNAPSHOT_SCHEMA = "todos.knowledge_snapshot.v1";
|
|
59681
59780
|
var DECISION_STATUSES = ["proposed", "accepted", "deprecated", "superseded", "rejected"];
|
|
@@ -59905,7 +60004,7 @@ function exportDecisionRecord(id, outputPath, format = "markdown", db) {
|
|
|
59905
60004
|
if (!record)
|
|
59906
60005
|
throw new Error(`Decision record not found: ${id}`);
|
|
59907
60006
|
const content = format === "markdown" ? formatDecisionRecordMarkdown(record) : JSON.stringify(record, null, 2);
|
|
59908
|
-
const path = outputPath ??
|
|
60007
|
+
const path = outputPath ?? join21(process.cwd(), ".todos", "decisions", `${record.short_ref}.${format === "markdown" ? "md" : "json"}`);
|
|
59909
60008
|
mkdirSync18(dirname16(path), { recursive: true });
|
|
59910
60009
|
writeFileSync16(path, content, "utf8");
|
|
59911
60010
|
return { path, content };
|
|
@@ -60053,7 +60152,7 @@ function exportKnowledgeSnapshot(id, outputPath, format = "markdown", db) {
|
|
|
60053
60152
|
throw new Error(`Knowledge snapshot not found: ${id}`);
|
|
60054
60153
|
const content = format === "markdown" ? formatKnowledgeSnapshotMarkdown(record) : JSON.stringify(record, null, 2);
|
|
60055
60154
|
const slug = record.title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
|
|
60056
|
-
const path = outputPath ??
|
|
60155
|
+
const path = outputPath ?? join21(process.cwd(), ".todos", "knowledge", `${slug || record.id.slice(0, 8)}.${format === "markdown" ? "md" : "json"}`);
|
|
60057
60156
|
mkdirSync18(dirname16(path), { recursive: true });
|
|
60058
60157
|
writeFileSync16(path, content, "utf8");
|
|
60059
60158
|
return { path, content };
|
|
@@ -60352,8 +60451,8 @@ todos report export --kind retrospective --days 14 --format markdown --out retro
|
|
|
60352
60451
|
`;
|
|
60353
60452
|
}
|
|
60354
60453
|
// src/lib/command-aliases.ts
|
|
60355
|
-
import { existsSync as
|
|
60356
|
-
import { join as
|
|
60454
|
+
import { existsSync as existsSync24, readFileSync as readFileSync21, writeFileSync as writeFileSync18, mkdirSync as mkdirSync20 } from "fs";
|
|
60455
|
+
import { join as join22 } from "path";
|
|
60357
60456
|
var COMMAND_ALIASES_SCHEMA = "todos.command_aliases.v1";
|
|
60358
60457
|
var RESERVED = new Set([...listTopLevelCommands(), "help", "version", "alias", "shortcuts"]);
|
|
60359
60458
|
var BUILTIN_SHORTCUTS = [
|
|
@@ -60372,7 +60471,7 @@ var BUILTIN_SHORTCUTS = [
|
|
|
60372
60471
|
{ pattern: /^reports?$/, argv: ["report", "docs"], explain: "Report export documentation" }
|
|
60373
60472
|
];
|
|
60374
60473
|
function aliasesPath(cwd = process.cwd()) {
|
|
60375
|
-
return
|
|
60474
|
+
return join22(cwd, ".todos", "aliases.json");
|
|
60376
60475
|
}
|
|
60377
60476
|
function emptyStore() {
|
|
60378
60477
|
return { schema_version: COMMAND_ALIASES_SCHEMA, aliases: {}, updated_at: new Date(0).toISOString() };
|
|
@@ -60389,7 +60488,7 @@ function validateAliasName(name) {
|
|
|
60389
60488
|
}
|
|
60390
60489
|
function loadAliasStore(cwd) {
|
|
60391
60490
|
const path = aliasesPath(cwd);
|
|
60392
|
-
if (!
|
|
60491
|
+
if (!existsSync24(path))
|
|
60393
60492
|
return emptyStore();
|
|
60394
60493
|
const parsed = JSON.parse(readFileSync21(path, "utf8"));
|
|
60395
60494
|
if (parsed.schema_version !== COMMAND_ALIASES_SCHEMA) {
|
|
@@ -60399,7 +60498,7 @@ function loadAliasStore(cwd) {
|
|
|
60399
60498
|
}
|
|
60400
60499
|
function saveAliasStore(store, cwd) {
|
|
60401
60500
|
const path = aliasesPath(cwd);
|
|
60402
|
-
mkdirSync20(
|
|
60501
|
+
mkdirSync20(join22(path, ".."), { recursive: true });
|
|
60403
60502
|
store.updated_at = new Date().toISOString();
|
|
60404
60503
|
writeFileSync18(path, JSON.stringify(store, null, 2), "utf8");
|
|
60405
60504
|
}
|
|
@@ -61054,18 +61153,18 @@ function createBranchWorkPlan(input, db) {
|
|
|
61054
61153
|
init_database();
|
|
61055
61154
|
init_templates();
|
|
61056
61155
|
init_plans();
|
|
61057
|
-
import { existsSync as
|
|
61058
|
-
import { join as
|
|
61156
|
+
import { existsSync as existsSync25, readFileSync as readFileSync22, writeFileSync as writeFileSync19, mkdirSync as mkdirSync21 } from "fs";
|
|
61157
|
+
import { join as join23 } from "path";
|
|
61059
61158
|
var USER_SCAFFOLD_SCHEMA = "todos.user_scaffold.v1";
|
|
61060
61159
|
var SCAFFOLD_KINDS = ["task", "project", "plan", "checklist", "contract", "verification_policy"];
|
|
61061
61160
|
function storeDir(cwd = process.cwd()) {
|
|
61062
|
-
return
|
|
61161
|
+
return join23(cwd, ".todos", "scaffolds");
|
|
61063
61162
|
}
|
|
61064
61163
|
function storePath(cwd) {
|
|
61065
|
-
return
|
|
61164
|
+
return join23(storeDir(cwd), "store.json");
|
|
61066
61165
|
}
|
|
61067
61166
|
function versionsDir(cwd) {
|
|
61068
|
-
return
|
|
61167
|
+
return join23(storeDir(cwd), "versions");
|
|
61069
61168
|
}
|
|
61070
61169
|
function slugify4(name) {
|
|
61071
61170
|
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
@@ -61075,7 +61174,7 @@ function emptyStore2() {
|
|
|
61075
61174
|
}
|
|
61076
61175
|
function loadUserScaffoldStore(cwd) {
|
|
61077
61176
|
const path = storePath(cwd);
|
|
61078
|
-
if (!
|
|
61177
|
+
if (!existsSync25(path))
|
|
61079
61178
|
return emptyStore2();
|
|
61080
61179
|
const parsed = JSON.parse(readFileSync22(path, "utf8"));
|
|
61081
61180
|
if (parsed.schema_version !== USER_SCAFFOLD_SCHEMA) {
|
|
@@ -61090,7 +61189,7 @@ function saveUserScaffoldStore(store, cwd) {
|
|
|
61090
61189
|
}
|
|
61091
61190
|
function snapshotVersion(scaffold, cwd) {
|
|
61092
61191
|
mkdirSync21(versionsDir(cwd), { recursive: true });
|
|
61093
|
-
const path =
|
|
61192
|
+
const path = join23(versionsDir(cwd), `${scaffold.id}-v${scaffold.version}.json`);
|
|
61094
61193
|
writeFileSync19(path, JSON.stringify(scaffold, null, 2), "utf8");
|
|
61095
61194
|
}
|
|
61096
61195
|
function listUserScaffolds(kind, cwd) {
|
|
@@ -61337,7 +61436,7 @@ function listLinkedTemplates(db, cwd) {
|
|
|
61337
61436
|
// src/lib/agent-workflow-demo.ts
|
|
61338
61437
|
init_database();
|
|
61339
61438
|
import { mkdtempSync } from "fs";
|
|
61340
|
-
import { join as
|
|
61439
|
+
import { join as join24 } from "path";
|
|
61341
61440
|
import { tmpdir as tmpdir4 } from "os";
|
|
61342
61441
|
init_projects();
|
|
61343
61442
|
init_task_lists();
|
|
@@ -61358,7 +61457,7 @@ function setupEphemeralDemoDb(options = {}) {
|
|
|
61358
61457
|
if (options.db_path) {
|
|
61359
61458
|
db_path = options.db_path;
|
|
61360
61459
|
} else if (options.persist) {
|
|
61361
|
-
db_path =
|
|
61460
|
+
db_path = join24(mkdtempSync(join24(tmpdir4(), "todos-demo-")), "todos.db");
|
|
61362
61461
|
} else {
|
|
61363
61462
|
db_path = ":memory:";
|
|
61364
61463
|
}
|
|
@@ -63695,16 +63794,16 @@ function runSearchView(idOrName, db) {
|
|
|
63695
63794
|
init_tasks();
|
|
63696
63795
|
init_config2();
|
|
63697
63796
|
init_sync_utils();
|
|
63698
|
-
import { existsSync as
|
|
63699
|
-
import { join as
|
|
63797
|
+
import { existsSync as existsSync26, readFileSync as readFileSync23, readdirSync as readdirSync5, writeFileSync as writeFileSync20 } from "fs";
|
|
63798
|
+
import { join as join25 } from "path";
|
|
63700
63799
|
function getTaskListDir(taskListId) {
|
|
63701
|
-
return
|
|
63800
|
+
return join25(HOME, ".claude", "tasks", taskListId);
|
|
63702
63801
|
}
|
|
63703
63802
|
function readClaudeTask(dir, filename) {
|
|
63704
|
-
return readJsonFile(
|
|
63803
|
+
return readJsonFile(join25(dir, filename));
|
|
63705
63804
|
}
|
|
63706
63805
|
function writeClaudeTask(dir, task3) {
|
|
63707
|
-
writeJsonFile(
|
|
63806
|
+
writeJsonFile(join25(dir, `${task3.id}.json`), task3);
|
|
63708
63807
|
}
|
|
63709
63808
|
function toClaudeStatus(status3) {
|
|
63710
63809
|
if (status3 === "pending" || status3 === "in_progress" || status3 === "completed") {
|
|
@@ -63716,14 +63815,14 @@ function toSqliteStatus(status3) {
|
|
|
63716
63815
|
return status3;
|
|
63717
63816
|
}
|
|
63718
63817
|
function readPrefixCounter(dir) {
|
|
63719
|
-
const path =
|
|
63720
|
-
if (!
|
|
63818
|
+
const path = join25(dir, ".prefix-counter");
|
|
63819
|
+
if (!existsSync26(path))
|
|
63721
63820
|
return 0;
|
|
63722
63821
|
const val = parseInt(readFileSync23(path, "utf-8").trim(), 10);
|
|
63723
63822
|
return isNaN(val) ? 0 : val;
|
|
63724
63823
|
}
|
|
63725
63824
|
function writePrefixCounter(dir, value) {
|
|
63726
|
-
writeFileSync20(
|
|
63825
|
+
writeFileSync20(join25(dir, ".prefix-counter"), String(value));
|
|
63727
63826
|
}
|
|
63728
63827
|
function formatPrefixedSubject(title, prefix, counter) {
|
|
63729
63828
|
const padded = String(counter).padStart(5, "0");
|
|
@@ -63750,7 +63849,7 @@ function taskToClaudeTask(task3, claudeTaskId, existingMeta) {
|
|
|
63750
63849
|
}
|
|
63751
63850
|
function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
63752
63851
|
const dir = getTaskListDir(taskListId);
|
|
63753
|
-
if (!
|
|
63852
|
+
if (!existsSync26(dir))
|
|
63754
63853
|
ensureDir(dir);
|
|
63755
63854
|
const filter = {};
|
|
63756
63855
|
if (projectId)
|
|
@@ -63759,7 +63858,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
63759
63858
|
const existingByTodosId = new Map;
|
|
63760
63859
|
const files = listJsonFiles(dir);
|
|
63761
63860
|
for (const f of files) {
|
|
63762
|
-
const path =
|
|
63861
|
+
const path = join25(dir, f);
|
|
63763
63862
|
const ct = readClaudeTask(dir, f);
|
|
63764
63863
|
if (ct?.metadata?.["todos_id"]) {
|
|
63765
63864
|
existingByTodosId.set(ct.metadata["todos_id"], { task: ct, mtimeMs: getFileMtimeMs(path) });
|
|
@@ -63848,7 +63947,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
63848
63947
|
}
|
|
63849
63948
|
function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
|
|
63850
63949
|
const dir = getTaskListDir(taskListId);
|
|
63851
|
-
if (!
|
|
63950
|
+
if (!existsSync26(dir)) {
|
|
63852
63951
|
return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
|
|
63853
63952
|
}
|
|
63854
63953
|
const files = readdirSync5(dir).filter((f) => f.endsWith(".json"));
|
|
@@ -63868,7 +63967,7 @@ function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
63868
63967
|
}
|
|
63869
63968
|
for (const f of files) {
|
|
63870
63969
|
try {
|
|
63871
|
-
const filePath =
|
|
63970
|
+
const filePath = join25(dir, f);
|
|
63872
63971
|
const ct = readClaudeTask(dir, f);
|
|
63873
63972
|
if (!ct)
|
|
63874
63973
|
continue;
|
|
@@ -63939,20 +64038,20 @@ function syncClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
63939
64038
|
init_tasks();
|
|
63940
64039
|
init_sync_utils();
|
|
63941
64040
|
init_config2();
|
|
63942
|
-
import { existsSync as
|
|
63943
|
-
import { join as
|
|
64041
|
+
import { existsSync as existsSync27 } from "fs";
|
|
64042
|
+
import { join as join26 } from "path";
|
|
63944
64043
|
function agentBaseDir(agent) {
|
|
63945
64044
|
const key2 = `TODOS_${agent.toUpperCase()}_TASKS_DIR`;
|
|
63946
|
-
return process.env[key2] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] ||
|
|
64045
|
+
return process.env[key2] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] || join26(getTodosGlobalDir(), "agents");
|
|
63947
64046
|
}
|
|
63948
64047
|
function getTaskListDir2(agent, taskListId) {
|
|
63949
|
-
return
|
|
64048
|
+
return join26(agentBaseDir(agent), agent, taskListId);
|
|
63950
64049
|
}
|
|
63951
64050
|
function readAgentTask(dir, filename) {
|
|
63952
|
-
return readJsonFile(
|
|
64051
|
+
return readJsonFile(join26(dir, filename));
|
|
63953
64052
|
}
|
|
63954
64053
|
function writeAgentTask(dir, task3) {
|
|
63955
|
-
writeJsonFile(
|
|
64054
|
+
writeJsonFile(join26(dir, `${task3.id}.json`), task3);
|
|
63956
64055
|
}
|
|
63957
64056
|
function taskToAgentTask(task3, externalId, existingMeta) {
|
|
63958
64057
|
return withSyncFingerprint({
|
|
@@ -63977,7 +64076,7 @@ function metadataKey(agent) {
|
|
|
63977
64076
|
}
|
|
63978
64077
|
function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
63979
64078
|
const dir = getTaskListDir2(agent, taskListId);
|
|
63980
|
-
if (!
|
|
64079
|
+
if (!existsSync27(dir))
|
|
63981
64080
|
ensureDir(dir);
|
|
63982
64081
|
const filter = {};
|
|
63983
64082
|
if (projectId)
|
|
@@ -63986,7 +64085,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
|
63986
64085
|
const existingByTodosId = new Map;
|
|
63987
64086
|
const files = listJsonFiles(dir);
|
|
63988
64087
|
for (const f of files) {
|
|
63989
|
-
const path =
|
|
64088
|
+
const path = join26(dir, f);
|
|
63990
64089
|
const at = readAgentTask(dir, f);
|
|
63991
64090
|
if (at?.metadata?.["todos_id"]) {
|
|
63992
64091
|
existingByTodosId.set(at.metadata["todos_id"], { task: at, mtimeMs: getFileMtimeMs(path) });
|
|
@@ -64062,7 +64161,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
|
64062
64161
|
}
|
|
64063
64162
|
function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
64064
64163
|
const dir = getTaskListDir2(agent, taskListId);
|
|
64065
|
-
if (!
|
|
64164
|
+
if (!existsSync27(dir)) {
|
|
64066
64165
|
return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
|
|
64067
64166
|
}
|
|
64068
64167
|
const files = listJsonFiles(dir);
|
|
@@ -64081,7 +64180,7 @@ function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
|
64081
64180
|
}
|
|
64082
64181
|
for (const f of files) {
|
|
64083
64182
|
try {
|
|
64084
|
-
const filePath =
|
|
64183
|
+
const filePath = join26(dir, f);
|
|
64085
64184
|
const at = readAgentTask(dir, f);
|
|
64086
64185
|
if (!at)
|
|
64087
64186
|
continue;
|
|
@@ -64221,9 +64320,9 @@ function syncWithAgents(agents, taskListIdByAgent, projectId, direction = "both"
|
|
|
64221
64320
|
// src/lib/extract.ts
|
|
64222
64321
|
init_tasks();
|
|
64223
64322
|
init_task_files();
|
|
64224
|
-
import { existsSync as
|
|
64323
|
+
import { existsSync as existsSync28, readFileSync as readFileSync24, statSync as statSync10 } from "fs";
|
|
64225
64324
|
import { createHash as createHash22 } from "crypto";
|
|
64226
|
-
import { relative as relative6, resolve as
|
|
64325
|
+
import { relative as relative6, resolve as resolve19, join as join27 } from "path";
|
|
64227
64326
|
var EXTRACT_TAGS = ["TODO", "FIXME", "HACK", "XXX", "BUG", "NOTE"];
|
|
64228
64327
|
var DEFAULT_EXTENSIONS = new Set([
|
|
64229
64328
|
".ts",
|
|
@@ -64293,9 +64392,9 @@ function normalizePathForMatch(value) {
|
|
|
64293
64392
|
return value.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
64294
64393
|
}
|
|
64295
64394
|
function readGitignorePatterns(basePath) {
|
|
64296
|
-
const root = statSync10(basePath).isFile() ?
|
|
64297
|
-
const gitignorePath =
|
|
64298
|
-
if (!
|
|
64395
|
+
const root = statSync10(basePath).isFile() ? resolve19(basePath, "..") : basePath;
|
|
64396
|
+
const gitignorePath = join27(root, ".gitignore");
|
|
64397
|
+
if (!existsSync28(gitignorePath))
|
|
64299
64398
|
return [];
|
|
64300
64399
|
try {
|
|
64301
64400
|
return readFileSync24(gitignorePath, "utf-8").split(`
|
|
@@ -64429,7 +64528,7 @@ function collectFiles(basePath, extensions, excludes, respectGitignore) {
|
|
|
64429
64528
|
return files.sort();
|
|
64430
64529
|
}
|
|
64431
64530
|
function buildCodebaseIndex(options) {
|
|
64432
|
-
const basePath =
|
|
64531
|
+
const basePath = resolve19(options.path);
|
|
64433
64532
|
const tags = options.patterns || [...EXTRACT_TAGS];
|
|
64434
64533
|
const extensions = options.extensions ? new Set(options.extensions.map((e) => e.startsWith(".") ? e : `.${e}`)) : DEFAULT_EXTENSIONS;
|
|
64435
64534
|
const excludes = options.exclude || [];
|
|
@@ -64437,10 +64536,10 @@ function buildCodebaseIndex(options) {
|
|
|
64437
64536
|
const files = collectFiles(basePath, extensions, excludes, respectGitignore);
|
|
64438
64537
|
const indexed = [];
|
|
64439
64538
|
for (const file of files) {
|
|
64440
|
-
const fullPath = statSync10(basePath).isFile() ? basePath :
|
|
64539
|
+
const fullPath = statSync10(basePath).isFile() ? basePath : join27(basePath, file);
|
|
64441
64540
|
try {
|
|
64442
64541
|
const source9 = readFileSync24(fullPath, "utf-8");
|
|
64443
|
-
const relPath = statSync10(basePath).isFile() ? relative6(
|
|
64542
|
+
const relPath = statSync10(basePath).isFile() ? relative6(resolve19(basePath, ".."), fullPath) : file;
|
|
64444
64543
|
indexed.push({
|
|
64445
64544
|
file: relPath,
|
|
64446
64545
|
checksum: stableHash(source9).slice(0, 24),
|
|
@@ -64460,7 +64559,7 @@ function buildCodebaseIndex(options) {
|
|
|
64460
64559
|
};
|
|
64461
64560
|
}
|
|
64462
64561
|
function extractTodos(options, db) {
|
|
64463
|
-
const basePath =
|
|
64562
|
+
const basePath = resolve19(options.path);
|
|
64464
64563
|
const tags = options.patterns || [...EXTRACT_TAGS];
|
|
64465
64564
|
const extensions = options.extensions ? new Set(options.extensions.map((e) => e.startsWith(".") ? e : `.${e}`)) : DEFAULT_EXTENSIONS;
|
|
64466
64565
|
const excludes = options.exclude || [];
|
|
@@ -64468,10 +64567,10 @@ function extractTodos(options, db) {
|
|
|
64468
64567
|
const files = collectFiles(basePath, extensions, excludes, respectGitignore);
|
|
64469
64568
|
const allComments = [];
|
|
64470
64569
|
for (const file of files) {
|
|
64471
|
-
const fullPath = statSync10(basePath).isFile() ? basePath :
|
|
64570
|
+
const fullPath = statSync10(basePath).isFile() ? basePath : join27(basePath, file);
|
|
64472
64571
|
try {
|
|
64473
64572
|
const source9 = readFileSync24(fullPath, "utf-8");
|
|
64474
|
-
const relPath = statSync10(basePath).isFile() ? relative6(
|
|
64573
|
+
const relPath = statSync10(basePath).isFile() ? relative6(resolve19(basePath, ".."), fullPath) : file;
|
|
64475
64574
|
const comments = extractFromSource(source9, relPath, tags);
|
|
64476
64575
|
allComments.push(...comments);
|
|
64477
64576
|
} catch {}
|
|
@@ -64565,7 +64664,7 @@ async function watchSourceTodos(options, onRun) {
|
|
|
64565
64664
|
const interval = Math.max(100, options.interval_ms || 2000);
|
|
64566
64665
|
const once = options.once !== false && (!options.max_runs || options.max_runs <= 1);
|
|
64567
64666
|
const maxRuns = options.max_runs ?? (once ? 1 : Number.POSITIVE_INFINITY);
|
|
64568
|
-
const root =
|
|
64667
|
+
const root = resolve19(options.path);
|
|
64569
64668
|
const runs = [];
|
|
64570
64669
|
let previous = new Map;
|
|
64571
64670
|
for (let runNumber = 1;runNumber <= maxRuns; runNumber++) {
|
|
@@ -65447,8 +65546,8 @@ function renderAgentReplaySimulationMarkdown(simulation) {
|
|
|
65447
65546
|
// src/lib/local-extensions.ts
|
|
65448
65547
|
init_config2();
|
|
65449
65548
|
import { createHash as createHash24, createVerify } from "crypto";
|
|
65450
|
-
import { existsSync as
|
|
65451
|
-
import { basename as basename6, join as
|
|
65549
|
+
import { existsSync as existsSync29, readdirSync as readdirSync6, readFileSync as readFileSync26, statSync as statSync11 } from "fs";
|
|
65550
|
+
import { basename as basename6, join as join28, resolve as resolve20 } from "path";
|
|
65452
65551
|
init_redaction();
|
|
65453
65552
|
init_runner_sandbox();
|
|
65454
65553
|
function isObject2(value) {
|
|
@@ -65729,11 +65828,11 @@ function verifyExtensionSignature(input) {
|
|
|
65729
65828
|
return verifier.verify(input.public_key, decodeSignature(input.signature));
|
|
65730
65829
|
}
|
|
65731
65830
|
function inspectExtensionSource(source9) {
|
|
65732
|
-
const resolved =
|
|
65733
|
-
if (!
|
|
65831
|
+
const resolved = resolve20(source9);
|
|
65832
|
+
if (!existsSync29(resolved))
|
|
65734
65833
|
throw new Error(`extension source not found: ${source9}`);
|
|
65735
65834
|
const stat = statSync11(resolved);
|
|
65736
|
-
const manifestPath = stat.isDirectory() ? [
|
|
65835
|
+
const manifestPath = stat.isDirectory() ? [join28(resolved, "todos.extension.json"), join28(resolved, "extension.json")].find(existsSync29) : resolved;
|
|
65737
65836
|
if (!manifestPath)
|
|
65738
65837
|
throw new Error(`extension directory ${source9} is missing todos.extension.json`);
|
|
65739
65838
|
const raw = readFileSync26(manifestPath);
|
|
@@ -65827,26 +65926,26 @@ function testExtensionCompatibility(sourceOrManifest) {
|
|
|
65827
65926
|
function projectExtensionSources(projectPath) {
|
|
65828
65927
|
if (!projectPath)
|
|
65829
65928
|
return [];
|
|
65830
|
-
const root =
|
|
65929
|
+
const root = resolve20(projectPath);
|
|
65831
65930
|
const candidates = [
|
|
65832
|
-
|
|
65833
|
-
|
|
65931
|
+
join28(root, "todos.extension.json"),
|
|
65932
|
+
join28(root, ".todos", "todos.extension.json")
|
|
65834
65933
|
];
|
|
65835
|
-
const extensionDir =
|
|
65836
|
-
if (
|
|
65934
|
+
const extensionDir = join28(root, ".todos", "extensions");
|
|
65935
|
+
if (existsSync29(extensionDir)) {
|
|
65837
65936
|
for (const entry2 of readdirSync6(extensionDir)) {
|
|
65838
65937
|
if (entry2.startsWith("."))
|
|
65839
65938
|
continue;
|
|
65840
|
-
const full =
|
|
65939
|
+
const full = join28(extensionDir, entry2);
|
|
65841
65940
|
if (statSync11(full).isDirectory() || entry2.endsWith(".json"))
|
|
65842
65941
|
candidates.push(full);
|
|
65843
65942
|
}
|
|
65844
65943
|
}
|
|
65845
|
-
return candidates.filter(
|
|
65944
|
+
return candidates.filter(existsSync29);
|
|
65846
65945
|
}
|
|
65847
65946
|
function discoverLocalExtensions(options = {}) {
|
|
65848
65947
|
const config = loadConfig();
|
|
65849
|
-
const projectPath = options.project_path ?
|
|
65948
|
+
const projectPath = options.project_path ? resolve20(options.project_path) : null;
|
|
65850
65949
|
const configuredSources = [
|
|
65851
65950
|
...config.extension_sources || [],
|
|
65852
65951
|
...projectPath ? config.project_overrides?.[projectPath]?.extension_sources || [] : []
|
|
@@ -65854,7 +65953,7 @@ function discoverLocalExtensions(options = {}) {
|
|
|
65854
65953
|
const sources = Array.from(new Set([
|
|
65855
65954
|
...configuredSources,
|
|
65856
65955
|
...projectExtensionSources(projectPath || undefined)
|
|
65857
|
-
])).map((source9) => projectPath && !source9.startsWith("/") ?
|
|
65956
|
+
])).map((source9) => projectPath && !source9.startsWith("/") ? resolve20(projectPath, source9) : resolve20(source9));
|
|
65858
65957
|
const warnings = [];
|
|
65859
65958
|
const discovered = [];
|
|
65860
65959
|
for (const source9 of sources) {
|
|
@@ -66722,7 +66821,7 @@ init_redaction();
|
|
|
66722
66821
|
// src/lib/retention-cleanup.ts
|
|
66723
66822
|
init_artifact_store();
|
|
66724
66823
|
init_database();
|
|
66725
|
-
import { existsSync as
|
|
66824
|
+
import { existsSync as existsSync30, unlinkSync as unlinkSync2 } from "fs";
|
|
66726
66825
|
var RETENTION_CLEANUP_CONFIRMATION = "delete-local-retention-data";
|
|
66727
66826
|
var ALL_SCOPES = ["comments", "runs", "verifications", "expired_artifacts"];
|
|
66728
66827
|
var EMPTY_COUNTS = {
|
|
@@ -66933,7 +67032,7 @@ function applyRetentionCleanup(input, db) {
|
|
|
66933
67032
|
for (const artifact of report.candidates.artifact_files) {
|
|
66934
67033
|
try {
|
|
66935
67034
|
const path = artifactStorePath(artifact.relative_path);
|
|
66936
|
-
if (!
|
|
67035
|
+
if (!existsSync30(path)) {
|
|
66937
67036
|
report.warnings.push(`stored artifact already missing: ${artifact.relative_path}`);
|
|
66938
67037
|
continue;
|
|
66939
67038
|
}
|
|
@@ -67174,8 +67273,8 @@ init_artifact_store();
|
|
|
67174
67273
|
|
|
67175
67274
|
// src/lib/doctor.ts
|
|
67176
67275
|
init_database();
|
|
67177
|
-
import { chmodSync, copyFileSync as copyFileSync2, existsSync as
|
|
67178
|
-
import { basename as basename7, dirname as dirname18, join as
|
|
67276
|
+
import { chmodSync, copyFileSync as copyFileSync2, existsSync as existsSync31, mkdirSync as mkdirSync22, statSync as statSync12 } from "fs";
|
|
67277
|
+
import { basename as basename7, dirname as dirname18, join as join29 } from "path";
|
|
67179
67278
|
init_migrations();
|
|
67180
67279
|
init_schema();
|
|
67181
67280
|
init_recurrence();
|
|
@@ -67285,7 +67384,7 @@ function findMissingProjectRoots(db) {
|
|
|
67285
67384
|
continue;
|
|
67286
67385
|
if (!row.path.startsWith("/"))
|
|
67287
67386
|
continue;
|
|
67288
|
-
if (!
|
|
67387
|
+
if (!existsSync31(row.path))
|
|
67289
67388
|
missing++;
|
|
67290
67389
|
}
|
|
67291
67390
|
return missing;
|
|
@@ -67345,16 +67444,16 @@ function databasePermissionsAreUnsafe(dbPath) {
|
|
|
67345
67444
|
function createBackup(dbPath) {
|
|
67346
67445
|
if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
|
|
67347
67446
|
return;
|
|
67348
|
-
if (!
|
|
67447
|
+
if (!existsSync31(dbPath))
|
|
67349
67448
|
return;
|
|
67350
67449
|
const stamp = now().replace(/[:.]/g, "-");
|
|
67351
|
-
const backupDir =
|
|
67450
|
+
const backupDir = join29(dirname18(dbPath), `${basename7(dbPath)}.backup-${stamp}`);
|
|
67352
67451
|
const files = [];
|
|
67353
67452
|
mkdirSync22(backupDir, { recursive: true });
|
|
67354
67453
|
for (const source9 of [dbPath, `${dbPath}-wal`, `${dbPath}-shm`]) {
|
|
67355
|
-
if (!
|
|
67454
|
+
if (!existsSync31(source9))
|
|
67356
67455
|
continue;
|
|
67357
|
-
const target =
|
|
67456
|
+
const target = join29(backupDir, basename7(source9));
|
|
67358
67457
|
copyFileSync2(source9, target);
|
|
67359
67458
|
files.push(target);
|
|
67360
67459
|
}
|