aitasks 1.3.3 → 1.3.4

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.
Files changed (3) hide show
  1. package/README.md +2 -1
  2. package/dist/index.js +33 -23
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -140,7 +140,8 @@ aitasks create \
140
140
  --ac "Returns 200" \ # Acceptance criterion (repeatable, at least one required)
141
141
  --priority high \ # critical | high | medium | low
142
142
  --type feature \ # feature | bug | chore | spike
143
- --parent TASK-001 # Parent task ID (optional)
143
+ --parent TASK-001 \ # Parent task ID (optional)
144
+ --agent $AITASKS_AGENT_ID # Agent creating the task (logged in event history)
144
145
  ```
145
146
 
146
147
  ---
package/dist/index.js CHANGED
@@ -1890,7 +1890,7 @@ var require_commander = __commonJS((exports) => {
1890
1890
  var require_package = __commonJS((exports, module) => {
1891
1891
  module.exports = {
1892
1892
  name: "aitasks",
1893
- version: "1.3.3",
1893
+ version: "1.3.4",
1894
1894
  description: "CLI task management tool built for AI agents",
1895
1895
  type: "module",
1896
1896
  bin: {
@@ -29071,7 +29071,7 @@ import { join as join3 } from "path";
29071
29071
  import { existsSync as existsSync3 } from "fs";
29072
29072
 
29073
29073
  // src/db/schema.ts
29074
- var SCHEMA_VERSION = 2;
29074
+ var SCHEMA_VERSION = 3;
29075
29075
  function runMigrations(db) {
29076
29076
  const row = db.query(`SELECT value FROM meta WHERE key = 'schema_version'`).get();
29077
29077
  const current = row ? parseInt(row.value, 10) : 1;
@@ -29080,6 +29080,11 @@ function runMigrations(db) {
29080
29080
  db.exec(`INSERT OR IGNORE INTO meta (key, value) VALUES ('review_required', 'false')`);
29081
29081
  db.exec(`UPDATE meta SET value = '2' WHERE key = 'schema_version'`);
29082
29082
  }
29083
+ if (current < 3) {
29084
+ db.exec(`ALTER TABLE agents ADD COLUMN first_seen INTEGER`);
29085
+ db.exec(`UPDATE agents SET first_seen = last_seen WHERE first_seen IS NULL`);
29086
+ db.exec(`UPDATE meta SET value = '3' WHERE key = 'schema_version'`);
29087
+ }
29083
29088
  }
29084
29089
  function initializeSchema(db) {
29085
29090
  db.exec(`
@@ -29111,6 +29116,7 @@ function initializeSchema(db) {
29111
29116
 
29112
29117
  CREATE TABLE IF NOT EXISTS agents (
29113
29118
  id TEXT PRIMARY KEY,
29119
+ first_seen INTEGER NOT NULL,
29114
29120
  last_seen INTEGER NOT NULL,
29115
29121
  current_task TEXT REFERENCES tasks(id) ON DELETE SET NULL
29116
29122
  );
@@ -29383,7 +29389,7 @@ Always note:
29383
29389
 
29384
29390
  Creating subtasks:
29385
29391
  \`\`\`bash
29386
- aitasks create --title "Write unit tests for auth" --desc "Add unit tests covering all auth edge cases" --ac "All tests pass" --ac "Coverage \u2265 90%" --parent TASK-001 --priority high --type chore
29392
+ aitasks create --title "Write unit tests for auth" --desc "Add unit tests covering all auth edge cases" --ac "All tests pass" --ac "Coverage \u2265 90%" --parent TASK-001 --priority high --type chore --agent $AITASKS_AGENT_ID
29387
29393
  \`\`\`
29388
29394
 
29389
29395
  If you discover your task is blocked by something:
@@ -29483,7 +29489,7 @@ aitasks unclaim TASK-001 --agent $AITASKS_AGENT_ID --reason "Blocked on missing
29483
29489
  5. Add implementation notes continuously, not just at the end.
29484
29490
  6. If a task needs splitting, create subtasks BEFORE marking parent done.
29485
29491
  7. Your evidence strings must be concrete and verifiable \u2014 not vague affirmations.
29486
- 8. Always provide --desc and at least one --ac when creating a task. Both are required.${reviewRequired ? `
29492
+ 8. Always provide --desc, at least one --ac, and --agent when creating a task. All three are required.${reviewRequired ? `
29487
29493
  9. NEVER move a task to done directly. Always submit for review first with \`aitasks review\`, then IMMEDIATELY spawn a review sub-agent with a DIFFERENT agent ID. Do NOT call \`aitasks done\` yourself after submitting for review \u2014 the system blocks self-approval.` : ""}
29488
29494
 
29489
29495
  ---
@@ -29496,7 +29502,7 @@ aitasks list [--status <s>] [--json] List tasks
29496
29502
  aitasks show <id> Full task detail (includes time tracking)
29497
29503
  aitasks search <query> Search titles, descriptions, notes
29498
29504
  aitasks deps <id> Show dependency tree
29499
- aitasks create --title <t> --desc <d> --ac <c> [--ac <c> ...] Create a task
29505
+ aitasks create --title <t> --desc <d> --ac <c> [--ac <c> ...] --agent <id> Create a task
29500
29506
  aitasks claim <id...> --agent <id> Claim task(s) - supports patterns like TASK-0*
29501
29507
  aitasks start <id...> --agent <id> Begin work on task(s)
29502
29508
  aitasks note <id> <text> --agent <id> Add implementation note
@@ -30323,7 +30329,7 @@ function createTask(data) {
30323
30329
  now,
30324
30330
  JSON.stringify(data.metadata ?? {})
30325
30331
  ]);
