Skip to content

Context Circuit CLI 2.4.0

Choose a tag to compare

@github-actions github-actions released this 20 Oct 20:20
· 350 commits to main since this release
2fef8d7

Context Circuit CLI 2.4.0

Every member of a workspace needs 2.4.0, and one of them goes first. The first
changing command 2.4.0 runs in an existing workspace, once setup is complete,
splits the shared .context-circuit/ids.yaml into one file per member,
.context-circuit/ids/<member>.yaml, and moves workspace.yaml from schema 2 to
schema 3. Each reservation goes to the file of its record's author; one with no
author goes to the member selected on that machine. The split is reported as a
notice and changes no command's result. Older CLIs refuse a schema 3 workspace
with "workspace schema 3 requires a newer CLI; this CLI supports schema 2", so
every member needs 2.4.0 before they pull the split.

Because the split writes every author's file, only one person on a team
upgrades first. That person makes the first changing command, commits the split,
and pushes it. Everyone else pulls before making any change. Teammates who
upgrade at the same time each write the same member files differently, and Git
reports a conflict in .context-circuit/ids/*.yaml. That conflict is theirs to
resolve by hand: keep the union of both sides' entries in each member file, then
run check, which reports any number reserved twice. A command that refuses its
own arguments, such as member add without --band, no longer splits on its way
to the refusal.

A shared ids.yaml that comes back after the split, for example merged in from
a teammate's 2.3.0 clone, is split again by the next changing command, which
adds only the reservations the member files do not already hold. check reports
a number reserved in two member files for a person to fix. Member IDs that are
Windows device names, such as con or nul, are refused, because no clone on
Windows could check out the ID file they name. A 2.3.0 roster may already hold
one: status and check report it, and the split refuses, naming the member or
the author and their records. No command renames a member, so rename it by hand
in members.yaml, every record's created_by, and each machine's
member.local.yaml. A 2.4.0 init starts at schema 3 with the first member's
own ID file.

Every workspace now has a roster, and every member a band. init requires a
member and suggests band 1; the solo workspace with no roster is gone. Band 0 is
a band like any other, i001-i099 and p0001-p0999. Until the roster lists
a member, every member holds a band, and this machine has selected one, every
changing command is refused with a message naming the missing step; init,
member add, member use, member band, and the reading commands still run.
status reports band_required with a suggested band for each member who has
none, and next_band for the next member added. A member whose band 2.3.0
stored as 0 counts as unbanded and is asked to pick one; picking 0 keeps their
old numbering. A 2.3.0 roster hand-edited to give two members band: 0 was
valid there and is now a roster error, because band 0 is a real band and bands
are distinct: status and check report it, and changing commands are refused
until a person moves one of them to another band in members.yaml by hand.

member add now requires --band, and without it the error names the next free
band. member band --band 0 sets band 0 rather than clearing the member's band,
and a band can no longer be cleared. record delete --all works only while the
roster lists exactly one member; otherwise name whose records go with
--member, or which records go with --id. A roster two clones broke is reported by status and check for a
person to fix, and changing commands are refused until it is: a members.yaml
that no longer reads, such as one left with conflict markers, two members on one
band, or a member given two bands.

record delete --id ID deletes the records a person names, and --id is
repeatable. It reaches any intent or plan, active or archived, approved or
completed, written by any member or with no author, and a reserved ID no record
file holds, shown as reservation only; it cannot be combined with --member
or --all, and an ID matching nothing is refused. The preview now shows each
record's status beside its author and path, in every mode. Links between the
named records do not block, and a deleted plan is taken out of its own intent's
plans: list and reported as unlinked; any other link from outside the
selection refuses, and the refusal names the --id values to add. A plan its
intent still lists that no record file holds any more is unlinked the same way.
Leftover local and remote-tracking cc/pNNNN/* branches, worktrees on them, and
a .worktrees/pNNNN directory for a deleted plan number are listed as
warnings in every mode and left alone; a worktree this machine prepared for
the plan still refuses. Released numbers are handed out again, lowest first in
the author's band. The workspace schema does not change; 2.3.0 rejects --id
and deletes nothing.

A confirmed record delete now removes the record files before it releases any
ID: plans before intents, and each plan.md after the rest of its folder.
Stopped part-way, every selected number is still reserved and every partly
removed plan is still a record, and the error names the path and the
record delete --id ... --confirm call, with exactly the IDs still reserved,
that finishes it; after --all it names record delete --all --confirm
instead. A plan folder that has already lost its plan.md is no longer a record,
so the error names it for removal by hand, and check reports it as an empty
plan folder to remove. Stopped while rewriting the ID files, after every record
file is gone, the error names the IDs still reserved and the same call, or says
nothing is left when none is. sync_required also tells every other machine to
pull the deletion, run check, and remove or prune the worktrees it names
before creating plans.

Commands that change one frontmatter field of an existing record now keep a
record written with CRLF line endings in CRLF: record delete taking a plan out
of its intent's plans: list, creating a plan, which adds it to its intent's
list, and record dependencies. record approve and record complete still
rewrite the record they stamp with LF line endings.

worktree prepare no longer resumes a worktree left from an earlier plan that
held the same number. The local association now records the plan's
created_at, and a worktree or branch whose association names a different one,
or, for an association written before 2.4.0 or a bare branch, holds commits made
before the plan record was created, is refused without --reuse; the refusal
names how to remove it. A bare branch is dated from the base branch, or from
origin/<base> when the clone has no local one. A worktree whose association was
written before 2.4.0 and whose branch holds no commit past its start is resumed
only when it has no uncommitted changes and sits at the tip of the base branch,
where a fresh prepare would start, and is refused the same way otherwise.
Preparing again for the plan a worktree was made for resumes it as before.
check names a worktree whose association records a different created_at from
its plan's, and says to remove it and its branch, or to run worktree prune if
Git no longer lists it.

record approve returns planning_recommended instead of planning_required:
approval records a decision, and planning follows a request for it, which may
arrive with the approval.

After it succeeds, record approve checks the intent's file, and
record complete the plan's files and its intent's file, wherever they live,
plus every ID file: the shared .context-circuit/ids.yaml and each per-member
file. When Git reports any of them uncommitted, the result carries
commit_recommended with files, each a path relative to the workspace root
with / separators on every OS and a change of new, modified, or
deleted, and a note saying committing needs the person's authorization. A
renamed record is its new path new and its old path deleted; other
uncommitted records are not listed. Both commands rewrite the record they touch,
so in a Git workspace that record is always listed. When Git is not installed or
the workspace is not in a Git repository, the result carries commit_unchecked
with the reason instead. The check only adds keys: it never blocks or undoes the
command, and the CLI never stages or commits. A workspace inside another
repository is reported relative to its own root. The Git status reader behind
status and repo inspect now reads renames, so changes lists a renamed file
once, as R new/path, rather than also listing its old path with no code.
This implements #144, reported via #141.

A member may carry an optional roles list of free text, set with
member add --role, init --member-role, or member roles, and cleared with
member roles --clear. Each role is one nonempty line, like a member's name,
and a role given twice is kept once. Roles are shown by member list and status and decide
nothing. They are written only at schema 3. A 2.3.0 member list on a roster
with roles fails on the unknown roles field rather than asking for an upgrade,
and check reports roles found in a schema 2 roster.

worktree prune --repo ID drops the plan-to-worktree associations of worktrees
Git no longer lists, and reports them as dropped. It touches no worktree,
branch, or file. When worktree prepare finds a plan's branch checked out in
another working copy, it now names the branch, where it is checked out, whether
that is a known worktree for the plan, and the safe next steps, and changes
nothing. check now points at worktree prune rather than worktree repair
when Git no longer lists a worktree a plan is associated with, and keeps the
repair advice for a checkout that only moved. The record delete refusal for a
plan's worktree names worktree prune too, and so does worktree prepare when
the working copy holding the plan's branch is one Git marks prunable.

worktree remove now also removes the empty .worktrees/ folders it leaves
behind, such as .worktrees/pNNNN/ after a plan's last worktree, up to and
including .worktrees/ itself, and lists them as removed_directories. It stops
at the first folder that holds anything and never reaches outside .worktrees/;
a folder it cannot remove is reported in warnings and does not fail the
command (#161).

Thanks to @hallode for worktree prune (#140).

For contributors to this repository, CI now runs on pushes to
development/v2, and CONTRIBUTING.md names it as the branch pull requests
target.


Built at commit 2fef8d76f1fd57bdec58e02fba755822e1c9a7fd.

Apache-2.0; the archive carries the license. The workspace template is 0BSD.