aitasks 1.4.5 → 1.4.6

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 +61 -1
  2. package/dist/index.js +86 -9
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -67,6 +67,21 @@ export AITASKS_JSON=true
67
67
 
68
68
  ---
69
69
 
70
+ ## Global Options
71
+
72
+ | Option | Description |
73
+ |---|---|
74
+ | `-C, --dir <path>` | Run as if `aitasks` were started in `<path>` instead of the current directory |
75
+ | `--json` | Output machine-readable JSON (available on most commands) |
76
+ | `--version` | Print the installed version |
77
+ | `--help` | Show help for any command, e.g. `aitasks update --help` |
78
+
79
+ ```sh
80
+ aitasks -C /path/to/project board
81
+ ```
82
+
83
+ ---
84
+
70
85
  ## Commands
71
86
 
72
87
  ### Setup
@@ -75,6 +90,7 @@ export AITASKS_JSON=true
75
90
  |---|---|
76
91
  | `aitasks init` | Initialize a task database in the current project |
77
92
  | `aitasks init --with-review` | Initialize with review enforcement (agents cannot mark done without a passing review) |
93
+ | `aitasks init --update` | Refresh the agent instructions block in an existing CLAUDE.md / AGENTS.md / GEMINI.md to the latest version |
78
94
  | `aitasks onboard` | Print or inject agent protocol instructions into CLAUDE.md / AGENTS.md |
79
95
 
80
96
  ### Task Discovery
@@ -82,7 +98,7 @@ export AITASKS_JSON=true
82
98
  | Command | Description |
83
99
  |---|---|
84
100
  | `aitasks list` | List all tasks, sorted by priority |
85
- | `aitasks list --status ready` | Filter by status (`ready`, `in_progress`, `blocked`, `review`, `done`) |
101
+ | `aitasks list --status ready` | Filter by status (`backlog`, `ready`, `in_progress`, `blocked`, `review`, `done`) |
86
102
  | `aitasks next` | Show the highest-priority unblocked ready task |
87
103
  | `aitasks next --claim --agent <id>` | Auto-claim and start the best task |
88
104
  | `aitasks show <id>` | Full detail on a specific task (includes time tracking) |
@@ -99,6 +115,7 @@ export AITASKS_JSON=true
99
115
  | `aitasks start <id...> --agent <id>` | Begin active work on task(s) |
100
116
  | `aitasks note <id> <text>` | Add an implementation note |
101
117
  | `aitasks check <id> <n> --evidence <text>` | Verify acceptance criterion n |
