@hasna/todos 0.13.5 → 0.13.7
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/agent-commands.d.ts.map +1 -1
- package/dist/cli/commands/mcp-hooks-commands.d.ts.map +1 -1
- package/dist/cli/commands/task-commands.d.ts.map +1 -1
- package/dist/cli/index.js +418 -177
- package/dist/contracts.js +29 -3
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/task-crud.d.ts.map +1 -1
- package/dist/index.js +43 -7
- package/dist/lib/creator-identity.d.ts +100 -0
- package/dist/lib/creator-identity.d.ts.map +1 -0
- package/dist/lib/onboarding-fixtures.d.ts.map +1 -1
- package/dist/mcp/index.js +177 -75
- package/dist/mcp/tools/task-crud.d.ts.map +1 -1
- package/dist/mcp.js +1 -1
- package/dist/registry.js +29 -3
- package/dist/release-provenance.json +5 -5
- package/dist/server/index.js +167 -65
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/v1.d.ts.map +1 -1
- package/dist/storage/local-sqlite.d.ts.map +1 -1
- package/dist/storage.js +41 -6
- package/dist/types/index.d.ts +18 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/server/index.js
CHANGED
|
@@ -70,7 +70,7 @@ var package_default;
|
|
|
70
70
|
var init_package = __esm(() => {
|
|
71
71
|
package_default = {
|
|
72
72
|
name: "@hasna/todos",
|
|
73
|
-
version: "0.13.
|
|
73
|
+
version: "0.13.7",
|
|
74
74
|
description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
|
|
75
75
|
type: "module",
|
|
76
76
|
main: "dist/index.js",
|
|
@@ -1759,6 +1759,10 @@ class PostgresJsonRecordStore {
|
|
|
1759
1759
|
conds.push(`payload->>'assigned_to' = ${p(filter.assigned_to)}`);
|
|
1760
1760
|
if (filter.agent_id !== undefined)
|
|
1761
1761
|
conds.push(`payload->>'agent_id' = ${p(filter.agent_id)}`);
|
|
1762
|
+
if (filter.created_by !== undefined)
|
|
1763
|
+
conds.push(`LOWER(payload->>'created_by') = LOWER(${p(filter.created_by)})`);
|
|
1764
|
+
if (filter.not_created_by !== undefined)
|
|
1765
|
+
conds.push(`(payload->>'created_by' IS NULL OR LOWER(payload->>'created_by') <> LOWER(${p(filter.not_created_by)}))`);
|
|
1762
1766
|
if (filter.session_id !== undefined)
|
|
1763
1767
|
conds.push(`payload->>'session_id' = ${p(filter.session_id)}`);
|
|
1764
1768
|
if (filter.tags?.length) {
|
|
@@ -2272,7 +2276,7 @@ async function createTask(input, store, context) {
|
|
|
2272
2276
|
description: input.description ?? null,
|
|
2273
2277
|
status: input.status ?? "pending",
|
|
2274
2278
|
priority: input.priority ?? "medium",
|
|
2275
|
-
agent_id: input.agent_id ?? null,
|
|
2279
|
+
agent_id: input.agent_id ?? context?.agentId ?? null,
|
|
2276
2280
|
assigned_to: input.assigned_to ?? null,
|
|
2277
2281
|
session_id: input.session_id ?? context?.sessionId ?? null,
|
|
2278
2282
|
working_dir: input.working_dir ?? null,
|
|
@@ -2297,7 +2301,8 @@ async function createTask(input, store, context) {
|
|
|
2297
2301
|
confidence: input.confidence ?? null,
|
|
2298
2302
|
reason: input.reason ?? null,
|
|
2299
2303
|
spawned_from_session: input.spawned_from_session ?? null,
|
|
2300
|
-
assigned_by: input.assigned_by ?? null,
|
|
2304
|
+
assigned_by: input.assigned_by ?? input.agent_id ?? context?.agentId ?? null,
|
|
2305
|
+
created_by: input.created_by ?? input.agent_id ?? context?.agentId ?? null,
|
|
2301
2306
|
assigned_from_project: input.assigned_from_project ?? null,
|
|
2302
2307
|
task_type: input.task_type ?? null,
|
|
2303
2308
|
cost_tokens: 0,
|
|
@@ -2334,7 +2339,8 @@ async function updateTask(id, input, store) {
|
|
|
2334
2339
|
tags: input.tags ?? existing.tags,
|
|
2335
2340
|
metadata: input.metadata ?? existing.metadata,
|
|
2336
2341
|
requires_approval: input.requires_approval ?? existing.requires_approval,
|
|
2337
|
-
task_list_id: input.task_list_id !== undefined ? input.task_list_id : existing.task_list_id
|
|
2342
|
+
task_list_id: input.task_list_id !== undefined ? input.task_list_id : existing.task_list_id,
|
|
2343
|
+
created_by: existing.created_by
|
|
2338
2344
|
};
|
|
2339
2345
|
await store.upsert("tasks", task);
|
|
2340
2346
|
return task;
|
|
@@ -7475,6 +7481,7 @@ function ensureSchema(db) {
|
|
|
7475
7481
|
ensureColumn("tasks", "reason", "TEXT");
|
|
7476
7482
|
ensureColumn("tasks", "spawned_from_session", "TEXT");
|
|
7477
7483
|
ensureColumn("tasks", "assigned_by", "TEXT");
|
|
7484
|
+
ensureColumn("tasks", "created_by", "TEXT");
|
|
7478
7485
|
ensureColumn("tasks", "assigned_from_project", "TEXT");
|
|
7479
7486
|
ensureColumn("tasks", "started_at", "TEXT");
|
|
7480
7487
|
ensureColumn("tasks", "task_type", "TEXT");
|
|
@@ -7637,6 +7644,8 @@ function ensureSchema(db) {
|
|
|
7637
7644
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_project_sources_project ON project_sources(project_id)");
|
|
7638
7645
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_project_sources_type ON project_sources(type)");
|
|
7639
7646
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_assigned_by ON tasks(assigned_by)");
|
|
7647
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_created_by ON tasks(created_by)");
|
|
7648
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_assigned_created ON tasks(assigned_to, created_by)");
|
|
7640
7649
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_rel_source ON task_relationships(source_task_id)");
|
|
7641
7650
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_rel_target ON task_relationships(target_task_id)");
|
|
7642
7651
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_rel_type ON task_relationships(relationship_type)");
|
|
@@ -13283,13 +13292,14 @@ function createTask2(input, db) {
|
|
|
13283
13292
|
const timestamp2 = now();
|
|
13284
13293
|
const tags = input.tags || [];
|
|
13285
13294
|
const machineId = currentStorageMachineId(d);
|
|
13295
|
+
const createdBy = input.created_by || input.agent_id || null;
|
|
13286
13296
|
const assignedBy = input.assigned_by || input.agent_id;
|
|
13287
13297
|
const assignedFromProject = input.assigned_from_project || null;
|
|
13288
13298
|
let id = uuid();
|
|
13289
13299
|
for (let attempt = 0;attempt < 3; attempt++) {
|
|
13290
13300
|
try {
|
|
13291
|
-
d.run(`INSERT INTO tasks (id, short_id, project_id, parent_id, plan_id, task_list_id, cycle_id, title, description, status, priority, agent_id, assigned_to, session_id, working_dir, tags, metadata, version, created_at, updated_at, due_at, estimated_minutes, sla_minutes, confidence, retry_count, max_retries, retry_after, requires_approval, approved_by, approved_at, recurrence_rule, recurrence_parent_id, spawns_template_id, reason, spawned_from_session, assigned_by, assigned_from_project, task_type, machine_id)
|
|
13292
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
13301
|
+
d.run(`INSERT INTO tasks (id, short_id, project_id, parent_id, plan_id, task_list_id, cycle_id, title, description, status, priority, agent_id, assigned_to, session_id, working_dir, tags, metadata, version, created_at, updated_at, due_at, estimated_minutes, sla_minutes, confidence, retry_count, max_retries, retry_after, requires_approval, approved_by, approved_at, recurrence_rule, recurrence_parent_id, spawns_template_id, reason, spawned_from_session, assigned_by, created_by, assigned_from_project, task_type, machine_id)
|
|
13302
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
13293
13303
|
id,
|
|
13294
13304
|
null,
|
|
13295
13305
|
input.project_id || null,
|
|
@@ -13325,6 +13335,7 @@ function createTask2(input, db) {
|
|
|
13325
13335
|
input.reason || null,
|
|
13326
13336
|
input.spawned_from_session || null,
|
|
13327
13337
|
assignedBy || null,
|
|
13338
|
+
createdBy,
|
|
13328
13339
|
assignedFromProject || null,
|
|
13329
13340
|
input.task_type || null,
|
|
13330
13341
|
machineId
|
|
@@ -13434,6 +13445,14 @@ function listTasks2(filter = {}, db) {
|
|
|
13434
13445
|
conditions.push("agent_id = ?");
|
|
13435
13446
|
params.push(filter.agent_id);
|
|
13436
13447
|
}
|
|
13448
|
+
if (filter.created_by) {
|
|
13449
|
+
conditions.push("LOWER(created_by) = LOWER(?)");
|
|
13450
|
+
params.push(filter.created_by);
|
|
13451
|
+
}
|
|
13452
|
+
if (filter.not_created_by) {
|
|
13453
|
+
conditions.push("(created_by IS NULL OR LOWER(created_by) != LOWER(?))");
|
|
13454
|
+
params.push(filter.not_created_by);
|
|
13455
|
+
}
|
|
13437
13456
|
if (filter.session_id) {
|
|
13438
13457
|
conditions.push("session_id = ?");
|
|
13439
13458
|
params.push(filter.session_id);
|
|
@@ -13587,6 +13606,14 @@ function countTasks(filter = {}, db) {
|
|
|
13587
13606
|
conditions.push("agent_id = ?");
|
|
13588
13607
|
params.push(filter.agent_id);
|
|
13589
13608
|
}
|
|
13609
|
+
if (filter.created_by) {
|
|
13610
|
+
conditions.push("LOWER(created_by) = LOWER(?)");
|
|
13611
|
+
params.push(filter.created_by);
|
|
13612
|
+
}
|
|
13613
|
+
if (filter.not_created_by) {
|
|
13614
|
+
conditions.push("(created_by IS NULL OR LOWER(created_by) != LOWER(?))");
|
|
13615
|
+
params.push(filter.not_created_by);
|
|
13616
|
+
}
|
|
13590
13617
|
if (filter.session_id) {
|
|
13591
13618
|
conditions.push("session_id = ?");
|
|
13592
13619
|
params.push(filter.session_id);
|
|
@@ -13647,6 +13674,10 @@ function updateTask2(id, input, db) {
|
|
|
13647
13674
|
sets.push("description = ?");
|
|
13648
13675
|
params.push(input.description);
|
|
13649
13676
|
}
|
|
13677
|
+
if (input.agent_id !== undefined) {
|
|
13678
|
+
sets.push("agent_id = ?");
|
|
13679
|
+
params.push(input.agent_id);
|
|
13680
|
+
}
|
|
13650
13681
|
if (input.status !== undefined) {
|
|
13651
13682
|
if (input.status === "completed") {
|
|
13652
13683
|
checkCompletionGuard(task, task.assigned_to || task.agent_id || null, d);
|
|
@@ -18157,11 +18188,15 @@ async function handleCreateTask(req, ctx, json2, taskToSummary2) {
|
|
|
18157
18188
|
const body = await req.json();
|
|
18158
18189
|
if (!body.title)
|
|
18159
18190
|
return json2({ error: "Missing 'title'" }, 400);
|
|
18191
|
+
const createdBy = body.created_by ?? body.agent_id ?? "dashboard";
|
|
18160
18192
|
const task = createTask2({
|
|
18161
18193
|
title: body.title,
|
|
18162
18194
|
description: body.description,
|
|
18163
18195
|
priority: body.priority,
|
|
18164
|
-
project_id: body.project_id
|
|
18196
|
+
project_id: body.project_id,
|
|
18197
|
+
agent_id: body.agent_id ?? createdBy,
|
|
18198
|
+
created_by: createdBy,
|
|
18199
|
+
...body.assigned_to ? { assigned_to: body.assigned_to } : {}
|
|
18165
18200
|
});
|
|
18166
18201
|
ctx.broadcastEvent({ type: "task", task_id: task.id, action: "created", agent_id: task.agent_id, project_id: task.project_id });
|
|
18167
18202
|
return json2(taskToSummary2(task), 201);
|
|
@@ -19425,7 +19460,11 @@ function createLocalSqliteTodosStorageAdapter(options = {}) {
|
|
|
19425
19460
|
sync: true
|
|
19426
19461
|
},
|
|
19427
19462
|
tasks: {
|
|
19428
|
-
create: (input) => createTask2(
|
|
19463
|
+
create: (input, context) => createTask2({
|
|
19464
|
+
...input,
|
|
19465
|
+
agent_id: input.agent_id ?? context?.agentId,
|
|
19466
|
+
created_by: input.created_by ?? input.agent_id ?? context?.agentId
|
|
19467
|
+
}, database()),
|
|
19429
19468
|
get: (id) => getTask(id, database()),
|
|
19430
19469
|
resolveRef: (ref) => resolveTaskRefLocal(database(), ref),
|
|
19431
19470
|
list: (filter = {}) => listTasksMaybeSearch(filter, database()),
|
|
@@ -22036,6 +22075,8 @@ async function handleV1Request(req, url, dependencies = {}) {
|
|
|
22036
22075
|
...url.searchParams.get("task_list_id") ? { task_list_id: url.searchParams.get("task_list_id") } : {},
|
|
22037
22076
|
...url.searchParams.get("assigned_to") ? { assigned_to: url.searchParams.get("assigned_to") } : {},
|
|
22038
22077
|
...url.searchParams.get("agent_id") ? { agent_id: url.searchParams.get("agent_id") } : {},
|
|
22078
|
+
...url.searchParams.get("created_by") ? { created_by: url.searchParams.get("created_by") } : {},
|
|
22079
|
+
...url.searchParams.get("not_created_by") ? { not_created_by: url.searchParams.get("not_created_by") } : {},
|
|
22039
22080
|
...url.searchParams.get("tags") ? {
|
|
22040
22081
|
tags: url.searchParams.get("tags").split(",").map((tag) => tag.trim()).filter(Boolean)
|
|
22041
22082
|
} : {},
|
|
@@ -44205,6 +44246,50 @@ var init_token_utils = __esm(() => {
|
|
|
44205
44246
|
};
|
|
44206
44247
|
});
|
|
44207
44248
|
|
|
44249
|
+
// src/lib/creator-identity.ts
|
|
44250
|
+
import { existsSync as existsSync8, rmSync as rmSync2 } from "fs";
|
|
44251
|
+
import { join as join8 } from "path";
|
|
44252
|
+
function identityFilePath() {
|
|
44253
|
+
return join8(getTodosGlobalDir(), "identity.json");
|
|
44254
|
+
}
|
|
44255
|
+
function readPersistedIdentity() {
|
|
44256
|
+
const path = identityFilePath();
|
|
44257
|
+
if (!existsSync8(path))
|
|
44258
|
+
return null;
|
|
44259
|
+
const parsed = readJsonFile(path);
|
|
44260
|
+
if (!parsed || typeof parsed.agent_id !== "string" || !parsed.agent_id.trim())
|
|
44261
|
+
return null;
|
|
44262
|
+
return parsed;
|
|
44263
|
+
}
|
|
44264
|
+
function canonicalAgentRef(value) {
|
|
44265
|
+
return value.trim().toLowerCase();
|
|
44266
|
+
}
|
|
44267
|
+
function isProcessBoundSource(source) {
|
|
44268
|
+
return source === "explicit" || source === "env";
|
|
44269
|
+
}
|
|
44270
|
+
function resolveWritableIdentity(explicit) {
|
|
44271
|
+
const resolved = resolveCreatorIdentity(explicit);
|
|
44272
|
+
if (!isProcessBoundSource(resolved.source))
|
|
44273
|
+
return { agent_id: null, source: "none" };
|
|
44274
|
+
return resolved;
|
|
44275
|
+
}
|
|
44276
|
+
function resolveCreatorIdentity(explicit) {
|
|
44277
|
+
const fromExplicit = explicit?.trim();
|
|
44278
|
+
if (fromExplicit)
|
|
44279
|
+
return { agent_id: canonicalAgentRef(fromExplicit), source: "explicit" };
|
|
44280
|
+
const fromEnv = (process.env["TODOS_AGENT_ID"] || process.env["HASNA_TODOS_AGENT_ID"] || "").trim();
|
|
44281
|
+
if (fromEnv)
|
|
44282
|
+
return { agent_id: canonicalAgentRef(fromEnv), source: "env" };
|
|
44283
|
+
const persisted = readPersistedIdentity();
|
|
44284
|
+
if (persisted) {
|
|
44285
|
+
return { agent_id: canonicalAgentRef(persisted.agent_name || persisted.agent_id), source: "persisted" };
|
|
44286
|
+
}
|
|
44287
|
+
return { agent_id: null, source: "none" };
|
|
44288
|
+
}
|
|
44289
|
+
var init_creator_identity = __esm(() => {
|
|
44290
|
+
init_sync_utils();
|
|
44291
|
+
});
|
|
44292
|
+
|
|
44208
44293
|
// src/pr-groups/http-client.ts
|
|
44209
44294
|
function normalizeBaseUrl(value) {
|
|
44210
44295
|
const url = new URL(value);
|
|
@@ -45554,6 +45639,8 @@ function registerTaskCrudTools(server, ctx) {
|
|
|
45554
45639
|
project_id: exports_external.string().optional().describe("Project ID"),
|
|
45555
45640
|
task_list_id: exports_external.string().optional().describe("Task list ID"),
|
|
45556
45641
|
assigned_to: exports_external.string().optional().describe("Agent ID or name to assign to"),
|
|
45642
|
+
created_by: exports_external.string().optional().describe("Agent who FILED this task. Defaults to the ambient agent identity (todos init / TODOS_AGENT_ID)."),
|
|
45643
|
+
unassigned: exports_external.boolean().optional().describe("Deliberately file with no assignee. Without it, the task defaults to the filer."),
|
|
45557
45644
|
depends_on: exports_external.array(exports_external.string()).optional().describe("Array of task IDs this task depends on"),
|
|
45558
45645
|
short_id: exports_external.string().nullable().optional().describe("Short ID (auto-generated if not provided, disabled if null)"),
|
|
45559
45646
|
tags: exports_external.array(exports_external.string()).optional().describe("Tags for the task"),
|
|
@@ -45564,12 +45651,19 @@ function registerTaskCrudTools(server, ctx) {
|
|
|
45564
45651
|
retry_count: exports_external.number().optional().describe("Max retry count for agent failures")
|
|
45565
45652
|
}, async (params) => {
|
|
45566
45653
|
try {
|
|
45567
|
-
const { depends_on, assigned_to, project_id, task_list_id, tags, estimate, confidence, retry_count, deadline, ...rest } = params;
|
|
45654
|
+
const { depends_on, assigned_to, project_id, task_list_id, tags, estimate, confidence, retry_count, deadline, created_by, unassigned, ...rest } = params;
|
|
45655
|
+
const creator = resolveCreatorIdentity(created_by);
|
|
45656
|
+
const router = resolveWritableIdentity(created_by);
|
|
45657
|
+
const assignee = assigned_to || (unassigned ? undefined : router.agent_id || undefined);
|
|
45568
45658
|
const cloud = getTodosCloudClient();
|
|
45569
45659
|
if (cloud) {
|
|
45570
45660
|
const payload = { ...rest };
|
|
45571
|
-
if (
|
|
45572
|
-
payload.
|
|
45661
|
+
if (creator.agent_id)
|
|
45662
|
+
payload.created_by = creator.agent_id;
|
|
45663
|
+
if (router.agent_id)
|
|
45664
|
+
payload.agent_id = payload.agent_id ?? router.agent_id;
|
|
45665
|
+
if (assignee)
|
|
45666
|
+
payload.assigned_to = assignee;
|
|
45573
45667
|
if (project_id)
|
|
45574
45668
|
payload.project_id = project_id;
|
|
45575
45669
|
if (task_list_id)
|
|
@@ -45590,8 +45684,12 @@ function registerTaskCrudTools(server, ctx) {
|
|
|
45590
45684
|
return { content: [{ type: "text", text: mutationTaskResponse(created) }] };
|
|
45591
45685
|
}
|
|
45592
45686
|
const resolved = { ...rest };
|
|
45593
|
-
if (
|
|
45594
|
-
resolved.
|
|
45687
|
+
if (creator.agent_id)
|
|
45688
|
+
resolved.created_by = creator.agent_id;
|
|
45689
|
+
if (router.agent_id)
|
|
45690
|
+
resolved.agent_id = resolved.agent_id ?? router.agent_id;
|
|
45691
|
+
if (assignee)
|
|
45692
|
+
resolved.assigned_to = resolveAssignee(assignee);
|
|
45595
45693
|
if (project_id)
|
|
45596
45694
|
resolved.project_id = resolveId(project_id, "projects");
|
|
45597
45695
|
if (task_list_id)
|
|
@@ -45677,6 +45775,8 @@ function registerTaskCrudTools(server, ctx) {
|
|
|
45677
45775
|
project_id: exports_external.string().optional().describe("Filter by project"),
|
|
45678
45776
|
task_list_id: exports_external.string().optional().describe("Filter by task list"),
|
|
45679
45777
|
assigned_to: exports_external.string().optional().describe("Filter by assignee (agent ID or name, empty string = unassigned)"),
|
|
45778
|
+
created_by: exports_external.string().optional().describe("Filter by the agent who FILED the task"),
|
|
45779
|
+
not_created_by: exports_external.string().optional().describe('Exclude tasks filed by this agent. With assigned_to=<me> this is the "my inbox, minus my own filings" query.'),
|
|
45680
45780
|
tags: exports_external.array(exports_external.string()).optional().describe("Filter by tags (AND logic)"),
|
|
45681
45781
|
created_after: exports_external.string().optional().describe("ISO date \u2014 tasks created after this date"),
|
|
45682
45782
|
created_before: exports_external.string().optional().describe("ISO date \u2014 tasks created before this date"),
|
|
@@ -45869,11 +45969,12 @@ var init_task_crud2 = __esm(() => {
|
|
|
45869
45969
|
init_tasks();
|
|
45870
45970
|
init_types();
|
|
45871
45971
|
init_token_utils();
|
|
45972
|
+
init_creator_identity();
|
|
45872
45973
|
init_cloud_router();
|
|
45873
45974
|
});
|
|
45874
45975
|
|
|
45875
45976
|
// src/lib/project-bootstrap.ts
|
|
45876
|
-
import { existsSync as
|
|
45977
|
+
import { existsSync as existsSync9, readFileSync as readFileSync3, statSync as statSync4 } from "fs";
|
|
45877
45978
|
import { basename as basename3, dirname as dirname6, resolve as resolve9 } from "path";
|
|
45878
45979
|
function safeStat(path) {
|
|
45879
45980
|
try {
|
|
@@ -45892,7 +45993,7 @@ function canonicalPath(input) {
|
|
|
45892
45993
|
function findUp(start, marker) {
|
|
45893
45994
|
let current = canonicalPath(start);
|
|
45894
45995
|
while (true) {
|
|
45895
|
-
if (
|
|
45996
|
+
if (existsSync9(resolve9(current, marker)))
|
|
45896
45997
|
return current;
|
|
45897
45998
|
const parent = dirname6(current);
|
|
45898
45999
|
if (parent === current)
|
|
@@ -45904,7 +46005,7 @@ function readPackageJson(path) {
|
|
|
45904
46005
|
if (!path)
|
|
45905
46006
|
return null;
|
|
45906
46007
|
const file = resolve9(path, "package.json");
|
|
45907
|
-
if (!
|
|
46008
|
+
if (!existsSync9(file))
|
|
45908
46009
|
return null;
|
|
45909
46010
|
try {
|
|
45910
46011
|
const parsed = JSON.parse(readFileSync3(file, "utf-8"));
|
|
@@ -45926,7 +46027,7 @@ function workspaceMarker(root, rootPackage) {
|
|
|
45926
46027
|
if (rootPackage?.workspaces)
|
|
45927
46028
|
markers.push("package.json#workspaces");
|
|
45928
46029
|
for (const marker of ["pnpm-workspace.yaml", "turbo.json", "nx.json", "lerna.json", "rush.json", "bun.lock", "bun.lockb"]) {
|
|
45929
|
-
if (
|
|
46030
|
+
if (existsSync9(resolve9(root, marker)))
|
|
45930
46031
|
markers.push(marker);
|
|
45931
46032
|
}
|
|
45932
46033
|
const kind = markers.find((marker) => marker !== "bun.lock" && marker !== "bun.lockb") ?? null;
|
|
@@ -46239,7 +46340,7 @@ var init_tags = __esm(() => {
|
|
|
46239
46340
|
});
|
|
46240
46341
|
|
|
46241
46342
|
// src/lib/retention-cleanup.ts
|
|
46242
|
-
import { existsSync as
|
|
46343
|
+
import { existsSync as existsSync10, unlinkSync } from "fs";
|
|
46243
46344
|
function normalizeScopes(scopes) {
|
|
46244
46345
|
if (!scopes || scopes.length === 0)
|
|
46245
46346
|
return [...ALL_SCOPES];
|
|
@@ -46442,7 +46543,7 @@ function applyRetentionCleanup(input, db) {
|
|
|
46442
46543
|
for (const artifact of report.candidates.artifact_files) {
|
|
46443
46544
|
try {
|
|
46444
46545
|
const path = artifactStorePath(artifact.relative_path);
|
|
46445
|
-
if (!
|
|
46546
|
+
if (!existsSync10(path)) {
|
|
46446
46547
|
report.warnings.push(`stored artifact already missing: ${artifact.relative_path}`);
|
|
46447
46548
|
continue;
|
|
46448
46549
|
}
|
|
@@ -46469,8 +46570,8 @@ var init_retention_cleanup = __esm(() => {
|
|
|
46469
46570
|
});
|
|
46470
46571
|
|
|
46471
46572
|
// src/lib/mention-resolver.ts
|
|
46472
|
-
import { existsSync as
|
|
46473
|
-
import { basename as basename4, isAbsolute, join as
|
|
46573
|
+
import { existsSync as existsSync11, readdirSync as readdirSync2, readFileSync as readFileSync4, statSync as statSync5 } from "fs";
|
|
46574
|
+
import { basename as basename4, isAbsolute, join as join9, relative as relative3, resolve as resolve10, sep as sep3 } from "path";
|
|
46474
46575
|
function blankResolution(parsed) {
|
|
46475
46576
|
return {
|
|
46476
46577
|
input: parsed.input,
|
|
@@ -46568,7 +46669,7 @@ function resolveFile(parsed, workspace) {
|
|
|
46568
46669
|
return resolution;
|
|
46569
46670
|
}
|
|
46570
46671
|
resolution.path = relPath;
|
|
46571
|
-
if (!
|
|
46672
|
+
if (!existsSync11(absolutePath)) {
|
|
46572
46673
|
resolution.warnings.push("file does not exist in the local workspace");
|
|
46573
46674
|
return resolution;
|
|
46574
46675
|
}
|
|
@@ -46601,7 +46702,7 @@ function walkSourceFiles(root, current = root, files = []) {
|
|
|
46601
46702
|
if (SKIP_DIRS.has(entry2.name))
|
|
46602
46703
|
continue;
|
|
46603
46704
|
}
|
|
46604
|
-
const absolutePath =
|
|
46705
|
+
const absolutePath = join9(current, entry2.name);
|
|
46605
46706
|
if (entry2.isDirectory()) {
|
|
46606
46707
|
if (!SKIP_DIRS.has(entry2.name))
|
|
46607
46708
|
walkSourceFiles(root, absolutePath, files);
|
|
@@ -50293,7 +50394,7 @@ var init_audit_ledger = __esm(() => {
|
|
|
50293
50394
|
|
|
50294
50395
|
// src/lib/release-compatibility.ts
|
|
50295
50396
|
import { readFileSync as readFileSync5 } from "fs";
|
|
50296
|
-
import { join as
|
|
50397
|
+
import { join as join10, resolve as resolve12 } from "path";
|
|
50297
50398
|
import { Database as Database2 } from "bun:sqlite";
|
|
50298
50399
|
function pass(id, message, details) {
|
|
50299
50400
|
return { id, status: "passed", message, details };
|
|
@@ -50305,7 +50406,7 @@ function warn(id, message, details) {
|
|
|
50305
50406
|
return { id, status: "warning", message, details };
|
|
50306
50407
|
}
|
|
50307
50408
|
function readPackageJson2(root) {
|
|
50308
|
-
return JSON.parse(readFileSync5(
|
|
50409
|
+
return JSON.parse(readFileSync5(join10(root, "package.json"), "utf8"));
|
|
50309
50410
|
}
|
|
50310
50411
|
function sortedKeys(value) {
|
|
50311
50412
|
return Object.keys(value ?? {}).sort((left, right) => left.localeCompare(right));
|
|
@@ -80200,7 +80301,7 @@ var init_agent_run_dispatcher = __esm(() => {
|
|
|
80200
80301
|
});
|
|
80201
80302
|
|
|
80202
80303
|
// src/lib/verification-providers.ts
|
|
80203
|
-
import { existsSync as
|
|
80304
|
+
import { existsSync as existsSync12, readFileSync as readFileSync6 } from "fs";
|
|
80204
80305
|
function normalizeName5(name) {
|
|
80205
80306
|
const normalized = name.trim().toLowerCase();
|
|
80206
80307
|
if (!/^[a-z0-9][a-z0-9_-]{0,63}$/.test(normalized)) {
|
|
@@ -80352,7 +80453,7 @@ Timed out after ${provider.timeout_ms}ms`);
|
|
|
80352
80453
|
};
|
|
80353
80454
|
}
|
|
80354
80455
|
function runCiLogProvider(input) {
|
|
80355
|
-
const text = input.log_text ?? (input.log_path &&
|
|
80456
|
+
const text = input.log_text ?? (input.log_path && existsSync12(input.log_path) ? readFileSync6(input.log_path, "utf-8") : "");
|
|
80356
80457
|
return {
|
|
80357
80458
|
status: classifyLog(text),
|
|
80358
80459
|
attempts: 1,
|
|
@@ -80364,7 +80465,7 @@ function runBrowserProvider(input) {
|
|
|
80364
80465
|
if (!input.artifact_path) {
|
|
80365
80466
|
return { status: "unknown", attempts: 1, exit_code: null, output_summary: "browser provider needs a screenshot or artifact path" };
|
|
80366
80467
|
}
|
|
80367
|
-
if (!
|
|
80468
|
+
if (!existsSync12(input.artifact_path)) {
|
|
80368
80469
|
return { status: "failed", attempts: 1, exit_code: null, output_summary: `artifact not found: ${input.artifact_path}` };
|
|
80369
80470
|
}
|
|
80370
80471
|
return {
|
|
@@ -83447,6 +83548,7 @@ function task(input) {
|
|
|
83447
83548
|
reason: "Bundled deterministic onboarding fixture",
|
|
83448
83549
|
spawned_from_session: null,
|
|
83449
83550
|
assigned_by: null,
|
|
83551
|
+
created_by: null,
|
|
83450
83552
|
assigned_from_project: null,
|
|
83451
83553
|
task_type: "onboarding",
|
|
83452
83554
|
cost_tokens: 0,
|
|
@@ -84644,8 +84746,8 @@ __export(exports_local_extensions, {
|
|
|
84644
84746
|
discoverLocalExtensions: () => discoverLocalExtensions
|
|
84645
84747
|
});
|
|
84646
84748
|
import { createHash as createHash10, createVerify } from "crypto";
|
|
84647
|
-
import { existsSync as
|
|
84648
|
-
import { basename as basename5, join as
|
|
84749
|
+
import { existsSync as existsSync13, readdirSync as readdirSync3, readFileSync as readFileSync8, statSync as statSync6 } from "fs";
|
|
84750
|
+
import { basename as basename5, join as join11, resolve as resolve14 } from "path";
|
|
84649
84751
|
function isObject3(value) {
|
|
84650
84752
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
84651
84753
|
}
|
|
@@ -84904,10 +85006,10 @@ function verifyExtensionSignature(input) {
|
|
|
84904
85006
|
}
|
|
84905
85007
|
function inspectExtensionSource(source3) {
|
|
84906
85008
|
const resolved = resolve14(source3);
|
|
84907
|
-
if (!
|
|
85009
|
+
if (!existsSync13(resolved))
|
|
84908
85010
|
throw new Error(`extension source not found: ${source3}`);
|
|
84909
85011
|
const stat = statSync6(resolved);
|
|
84910
|
-
const manifestPath = stat.isDirectory() ? [
|
|
85012
|
+
const manifestPath = stat.isDirectory() ? [join11(resolved, "todos.extension.json"), join11(resolved, "extension.json")].find(existsSync13) : resolved;
|
|
84911
85013
|
if (!manifestPath)
|
|
84912
85014
|
throw new Error(`extension directory ${source3} is missing todos.extension.json`);
|
|
84913
85015
|
const raw = readFileSync8(manifestPath);
|
|
@@ -85003,20 +85105,20 @@ function projectExtensionSources(projectPath) {
|
|
|
85003
85105
|
return [];
|
|
85004
85106
|
const root = resolve14(projectPath);
|
|
85005
85107
|
const candidates = [
|
|
85006
|
-
|
|
85007
|
-
|
|
85108
|
+
join11(root, "todos.extension.json"),
|
|
85109
|
+
join11(root, ".todos", "todos.extension.json")
|
|
85008
85110
|
];
|
|
85009
|
-
const extensionDir =
|
|
85010
|
-
if (
|
|
85111
|
+
const extensionDir = join11(root, ".todos", "extensions");
|
|
85112
|
+
if (existsSync13(extensionDir)) {
|
|
85011
85113
|
for (const entry2 of readdirSync3(extensionDir)) {
|
|
85012
85114
|
if (entry2.startsWith("."))
|
|
85013
85115
|
continue;
|
|
85014
|
-
const full =
|
|
85116
|
+
const full = join11(extensionDir, entry2);
|
|
85015
85117
|
if (statSync6(full).isDirectory() || entry2.endsWith(".json"))
|
|
85016
85118
|
candidates.push(full);
|
|
85017
85119
|
}
|
|
85018
85120
|
}
|
|
85019
|
-
return candidates.filter(
|
|
85121
|
+
return candidates.filter(existsSync13);
|
|
85020
85122
|
}
|
|
85021
85123
|
function discoverLocalExtensions(options = {}) {
|
|
85022
85124
|
const config2 = loadConfig();
|
|
@@ -89423,9 +89525,9 @@ __export(exports_extract, {
|
|
|
89423
89525
|
buildCodebaseIndex: () => buildCodebaseIndex,
|
|
89424
89526
|
EXTRACT_TAGS: () => EXTRACT_TAGS
|
|
89425
89527
|
});
|
|
89426
|
-
import { existsSync as
|
|
89528
|
+
import { existsSync as existsSync14, readFileSync as readFileSync9, statSync as statSync7 } from "fs";
|
|
89427
89529
|
import { createHash as createHash12 } from "crypto";
|
|
89428
|
-
import { relative as relative5, resolve as resolve15, join as
|
|
89530
|
+
import { relative as relative5, resolve as resolve15, join as join12 } from "path";
|
|
89429
89531
|
function stableHash(value) {
|
|
89430
89532
|
return createHash12("sha256").update(value).digest("hex");
|
|
89431
89533
|
}
|
|
@@ -89434,8 +89536,8 @@ function normalizePathForMatch(value) {
|
|
|
89434
89536
|
}
|
|
89435
89537
|
function readGitignorePatterns(basePath) {
|
|
89436
89538
|
const root = statSync7(basePath).isFile() ? resolve15(basePath, "..") : basePath;
|
|
89437
|
-
const gitignorePath =
|
|
89438
|
-
if (!
|
|
89539
|
+
const gitignorePath = join12(root, ".gitignore");
|
|
89540
|
+
if (!existsSync14(gitignorePath))
|
|
89439
89541
|
return [];
|
|
89440
89542
|
try {
|
|
89441
89543
|
return readFileSync9(gitignorePath, "utf-8").split(`
|
|
@@ -89577,7 +89679,7 @@ function buildCodebaseIndex(options) {
|
|
|
89577
89679
|
const files = collectFiles(basePath, extensions, excludes, respectGitignore);
|
|
89578
89680
|
const indexed = [];
|
|
89579
89681
|
for (const file of files) {
|
|
89580
|
-
const fullPath = statSync7(basePath).isFile() ? basePath :
|
|
89682
|
+
const fullPath = statSync7(basePath).isFile() ? basePath : join12(basePath, file);
|
|
89581
89683
|
try {
|
|
89582
89684
|
const source3 = readFileSync9(fullPath, "utf-8");
|
|
89583
89685
|
const relPath = statSync7(basePath).isFile() ? relative5(resolve15(basePath, ".."), fullPath) : file;
|
|
@@ -89608,7 +89710,7 @@ function extractTodos(options, db) {
|
|
|
89608
89710
|
const files = collectFiles(basePath, extensions, excludes, respectGitignore);
|
|
89609
89711
|
const allComments = [];
|
|
89610
89712
|
for (const file of files) {
|
|
89611
|
-
const fullPath = statSync7(basePath).isFile() ? basePath :
|
|
89713
|
+
const fullPath = statSync7(basePath).isFile() ? basePath : join12(basePath, file);
|
|
89612
89714
|
try {
|
|
89613
89715
|
const source3 = readFileSync9(fullPath, "utf-8");
|
|
89614
89716
|
const relPath = statSync7(basePath).isFile() ? relative5(resolve15(basePath, ".."), fullPath) : file;
|
|
@@ -90559,7 +90661,7 @@ __export(exports_builtin_templates, {
|
|
|
90559
90661
|
BUILTIN_TEMPLATES: () => BUILTIN_TEMPLATES
|
|
90560
90662
|
});
|
|
90561
90663
|
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
90562
|
-
import { join as
|
|
90664
|
+
import { join as join13 } from "path";
|
|
90563
90665
|
function templateMetadata(template) {
|
|
90564
90666
|
return {
|
|
90565
90667
|
source: BUILTIN_TEMPLATE_LIBRARY_SOURCE,
|
|
@@ -90618,7 +90720,7 @@ function writeBuiltinTemplateFiles(directory) {
|
|
|
90618
90720
|
mkdirSync7(directory, { recursive: true });
|
|
90619
90721
|
const files = [];
|
|
90620
90722
|
for (const entry2 of exportBuiltinTemplateFiles()) {
|
|
90621
|
-
const path =
|
|
90723
|
+
const path = join13(directory, entry2.filename);
|
|
90622
90724
|
writeFileSync4(path, `${JSON.stringify(entry2.template, null, 2)}
|
|
90623
90725
|
`, "utf-8");
|
|
90624
90726
|
files.push(path);
|
|
@@ -91144,16 +91246,16 @@ __export(exports_environment_snapshots, {
|
|
|
91144
91246
|
captureEnvironmentSnapshot: () => captureEnvironmentSnapshot
|
|
91145
91247
|
});
|
|
91146
91248
|
import { createHash as createHash13 } from "crypto";
|
|
91147
|
-
import { existsSync as
|
|
91249
|
+
import { existsSync as existsSync15, readFileSync as readFileSync10, statSync as statSync8 } from "fs";
|
|
91148
91250
|
import { hostname as hostname3, platform, arch } from "os";
|
|
91149
|
-
import { dirname as dirname8, join as
|
|
91251
|
+
import { dirname as dirname8, join as join14, resolve as resolve16 } from "path";
|
|
91150
91252
|
import { tmpdir as tmpdir3 } from "os";
|
|
91151
91253
|
function sha2567(value) {
|
|
91152
91254
|
return createHash13("sha256").update(value).digest("hex");
|
|
91153
91255
|
}
|
|
91154
91256
|
function fileRecord(root, relativePath) {
|
|
91155
|
-
const path =
|
|
91156
|
-
if (!
|
|
91257
|
+
const path = join14(root, relativePath);
|
|
91258
|
+
if (!existsSync15(path))
|
|
91157
91259
|
return null;
|
|
91158
91260
|
const stat = statSync8(path);
|
|
91159
91261
|
if (!stat.isFile())
|
|
@@ -91165,7 +91267,7 @@ function manifestRecord(root, relativePath) {
|
|
|
91165
91267
|
const base = fileRecord(root, relativePath);
|
|
91166
91268
|
if (!base)
|
|
91167
91269
|
return null;
|
|
91168
|
-
const parsed = readJsonFile(
|
|
91270
|
+
const parsed = readJsonFile(join14(root, relativePath));
|
|
91169
91271
|
if (!parsed)
|
|
91170
91272
|
return { ...base, redacted: {} };
|
|
91171
91273
|
const redacted = redactValue({
|
|
@@ -91260,8 +91362,8 @@ function commandEnv(env, includeValues) {
|
|
|
91260
91362
|
function defaultSnapshotDir() {
|
|
91261
91363
|
const dbPath = getDatabasePath();
|
|
91262
91364
|
if (dbPath === ":memory:" || dbPath.startsWith("file::memory:"))
|
|
91263
|
-
return
|
|
91264
|
-
return
|
|
91365
|
+
return join14(tmpdir3(), "hasna-todos", "environment-snapshots");
|
|
91366
|
+
return join14(dirname8(resolve16(dbPath)), "environment-snapshots");
|
|
91265
91367
|
}
|
|
91266
91368
|
function snapshotWithId(snapshot) {
|
|
91267
91369
|
const digest = sha2567(JSON.stringify(snapshot)).slice(0, 24);
|
|
@@ -91308,7 +91410,7 @@ function captureEnvironmentSnapshot(input = {}) {
|
|
|
91308
91410
|
});
|
|
91309
91411
|
}
|
|
91310
91412
|
function writeEnvironmentSnapshot(snapshot, outputPath) {
|
|
91311
|
-
const path = outputPath ? resolve16(outputPath) :
|
|
91413
|
+
const path = outputPath ? resolve16(outputPath) : join14(defaultSnapshotDir(), `${snapshot.id}.json`);
|
|
91312
91414
|
ensureDir(dirname8(path));
|
|
91313
91415
|
writeJsonFile(path, snapshot);
|
|
91314
91416
|
return path;
|
|
@@ -92231,27 +92333,27 @@ __export(exports_serve, {
|
|
|
92231
92333
|
SECURITY_HEADERS: () => SECURITY_HEADERS,
|
|
92232
92334
|
MIME_TYPES: () => MIME_TYPES
|
|
92233
92335
|
});
|
|
92234
|
-
import { existsSync as
|
|
92235
|
-
import { join as
|
|
92336
|
+
import { existsSync as existsSync16 } from "fs";
|
|
92337
|
+
import { join as join15, dirname as dirname9, extname } from "path";
|
|
92236
92338
|
import { fileURLToPath } from "url";
|
|
92237
92339
|
function resolveDashboardDir() {
|
|
92238
92340
|
const candidates = [];
|
|
92239
92341
|
try {
|
|
92240
92342
|
const scriptDir = dirname9(fileURLToPath(import.meta.url));
|
|
92241
|
-
candidates.push(
|
|
92242
|
-
candidates.push(
|
|
92343
|
+
candidates.push(join15(scriptDir, "..", "dashboard", "dist"));
|
|
92344
|
+
candidates.push(join15(scriptDir, "..", "..", "dashboard", "dist"));
|
|
92243
92345
|
} catch {}
|
|
92244
92346
|
if (process.argv[1]) {
|
|
92245
92347
|
const mainDir = dirname9(process.argv[1]);
|
|
92246
|
-
candidates.push(
|
|
92247
|
-
candidates.push(
|
|
92348
|
+
candidates.push(join15(mainDir, "..", "dashboard", "dist"));
|
|
92349
|
+
candidates.push(join15(mainDir, "..", "..", "dashboard", "dist"));
|
|
92248
92350
|
}
|
|
92249
|
-
candidates.push(
|
|
92351
|
+
candidates.push(join15(process.cwd(), "dashboard", "dist"));
|
|
92250
92352
|
for (const candidate of candidates) {
|
|
92251
|
-
if (
|
|
92353
|
+
if (existsSync16(candidate))
|
|
92252
92354
|
return candidate;
|
|
92253
92355
|
}
|
|
92254
|
-
return
|
|
92356
|
+
return join15(process.cwd(), "dashboard", "dist");
|
|
92255
92357
|
}
|
|
92256
92358
|
function getProvidedApiKey(req) {
|
|
92257
92359
|
const headerKey = req.headers.get("x-api-key");
|
|
@@ -92323,7 +92425,7 @@ function json(data, status = 200, headers) {
|
|
|
92323
92425
|
});
|
|
92324
92426
|
}
|
|
92325
92427
|
function serveStaticFile(filePath) {
|
|
92326
|
-
if (!
|
|
92428
|
+
if (!existsSync16(filePath))
|
|
92327
92429
|
return null;
|
|
92328
92430
|
const ext = extname(filePath);
|
|
92329
92431
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
@@ -92424,7 +92526,7 @@ data: ${data}
|
|
|
92424
92526
|
filteredSseClients.delete(client);
|
|
92425
92527
|
}
|
|
92426
92528
|
const dashboardDir = resolveDashboardDir();
|
|
92427
|
-
const dashboardExists =
|
|
92529
|
+
const dashboardExists = existsSync16(dashboardDir);
|
|
92428
92530
|
if (!dashboardExists) {
|
|
92429
92531
|
console.error(`
|
|
92430
92532
|
Dashboard not found at: ${dashboardDir}`);
|