@hasna/todos 0.11.64 → 0.11.66
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/README.md +76 -47
- 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/commands/task-commands.d.ts.map +1 -1
- package/dist/cli/index.js +368 -63
- package/dist/contracts.js +108 -58
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +300 -59
- package/dist/lib/project-bootstrap.d.ts +1 -0
- package/dist/lib/project-bootstrap.d.ts.map +1 -1
- package/dist/lib/shared-events.d.ts.map +1 -1
- package/dist/lib/task-route-contract.d.ts +33 -0
- package/dist/lib/task-route-contract.d.ts.map +1 -0
- package/dist/lib/task-routing.d.ts +55 -0
- package/dist/lib/task-routing.d.ts.map +1 -0
- package/dist/mcp/index.js +116 -58
- package/dist/registry.js +108 -58
- package/dist/release-provenance.json +3 -3
- package/dist/server/index.js +116 -58
- package/dist/storage.js +108 -58
- package/package.json +1 -1
package/dist/mcp/index.js
CHANGED
|
@@ -9413,38 +9413,7 @@ var init_task_lists = __esm(() => {
|
|
|
9413
9413
|
init_projects();
|
|
9414
9414
|
});
|
|
9415
9415
|
|
|
9416
|
-
// src/lib/
|
|
9417
|
-
function taskEventData(task, extra = {}) {
|
|
9418
|
-
return {
|
|
9419
|
-
id: task.id,
|
|
9420
|
-
task_id: task.id,
|
|
9421
|
-
short_id: task.short_id,
|
|
9422
|
-
title: task.title,
|
|
9423
|
-
description: task.description,
|
|
9424
|
-
status: task.status,
|
|
9425
|
-
priority: task.priority,
|
|
9426
|
-
project_id: task.project_id,
|
|
9427
|
-
parent_id: task.parent_id,
|
|
9428
|
-
plan_id: task.plan_id,
|
|
9429
|
-
task_list_id: task.task_list_id,
|
|
9430
|
-
agent_id: task.agent_id,
|
|
9431
|
-
assigned_to: task.assigned_to,
|
|
9432
|
-
session_id: task.session_id,
|
|
9433
|
-
working_dir: task.working_dir,
|
|
9434
|
-
tags: task.tags,
|
|
9435
|
-
metadata: task.metadata,
|
|
9436
|
-
version: task.version,
|
|
9437
|
-
created_at: task.created_at,
|
|
9438
|
-
updated_at: task.updated_at,
|
|
9439
|
-
started_at: task.started_at,
|
|
9440
|
-
completed_at: task.completed_at,
|
|
9441
|
-
due_at: task.due_at,
|
|
9442
|
-
requires_approval: task.requires_approval,
|
|
9443
|
-
approved_by: task.approved_by,
|
|
9444
|
-
approved_at: task.approved_at,
|
|
9445
|
-
...extra
|
|
9446
|
-
};
|
|
9447
|
-
}
|
|
9416
|
+
// src/lib/task-route-contract.ts
|
|
9448
9417
|
function booleanField(value) {
|
|
9449
9418
|
if (typeof value === "boolean")
|
|
9450
9419
|
return value;
|
|
@@ -9466,21 +9435,31 @@ function booleanField(value) {
|
|
|
9466
9435
|
function objectField(value) {
|
|
9467
9436
|
return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
|
|
9468
9437
|
}
|
|
9469
|
-
function
|
|
9438
|
+
function collectBooleans(records, keys) {
|
|
9439
|
+
const values = [];
|
|
9470
9440
|
for (const record of records) {
|
|
9441
|
+
if (!record)
|
|
9442
|
+
continue;
|
|
9471
9443
|
for (const key of keys) {
|
|
9472
9444
|
const value = booleanField(record[key]);
|
|
9473
9445
|
if (value !== undefined)
|
|
9474
|
-
|
|
9446
|
+
values.push(value);
|
|
9475
9447
|
}
|
|
9476
9448
|
}
|
|
9477
|
-
return;
|
|
9449
|
+
return values;
|
|
9478
9450
|
}
|
|
9479
|
-
function
|
|
9480
|
-
const
|
|
9481
|
-
|
|
9482
|
-
|
|
9483
|
-
|
|
9451
|
+
function mergedBoolean(records, keys, trueWins) {
|
|
9452
|
+
const values = collectBooleans(records, keys);
|
|
9453
|
+
if (values.length === 0)
|
|
9454
|
+
return;
|
|
9455
|
+
if (trueWins)
|
|
9456
|
+
return values.some(Boolean);
|
|
9457
|
+
return values.includes(false) ? false : true;
|
|
9458
|
+
}
|
|
9459
|
+
function routingAutomationMetadata(task, taskList) {
|
|
9460
|
+
const taskAutomation = objectField(task.metadata.automation);
|
|
9461
|
+
const taskListAutomation = taskList ? objectField(taskList.metadata.automation) : undefined;
|
|
9462
|
+
const records = [task.metadata, taskAutomation, taskList?.metadata, taskListAutomation];
|
|
9484
9463
|
const result = {};
|
|
9485
9464
|
const aliases = [
|
|
9486
9465
|
["allowed", ["allowed", "automation_allowed", "automationAllowed"]],
|
|
@@ -9491,7 +9470,7 @@ function routingAutomationMetadata(task) {
|
|
|
9491
9470
|
["approval_required", ["approval_required", "approvalRequired"]]
|
|
9492
9471
|
];
|
|
9493
9472
|
for (const [canonical, keys] of aliases) {
|
|
9494
|
-
const value =
|
|
9473
|
+
const value = mergedBoolean(records, keys, canonical !== "allowed");
|
|
9495
9474
|
if (value !== undefined)
|
|
9496
9475
|
result[canonical] = value;
|
|
9497
9476
|
}
|
|
@@ -9499,23 +9478,88 @@ function routingAutomationMetadata(task) {
|
|
|
9499
9478
|
result.requires_approval = true;
|
|
9500
9479
|
return Object.keys(result).length > 0 ? result : undefined;
|
|
9501
9480
|
}
|
|
9481
|
+
function routeEnabledForTask(task, taskList) {
|
|
9482
|
+
const explicit = booleanField(task.metadata.route_enabled);
|
|
9483
|
+
if (explicit !== undefined)
|
|
9484
|
+
return explicit;
|
|
9485
|
+
if (task.tags.includes("auto:route") || task.tags.includes("route:enabled"))
|
|
9486
|
+
return true;
|
|
9487
|
+
const taskListDefault = taskList ? booleanField(taskList.metadata.route_enabled) : undefined;
|
|
9488
|
+
if (taskListDefault !== undefined)
|
|
9489
|
+
return taskListDefault;
|
|
9490
|
+
return;
|
|
9491
|
+
}
|
|
9492
|
+
function stringField(value) {
|
|
9493
|
+
return typeof value === "string" && value.trim() ? value : undefined;
|
|
9494
|
+
}
|
|
9495
|
+
function workflowPointersFromMetadata(metadata) {
|
|
9496
|
+
const nested = objectField(metadata.workflow_invocation) ?? objectField(metadata.workflow) ?? {};
|
|
9497
|
+
return {
|
|
9498
|
+
current_workflow_invocation_id: stringField(metadata.current_workflow_invocation_id) ?? stringField(nested.current_workflow_invocation_id) ?? stringField(nested.invocation_id),
|
|
9499
|
+
current_run_id: stringField(metadata.current_run_id) ?? stringField(nested.current_run_id) ?? stringField(nested.run_id),
|
|
9500
|
+
latest_manifest_path: stringField(metadata.latest_manifest_path) ?? stringField(nested.latest_manifest_path) ?? stringField(nested.manifest_path),
|
|
9501
|
+
latest_evaluation_path: stringField(metadata.latest_evaluation_path) ?? stringField(nested.latest_evaluation_path) ?? stringField(nested.evaluation_path),
|
|
9502
|
+
workflow_state: stringField(metadata.workflow_state) ?? stringField(nested.workflow_state) ?? stringField(nested.state)
|
|
9503
|
+
};
|
|
9504
|
+
}
|
|
9505
|
+
function classifyProjectKind(path) {
|
|
9506
|
+
return path.includes("/hasna/opensource/") ? "open-source" : "unknown";
|
|
9507
|
+
}
|
|
9508
|
+
function isWorktreePath(path) {
|
|
9509
|
+
return path.includes("/.codewith/worktrees/") || path.includes("/.worktrees/");
|
|
9510
|
+
}
|
|
9511
|
+
function inferRootProjectId(project) {
|
|
9512
|
+
return isWorktreePath(project.path) ? null : project.id;
|
|
9513
|
+
}
|
|
9514
|
+
var TODOS_TASK_ROUTE_STATE_SCHEMA_VERSION = "todos.task_route_state.v1";
|
|
9515
|
+
|
|
9516
|
+
// src/lib/shared-events.ts
|
|
9517
|
+
function taskEventData(task, extra = {}) {
|
|
9518
|
+
return {
|
|
9519
|
+
id: task.id,
|
|
9520
|
+
task_id: task.id,
|
|
9521
|
+
short_id: task.short_id,
|
|
9522
|
+
title: task.title,
|
|
9523
|
+
description: task.description,
|
|
9524
|
+
status: task.status,
|
|
9525
|
+
priority: task.priority,
|
|
9526
|
+
project_id: task.project_id,
|
|
9527
|
+
parent_id: task.parent_id,
|
|
9528
|
+
plan_id: task.plan_id,
|
|
9529
|
+
task_list_id: task.task_list_id,
|
|
9530
|
+
agent_id: task.agent_id,
|
|
9531
|
+
assigned_to: task.assigned_to,
|
|
9532
|
+
session_id: task.session_id,
|
|
9533
|
+
working_dir: task.working_dir,
|
|
9534
|
+
tags: task.tags,
|
|
9535
|
+
metadata: task.metadata,
|
|
9536
|
+
version: task.version,
|
|
9537
|
+
created_at: task.created_at,
|
|
9538
|
+
updated_at: task.updated_at,
|
|
9539
|
+
started_at: task.started_at,
|
|
9540
|
+
completed_at: task.completed_at,
|
|
9541
|
+
due_at: task.due_at,
|
|
9542
|
+
requires_approval: task.requires_approval,
|
|
9543
|
+
approved_by: task.approved_by,
|
|
9544
|
+
approved_at: task.approved_at,
|
|
9545
|
+
...extra
|
|
9546
|
+
};
|
|
9547
|
+
}
|
|
9502
9548
|
function taskEventMetadata(task) {
|
|
9503
9549
|
const metadata = {
|
|
9504
9550
|
package: "@hasna/todos",
|
|
9505
9551
|
todos_event_schema_version: 1,
|
|
9552
|
+
route_state_schema_version: TODOS_TASK_ROUTE_STATE_SCHEMA_VERSION,
|
|
9506
9553
|
task_id: task.id,
|
|
9507
9554
|
task_short_id: task.short_id,
|
|
9508
9555
|
project_id: task.project_id,
|
|
9509
9556
|
task_list_id: task.task_list_id,
|
|
9510
9557
|
working_dir: task.working_dir
|
|
9511
9558
|
};
|
|
9512
|
-
const
|
|
9513
|
-
|
|
9514
|
-
|
|
9515
|
-
|
|
9516
|
-
const automation = routingAutomationMetadata(task);
|
|
9517
|
-
if (automation) {
|
|
9518
|
-
metadata.automation = automation;
|
|
9559
|
+
const pointers = workflowPointersFromMetadata(task.metadata);
|
|
9560
|
+
for (const [key, value] of Object.entries(pointers)) {
|
|
9561
|
+
if (value)
|
|
9562
|
+
metadata[key] = value;
|
|
9519
9563
|
}
|
|
9520
9564
|
try {
|
|
9521
9565
|
const project = task.project_id ? getProject(task.project_id) : null;
|
|
@@ -9544,18 +9588,20 @@ function taskEventMetadata(task) {
|
|
|
9544
9588
|
metadata.task_list_project_id = taskList.project_id;
|
|
9545
9589
|
metadata.task_list_is_project_default = Boolean(project?.task_list_id && taskList.slug === project.task_list_id);
|
|
9546
9590
|
}
|
|
9591
|
+
const routeEnabled = routeEnabledForTask(task, taskList);
|
|
9592
|
+
if (routeEnabled !== undefined) {
|
|
9593
|
+
metadata.route_enabled = routeEnabled;
|
|
9594
|
+
}
|
|
9595
|
+
const automation = routingAutomationMetadata(task, taskList);
|
|
9596
|
+
if (automation) {
|
|
9597
|
+
metadata.automation = automation;
|
|
9598
|
+
metadata.route_blocked_by_no_auto = automation.no_auto === true;
|
|
9599
|
+
metadata.route_blocked_by_manual = automation.manual === true || automation.manual_required === true;
|
|
9600
|
+
metadata.route_blocked_by_approval = (automation.requires_approval === true || automation.approval_required === true) && !task.approved_by;
|
|
9601
|
+
}
|
|
9547
9602
|
} catch {}
|
|
9548
9603
|
return metadata;
|
|
9549
9604
|
}
|
|
9550
|
-
function classifyProjectKind(path) {
|
|
9551
|
-
return path.includes("/hasna/opensource/") ? "open-source" : "unknown";
|
|
9552
|
-
}
|
|
9553
|
-
function isWorktreePath(path) {
|
|
9554
|
-
return path.includes("/.codewith/worktrees/") || path.includes("/.worktrees/");
|
|
9555
|
-
}
|
|
9556
|
-
function inferRootProjectId(project) {
|
|
9557
|
-
return isWorktreePath(project.path) ? null : project.id;
|
|
9558
|
-
}
|
|
9559
9605
|
function readMachineLocalPath(project) {
|
|
9560
9606
|
const machineId = process.env["TODOS_MACHINE_ID"];
|
|
9561
9607
|
if (!machineId)
|
|
@@ -15999,7 +16045,19 @@ function bootstrapProject(options = {}, db) {
|
|
|
15999
16045
|
}
|
|
16000
16046
|
setMachineLocalPath(project.id, discovery.projectPath, d);
|
|
16001
16047
|
const beforeTaskList = d.query("SELECT id FROM task_lists WHERE project_id = ? AND slug = ?").get(project.id, taskListSlug);
|
|
16002
|
-
|
|
16048
|
+
let taskList = ensureTaskList(`${project.name} Tasks`, taskListSlug, project.id, d);
|
|
16049
|
+
if (options.routeEnabled && taskList.metadata.route_enabled !== true) {
|
|
16050
|
+
taskList = updateTaskList(taskList.id, {
|
|
16051
|
+
metadata: {
|
|
16052
|
+
...taskList.metadata,
|
|
16053
|
+
route_enabled: true,
|
|
16054
|
+
automation: {
|
|
16055
|
+
...taskList.metadata.automation && typeof taskList.metadata.automation === "object" && !Array.isArray(taskList.metadata.automation) ? taskList.metadata.automation : {},
|
|
16056
|
+
no_auto: false
|
|
16057
|
+
}
|
|
16058
|
+
}
|
|
16059
|
+
}, d);
|
|
16060
|
+
}
|
|
16003
16061
|
const createdSources = [];
|
|
16004
16062
|
for (const source of [
|
|
16005
16063
|
addSourceOnce(project.id, "local", "Project root", discovery.projectPath, { role: "project-root" }, d),
|
package/dist/registry.js
CHANGED
|
@@ -7628,39 +7628,9 @@ function ensureTaskList(name, slug, projectId, db) {
|
|
|
7628
7628
|
return createTaskList({ name, slug, project_id: projectId }, d);
|
|
7629
7629
|
}
|
|
7630
7630
|
|
|
7631
|
-
// src/lib/
|
|
7632
|
-
var
|
|
7633
|
-
|
|
7634
|
-
return {
|
|
7635
|
-
id: task.id,
|
|
7636
|
-
task_id: task.id,
|
|
7637
|
-
short_id: task.short_id,
|
|
7638
|
-
title: task.title,
|
|
7639
|
-
description: task.description,
|
|
7640
|
-
status: task.status,
|
|
7641
|
-
priority: task.priority,
|
|
7642
|
-
project_id: task.project_id,
|
|
7643
|
-
parent_id: task.parent_id,
|
|
7644
|
-
plan_id: task.plan_id,
|
|
7645
|
-
task_list_id: task.task_list_id,
|
|
7646
|
-
agent_id: task.agent_id,
|
|
7647
|
-
assigned_to: task.assigned_to,
|
|
7648
|
-
session_id: task.session_id,
|
|
7649
|
-
working_dir: task.working_dir,
|
|
7650
|
-
tags: task.tags,
|
|
7651
|
-
metadata: task.metadata,
|
|
7652
|
-
version: task.version,
|
|
7653
|
-
created_at: task.created_at,
|
|
7654
|
-
updated_at: task.updated_at,
|
|
7655
|
-
started_at: task.started_at,
|
|
7656
|
-
completed_at: task.completed_at,
|
|
7657
|
-
due_at: task.due_at,
|
|
7658
|
-
requires_approval: task.requires_approval,
|
|
7659
|
-
approved_by: task.approved_by,
|
|
7660
|
-
approved_at: task.approved_at,
|
|
7661
|
-
...extra
|
|
7662
|
-
};
|
|
7663
|
-
}
|
|
7631
|
+
// src/lib/task-route-contract.ts
|
|
7632
|
+
var TODOS_TASK_ROUTE_STATE_SCHEMA_VERSION = "todos.task_route_state.v1";
|
|
7633
|
+
var TASK_WORKFLOW_POINTER_SCHEMA_VERSION = "todos.task_workflow_pointer.v1";
|
|
7664
7634
|
function booleanField(value) {
|
|
7665
7635
|
if (typeof value === "boolean")
|
|
7666
7636
|
return value;
|
|
@@ -7682,21 +7652,31 @@ function booleanField(value) {
|
|
|
7682
7652
|
function objectField(value) {
|
|
7683
7653
|
return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
|
|
7684
7654
|
}
|
|
7685
|
-
function
|
|
7655
|
+
function collectBooleans(records, keys) {
|
|
7656
|
+
const values = [];
|
|
7686
7657
|
for (const record of records) {
|
|
7658
|
+
if (!record)
|
|
7659
|
+
continue;
|
|
7687
7660
|
for (const key of keys) {
|
|
7688
7661
|
const value = booleanField(record[key]);
|
|
7689
7662
|
if (value !== undefined)
|
|
7690
|
-
|
|
7663
|
+
values.push(value);
|
|
7691
7664
|
}
|
|
7692
7665
|
}
|
|
7693
|
-
return;
|
|
7666
|
+
return values;
|
|
7694
7667
|
}
|
|
7695
|
-
function
|
|
7696
|
-
const
|
|
7697
|
-
|
|
7698
|
-
|
|
7699
|
-
|
|
7668
|
+
function mergedBoolean(records, keys, trueWins) {
|
|
7669
|
+
const values = collectBooleans(records, keys);
|
|
7670
|
+
if (values.length === 0)
|
|
7671
|
+
return;
|
|
7672
|
+
if (trueWins)
|
|
7673
|
+
return values.some(Boolean);
|
|
7674
|
+
return values.includes(false) ? false : true;
|
|
7675
|
+
}
|
|
7676
|
+
function routingAutomationMetadata(task, taskList) {
|
|
7677
|
+
const taskAutomation = objectField(task.metadata.automation);
|
|
7678
|
+
const taskListAutomation = taskList ? objectField(taskList.metadata.automation) : undefined;
|
|
7679
|
+
const records = [task.metadata, taskAutomation, taskList?.metadata, taskListAutomation];
|
|
7700
7680
|
const result = {};
|
|
7701
7681
|
const aliases = [
|
|
7702
7682
|
["allowed", ["allowed", "automation_allowed", "automationAllowed"]],
|
|
@@ -7707,7 +7687,7 @@ function routingAutomationMetadata(task) {
|
|
|
7707
7687
|
["approval_required", ["approval_required", "approvalRequired"]]
|
|
7708
7688
|
];
|
|
7709
7689
|
for (const [canonical, keys] of aliases) {
|
|
7710
|
-
const value =
|
|
7690
|
+
const value = mergedBoolean(records, keys, canonical !== "allowed");
|
|
7711
7691
|
if (value !== undefined)
|
|
7712
7692
|
result[canonical] = value;
|
|
7713
7693
|
}
|
|
@@ -7715,23 +7695,91 @@ function routingAutomationMetadata(task) {
|
|
|
7715
7695
|
result.requires_approval = true;
|
|
7716
7696
|
return Object.keys(result).length > 0 ? result : undefined;
|
|
7717
7697
|
}
|
|
7698
|
+
function routeEnabledForTask(task, taskList) {
|
|
7699
|
+
const explicit = booleanField(task.metadata.route_enabled);
|
|
7700
|
+
if (explicit !== undefined)
|
|
7701
|
+
return explicit;
|
|
7702
|
+
if (task.tags.includes("auto:route") || task.tags.includes("route:enabled"))
|
|
7703
|
+
return true;
|
|
7704
|
+
const taskListDefault = taskList ? booleanField(taskList.metadata.route_enabled) : undefined;
|
|
7705
|
+
if (taskListDefault !== undefined)
|
|
7706
|
+
return taskListDefault;
|
|
7707
|
+
return;
|
|
7708
|
+
}
|
|
7709
|
+
function stringField(value) {
|
|
7710
|
+
return typeof value === "string" && value.trim() ? value : undefined;
|
|
7711
|
+
}
|
|
7712
|
+
function workflowPointersFromMetadata(metadata) {
|
|
7713
|
+
const nested = objectField(metadata.workflow_invocation) ?? objectField(metadata.workflow) ?? {};
|
|
7714
|
+
return {
|
|
7715
|
+
current_workflow_invocation_id: stringField(metadata.current_workflow_invocation_id) ?? stringField(nested.current_workflow_invocation_id) ?? stringField(nested.invocation_id),
|
|
7716
|
+
current_run_id: stringField(metadata.current_run_id) ?? stringField(nested.current_run_id) ?? stringField(nested.run_id),
|
|
7717
|
+
latest_manifest_path: stringField(metadata.latest_manifest_path) ?? stringField(nested.latest_manifest_path) ?? stringField(nested.manifest_path),
|
|
7718
|
+
latest_evaluation_path: stringField(metadata.latest_evaluation_path) ?? stringField(nested.latest_evaluation_path) ?? stringField(nested.evaluation_path),
|
|
7719
|
+
workflow_state: stringField(metadata.workflow_state) ?? stringField(nested.workflow_state) ?? stringField(nested.state)
|
|
7720
|
+
};
|
|
7721
|
+
}
|
|
7722
|
+
function compactWorkflowPointers(pointers) {
|
|
7723
|
+
return Object.fromEntries(Object.entries(pointers).filter(([, value]) => typeof value === "string" && value.length > 0));
|
|
7724
|
+
}
|
|
7725
|
+
function classifyProjectKind(path) {
|
|
7726
|
+
return path.includes("/hasna/opensource/") ? "open-source" : "unknown";
|
|
7727
|
+
}
|
|
7728
|
+
function isWorktreePath(path) {
|
|
7729
|
+
return path.includes("/.codewith/worktrees/") || path.includes("/.worktrees/");
|
|
7730
|
+
}
|
|
7731
|
+
function inferRootProjectId(project) {
|
|
7732
|
+
return isWorktreePath(project.path) ? null : project.id;
|
|
7733
|
+
}
|
|
7734
|
+
|
|
7735
|
+
// src/lib/shared-events.ts
|
|
7736
|
+
var SOURCE = "todos";
|
|
7737
|
+
function taskEventData(task, extra = {}) {
|
|
7738
|
+
return {
|
|
7739
|
+
id: task.id,
|
|
7740
|
+
task_id: task.id,
|
|
7741
|
+
short_id: task.short_id,
|
|
7742
|
+
title: task.title,
|
|
7743
|
+
description: task.description,
|
|
7744
|
+
status: task.status,
|
|
7745
|
+
priority: task.priority,
|
|
7746
|
+
project_id: task.project_id,
|
|
7747
|
+
parent_id: task.parent_id,
|
|
7748
|
+
plan_id: task.plan_id,
|
|
7749
|
+
task_list_id: task.task_list_id,
|
|
7750
|
+
agent_id: task.agent_id,
|
|
7751
|
+
assigned_to: task.assigned_to,
|
|
7752
|
+
session_id: task.session_id,
|
|
7753
|
+
working_dir: task.working_dir,
|
|
7754
|
+
tags: task.tags,
|
|
7755
|
+
metadata: task.metadata,
|
|
7756
|
+
version: task.version,
|
|
7757
|
+
created_at: task.created_at,
|
|
7758
|
+
updated_at: task.updated_at,
|
|
7759
|
+
started_at: task.started_at,
|
|
7760
|
+
completed_at: task.completed_at,
|
|
7761
|
+
due_at: task.due_at,
|
|
7762
|
+
requires_approval: task.requires_approval,
|
|
7763
|
+
approved_by: task.approved_by,
|
|
7764
|
+
approved_at: task.approved_at,
|
|
7765
|
+
...extra
|
|
7766
|
+
};
|
|
7767
|
+
}
|
|
7718
7768
|
function taskEventMetadata(task) {
|
|
7719
7769
|
const metadata = {
|
|
7720
7770
|
package: "@hasna/todos",
|
|
7721
7771
|
todos_event_schema_version: 1,
|
|
7772
|
+
route_state_schema_version: TODOS_TASK_ROUTE_STATE_SCHEMA_VERSION,
|
|
7722
7773
|
task_id: task.id,
|
|
7723
7774
|
task_short_id: task.short_id,
|
|
7724
7775
|
project_id: task.project_id,
|
|
7725
7776
|
task_list_id: task.task_list_id,
|
|
7726
7777
|
working_dir: task.working_dir
|
|
7727
7778
|
};
|
|
7728
|
-
const
|
|
7729
|
-
|
|
7730
|
-
|
|
7731
|
-
|
|
7732
|
-
const automation = routingAutomationMetadata(task);
|
|
7733
|
-
if (automation) {
|
|
7734
|
-
metadata.automation = automation;
|
|
7779
|
+
const pointers = workflowPointersFromMetadata(task.metadata);
|
|
7780
|
+
for (const [key, value] of Object.entries(pointers)) {
|
|
7781
|
+
if (value)
|
|
7782
|
+
metadata[key] = value;
|
|
7735
7783
|
}
|
|
7736
7784
|
try {
|
|
7737
7785
|
const project = task.project_id ? getProject(task.project_id) : null;
|
|
@@ -7760,18 +7808,20 @@ function taskEventMetadata(task) {
|
|
|
7760
7808
|
metadata.task_list_project_id = taskList.project_id;
|
|
7761
7809
|
metadata.task_list_is_project_default = Boolean(project?.task_list_id && taskList.slug === project.task_list_id);
|
|
7762
7810
|
}
|
|
7811
|
+
const routeEnabled = routeEnabledForTask(task, taskList);
|
|
7812
|
+
if (routeEnabled !== undefined) {
|
|
7813
|
+
metadata.route_enabled = routeEnabled;
|
|
7814
|
+
}
|
|
7815
|
+
const automation = routingAutomationMetadata(task, taskList);
|
|
7816
|
+
if (automation) {
|
|
7817
|
+
metadata.automation = automation;
|
|
7818
|
+
metadata.route_blocked_by_no_auto = automation.no_auto === true;
|
|
7819
|
+
metadata.route_blocked_by_manual = automation.manual === true || automation.manual_required === true;
|
|
7820
|
+
metadata.route_blocked_by_approval = (automation.requires_approval === true || automation.approval_required === true) && !task.approved_by;
|
|
7821
|
+
}
|
|
7763
7822
|
} catch {}
|
|
7764
7823
|
return metadata;
|
|
7765
7824
|
}
|
|
7766
|
-
function classifyProjectKind(path) {
|
|
7767
|
-
return path.includes("/hasna/opensource/") ? "open-source" : "unknown";
|
|
7768
|
-
}
|
|
7769
|
-
function isWorktreePath(path) {
|
|
7770
|
-
return path.includes("/.codewith/worktrees/") || path.includes("/.worktrees/");
|
|
7771
|
-
}
|
|
7772
|
-
function inferRootProjectId(project) {
|
|
7773
|
-
return isWorktreePath(project.path) ? null : project.id;
|
|
7774
|
-
}
|
|
7775
7825
|
function readMachineLocalPath(project) {
|
|
7776
7826
|
const machineId = process.env["TODOS_MACHINE_ID"];
|
|
7777
7827
|
if (!machineId)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"packageName": "@hasna/todos",
|
|
3
|
-
"packageVersion": "0.11.
|
|
3
|
+
"packageVersion": "0.11.66",
|
|
4
4
|
"repository": "https://github.com/hasna/todos.git",
|
|
5
|
-
"gitCommit": "
|
|
6
|
-
"generatedAt": "2026-06-
|
|
5
|
+
"gitCommit": "d016ecf14209af05d9d2040ff52e8b69b27a0b6f",
|
|
6
|
+
"generatedAt": "2026-06-28T16:44:28.364Z"
|
|
7
7
|
}
|