aitasks 1.3.3 → 1.3.5
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 +2 -1
- package/dist/index.js +73 -37
- 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
|
|
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.
|
|
1893
|
+
version: "1.3.5",
|
|
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 =
|
|
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:
|
|
@@ -29420,12 +29426,13 @@ ${reviewRequired ? `3. Submit for review \u2014 you CANNOT mark done directly:
|
|
|
29420
29426
|
\`\`\`bash
|
|
29421
29427
|
aitasks review TASK-001 --agent $AITASKS_AGENT_ID
|
|
29422
29428
|
\`\`\`
|
|
29423
|
-
**
|
|
29429
|
+
**Do not run \`aitasks done\` yourself.** The system will block self-approval.
|
|
29424
29430
|
|
|
29425
|
-
4. **
|
|
29426
|
-
|
|
29431
|
+
4. **IN THIS SAME SESSION, immediately spawn a review sub-agent** with a DIFFERENT agent ID.
|
|
29432
|
+
Do this NOW \u2014 before writing any summary, before moving to any other task, before anything else.
|
|
29433
|
+
The review sub-agent must register first, then inspect and approve or reject:
|
|
29427
29434
|
\`\`\`bash
|
|
29428
|
-
# Review sub-agent registers itself
|
|
29435
|
+
# Review sub-agent registers itself (BEFORE the review was submitted \u2014 or it will be blocked)
|
|
29429
29436
|
aitasks heartbeat --agent <review-agent-id>
|
|
29430
29437
|
|
|
29431
29438
|
# Approve (moves task to done):
|
|
@@ -29434,12 +29441,15 @@ ${reviewRequired ? `3. Submit for review \u2014 you CANNOT mark done directly:
|
|
|
29434
29441
|
# OR reject (sends task back to in_progress with feedback):
|
|
29435
29442
|
aitasks reject TASK-001 --reason "<specific feedback>" --agent <review-agent-id>
|
|
29436
29443
|
\`\`\`
|
|
29437
|
-
|
|
29438
|
-
|
|
29444
|
+
**Your session is NOT complete after submitting for review. You must remain active and drive the
|
|
29445
|
+
review to completion. The task is still incomplete until \`aitasks done\` succeeds.**
|
|
29446
|
+
The system will block approval from any agent that registered after the review was submitted
|
|
29447
|
+
or that submitted the review itself.
|
|
29439
29448
|
|
|
29440
29449
|
5. If rejected: address the feedback, re-check criteria, and repeat from step 3.
|
|
29441
29450
|
|
|
29442
|
-
> The task is only done when \`aitasks done\` completes successfully. \`review\` status means
|
|
29451
|
+
> The task is only done when \`aitasks done\` completes successfully. \`review\` status means
|
|
29452
|
+
> awaiting approval \u2014 it is NOT done. Do not write a final summary until all tasks are \`done\`.` : `3. Mark done (will FAIL if any criterion is unchecked):
|
|
29443
29453
|
\`\`\`bash
|
|
29444
29454
|
aitasks done TASK-001 --agent $AITASKS_AGENT_ID
|
|
29445
29455
|
\`\`\`
|
|
@@ -29483,10 +29493,29 @@ aitasks unclaim TASK-001 --agent $AITASKS_AGENT_ID --reason "Blocked on missing
|
|
|
29483
29493
|
5. Add implementation notes continuously, not just at the end.
|
|
29484
29494
|
6. If a task needs splitting, create subtasks BEFORE marking parent done.
|
|
29485
29495
|
7. Your evidence strings must be concrete and verifiable \u2014 not vague affirmations.
|
|
29486
|
-
8. Always provide --desc
|
|
29487
|
-
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
|
|
29496
|
+
8. Always provide --desc, at least one --ac, and --agent when creating a task. All three are required.${reviewRequired ? `
|
|
29497
|
+
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 in the SAME session. Do NOT call \`aitasks done\` yourself after submitting for review \u2014 the system blocks self-approval.
|
|
29498
|
+
10. **Do not end your session or write a final summary until every task you worked on is in \`done\` status.** If any task is in \`review\`, you must spawn the review sub-agent NOW in this session. Submitting for review and stopping is an incomplete session.` : ""}
|
|
29488
29499
|
|
|
29489
|
-
|
|
29500
|
+
${reviewRequired ? `---
|
|
29501
|
+
|
|
29502
|
+
### Before Ending Your Session
|
|
29503
|
+
|
|
29504
|
+
**Run this check before writing any final summary or concluding your work:**
|
|
29505
|
+
|
|
29506
|
+
\`\`\`bash
|
|
29507
|
+
aitasks list --json # Check that ALL your tasks are in done status
|
|
29508
|
+
\`\`\`
|
|
29509
|
+
|
|
29510
|
+
- Any task in \`done\` \u2192 \u2713 complete
|
|
29511
|
+
- Any task in \`review\` \u2192 you MUST spawn a review sub-agent NOW in this session before stopping
|
|
29512
|
+
- Any task in \`in_progress\` \u2192 continue implementation
|
|
29513
|
+
|
|
29514
|
+
**You are NOT finished until \`aitasks list\` shows every task you worked on as \`done\`.**
|
|
29515
|
+
Submitting tasks for review and then stopping is an incomplete session. The review sub-agent
|
|
29516
|
+
must be spawned and must approve the task in this same session.
|
|
29517
|
+
|
|
29518
|
+
` : ""}---
|
|
29490
29519
|
|
|
29491
29520
|
### Quick Reference
|
|
29492
29521
|
|
|
@@ -29496,7 +29525,7 @@ aitasks list [--status <s>] [--json] List tasks
|
|
|
29496
29525
|
aitasks show <id> Full task detail (includes time tracking)
|
|
29497
29526
|
aitasks search <query> Search titles, descriptions, notes
|
|
29498
29527
|
aitasks deps <id> Show dependency tree
|
|
29499
|
-
aitasks create --title <t> --desc <d> --ac <c> [--ac <c> ...] Create a task
|
|
29528
|
+
aitasks create --title <t> --desc <d> --ac <c> [--ac <c> ...] --agent <id> Create a task
|
|
29500
29529
|
aitasks claim <id...> --agent <id> Claim task(s) - supports patterns like TASK-0*
|
|
29501
29530
|
aitasks start <id...> --agent <id> Begin work on task(s)
|
|
29502
29531
|
aitasks note <id> <text> --agent <id> Add implementation note
|
|
@@ -30323,7 +30352,7 @@ function createTask(data) {
|
|
|
30323
30352
|
now,
|
|
30324
30353
|
JSON.stringify(data.metadata ?? {})
|
|
30325
30354
|
]);
|
|
30326
|
-
logEvent({ task_id: id, event_type: "created", payload: { title: data.title } });
|
|
30355
|
+
logEvent({ task_id: id, agent_id: data.created_by, event_type: "created", payload: { title: data.title } });
|
|
30327
30356
|
return getTask(id);
|
|
30328
30357
|
}
|
|
30329
30358
|
var JSON_FIELDS = new Set([
|
|
@@ -30409,9 +30438,9 @@ function claimTask(taskId, agentId) {
|
|
|
30409
30438
|
error: `Task is blocked by: ${task.blocked_by.join(", ")}. Complete those first.`
|
|
30410
30439
|
};
|
|
30411
30440
|
}
|
|
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]);
|
|
30441
|
+
db.run(`INSERT INTO agents (id, first_seen, last_seen, current_task)
|
|
30442
|
+
VALUES (?, ?, ?, ?)
|
|
30443
|
+
ON CONFLICT(id) DO UPDATE SET last_seen = excluded.last_seen, current_task = excluded.current_task`, [agentId, Date.now(), Date.now(), taskId]);
|
|
30415
30444
|
const updated = updateTask(taskId, { assigned_to: agentId, status: "ready" });
|
|
30416
30445
|
logEvent({ task_id: taskId, agent_id: agentId, event_type: "claimed", payload: {} });
|
|
30417
30446
|
return { task: updated };
|
|
@@ -30427,9 +30456,9 @@ function startTask(taskId, agentId) {
|
|
|
30427
30456
|
}
|
|
30428
30457
|
const db = getDb();
|
|
30429
30458
|
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]);
|
|
30459
|
+
db.run(`INSERT INTO agents (id, first_seen, last_seen, current_task)
|
|
30460
|
+
VALUES (?, ?, ?, ?)
|
|
30461
|
+
ON CONFLICT(id) DO UPDATE SET last_seen = excluded.last_seen, current_task = excluded.current_task`, [agentId, Date.now(), Date.now(), taskId]);
|
|
30433
30462
|
}
|
|
30434
30463
|
const updated = updateTask(taskId, {
|
|
30435
30464
|
assigned_to: agentId,
|
|
@@ -30481,14 +30510,18 @@ function completeTask(taskId, agentId) {
|
|
|
30481
30510
|
` + ` A separate review sub-agent must run: aitasks done ${taskId} --agent <review-agent-id>`
|
|
30482
30511
|
};
|
|
30483
30512
|
}
|
|
30484
|
-
|
|
30485
|
-
|
|
30486
|
-
|
|
30487
|
-
|
|
30488
|
-
|
|
30489
|
-
|
|
30490
|
-
|
|
30491
|
-
|
|
30513
|
+
if (agentId) {
|
|
30514
|
+
const reviewerRow = db.query(`SELECT first_seen FROM agents WHERE id = ?`).get(agentId);
|
|
30515
|
+
const reviewSubmittedAt = reviewEvent?.created_at ?? 0;
|
|
30516
|
+
if (!reviewerRow || reviewerRow.first_seen > reviewSubmittedAt) {
|
|
30517
|
+
return {
|
|
30518
|
+
task: null,
|
|
30519
|
+
error: `Review agent '${agentId}' was not active before this review was submitted.
|
|
30520
|
+
` + ` A real review sub-agent must be independently spawned \u2014 it cannot be registered
|
|
30521
|
+
` + ` moments before approving. The reviewer must have prior activity in the system
|
|
30522
|
+
` + ` before the review was submitted.`
|
|
30523
|
+
};
|
|
30524
|
+
}
|
|
30492
30525
|
}
|
|
30493
30526
|
}
|
|
30494
30527
|
const updated = updateTask(taskId, { status: "done", completed_at: Date.now() });
|
|
@@ -30509,7 +30542,8 @@ function completeTask(taskId, agentId) {
|
|
|
30509
30542
|
});
|
|
30510
30543
|
}
|
|
30511
30544
|
}
|
|
30512
|
-
|
|
30545
|
+
if (agentId)
|
|
30546
|
+
db.run(`UPDATE agents SET current_task = NULL WHERE id = ?`, [agentId]);
|
|
30513
30547
|
return { task: updated };
|
|
30514
30548
|
}
|
|
30515
30549
|
function blockTask(taskId, blockerIds, agentId) {
|
|
@@ -30621,9 +30655,9 @@ function unclaimTask(taskId, agentId, reason) {
|
|
|
30621
30655
|
}
|
|
30622
30656
|
function heartbeat(agentId, taskId) {
|
|
30623
30657
|
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]);
|
|
30658
|
+
db.run(`INSERT INTO agents (id, first_seen, last_seen, current_task)
|
|
30659
|
+
VALUES (?, ?, ?, ?)
|
|
30660
|
+
ON CONFLICT(id) DO UPDATE SET last_seen = excluded.last_seen`, [agentId, Date.now(), Date.now(), taskId ?? null]);
|
|
30627
30661
|
}
|
|
30628
30662
|
function listAgents() {
|
|
30629
30663
|
const db = getDb();
|
|
@@ -30721,7 +30755,7 @@ function exitError(msg, json) {
|
|
|
30721
30755
|
}
|
|
30722
30756
|
|
|
30723
30757
|
// 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) => {
|
|
30758
|
+
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
30759
|
requireInitialized();
|
|
30726
30760
|
const json = isJsonMode(opts.json);
|
|
30727
30761
|
if (opts.title) {
|
|
@@ -30746,13 +30780,15 @@ var createCommand2 = new Command("create").description("Create a new task").opti
|
|
|
30746
30780
|
process.exit(1);
|
|
30747
30781
|
}
|
|
30748
30782
|
}
|
|
30783
|
+
const aid = agentId(opts.agent) ?? undefined;
|
|
30749
30784
|
const task2 = createTask({
|
|
30750
30785
|
title: opts.title,
|
|
30751
30786
|
description: opts.desc ?? "",
|
|
30752
30787
|
acceptance_criteria: opts.ac,
|
|
30753
30788
|
priority: opts.priority,
|
|
30754
30789
|
type: opts.type,
|
|
30755
|
-
parent_id: opts.parent
|
|
30790
|
+
parent_id: opts.parent,
|
|
30791
|
+
created_by: aid
|
|
30756
30792
|
});
|
|
30757
30793
|
if (json)
|
|
30758
30794
|
return jsonOut(true, task2);
|
|
@@ -41226,7 +41262,7 @@ var checkCommand = new Command("check").description("Verify an acceptance criter
|
|
|
41226
41262
|
var doneCommand = new Command("done").description("Mark task(s) as complete (all acceptance criteria must be verified) - supports patterns").argument("<taskId...>", "Task ID(s) - can specify multiple or use patterns (e.g., TASK-00*)").option("--agent <agentId>", "Agent ID (or set AITASKS_AGENT_ID)").option("--json", "Output as JSON").action((taskIds, opts) => {
|
|
41227
41263
|
requireInitialized();
|
|
41228
41264
|
const json = isJsonMode(opts.json);
|
|
41229
|
-
const agent =
|
|
41265
|
+
const agent = opts.agent ?? process.env.AITASKS_AGENT_ID;
|
|
41230
41266
|
const allTaskIds = listTasks().map((t) => t.id);
|
|
41231
41267
|
const resolvedIds = resolveTaskIds(taskIds.map((id) => id.toUpperCase()), allTaskIds);
|
|
41232
41268
|
if (resolvedIds.length === 0) {
|
|
@@ -43318,4 +43354,4 @@ program2.parseAsync(process.argv).catch((err) => {
|
|
|
43318
43354
|
process.exit(1);
|
|
43319
43355
|
});
|
|
43320
43356
|
|
|
43321
|
-
//# debugId=
|
|
43357
|
+
//# debugId=1AD83EE12EE8B53364756E2164756E21
|