@hasna/todos 0.11.65 → 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 +367 -62
- 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/server/index.js
CHANGED
|
@@ -4774,38 +4774,7 @@ var init_task_lists = __esm(() => {
|
|
|
4774
4774
|
init_projects();
|
|
4775
4775
|
});
|
|
4776
4776
|
|
|
4777
|
-
// src/lib/
|
|
4778
|
-
function taskEventData(task, extra = {}) {
|
|
4779
|
-
return {
|
|
4780
|
-
id: task.id,
|
|
4781
|
-
task_id: task.id,
|
|
4782
|
-
short_id: task.short_id,
|
|
4783
|
-
title: task.title,
|
|
4784
|
-
description: task.description,
|
|
4785
|
-
status: task.status,
|
|
4786
|
-
priority: task.priority,
|
|
4787
|
-
project_id: task.project_id,
|
|
4788
|
-
parent_id: task.parent_id,
|
|
4789
|
-
plan_id: task.plan_id,
|
|
4790
|
-
task_list_id: task.task_list_id,
|
|
4791
|
-
agent_id: task.agent_id,
|
|
4792
|
-
assigned_to: task.assigned_to,
|
|
4793
|
-
session_id: task.session_id,
|
|
4794
|
-
working_dir: task.working_dir,
|
|
4795
|
-
tags: task.tags,
|
|
4796
|
-
metadata: task.metadata,
|
|
4797
|
-
version: task.version,
|
|
4798
|
-
created_at: task.created_at,
|
|
4799
|
-
updated_at: task.updated_at,
|
|
4800
|
-
started_at: task.started_at,
|
|
4801
|
-
completed_at: task.completed_at,
|
|
4802
|
-
due_at: task.due_at,
|
|
4803
|
-
requires_approval: task.requires_approval,
|
|
4804
|
-
approved_by: task.approved_by,
|
|
4805
|
-
approved_at: task.approved_at,
|
|
4806
|
-
...extra
|
|
4807
|
-
};
|
|
4808
|
-
}
|
|
4777
|
+
// src/lib/task-route-contract.ts
|
|
4809
4778
|
function booleanField(value) {
|
|
4810
4779
|
if (typeof value === "boolean")
|
|
4811
4780
|
return value;
|
|
@@ -4827,21 +4796,31 @@ function booleanField(value) {
|
|
|
4827
4796
|
function objectField(value) {
|
|
4828
4797
|
return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
|
|
4829
4798
|
}
|
|
4830
|
-
function
|
|
4799
|
+
function collectBooleans(records, keys) {
|
|
4800
|
+
const values = [];
|
|
4831
4801
|
for (const record of records) {
|
|
4802
|
+
if (!record)
|
|
4803
|
+
continue;
|
|
4832
4804
|
for (const key of keys) {
|
|
4833
4805
|
const value = booleanField(record[key]);
|
|
4834
4806
|
if (value !== undefined)
|
|
4835
|
-
|
|
4807
|
+
values.push(value);
|
|
4836
4808
|
}
|
|
4837
4809
|
}
|
|
4838
|
-
return;
|
|
4810
|
+
return values;
|
|
4839
4811
|
}
|
|
4840
|
-
function
|
|
4841
|
-
const
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
|
|
4812
|
+
function mergedBoolean(records, keys, trueWins) {
|
|
4813
|
+
const values = collectBooleans(records, keys);
|
|
4814
|
+
if (values.length === 0)
|
|
4815
|
+
return;
|
|
4816
|
+
if (trueWins)
|
|
4817
|
+
return values.some(Boolean);
|
|
4818
|
+
return values.includes(false) ? false : true;
|
|
4819
|
+
}
|
|
4820
|
+
function routingAutomationMetadata(task, taskList) {
|
|
4821
|
+
const taskAutomation = objectField(task.metadata.automation);
|
|
4822
|
+
const taskListAutomation = taskList ? objectField(taskList.metadata.automation) : undefined;
|
|
4823
|
+
const records = [task.metadata, taskAutomation, taskList?.metadata, taskListAutomation];
|
|
4845
4824
|
const result = {};
|
|
4846
4825
|
const aliases = [
|
|
4847
4826
|
["allowed", ["allowed", "automation_allowed", "automationAllowed"]],
|
|
@@ -4852,7 +4831,7 @@ function routingAutomationMetadata(task) {
|
|
|
4852
4831
|
["approval_required", ["approval_required", "approvalRequired"]]
|
|
4853
4832
|
];
|
|
4854
4833
|
for (const [canonical, keys] of aliases) {
|
|
4855
|
-
const value =
|
|
4834
|
+
const value = mergedBoolean(records, keys, canonical !== "allowed");
|
|
4856
4835
|
if (value !== undefined)
|
|
4857
4836
|
result[canonical] = value;
|
|
4858
4837
|
}
|
|
@@ -4860,23 +4839,88 @@ function routingAutomationMetadata(task) {
|
|
|
4860
4839
|
result.requires_approval = true;
|
|
4861
4840
|
return Object.keys(result).length > 0 ? result : undefined;
|
|
4862
4841
|
}
|
|
4842
|
+
function routeEnabledForTask(task, taskList) {
|
|
4843
|
+
const explicit = booleanField(task.metadata.route_enabled);
|
|
4844
|
+
if (explicit !== undefined)
|
|
4845
|
+
return explicit;
|
|
4846
|
+
if (task.tags.includes("auto:route") || task.tags.includes("route:enabled"))
|
|
4847
|
+
return true;
|
|
4848
|
+
const taskListDefault = taskList ? booleanField(taskList.metadata.route_enabled) : undefined;
|
|
4849
|
+
if (taskListDefault !== undefined)
|
|
4850
|
+
return taskListDefault;
|
|
4851
|
+
return;
|
|
4852
|
+
}
|
|
4853
|
+
function stringField(value) {
|
|
4854
|
+
return typeof value === "string" && value.trim() ? value : undefined;
|
|
4855
|
+
}
|
|
4856
|
+
function workflowPointersFromMetadata(metadata) {
|
|
4857
|
+
const nested = objectField(metadata.workflow_invocation) ?? objectField(metadata.workflow) ?? {};
|
|
4858
|
+
return {
|
|
4859
|
+
current_workflow_invocation_id: stringField(metadata.current_workflow_invocation_id) ?? stringField(nested.current_workflow_invocation_id) ?? stringField(nested.invocation_id),
|
|
4860
|
+
current_run_id: stringField(metadata.current_run_id) ?? stringField(nested.current_run_id) ?? stringField(nested.run_id),
|
|
4861
|
+
latest_manifest_path: stringField(metadata.latest_manifest_path) ?? stringField(nested.latest_manifest_path) ?? stringField(nested.manifest_path),
|
|
4862
|
+
latest_evaluation_path: stringField(metadata.latest_evaluation_path) ?? stringField(nested.latest_evaluation_path) ?? stringField(nested.evaluation_path),
|
|
4863
|
+
workflow_state: stringField(metadata.workflow_state) ?? stringField(nested.workflow_state) ?? stringField(nested.state)
|
|
4864
|
+
};
|
|
4865
|
+
}
|
|
4866
|
+
function classifyProjectKind(path) {
|
|
4867
|
+
return path.includes("/hasna/opensource/") ? "open-source" : "unknown";
|
|
4868
|
+
}
|
|
4869
|
+
function isWorktreePath(path) {
|
|
4870
|
+
return path.includes("/.codewith/worktrees/") || path.includes("/.worktrees/");
|
|
4871
|
+
}
|
|
4872
|
+
function inferRootProjectId(project) {
|
|
4873
|
+
return isWorktreePath(project.path) ? null : project.id;
|
|
4874
|
+
}
|
|
4875
|
+
var TODOS_TASK_ROUTE_STATE_SCHEMA_VERSION = "todos.task_route_state.v1";
|
|
4876
|
+
|
|
4877
|
+
// src/lib/shared-events.ts
|
|
4878
|
+
function taskEventData(task, extra = {}) {
|
|
4879
|
+
return {
|
|
4880
|
+
id: task.id,
|
|
4881
|
+
task_id: task.id,
|
|
4882
|
+
short_id: task.short_id,
|
|
4883
|
+
title: task.title,
|
|
4884
|
+
description: task.description,
|
|
4885
|
+
status: task.status,
|
|
4886
|
+
priority: task.priority,
|
|
4887
|
+
project_id: task.project_id,
|
|
4888
|
+
parent_id: task.parent_id,
|
|
4889
|
+
plan_id: task.plan_id,
|
|
4890
|
+
task_list_id: task.task_list_id,
|
|
4891
|
+
agent_id: task.agent_id,
|
|
4892
|
+
assigned_to: task.assigned_to,
|
|
4893
|
+
session_id: task.session_id,
|
|
4894
|
+
working_dir: task.working_dir,
|
|
4895
|
+
tags: task.tags,
|
|
4896
|
+
metadata: task.metadata,
|
|
4897
|
+
version: task.version,
|
|
4898
|
+
created_at: task.created_at,
|
|
4899
|
+
updated_at: task.updated_at,
|
|
4900
|
+
started_at: task.started_at,
|
|
4901
|
+
completed_at: task.completed_at,
|
|
4902
|
+
due_at: task.due_at,
|
|
4903
|
+
requires_approval: task.requires_approval,
|
|
4904
|
+
approved_by: task.approved_by,
|
|
4905
|
+
approved_at: task.approved_at,
|
|
4906
|
+
...extra
|
|
4907
|
+
};
|
|
4908
|
+
}
|
|
4863
4909
|
function taskEventMetadata(task) {
|
|
4864
4910
|
const metadata = {
|
|
4865
4911
|
package: "@hasna/todos",
|
|
4866
4912
|
todos_event_schema_version: 1,
|
|
4913
|
+
route_state_schema_version: TODOS_TASK_ROUTE_STATE_SCHEMA_VERSION,
|
|
4867
4914
|
task_id: task.id,
|
|
4868
4915
|
task_short_id: task.short_id,
|
|
4869
4916
|
project_id: task.project_id,
|
|
4870
4917
|
task_list_id: task.task_list_id,
|
|
4871
4918
|
working_dir: task.working_dir
|
|
4872
4919
|
};
|
|
4873
|
-
const
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
const automation = routingAutomationMetadata(task);
|
|
4878
|
-
if (automation) {
|
|
4879
|
-
metadata.automation = automation;
|
|
4920
|
+
const pointers = workflowPointersFromMetadata(task.metadata);
|
|
4921
|
+
for (const [key, value] of Object.entries(pointers)) {
|
|
4922
|
+
if (value)
|
|
4923
|
+
metadata[key] = value;
|
|
4880
4924
|
}
|
|
4881
4925
|
try {
|
|
4882
4926
|
const project = task.project_id ? getProject(task.project_id) : null;
|
|
@@ -4905,18 +4949,20 @@ function taskEventMetadata(task) {
|
|
|
4905
4949
|
metadata.task_list_project_id = taskList.project_id;
|
|
4906
4950
|
metadata.task_list_is_project_default = Boolean(project?.task_list_id && taskList.slug === project.task_list_id);
|
|
4907
4951
|
}
|
|
4952
|
+
const routeEnabled = routeEnabledForTask(task, taskList);
|
|
4953
|
+
if (routeEnabled !== undefined) {
|
|
4954
|
+
metadata.route_enabled = routeEnabled;
|
|
4955
|
+
}
|
|
4956
|
+
const automation = routingAutomationMetadata(task, taskList);
|
|
4957
|
+
if (automation) {
|
|
4958
|
+
metadata.automation = automation;
|
|
4959
|
+
metadata.route_blocked_by_no_auto = automation.no_auto === true;
|
|
4960
|
+
metadata.route_blocked_by_manual = automation.manual === true || automation.manual_required === true;
|
|
4961
|
+
metadata.route_blocked_by_approval = (automation.requires_approval === true || automation.approval_required === true) && !task.approved_by;
|
|
4962
|
+
}
|
|
4908
4963
|
} catch {}
|
|
4909
4964
|
return metadata;
|
|
4910
4965
|
}
|
|
4911
|
-
function classifyProjectKind(path) {
|
|
4912
|
-
return path.includes("/hasna/opensource/") ? "open-source" : "unknown";
|
|
4913
|
-
}
|
|
4914
|
-
function isWorktreePath(path) {
|
|
4915
|
-
return path.includes("/.codewith/worktrees/") || path.includes("/.worktrees/");
|
|
4916
|
-
}
|
|
4917
|
-
function inferRootProjectId(project) {
|
|
4918
|
-
return isWorktreePath(project.path) ? null : project.id;
|
|
4919
|
-
}
|
|
4920
4966
|
function readMachineLocalPath(project) {
|
|
4921
4967
|
const machineId = process.env["TODOS_MACHINE_ID"];
|
|
4922
4968
|
if (!machineId)
|
|
@@ -33684,7 +33730,19 @@ function bootstrapProject(options = {}, db) {
|
|
|
33684
33730
|
}
|
|
33685
33731
|
setMachineLocalPath(project.id, discovery.projectPath, d);
|
|
33686
33732
|
const beforeTaskList = d.query("SELECT id FROM task_lists WHERE project_id = ? AND slug = ?").get(project.id, taskListSlug);
|
|
33687
|
-
|
|
33733
|
+
let taskList = ensureTaskList(`${project.name} Tasks`, taskListSlug, project.id, d);
|
|
33734
|
+
if (options.routeEnabled && taskList.metadata.route_enabled !== true) {
|
|
33735
|
+
taskList = updateTaskList(taskList.id, {
|
|
33736
|
+
metadata: {
|
|
33737
|
+
...taskList.metadata,
|
|
33738
|
+
route_enabled: true,
|
|
33739
|
+
automation: {
|
|
33740
|
+
...taskList.metadata.automation && typeof taskList.metadata.automation === "object" && !Array.isArray(taskList.metadata.automation) ? taskList.metadata.automation : {},
|
|
33741
|
+
no_auto: false
|
|
33742
|
+
}
|
|
33743
|
+
}
|
|
33744
|
+
}, d);
|
|
33745
|
+
}
|
|
33688
33746
|
const createdSources = [];
|
|
33689
33747
|
for (const source of [
|
|
33690
33748
|
addSourceOnce(project.id, "local", "Project root", discovery.projectPath, { role: "project-root" }, d),
|
package/dist/storage.js
CHANGED
|
@@ -5176,39 +5176,9 @@ function ensureTaskList(name, slug, projectId, db) {
|
|
|
5176
5176
|
return createTaskList({ name, slug, project_id: projectId }, d);
|
|
5177
5177
|
}
|
|
5178
5178
|
|
|
5179
|
-
// src/lib/
|
|
5180
|
-
var
|
|
5181
|
-
|
|
5182
|
-
return {
|
|
5183
|
-
id: task.id,
|
|
5184
|
-
task_id: task.id,
|
|
5185
|
-
short_id: task.short_id,
|
|
5186
|
-
title: task.title,
|
|
5187
|
-
description: task.description,
|
|
5188
|
-
status: task.status,
|
|
5189
|
-
priority: task.priority,
|
|
5190
|
-
project_id: task.project_id,
|
|
5191
|
-
parent_id: task.parent_id,
|
|
5192
|
-
plan_id: task.plan_id,
|
|
5193
|
-
task_list_id: task.task_list_id,
|
|
5194
|
-
agent_id: task.agent_id,
|
|
5195
|
-
assigned_to: task.assigned_to,
|
|
5196
|
-
session_id: task.session_id,
|
|
5197
|
-
working_dir: task.working_dir,
|
|
5198
|
-
tags: task.tags,
|
|
5199
|
-
metadata: task.metadata,
|
|
5200
|
-
version: task.version,
|
|
5201
|
-
created_at: task.created_at,
|
|
5202
|
-
updated_at: task.updated_at,
|
|
5203
|
-
started_at: task.started_at,
|
|
5204
|
-
completed_at: task.completed_at,
|
|
5205
|
-
due_at: task.due_at,
|
|
5206
|
-
requires_approval: task.requires_approval,
|
|
5207
|
-
approved_by: task.approved_by,
|
|
5208
|
-
approved_at: task.approved_at,
|
|
5209
|
-
...extra
|
|
5210
|
-
};
|
|
5211
|
-
}
|
|
5179
|
+
// src/lib/task-route-contract.ts
|
|
5180
|
+
var TODOS_TASK_ROUTE_STATE_SCHEMA_VERSION = "todos.task_route_state.v1";
|
|
5181
|
+
var TASK_WORKFLOW_POINTER_SCHEMA_VERSION = "todos.task_workflow_pointer.v1";
|
|
5212
5182
|
function booleanField(value) {
|
|
5213
5183
|
if (typeof value === "boolean")
|
|
5214
5184
|
return value;
|
|
@@ -5230,21 +5200,31 @@ function booleanField(value) {
|
|
|
5230
5200
|
function objectField(value) {
|
|
5231
5201
|
return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
|
|
5232
5202
|
}
|
|
5233
|
-
function
|
|
5203
|
+
function collectBooleans(records, keys) {
|
|
5204
|
+
const values = [];
|
|
5234
5205
|
for (const record of records) {
|
|
5206
|
+
if (!record)
|
|
5207
|
+
continue;
|
|
5235
5208
|
for (const key of keys) {
|
|
5236
5209
|
const value = booleanField(record[key]);
|
|
5237
5210
|
if (value !== undefined)
|
|
5238
|
-
|
|
5211
|
+
values.push(value);
|
|
5239
5212
|
}
|
|
5240
5213
|
}
|
|
5241
|
-
return;
|
|
5214
|
+
return values;
|
|
5242
5215
|
}
|
|
5243
|
-
function
|
|
5244
|
-
const
|
|
5245
|
-
|
|
5246
|
-
|
|
5247
|
-
|
|
5216
|
+
function mergedBoolean(records, keys, trueWins) {
|
|
5217
|
+
const values = collectBooleans(records, keys);
|
|
5218
|
+
if (values.length === 0)
|
|
5219
|
+
return;
|
|
5220
|
+
if (trueWins)
|
|
5221
|
+
return values.some(Boolean);
|
|
5222
|
+
return values.includes(false) ? false : true;
|
|
5223
|
+
}
|
|
5224
|
+
function routingAutomationMetadata(task, taskList) {
|
|
5225
|
+
const taskAutomation = objectField(task.metadata.automation);
|
|
5226
|
+
const taskListAutomation = taskList ? objectField(taskList.metadata.automation) : undefined;
|
|
5227
|
+
const records = [task.metadata, taskAutomation, taskList?.metadata, taskListAutomation];
|
|
5248
5228
|
const result = {};
|
|
5249
5229
|
const aliases = [
|
|
5250
5230
|
["allowed", ["allowed", "automation_allowed", "automationAllowed"]],
|
|
@@ -5255,7 +5235,7 @@ function routingAutomationMetadata(task) {
|
|
|
5255
5235
|
["approval_required", ["approval_required", "approvalRequired"]]
|
|
5256
5236
|
];
|
|
5257
5237
|
for (const [canonical, keys] of aliases) {
|
|
5258
|
-
const value =
|
|
5238
|
+
const value = mergedBoolean(records, keys, canonical !== "allowed");
|
|
5259
5239
|
if (value !== undefined)
|
|
5260
5240
|
result[canonical] = value;
|
|
5261
5241
|
}
|
|
@@ -5263,23 +5243,91 @@ function routingAutomationMetadata(task) {
|
|
|
5263
5243
|
result.requires_approval = true;
|
|
5264
5244
|
return Object.keys(result).length > 0 ? result : undefined;
|
|
5265
5245
|
}
|
|
5246
|
+
function routeEnabledForTask(task, taskList) {
|
|
5247
|
+
const explicit = booleanField(task.metadata.route_enabled);
|
|
5248
|
+
if (explicit !== undefined)
|
|
5249
|
+
return explicit;
|
|
5250
|
+
if (task.tags.includes("auto:route") || task.tags.includes("route:enabled"))
|
|
5251
|
+
return true;
|
|
5252
|
+
const taskListDefault = taskList ? booleanField(taskList.metadata.route_enabled) : undefined;
|
|
5253
|
+
if (taskListDefault !== undefined)
|
|
5254
|
+
return taskListDefault;
|
|
5255
|
+
return;
|
|
5256
|
+
}
|
|
5257
|
+
function stringField(value) {
|
|
5258
|
+
return typeof value === "string" && value.trim() ? value : undefined;
|
|
5259
|
+
}
|
|
5260
|
+
function workflowPointersFromMetadata(metadata) {
|
|
5261
|
+
const nested = objectField(metadata.workflow_invocation) ?? objectField(metadata.workflow) ?? {};
|
|
5262
|
+
return {
|
|
5263
|
+
current_workflow_invocation_id: stringField(metadata.current_workflow_invocation_id) ?? stringField(nested.current_workflow_invocation_id) ?? stringField(nested.invocation_id),
|
|
5264
|
+
current_run_id: stringField(metadata.current_run_id) ?? stringField(nested.current_run_id) ?? stringField(nested.run_id),
|
|
5265
|
+
latest_manifest_path: stringField(metadata.latest_manifest_path) ?? stringField(nested.latest_manifest_path) ?? stringField(nested.manifest_path),
|
|
5266
|
+
latest_evaluation_path: stringField(metadata.latest_evaluation_path) ?? stringField(nested.latest_evaluation_path) ?? stringField(nested.evaluation_path),
|
|
5267
|
+
workflow_state: stringField(metadata.workflow_state) ?? stringField(nested.workflow_state) ?? stringField(nested.state)
|
|
5268
|
+
};
|
|
5269
|
+
}
|
|
5270
|
+
function compactWorkflowPointers(pointers) {
|
|
5271
|
+
return Object.fromEntries(Object.entries(pointers).filter(([, value]) => typeof value === "string" && value.length > 0));
|
|
5272
|
+
}
|
|
5273
|
+
function classifyProjectKind(path) {
|
|
5274
|
+
return path.includes("/hasna/opensource/") ? "open-source" : "unknown";
|
|
5275
|
+
}
|
|
5276
|
+
function isWorktreePath(path) {
|
|
5277
|
+
return path.includes("/.codewith/worktrees/") || path.includes("/.worktrees/");
|
|
5278
|
+
}
|
|
5279
|
+
function inferRootProjectId(project) {
|
|
5280
|
+
return isWorktreePath(project.path) ? null : project.id;
|
|
5281
|
+
}
|
|
5282
|
+
|
|
5283
|
+
// src/lib/shared-events.ts
|
|
5284
|
+
var SOURCE = "todos";
|
|
5285
|
+
function taskEventData(task, extra = {}) {
|
|
5286
|
+
return {
|
|
5287
|
+
id: task.id,
|
|
5288
|
+
task_id: task.id,
|
|
5289
|
+
short_id: task.short_id,
|
|
5290
|
+
title: task.title,
|
|
5291
|
+
description: task.description,
|
|
5292
|
+
status: task.status,
|
|
5293
|
+
priority: task.priority,
|
|
5294
|
+
project_id: task.project_id,
|
|
5295
|
+
parent_id: task.parent_id,
|
|
5296
|
+
plan_id: task.plan_id,
|
|
5297
|
+
task_list_id: task.task_list_id,
|
|
5298
|
+
agent_id: task.agent_id,
|
|
5299
|
+
assigned_to: task.assigned_to,
|
|
5300
|
+
session_id: task.session_id,
|
|
5301
|
+
working_dir: task.working_dir,
|
|
5302
|
+
tags: task.tags,
|
|
5303
|
+
metadata: task.metadata,
|
|
5304
|
+
version: task.version,
|
|
5305
|
+
created_at: task.created_at,
|
|
5306
|
+
updated_at: task.updated_at,
|
|
5307
|
+
started_at: task.started_at,
|
|
5308
|
+
completed_at: task.completed_at,
|
|
5309
|
+
due_at: task.due_at,
|
|
5310
|
+
requires_approval: task.requires_approval,
|
|
5311
|
+
approved_by: task.approved_by,
|
|
5312
|
+
approved_at: task.approved_at,
|
|
5313
|
+
...extra
|
|
5314
|
+
};
|
|
5315
|
+
}
|
|
5266
5316
|
function taskEventMetadata(task) {
|
|
5267
5317
|
const metadata = {
|
|
5268
5318
|
package: "@hasna/todos",
|
|
5269
5319
|
todos_event_schema_version: 1,
|
|
5320
|
+
route_state_schema_version: TODOS_TASK_ROUTE_STATE_SCHEMA_VERSION,
|
|
5270
5321
|
task_id: task.id,
|
|
5271
5322
|
task_short_id: task.short_id,
|
|
5272
5323
|
project_id: task.project_id,
|
|
5273
5324
|
task_list_id: task.task_list_id,
|
|
5274
5325
|
working_dir: task.working_dir
|
|
5275
5326
|
};
|
|
5276
|
-
const
|
|
5277
|
-
|
|
5278
|
-
|
|
5279
|
-
|
|
5280
|
-
const automation = routingAutomationMetadata(task);
|
|
5281
|
-
if (automation) {
|
|
5282
|
-
metadata.automation = automation;
|
|
5327
|
+
const pointers = workflowPointersFromMetadata(task.metadata);
|
|
5328
|
+
for (const [key, value] of Object.entries(pointers)) {
|
|
5329
|
+
if (value)
|
|
5330
|
+
metadata[key] = value;
|
|
5283
5331
|
}
|
|
5284
5332
|
try {
|
|
5285
5333
|
const project = task.project_id ? getProject(task.project_id) : null;
|
|
@@ -5308,18 +5356,20 @@ function taskEventMetadata(task) {
|
|
|
5308
5356
|
metadata.task_list_project_id = taskList.project_id;
|
|
5309
5357
|
metadata.task_list_is_project_default = Boolean(project?.task_list_id && taskList.slug === project.task_list_id);
|
|
5310
5358
|
}
|
|
5359
|
+
const routeEnabled = routeEnabledForTask(task, taskList);
|
|
5360
|
+
if (routeEnabled !== undefined) {
|
|
5361
|
+
metadata.route_enabled = routeEnabled;
|
|
5362
|
+
}
|
|
5363
|
+
const automation = routingAutomationMetadata(task, taskList);
|
|
5364
|
+
if (automation) {
|
|
5365
|
+
metadata.automation = automation;
|
|
5366
|
+
metadata.route_blocked_by_no_auto = automation.no_auto === true;
|
|
5367
|
+
metadata.route_blocked_by_manual = automation.manual === true || automation.manual_required === true;
|
|
5368
|
+
metadata.route_blocked_by_approval = (automation.requires_approval === true || automation.approval_required === true) && !task.approved_by;
|
|
5369
|
+
}
|
|
5311
5370
|
} catch {}
|
|
5312
5371
|
return metadata;
|
|
5313
5372
|
}
|
|
5314
|
-
function classifyProjectKind(path) {
|
|
5315
|
-
return path.includes("/hasna/opensource/") ? "open-source" : "unknown";
|
|
5316
|
-
}
|
|
5317
|
-
function isWorktreePath(path) {
|
|
5318
|
-
return path.includes("/.codewith/worktrees/") || path.includes("/.worktrees/");
|
|
5319
|
-
}
|
|
5320
|
-
function inferRootProjectId(project) {
|
|
5321
|
-
return isWorktreePath(project.path) ? null : project.id;
|
|
5322
|
-
}
|
|
5323
5373
|
function readMachineLocalPath(project) {
|
|
5324
5374
|
const machineId = process.env["TODOS_MACHINE_ID"];
|
|
5325
5375
|
if (!machineId)
|