118
+ | `aitasks update <id>` | Update task fields (title, description, priority, type, status, acceptance criteria) — see [`update` Flags](#update-flags) |
102
119
  | `aitasks done <id...> --agent <id>` | Mark task(s) complete (all criteria must be verified; must be in `review` status if enforcement is on) |
103
120
  | `aitasks review <id...> --agent <id>` | Submit task(s) for review (moves to `review` status) |
104
121
  | `aitasks reject <id> --reason <text>` | Reject a task in review, send it back to `in_progress` with feedback |
@@ -148,6 +165,41 @@ aitasks create \
148
165
 
149
166
  ---
150
167
 
168
+ ## `update` Flags
169
+
170
+ Change any field on an existing task:
171
+
172
+ ```sh
173
+ aitasks update TASK-001 \
174
+ --title "New title" \ # Replace the title
175
+ --desc "New description" \ # Replace the description
176
+ --priority high \ # critical | high | medium | low
177
+ --type bug \ # feature | bug | chore | spike
178
+ --status ready # Manually override status (use with care)
179
+ ```
180
+
181
+ ### Editing acceptance criteria
182
+
183
+ Criterion indices are **0-based**, matching what `aitasks show` and `aitasks check` display. Use **only one** of these flags per invocation:
184
+
185
+ | Flag | Effect |
186
+ |---|---|
187
+ | `--ac <text>` | **Append** a new criterion (repeatable). Does *not* replace existing ones — re-passing an existing criterion duplicates it. |
188
+ | `--set-ac <index>=<text>` | Replace just the criterion at `<index>` in place. |
189
+ | `--remove-ac <index>` | Delete the criterion at `<index>`. |
190
+ | `--replace-ac <list>` | Overwrite the **entire** list (newline-separated). |
191
+
192
+ ```sh
193
+ aitasks update TASK-001 --ac "New criterion to append"
194
+ aitasks update TASK-001 --set-ac 1="Returns 404 with a JSON error body"
195
+ aitasks update TASK-001 --remove-ac 2
196
+ aitasks update TASK-001 --replace-ac $'First criterion\nSecond criterion\nThird criterion'
197
+ ```
198
+
199
+ > **Re-verify after editing.** `--set-ac` clears any prior verification of that criterion (since the wording changed), and `--remove-ac` re-indexes the remaining verifications. Run `aitasks check` again for affected criteria before marking the task done.
200
+
201
+ ---
202
+
151
203
  ## Agent Protocol
152
204
 
153
205
  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`.
@@ -163,6 +215,14 @@ aitasks onboard --json # output as JSON string
163
215
 
164
216
  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
217
 
218
+ **Updating after an upgrade:** Re-running `aitasks init` on a project whose agent file already contains instructions leaves them untouched (and prints a hint). To pull the latest protocol after upgrading `aitasks`, run:
219
+
220
+ ```sh
221
+ aitasks init --update
222
+ ```
223
+
224
+ This replaces only the block between the `<!-- aitasks:instructions -->` markers in place — the rest of your `CLAUDE.md` / `AGENTS.md` is preserved.
225
+
166
226
  ---
167
227
 
168
228
  ## Review Enforcement
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.4.5",
1893
+ version: "1.4.6",
1894
1894
  description: "CLI task management tool built for AI agents",
1895
1895
  type: "module",
1896
1896
  bin: {
@@ -29402,6 +29402,18 @@ Creating subtasks:
29402
29402
  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
29403
29403
  \`\`\`
29404
29404
 
29405
+ Editing acceptance criteria (if the requirements change or were worded wrong):
29406
+ \`\`\`bash
29407
+ aitasks update TASK-001 --ac "A brand-new criterion to append" # add one
29408
+ aitasks update TASK-001 --set-ac 1="Returns 404 with a JSON error body" # fix criterion #1 in place
29409
+ aitasks update TASK-001 --remove-ac 2 # delete criterion #2
29410
+ aitasks update TASK-001 --replace-ac $'first\\nsecond\\nthird' # replace the whole list
29411
+ \`\`\`
29412
+ Indices are 0-based (matching \`aitasks show\` and \`aitasks check\`). Use exactly one of these
29413
+ flags per call. \`--ac\` only APPENDS \u2014 re-passing existing criteria duplicates them; use
29414
+ \`--set-ac\` to correct one criterion or \`--replace-ac\` to rewrite all of them. After
29415
+ \`--set-ac\`, re-run \`aitasks check\` for that index since editing the wording clears its prior verification.
29416
+
29405
29417
  If you discover your task is blocked by something:
29406
29418
  \`\`\`bash
29407
29419
  aitasks block TASK-001 --on TASK-002,TASK-003
@@ -29540,7 +29552,11 @@ aitasks show <id> Full task detail (includes time trac
29540
29552
  aitasks search <query> Search titles, descriptions, notes
29541
29553
  aitasks deps <id> Show dependency tree
29542
29554
  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
29555
+ aitasks update <id> [--status|--priority|--title|--desc|--type] Update task fields
29556
+ aitasks update <id> --ac <text> Append a new acceptance criterion
29557
+ aitasks update <id> --set-ac <n>=<text> Replace a single criterion at index n (0-based)
29558
+ aitasks update <id> --remove-ac <n> Remove a single criterion at index n (0-based)
29559
+ aitasks update <id> --replace-ac <list> Replace ALL criteria (newline-separated)
29544
29560
  aitasks claim <id...> --agent <id> Claim task(s) - supports patterns like TASK-0*
29545
29561
  aitasks start <id...> --agent <id> Begin work on task(s)
29546
29562
  aitasks note <id> <text> --agent <id> Add implementation note
@@ -29587,7 +29603,7 @@ function injectOrCreateAgentFile(projectRoot, version, reviewRequired = false, f
29587
29603
  return { filePath: existing, action: "skipped" };
29588
29604
  const replaced = replaceInstructionsBlock(content, instructions);
29589
29605
  writeFileSync2(existing, replaced, "utf8");
29590
- return { filePath: existing, action: "appended" };
29606
+ return { filePath: existing, action: "updated" };
29591
29607
  }
29592
29608
  const separator = content.endsWith(`
29593
29609
  `) ? `
@@ -29678,7 +29694,7 @@ function getVersion() {
29678
29694
  }
29679
29695
 
29680
29696
  // src/commands/init.ts
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", `
29697
+ 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").option("--update", "Refresh the agent instructions block in an existing CLAUDE.md/AGENTS.md/GEMINI.md to the latest version").addHelpText("after", `
29682
29698
  Examples:
29683
29699
  $ aitasks init
29684
29700
  Initialize in current directory, inject agent instructions into CLAUDE.md/AGENTS.md.
@@ -29689,6 +29705,11 @@ Examples:
29689
29705
  marked done. Running this on an existing project also updates the agent
29690
29706
  instructions file with the review workflow.
29691
29707
 
29708
+ $ aitasks init --update
29709
+ Re-inject the latest agent instructions, replacing the existing block
29710
+ between the AITasks markers in place. The rest of the file is left
29711
+ untouched. Use after upgrading aitasks to pull new protocol docs.
29712
+
29692
29713
  $ aitasks init --skip-agent-file
29693
29714
  Initialize without touching any CLAUDE.md / AGENTS.md file.`).action(async (opts) => {
29694
29715
  const root = findProjectRoot();
@@ -29701,7 +29722,8 @@ Examples:
29701
29722
  console.log(source_default.green(" \u2713") + " Review enforcement enabled.");
29702
29723
  }
29703
29724
  if (!opts.skipAgentFile) {
29704
- const result = injectOrCreateAgentFile(root, getVersion(), !!opts.withReview, !!opts.withReview);
29725
+ const force = !!opts.withReview || !!opts.update;
29726
+ const result = injectOrCreateAgentFile(root, getVersion(), !!opts.withReview, force);
29705
29727
  printAgentFileResult(result);
29706
29728
  }
29707
29729
  return;
@@ -29722,7 +29744,7 @@ Examples:
29722
29744
  }
29723
29745
  console.log("");
29724
29746
  if (!opts.skipAgentFile) {
29725
- const result = injectOrCreateAgentFile(root, getVersion(), !!opts.withReview);
29747
+ const result = injectOrCreateAgentFile(root, getVersion(), !!opts.withReview, !!opts.update);
29726
29748
  printAgentFileResult(result);
29727
29749
  }
29728
29750
  console.log(source_default.dim(" Run `aitasks create` to add your first task."));
@@ -29737,8 +29759,12 @@ function printAgentFileResult(result) {
29737
29759
  case "appended":
29738
29760
  console.log(source_default.green(" \u2713") + ` Appended agent instructions to ${source_default.bold(rel)}`);
29739
29761
  break;
29762
+ case "updated":
29763
+ console.log(source_default.green(" \u2713") + ` Updated agent instructions in ${source_default.bold(rel)}`);
29764
+ break;
29740
29765
  case "skipped":
29741
29766
  console.log(source_default.dim(` \u2500 ${rel} already contains AITasks instructions`));
29767
+ console.log(source_default.dim(` Run \`aitasks init --update\` to refresh them to the latest version.`));
29742
29768
  break;
