aitasks 1.4.2 → 1.4.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 +215 -213
  2. package/dist/index.js +109 -98
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,213 +1,215 @@
1
- # aitasks
2
-
3
- > CLI task management built for AI agents.
4
-
5
- `aitasks` gives AI agents (Claude, Gemini, GPT, etc.) a structured task queue to work from. Agents can claim tasks, log progress notes, verify acceptance criteria with evidence, and hand off work — all via simple shell commands.
6
-
7
- **Requires [Bun](https://bun.sh) 1.0.0.**
8
-
9
- ---
10
-
11
- ## Install
12
-
13
- ```sh
14
- bun install -g aitasks
15
- ```
16
-
17
- ## Quick Start
18
-
19
- ```sh
20
- # 1. Initialize in your project
21
- aitasks init
22
-
23
- # 2. Create a task
24
- aitasks create --title "Add JWT auth" --desc "Implement user authentication" --priority high --ac "POST /login returns token" --ac "Token expires in 1h"
25
-
26
- # 3. Agent picks up work (one-liner with auto-claim)
27
- aitasks next --claim --agent claude-sonnet
28
-
29
- # 4. Or claim and start separately
30
- aitasks claim TASK-001 --agent claude-sonnet
31
- aitasks start TASK-001 --agent claude-sonnet
32
-
33
- # 5. Log notes along the way
34
- aitasks note TASK-001 "Using bcrypt for hashing — src/auth.ts:L22" --agent claude-sonnet
35
-
36
- # 6. Verify acceptance criteria
37
- aitasks check TASK-001 0 --evidence "POST /login returns 200 with token field" --agent claude-sonnet
38
- aitasks check TASK-001 1 --evidence "token exp claim set to now+3600, confirmed in jwt.test.ts:L14"
39
-
40
- # 7. Mark done
41
- aitasks done TASK-001 --agent claude-sonnet
42
- ```
43
-
44
- **Pro tips:**
45
- - Use `aitasks next --claim --agent <id>` to find, claim, and start in one command
46
- - Bulk operations: `aitasks done TASK-001 TASK-002 TASK-003 --agent <id>`
47
- - Pattern matching: `aitasks claim TASK-0* --agent <id>` claims all TASK-00x tasks
48
- - Search: `aitasks search "auth"` finds tasks mentioning authentication
49
- - Undo mistakes: `aitasks undo TASK-001`
50
- - Delete tasks: `aitasks delete TASK-001` (no need to claim first)
51
-
52
- ---
53
-
54
- ## Environment Variables
55
-
56
- | Variable | Description |
57
- |---|---|
58
- | `AITASKS_AGENT_ID` | Default agent ID — avoids passing `--agent` on every command |
59
- | `AITASKS_JSON` | Set to `true` to force JSON output globally (useful for scripting) |
60
-
61
- ```sh
62
- export AITASKS_AGENT_ID=claude-sonnet
63
- export AITASKS_JSON=true
64
- ```
65
-
66
- ---
67
-
68
- ## Commands
69
-
70
- ### Setup
71
-
72
- | Command | Description |
73
- |---|---|
74
- | `aitasks init` | Initialize a task database in the current project |
75
- | `aitasks init --with-review` | Initialize with review enforcement (agents cannot mark done without a passing review) |
76
- | `aitasks onboard` | Print or inject agent protocol instructions into CLAUDE.md / AGENTS.md |
77
-
78
- ### Task Discovery
79
-
80
- | Command | Description |
81
- |---|---|
82
- | `aitasks list` | List all tasks, sorted by priority |
83
- | `aitasks list --status ready` | Filter by status (`ready`, `in_progress`, `blocked`, `review`, `done`) |
84
- | `aitasks next` | Show the highest-priority unblocked ready task |
85
- | `aitasks next --claim --agent <id>` | Auto-claim and start the best task |
86
- | `aitasks show <id>` | Full detail on a specific task (includes time tracking) |
87
- | `aitasks search <query>` | Full-text search across titles, descriptions, and notes |
88
- | `aitasks deps <id>` | Show dependency tree (what blocks what) |
89
- | `aitasks board` | Kanban-style board view |
90
-
91
- ### Task Lifecycle
92
-
93
- | Command | Description |
94
- |---|---|
95
- | `aitasks create` | Create a task (interactive if no flags given) |
96
- | `aitasks claim <id...> --agent <id>` | Claim task(s) - supports patterns like `TASK-0*` |
97
- | `aitasks start <id...> --agent <id>` | Begin active work on task(s) |
98
- | `aitasks note <id> <text>` | Add an implementation note |
99
- | `aitasks check <id> <n> --evidence <text>` | Verify acceptance criterion n |
100
- | `aitasks done <id...> --agent <id>` | Mark task(s) complete (all criteria must be verified; must be in `review` status if enforcement is on) |
101
- | `aitasks review <id...> --agent <id>` | Submit task(s) for review (moves to `review` status) |
102
- | `aitasks reject <id> --reason <text>` | Reject a task in review, send it back to `in_progress` with feedback |
103
- | `aitasks unclaim <id> --agent <id>` | Release a task back to the pool |
104
- | `aitasks undo <id>` | Undo the last action on a task |
105
- | `aitasks delete <id...>` | Delete task(s) - does not require claiming first |
106
-
107
- **Note:** Commands marked with `<id...>` support multiple task IDs and pattern matching (e.g., `TASK-0*`).
108
-
109
- ### Blocking
110
-
111
- | Command | Description |
112
- |---|---|
113
- | `aitasks block <id> --on <id,...>` | Mark a task as blocked by others |
114
- | `aitasks unblock <id> --from <id>` | Manually remove a blocker |
115
-
116
- ### Agents & History
117
-
118
- | Command | Description |
119
- |---|---|
120
- | `aitasks agents` | List active agents and their current tasks |
121
- | `aitasks heartbeat [taskId]` | Update agent last-seen timestamp |
122
- | `aitasks log <id>` | Full event history for a task |
123
- | `aitasks export --format json` | Export all tasks as JSON |
124
- | `aitasks export --format csv` | Export all tasks as CSV |
125
-
126
- ### Database
127
-
128
- | Command | Description |
129
- |---|---|
130
- | `aitasks db status` | Show database health and stats |
131
-
132
- ---
133
-
134
- ## `create` Flags
135
-
136
- ```sh
137
- aitasks create \
138
- --title "My task" \
139
- --desc "Longer description" \
140
- --ac "Returns 200" \ # Acceptance criterion (repeatable, at least one required)
141
- --priority high \ # critical | high | medium | low
142
- --type feature \ # feature | bug | chore | spike
143
- --parent TASK-001 \ # Parent task ID (optional)
144
- --agent $AITASKS_AGENT_ID # Agent creating the task (logged in event history)
145
- ```
146
-
147
- ---
148
-
149
- ## Agent Protocol
150
-
151
- When you run `aitasks init`, it automatically injects a full agent protocol into `CLAUDE.md`, `AGENTS.md`, or `GEMINI.md` (whichever exists, or creates `AGENTS.md`). This tells the AI agent exactly how to use `aitasks`.
152
-
153
- You can also inject/view it manually:
154
-
155
- ```sh
156
- aitasks onboard # print to stdout (reflects current review_required setting)
157
- aitasks onboard --append # append to detected agent file
158
- aitasks onboard --file MY.md # append to a specific file
159
- aitasks onboard --json # output as JSON string
160
- ```
161
-
162
- The injected instructions automatically adapt to the project's review enforcement setting — if `--with-review` is enabled, agents receive the full review workflow (with `aitasks review`, sub-agent approval, and `aitasks reject`) instead of the standard completion flow.
163
-
164
- ---
165
-
166
- ## Review Enforcement
167
-
168
- Enable a mandatory review gate so agents cannot mark tasks done without an explicit approval step:
169
-
170
- ```sh
171
- # Enable at init time
172
- aitasks init --with-review
173
-
174
- # Enable on an existing project (also replaces the agent instructions file with review-aware version)
175
- aitasks init --with-review # safe to re-run; updates DB setting and rewrites agent file
176
- ```
177
-
178
- **A task is only complete when its status is `done`.** No other status — verified criteria, `review`, `in_progress` — counts as complete. Agents must reach `done` to consider a task finished.
179
-
180
- **How it works:**
181
-
182
- 1. Agent completes work and verifies all acceptance criteria with evidence
183
- 2. Agent submits for review — task moves to `review` status:
184
- ```sh
185
- aitasks review TASK-001 --agent $AITASKS_AGENT_ID
186
- ```
187
- The command output explicitly instructs the agent to immediately spawn a review sub-agent. The task is **not complete** at this point.
188
- 3. The agent **immediately spawns a review sub-agent** to inspect the implementation:
189
- - **Approves** moves task to done:
190
- ```sh
191
- aitasks done TASK-001 --agent review-agent
192
- ```
193
- - **Rejects** sends it back to `in_progress` with feedback:
194
- ```sh
195
- aitasks reject TASK-001 --reason "Missing error handling for 404 case" --agent review-agent
196
- ```
197
- 4. If rejected, the original agent addresses the feedback, re-verifies criteria, and repeats from step 2.
198
-
199
- **Enforcement:** `aitasks done` and `aitasks update --status done` both block if the task isn't already in `review` status. The gate cannot be bypassed.
200
-
201
- **Board:** Tasks in `review` status appear in the **IN PROGRESS** section with a `◈` magenta indicator so they're visually distinct from actively-worked tasks.
202
-
203
- ---
204
-
205
- ## Data Storage
206
-
207
- `aitasks init` creates a `.aitasks/` directory in your project root containing a SQLite database. Add `.aitasks/` to your `.gitignore` if you don't want to commit task data, or commit it to share tasks across your team.
208
-
209
- ---
210
-
211
- ## License
212
-
213
- MIT
1
+ [![DOWNLOADS](https://img.shields.io/npm/dt/aitasks?label=npm&colorA=151B23&colorB=81F096&style=for-the-badge)](https://www.npmjs.com/package/aitasks)
2
+
3
+ # aitasks
4
+
5
+ > CLI task management built for AI agents.
6
+
7
+ `aitasks` gives AI agents (Claude, Gemini, GPT, etc.) a structured task queue to work from. Agents can claim tasks, log progress notes, verify acceptance criteria with evidence, and hand off work — all via simple shell commands.
8
+
9
+ **Requires [Bun](https://bun.sh) ≥ 1.0.0.**
10
+
11
+ ---
12
+
13
+ ## Install
14
+
15
+ ```sh
16
+ bun install -g aitasks
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ ```sh
22
+ # 1. Initialize in your project
23
+ aitasks init
24
+
25
+ # 2. Create a task
26
+ aitasks create --title "Add JWT auth" --desc "Implement user authentication" --priority high --ac "POST /login returns token" --ac "Token expires in 1h"
27
+
28
+ # 3. Agent picks up work (one-liner with auto-claim)
29
+ aitasks next --claim --agent claude-sonnet
30
+
31
+ # 4. Or claim and start separately
32
+ aitasks claim TASK-001 --agent claude-sonnet
33
+ aitasks start TASK-001 --agent claude-sonnet
34
+
35
+ # 5. Log notes along the way
36
+ aitasks note TASK-001 "Using bcrypt for hashing — src/auth.ts:L22" --agent claude-sonnet
37
+
38
+ # 6. Verify acceptance criteria
39
+ aitasks check TASK-001 0 --evidence "POST /login returns 200 with token field" --agent claude-sonnet
40
+ aitasks check TASK-001 1 --evidence "token exp claim set to now+3600, confirmed in jwt.test.ts:L14"
41
+
42
+ # 7. Mark done
43
+ aitasks done TASK-001 --agent claude-sonnet
44
+ ```
45
+
46
+ **Pro tips:**
47
+ - Use `aitasks next --claim --agent <id>` to find, claim, and start in one command
48
+ - Bulk operations: `aitasks done TASK-001 TASK-002 TASK-003 --agent <id>`
49
+ - Pattern matching: `aitasks claim TASK-0* --agent <id>` claims all TASK-00x tasks
50
+ - Search: `aitasks search "auth"` finds tasks mentioning authentication
51
+ - Undo mistakes: `aitasks undo TASK-001`
52
+ - Delete tasks: `aitasks delete TASK-001` (no need to claim first)
53
+
54
+ ---
55
+
56
+ ## Environment Variables
57
+
58
+ | Variable | Description |
59
+ |---|---|
60
+ | `AITASKS_AGENT_ID` | Default agent ID — avoids passing `--agent` on every command |
61
+ | `AITASKS_JSON` | Set to `true` to force JSON output globally (useful for scripting) |
62
+
63
+ ```sh
64
+ export AITASKS_AGENT_ID=claude-sonnet
65
+ export AITASKS_JSON=true
66
+ ```
67
+
68
+ ---
69
+
70
+ ## Commands
71
+
72
+ ### Setup
73
+
74
+ | Command | Description |
75
+ |---|---|
76
+ | `aitasks init` | Initialize a task database in the current project |
77
+ | `aitasks init --with-review` | Initialize with review enforcement (agents cannot mark done without a passing review) |
78
+ | `aitasks onboard` | Print or inject agent protocol instructions into CLAUDE.md / AGENTS.md |
79
+
80
+ ### Task Discovery
81
+
82
+ | Command | Description |
83
+ |---|---|
84
+ | `aitasks list` | List all tasks, sorted by priority |
85
+ | `aitasks list --status ready` | Filter by status (`ready`, `in_progress`, `blocked`, `review`, `done`) |
86
+ | `aitasks next` | Show the highest-priority unblocked ready task |
87
+ | `aitasks next --claim --agent <id>` | Auto-claim and start the best task |
88
+ | `aitasks show <id>` | Full detail on a specific task (includes time tracking) |
89
+ | `aitasks search <query>` | Full-text search across titles, descriptions, and notes |
90
+ | `aitasks deps <id>` | Show dependency tree (what blocks what) |
91
+ | `aitasks board` | Kanban-style board view |
92
+
93
+ ### Task Lifecycle
94
+
95
+ | Command | Description |
96
+ |---|---|
97
+ | `aitasks create` | Create a task (interactive if no flags given) |
98
+ | `aitasks claim <id...> --agent <id>` | Claim task(s) - supports patterns like `TASK-0*` |
99
+ | `aitasks start <id...> --agent <id>` | Begin active work on task(s) |
100
+ | `aitasks note <id> <text>` | Add an implementation note |
101
+ | `aitasks check <id> <n> --evidence <text>` | Verify acceptance criterion n |
102
+ | `aitasks done <id...> --agent <id>` | Mark task(s) complete (all criteria must be verified; must be in `review` status if enforcement is on) |
103
+ | `aitasks review <id...> --agent <id>` | Submit task(s) for review (moves to `review` status) |
104
+ | `aitasks reject <id> --reason <text>` | Reject a task in review, send it back to `in_progress` with feedback |
105
+ | `aitasks unclaim <id> --agent <id>` | Release a task back to the pool |
106
+ | `aitasks undo <id>` | Undo the last action on a task |
107
+ | `aitasks delete <id...>` | Delete task(s) - does not require claiming first |
108
+
109
+ **Note:** Commands marked with `<id...>` support multiple task IDs and pattern matching (e.g., `TASK-0*`).
110
+
111
+ ### Blocking
112
+
113
+ | Command | Description |
114
+ |---|---|
115
+ | `aitasks block <id> --on <id,...>` | Mark a task as blocked by others |
116
+ | `aitasks unblock <id> --from <id>` | Manually remove a blocker |
117
+
118
+ ### Agents & History
119
+
120
+ | Command | Description |
121
+ |---|---|
122
+ | `aitasks agents` | List active agents and their current tasks |
123
+ | `aitasks heartbeat [taskId]` | Update agent last-seen timestamp |
124
+ | `aitasks log <id>` | Full event history for a task |
125
+ | `aitasks export --format json` | Export all tasks as JSON |
126
+ | `aitasks export --format csv` | Export all tasks as CSV |
127
+
128
+ ### Database
129
+
130
+ | Command | Description |
131
+ |---|---|
132
+ | `aitasks db status` | Show database health and stats |
133
+
134
+ ---
135
+
136
+ ## `create` Flags
137
+
138
+ ```sh
139
+ aitasks create \
140
+ --title "My task" \
141
+ --desc "Longer description" \
142
+ --ac "Returns 200" \ # Acceptance criterion (repeatable, at least one required)
143
+ --priority high \ # critical | high | medium | low
144
+ --type feature \ # feature | bug | chore | spike
145
+ --parent TASK-001 \ # Parent task ID (optional)
146
+ --agent $AITASKS_AGENT_ID # Agent creating the task (logged in event history)
147
+ ```
148
+
149
+ ---
150
+
151
+ ## Agent Protocol
152
+
153
+ When you run `aitasks init`, it automatically injects a full agent protocol into `CLAUDE.md`, `AGENTS.md`, or `GEMINI.md` (whichever exists, or creates `AGENTS.md`). This tells the AI agent exactly how to use `aitasks`.
154
+
155
+ You can also inject/view it manually:
156
+
157
+ ```sh
158
+ aitasks onboard # print to stdout (reflects current review_required setting)
159
+ aitasks onboard --append # append to detected agent file
160
+ aitasks onboard --file MY.md # append to a specific file
161
+ aitasks onboard --json # output as JSON string
162
+ ```
163
+
164
+ The injected instructions automatically adapt to the project's review enforcement setting — if `--with-review` is enabled, agents receive the full review workflow (with `aitasks review`, sub-agent approval, and `aitasks reject`) instead of the standard completion flow.
165
+
166
+ ---
167
+
168
+ ## Review Enforcement
169
+
170
+ Enable a mandatory review gate so agents cannot mark tasks done without an explicit approval step:
171
+
172
+ ```sh
173
+ # Enable at init time
174
+ aitasks init --with-review
175
+
176
+ # Enable on an existing project (also replaces the agent instructions file with review-aware version)
177
+ aitasks init --with-review # safe to re-run; updates DB setting and rewrites agent file
178
+ ```
179
+
180
+ **A task is only complete when its status is `done`.** No other status — verified criteria, `review`, `in_progress` — counts as complete. Agents must reach `done` to consider a task finished.
181
+
182
+ **How it works:**
183
+
184
+ 1. Agent completes work and verifies all acceptance criteria with evidence
185
+ 2. Agent submits for review task moves to `review` status:
186
+ ```sh
187
+ aitasks review TASK-001 --agent $AITASKS_AGENT_ID
188
+ ```
189
+ The command output explicitly instructs the agent to immediately spawn a review sub-agent. The task is **not complete** at this point.
190
+ 3. The agent **immediately spawns a review sub-agent** to inspect the implementation:
191
+ - **Approves** moves task to done:
192
+ ```sh
193
+ aitasks done TASK-001 --agent review-agent
194
+ ```
195
+ - **Rejects** sends it back to `in_progress` with feedback:
196
+ ```sh
197
+ aitasks reject TASK-001 --reason "Missing error handling for 404 case" --agent review-agent
198
+ ```
199
+ 4. If rejected, the original agent addresses the feedback, re-verifies criteria, and repeats from step 2.
200
+
201
+ **Enforcement:** `aitasks done` and `aitasks update --status done` both block if the task isn't already in `review` status. The gate cannot be bypassed.
202
+
203
+ **Board:** Tasks in `review` status appear in the **IN PROGRESS** section with a `◈` magenta indicator so they're visually distinct from actively-worked tasks.
204
+
205
+ ---
206
+
207
+ ## Data Storage
208
+
209
+ `aitasks init` creates a `.aitasks/` directory in your project root containing a SQLite database. Add `.aitasks/` to your `.gitignore` if you don't want to commit task data, or commit it to share tasks across your team.
210
+
211
+ ---
212
+
213
+ ## License
214
+
215
+ MIT
package/dist/index.js CHANGED
@@ -861,7 +861,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
861
861
  this._exitCallback = (err) => {
862
862
  if (err.code !== "commander.executeSubCommandAsync") {
863
863
  throw err;
864
- } else {}
864
+ }
865
865
  };
866
866
  }
867
867
  return this;
@@ -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.4.2",
1893
+ version: "1.4.4",
1894
1894
  description: "CLI task management tool built for AI agents",
1895
1895
  type: "module",
1896
1896
  bin: {
@@ -9868,7 +9868,7 @@ Learn more about data fetching with Hooks: https://react.dev/link/hooks-data-fet
9868
9868
  offscreenSubtreeIsHidden = prevOffscreenSubtreeIsHidden;
9869
9869
  wasHidden && !hoistableRoot && !prevOffscreenSubtreeIsHidden && !prevOffscreenSubtreeWasHidden && (finishedWork.mode & 2) !== NoMode && 0 <= componentEffectStartTime && 0 <= componentEffectEndTime && 0.05 < componentEffectEndTime - componentEffectStartTime && logComponentReappeared(finishedWork, componentEffectStartTime, componentEffectEndTime);
9870
9870
  commitReconciliationEffects(finishedWork);
9871
- if (flags & 8192 && (root = finishedWork.stateNode, root._visibility = hoistableRoot ? root._visibility & ~OffscreenVisible : root._visibility | OffscreenVisible, !hoistableRoot || current2 === null || wasHidden || offscreenSubtreeIsHidden || offscreenSubtreeWasHidden || (recursivelyTraverseDisappearLayoutEffects(finishedWork), (finishedWork.mode & 2) !== NoMode && 0 <= componentEffectStartTime && 0 <= componentEffectEndTime && 0.05 < componentEffectEndTime - componentEffectStartTime && logComponentTrigger(finishedWork, componentEffectStartTime, componentEffectEndTime, "Disconnect")), supportsMutation))
9871
+ if (flags & 8192 && (root = finishedWork.stateNode, root._visibility = hoistableRoot ? root._visibility & ~OffscreenVisible : root._visibility | OffscreenVisible, !hoistableRoot || current2 === null || wasHidden || offscreenSubtreeIsHidden || offscreenSubtreeWasHidden || (recursivelyTraverseDisappearLayoutEffects(finishedWork), (finishedWork.mode & 2) !== NoMode && 0 <= componentEffectStartTime && 0 <= componentEffectEndTime && 0.05 < componentEffectEndTime - componentEffectStartTime && logComponentTrigger(finishedWork, componentEffectStartTime, componentEffectEndTime, "Disconnect")), supportsMutation)) {
9872
9872
  a:
9873
9873
  if (current2 = null, supportsMutation)
9874
9874
  for (root = finishedWork;; ) {
@@ -9918,6 +9918,7 @@ Learn more about data fetching with Hooks: https://react.dev/link/hooks-data-fet
9918
9918
  root.sibling.return = root.return;
9919
9919
  root = root.sibling;
9920
9920
  }
9921
+ }
9921
9922
  flags & 4 && (flags = finishedWork.updateQueue, flags !== null && (current2 = flags.retryQueue, current2 !== null && (flags.retryQueue = null, attachSuspenseRetryListeners(finishedWork, current2))));
9922
9923
  break;
9923
9924
  case 19:
@@ -14590,7 +14591,7 @@ var require_backend = __commonJS((exports, module) => {
14590
14591
  987: (module2, __unused_webpack_exports, __webpack_require__2) => {
14591
14592
  if (true) {
14592
14593
  module2.exports = __webpack_require__2(786);
14593
- } else {}
14594
+ }
14594
14595
  },
14595
14596
  126: (__unused_webpack_module, exports2, __webpack_require__2) => {
14596
14597
  var process6 = __webpack_require__2(169);
@@ -15050,7 +15051,7 @@ var require_backend = __commonJS((exports, module) => {
15050
15051
  189: (module2, __unused_webpack_exports, __webpack_require__2) => {
15051
15052
  if (true) {
15052
15053
  module2.exports = __webpack_require__2(126);
15053
- } else {}
15054
+ }
15054
15055
  },
15055
15056
  206: function(module2, exports2, __webpack_require__2) {
15056
15057
  var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;
@@ -15070,7 +15071,7 @@ var require_backend = __commonJS((exports, module) => {
15070
15071
  (function(root, factory) {
15071
15072
  if (true) {
15072
15073
  __WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__2(430)], __WEBPACK_AMD_DEFINE_FACTORY__ = factory, __WEBPACK_AMD_DEFINE_RESULT__ = typeof __WEBPACK_AMD_DEFINE_FACTORY__ === "function" ? __WEBPACK_AMD_DEFINE_FACTORY__.apply(exports2, __WEBPACK_AMD_DEFINE_ARRAY__) : __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module2.exports = __WEBPACK_AMD_DEFINE_RESULT__);
15073
- } else {}
15074
+ }
15074
15075
  })(this, function ErrorStackParser(StackFrame) {
15075
15076
  var FIREFOX_SAFARI_STACK_REGEXP = /(^|@)\S+:\d+/;
15076
15077
  var CHROME_IE_STACK_REGEXP = /^\s*at .*(\S+:\d+|\(native\))/m;
@@ -15746,7 +15747,7 @@ var require_backend = __commonJS((exports, module) => {
15746
15747
  (function(root, factory) {
15747
15748
  if (true) {
15748
15749
  __WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = factory, __WEBPACK_AMD_DEFINE_RESULT__ = typeof __WEBPACK_AMD_DEFINE_FACTORY__ === "function" ? __WEBPACK_AMD_DEFINE_FACTORY__.apply(exports2, __WEBPACK_AMD_DEFINE_ARRAY__) : __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module2.exports = __WEBPACK_AMD_DEFINE_RESULT__);
15749
- } else {}
15750
+ }
15750
15751
  })(this, function() {
15751
15752
  function _isNumber(n) {
15752
15753
  return !isNaN(parseFloat(n)) && isFinite(n);
@@ -20528,7 +20529,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
20528
20529
  var suffix = "";
20529
20530
  if (true) {
20530
20531
  suffix = " (<anonymous>)";
20531
- } else {}
20532
+ }
20532
20533
  return `
20533
20534
  ` + prefix + name + suffix;
20534
20535
  }
@@ -22857,7 +22858,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
22857
22858
  hasChanges = true;
22858
22859
  updateMostRecentlyInspectedElementIfNecessary(devtoolsInstance.id);
22859
22860
  }
22860
- } else {}
22861
+ }
22861
22862
  }
22862
22863
  } catch (err) {
22863
22864
  _iterator2.e(err);
@@ -26729,7 +26730,7 @@ The error thrown in the component is:
26729
26730
  rendererInterface = renderer_attach(hook, id, renderer, global2, shouldStartProfilingNow, profilingSettings);
26730
26731
  } else if (renderer.ComponentTree) {
26731
26732
  rendererInterface = legacy_renderer_attach(hook, id, renderer, global2);
26732
- } else {}
26733
+ }
26733
26734
  }
26734
26735
  return rendererInterface;
26735
26736
  }
@@ -29409,8 +29410,14 @@ aitasks block TASK-001 --on TASK-002,TASK-003
29409
29410
  View dependencies:
29410
29411
  \`\`\`bash
29411
29412
  aitasks deps TASK-001 # Shows what this task is blocked by and what it blocks
29413
+ aitasks show TASK-001 # Also lists "Blocked by" / "Blocks" for a single task
29412
29414
  \`\`\`
29413
29415
 
29416
+ When a prerequisite is marked \`done\`, its dependents are **auto-unblocked**: any task
29417
+ whose last blocker just completed moves to \`ready\` automatically (no manual promotion
29418
+ needed). You can then \`aitasks claim\` it directly. To override a status by hand, use
29419
+ \`aitasks update <id> --status ready\`.
29420
+
29414
29421
  ---
29415
29422
 
29416
29423
  ### Completing a Task${reviewRequired ? " \u26A0\uFE0F REVIEW REQUIRED" : ""}
@@ -29528,10 +29535,12 @@ must be spawned and must approve the task in this same session.
29528
29535
  \`\`\`
29529
29536
  aitasks next [--claim] [--agent <id>] Find best task (optionally auto-claim/start)
29530
29537
  aitasks list [--status <s>] [--json] List tasks
29538
+ aitasks board Live kanban board (visual TUI)
29531
29539
  aitasks show <id> Full task detail (includes time tracking)
29532
29540
  aitasks search <query> Search titles, descriptions, notes
29533
29541
  aitasks deps <id> Show dependency tree
29534
29542
  aitasks create --title <t> --desc <d> --ac <c> [--ac <c> ...] --agent <id> Create a task
29543
+ aitasks update <id> [--status|--priority|--title|--desc|--ac|--type] Update task fields
29535
29544
  aitasks claim <id...> --agent <id> Claim task(s) - supports patterns like TASK-0*
29536
29545
  aitasks start <id...> --agent <id> Begin work on task(s)
29537
29546
  aitasks note <id> <text> --agent <id> Add implementation note
@@ -29546,6 +29555,7 @@ aitasks undo <id> Undo last action on task
29546
29555
  aitasks delete <id...> Delete task(s) - no claim required
29547
29556
  aitasks log <id> Full event history
29548
29557
  aitasks agents List active agents
29558
+ aitasks heartbeat [<id>] --agent <id> Keep-alive: refresh agent last-seen
29549
29559
  aitasks export --format json Export all tasks
29550
29560
  \`\`\`
29551
29561
 
@@ -29631,6 +29641,42 @@ function appendToSpecificFile(filePath, version, reviewRequired = false) {
29631
29641
  return { filePath, action: "appended" };
29632
29642
  }
29633
29643
 
29644
+ // src/commands/shared.ts
29645
+ function jsonOut(success, data, errorMsg) {
29646
+ console.log(JSON.stringify(success ? { success: true, data } : { success: false, error: errorMsg }, null, 2));
29647
+ }
29648
+ function agentId(flagValue) {
29649
+ return flagValue ?? process.env["AITASKS_AGENT_ID"] ?? null;
29650
+ }
29651
+ function requireAgentId(flagValue, command = "this command") {
29652
+ const id = agentId(flagValue);
29653
+ if (!id) {
29654
+ console.error(` Agent ID required for ${command}.
29655
+ ` + ` Use --agent <id> or set AITASKS_AGENT_ID environment variable.`);
29656
+ process.exit(1);
29657
+ }
29658
+ return id;
29659
+ }
29660
+ function isJsonMode(flag) {
29661
+ return flag === true || process.env["AITASKS_JSON"] === "true";
29662
+ }
29663
+ function exitError(msg, json) {
29664
+ if (json) {
29665
+ console.log(JSON.stringify({ success: false, error: msg }, null, 2));
29666
+ } else {
29667
+ console.error(` Error: ${msg}`);
29668
+ }
29669
+ process.exit(1);
29670
+ }
29671
+ function getVersion() {
29672
+ try {
29673
+ const pkg = require_package();
29674
+ return pkg.version;
29675
+ } catch {
29676
+ return "0.0.0";
29677
+ }
29678
+ }
29679
+
29634
29680
  // src/commands/init.ts
29635
29681
  var initCommand = new Command("init").description("Initialize AITasks in the current project").option("--skip-agent-file", "Skip injecting agent instructions into CLAUDE.md/AGENTS.md/GEMINI.md").option("--with-review", "Enforce review gate: agents cannot mark tasks done without a passing review").addHelpText("after", `
29636
29682
  Examples:
@@ -29697,14 +29743,6 @@ function printAgentFileResult(result) {
29697
29743
  }
29698
29744
  console.log("");
29699
29745
  }
29700
- function getVersion() {
29701
- try {
29702
- const pkg = require_package();
29703
- return pkg.version;
29704
- } catch {
29705
- return "1.0.0";
29706
- }
29707
- }
29708
29746
 
29709
29747
  // node_modules/@clack/core/dist/index.mjs
29710
29748
  var import_sisteransi = __toESM(require_src(), 1);
@@ -30456,22 +30494,22 @@ function updateTask(id, updates) {
30456
30494
  const row = db.query(`UPDATE tasks SET ${fields.join(", ")} WHERE id = ? RETURNING *`).get(...params);
30457
30495
  return row ? parseTask(row) : null;
30458
30496
  }
30459
- function addImplementationNote(taskId, note, agentId) {
30497
+ function addImplementationNote(taskId, note, agentId2) {
30460
30498
  const task = getTask(taskId);
30461
30499
  if (!task)
30462
30500
  return null;
30463
30501
  const entry = {
30464
30502
  timestamp: Date.now(),
30465
- agent: agentId,
30503
+ agent: agentId2,
30466
30504
  note
30467
30505
  };
30468
30506
  const updated = updateTask(taskId, {
30469
30507
  implementation_notes: [...task.implementation_notes, entry]
30470
30508
  });
30471
- logEvent({ task_id: taskId, agent_id: agentId, event_type: "note_added", payload: { note } });
30509
+ logEvent({ task_id: taskId, agent_id: agentId2, event_type: "note_added", payload: { note } });
30472
30510
  return updated;
30473
30511
  }
30474
- function checkCriterion(taskId, index, evidence, agentId) {
30512
+ function checkCriterion(taskId, index, evidence, agentId2) {
30475
30513
  const task = getTask(taskId);
30476
30514
  if (!task)
30477
30515
  return { task: null, error: "Task not found" };
@@ -30488,20 +30526,20 @@ function checkCriterion(taskId, index, evidence, agentId) {
30488
30526
  passed: true,
30489
30527
  evidence,
30490
30528
  checked_at: Date.now(),
30491
- agent: agentId
30529
+ agent: agentId2
30492
30530
  };
30493
30531
  const results = task.test_results.filter((r2) => r2.index !== index);
30494
30532
  results.push(result);
30495
30533
  const updated = updateTask(taskId, { test_results: results });
30496
30534
  logEvent({
30497
30535
  task_id: taskId,
30498
- agent_id: agentId,
30536
+ agent_id: agentId2,
30499
30537
  event_type: "criterion_checked",
30500
30538
  payload: { index, criterion, evidence }
30501
30539
  });
30502
30540
  return { task: updated };
30503
30541
  }
30504
- function claimTask(taskId, agentId) {
30542
+ function claimTask(taskId, agentId2) {
30505
30543
  const s = stmts2();
30506
30544
  const task = getTask(taskId);
30507
30545
  if (!task)
@@ -30518,34 +30556,34 @@ function claimTask(taskId, agentId) {
30518
30556
  };
30519
30557
  }
30520
30558
  const now = Date.now();
30521
- s.upsertAgent.run(agentId, now, now, taskId);
30522
- const updated = updateTask(taskId, { assigned_to: agentId, status: "ready" });
30523
- logEvent({ task_id: taskId, agent_id: agentId, event_type: "claimed", payload: {} });
30559
+ s.upsertAgent.run(agentId2, now, now, taskId);
30560
+ const updated = updateTask(taskId, { assigned_to: agentId2, status: "ready" });
30561
+ logEvent({ task_id: taskId, agent_id: agentId2, event_type: "claimed", payload: {} });
30524
30562
  return { task: updated };
30525
30563
  }
30526
- function startTask(taskId, agentId) {
30564
+ function startTask(taskId, agentId2) {
30527
30565
  const s = stmts2();
30528
30566
  const task = getTask(taskId);
30529
30567
  if (!task)
30530
30568
  return { task: null, error: "Task not found" };
30531
30569
  if (task.status === "in_progress")
30532
30570
  return { task: null, error: "Task is already in progress" };
30533
- if (task.assigned_to && task.assigned_to !== agentId) {
30534
- return { task: null, error: `Task is assigned to ${task.assigned_to}, not ${agentId}` };
30571
+ if (task.assigned_to && task.assigned_to !== agentId2) {
30572
+ return { task: null, error: `Task is assigned to ${task.assigned_to}, not ${agentId2}` };
30535
30573
  }
30536
30574
  if (!task.assigned_to) {
30537
30575
  const now = Date.now();
30538
- s.upsertAgent.run(agentId, now, now, taskId);
30576
+ s.upsertAgent.run(agentId2, now, now, taskId);
30539
30577
  }
30540
30578
  const updated = updateTask(taskId, {
30541
- assigned_to: agentId,
30579
+ assigned_to: agentId2,
30542
30580
  status: "in_progress",
30543
30581
  started_at: Date.now()
30544
30582
  });
30545
- logEvent({ task_id: taskId, agent_id: agentId, event_type: "started", payload: {} });
30583
+ logEvent({ task_id: taskId, agent_id: agentId2, event_type: "started", payload: {} });
30546
30584
  return { task: updated };
30547
30585
  }
30548
- function completeTask(taskId, agentId) {
30586
+ function completeTask(taskId, agentId2) {
30549
30587
  const s = stmts2();
30550
30588
  const task = getTask(taskId);
30551
30589
  if (!task)
@@ -30571,18 +30609,18 @@ function completeTask(taskId, agentId) {
30571
30609
  ` + " Tasks cannot be moved to Done without a passing review."
30572
30610
  };
30573
30611
  }
30574
- if (task.assigned_to && task.assigned_to === agentId) {
30612
+ if (task.assigned_to && task.assigned_to === agentId2) {
30575
30613
  return {
30576
30614
  task: null,
30577
- error: `Self-approval blocked: ${agentId} is the implementing agent and cannot approve their own review.
30615
+ error: `Self-approval blocked: ${agentId2} is the implementing agent and cannot approve their own review.
30578
30616
  ` + ` A separate review sub-agent must run: aitasks done ${taskId} --agent <review-agent-id>`
30579
30617
  };
30580
30618
  }
30581
30619
  const reviewEvent = getLastReviewEvent(taskId);
30582
- if (reviewEvent?.agent_id && reviewEvent.agent_id === agentId) {
30620
+ if (reviewEvent?.agent_id && reviewEvent.agent_id === agentId2) {
30583
30621
  return {
30584
30622
  task: null,
30585
- error: `Self-approval blocked: ${agentId} submitted this task for review and cannot also approve it.
30623
+ error: `Self-approval blocked: ${agentId2} submitted this task for review and cannot also approve it.
30586
30624
  ` + ` A separate review sub-agent must run: aitasks done ${taskId} --agent <review-agent-id>`
30587
30625
  };
30588
30626
  }
@@ -30590,7 +30628,7 @@ function completeTask(taskId, agentId) {
30590
30628
  const db = s.db;
30591
30629
  const doComplete = db.transaction(() => {
30592
30630
  const updated2 = updateTask(taskId, { status: "done", completed_at: Date.now() });
30593
- logEvent({ task_id: taskId, agent_id: agentId, event_type: "completed", payload: {} });
30631
+ logEvent({ task_id: taskId, agent_id: agentId2, event_type: "completed", payload: {} });
30594
30632
  const pendingRows = db.query(`SELECT id, blocked_by FROM tasks
30595
30633
  WHERE status != 'done' AND blocked_by LIKE '%' || ? || '%'`).all(taskId);
30596
30634
  for (const row of pendingRows) {
@@ -30608,14 +30646,14 @@ function completeTask(taskId, agentId) {
30608
30646
  });
30609
30647
  }
30610
30648
  }
30611
- if (agentId)
30612
- s.releaseAgent.run(agentId);
30649
+ if (agentId2)
30650
+ s.releaseAgent.run(agentId2);
30613
30651
  return updated2;
30614
30652
  });
30615
30653
  const updated = doComplete();
30616
30654
  return { task: updated };
30617
30655
  }
30618
- function blockTask(taskId, blockerIds, agentId) {
30656
+ function blockTask(taskId, blockerIds, agentId2) {
30619
30657
  const s = stmts2();
30620
30658
  const db = s.db;
30621
30659
  const task = getTask(taskId);
@@ -30647,7 +30685,7 @@ function blockTask(taskId, blockerIds, agentId) {
30647
30685
  const updated = updateTask(taskId, { blocked_by: newBlockedBy, status: "blocked" });
30648
30686
  logEvent({
30649
30687
  task_id: taskId,
30650
- agent_id: agentId,
30688
+ agent_id: agentId2,
30651
30689
  event_type: "blocked",
30652
30690
  payload: { blocked_by: blockerIds }
30653
30691
  });
@@ -30666,7 +30704,7 @@ function detectCycleFromMap(taskId, candidateBlocker, taskMap, visited = new Set
30666
30704
  return false;
30667
30705
  return blocker.blocked_by.some((id) => detectCycleFromMap(taskId, id, taskMap, visited));
30668
30706
  }
30669
- function unblockTask(taskId, fromId, agentId) {
30707
+ function unblockTask(taskId, fromId, agentId2) {
30670
30708
  const db = stmts2().db;
30671
30709
  const task = getTask(taskId);
30672
30710
  if (!task)
@@ -30682,10 +30720,10 @@ function unblockTask(taskId, fromId, agentId) {
30682
30720
  }
30683
30721
  const newStatus = remaining.length === 0 ? "ready" : "blocked";
30684
30722
  const updated = updateTask(taskId, { blocked_by: remaining, status: newStatus });
30685
- logEvent({ task_id: taskId, agent_id: agentId, event_type: "unblocked", payload: { from: fromId } });
30723
+ logEvent({ task_id: taskId, agent_id: agentId2, event_type: "unblocked", payload: { from: fromId } });
30686
30724
  return { task: updated };
30687
30725
  }
30688
- function reviewTask(taskId, agentId) {
30726
+ function reviewTask(taskId, agentId2) {
30689
30727
  const task = getTask(taskId);
30690
30728
  if (!task)
30691
30729
  return { task: null, error: "Task not found" };
@@ -30693,17 +30731,17 @@ function reviewTask(taskId, agentId) {
30693
30731
  return { task: null, error: "Task must be in_progress to request review" };
30694
30732
  }
30695
30733
  const updated = updateTask(taskId, { status: "review" });
30696
- logEvent({ task_id: taskId, agent_id: agentId, event_type: "review_requested", payload: {} });
30734
+ logEvent({ task_id: taskId, agent_id: agentId2, event_type: "review_requested", payload: {} });
30697
30735
  return { task: updated };
30698
30736
  }
30699
- function rejectTask(taskId, reason, agentId) {
30737
+ function rejectTask(taskId, reason, agentId2) {
30700
30738
  const task = getTask(taskId);
30701
30739
  if (!task)
30702
30740
  return { task: null, error: "Task not found" };
30703
30741
  if (task.status !== "review") {
30704
30742
  return { task: null, error: "Task must be in review status to reject" };
30705
30743
  }
30706
- const agent = agentId ?? "human";
30744
+ const agent = agentId2 ?? "human";
30707
30745
  const entry = {
30708
30746
  timestamp: Date.now(),
30709
30747
  agent,
@@ -30713,30 +30751,30 @@ function rejectTask(taskId, reason, agentId) {
30713
30751
  status: "in_progress",
30714
30752
  implementation_notes: [...task.implementation_notes, entry]
30715
30753
  });
30716
- logEvent({ task_id: taskId, agent_id: agentId, event_type: "note_added", payload: { note: entry.note } });
30754
+ logEvent({ task_id: taskId, agent_id: agentId2, event_type: "note_added", payload: { note: entry.note } });
30717
30755
  logEvent({
30718
30756
  task_id: taskId,
30719
- agent_id: agentId,
30757
+ agent_id: agentId2,
30720
30758
  event_type: "rejected",
30721
30759
  payload: { reason }
30722
30760
  });
30723
30761
  return { task: updated };
30724
30762
  }
30725
- function unclaimTask(taskId, agentId, reason) {
30763
+ function unclaimTask(taskId, agentId2, reason) {
30726
30764
  const s = stmts2();
30727
30765
  const task = getTask(taskId);
30728
30766
  if (!task)
30729
30767
  return { task: null, error: "Task not found" };
30730
- if (task.assigned_to !== agentId) {
30731
- return { task: null, error: `Task is not assigned to ${agentId}` };
30768
+ if (task.assigned_to !== agentId2) {
30769
+ return { task: null, error: `Task is not assigned to ${agentId2}` };
30732
30770
  }
30733
30771
  const backStatus = task.blocked_by.length > 0 ? "blocked" : "ready";
30734
30772
  let updated;
30735
30773
  if (reason) {
30736
30774
  const entry = {
30737
30775
  timestamp: Date.now(),
30738
- agent: agentId,
30739
- note: `UNCLAIMED by ${agentId}: ${reason}`
30776
+ agent: agentId2,
30777
+ note: `UNCLAIMED by ${agentId2}: ${reason}`
30740
30778
  };
30741
30779
  updated = updateTask(taskId, {
30742
30780
  assigned_to: null,
@@ -30744,32 +30782,32 @@ function unclaimTask(taskId, agentId, reason) {
30744
30782
  started_at: null,
30745
30783
  implementation_notes: [...task.implementation_notes, entry]
30746
30784
  });
30747
- logEvent({ task_id: taskId, agent_id: agentId, event_type: "note_added", payload: { note: entry.note } });
30785
+ logEvent({ task_id: taskId, agent_id: agentId2, event_type: "note_added", payload: { note: entry.note } });
30748
30786
  } else {
30749
30787
  updated = updateTask(taskId, { assigned_to: null, status: backStatus, started_at: null });
30750
30788
  }
30751
- s.releaseAgent.run(agentId);
30789
+ s.releaseAgent.run(agentId2);
30752
30790
  logEvent({
30753
30791
  task_id: taskId,
30754
- agent_id: agentId,
30792
+ agent_id: agentId2,
30755
30793
  event_type: "unclaimed",
30756
30794
  payload: { reason: reason ?? "" }
30757
30795
  });
30758
30796
  return { task: updated };
30759
30797
  }
30760
- function heartbeat(agentId, taskId) {
30798
+ function heartbeat(agentId2, taskId) {
30761
30799
  const now = Date.now();
30762
- stmts2().heartbeat.run(agentId, now, now, taskId ?? null);
30800
+ stmts2().heartbeat.run(agentId2, now, now, taskId ?? null);
30763
30801
  }
30764
30802
  function listAgents() {
30765
30803
  const db = stmts2().db;
30766
30804
  return db.query("SELECT * FROM agents ORDER BY last_seen DESC").all();
30767
30805
  }
30768
- function getNextTask(agentId) {
30806
+ function getNextTask(agentId2) {
30769
30807
  const db = stmts2().db;
30770
- if (agentId) {
30808
+ if (agentId2) {
30771
30809
  const mine = db.query(`SELECT * FROM tasks WHERE status = 'ready' AND assigned_to = ?
30772
- ORDER BY ${PRIORITY_ORDER}, created_at ASC LIMIT 1`).get(agentId);
30810
+ ORDER BY ${PRIORITY_ORDER}, created_at ASC LIMIT 1`).get(agentId2);
30773
30811
  if (mine)
30774
30812
  return parseTask(mine);
30775
30813
  }
@@ -30796,7 +30834,7 @@ function getStats() {
30796
30834
  }
30797
30835
  return { by_status, by_priority, by_type, total };
30798
30836
  }
30799
- function deleteTask(taskId, agentId) {
30837
+ function deleteTask(taskId, agentId2) {
30800
30838
  const s = stmts2();
30801
30839
  const db = s.db;
30802
30840
  const task = getTask(taskId);
@@ -30813,7 +30851,7 @@ function deleteTask(taskId, agentId) {
30813
30851
  const doDelete = db.transaction(() => {
30814
30852
  logEvent({
30815
30853
  task_id: taskId,
30816
- agent_id: agentId,
30854
+ agent_id: agentId2,
30817
30855
  event_type: "deleted",
30818
30856
  payload: {}
30819
30857
  });
@@ -30837,34 +30875,6 @@ function deleteTask(taskId, agentId) {
30837
30875
  return { success: true };
30838
30876
  }
30839
30877
 
30840
- // src/commands/shared.ts
30841
- function jsonOut(success, data, errorMsg) {
30842
- console.log(JSON.stringify(success ? { success: true, data } : { success: false, error: errorMsg }, null, 2));
30843
- }
30844
- function agentId(flagValue) {
30845
- return flagValue ?? process.env["AITASKS_AGENT_ID"] ?? null;
30846
- }
30847
- function requireAgentId(flagValue, command = "this command") {
30848
- const id = agentId(flagValue);
30849
- if (!id) {
30850
- console.error(` Agent ID required for ${command}.
30851
- ` + ` Use --agent <id> or set AITASKS_AGENT_ID environment variable.`);
30852
- process.exit(1);
30853
- }
30854
- return id;
30855
- }
30856
- function isJsonMode(flag) {
30857
- return flag === true || process.env["AITASKS_JSON"] === "true";
30858
- }
30859
- function exitError(msg, json) {
30860
- if (json) {
30861
- console.log(JSON.stringify({ success: false, error: msg }, null, 2));
30862
- } else {
30863
- console.error(` Error: ${msg}`);
30864
- }
30865
- process.exit(1);
30866
- }
30867
-
30868
30878
  // src/commands/create.ts
30869
30879
  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) => {
30870
30880
  requireInitialized();
@@ -42397,7 +42407,8 @@ var TreeBoardComponent = ({ getTasks }) => {
42397
42407
  }
42398
42408
  return bar;
42399
42409
  })();
42400
- const taskCountLabel = searchQuery ? `${filteredTasks.length} of ${tasks.length}` : `${tasks.length}`;
42410
+ const doneCount = tasks.filter((t) => t.status === "done").length;
42411
+ const taskCountLabel = searchQuery ? `${filteredTasks.length} of ${tasks.length}` : `${doneCount}/${tasks.length}`;
42401
42412
  const searchMode = mode === "search";
42402
42413
  return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
42403
42414
  flexDirection: "column",
@@ -42919,7 +42930,7 @@ var exportCommand = new Command("export").description("Export all task data").op
42919
42930
  });
42920
42931
 
42921
42932
  // src/commands/onboard.ts
42922
- var VERSION = "1.0.0";
42933
+ var VERSION = getVersion();
42923
42934
  var onboardCommand = new Command("onboard").description("Print or inject agent protocol instructions").option("--append", "Auto-detect and append to CLAUDE.md/AGENTS.md/GEMINI.md").option("--file <path>", "Append to a specific file").option("--json", "Output the instructions as a JSON string").action((opts) => {
42924
42935
  const reviewRequired = isInitialized() ? getReviewRequired() : false;
42925
42936
  const instructions = getAgentInstructions(VERSION, { reviewRequired });
@@ -43514,4 +43525,4 @@ program2.parseAsync(process.argv).catch((err) => {
43514
43525
  process.exit(1);
43515
43526
  });
43516
43527
 
43517
- //# debugId=55B7B23CFF99871064756E2164756E21
43528
+ //# debugId=96EAA57A05142DDB64756E2164756E21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aitasks",
3
- "version": "1.4.2",
3
+ "version": "1.4.4",
4
4
  "description": "CLI task management tool built for AI agents",
5
5
  "type": "module",
6
6
  "bin": {