@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/contracts.js CHANGED
@@ -2331,6 +2331,7 @@ function ensureSchema(db) {
2331
2331
  ensureColumn("tasks", "reason", "TEXT");
2332
2332
  ensureColumn("tasks", "spawned_from_session", "TEXT");
2333
2333
  ensureColumn("tasks", "assigned_by", "TEXT");
2334
+ ensureColumn("tasks", "created_by", "TEXT");
2334
2335
  ensureColumn("tasks", "assigned_from_project", "TEXT");
2335
2336
  ensureColumn("tasks", "started_at", "TEXT");
2336
2337
  ensureColumn("tasks", "task_type", "TEXT");
@@ -2493,6 +2494,8 @@ function ensureSchema(db) {
2493
2494
  ensureIndex("CREATE INDEX IF NOT EXISTS idx_project_sources_project ON project_sources(project_id)");
2494
2495
  ensureIndex("CREATE INDEX IF NOT EXISTS idx_project_sources_type ON project_sources(type)");
2495
2496
  ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_assigned_by ON tasks(assigned_by)");
2497
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_created_by ON tasks(created_by)");
2498
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_assigned_created ON tasks(assigned_to, created_by)");
2496
2499
  ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_rel_source ON task_relationships(source_task_id)");
2497
2500
  ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_rel_target ON task_relationships(target_task_id)");
2498
2501
  ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_rel_type ON task_relationships(relationship_type)");
@@ -8792,13 +8795,14 @@ function createTask(input, db) {
8792
8795
  const timestamp2 = now();
8793
8796
  const tags = input.tags || [];
8794
8797
  const machineId = currentStorageMachineId(d);
8798
+ const createdBy = input.created_by || input.agent_id || null;
8795
8799
  const assignedBy = input.assigned_by || input.agent_id;
8796
8800
  const assignedFromProject = input.assigned_from_project || null;
8797
8801
  let id = uuid();
8798
8802
  for (let attempt = 0;attempt < 3; attempt++) {
8799
8803
  try {
8800
- 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)
8801
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
8804
+ 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)
8805
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
8802
8806
  id,
8803
8807
  null,
8804
8808
  input.project_id || null,
@@ -8834,6 +8838,7 @@ function createTask(input, db) {
8834
8838
  input.reason || null,
8835
8839
  input.spawned_from_session || null,
8836
8840
  assignedBy || null,
8841
+ createdBy,
8837
8842
  assignedFromProject || null,
8838
8843
  input.task_type || null,
8839
8844
  machineId
@@ -8943,6 +8948,14 @@ function listTasks(filter = {}, db) {
8943
8948
  conditions.push("agent_id = ?");
8944
8949
  params.push(filter.agent_id);
8945
8950
  }
8951
+ if (filter.created_by) {
8952
+ conditions.push("LOWER(created_by) = LOWER(?)");
8953
+ params.push(filter.created_by);
8954
+ }
8955
+ if (filter.not_created_by) {
8956
+ conditions.push("(created_by IS NULL OR LOWER(created_by) != LOWER(?))");
8957
+ params.push(filter.not_created_by);
8958
+ }
8946
8959
  if (filter.session_id) {
8947
8960
  conditions.push("session_id = ?");
8948
8961
  params.push(filter.session_id);
@@ -9096,6 +9109,14 @@ function countTasks(filter = {}, db) {
9096
9109
  conditions.push("agent_id = ?");
9097
9110
  params.push(filter.agent_id);
9098
9111
  }
9112
+ if (filter.created_by) {
9113
+ conditions.push("LOWER(created_by) = LOWER(?)");
9114
+ params.push(filter.created_by);
9115
+ }
9116
+ if (filter.not_created_by) {
9117
+ conditions.push("(created_by IS NULL OR LOWER(created_by) != LOWER(?))");
9118
+ params.push(filter.not_created_by);
9119
+ }
9099
9120
  if (filter.session_id) {
9100
9121
  conditions.push("session_id = ?");
9101
9122
  params.push(filter.session_id);
@@ -9156,6 +9177,10 @@ function updateTask(id, input, db) {
9156
9177
  sets.push("description = ?");
9157
9178
  params.push(input.description);
9158
9179
  }
9180
+ if (input.agent_id !== undefined) {
9181
+ sets.push("agent_id = ?");
9182
+ params.push(input.agent_id);
9183
+ }
9159
9184
  if (input.status !== undefined) {
9160
9185
  if (input.status === "completed") {
9161
9186
  checkCompletionGuard(task, task.assigned_to || task.agent_id || null, d);
@@ -11900,7 +11925,7 @@ var init_tasks = __esm(() => {
11900
11925
  // package.json
11901
11926
  var package_default = {
11902
11927
  name: "@hasna/todos",
11903
- version: "0.13.5",
11928
+ version: "0.13.7",
11904
11929
  description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
11905
11930
  type: "module",
11906
11931
  main: "dist/index.js",
@@ -15332,6 +15357,7 @@ function task(input) {
15332
15357
  reason: "Bundled deterministic onboarding fixture",
15333
15358
  spawned_from_session: null,
15334
15359
  assigned_by: null,
15360
+ created_by: null,
15335
15361
  assigned_from_project: null,
15336
15362
  task_type: "onboarding",
15337
15363
  cost_tokens: 0,
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/db/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGtC,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAoChD;AA8BD,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAy+C/C;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CA4BnD"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/db/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGtC,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAoChD;AA8BD,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAi/C/C;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CA4BnD"}
@@ -1 +1 @@
1
- {"version":3,"file":"task-crud.d.ts","sourceRoot":"","sources":["../../src/db/task-crud.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAoB,MAAM,YAAY,CAAC;AAC7D,OAAO,KAAK,EACV,eAAe,EACf,IAAI,EACJ,UAAU,EACV,OAAO,EACP,iBAAiB,EACjB,eAAe,EACf,4BAA4B,EAC5B,6BAA6B,EAC9B,MAAM,mBAAmB,CAAC;AAkB3B,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAS5C;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,GAAG,IAAI,CAMjF;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,GAAG,IAAI,CAGlF;AAwCD,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,IAAI,CAkFtE;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,IAAI,CAK9D;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,MAAM,EACV,EAAE,CAAC,EAAE,QAAQ,GACZ,iBAAiB,GAAG,IAAI,CA4D1B;AAED,wBAAgB,SAAS,CAAC,MAAM,GAAE,UAAe,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,IAAI,EAAE,CAwIxE;AAED,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EACnB,EAAE,CAAC,EAAE,QAAQ,GACZ,IAAI,GAAG,IAAI,CAKb;AAcD,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,4BAA4B,EACnC,EAAE,CAAC,EAAE,QAAQ,GACZ,6BAA6B,CAmD/B;AAED,wBAAgB,UAAU,CAAC,MAAM,GAAE,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,QAAQ,CAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,MAAM,CAwGnG;AAED,wBAAgB,UAAU,CACxB,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,eAAe,EACtB,EAAE,CAAC,EAAE,QAAQ,GACZ,IAAI,CA2ON;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAY7D"}
1
+ {"version":3,"file":"task-crud.d.ts","sourceRoot":"","sources":["../../src/db/task-crud.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAoB,MAAM,YAAY,CAAC;AAC7D,OAAO,KAAK,EACV,eAAe,EACf,IAAI,EACJ,UAAU,EACV,OAAO,EACP,iBAAiB,EACjB,eAAe,EACf,4BAA4B,EAC5B,6BAA6B,EAC9B,MAAM,mBAAmB,CAAC;AAkB3B,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAS5C;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,GAAG,IAAI,CAMjF;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,GAAG,IAAI,CAGlF;AAwCD,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,IAAI,CAwFtE;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,IAAI,CAK9D;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,MAAM,EACV,EAAE,CAAC,EAAE,QAAQ,GACZ,iBAAiB,GAAG,IAAI,CA4D1B;AAED,wBAAgB,SAAS,CAAC,MAAM,GAAE,UAAe,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,IAAI,EAAE,CA2JxE;AAED,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EACnB,EAAE,CAAC,EAAE,QAAQ,GACZ,IAAI,GAAG,IAAI,CAKb;AAcD,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,4BAA4B,EACnC,EAAE,CAAC,EAAE,QAAQ,GACZ,6BAA6B,CAmD/B;AAED,wBAAgB,UAAU,CAAC,MAAM,GAAE,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,QAAQ,CAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,MAAM,CA2HnG;AAED,wBAAgB,UAAU,CACxB,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,eAAe,EACtB,EAAE,CAAC,EAAE,QAAQ,GACZ,IAAI,CAkPN;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAY7D"}
package/dist/index.js CHANGED
@@ -2331,6 +2331,7 @@ function ensureSchema(db) {
2331
2331
  ensureColumn("tasks", "reason", "TEXT");
2332
2332
  ensureColumn("tasks", "spawned_from_session", "TEXT");
2333
2333
  ensureColumn("tasks", "assigned_by", "TEXT");
2334
+ ensureColumn("tasks", "created_by", "TEXT");
2334
2335
  ensureColumn("tasks", "assigned_from_project", "TEXT");
2335
2336
  ensureColumn("tasks", "started_at", "TEXT");
2336
2337
  ensureColumn("tasks", "task_type", "TEXT");
@@ -2493,6 +2494,8 @@ function ensureSchema(db) {
2493
2494
  ensureIndex("CREATE INDEX IF NOT EXISTS idx_project_sources_project ON project_sources(project_id)");
2494
2495
  ensureIndex("CREATE INDEX IF NOT EXISTS idx_project_sources_type ON project_sources(type)");
2495
2496
  ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_assigned_by ON tasks(assigned_by)");
2497
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_created_by ON tasks(created_by)");
2498
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_assigned_created ON tasks(assigned_to, created_by)");
2496
2499
  ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_rel_source ON task_relationships(source_task_id)");
2497
2500
  ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_rel_target ON task_relationships(target_task_id)");
2498
2501
  ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_rel_type ON task_relationships(relationship_type)");
@@ -8792,13 +8795,14 @@ function createTask(input, db) {
8792
8795
  const timestamp2 = now();
8793
8796
  const tags = input.tags || [];
8794
8797
  const machineId = currentStorageMachineId(d);
8798
+ const createdBy = input.created_by || input.agent_id || null;
8795
8799
  const assignedBy = input.assigned_by || input.agent_id;
8796
8800
  const assignedFromProject = input.assigned_from_project || null;
8797
8801
  let id = uuid();
8798
8802
  for (let attempt = 0;attempt < 3; attempt++) {
8799
8803
  try {
8800
- 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)
8801
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
8804
+ 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)
8805
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
8802
8806
  id,
8803
8807
  null,
8804
8808
  input.project_id || null,
@@ -8834,6 +8838,7 @@ function createTask(input, db) {
8834
8838
  input.reason || null,
8835
8839
  input.spawned_from_session || null,
8836
8840
  assignedBy || null,
8841
+ createdBy,
8837
8842
  assignedFromProject || null,
8838
8843
  input.task_type || null,
8839
8844
  machineId
@@ -8943,6 +8948,14 @@ function listTasks(filter = {}, db) {
8943
8948
  conditions.push("agent_id = ?");
8944
8949
  params.push(filter.agent_id);
8945
8950
  }
8951
+ if (filter.created_by) {
8952
+ conditions.push("LOWER(created_by) = LOWER(?)");
8953
+ params.push(filter.created_by);
8954
+ }
8955
+ if (filter.not_created_by) {
8956
+ conditions.push("(created_by IS NULL OR LOWER(created_by) != LOWER(?))");
8957
+ params.push(filter.not_created_by);
8958
+ }
8946
8959
  if (filter.session_id) {
8947
8960
  conditions.push("session_id = ?");
8948
8961
  params.push(filter.session_id);
@@ -9096,6 +9109,14 @@ function countTasks(filter = {}, db) {
9096
9109
  conditions.push("agent_id = ?");
9097
9110
  params.push(filter.agent_id);
9098
9111
  }
9112
+ if (filter.created_by) {
9113
+ conditions.push("LOWER(created_by) = LOWER(?)");
9114
+ params.push(filter.created_by);
9115
+ }
9116
+ if (filter.not_created_by) {
9117
+ conditions.push("(created_by IS NULL OR LOWER(created_by) != LOWER(?))");
9118
+ params.push(filter.not_created_by);
9119
+ }
9099
9120
  if (filter.session_id) {
9100
9121
  conditions.push("session_id = ?");
9101
9122
  params.push(filter.session_id);
@@ -9156,6 +9177,10 @@ function updateTask(id, input, db) {
9156
9177
  sets.push("description = ?");
9157
9178
  params.push(input.description);
9158
9179
  }
9180
+ if (input.agent_id !== undefined) {
9181
+ sets.push("agent_id = ?");
9182
+ params.push(input.agent_id);
9183
+ }
9159
9184
  if (input.status !== undefined) {
9160
9185
  if (input.status === "completed") {
9161
9186
  checkCompletionGuard(task, task.assigned_to || task.agent_id || null, d);
@@ -12013,7 +12038,7 @@ var init_dispatches = __esm(() => {
12013
12038
  // package.json
12014
12039
  var package_default = {
12015
12040
  name: "@hasna/todos",
12016
- version: "0.13.5",
12041
+ version: "0.13.7",
12017
12042
  description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
12018
12043
  type: "module",
12019
12044
  main: "dist/index.js",
@@ -15445,6 +15470,7 @@ function task(input) {
15445
15470
  reason: "Bundled deterministic onboarding fixture",
15446
15471
  spawned_from_session: null,
15447
15472
  assigned_by: null,
15473
+ created_by: null,
15448
15474
  assigned_from_project: null,
15449
15475
  task_type: "onboarding",
15450
15476
  cost_tokens: 0,
@@ -25274,7 +25300,11 @@ function createLocalSqliteTodosStorageAdapter(options = {}) {
25274
25300
  sync: true
25275
25301
  },
25276
25302
  tasks: {
25277
- create: (input) => createTask(input, database()),
25303
+ create: (input, context) => createTask({
25304
+ ...input,
25305
+ agent_id: input.agent_id ?? context?.agentId,
25306
+ created_by: input.created_by ?? input.agent_id ?? context?.agentId
25307
+ }, database()),
25278
25308
  get: (id) => getTask(id, database()),
25279
25309
  resolveRef: (ref) => resolveTaskRefLocal(database(), ref),
25280
25310
  list: (filter = {}) => listTasksMaybeSearch(filter, database()),
@@ -25997,6 +26027,10 @@ class PostgresJsonRecordStore {
25997
26027
  conds.push(`payload->>'assigned_to' = ${p(filter.assigned_to)}`);
25998
26028
  if (filter.agent_id !== undefined)
25999
26029
  conds.push(`payload->>'agent_id' = ${p(filter.agent_id)}`);
26030
+ if (filter.created_by !== undefined)
26031
+ conds.push(`LOWER(payload->>'created_by') = LOWER(${p(filter.created_by)})`);
26032
+ if (filter.not_created_by !== undefined)
26033
+ conds.push(`(payload->>'created_by' IS NULL OR LOWER(payload->>'created_by') <> LOWER(${p(filter.not_created_by)}))`);
26000
26034
  if (filter.session_id !== undefined)
26001
26035
  conds.push(`payload->>'session_id' = ${p(filter.session_id)}`);
26002
26036
  if (filter.tags?.length) {
@@ -26510,7 +26544,7 @@ async function createTask2(input, store, context) {
26510
26544
  description: input.description ?? null,
26511
26545
  status: input.status ?? "pending",
26512
26546
  priority: input.priority ?? "medium",
26513
- agent_id: input.agent_id ?? null,
26547
+ agent_id: input.agent_id ?? context?.agentId ?? null,
26514
26548
  assigned_to: input.assigned_to ?? null,
26515
26549
  session_id: input.session_id ?? context?.sessionId ?? null,
26516
26550
  working_dir: input.working_dir ?? null,
@@ -26535,7 +26569,8 @@ async function createTask2(input, store, context) {
26535
26569
  confidence: input.confidence ?? null,
26536
26570
  reason: input.reason ?? null,
26537
26571
  spawned_from_session: input.spawned_from_session ?? null,
26538
- assigned_by: input.assigned_by ?? null,
26572
+ assigned_by: input.assigned_by ?? input.agent_id ?? context?.agentId ?? null,
26573
+ created_by: input.created_by ?? input.agent_id ?? context?.agentId ?? null,
26539
26574
  assigned_from_project: input.assigned_from_project ?? null,
26540
26575
  task_type: input.task_type ?? null,
26541
26576
  cost_tokens: 0,
@@ -26572,7 +26607,8 @@ async function updateTask2(id, input, store) {
26572
26607
  tags: input.tags ?? existing.tags,
26573
26608
  metadata: input.metadata ?? existing.metadata,
26574
26609
  requires_approval: input.requires_approval ?? existing.requires_approval,
26575
- task_list_id: input.task_list_id !== undefined ? input.task_list_id : existing.task_list_id
26610
+ task_list_id: input.task_list_id !== undefined ? input.task_list_id : existing.task_list_id,
26611
+ created_by: existing.created_by
26576
26612
  };
26577
26613
  await store.upsert("tasks", task2);
26578
26614
  return task2;
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Ambient creator identity.
3
+ *
4
+ * The defect this closes: `todos init <name>` registered an agent and printed
5
+ * "Use --agent <id> on future commands", but persisted that identity NOWHERE.
6
+ * Every later command therefore had to re-supply `--agent` by hand, and in
7
+ * practice nothing did — so `todos add` recorded who a task was FOR
8
+ * (`assigned_to`) and never who FILED it. Measured on project 931835c7:
9
+ * agent_id populated on 35/436 tasks, assigned_by on 0/436.
10
+ *
11
+ * Resolution order, most explicit first:
12
+ * 1. an explicit value (the `--agent` flag)
13
+ * 2. TODOS_AGENT_ID
14
+ * 3. HASNA_TODOS_AGENT_ID
15
+ * 4. the identity persisted by `todos init`
16
+ *
17
+ * Returns null when no identity can be established. Callers must treat null as
18
+ * "unattributable" and say so — never as "attributable to nobody in particular".
19
+ */
20
+ export interface PersistedIdentity {
21
+ agent_id: string;
22
+ agent_name?: string;
23
+ session_id?: string;
24
+ registered_at: string;
25
+ }
26
+ export type CreatorIdentitySource = "explicit" | "env" | "persisted" | "none";
27
+ export interface ResolvedCreatorIdentity {
28
+ agent_id: string | null;
29
+ source: CreatorIdentitySource;
30
+ }
31
+ export declare function identityFilePath(): string;
32
+ export declare function readPersistedIdentity(): PersistedIdentity | null;
33
+ export interface IdentityCollision {
34
+ /** The identity already on disk that a new `init` would have overwritten. */
35
+ existing: PersistedIdentity;
36
+ }
37
+ /**
38
+ * The file is keyed on $HOME, and this fleet runs many named agent sessions per
39
+ * station under one HOME. Two sessions each running `todos init` would silently
40
+ * leave the loser attributing its tasks to the winner — and a WRONG author is
41
+ * worse than a missing one, because a null is visibly absent while a name is
42
+ * simply believed. So a second, different identity is refused rather than
43
+ * clobbered; the per-session escape hatch is the TODOS_AGENT_ID environment
44
+ * variable, which outranks this file and cannot collide between processes.
45
+ */
46
+ export declare function detectIdentityCollision(agentId: string, agentName?: string): IdentityCollision | null;
47
+ /** Persist the identity established by `todos init` so later commands inherit it. */
48
+ export declare function persistIdentity(identity: {
49
+ agent_id: string;
50
+ agent_name?: string;
51
+ session_id?: string;
52
+ }): PersistedIdentity;
53
+ /** Drop the persisted identity — used by `todos release` so the seat does not leak into the next session. */
54
+ export declare function clearPersistedIdentity(): boolean;
55
+ /**
56
+ * Canonicalise exactly as `registerAgent` does (src/db/agents.ts: trim + lower-case).
57
+ *
58
+ * Without this the three sources disagree about the SAME agent: the persisted file
59
+ * returns the registered name, which is already lower-cased, while the flag and the
60
+ * environment variable were taken verbatim. An agent that registered with `todos init`
61
+ * in one session and `TODOS_AGENT_ID=Cassius` in another — both sanctioned, and the
62
+ * env var is the very escape hatch this module recommends for concurrent sessions —
63
+ * would file some tasks as "cassius" and others as "Cassius". The comparison is a SQL
64
+ * string inequality, so `not_created_by` would fail to exclude half of the agent's own
65
+ * filings and leak them back into its own inbox: exactly the self-noise the filter
66
+ * exists to remove.
67
+ */
68
+ export declare function canonicalAgentRef(value: string): string;
69
+ /**
70
+ * Is this identity bound to THIS PROCESS, or merely lying around on the disk?
71
+ *
72
+ * `explicit` (--agent) and `env` (TODOS_AGENT_ID) travel with the process, so two
73
+ * concurrent sessions cannot be handed the same one by accident. `persisted` is a
74
+ * single file keyed on $HOME, and this fleet runs many named agent sessions per
75
+ * station under one HOME — so it identifies the STATION, never the caller.
76
+ *
77
+ * The write side was already guarded: `todos init` refuses to clobber a foreign
78
+ * identity (detectIdentityCollision). Nothing guarded the read side, and that is
79
+ * the whole defect — refusing to record session B's identity silently converted
80
+ * into attributing B's work to A. Measured on station01 2026-07-31: one agent ran
81
+ * `todos init` at 17:31:04Z and every unregistered session on the box filed as it
82
+ * from 17:37:36Z onward.
83
+ *
84
+ * So an ambient identity may be DISPLAYED, but it must never be written into a
85
+ * task. A wrong name is worse than a missing one — this module's own doctrine —
86
+ * and it is worse here in the direction that costs most: `assigned_to` is the
87
+ * queue every seat reads, and `agent_id` is a filterable column
88
+ * (task-crud.ts `filter.agent_id`) that also stands in as the acting agent
89
+ * wherever `assigned_to` is null (`task.assigned_to || task.agent_id`).
90
+ */
91
+ export declare function isProcessBoundSource(source: CreatorIdentitySource): boolean;
92
+ /**
93
+ * The identity this process may WRITE onto a task, or null when it has none.
94
+ *
95
+ * Deliberately narrower than `resolveCreatorIdentity`, which still reports the
96
+ * ambient identity so that `todos init`/diagnostics can show what is on disk.
97
+ */
98
+ export declare function resolveWritableIdentity(explicit?: string | null): ResolvedCreatorIdentity;
99
+ export declare function resolveCreatorIdentity(explicit?: string | null): ResolvedCreatorIdentity;
100
+ //# sourceMappingURL=creator-identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"creator-identity.d.ts","sourceRoot":"","sources":["../../src/lib/creator-identity.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,MAAM,qBAAqB,GAAG,UAAU,GAAG,KAAK,GAAG,WAAW,GAAG,MAAM,CAAC;AAE9E,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,qBAAqB,CAAC;CAC/B;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,wBAAgB,qBAAqB,IAAI,iBAAiB,GAAG,IAAI,CAMhE;AAED,MAAM,WAAW,iBAAiB;IAChC,6EAA6E;IAC7E,QAAQ,EAAE,iBAAiB,CAAC;CAC7B;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAOrG;AAED,qFAAqF;AACrF,wBAAgB,eAAe,CAAC,QAAQ,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,iBAAiB,CAU3H;AAED,6GAA6G;AAC7G,wBAAgB,sBAAsB,IAAI,OAAO,CAShD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAE3E;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,uBAAuB,CAIzF;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,uBAAuB,CAmBxF"}
@@ -1 +1 @@
1
- {"version":3,"file":"onboarding-fixtures.d.ts","sourceRoot":"","sources":["../../src/lib/onboarding-fixtures.ts"],"names":[],"mappings":"AAGA,OAAO,EAIL,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EAC1B,MAAM,mBAAmB,CAAC;AAE3B,eAAO,MAAM,wCAAwC,eAAe,CAAC;AACrE,eAAO,MAAM,+BAA+B,sCAAsC,CAAC;AAEnF,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,IAAI,CAAC;IACjB,UAAU,EAAE,IAAI,CAAC;IACjB,QAAQ,EAAE,IAAI,CAAC;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC,MAAM,oBAAoB,EAAE,MAAM,CAAC,CAAC;CACnD;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,IAAI,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;IACjD,MAAM,EAAE,sBAAsB,CAAC;CAChC;AAED,MAAM,WAAW,4BAA4B;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,8BAA+B,SAAQ,wBAAwB;IAC9E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAoXD,wBAAgB,sBAAsB,IAAI,wBAAwB,EAAE,CAMnE;AAED,wBAAgB,oBAAoB,CAAC,IAAI,SAAuB,GAAG,iBAAiB,CAUnF;AAED,wBAAgB,0BAA0B,CAAC,IAAI,SAAuB,GAAG,sBAAsB,CAE9F;AAED,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,MAAM,GAAG,4BAA4B,CAS3F;AAED,wBAAgB,uBAAuB,CACrC,OAAO,GAAE,8BAAmC,GAC3C,uBAAuB,CAMzB"}
1
+ {"version":3,"file":"onboarding-fixtures.d.ts","sourceRoot":"","sources":["../../src/lib/onboarding-fixtures.ts"],"names":[],"mappings":"AAGA,OAAO,EAIL,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EAC1B,MAAM,mBAAmB,CAAC;AAE3B,eAAO,MAAM,wCAAwC,eAAe,CAAC;AACrE,eAAO,MAAM,+BAA+B,sCAAsC,CAAC;AAEnF,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,IAAI,CAAC;IACjB,UAAU,EAAE,IAAI,CAAC;IACjB,QAAQ,EAAE,IAAI,CAAC;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC,MAAM,oBAAoB,EAAE,MAAM,CAAC,CAAC;CACnD;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,IAAI,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;IACjD,MAAM,EAAE,sBAAsB,CAAC;CAChC;AAED,MAAM,WAAW,4BAA4B;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,8BAA+B,SAAQ,wBAAwB;IAC9E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAqXD,wBAAgB,sBAAsB,IAAI,wBAAwB,EAAE,CAMnE;AAED,wBAAgB,oBAAoB,CAAC,IAAI,SAAuB,GAAG,iBAAiB,CAUnF;AAED,wBAAgB,0BAA0B,CAAC,IAAI,SAAuB,GAAG,sBAAsB,CAE9F;AAED,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,MAAM,GAAG,4BAA4B,CAS3F;AAED,wBAAgB,uBAAuB,CACrC,OAAO,GAAE,8BAAmC,GAC3C,uBAAuB,CAMzB"}