@erclx/aitk 3.37.0 → 3.37.1
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/docs/agents/records.md
CHANGED
|
@@ -134,7 +134,7 @@ aitk records pull
|
|
|
134
134
|
|
|
135
135
|
The backed folders are `diagrams`, `groundwork`, `intake`, `memory`, `plans`, `proposals`, `review`, `tasks`, and `teach`, all under `.claude/`. Seven of them are the Claude ignore group the claude manifest ships, minus three entries: `.claude/.tmp`, which is deletable without loss, `.claude/worktrees/`, whose contents belong to the project repository already, and `.claude/.records.git/`, which is the history the rest are pushed into. `diagrams` and `proposals` are the two that group does not carry at all, since a target still tracks its own copies of both, which is why the list is spelled out rather than derived. Each name is a top-level record folder and every archive sits inside the one it archives, so the list stays at one entry per surface however many archives appear. It is a constant rather than configuration, and it deliberately does not match the six record kinds `validate` hardcodes.
|
|
136
136
|
|
|
137
|
-
Records are gitignored by design, so the history lives in a second git directory at `.claude/.records.git` with `.claude/` as its work tree. Every path stays where it is, which is what a separate checkout could not do. The verbs stage the nine folders by explicit pathspec with `--force`, so nothing outside them can enter the index however the ignore rules read, and the project working tree and its index are never touched.
|
|
137
|
+
Records are gitignored by design, so the history lives in a second git directory at `.claude/.records.git` with `.claude/` as its work tree. Every path stays where it is, which is what a separate checkout could not do. The verbs stage the nine folders by explicit pathspec with `--force`, so nothing outside them can enter the index however the ignore rules read, and the project working tree and its index are never touched. Each pathspec is a bare folder name and git reads it against the current directory rather than against the work tree the same call names, so the invocation carries `-C` at the work tree beside the other two flags. That is what lets either verb run from a linked worktree under `.claude/worktrees/`, which sits inside the records work tree and would otherwise prefix every name with its own path.
|
|
138
138
|
|
|
139
139
|
### Setup
|
|
140
140
|
|
package/docs/agents/tasks.md
CHANGED
|
@@ -28,6 +28,10 @@ Exit codes: `0` archived, `1` refused. Every gate is a refusal rather than a war
|
|
|
28
28
|
|
|
29
29
|
`bad-input` covers a malformed command line, which all three task verbs answer the same way. It is separate from `ambiguous` and `no-match` because those describe the board, and a caller that passed two selectors would otherwise be sent to repair a task citation that is fine.
|
|
30
30
|
|
|
31
|
+
The row is matched by the link in its first cell rather than by a pattern against the whole line. A row names the task it is about in the first cell, so a link anywhere after it is a reference, such as a blocker naming what it waits on, and matching the line would drop the referring task's row too.
|
|
32
|
+
|
|
33
|
+
The row removal reaches `priority.md` alone. A task gets to a merge by being planned and handed out, and both steps move it onto the board first, so one archived straight off `backlog.md` leaves its bullet standing and `aitk tasks validate` reports that bullet as naming a file that is gone.
|
|
34
|
+
|
|
31
35
|
The board is shared scratch at the main worktree root, so `--root` defaults to the first entry of `git worktree list` rather than the working directory. A linked worktree archives against the same board every other session reads.
|
|
32
36
|
|
|
33
37
|
Skills branch on the reason rather than on the exit code:
|
|
@@ -47,6 +51,8 @@ aitk tasks archive --pull-request 673 --json | jq -r 'if .ok then .task else .re
|
|
|
47
51
|
|
|
48
52
|
The record carries `location`, one of `unstated`, `live`, `archived`, or `outside`, and `citedBy`, the other live tasks whose `Plan:` line lands on the same file. Exit codes: `0` read, `1` refused with `no-board` or `no-match`.
|
|
49
53
|
|
|
54
|
+
The target resolves against `.claude/tasks/` and against the project root both, so `../plans/x.md` and `.claude/plans/x.md` land on the same file and one plan two tasks spelled differently counts once.
|
|
55
|
+
|
|
50
56
|
`aitk tasks archive` gates on this same answer, so a caller wanting the count reads it here rather than scanning the board. The `claude-docs` plans sweep is the exception and still states the rule in its own body, because a plugin skill reaches a target on merge while the CLI reaches one on release, so a sweep calling a verb the installed `aitk` predates gets no record back and archives nothing.
|
|
51
57
|
|
|
52
58
|
Branch on `reason` rather than on the exit code, which is the rule the archive section above already states and which this verb needs for a second reason. An operator's shell profile may wrap `aitk` in a function that runs the binary and then another command and takes the second status, which masks every non-zero exit rather than only an absent verb. The binary exits 1 for an unknown subcommand and 1 for an ordinary refusal alike, so the record is the only signal that survives the wrapper.
|
package/package.json
CHANGED
package/src/records/backup.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
|
-
import { join } from 'node:path'
|
|
2
|
+
import { join, resolve } from 'node:path'
|
|
3
3
|
import { $ } from 'bun'
|
|
4
4
|
import { gitEnv } from '@/git-env'
|
|
5
5
|
|
|
@@ -124,19 +124,30 @@ interface GitResult {
|
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
/**
|
|
127
|
-
* Runs one git command against the records history.
|
|
127
|
+
* Runs one git command against the records history, from the work tree.
|
|
128
128
|
*
|
|
129
|
-
*
|
|
129
|
+
* All three flags go on every call. `git --git-dir=<path> init` writes
|
|
130
130
|
* `core.bare = true`, and an explicit `--work-tree` is what overrides it, so
|
|
131
|
-
* dropping
|
|
131
|
+
* dropping that flag on a single call reads the enclosing project as the tree
|
|
132
132
|
* and stages everything in it.
|
|
133
|
+
*
|
|
134
|
+
* `-C` is what makes a bare pathspec like `groundwork` mean the work-tree root
|
|
135
|
+
* wherever the caller stands. Git derives a pathspec prefix from the current
|
|
136
|
+
* directory, so without it a caller sitting inside `.claude/`, which is every
|
|
137
|
+
* session in a linked worktree under `.claude/worktrees/<name>/`, prefixes
|
|
138
|
+
* each name with its own path and matches nothing. The root a caller names
|
|
139
|
+
* does not reach that prefix, so `--root` cannot stand in for this.
|
|
140
|
+
*
|
|
141
|
+
* Both paths are absolute because `-C` takes effect before the other two flags
|
|
142
|
+
* are read, so a relative root would otherwise send them looking inside the
|
|
143
|
+
* work tree.
|
|
133
144
|
*/
|
|
134
145
|
async function records(root: string, args: string[]): Promise<GitResult> {
|
|
135
|
-
const gitDir =
|
|
136
|
-
const workTree =
|
|
146
|
+
const gitDir = resolve(root, RECORDS_GIT_DIR)
|
|
147
|
+
const workTree = resolve(root, WORK_TREE)
|
|
137
148
|
|
|
138
149
|
const result =
|
|
139
|
-
await $`git --git-dir=${gitDir} --work-tree=${workTree} ${args}`
|
|
150
|
+
await $`git -C ${workTree} --git-dir=${gitDir} --work-tree=${workTree} ${args}`
|
|
140
151
|
.env(gitEnv())
|
|
141
152
|
.quiet()
|
|
142
153
|
.nothrow()
|
package/standards/tasks.md
CHANGED
|
@@ -133,13 +133,7 @@ Add no fourth readiness group in place of this file. The three group names are t
|
|
|
133
133
|
|
|
134
134
|
## Validation
|
|
135
135
|
|
|
136
|
-
`aitk tasks validate` reads the
|
|
137
|
-
|
|
138
|
-
A cited task is settled by being archived, or by closing every outcome and carrying a `Pull request:` line the trunk holds. The closed checkbox alone settles nothing, because the ship chain marks outcomes as its first step and opens the pull request several steps later, so a row read off the checkbox reports settled while the branch is still in review. A task that closed every outcome and names no pull request, and one whose pull request the run could not read against the trunk, are both reported as untested. Degrading either back to the checkbox would reproduce the defect under a name claiming it was fixed.
|
|
139
|
-
|
|
140
|
-
The trunk is read as the clone already holds it, `origin/main` first and local `main` behind it, and no run fetches. A validate happens several times a sweep and a fetch per run is a cost this check does not carry, so a clone behind the remote under-reports rather than claiming work landed.
|
|
141
|
-
|
|
142
|
-
A task file is accounted for when a row on `priority.md` or a line on `backlog.md` names it, and reported when neither does. One check across both surfaces is what lets a task move between them without the move looking like a dropped file, and a task named by both is reported for the same reason a task in two groups is: it claims two things about itself and only one of them can hold. A project carrying no `backlog.md` is read as an empty backlog rather than refused, which leaves the one-to-one mapping this check ran before the second surface existed.
|
|
136
|
+
`aitk tasks validate` reads the board against the tree, and what it checks, what it refuses on, and what it reports are at `docs/agents/tasks.md`. Run it when the readiness claim is made rather than on a schedule, since the board is gitignored per-machine scratch and no shared moment exists to hang it on.
|
|
143
137
|
|
|
144
138
|
## Filenames
|
|
145
139
|
|
|
@@ -247,30 +241,14 @@ The line is what lets a merge close its own task. Every merge on `main` is a squ
|
|
|
247
241
|
|
|
248
242
|
## Archiving
|
|
249
243
|
|
|
250
|
-
Never delete a task file. A shipped task moves to `.claude/tasks/archive/` under its own name, and the live index regenerates without it. `aitk tasks archive` owns
|
|
244
|
+
Never delete a task file. A shipped task moves to `.claude/tasks/archive/` under its own name, and the live index regenerates without it. `aitk tasks archive` owns that move, and what it does and what it refuses on are at `docs/agents/tasks.md`.
|
|
251
245
|
|
|
252
246
|
The archive nests inside `.claude/tasks/` rather than sitting beside it as a flat `.claude/task-archive/`. Nesting is what lets a reader tell the two shapes apart on sight: the flat sibling is what a binary predating this convention still writes, so meeting one names an older checkout rather than a second archive to reconcile against this one.
|
|
253
247
|
|
|
254
|
-
Two callers reach that command. The `claude-tasks` skill runs it inside a session, and the `post-merge` hook runs it unattended after a pull that merged the work. Both go through the command rather than moving the file themselves, so the two paths cannot drift into archiving differently. Every gate the command applies refuses with a non-zero exit rather than reporting, because a caller with nobody watching cannot act on a warning.
|
|
255
|
-
|
|
256
248
|
One destination rather than a per-project choice is what lets the move happen without asking. It mirrors the plans archive at `.claude/plans/archive/`, sitting inside the folder it archives the same way, and it inherits the board's own ignore entry rather than needing one of its own. The cost is that an archived task does not appear in diffs, which is the cost the live board already carries.
|
|
257
249
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
Archiving a task does not archive its plan. `claude-docs` owns the plans sweep and moves a plan only when the closing task is its last live citation. The archive clears the task's row from `priority.md` itself, since a shipped task left in the ordering reads as ready to hand a worker. It leaves prose naming the task alone for a person to resolve.
|
|
261
|
-
|
|
262
|
-
The row is matched by the link in its first cell rather than by a pattern against the whole line. A row names the task it is about in the first cell, so a link anywhere after that is a reference, such as a blocker pointing at what it waits on. Matching the line would delete the referring task's row too, on a board that is gitignored and has nothing to recover it from.
|
|
263
|
-
|
|
264
|
-
Sweep the plan before archiving the task. The sweep finds its work by scanning the live folder, so a task archived first is beyond its reach for good, and the plan is left with no live task citing it and an archived task pointing at a path nothing will retarget. The archive refuses the last task pointing at a live plan for that reason, which puts the ordering under a gate rather than under a convention the unattended caller cannot follow.
|
|
265
|
-
|
|
266
|
-
The gate counts the other live tasks citing the same plan rather than reading which folder the plan sits in. A plan several tasks share stays in the live folder by design, because the sweep is correct to leave a plan another live task still cites, so a gate reading the folder alone refuses every one of those tasks and the board and the sweep block each other with neither in the wrong. Counting the citations asks the question the gate means: a plan nothing else holds is one the sweep has yet to reach, and a plan a sibling still holds is one the sweep already decided about.
|
|
267
|
-
|
|
268
|
-
The count resolves the target against `.claude/tasks/` and against the project root both, so `../plans/x.md` and `.claude/plans/x.md` land on the same file and one plan two tasks spelled differently counts once. `aitk tasks plan-citations` exposes that count for a caller that wants it, and the gate reads it.
|
|
269
|
-
|
|
270
|
-
The `claude-docs` sweep states the rule rather than calling that verb, which is a duplication accepted with a reason rather than an oversight. A skill reaches a target the moment it merges and the CLI reaches one only when a release publishes, so a body calling a verb the installed `aitk` predates gets no record back and sweeps nothing. The two spellings therefore have to agree by hand until a release carries the verb, and the failure they guard against is a plan stranded by the form its citation was written in.
|
|
271
|
-
|
|
272
|
-
A caller reads the outcome off the record's `reason` field and never off the exit code. An operator's shell profile may wrap `aitk` in a function that runs the binary and then another command, taking its status from the second, which masks an ordinary refusal exactly as it masks an absent verb.
|
|
250
|
+
Archiving a task does not archive its plan. `claude-docs` owns the plans sweep and moves a plan only when the closing task is its last live citation, so the sweep runs before the archive rather than after it. The sweep finds its work by scanning the live folder, and a task archived first is beyond its reach for good, leaving the plan with no live task citing it and an archived task pointing at a path nothing will retarget.
|
|
273
251
|
|
|
274
|
-
|
|
252
|
+
The `claude-docs` sweep states that ordering in its own body rather than reading it back from a command, which is a duplication accepted with a reason rather than an oversight. A skill reaches a target the moment it merges and the CLI reaches one only when a release publishes, so a body calling a verb the installed `aitk` predates gets no record back and sweeps nothing. The two spellings therefore have to agree by hand until a release carries the verb, and the failure they guard against is a plan stranded by the form its citation was written in.
|
|
275
253
|
|
|
276
254
|
A task with an open outcome stays on the board. Close it, or cut it from the task when the work is being abandoned, so what was dropped is recorded rather than inferred from an archived file. The sweep is gated on the same condition, so archiving around an open outcome also leaves the plan behind.
|