30326
- logEvent({ task_id: id, event_type: "created", payload: { title: data.title } });
30332
+ logEvent({ task_id: id, agent_id: data.created_by, event_type: "created", payload: { title: data.title } });
30327
30333
  return getTask(id);
30328
30334
  }
30329
30335
  var JSON_FIELDS = new Set([
@@ -30409,9 +30415,9 @@ function claimTask(taskId, agentId) {
30409
30415
  error: `Task is blocked by: ${task.blocked_by.join(", ")}. Complete those first.`
30410
30416
  };
30411
30417
  }
30412
- db.run(`INSERT INTO agents (id, last_seen, current_task)
30413
- VALUES (?, ?, ?)
30414
- ON CONFLICT(id) DO UPDATE SET last_seen = excluded.last_seen, current_task = excluded.current_task`, [agentId, Date.now(), taskId]);
30418
+ db.run(`INSERT INTO agents (id, first_seen, last_seen, current_task)
30419
+ VALUES (?, ?, ?, ?)
30420
+ ON CONFLICT(id) DO UPDATE SET last_seen = excluded.last_seen, current_task = excluded.current_task`, [agentId, Date.now(), Date.now(), taskId]);
30415
30421
  const updated = updateTask(taskId, { assigned_to: agentId, status: "ready" });
30416
30422
  logEvent({ task_id: taskId, agent_id: agentId, event_type: "claimed", payload: {} });
30417
30423
  return { task: updated };
@@ -30427,9 +30433,9 @@ function startTask(taskId, agentId) {
30427
30433
  }
30428
30434
  const db = getDb();
30429
30435
  if (!task.assigned_to) {
30430
- db.run(`INSERT INTO agents (id, last_seen, current_task)
30431
- VALUES (?, ?, ?)
30432
- ON CONFLICT(id) DO UPDATE SET last_seen = excluded.last_seen, current_task = excluded.current_task`, [agentId, Date.now(), taskId]);
30436
+ db.run(`INSERT INTO agents (id, first_seen, last_seen, current_task)
30437
+ VALUES (?, ?, ?, ?)
30438
+ ON CONFLICT(id) DO UPDATE SET last_seen = excluded.last_seen, current_task = excluded.current_task`, [agentId, Date.now(), Date.now(), taskId]);
30433
30439
  }
30434
30440
  const updated = updateTask(taskId, {
30435
30441
  assigned_to: agentId,
@@ -30481,13 +30487,15 @@ function completeTask(taskId, agentId) {
30481
30487
  ` + ` A separate review sub-agent must run: aitasks done ${taskId} --agent <review-agent-id>`
30482
30488
  };
30483
30489
  }
30484
- const knownAgent = db.query(`SELECT id FROM agents WHERE id = ?`).get(agentId);
30485
- if (!knownAgent) {
30490
+ const reviewerRow = db.query(`SELECT first_seen FROM agents WHERE id = ?`).get(agentId);
30491
+ const reviewSubmittedAt = reviewEvent?.created_at ?? 0;
30492
+ if (!reviewerRow || reviewerRow.first_seen > reviewSubmittedAt) {
30486
30493
  return {
30487
30494
  task: null,
30488
- error: `Unknown review agent: '${agentId}' has not registered with the system.
30489
- ` + ` A real review sub-agent must register first by running any aitasks command
30490
- ` + ` (e.g. aitasks heartbeat --agent ${agentId}) before it can approve a review.`
30495
+ error: `Review agent '${agentId}' was not active before this review was submitted.
30496
+ ` + ` A real review sub-agent must be independently spawned \u2014 it cannot be registered
30497
+ ` + ` moments before approving. The reviewer must have prior activity in the system
30498
+ ` + ` before the review was submitted.`
30491
30499
  };
30492
30500
  }
30493
30501
  }
@@ -30621,9 +30629,9 @@ function unclaimTask(taskId, agentId, reason) {
30621
30629
  }
30622
30630
  function heartbeat(agentId, taskId) {
30623
30631
  const db = getDb();
30624
- db.run(`INSERT INTO agents (id, last_seen, current_task)
30625
- VALUES (?, ?, ?)
30626
- ON CONFLICT(id) DO UPDATE SET last_seen = excluded.last_seen`, [agentId, Date.now(), taskId ?? null]);
30632
+ db.run(`INSERT INTO agents (id, first_seen, last_seen, current_task)
30633
+ VALUES (?, ?, ?, ?)
30634
+ ON CONFLICT(id) DO UPDATE SET last_seen = excluded.last_seen`, [agentId, Date.now(), Date.now(), taskId ?? null]);
30627
30635
  }
30628
30636
  function listAgents() {
30629
30637
  const db = getDb();
@@ -30721,7 +30729,7 @@ function exitError(msg, json) {
30721
30729
  }
30722
30730
 
30723
30731
  // src/commands/create.ts
30724
- var createCommand2 = new Command("create").description("Create a new task").option("-t, --title <title>", "Task title").option("-d, --desc <description>", "Task description").option("-a, --ac <criterion>", "Acceptance criterion (repeatable)", collect, []).option("-p, --priority <priority>", "Priority: critical|high|medium|low", "medium").option("--type <type>", "Type: feature|bug|chore|spike", "feature").option("--parent <taskId>", "Parent task ID for subtasks").option("--json", "Output as JSON").action(async (opts) => {
30732
+ var createCommand2 = new Command("create").description("Create a new task").option("-t, --title <title>", "Task title").option("-d, --desc <description>", "Task description").option("-a, --ac <criterion>", "Acceptance criterion (repeatable)", collect, []).option("-p, --priority <priority>", "Priority: critical|high|medium|low", "medium").option("--type <type>", "Type: feature|bug|chore|spike", "feature").option("--parent <taskId>", "Parent task ID for subtasks").option("--agent <agentId>", "Agent ID creating this task (or set AITASKS_AGENT_ID)").option("--json", "Output as JSON").action(async (opts) => {
30725
30733
  requireInitialized();
30726
30734
  const json = isJsonMode(opts.json);
30727
30735
  if (opts.title) {
@@ -30746,13 +30754,15 @@ var createCommand2 = new Command("create").description("Create a new task").opti
30746
30754
  process.exit(1);
30747
30755
  }
30748
30756
  }
30757
+ const aid = agentId(opts.agent) ?? undefined;
30749
30758
  const task2 = createTask({
30750
30759
  title: opts.title,
30751
30760
  description: opts.desc ?? "",
30752
30761
  acceptance_criteria: opts.ac,
30753
30762
  priority: opts.priority,
30754
30763
  type: opts.type,
30755
- parent_id: opts.parent
30764
+ parent_id: opts.parent,
30765
+ created_by: aid
30756
30766
  });
30757
30767
  if (json)
30758
30768
  return jsonOut(true, task2);
@@ -43318,4 +43328,4 @@ program2.parseAsync(process.argv).catch((err) => {
43318
43328
  process.exit(1);
43319
43329
  });
43320
43330
 
43321
- //# debugId=62CCA2B3357C2C9A64756E2164756E21
43331
+ //# debugId=6CE8123AAE8C303564756E2164756E21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aitasks",
3
- "version": "1.3.3",
3
+ "version": "1.3.4",
4
4
  "description": "CLI task management tool built for AI agents",
5
5
  "type": "module",
6
6
  "bin": {