@hasna/todos 0.15.50 → 0.15.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/cloud-router.d.ts.map +1 -1
- package/dist/cli/commands/project-commands.d.ts +15 -0
- package/dist/cli/commands/project-commands.d.ts.map +1 -1
- package/dist/cli/commands/query-commands.d.ts.map +1 -1
- package/dist/cli/helpers.d.ts.map +1 -1
- package/dist/cli/index.js +521 -342
- package/dist/contracts.js +194 -95
- package/dist/db/task-crud.d.ts.map +1 -1
- package/dist/index.js +406 -299
- package/dist/lib/model-config.d.ts +2 -1
- package/dist/lib/model-config.d.ts.map +1 -1
- package/dist/lib/paths.d.ts +40 -0
- package/dist/lib/paths.d.ts.map +1 -0
- package/dist/lib/sync-utils.d.ts +7 -0
- package/dist/lib/sync-utils.d.ts.map +1 -1
- package/dist/mcp/index.js +280 -174
- package/dist/mcp.js +7 -4
- package/dist/project-registration.js +192 -93
- package/dist/registry.js +194 -95
- package/dist/release-provenance.json +5 -5
- package/dist/sdk/index.js +100 -8
- package/dist/server/index.js +449 -220
- package/dist/storage.js +183 -87
- package/dist/task-manifest.js +113 -17
- package/dist/testing.d.ts +10 -9
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +2 -2
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +7 -4
- package/postinstall.js +34 -0
package/dist/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.52",
|
|
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: {
|
|
@@ -13327,7 +13426,7 @@ var package_default = {
|
|
|
13327
13426
|
zod: "3.25.76"
|
|
13328
13427
|
},
|
|
13329
13428
|
devDependencies: {
|
|
13330
|
-
"@types/bun": "
|
|
13429
|
+
"@types/bun": "1.3.14",
|
|
13331
13430
|
"@types/react": "^18.3.18",
|
|
13332
13431
|
"bun-types": "1.3.9",
|
|
13333
13432
|
"hasna-deployment-contracts": "npm:@hasna/contracts@0.10.4",
|
|
@@ -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);
|
|
@@ -45655,15 +45754,23 @@ function normalizeRemoteAuthorityUrl(value) {
|
|
|
45655
45754
|
if (url.search || url.hash) {
|
|
45656
45755
|
throw new Error("REMOTE_API_URL_INVALID: HASNA_TODOS_API_URL must not contain a query or fragment; local SQLite fallback is disabled");
|
|
45657
45756
|
}
|
|
45658
|
-
|
|
45659
|
-
|
|
45757
|
+
const path = url.pathname.replace(/\/+$/, "");
|
|
45758
|
+
const segments = path.split("/").filter(Boolean);
|
|
45759
|
+
const reservedGatewaySegments = new Set(["api", "v1"]);
|
|
45760
|
+
const isRoot = path === "";
|
|
45761
|
+
const isV1Root = segments.length === 1 && segments[0] === "v1";
|
|
45762
|
+
const isAppRoot = segments.length === 1 && !reservedGatewaySegments.has(segments[0].toLowerCase());
|
|
45763
|
+
const isAppV1Root = segments.length === 2 && segments[1] === "v1" && !reservedGatewaySegments.has(segments[0].toLowerCase());
|
|
45764
|
+
if (!isRoot && !isV1Root && !isAppRoot && !isAppV1Root) {
|
|
45765
|
+
throw new Error("REMOTE_API_URL_INVALID: HASNA_TODOS_API_URL must be an authority root, /v1, or <app>[/v1], not /api/v1 or another path; " + "local SQLite fallback is disabled");
|
|
45660
45766
|
}
|
|
45661
45767
|
const hostname2 = url.hostname.toLowerCase();
|
|
45662
45768
|
const loopback = hostname2 === "localhost" || hostname2 === "::1" || hostname2 === "[::1]" || /^127(?:\.\d{1,3}){3}$/.test(hostname2);
|
|
45663
45769
|
if (url.protocol === "http:" && !loopback) {
|
|
45664
45770
|
throw new Error("REMOTE_API_URL_INVALID: plaintext HTTP is allowed only for loopback Todos authorities; local SQLite fallback is disabled");
|
|
45665
45771
|
}
|
|
45666
|
-
|
|
45772
|
+
const rootPath = isV1Root || isAppV1Root ? path.slice(0, -"/v1".length) : path;
|
|
45773
|
+
return rootPath ? `${url.origin}${rootPath}` : url.origin;
|
|
45667
45774
|
}
|
|
45668
45775
|
function getTodosRemoteAuthorityConfigStatus(env = process.env) {
|
|
45669
45776
|
let resolution;
|
|
@@ -46217,8 +46324,8 @@ var DANGEROUS_TOOLS = new Set([
|
|
|
46217
46324
|
"merge_tasks",
|
|
46218
46325
|
"cancel_agent_run"
|
|
46219
46326
|
]);
|
|
46220
|
-
function resolveAccessProfile(
|
|
46221
|
-
const raw = (
|
|
46327
|
+
function resolveAccessProfile(envValue2) {
|
|
46328
|
+
const raw = (envValue2 ?? process.env["TODOS_PROFILE"] ?? "full").toLowerCase();
|
|
46222
46329
|
if (ACCESS_PROFILES.includes(raw))
|
|
46223
46330
|
return raw;
|
|
46224
46331
|
if (raw === "readonly")
|
|
@@ -47761,8 +47868,8 @@ init_task_crud();
|
|
|
47761
47868
|
init_redaction();
|
|
47762
47869
|
import { Database as Database3 } from "bun:sqlite";
|
|
47763
47870
|
import { createHash as createHash17 } from "crypto";
|
|
47764
|
-
import { existsSync as
|
|
47765
|
-
import { basename as basename2, dirname as dirname6, join as
|
|
47871
|
+
import { existsSync as existsSync10, readdirSync as readdirSync2, statSync as statSync4 } from "fs";
|
|
47872
|
+
import { basename as basename2, dirname as dirname6, join as join11, resolve as resolve11 } from "path";
|
|
47766
47873
|
|
|
47767
47874
|
// src/lib/task-routing.ts
|
|
47768
47875
|
init_database();
|
|
@@ -47770,7 +47877,7 @@ init_projects();
|
|
|
47770
47877
|
init_task_crud();
|
|
47771
47878
|
init_task_lifecycle();
|
|
47772
47879
|
init_task_lists();
|
|
47773
|
-
import { existsSync as
|
|
47880
|
+
import { existsSync as existsSync9, statSync as statSync3 } from "fs";
|
|
47774
47881
|
var DEFAULT_STALE_IN_PROGRESS_MS = 3 * 24 * 60 * 60 * 1000;
|
|
47775
47882
|
var TERMINAL_WORKFLOW_STATES = new Set([
|
|
47776
47883
|
"failed",
|
|
@@ -47825,7 +47932,7 @@ function routeConcurrencyKey(task3, project, taskList, projectPath) {
|
|
|
47825
47932
|
}
|
|
47826
47933
|
function directoryExists(path) {
|
|
47827
47934
|
try {
|
|
47828
|
-
return
|
|
47935
|
+
return existsSync9(path) && statSync3(path).isDirectory();
|
|
47829
47936
|
} catch {
|
|
47830
47937
|
return false;
|
|
47831
47938
|
}
|
|
@@ -48026,7 +48133,7 @@ function pointerPatch(previous, input, key2) {
|
|
|
48026
48133
|
|
|
48027
48134
|
// src/lib/task-route-sources.ts
|
|
48028
48135
|
var TASK_ROUTE_SOURCE_DISCOVERY_SCHEMA_VERSION = "todos.task_route_sources.v1";
|
|
48029
|
-
var TODO_STORE_RELATIVE_PATH =
|
|
48136
|
+
var TODO_STORE_RELATIVE_PATH = join11(".hasna", "todos", "todos.db");
|
|
48030
48137
|
var ROOT_SCAN_MAX_DEPTH = 5;
|
|
48031
48138
|
var SKIPPED_SCAN_DIRS = new Set([
|
|
48032
48139
|
".git",
|
|
@@ -48040,7 +48147,7 @@ var SKIPPED_SCAN_DIRS = new Set([
|
|
|
48040
48147
|
".cache"
|
|
48041
48148
|
]);
|
|
48042
48149
|
function normalizePath3(input) {
|
|
48043
|
-
return
|
|
48150
|
+
return resolve11(input);
|
|
48044
48151
|
}
|
|
48045
48152
|
function sourceStoreId(sourceDbPath) {
|
|
48046
48153
|
const digest3 = createHash17("sha256").update(sourceDbPath).digest("hex").slice(0, 16);
|
|
@@ -48102,8 +48209,8 @@ function discoverStoresUnderRoot(sourceRoot) {
|
|
|
48102
48209
|
const rootPath = normalizePath3(sourceRoot);
|
|
48103
48210
|
const errors2 = [];
|
|
48104
48211
|
const stores = [];
|
|
48105
|
-
if (!
|
|
48106
|
-
const ref = createStoreRef(
|
|
48212
|
+
if (!existsSync10(rootPath)) {
|
|
48213
|
+
const ref = createStoreRef(join11(rootPath, TODO_STORE_RELATIVE_PATH));
|
|
48107
48214
|
errors2.push({
|
|
48108
48215
|
...ref,
|
|
48109
48216
|
code: "SOURCE_ROOT_MISSING",
|
|
@@ -48115,7 +48222,7 @@ function discoverStoresUnderRoot(sourceRoot) {
|
|
|
48115
48222
|
try {
|
|
48116
48223
|
rootStat = statSync4(rootPath);
|
|
48117
48224
|
} catch (error) {
|
|
48118
|
-
const ref = createStoreRef(
|
|
48225
|
+
const ref = createStoreRef(join11(rootPath, TODO_STORE_RELATIVE_PATH));
|
|
48119
48226
|
errors2.push({
|
|
48120
48227
|
...ref,
|
|
48121
48228
|
code: "SOURCE_ROOT_UNREADABLE",
|
|
@@ -48128,8 +48235,8 @@ function discoverStoresUnderRoot(sourceRoot) {
|
|
|
48128
48235
|
return { stores, errors: errors2 };
|
|
48129
48236
|
}
|
|
48130
48237
|
function scanDirectory(dir, depth) {
|
|
48131
|
-
const candidate =
|
|
48132
|
-
if (
|
|
48238
|
+
const candidate = join11(dir, TODO_STORE_RELATIVE_PATH);
|
|
48239
|
+
if (existsSync10(candidate)) {
|
|
48133
48240
|
stores.push(createStoreRef(candidate));
|
|
48134
48241
|
}
|
|
48135
48242
|
if (depth >= ROOT_SCAN_MAX_DEPTH)
|
|
@@ -48149,7 +48256,7 @@ function discoverStoresUnderRoot(sourceRoot) {
|
|
|
48149
48256
|
for (const entry2 of entries) {
|
|
48150
48257
|
if (!entry2.isDirectory() || SKIPPED_SCAN_DIRS.has(entry2.name))
|
|
48151
48258
|
continue;
|
|
48152
|
-
scanDirectory(
|
|
48259
|
+
scanDirectory(join11(dir, entry2.name), depth + 1);
|
|
48153
48260
|
}
|
|
48154
48261
|
}
|
|
48155
48262
|
scanDirectory(rootPath, 0);
|
|
@@ -48175,7 +48282,7 @@ function collectStoreRefs(input) {
|
|
|
48175
48282
|
};
|
|
48176
48283
|
}
|
|
48177
48284
|
function openReadonlyStore(ref) {
|
|
48178
|
-
if (!
|
|
48285
|
+
if (!existsSync10(ref.source_db_path)) {
|
|
48179
48286
|
throw Object.assign(new Error(`Store does not exist: ${ref.source_db_path}`), { code: "STORE_MISSING" });
|
|
48180
48287
|
}
|
|
48181
48288
|
return new Database3(ref.source_db_path, { readonly: true, create: false });
|
|
@@ -48487,8 +48594,8 @@ init_plans();
|
|
|
48487
48594
|
init_database();
|
|
48488
48595
|
init_projects();
|
|
48489
48596
|
init_tasks();
|
|
48490
|
-
import { existsSync as
|
|
48491
|
-
import { join as
|
|
48597
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
|
|
48598
|
+
import { join as join12, resolve as resolve12 } from "path";
|
|
48492
48599
|
var PLAN_MARKDOWN_SCHEMA = "hasna.todos.plan/v1";
|
|
48493
48600
|
function assertSafePathSegment(value, label) {
|
|
48494
48601
|
const trimmed = value.trim();
|
|
@@ -48532,7 +48639,7 @@ function resolvePlanArtifactProject(input) {
|
|
|
48532
48639
|
const ref = input.project_id || input.project_ref;
|
|
48533
48640
|
if (!ref)
|
|
48534
48641
|
throw new Error("Plan artifacts require a project id or project reference");
|
|
48535
|
-
const byPath = getProjectByPath(
|
|
48642
|
+
const byPath = getProjectByPath(resolve12(ref), db);
|
|
48536
48643
|
if (byPath)
|
|
48537
48644
|
return byPath;
|
|
48538
48645
|
const resolvedId = resolvePartialId(db, "projects", ref);
|
|
@@ -48549,8 +48656,8 @@ function resolvePlanArtifactProject(input) {
|
|
|
48549
48656
|
function resolvePlanArtifactPaths(input) {
|
|
48550
48657
|
const project = resolvePlanArtifactProject(input);
|
|
48551
48658
|
const projectId = assertSafePathSegment(project.id, "project id");
|
|
48552
|
-
const projectRoot =
|
|
48553
|
-
const directory =
|
|
48659
|
+
const projectRoot = resolve12(project.path);
|
|
48660
|
+
const directory = join12(projectRoot, ".hasna", "todos", "plans", projectId);
|
|
48554
48661
|
const planId = input.plan_id ? assertSafePathSegment(input.plan_id, "plan id") : null;
|
|
48555
48662
|
const planSlug = input.plan_slug ? assertSafePathSegment(slugify(input.plan_slug), "plan slug") : null;
|
|
48556
48663
|
const fileName = planId ? planSlug ? `${planSlug}--${planId.slice(0, 8)}.md` : `${planId}.md` : null;
|
|
@@ -48558,7 +48665,7 @@ function resolvePlanArtifactPaths(input) {
|
|
|
48558
48665
|
project_id: project.id,
|
|
48559
48666
|
project_root: projectRoot,
|
|
48560
48667
|
directory,
|
|
48561
|
-
file_path: fileName ?
|
|
48668
|
+
file_path: fileName ? join12(directory, fileName) : directory
|
|
48562
48669
|
};
|
|
48563
48670
|
}
|
|
48564
48671
|
function resolvePlanArtifactCandidatePaths(plan, db) {
|
|
@@ -48724,7 +48831,7 @@ function readPlanArtifact(plan, db) {
|
|
|
48724
48831
|
return null;
|
|
48725
48832
|
const d = db || getDatabase();
|
|
48726
48833
|
const paths = resolvePlanArtifactCandidatePaths(plan, d);
|
|
48727
|
-
const path =
|
|
48834
|
+
const path = existsSync11(paths.primary.file_path) ? paths.primary.file_path : existsSync11(paths.legacy.file_path) ? paths.legacy.file_path : null;
|
|
48728
48835
|
if (!path)
|
|
48729
48836
|
return null;
|
|
48730
48837
|
const markdown = readFileSync7(path, "utf8");
|
|
@@ -48739,7 +48846,7 @@ function inspectPlanArtifact(plan, db) {
|
|
|
48739
48846
|
return null;
|
|
48740
48847
|
const d = db || getDatabase();
|
|
48741
48848
|
const paths = resolvePlanArtifactCandidatePaths(plan, d);
|
|
48742
|
-
const path =
|
|
48849
|
+
const path = existsSync11(paths.primary.file_path) ? paths.primary.file_path : existsSync11(paths.legacy.file_path) ? paths.legacy.file_path : null;
|
|
48743
48850
|
if (!path) {
|
|
48744
48851
|
return {
|
|
48745
48852
|
path: paths.primary.file_path,
|
|
@@ -49828,8 +49935,8 @@ function renderRetrospectiveMarkdown(record) {
|
|
|
49828
49935
|
init_database();
|
|
49829
49936
|
init_projects();
|
|
49830
49937
|
init_task_lists();
|
|
49831
|
-
import { existsSync as
|
|
49832
|
-
import { basename as basename3, dirname as dirname7, resolve as
|
|
49938
|
+
import { existsSync as existsSync12, readFileSync as readFileSync8, statSync as statSync5 } from "fs";
|
|
49939
|
+
import { basename as basename3, dirname as dirname7, resolve as resolve13 } from "path";
|
|
49833
49940
|
function safeStat(path) {
|
|
49834
49941
|
try {
|
|
49835
49942
|
return statSync5(path);
|
|
@@ -49838,7 +49945,7 @@ function safeStat(path) {
|
|
|
49838
49945
|
}
|
|
49839
49946
|
}
|
|
49840
49947
|
function canonicalPath(input) {
|
|
49841
|
-
const resolved =
|
|
49948
|
+
const resolved = resolve13(input);
|
|
49842
49949
|
const stats2 = safeStat(resolved);
|
|
49843
49950
|
if (stats2?.isFile())
|
|
49844
49951
|
return dirname7(resolved);
|
|
@@ -49847,7 +49954,7 @@ function canonicalPath(input) {
|
|
|
49847
49954
|
function findUp(start, marker) {
|
|
49848
49955
|
let current = canonicalPath(start);
|
|
49849
49956
|
while (true) {
|
|
49850
|
-
if (
|
|
49957
|
+
if (existsSync12(resolve13(current, marker)))
|
|
49851
49958
|
return current;
|
|
49852
49959
|
const parent = dirname7(current);
|
|
49853
49960
|
if (parent === current)
|
|
@@ -49858,8 +49965,8 @@ function findUp(start, marker) {
|
|
|
49858
49965
|
function readPackageJson2(path) {
|
|
49859
49966
|
if (!path)
|
|
49860
49967
|
return null;
|
|
49861
|
-
const file =
|
|
49862
|
-
if (!
|
|
49968
|
+
const file = resolve13(path, "package.json");
|
|
49969
|
+
if (!existsSync12(file))
|
|
49863
49970
|
return null;
|
|
49864
49971
|
try {
|
|
49865
49972
|
const parsed = JSON.parse(readFileSync8(file, "utf-8"));
|
|
@@ -49881,7 +49988,7 @@ function workspaceMarker(root, rootPackage) {
|
|
|
49881
49988
|
if (rootPackage?.workspaces)
|
|
49882
49989
|
markers.push("package.json#workspaces");
|
|
49883
49990
|
for (const marker of ["pnpm-workspace.yaml", "turbo.json", "nx.json", "lerna.json", "rush.json", "bun.lock", "bun.lockb"]) {
|
|
49884
|
-
if (
|
|
49991
|
+
if (existsSync12(resolve13(root, marker)))
|
|
49885
49992
|
markers.push(marker);
|
|
49886
49993
|
}
|
|
49887
49994
|
const kind = markers.find((marker) => marker !== "bun.lock" && marker !== "bun.lockb") ?? null;
|
|
@@ -50219,18 +50326,18 @@ var gatherTrainingData = async (options = {}) => {
|
|
|
50219
50326
|
};
|
|
50220
50327
|
// src/lib/model-config.ts
|
|
50221
50328
|
init_sync_utils();
|
|
50222
|
-
import { existsSync as
|
|
50223
|
-
import { join as
|
|
50329
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync9, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
|
|
50330
|
+
import { join as join13 } from "path";
|
|
50224
50331
|
var DEFAULT_MODEL = "gpt-4o-mini";
|
|
50225
50332
|
function getConfigDir() {
|
|
50226
50333
|
return getTodosGlobalDir();
|
|
50227
50334
|
}
|
|
50228
50335
|
function getConfigPath2() {
|
|
50229
|
-
return
|
|
50336
|
+
return join13(getConfigDir(), "config.json");
|
|
50230
50337
|
}
|
|
50231
50338
|
function readConfig() {
|
|
50232
50339
|
const configPath = getConfigPath2();
|
|
50233
|
-
if (!
|
|
50340
|
+
if (!existsSync13(configPath))
|
|
50234
50341
|
return {};
|
|
50235
50342
|
try {
|
|
50236
50343
|
const raw = readFileSync9(configPath, "utf-8");
|
|
@@ -50241,7 +50348,7 @@ function readConfig() {
|
|
|
50241
50348
|
}
|
|
50242
50349
|
function writeConfig(config) {
|
|
50243
50350
|
const configDir = getConfigDir();
|
|
50244
|
-
if (!
|
|
50351
|
+
if (!existsSync13(configDir)) {
|
|
50245
50352
|
mkdirSync9(configDir, { recursive: true });
|
|
50246
50353
|
}
|
|
50247
50354
|
writeFileSync7(getConfigPath2(), JSON.stringify(config, null, 2) + `
|
|
@@ -50989,7 +51096,7 @@ init_database();
|
|
|
50989
51096
|
init_tasks();
|
|
50990
51097
|
init_config2();
|
|
50991
51098
|
init_redaction();
|
|
50992
|
-
import { existsSync as
|
|
51099
|
+
import { existsSync as existsSync14, readFileSync as readFileSync10 } from "fs";
|
|
50993
51100
|
var DEFAULT_RETRY = {
|
|
50994
51101
|
attempts: 1,
|
|
50995
51102
|
backoff_ms: 0
|
|
@@ -51097,7 +51204,7 @@ function classifyLog(text) {
|
|
|
51097
51204
|
async function sleep2(ms) {
|
|
51098
51205
|
if (ms <= 0)
|
|
51099
51206
|
return;
|
|
51100
|
-
await new Promise((
|
|
51207
|
+
await new Promise((resolve14) => setTimeout(resolve14, ms));
|
|
51101
51208
|
}
|
|
51102
51209
|
async function runCommandProvider(provider, input) {
|
|
51103
51210
|
const commandTemplate = input.command || provider.command;
|
|
@@ -51152,7 +51259,7 @@ Timed out after ${provider.timeout_ms}ms`);
|
|
|
51152
51259
|
};
|
|
51153
51260
|
}
|
|
51154
51261
|
function runCiLogProvider(input) {
|
|
51155
|
-
const text = input.log_text ?? (input.log_path &&
|
|
51262
|
+
const text = input.log_text ?? (input.log_path && existsSync14(input.log_path) ? readFileSync10(input.log_path, "utf-8") : "");
|
|
51156
51263
|
return {
|
|
51157
51264
|
status: classifyLog(text),
|
|
51158
51265
|
attempts: 1,
|
|
@@ -51164,7 +51271,7 @@ function runBrowserProvider(input) {
|
|
|
51164
51271
|
if (!input.artifact_path) {
|
|
51165
51272
|
return { status: "unknown", attempts: 1, exit_code: null, output_summary: "browser provider needs a screenshot or artifact path" };
|
|
51166
51273
|
}
|
|
51167
|
-
if (!
|
|
51274
|
+
if (!existsSync14(input.artifact_path)) {
|
|
51168
51275
|
return { status: "failed", attempts: 1, exit_code: null, output_summary: `artifact not found: ${input.artifact_path}` };
|
|
51169
51276
|
}
|
|
51170
51277
|
return {
|
|
@@ -51458,9 +51565,9 @@ init_database();
|
|
|
51458
51565
|
init_tasks();
|
|
51459
51566
|
init_task_runs();
|
|
51460
51567
|
init_config2();
|
|
51461
|
-
import { relative as relative3, resolve as
|
|
51568
|
+
import { relative as relative3, resolve as resolve14 } from "path";
|
|
51462
51569
|
function normalizePath4(path) {
|
|
51463
|
-
return
|
|
51570
|
+
return resolve14(path);
|
|
51464
51571
|
}
|
|
51465
51572
|
function unique4(values) {
|
|
51466
51573
|
return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));
|
|
@@ -51515,7 +51622,7 @@ function commandMatches(commands, pattern) {
|
|
|
51515
51622
|
}
|
|
51516
51623
|
function pathMatches(paths, pattern, root) {
|
|
51517
51624
|
return paths.filter((path) => {
|
|
51518
|
-
const candidate = path.startsWith("/") ? path :
|
|
51625
|
+
const candidate = path.startsWith("/") ? path : resolve14(root, path);
|
|
51519
51626
|
if (!isPathInside3(root, candidate))
|
|
51520
51627
|
return matchesPattern4(path, pattern);
|
|
51521
51628
|
return matchesPattern4(path, pattern) || matchesPattern4(relative3(root, candidate), pattern);
|
|
@@ -51810,20 +51917,20 @@ function resourceDiagnostics() {
|
|
|
51810
51917
|
}
|
|
51811
51918
|
// src/lib/sandbox-profiles.ts
|
|
51812
51919
|
init_sync_utils();
|
|
51813
|
-
import { existsSync as
|
|
51814
|
-
import { join as
|
|
51920
|
+
import { existsSync as existsSync15, readFileSync as readFileSync11, writeFileSync as writeFileSync9, mkdirSync as mkdirSync11 } from "fs";
|
|
51921
|
+
import { join as join14, dirname as dirname9 } from "path";
|
|
51815
51922
|
var SANDBOX_PROFILE_VERSION = "todos.sandbox-profile.v1";
|
|
51816
51923
|
function getProfilesPath() {
|
|
51817
51924
|
if (process.env["TODOS_SANDBOX_PROFILES_PATH"]) {
|
|
51818
51925
|
return process.env["TODOS_SANDBOX_PROFILES_PATH"];
|
|
51819
51926
|
}
|
|
51820
|
-
const localDir =
|
|
51821
|
-
const local =
|
|
51822
|
-
if (
|
|
51927
|
+
const localDir = join14(process.cwd(), ".todos");
|
|
51928
|
+
const local = join14(localDir, "sandbox-profiles.json");
|
|
51929
|
+
if (existsSync15(localDir))
|
|
51823
51930
|
return local;
|
|
51824
|
-
if (
|
|
51931
|
+
if (existsSync15(local))
|
|
51825
51932
|
return local;
|
|
51826
|
-
return
|
|
51933
|
+
return join14(getTodosGlobalDir(), "sandbox-profiles.json");
|
|
51827
51934
|
}
|
|
51828
51935
|
var cached2 = null;
|
|
51829
51936
|
function resetSandboxProfileCache() {
|
|
@@ -51855,7 +51962,7 @@ function loadSandboxProfiles() {
|
|
|
51855
51962
|
if (cached2)
|
|
51856
51963
|
return cached2;
|
|
51857
51964
|
const path = getProfilesPath();
|
|
51858
|
-
if (!
|
|
51965
|
+
if (!existsSync15(path)) {
|
|
51859
51966
|
cached2 = getDefaultSandboxProfiles();
|
|
51860
51967
|
return cached2;
|
|
51861
51968
|
}
|
|
@@ -52235,9 +52342,9 @@ init_task_commits();
|
|
|
52235
52342
|
|
|
52236
52343
|
// src/lib/git-traceability.ts
|
|
52237
52344
|
init_task_commits();
|
|
52238
|
-
import { existsSync as
|
|
52345
|
+
import { existsSync as existsSync16, readFileSync as readFileSync12 } from "fs";
|
|
52239
52346
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
52240
|
-
import { resolve as
|
|
52347
|
+
import { resolve as resolve15 } from "path";
|
|
52241
52348
|
var GIT_TRACEABILITY_SCHEMA_VERSION = "todos.git_traceability.v1";
|
|
52242
52349
|
function runGit(args, cwd) {
|
|
52243
52350
|
const result = spawnSync2("git", args, { cwd, encoding: "utf8" });
|
|
@@ -52280,8 +52387,8 @@ function inspectGitCommit(sha, cwd) {
|
|
|
52280
52387
|
};
|
|
52281
52388
|
}
|
|
52282
52389
|
function loadCiSnapshot(path) {
|
|
52283
|
-
const target = path ?
|
|
52284
|
-
if (!
|
|
52390
|
+
const target = path ? resolve15(path) : resolve15(process.cwd(), ".todos", "ci-snapshot.json");
|
|
52391
|
+
if (!existsSync16(target))
|
|
52285
52392
|
return null;
|
|
52286
52393
|
try {
|
|
52287
52394
|
const parsed = JSON.parse(readFileSync12(target, "utf8"));
|
|
@@ -52377,8 +52484,8 @@ function formatTraceabilityReport(report) {
|
|
|
52377
52484
|
`);
|
|
52378
52485
|
}
|
|
52379
52486
|
// src/lib/mention-resolver.ts
|
|
52380
|
-
import { existsSync as
|
|
52381
|
-
import { basename as basename4, isAbsolute, join as
|
|
52487
|
+
import { existsSync as existsSync17, readdirSync as readdirSync3, readFileSync as readFileSync13, statSync as statSync6 } from "fs";
|
|
52488
|
+
import { basename as basename4, isAbsolute, join as join15, relative as relative4, resolve as resolve16, sep as sep2 } from "path";
|
|
52382
52489
|
init_database();
|
|
52383
52490
|
init_plans();
|
|
52384
52491
|
init_task_runs();
|
|
@@ -52457,7 +52564,7 @@ function backlink(kind, key2, label, target = key2) {
|
|
|
52457
52564
|
return { kind, key: key2, label, target };
|
|
52458
52565
|
}
|
|
52459
52566
|
function normalizeWorkspace(workspace) {
|
|
52460
|
-
return
|
|
52567
|
+
return resolve16(workspace || process.cwd());
|
|
52461
52568
|
}
|
|
52462
52569
|
function isInside(root, absolutePath) {
|
|
52463
52570
|
const rel = relative4(root, absolutePath);
|
|
@@ -52525,14 +52632,14 @@ function resolveFile(parsed, workspace) {
|
|
|
52525
52632
|
resolution.warnings.push("path is empty or escapes the workspace");
|
|
52526
52633
|
return resolution;
|
|
52527
52634
|
}
|
|
52528
|
-
const absolutePath =
|
|
52635
|
+
const absolutePath = resolve16(workspace, relPath);
|
|
52529
52636
|
if (!isInside(workspace, absolutePath)) {
|
|
52530
52637
|
resolution.path = relPath;
|
|
52531
52638
|
resolution.warnings.push("path escapes the workspace");
|
|
52532
52639
|
return resolution;
|
|
52533
52640
|
}
|
|
52534
52641
|
resolution.path = relPath;
|
|
52535
|
-
if (!
|
|
52642
|
+
if (!existsSync17(absolutePath)) {
|
|
52536
52643
|
resolution.warnings.push("file does not exist in the local workspace");
|
|
52537
52644
|
return resolution;
|
|
52538
52645
|
}
|
|
@@ -52565,7 +52672,7 @@ function walkSourceFiles(root, current = root, files = []) {
|
|
|
52565
52672
|
if (SKIP_DIRS.has(entry2.name))
|
|
52566
52673
|
continue;
|
|
52567
52674
|
}
|
|
52568
|
-
const absolutePath =
|
|
52675
|
+
const absolutePath = join15(current, entry2.name);
|
|
52569
52676
|
if (entry2.isDirectory()) {
|
|
52570
52677
|
if (!SKIP_DIRS.has(entry2.name))
|
|
52571
52678
|
walkSourceFiles(root, absolutePath, files);
|
|
@@ -53918,7 +54025,7 @@ function getAdapterDocsFingerprint() {
|
|
|
53918
54025
|
// src/lib/inbox-intake.ts
|
|
53919
54026
|
init_database();
|
|
53920
54027
|
init_tasks();
|
|
53921
|
-
import { existsSync as
|
|
54028
|
+
import { existsSync as existsSync18, readFileSync as readFileSync14 } from "fs";
|
|
53922
54029
|
import { basename as basename5 } from "path";
|
|
53923
54030
|
import { createHash as createHash19 } from "crypto";
|
|
53924
54031
|
init_secret_redaction();
|
|
@@ -53964,7 +54071,7 @@ function loadRawContent(input) {
|
|
|
53964
54071
|
}
|
|
53965
54072
|
}
|
|
53966
54073
|
if (input.file_path) {
|
|
53967
|
-
if (!
|
|
54074
|
+
if (!existsSync18(input.file_path))
|
|
53968
54075
|
throw new Error(`File not found: ${input.file_path}`);
|
|
53969
54076
|
const raw = readFileSync14(input.file_path, "utf8");
|
|
53970
54077
|
const name = basename5(input.file_path).toLowerCase();
|
|
@@ -54585,7 +54692,7 @@ function formatNlIntakePreviewText(preview) {
|
|
|
54585
54692
|
// src/lib/issue-importers.ts
|
|
54586
54693
|
init_database();
|
|
54587
54694
|
init_tasks();
|
|
54588
|
-
import { existsSync as
|
|
54695
|
+
import { existsSync as existsSync19, readFileSync as readFileSync15 } from "fs";
|
|
54589
54696
|
var ISSUE_IMPORT_SCHEMA = "todos.issue_import.v1";
|
|
54590
54697
|
var ISSUE_SOURCES = ["github", "linear", "jira", "auto"];
|
|
54591
54698
|
var GITHUB_LABEL_PRIORITY = {
|
|
@@ -54804,7 +54911,7 @@ function parseIssueExport(data, source9 = "auto") {
|
|
|
54804
54911
|
return normalized;
|
|
54805
54912
|
}
|
|
54806
54913
|
function loadIssueExportFromFile(path) {
|
|
54807
|
-
if (!
|
|
54914
|
+
if (!existsSync19(path))
|
|
54808
54915
|
throw new Error(`File not found: ${path}`);
|
|
54809
54916
|
return JSON.parse(readFileSync15(path, "utf8"));
|
|
54810
54917
|
}
|
|
@@ -54965,8 +55072,8 @@ todos import issues ./linear.json --source linear --dry-run
|
|
|
54965
55072
|
init_sync_utils();
|
|
54966
55073
|
init_database();
|
|
54967
55074
|
init_secret_redaction();
|
|
54968
|
-
import { existsSync as
|
|
54969
|
-
import { join as
|
|
55075
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync12, writeFileSync as writeFileSync10 } from "fs";
|
|
55076
|
+
import { join as join16, dirname as dirname10 } from "path";
|
|
54970
55077
|
var RUN_RECORD_SCHEMA = "todos.run_record.v1";
|
|
54971
55078
|
var RUN_RECORD_STATUSES = ["active", "completed", "failed", "archived"];
|
|
54972
55079
|
function parseJsonArray3(raw, fallback = []) {
|
|
@@ -55159,7 +55266,7 @@ function buildRunReplayBundle(id, db) {
|
|
|
55159
55266
|
}
|
|
55160
55267
|
function exportRunReplay(id, outputPath, db) {
|
|
55161
55268
|
const bundle = buildRunReplayBundle(id, db);
|
|
55162
|
-
const path = outputPath ??
|
|
55269
|
+
const path = outputPath ?? join16(process.cwd(), ".todos", "replays", `${id.slice(0, 8)}.json`);
|
|
55163
55270
|
mkdirSync12(dirname10(path), { recursive: true });
|
|
55164
55271
|
writeFileSync10(path, JSON.stringify(bundle, null, 2));
|
|
55165
55272
|
const d = db || getDatabase();
|
|
@@ -55199,15 +55306,15 @@ function formatRunRecordMarkdown(record) {
|
|
|
55199
55306
|
`;
|
|
55200
55307
|
}
|
|
55201
55308
|
function getDefaultReplayDir() {
|
|
55202
|
-
const local =
|
|
55203
|
-
if (
|
|
55309
|
+
const local = join16(process.cwd(), ".todos", "replays");
|
|
55310
|
+
if (existsSync20(join16(process.cwd(), ".todos")))
|
|
55204
55311
|
return local;
|
|
55205
|
-
return
|
|
55312
|
+
return join16(getTodosGlobalDir(), "replays");
|
|
55206
55313
|
}
|
|
55207
55314
|
// src/lib/release-checks.ts
|
|
55208
55315
|
init_secret_redaction();
|
|
55209
|
-
import { existsSync as
|
|
55210
|
-
import { join as
|
|
55316
|
+
import { existsSync as existsSync21, readFileSync as readFileSync16, readdirSync as readdirSync4, statSync as statSync7 } from "fs";
|
|
55317
|
+
import { join as join17, relative as relative5 } from "path";
|
|
55211
55318
|
var RELEASE_CHECK_SCHEMA = "todos.release_check.v1";
|
|
55212
55319
|
var FORBIDDEN_DIST_PATTERNS = [
|
|
55213
55320
|
{
|
|
@@ -55220,16 +55327,16 @@ var FORBIDDEN_DIST_PATTERNS = [
|
|
|
55220
55327
|
];
|
|
55221
55328
|
var REQUIRED_BINS = ["todos", "todos-mcp", "todos-serve"];
|
|
55222
55329
|
function readPackageJson3(root) {
|
|
55223
|
-
const path =
|
|
55224
|
-
if (!
|
|
55330
|
+
const path = join17(root, "package.json");
|
|
55331
|
+
if (!existsSync21(path))
|
|
55225
55332
|
throw new Error(`package.json not found in ${root}`);
|
|
55226
55333
|
return JSON.parse(readFileSync16(path, "utf8"));
|
|
55227
55334
|
}
|
|
55228
55335
|
function walkFiles(dir, acc = []) {
|
|
55229
|
-
if (!
|
|
55336
|
+
if (!existsSync21(dir))
|
|
55230
55337
|
return acc;
|
|
55231
55338
|
for (const entry2 of readdirSync4(dir)) {
|
|
55232
|
-
const full =
|
|
55339
|
+
const full = join17(dir, entry2);
|
|
55233
55340
|
const st = statSync7(full);
|
|
55234
55341
|
if (st.isDirectory())
|
|
55235
55342
|
walkFiles(full, acc);
|
|
@@ -55247,8 +55354,8 @@ function auditPackageContents(root) {
|
|
|
55247
55354
|
checks.push({ id: "files_dist", severity: "error", message: "package.json files must include dist" });
|
|
55248
55355
|
}
|
|
55249
55356
|
for (const pattern of files) {
|
|
55250
|
-
const target =
|
|
55251
|
-
if (!
|
|
55357
|
+
const target = join17(root, pattern);
|
|
55358
|
+
if (!existsSync21(target)) {
|
|
55252
55359
|
checks.push({ id: `files_missing_${pattern}`, severity: "error", message: `Published file path missing: ${pattern}` });
|
|
55253
55360
|
}
|
|
55254
55361
|
}
|
|
@@ -55262,8 +55369,8 @@ function auditPackageContents(root) {
|
|
|
55262
55369
|
checks.push({ id: `bin_${name}`, severity: "error", message: `Missing bin entry: ${name}` });
|
|
55263
55370
|
continue;
|
|
55264
55371
|
}
|
|
55265
|
-
const binPath =
|
|
55266
|
-
if (!
|
|
55372
|
+
const binPath = join17(root, rel);
|
|
55373
|
+
if (!existsSync21(binPath)) {
|
|
55267
55374
|
checks.push({ id: `bin_path_${name}`, severity: "error", message: `Bin file missing: ${rel}` });
|
|
55268
55375
|
} else {
|
|
55269
55376
|
checks.push({ id: `bin_ok_${name}`, severity: "info", message: `Bin present: ${name} \u2192 ${rel}` });
|
|
@@ -55280,8 +55387,8 @@ function auditPackageContents(root) {
|
|
|
55280
55387
|
}
|
|
55281
55388
|
function scanDistArtifacts(root) {
|
|
55282
55389
|
const checks = [];
|
|
55283
|
-
const distDir =
|
|
55284
|
-
if (!
|
|
55390
|
+
const distDir = join17(root, "dist");
|
|
55391
|
+
if (!existsSync21(distDir)) {
|
|
55285
55392
|
checks.push({ id: "dist_missing", severity: "error", message: "dist/ directory not found \u2014 run bun run build" });
|
|
55286
55393
|
return checks;
|
|
55287
55394
|
}
|
|
@@ -55591,15 +55698,15 @@ function renderReleaseNotesMarkdown(document) {
|
|
|
55591
55698
|
// src/lib/db-backup.ts
|
|
55592
55699
|
init_database();
|
|
55593
55700
|
init_migrations();
|
|
55594
|
-
import { existsSync as
|
|
55595
|
-
import { dirname as dirname11, join as
|
|
55701
|
+
import { existsSync as existsSync22, copyFileSync, mkdirSync as mkdirSync13, readFileSync as readFileSync17, renameSync, statSync as statSync8, writeFileSync as writeFileSync11, unlinkSync } from "fs";
|
|
55702
|
+
import { dirname as dirname11, join as join18, resolve as resolve17 } from "path";
|
|
55596
55703
|
import { Database as Database4 } from "bun:sqlite";
|
|
55597
55704
|
var DB_BACKUP_SCHEMA = "todos.db_backup.v1";
|
|
55598
55705
|
function resolveDbPath(dbPath) {
|
|
55599
55706
|
if (dbPath)
|
|
55600
|
-
return
|
|
55707
|
+
return resolve17(dbPath);
|
|
55601
55708
|
if (process.env["TODOS_DB_PATH"] && process.env["TODOS_DB_PATH"] !== ":memory:") {
|
|
55602
|
-
return
|
|
55709
|
+
return resolve17(process.env["TODOS_DB_PATH"]);
|
|
55603
55710
|
}
|
|
55604
55711
|
const db = getDatabase();
|
|
55605
55712
|
const filename = db.filename;
|
|
@@ -55609,7 +55716,7 @@ function resolveDbPath(dbPath) {
|
|
|
55609
55716
|
}
|
|
55610
55717
|
function backupDatabase(outputPath, sourcePath) {
|
|
55611
55718
|
const source9 = resolveDbPath(sourcePath);
|
|
55612
|
-
if (!
|
|
55719
|
+
if (!existsSync22(source9))
|
|
55613
55720
|
throw new Error(`Database not found: ${source9}`);
|
|
55614
55721
|
mkdirSync13(dirname11(outputPath), { recursive: true });
|
|
55615
55722
|
closeDatabase();
|
|
@@ -55632,13 +55739,13 @@ function backupDatabase(outputPath, sourcePath) {
|
|
|
55632
55739
|
};
|
|
55633
55740
|
}
|
|
55634
55741
|
function restoreDatabase(backupPath, targetPath) {
|
|
55635
|
-
if (!
|
|
55742
|
+
if (!existsSync22(backupPath))
|
|
55636
55743
|
throw new Error(`Backup not found: ${backupPath}`);
|
|
55637
55744
|
const integrity = checkDatabaseIntegrity(backupPath);
|
|
55638
55745
|
if (!integrity.ok) {
|
|
55639
55746
|
throw new Error(`Backup failed integrity check: ${integrity.errors.join("; ")}`);
|
|
55640
55747
|
}
|
|
55641
|
-
const target = targetPath ?
|
|
55748
|
+
const target = targetPath ? resolve17(targetPath) : resolveDbPath();
|
|
55642
55749
|
mkdirSync13(dirname11(target), { recursive: true });
|
|
55643
55750
|
closeDatabase();
|
|
55644
55751
|
const staging = `${target}.restore.tmp`;
|
|
@@ -55648,7 +55755,7 @@ function restoreDatabase(backupPath, targetPath) {
|
|
|
55648
55755
|
copyFileSync(backupPath, staging);
|
|
55649
55756
|
for (const sidecar of [`${target}-wal`, `${target}-shm`]) {
|
|
55650
55757
|
try {
|
|
55651
|
-
if (
|
|
55758
|
+
if (existsSync22(sidecar))
|
|
55652
55759
|
unlinkSync(sidecar);
|
|
55653
55760
|
} catch {}
|
|
55654
55761
|
}
|
|
@@ -55663,9 +55770,9 @@ function restoreDatabase(backupPath, targetPath) {
|
|
|
55663
55770
|
};
|
|
55664
55771
|
}
|
|
55665
55772
|
function checkDatabaseIntegrity(dbPath) {
|
|
55666
|
-
const path = dbPath ?
|
|
55773
|
+
const path = dbPath ? resolve17(dbPath) : resolveDbPath();
|
|
55667
55774
|
const errors2 = [];
|
|
55668
|
-
if (!
|
|
55775
|
+
if (!existsSync22(path)) {
|
|
55669
55776
|
return {
|
|
55670
55777
|
schema_version: DB_BACKUP_SCHEMA,
|
|
55671
55778
|
path,
|
|
@@ -55728,7 +55835,7 @@ function checkDatabaseIntegrity(dbPath) {
|
|
|
55728
55835
|
};
|
|
55729
55836
|
}
|
|
55730
55837
|
function compactDatabase(dbPath) {
|
|
55731
|
-
const path = dbPath ?
|
|
55838
|
+
const path = dbPath ? resolve17(dbPath) : resolveDbPath();
|
|
55732
55839
|
const before = statSync8(path).size;
|
|
55733
55840
|
const db = new Database4(path);
|
|
55734
55841
|
db.exec("VACUUM");
|
|
@@ -55738,7 +55845,7 @@ function compactDatabase(dbPath) {
|
|
|
55738
55845
|
return { path, bytes_before: before, bytes_after: after };
|
|
55739
55846
|
}
|
|
55740
55847
|
function migrationDryRun(dbPath) {
|
|
55741
|
-
const path = dbPath ?
|
|
55848
|
+
const path = dbPath ? resolve17(dbPath) : resolveDbPath();
|
|
55742
55849
|
const db = new Database4(path, { readonly: true });
|
|
55743
55850
|
let current = 0;
|
|
55744
55851
|
try {
|
|
@@ -55762,13 +55869,13 @@ function migrationDryRun(dbPath) {
|
|
|
55762
55869
|
};
|
|
55763
55870
|
}
|
|
55764
55871
|
function defaultBackupPath(dbPath) {
|
|
55765
|
-
const base = dbPath ? dirname11(
|
|
55872
|
+
const base = dbPath ? dirname11(resolve17(dbPath)) : dirname11(resolveDbPath());
|
|
55766
55873
|
const stamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
55767
|
-
return
|
|
55874
|
+
return join18(base, "backups", `todos-${stamp}.db`);
|
|
55768
55875
|
}
|
|
55769
55876
|
function readBackupManifest(backupPath) {
|
|
55770
55877
|
const manifestPath = `${backupPath}.json`;
|
|
55771
|
-
if (!
|
|
55878
|
+
if (!existsSync22(manifestPath))
|
|
55772
55879
|
return null;
|
|
55773
55880
|
try {
|
|
55774
55881
|
return JSON.parse(readFileSync17(manifestPath, "utf8"));
|
|
@@ -56289,15 +56396,15 @@ ${SCHEMA_ENTITIES.map((e) => `- **${e}**: \`${JSON_SCHEMAS[e].schema_version}\``
|
|
|
56289
56396
|
}
|
|
56290
56397
|
function exportSchemasToDirectory(dir) {
|
|
56291
56398
|
const { mkdirSync: mkdirSync14, writeFileSync: writeFileSync12 } = __require("fs");
|
|
56292
|
-
const { join:
|
|
56399
|
+
const { join: join19 } = __require("path");
|
|
56293
56400
|
mkdirSync14(dir, { recursive: true });
|
|
56294
56401
|
const written = [];
|
|
56295
56402
|
for (const entity of SCHEMA_ENTITIES) {
|
|
56296
|
-
const path =
|
|
56403
|
+
const path = join19(dir, `${entity}.${JSON_SCHEMAS[entity].schema_version.replace(/\./g, "-")}.json`);
|
|
56297
56404
|
writeFileSync12(path, JSON.stringify(JSON_SCHEMAS[entity], null, 2));
|
|
56298
56405
|
written.push(path);
|
|
56299
56406
|
}
|
|
56300
|
-
const catalogPath =
|
|
56407
|
+
const catalogPath = join19(dir, "catalog.json");
|
|
56301
56408
|
writeFileSync12(catalogPath, JSON.stringify({
|
|
56302
56409
|
catalog_version: JSON_SCHEMA_CATALOG_VERSION,
|
|
56303
56410
|
semver: SCHEMA_SEMVER,
|
|
@@ -58832,7 +58939,7 @@ init_templates();
|
|
|
58832
58939
|
init_database();
|
|
58833
58940
|
init_templates();
|
|
58834
58941
|
import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync14 } from "fs";
|
|
58835
|
-
import { join as
|
|
58942
|
+
import { join as join19 } from "path";
|
|
58836
58943
|
var BUILTIN_TEMPLATE_LIBRARY_VERSION = "2026-05-21";
|
|
58837
58944
|
var BUILTIN_TEMPLATE_LIBRARY_SOURCE = "bundled-local-template-library";
|
|
58838
58945
|
var TEMPLATE_LIBRARY_SCHEMA = "todos.template_library.v1";
|
|
@@ -59108,7 +59215,7 @@ function writeBuiltinTemplateFiles(directory) {
|
|
|
59108
59215
|
mkdirSync16(directory, { recursive: true });
|
|
59109
59216
|
const files = [];
|
|
59110
59217
|
for (const entry2 of exportBuiltinTemplateFiles()) {
|
|
59111
|
-
const path =
|
|
59218
|
+
const path = join19(directory, entry2.filename);
|
|
59112
59219
|
writeFileSync14(path, `${JSON.stringify(entry2.template, null, 2)}
|
|
59113
59220
|
`, "utf-8");
|
|
59114
59221
|
files.push(path);
|
|
@@ -59400,9 +59507,9 @@ init_tasks();
|
|
|
59400
59507
|
init_redaction();
|
|
59401
59508
|
init_sync_utils();
|
|
59402
59509
|
import { createHash as createHash20 } from "crypto";
|
|
59403
|
-
import { existsSync as
|
|
59510
|
+
import { existsSync as existsSync23, readFileSync as readFileSync20, statSync as statSync9 } from "fs";
|
|
59404
59511
|
import { hostname as hostname3, platform, arch } from "os";
|
|
59405
|
-
import { dirname as dirname15, join as
|
|
59512
|
+
import { dirname as dirname15, join as join20, resolve as resolve18 } from "path";
|
|
59406
59513
|
import { tmpdir as tmpdir3 } from "os";
|
|
59407
59514
|
var MANIFEST_FILES = ["package.json", "dashboard/package.json", "sdk/package.json"];
|
|
59408
59515
|
var LOCKFILES = ["bun.lock", "bun.lockb", "package-lock.json", "npm-shrinkwrap.json"];
|
|
@@ -59424,8 +59531,8 @@ function sha2566(value) {
|
|
|
59424
59531
|
return createHash20("sha256").update(value).digest("hex");
|
|
59425
59532
|
}
|
|
59426
59533
|
function fileRecord(root, relativePath) {
|
|
59427
|
-
const path =
|
|
59428
|
-
if (!
|
|
59534
|
+
const path = join20(root, relativePath);
|
|
59535
|
+
if (!existsSync23(path))
|
|
59429
59536
|
return null;
|
|
59430
59537
|
const stat = statSync9(path);
|
|
59431
59538
|
if (!stat.isFile())
|
|
@@ -59437,7 +59544,7 @@ function manifestRecord(root, relativePath) {
|
|
|
59437
59544
|
const base = fileRecord(root, relativePath);
|
|
59438
59545
|
if (!base)
|
|
59439
59546
|
return null;
|
|
59440
|
-
const parsed = readJsonFile(
|
|
59547
|
+
const parsed = readJsonFile(join20(root, relativePath));
|
|
59441
59548
|
if (!parsed)
|
|
59442
59549
|
return { ...base, redacted: {} };
|
|
59443
59550
|
const redacted = redactValue({
|
|
@@ -59532,15 +59639,15 @@ function commandEnv(env, includeValues) {
|
|
|
59532
59639
|
function defaultSnapshotDir() {
|
|
59533
59640
|
const dbPath = getDatabasePath();
|
|
59534
59641
|
if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
|
|
59535
|
-
return
|
|
59536
|
-
return
|
|
59642
|
+
return join20(tmpdir3(), "hasna-todos", "environment-snapshots");
|
|
59643
|
+
return join20(dirname15(resolve18(dbPath)), "environment-snapshots");
|
|
59537
59644
|
}
|
|
59538
59645
|
function snapshotWithId(snapshot) {
|
|
59539
59646
|
const digest3 = sha2566(JSON.stringify(snapshot)).slice(0, 24);
|
|
59540
59647
|
return { id: `env_${digest3}`, ...snapshot };
|
|
59541
59648
|
}
|
|
59542
59649
|
function captureEnvironmentSnapshot(input = {}) {
|
|
59543
|
-
const root =
|
|
59650
|
+
const root = resolve18(input.root || process.cwd());
|
|
59544
59651
|
const env = input.env || process.env;
|
|
59545
59652
|
const warnings = [];
|
|
59546
59653
|
const manifests = MANIFEST_FILES.map((file) => manifestRecord(root, file)).filter((file) => Boolean(file));
|
|
@@ -59580,13 +59687,13 @@ function captureEnvironmentSnapshot(input = {}) {
|
|
|
59580
59687
|
});
|
|
59581
59688
|
}
|
|
59582
59689
|
function writeEnvironmentSnapshot(snapshot, outputPath) {
|
|
59583
|
-
const path = outputPath ?
|
|
59690
|
+
const path = outputPath ? resolve18(outputPath) : join20(defaultSnapshotDir(), `${snapshot.id}.json`);
|
|
59584
59691
|
ensureDir(dirname15(path));
|
|
59585
59692
|
writeJsonFile(path, snapshot);
|
|
59586
59693
|
return path;
|
|
59587
59694
|
}
|
|
59588
59695
|
function readEnvironmentSnapshot(path) {
|
|
59589
|
-
const snapshot = readJsonFile(
|
|
59696
|
+
const snapshot = readJsonFile(resolve18(path));
|
|
59590
59697
|
if (!snapshot || snapshot.schema_version !== 1 || typeof snapshot.id !== "string") {
|
|
59591
59698
|
throw new Error(`Invalid environment snapshot: ${path}`);
|
|
59592
59699
|
}
|
|
@@ -59675,7 +59782,7 @@ init_projects();
|
|
|
59675
59782
|
init_plans();
|
|
59676
59783
|
import { createHash as createHash21 } from "crypto";
|
|
59677
59784
|
import { mkdirSync as mkdirSync18, writeFileSync as writeFileSync16 } from "fs";
|
|
59678
|
-
import { dirname as dirname16, join as
|
|
59785
|
+
import { dirname as dirname16, join as join21 } from "path";
|
|
59679
59786
|
var DECISION_RECORD_SCHEMA = "todos.decision_record.v1";
|
|
59680
59787
|
var KNOWLEDGE_SNAPSHOT_SCHEMA = "todos.knowledge_snapshot.v1";
|
|
59681
59788
|
var DECISION_STATUSES = ["proposed", "accepted", "deprecated", "superseded", "rejected"];
|
|
@@ -59905,7 +60012,7 @@ function exportDecisionRecord(id, outputPath, format = "markdown", db) {
|
|
|
59905
60012
|
if (!record)
|
|
59906
60013
|
throw new Error(`Decision record not found: ${id}`);
|
|
59907
60014
|
const content = format === "markdown" ? formatDecisionRecordMarkdown(record) : JSON.stringify(record, null, 2);
|
|
59908
|
-
const path = outputPath ??
|
|
60015
|
+
const path = outputPath ?? join21(process.cwd(), ".todos", "decisions", `${record.short_ref}.${format === "markdown" ? "md" : "json"}`);
|
|
59909
60016
|
mkdirSync18(dirname16(path), { recursive: true });
|
|
59910
60017
|
writeFileSync16(path, content, "utf8");
|
|
59911
60018
|
return { path, content };
|
|
@@ -60053,7 +60160,7 @@ function exportKnowledgeSnapshot(id, outputPath, format = "markdown", db) {
|
|
|
60053
60160
|
throw new Error(`Knowledge snapshot not found: ${id}`);
|
|
60054
60161
|
const content = format === "markdown" ? formatKnowledgeSnapshotMarkdown(record) : JSON.stringify(record, null, 2);
|
|
60055
60162
|
const slug = record.title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
|
|
60056
|
-
const path = outputPath ??
|
|
60163
|
+
const path = outputPath ?? join21(process.cwd(), ".todos", "knowledge", `${slug || record.id.slice(0, 8)}.${format === "markdown" ? "md" : "json"}`);
|
|
60057
60164
|
mkdirSync18(dirname16(path), { recursive: true });
|
|
60058
60165
|
writeFileSync16(path, content, "utf8");
|
|
60059
60166
|
return { path, content };
|
|
@@ -60352,8 +60459,8 @@ todos report export --kind retrospective --days 14 --format markdown --out retro
|
|
|
60352
60459
|
`;
|
|
60353
60460
|
}
|
|
60354
60461
|
// src/lib/command-aliases.ts
|
|
60355
|
-
import { existsSync as
|
|
60356
|
-
import { join as
|
|
60462
|
+
import { existsSync as existsSync24, readFileSync as readFileSync21, writeFileSync as writeFileSync18, mkdirSync as mkdirSync20 } from "fs";
|
|
60463
|
+
import { join as join22 } from "path";
|
|
60357
60464
|
var COMMAND_ALIASES_SCHEMA = "todos.command_aliases.v1";
|
|
60358
60465
|
var RESERVED = new Set([...listTopLevelCommands(), "help", "version", "alias", "shortcuts"]);
|
|
60359
60466
|
var BUILTIN_SHORTCUTS = [
|
|
@@ -60372,7 +60479,7 @@ var BUILTIN_SHORTCUTS = [
|
|
|
60372
60479
|
{ pattern: /^reports?$/, argv: ["report", "docs"], explain: "Report export documentation" }
|
|
60373
60480
|
];
|
|
60374
60481
|
function aliasesPath(cwd = process.cwd()) {
|
|
60375
|
-
return
|
|
60482
|
+
return join22(cwd, ".todos", "aliases.json");
|
|
60376
60483
|
}
|
|
60377
60484
|
function emptyStore() {
|
|
60378
60485
|
return { schema_version: COMMAND_ALIASES_SCHEMA, aliases: {}, updated_at: new Date(0).toISOString() };
|
|
@@ -60389,7 +60496,7 @@ function validateAliasName(name) {
|
|
|
60389
60496
|
}
|
|
60390
60497
|
function loadAliasStore(cwd) {
|
|
60391
60498
|
const path = aliasesPath(cwd);
|
|
60392
|
-
if (!
|
|
60499
|
+
if (!existsSync24(path))
|
|
60393
60500
|
return emptyStore();
|
|
60394
60501
|
const parsed = JSON.parse(readFileSync21(path, "utf8"));
|
|
60395
60502
|
if (parsed.schema_version !== COMMAND_ALIASES_SCHEMA) {
|
|
@@ -60399,7 +60506,7 @@ function loadAliasStore(cwd) {
|
|
|
60399
60506
|
}
|
|
60400
60507
|
function saveAliasStore(store, cwd) {
|
|
60401
60508
|
const path = aliasesPath(cwd);
|
|
60402
|
-
mkdirSync20(
|
|
60509
|
+
mkdirSync20(join22(path, ".."), { recursive: true });
|
|
60403
60510
|
store.updated_at = new Date().toISOString();
|
|
60404
60511
|
writeFileSync18(path, JSON.stringify(store, null, 2), "utf8");
|
|
60405
60512
|
}
|
|
@@ -61054,18 +61161,18 @@ function createBranchWorkPlan(input, db) {
|
|
|
61054
61161
|
init_database();
|
|
61055
61162
|
init_templates();
|
|
61056
61163
|
init_plans();
|
|
61057
|
-
import { existsSync as
|
|
61058
|
-
import { join as
|
|
61164
|
+
import { existsSync as existsSync25, readFileSync as readFileSync22, writeFileSync as writeFileSync19, mkdirSync as mkdirSync21 } from "fs";
|
|
61165
|
+
import { join as join23 } from "path";
|
|
61059
61166
|
var USER_SCAFFOLD_SCHEMA = "todos.user_scaffold.v1";
|
|
61060
61167
|
var SCAFFOLD_KINDS = ["task", "project", "plan", "checklist", "contract", "verification_policy"];
|
|
61061
61168
|
function storeDir(cwd = process.cwd()) {
|
|
61062
|
-
return
|
|
61169
|
+
return join23(cwd, ".todos", "scaffolds");
|
|
61063
61170
|
}
|
|
61064
61171
|
function storePath(cwd) {
|
|
61065
|
-
return
|
|
61172
|
+
return join23(storeDir(cwd), "store.json");
|
|
61066
61173
|
}
|
|
61067
61174
|
function versionsDir(cwd) {
|
|
61068
|
-
return
|
|
61175
|
+
return join23(storeDir(cwd), "versions");
|
|
61069
61176
|
}
|
|
61070
61177
|
function slugify4(name) {
|
|
61071
61178
|
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
@@ -61075,7 +61182,7 @@ function emptyStore2() {
|
|
|
61075
61182
|
}
|
|
61076
61183
|
function loadUserScaffoldStore(cwd) {
|
|
61077
61184
|
const path = storePath(cwd);
|
|
61078
|
-
if (!
|
|
61185
|
+
if (!existsSync25(path))
|
|
61079
61186
|
return emptyStore2();
|
|
61080
61187
|
const parsed = JSON.parse(readFileSync22(path, "utf8"));
|
|
61081
61188
|
if (parsed.schema_version !== USER_SCAFFOLD_SCHEMA) {
|
|
@@ -61090,7 +61197,7 @@ function saveUserScaffoldStore(store, cwd) {
|
|
|
61090
61197
|
}
|
|
61091
61198
|
function snapshotVersion(scaffold, cwd) {
|
|
61092
61199
|
mkdirSync21(versionsDir(cwd), { recursive: true });
|
|
61093
|
-
const path =
|
|
61200
|
+
const path = join23(versionsDir(cwd), `${scaffold.id}-v${scaffold.version}.json`);
|
|
61094
61201
|
writeFileSync19(path, JSON.stringify(scaffold, null, 2), "utf8");
|
|
61095
61202
|
}
|
|
61096
61203
|
function listUserScaffolds(kind, cwd) {
|
|
@@ -61337,7 +61444,7 @@ function listLinkedTemplates(db, cwd) {
|
|
|
61337
61444
|
// src/lib/agent-workflow-demo.ts
|
|
61338
61445
|
init_database();
|
|
61339
61446
|
import { mkdtempSync } from "fs";
|
|
61340
|
-
import { join as
|
|
61447
|
+
import { join as join24 } from "path";
|
|
61341
61448
|
import { tmpdir as tmpdir4 } from "os";
|
|
61342
61449
|
init_projects();
|
|
61343
61450
|
init_task_lists();
|
|
@@ -61358,7 +61465,7 @@ function setupEphemeralDemoDb(options = {}) {
|
|
|
61358
61465
|
if (options.db_path) {
|
|
61359
61466
|
db_path = options.db_path;
|
|
61360
61467
|
} else if (options.persist) {
|
|
61361
|
-
db_path =
|
|
61468
|
+
db_path = join24(mkdtempSync(join24(tmpdir4(), "todos-demo-")), "todos.db");
|
|
61362
61469
|
} else {
|
|
61363
61470
|
db_path = ":memory:";
|
|
61364
61471
|
}
|
|
@@ -63695,16 +63802,16 @@ function runSearchView(idOrName, db) {
|
|
|
63695
63802
|
init_tasks();
|
|
63696
63803
|
init_config2();
|
|
63697
63804
|
init_sync_utils();
|
|
63698
|
-
import { existsSync as
|
|
63699
|
-
import { join as
|
|
63805
|
+
import { existsSync as existsSync26, readFileSync as readFileSync23, readdirSync as readdirSync5, writeFileSync as writeFileSync20 } from "fs";
|
|
63806
|
+
import { join as join25 } from "path";
|
|
63700
63807
|
function getTaskListDir(taskListId) {
|
|
63701
|
-
return
|
|
63808
|
+
return join25(HOME, ".claude", "tasks", taskListId);
|
|
63702
63809
|
}
|
|
63703
63810
|
function readClaudeTask(dir, filename) {
|
|
63704
|
-
return readJsonFile(
|
|
63811
|
+
return readJsonFile(join25(dir, filename));
|
|
63705
63812
|
}
|
|
63706
63813
|
function writeClaudeTask(dir, task3) {
|
|
63707
|
-
writeJsonFile(
|
|
63814
|
+
writeJsonFile(join25(dir, `${task3.id}.json`), task3);
|
|
63708
63815
|
}
|
|
63709
63816
|
function toClaudeStatus(status3) {
|
|
63710
63817
|
if (status3 === "pending" || status3 === "in_progress" || status3 === "completed") {
|
|
@@ -63716,14 +63823,14 @@ function toSqliteStatus(status3) {
|
|
|
63716
63823
|
return status3;
|
|
63717
63824
|
}
|
|
63718
63825
|
function readPrefixCounter(dir) {
|
|
63719
|
-
const path =
|
|
63720
|
-
if (!
|
|
63826
|
+
const path = join25(dir, ".prefix-counter");
|
|
63827
|
+
if (!existsSync26(path))
|
|
63721
63828
|
return 0;
|
|
63722
63829
|
const val = parseInt(readFileSync23(path, "utf-8").trim(), 10);
|
|
63723
63830
|
return isNaN(val) ? 0 : val;
|
|
63724
63831
|
}
|
|
63725
63832
|
function writePrefixCounter(dir, value) {
|
|
63726
|
-
writeFileSync20(
|
|
63833
|
+
writeFileSync20(join25(dir, ".prefix-counter"), String(value));
|
|
63727
63834
|
}
|
|
63728
63835
|
function formatPrefixedSubject(title, prefix, counter) {
|
|
63729
63836
|
const padded = String(counter).padStart(5, "0");
|
|
@@ -63750,7 +63857,7 @@ function taskToClaudeTask(task3, claudeTaskId, existingMeta) {
|
|
|
63750
63857
|
}
|
|
63751
63858
|
function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
63752
63859
|
const dir = getTaskListDir(taskListId);
|
|
63753
|
-
if (!
|
|
63860
|
+
if (!existsSync26(dir))
|
|
63754
63861
|
ensureDir(dir);
|
|
63755
63862
|
const filter = {};
|
|
63756
63863
|
if (projectId)
|
|
@@ -63759,7 +63866,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
63759
63866
|
const existingByTodosId = new Map;
|
|
63760
63867
|
const files = listJsonFiles(dir);
|
|
63761
63868
|
for (const f of files) {
|
|
63762
|
-
const path =
|
|
63869
|
+
const path = join25(dir, f);
|
|
63763
63870
|
const ct = readClaudeTask(dir, f);
|
|
63764
63871
|
if (ct?.metadata?.["todos_id"]) {
|
|
63765
63872
|
existingByTodosId.set(ct.metadata["todos_id"], { task: ct, mtimeMs: getFileMtimeMs(path) });
|
|
@@ -63848,7 +63955,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
63848
63955
|
}
|
|
63849
63956
|
function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
|
|
63850
63957
|
const dir = getTaskListDir(taskListId);
|
|
63851
|
-
if (!
|
|
63958
|
+
if (!existsSync26(dir)) {
|
|
63852
63959
|
return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
|
|
63853
63960
|
}
|
|
63854
63961
|
const files = readdirSync5(dir).filter((f) => f.endsWith(".json"));
|
|
@@ -63868,7 +63975,7 @@ function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
63868
63975
|
}
|
|
63869
63976
|
for (const f of files) {
|
|
63870
63977
|
try {
|
|
63871
|
-
const filePath =
|
|
63978
|
+
const filePath = join25(dir, f);
|
|
63872
63979
|
const ct = readClaudeTask(dir, f);
|
|
63873
63980
|
if (!ct)
|
|
63874
63981
|
continue;
|
|
@@ -63939,20 +64046,20 @@ function syncClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
63939
64046
|
init_tasks();
|
|
63940
64047
|
init_sync_utils();
|
|
63941
64048
|
init_config2();
|
|
63942
|
-
import { existsSync as
|
|
63943
|
-
import { join as
|
|
64049
|
+
import { existsSync as existsSync27 } from "fs";
|
|
64050
|
+
import { join as join26 } from "path";
|
|
63944
64051
|
function agentBaseDir(agent) {
|
|
63945
64052
|
const key2 = `TODOS_${agent.toUpperCase()}_TASKS_DIR`;
|
|
63946
|
-
return process.env[key2] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] ||
|
|
64053
|
+
return process.env[key2] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] || join26(getTodosGlobalDir(), "agents");
|
|
63947
64054
|
}
|
|
63948
64055
|
function getTaskListDir2(agent, taskListId) {
|
|
63949
|
-
return
|
|
64056
|
+
return join26(agentBaseDir(agent), agent, taskListId);
|
|
63950
64057
|
}
|
|
63951
64058
|
function readAgentTask(dir, filename) {
|
|
63952
|
-
return readJsonFile(
|
|
64059
|
+
return readJsonFile(join26(dir, filename));
|
|
63953
64060
|
}
|
|
63954
64061
|
function writeAgentTask(dir, task3) {
|
|
63955
|
-
writeJsonFile(
|
|
64062
|
+
writeJsonFile(join26(dir, `${task3.id}.json`), task3);
|
|
63956
64063
|
}
|
|
63957
64064
|
function taskToAgentTask(task3, externalId, existingMeta) {
|
|
63958
64065
|
return withSyncFingerprint({
|
|
@@ -63977,7 +64084,7 @@ function metadataKey(agent) {
|
|
|
63977
64084
|
}
|
|
63978
64085
|
function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
63979
64086
|
const dir = getTaskListDir2(agent, taskListId);
|
|
63980
|
-
if (!
|
|
64087
|
+
if (!existsSync27(dir))
|
|
63981
64088
|
ensureDir(dir);
|
|
63982
64089
|
const filter = {};
|
|
63983
64090
|
if (projectId)
|
|
@@ -63986,7 +64093,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
|
63986
64093
|
const existingByTodosId = new Map;
|
|
63987
64094
|
const files = listJsonFiles(dir);
|
|
63988
64095
|
for (const f of files) {
|
|
63989
|
-
const path =
|
|
64096
|
+
const path = join26(dir, f);
|
|
63990
64097
|
const at = readAgentTask(dir, f);
|
|
63991
64098
|
if (at?.metadata?.["todos_id"]) {
|
|
63992
64099
|
existingByTodosId.set(at.metadata["todos_id"], { task: at, mtimeMs: getFileMtimeMs(path) });
|
|
@@ -64062,7 +64169,7 @@ function pushToAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
|
64062
64169
|
}
|
|
64063
64170
|
function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
64064
64171
|
const dir = getTaskListDir2(agent, taskListId);
|
|
64065
|
-
if (!
|
|
64172
|
+
if (!existsSync27(dir)) {
|
|
64066
64173
|
return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
|
|
64067
64174
|
}
|
|
64068
64175
|
const files = listJsonFiles(dir);
|
|
@@ -64081,7 +64188,7 @@ function pullFromAgentTaskList(agent, taskListId, projectId, options = {}) {
|
|
|
64081
64188
|
}
|
|
64082
64189
|
for (const f of files) {
|
|
64083
64190
|
try {
|
|
64084
|
-
const filePath =
|
|
64191
|
+
const filePath = join26(dir, f);
|
|
64085
64192
|
const at = readAgentTask(dir, f);
|
|
64086
64193
|
if (!at)
|
|
64087
64194
|
continue;
|
|
@@ -64221,9 +64328,9 @@ function syncWithAgents(agents, taskListIdByAgent, projectId, direction = "both"
|
|
|
64221
64328
|
// src/lib/extract.ts
|
|
64222
64329
|
init_tasks();
|
|
64223
64330
|
init_task_files();
|
|
64224
|
-
import { existsSync as
|
|
64331
|
+
import { existsSync as existsSync28, readFileSync as readFileSync24, statSync as statSync10 } from "fs";
|
|
64225
64332
|
import { createHash as createHash22 } from "crypto";
|
|
64226
|
-
import { relative as relative6, resolve as
|
|
64333
|
+
import { relative as relative6, resolve as resolve19, join as join27 } from "path";
|
|
64227
64334
|
var EXTRACT_TAGS = ["TODO", "FIXME", "HACK", "XXX", "BUG", "NOTE"];
|
|
64228
64335
|
var DEFAULT_EXTENSIONS = new Set([
|
|
64229
64336
|
".ts",
|
|
@@ -64293,9 +64400,9 @@ function normalizePathForMatch(value) {
|
|
|
64293
64400
|
return value.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
64294
64401
|
}
|
|
64295
64402
|
function readGitignorePatterns(basePath) {
|
|
64296
|
-
const root = statSync10(basePath).isFile() ?
|
|
64297
|
-
const gitignorePath =
|
|
64298
|
-
if (!
|
|
64403
|
+
const root = statSync10(basePath).isFile() ? resolve19(basePath, "..") : basePath;
|
|
64404
|
+
const gitignorePath = join27(root, ".gitignore");
|
|
64405
|
+
if (!existsSync28(gitignorePath))
|
|
64299
64406
|
return [];
|
|
64300
64407
|
try {
|
|
64301
64408
|
return readFileSync24(gitignorePath, "utf-8").split(`
|
|
@@ -64429,7 +64536,7 @@ function collectFiles(basePath, extensions, excludes, respectGitignore) {
|
|
|
64429
64536
|
return files.sort();
|
|
64430
64537
|
}
|
|
64431
64538
|
function buildCodebaseIndex(options) {
|
|
64432
|
-
const basePath =
|
|
64539
|
+
const basePath = resolve19(options.path);
|
|
64433
64540
|
const tags = options.patterns || [...EXTRACT_TAGS];
|
|
64434
64541
|
const extensions = options.extensions ? new Set(options.extensions.map((e) => e.startsWith(".") ? e : `.${e}`)) : DEFAULT_EXTENSIONS;
|
|
64435
64542
|
const excludes = options.exclude || [];
|
|
@@ -64437,10 +64544,10 @@ function buildCodebaseIndex(options) {
|
|
|
64437
64544
|
const files = collectFiles(basePath, extensions, excludes, respectGitignore);
|
|
64438
64545
|
const indexed = [];
|
|
64439
64546
|
for (const file of files) {
|
|
64440
|
-
const fullPath = statSync10(basePath).isFile() ? basePath :
|
|
64547
|
+
const fullPath = statSync10(basePath).isFile() ? basePath : join27(basePath, file);
|
|
64441
64548
|
try {
|
|
64442
64549
|
const source9 = readFileSync24(fullPath, "utf-8");
|
|
64443
|
-
const relPath = statSync10(basePath).isFile() ? relative6(
|
|
64550
|
+
const relPath = statSync10(basePath).isFile() ? relative6(resolve19(basePath, ".."), fullPath) : file;
|
|
64444
64551
|
indexed.push({
|
|
64445
64552
|
file: relPath,
|
|
64446
64553
|
checksum: stableHash(source9).slice(0, 24),
|
|
@@ -64460,7 +64567,7 @@ function buildCodebaseIndex(options) {
|
|
|
64460
64567
|
};
|
|
64461
64568
|
}
|
|
64462
64569
|
function extractTodos(options, db) {
|
|
64463
|
-
const basePath =
|
|
64570
|
+
const basePath = resolve19(options.path);
|
|
64464
64571
|
const tags = options.patterns || [...EXTRACT_TAGS];
|
|
64465
64572
|
const extensions = options.extensions ? new Set(options.extensions.map((e) => e.startsWith(".") ? e : `.${e}`)) : DEFAULT_EXTENSIONS;
|
|
64466
64573
|
const excludes = options.exclude || [];
|
|
@@ -64468,10 +64575,10 @@ function extractTodos(options, db) {
|
|
|
64468
64575
|
const files = collectFiles(basePath, extensions, excludes, respectGitignore);
|
|
64469
64576
|
const allComments = [];
|
|
64470
64577
|
for (const file of files) {
|
|
64471
|
-
const fullPath = statSync10(basePath).isFile() ? basePath :
|
|
64578
|
+
const fullPath = statSync10(basePath).isFile() ? basePath : join27(basePath, file);
|
|
64472
64579
|
try {
|
|
64473
64580
|
const source9 = readFileSync24(fullPath, "utf-8");
|
|
64474
|
-
const relPath = statSync10(basePath).isFile() ? relative6(
|
|
64581
|
+
const relPath = statSync10(basePath).isFile() ? relative6(resolve19(basePath, ".."), fullPath) : file;
|
|
64475
64582
|
const comments = extractFromSource(source9, relPath, tags);
|
|
64476
64583
|
allComments.push(...comments);
|
|
64477
64584
|
} catch {}
|
|
@@ -64565,7 +64672,7 @@ async function watchSourceTodos(options, onRun) {
|
|
|
64565
64672
|
const interval = Math.max(100, options.interval_ms || 2000);
|
|
64566
64673
|
const once = options.once !== false && (!options.max_runs || options.max_runs <= 1);
|
|
64567
64674
|
const maxRuns = options.max_runs ?? (once ? 1 : Number.POSITIVE_INFINITY);
|
|
64568
|
-
const root =
|
|
64675
|
+
const root = resolve19(options.path);
|
|
64569
64676
|
const runs = [];
|
|
64570
64677
|
let previous = new Map;
|
|
64571
64678
|
for (let runNumber = 1;runNumber <= maxRuns; runNumber++) {
|
|
@@ -65447,8 +65554,8 @@ function renderAgentReplaySimulationMarkdown(simulation) {
|
|
|
65447
65554
|
// src/lib/local-extensions.ts
|
|
65448
65555
|
init_config2();
|
|
65449
65556
|
import { createHash as createHash24, createVerify } from "crypto";
|
|
65450
|
-
import { existsSync as
|
|
65451
|
-
import { basename as basename6, join as
|
|
65557
|
+
import { existsSync as existsSync29, readdirSync as readdirSync6, readFileSync as readFileSync26, statSync as statSync11 } from "fs";
|
|
65558
|
+
import { basename as basename6, join as join28, resolve as resolve20 } from "path";
|
|
65452
65559
|
init_redaction();
|
|
65453
65560
|
init_runner_sandbox();
|
|
65454
65561
|
function isObject2(value) {
|
|
@@ -65729,11 +65836,11 @@ function verifyExtensionSignature(input) {
|
|
|
65729
65836
|
return verifier.verify(input.public_key, decodeSignature(input.signature));
|
|
65730
65837
|
}
|
|
65731
65838
|
function inspectExtensionSource(source9) {
|
|
65732
|
-
const resolved =
|
|
65733
|
-
if (!
|
|
65839
|
+
const resolved = resolve20(source9);
|
|
65840
|
+
if (!existsSync29(resolved))
|
|
65734
65841
|
throw new Error(`extension source not found: ${source9}`);
|
|
65735
65842
|
const stat = statSync11(resolved);
|
|
65736
|
-
const manifestPath = stat.isDirectory() ? [
|
|
65843
|
+
const manifestPath = stat.isDirectory() ? [join28(resolved, "todos.extension.json"), join28(resolved, "extension.json")].find(existsSync29) : resolved;
|
|
65737
65844
|
if (!manifestPath)
|
|
65738
65845
|
throw new Error(`extension directory ${source9} is missing todos.extension.json`);
|
|
65739
65846
|
const raw = readFileSync26(manifestPath);
|
|
@@ -65827,26 +65934,26 @@ function testExtensionCompatibility(sourceOrManifest) {
|
|
|
65827
65934
|
function projectExtensionSources(projectPath) {
|
|
65828
65935
|
if (!projectPath)
|
|
65829
65936
|
return [];
|
|
65830
|
-
const root =
|
|
65937
|
+
const root = resolve20(projectPath);
|
|
65831
65938
|
const candidates = [
|
|
65832
|
-
|
|
65833
|
-
|
|
65939
|
+
join28(root, "todos.extension.json"),
|
|
65940
|
+
join28(root, ".todos", "todos.extension.json")
|
|
65834
65941
|
];
|
|
65835
|
-
const extensionDir =
|
|
65836
|
-
if (
|
|
65942
|
+
const extensionDir = join28(root, ".todos", "extensions");
|
|
65943
|
+
if (existsSync29(extensionDir)) {
|
|
65837
65944
|
for (const entry2 of readdirSync6(extensionDir)) {
|
|
65838
65945
|
if (entry2.startsWith("."))
|
|
65839
65946
|
continue;
|
|
65840
|
-
const full =
|
|
65947
|
+
const full = join28(extensionDir, entry2);
|
|
65841
65948
|
if (statSync11(full).isDirectory() || entry2.endsWith(".json"))
|
|
65842
65949
|
candidates.push(full);
|
|
65843
65950
|
}
|
|
65844
65951
|
}
|
|
65845
|
-
return candidates.filter(
|
|
65952
|
+
return candidates.filter(existsSync29);
|
|
65846
65953
|
}
|
|
65847
65954
|
function discoverLocalExtensions(options = {}) {
|
|
65848
65955
|
const config = loadConfig();
|
|
65849
|
-
const projectPath = options.project_path ?
|
|
65956
|
+
const projectPath = options.project_path ? resolve20(options.project_path) : null;
|
|
65850
65957
|
const configuredSources = [
|
|
65851
65958
|
...config.extension_sources || [],
|
|
65852
65959
|
...projectPath ? config.project_overrides?.[projectPath]?.extension_sources || [] : []
|
|
@@ -65854,7 +65961,7 @@ function discoverLocalExtensions(options = {}) {
|
|
|
65854
65961
|
const sources = Array.from(new Set([
|
|
65855
65962
|
...configuredSources,
|
|
65856
65963
|
...projectExtensionSources(projectPath || undefined)
|
|
65857
|
-
])).map((source9) => projectPath && !source9.startsWith("/") ?
|
|
65964
|
+
])).map((source9) => projectPath && !source9.startsWith("/") ? resolve20(projectPath, source9) : resolve20(source9));
|
|
65858
65965
|
const warnings = [];
|
|
65859
65966
|
const discovered = [];
|
|
65860
65967
|
for (const source9 of sources) {
|
|
@@ -66722,7 +66829,7 @@ init_redaction();
|
|
|
66722
66829
|
// src/lib/retention-cleanup.ts
|
|
66723
66830
|
init_artifact_store();
|
|
66724
66831
|
init_database();
|
|
66725
|
-
import { existsSync as
|
|
66832
|
+
import { existsSync as existsSync30, unlinkSync as unlinkSync2 } from "fs";
|
|
66726
66833
|
var RETENTION_CLEANUP_CONFIRMATION = "delete-local-retention-data";
|
|
66727
66834
|
var ALL_SCOPES = ["comments", "runs", "verifications", "expired_artifacts"];
|
|
66728
66835
|
var EMPTY_COUNTS = {
|
|
@@ -66933,7 +67040,7 @@ function applyRetentionCleanup(input, db) {
|
|
|
66933
67040
|
for (const artifact of report.candidates.artifact_files) {
|
|
66934
67041
|
try {
|
|
66935
67042
|
const path = artifactStorePath(artifact.relative_path);
|
|
66936
|
-
if (!
|
|
67043
|
+
if (!existsSync30(path)) {
|
|
66937
67044
|
report.warnings.push(`stored artifact already missing: ${artifact.relative_path}`);
|
|
66938
67045
|
continue;
|
|
66939
67046
|
}
|
|
@@ -67174,8 +67281,8 @@ init_artifact_store();
|
|
|
67174
67281
|
|
|
67175
67282
|
// src/lib/doctor.ts
|
|
67176
67283
|
init_database();
|
|
67177
|
-
import { chmodSync, copyFileSync as copyFileSync2, existsSync as
|
|
67178
|
-
import { basename as basename7, dirname as dirname18, join as
|
|
67284
|
+
import { chmodSync, copyFileSync as copyFileSync2, existsSync as existsSync31, mkdirSync as mkdirSync22, statSync as statSync12 } from "fs";
|
|
67285
|
+
import { basename as basename7, dirname as dirname18, join as join29 } from "path";
|
|
67179
67286
|
init_migrations();
|
|
67180
67287
|
init_schema();
|
|
67181
67288
|
init_recurrence();
|
|
@@ -67285,7 +67392,7 @@ function findMissingProjectRoots(db) {
|
|
|
67285
67392
|
continue;
|
|
67286
67393
|
if (!row.path.startsWith("/"))
|
|
67287
67394
|
continue;
|
|
67288
|
-
if (!
|
|
67395
|
+
if (!existsSync31(row.path))
|
|
67289
67396
|
missing++;
|
|
67290
67397
|
}
|
|
67291
67398
|
return missing;
|
|
@@ -67345,16 +67452,16 @@ function databasePermissionsAreUnsafe(dbPath) {
|
|
|
67345
67452
|
function createBackup(dbPath) {
|
|
67346
67453
|
if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
|
|
67347
67454
|
return;
|
|
67348
|
-
if (!
|
|
67455
|
+
if (!existsSync31(dbPath))
|
|
67349
67456
|
return;
|
|
67350
67457
|
const stamp = now().replace(/[:.]/g, "-");
|
|
67351
|
-
const backupDir =
|
|
67458
|
+
const backupDir = join29(dirname18(dbPath), `${basename7(dbPath)}.backup-${stamp}`);
|
|
67352
67459
|
const files = [];
|
|
67353
67460
|
mkdirSync22(backupDir, { recursive: true });
|
|
67354
67461
|
for (const source9 of [dbPath, `${dbPath}-wal`, `${dbPath}-shm`]) {
|
|
67355
|
-
if (!
|
|
67462
|
+
if (!existsSync31(source9))
|
|
67356
67463
|
continue;
|
|
67357
|
-
const target =
|
|
67464
|
+
const target = join29(backupDir, basename7(source9));
|
|
67358
67465
|
copyFileSync2(source9, target);
|
|
67359
67466
|
files.push(target);
|
|
67360
67467
|
}
|