29743
29769
  }
29744
29770
  console.log("");
@@ -41672,7 +41698,20 @@ var nextCommand = new Command("next").description("Show the next best task to wo
41672
41698
  });
41673
41699
 
41674
41700
  // src/commands/update.ts
41675
- var updateCommand = new Command("update").description("Update task fields").argument("<taskId>", "Task ID").option("-t, --title <title>", "New title").option("-d, --desc <description>", "New description").option("-a, --ac <criterion>", "Add an acceptance criterion (repeatable)", collect2, []).option("--replace-ac <criteria>", "Replace ALL acceptance criteria (newline-separated)").option("-p, --priority <priority>", "New priority: critical|high|medium|low").option("--type <type>", "New type: feature|bug|chore|spike").option("--status <status>", "Manually set status (use with care)").option("--json", "Output as JSON").action((taskId, opts) => {
41701
+ var updateCommand = new Command("update").description("Update task fields").argument("<taskId>", "Task ID").option("-t, --title <title>", "New title").option("-d, --desc <description>", "New description").option("-a, --ac <criterion>", "Add an acceptance criterion (repeatable)", collect2, []).option("--replace-ac <criteria>", "Replace ALL acceptance criteria (newline-separated)").option("--set-ac <index=text>", 'Replace a single acceptance criterion by 0-based index, e.g. --set-ac 1="New text"').option("--remove-ac <index>", "Remove a single acceptance criterion by 0-based index").option("-p, --priority <priority>", "New priority: critical|high|medium|low").option("--type <type>", "New type: feature|bug|chore|spike").option("--status <status>", "Manually set status (use with care)").option("--json", "Output as JSON").addHelpText("after", `
41702
+ Acceptance criteria editing:
41703
+ --ac <text> Append a new criterion (repeatable). Does NOT replace existing ones.
41704
+ --set-ac <index=text> Replace just the criterion at <index> (0-based). Re-verify it afterward \u2014
41705
+ any prior verification of that criterion is cleared since the wording changed.
41706
+ --remove-ac <index> Delete the criterion at <index> (0-based). Verifications are re-indexed.
41707
+ --replace-ac <list> Overwrite the entire list (newline-separated).
41708
+
41709
+ Only one acceptance-criteria mode may be used per invocation.
41710
+
41711
+ Examples:
41712
+ $ aitasks update TASK-001 --set-ac 1="Returns 404 with a JSON error body"
41713
+ $ aitasks update TASK-001 --remove-ac 2
41714
+ $ aitasks update TASK-001 --ac "New criterion to append"`).action((taskId, opts) => {
41676
41715
  requireInitialized();
41677
41716
  const json = isJsonMode(opts.json);
41678
41717
  const id = taskId.toUpperCase();
@@ -41690,11 +41729,39 @@ var updateCommand = new Command("update").description("Update task fields").argu
41690
41729
  changes.type = opts.type;
41691
41730
  if (opts.status)
41692
41731
  changes.status = opts.status;
41693
- if (opts.replaceAc) {
41732
+ const acModes = [
41733
+ opts.ac.length > 0,
41734
+ opts.replaceAc !== undefined,
41735
+ opts.setAc !== undefined,
41736
+ opts.removeAc !== undefined
41737
+ ].filter(Boolean).length;
41738
+ if (acModes > 1) {
41739
+ exitError("Use only one of --ac, --replace-ac, --set-ac, or --remove-ac per invocation.", json);
41740
+ }
41741
+ if (opts.replaceAc !== undefined) {
41694
41742
  changes.acceptance_criteria = opts.replaceAc.split(`
41695
41743
  `).map((s) => s.trim()).filter(Boolean);
41696
41744
  } else if (opts.ac.length > 0) {
41697
41745
  changes.acceptance_criteria = [...task.acceptance_criteria, ...opts.ac];
41746
+ } else if (opts.setAc !== undefined) {
41747
+ const eq = opts.setAc.indexOf("=");
41748
+ if (eq < 0) {
41749
+ exitError('--set-ac requires the format <index>=<text>, e.g. --set-ac 1="New criterion".', json);
41750
+ }
41751
+ const index = parseCriterionIndex(opts.setAc.slice(0, eq), task.acceptance_criteria.length, json);
41752
+ const text = opts.setAc.slice(eq + 1).trim();
41753
+ if (!text)
41754
+ exitError("--set-ac text cannot be empty.", json);
41755
+ const criteria = [...task.acceptance_criteria];
41756
+ criteria[index] = text;
41757
+ changes.acceptance_criteria = criteria;
41758
+ if (task.test_results.some((r2) => r2.index === index)) {
41759
+ changes.test_results = task.test_results.filter((r2) => r2.index !== index);
41760
+ }
41761
+ } else if (opts.removeAc !== undefined) {
41762
+ const index = parseCriterionIndex(opts.removeAc, task.acceptance_criteria.length, json);
41763
+ changes.acceptance_criteria = task.acceptance_criteria.filter((_2, i) => i !== index);
41764
+ changes.test_results = task.test_results.filter((r2) => r2.index !== index).map((r2) => r2.index > index ? { ...r2, index: r2.index - 1 } : r2);
41698
41765
  }
41699
41766
  if (Object.keys(changes).length === 0) {
41700
41767
  exitError("No changes specified. Use --help to see available options.", json);
@@ -41716,6 +41783,16 @@ function collect2(val, acc) {
41716
41783
  acc.push(val);
41717
41784
  return acc;
41718
41785
  }
41786
+ function parseCriterionIndex(raw, total, json) {
41787
+ const index = parseInt(raw.trim(), 10);
41788
+ if (isNaN(index) || index < 0) {
41789
+ exitError(`Invalid criterion index "${raw.trim()}". Use a non-negative integer: 0, 1, 2, \u2026`, json);
41790
+ }
41791
+ if (index >= total) {
41792
+ exitError(`Index ${index} out of range \u2014 task has ${total} criteria (0-based, so valid range is 0\u2013${total - 1}).`, json);
41793
+ }
41794
+ return index;
41795
+ }
41719
41796
 
41720
41797
  // src/display/board.tsx
41721
41798
  var import_react29 = __toESM(require_react(), 1);
@@ -43533,4 +43610,4 @@ program2.parseAsync(process.argv).catch((err) => {
43533
43610
  process.exit(1);
43534
43611
  });
43535
43612
 
43536
- //# debugId=DD10AE067D1A79CC64756E2164756E21
43613
+ //# debugId=49CA369B086466F464756E2164756E21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aitasks",
3
- "version": "1.4.5",
3
+ "version": "1.4.6",
4
4
  "description": "CLI task management tool built for AI agents",
5
5
  "type": "module",
6
6
  "bin": {