Repository navigation
Releases
ctxpack v0.1.16
What's changed in v0.1.16
The MCP parity release: the server's analytic tools now walk the tree the
same way the CLI does, and the arguments they advertise actually take effect.
- MCP
repo_maphonoursno_gitignoreandhidden— the flags were
declared in the schema but ignored; now a caller asking for
no_gitignore: truereally gets the unfiltered tree. It also reads
contents like the CLI'smap, so totals agree. - MCP
count_tokensreads contents like the CLI'stokens— the same
tree previously produced two different totals depending on which interface
you asked;max_sizestill caps the reading.
Plus the walk-flag integration series: every
--include/--exclude/--max-size/--depth/--hidden/gitignore behavior
now has a test at both the CLI and MCP layers.
Full changelog: https://github.com/la2278647-arch/ctxpack/blob/v0.1.16/CHANGELOG.md
Assets are the eight cross-compiled release binaries plus SHA256SUMS.txt.
ctxpack v0.1.15
What's changed in v0.1.15
The empty-diff release: both frontends now treat "nothing changed" as a
normal result.
diff --format jsonemits an envelope even when nothing changed —
scripts can json-parse every diff run; the stderr note stays and respects
--quiet.- MCP
diff_reporeports an empty diff as a success, not an error — json
gets the same empty envelope as the CLI.
Plus a long tail of hardening since v0.1.14: empty-directory envelopes for
both frontends, --top 0 semantics across all four top-taking commands,
--include/--exclude path globs and their pack/tokens integration,
--max-size's estimate behavior on map, the window/limit/reserve
invariants on both json envelopes, and a gofmt sweep.
Full changelog: https://github.com/la2278647-arch/ctxpack/blob/v0.1.15/CHANGELOG.md
Assets are the eight cross-compiled release binaries plus SHA256SUMS.txt.
ctxpack v0.1.14
What's changed in v0.1.14
The parity release: the CLI's tokens --json fit envelope and the MCP
count_tokens envelope are now identical field for field —
model/vendor/window/used/limit/fits/pct_used — so a script
consuming both interfaces needs exactly one parser.
tokens --jsonfits now carryvendorandwindow(the raw window,
alongsidelimit). The csv output is unchanged.- MCP
count_tokensfits renamenametomodel, matching the CLI. smokechecksinstall.sh --helpdoes not touch the network, so the
installer's help branch cannot rot into a version install.
Full changelog: https://github.com/la2278647-arch/ctxpack/blob/v0.1.14/CHANGELOG.md
Assets are the eight cross-compiled release binaries plus SHA256SUMS.txt.
ctxpack v0.1.13
What's changed in v0.1.13
- Installers learn
--help—install.sh --helpprints the usage and
exits without downloading;install.ps1gets the same branch. commandschecknow runs the invocations inexamples/diff-demo/README.md
— the<repo>placeholder is rewritten to a scratch repository before
splitting, so the documented diff commands run for real.help --help/help -hshow the help instead of an
unknown command "--help"error.tokens --topnow means "the N largest context windows" in all three
formats, matchingmodels --top(it used to cut the registration order).- MCP
count_tokens topfixed to the same window semantics as the CLI. - A bad
--outputpath no longer callsos.Exit(1)— it returns exit
code 1 like any other runtime error, and is now testable. - The (still doc-only) workflow's release job builds with Go 1.26,
matching the test matrix.
Full changelog: https://github.com/la2278647-arch/ctxpack/blob/v0.1.13/CHANGELOG.md
Assets are the eight cross-compiled release binaries plus SHA256SUMS.txt.
ctxpack v0.1.12
What's changed in v0.1.12
- Bash, zsh and fish shell completion for every command and flag —
scripts/completion.bash,scripts/completion.zsh,scripts/completion.fish. smokeverifies the completion tables against the help text in both
directions, and caught a real drift on its first run (--quietwas missing).version --shortprints just the semantic version (0.1.12), identical
acrossversion/--version/-v.- MCP
versiontool — the build identity alone, without a fulldoctor
report; its JSON envelope matches the CLI'sversion --json. -h/--helpreturn 0 on every subcommand, andhelp <command>
validates the command name.- The (still doc-only) GitHub Actions workflow now runs the remaining
make ciguards, produces theSHA256SUMS.txtthe installers parse, and
tests Go 1.21 through 1.26. commandscheckno longer reports real variables as unread — the two
CTXPACK_TAP/CTXPACK_BUCKETvariables read bycheck-release.share
recognized.
Full changelog: https://github.com/la2278647-arch/ctxpack/blob/v0.1.12/CHANGELOG.md
Assets are the eight cross-compiled release binaries plus SHA256SUMS.txt.
ctxpack v0.1.11
What's changed in v0.1.11
version --json— machine-readable build identity for scripted consumers.models --csvandtokens --csv— the lookup tables as CSV,
mirroring the--jsonfield names (name,context_window,vendorand
model,used,limit,fits,pct_used).- MCP
list_modelsnow acceptsvendor,topandsort; MCP
repo_mapacceptstopfor a flat largest-files list — both matching
their CLI commands. map --topheader fix — says "by tokens"/"by bytes", the real ranking
key, instead of the misleading--sortdefault of "name".- Model table cleanup — removed the legacy
qwen2.5alias (duplicate of
qwen-2.5-72b); the table is 30 models across 7 vendors.
Full changelog: https://github.com/la2278647-arch/ctxpack/blob/v0.1.11/CHANGELOG.md
Assets are the eight cross-compiled release binaries plus SHA256SUMS.txt.
ctxpack v0.1.10
v0.1.10
The release that fixes how the packer decides what a file is. packer.priority
scores every file before a budget is applied, and three of the fixes below are
matching defects in that one function: each one classified a file as something it
is not, so under a tight budget the wrong files survived. The other seven are
release-plumbing defects — the parts of the pipeline that turn a commit into a
downloadable binary — most of which had never been exercised on any machine other
than the one that wrote them.
Fixed
-
readme_helper.pywas scored as a project document.
The README check wasstrings.HasPrefix(base, "readme")— any basename
beginning with readme.readme_helper.pyandreadmes.pytherefore scored
1000, the policy-document tier, instead of 200 (source), outranking config
files, scripts and every test. The same function matchedpolicyDocsby exact
basename, wheresecurityscanner.gocorrectly scored 200 against
SECURITY.mdat 1000, so the two halves of one rule disagreed: one exact, one
greedy.isPolicyDocnow accepts only the basenamereadmeorreadme.<ext>,
soREADME.mdanddocs/README.rststill score 1000 whilereadme_helper.py
andreadmes.pyscore 200 anddocs/READMEING.mdscores 300 — a markdown file
that is not a README. -
notmain.gowas scored as an application entry point.
Entry-point detection ranstrings.HasSuffixon the full path, and
HasSuffix("notmain.go", "main.go")is true — as aremyindex.jsagainst
index.js,mymanage.pyagainstmanage.pyandcustomserver.jsagainst
server.js. Four ordinary source files therefore scored 400, outranking the
real source they sat among at 200, so a tight budget spent tokens on
notmain.gobefore they reached anything the repository actually runs. Entry
points are now an exact-basename set:main.go,mod.go,index.ts,
index.js,index.jsx,index.tsx,server.js,manage.py. -
React and TSX files scored 10, the lowest tier of all.
The source list was.go .ts .js .py .rs .java .rb .csand contained no
.tsxor.jsx, so React and TypeScript-JSX components fell through to the
default 10 — below config files (150), shell scripts (100) and even test files
(50). Under a budget a component was dropped before a YAML file. Both
extensions now score 200 as source, andindex.jsx/index.tsxare
registered as entry points at 400. -
ctxpack models --sort vendorcould sort wrong.
The comparator compared vendor strings raw for equality but folded them to
lowercase for ordering, soOpenAIandopenaiwere treated as different
vendors while ordering as equal. That is an inconsistent comparator, and
sort.Slicehas no defined result for one — the grouping came out wrong. The
default (name) sort had the identical defect for case-variant names. Both now
fold before comparing. Found by writing tests for the two tiebreak branches
that had never been exercised; the real 31-entry table has distinct names, so
neither branch had ever run. -
Both installers could not verify any checksum file.
install.shandinstall.ps1matched an asset with a two-space separator,
which is whatsha256sum -temits in text mode. But GNU coreutils defaults to
binary mode when given file arguments, which emitshash *nameinstead.
sha256sum --helpstates it plainly:-b, --binary read in binary mode (default unless reading tty stdin). So the checksum file thatmake release
produces on this project's own release host made both installers fail with
ctxpack_0.1.10_windows_amd64.exe is not listed in SHA256SUMS.txt— the
installers rejected every release, on every platform. Neither had ever been
executed, so the defect shipped for four releases. Both parsers now accept
either marker and compare the name after stripping it, and the Makefile pins
-tso the published file is deterministic. The parsers are covered by 8
offline cases each: binary and text mode, the asset not being first, and two
prefix traps —..._amd64.exemust not match..._amd64.exe.debug, and
..._386.exemust not match..._amd64.exe. -
install.shwithout a version produced a "version" made of release notes.
The REST call was piped throughgrep -m1 '"tag_name"', which returns the
whole matching line. When the API answers on a single line that line is the
entire response including the release body, and the greedysedthen matched
inside it, yielding a URL fragment before curl refused the malformed URL.
grep -oextracts just the"tag_name": "v0.1.10"fragment, so thesedonly
ever sees that. -
A transient GitHub connection reset aborted an install.
Invoke-WebRequesthas no retry of its own, and the script runs under
$ErrorActionPreference = 'Stop', so one reset connection killed the install
with no attempt to recover.install.ps1now retries with backoff before
giving up, andinstall.shpasses--retry 3to curl. Under a live reset the
retry path was observed printingretry 1/4 ... 3/4and then rethrowing the
real error, so a failure still reports clearly. -
The CI release-binary job could not upload its artifacts.
The workflow declarespermissions: contents: readat the top level, and that
applies to every job unless a job overrides it.actions/upload-artifact@v4
requiresactions: write, so thepackagesjob would have failed at the very
last step of a release build. The job now declares both permissions itself
instead of widening the whole workflow. Found while validating the workflow
structurally — every step, matrix and permission is checked by a script that
parses the YAML, and all sevenrun:blocks passbash -n. -
CI release binaries were named differently from the real release assets.
The workflow builtctxpack-0.1.10-linux-amd64(hyphens) whilemake release,
the published assets, and both installers all use
ctxpack_0.1.10_linux_amd64(underscores). A CI artifact therefore could not
stand in for a release download, and asha256sum -cagainst the published
sums file would fail. The naming now matches. -
A mistyped
-ldflags -Xpath is now detected instead of silently ignored.
Go accepts a wrong-Xpath with exit 0 and quietly leaves the source default
in place: building with-X ...version.Vresion=9.9.9-typo(one letter wrong)
and with-X ...internal/versionz.Version=...(wrong package) both succeed, and
both binaries report the source default. That makes a typo in a version stamp
invisible until a user inspects the output. The test job now builds with a
sentinel version and fails if it does not appear inctxpack version.
Added
-
Fourteen regression cases pin the priority ladder's matching rules.
TestPriorityLaddernow covers the two basename boundaries the defects above
crossed —readme.md,readme.rstanddocs/README.adocat 1000 against
readme_helper.pyandreadmes.pyat 200 anddocs/READMEING.mdat 300 —
every entry-point near miss (notmain.go,myindex.js,mymanage.py,
customserver.js, all 200) against the real entry points at 400, and the new
.tsx/.jsxtiers. Each case varies the extension and the basename
independently, so the two matching rules cannot drift back into each other
again. The self-packing snapshots inexamples/are regenerated in the same
commit: they now cover 55 files instead of 54 and about 280922 tokens instead
of 273107, becauseinternal/cli/sortmodels_test.gois new since they were
taken and enters the omitted list. The kept-file selection is unchanged, so
they still demonstrate the same budget behaviour. -
Twelve tests cover the
sortModelscontract, including the two branches
that had never run.
internal/cli/sortmodels_test.gopins the ordering forname,window, and
vendor— the primary key, each tiebreak, case-folding, case-insensitive sort
keys, the fallback for an unknown key, idempotence, and empty and
single-element slices. Coverage ofinternal/clirose from 99.4% to 99.6%;
the one remaining uncovered statement isoutputWriter'sos.Createfailure,
which callsos.Exit(1)and so cannot be reached from a test. -
The
go installpath is now verified end to end.
It is the first install method the README and release notes show, and it had
never been executed. From a clean GOPATH,go install github.com/la2278647-arch/ctxpack@v0.1.9downloads, builds and installs
ctxpack.exe, which reportsctxpack 0.1.9.@latestand@mainresolve to
the release,@v0.1.8correctly resolves the older release, and@v9.9.9
fails with a clear error. This also confirms the module path ingo.mod
matches the repository and that the root package is a main package, both of
whichgo installsilently requires.
Test coverage
| package | v0.1.9 | v0.1.10 |
|---|---|---|
| cli | 99.4% | 99.6% |
| counter | 100% | 100% |
| doctor | 98.0% | 98.0% |
| format | 99.3% | 99.3% |
| gitutil | 100% | 100% |
| ignore | 98.0% | 98.0% |
| mcp | 97.3% | 97.3% |
| packer | 100% | 100% |
| repomap | 100% | 100% |
| version | 100% | 100% |
| walker | 94.4% | 94.4% |
| total | 98.5% | 98.5% |
425 test functions and 12 subtests, all passing. packer stays at 100%: the
three fixes above are covered by the new TestPriorityLadder rows, and the
function they changed already had no uncovered statement. Every remaining
uncovered branch in the suite is one that cannot be reached — a filepath.Abs
failure that needs the working directory deleted mid-call, a json.Marshal
failure over values that cannot fail to marshal, a regexp.Compile of a pattern
the translator always escapes, and outputWriter's os.Create failure, which
calls os.Exit(1). They are marked in comments ra...
ctxpack v0.1.9
v0.1.9
The release that closes the gap between what the tool advertises and what the
tool does. Six of the seven fixes below were not found by reading the code but by
pointing a test or a smoke assertion at the boundary between a documented
contract and the implementation behind it.
Fixed
-
pack_repowithformat: "json"and amodelreturned unparseable JSON.
The MCP tool prepended the HTML comment the text formats carry —<!-- fit: OVERFLOW model=gpt-4 used=267.6k/4.1k (6533%) OVERFLOW -->— in front of the
JSON document, so any client thatJSON.parses the tool result threw on every
annotated call. The CLI sidesteps this by routing the note to stderr, but an
MCP client only ever sees the envelope. The annotation now travels inside the
envelope as afitobject using the same keyscount_tokens --jsonalready
uses for its per-model entries (name,vendor,window,limit,used,
pct_used,fits,reserve), so the information is still there and the
document stays valid.diff_reposhares the path and gets the same treatment.
Text formats keep the comment, and an unknown model yields
fit: {"model": "...", "unknown": true}instead of destroying the envelope.
fitNotenow derives both renderings from one place, and the smoke suite
asserts thefitkey survives. -
doctor -o FILEdid not work.
The help text advertises-o, --output FILEon all commands, butdoctoronly
registered the long form. The shorthand failed withflag provided but not defined: -oand exited 2, so anyone scriptingctxpack doctor -o report.txt
got a usage screen instead of a report. Both spellings now write to the file,
matchingpack,map,diff,tokensandmodels. -
The help text described flags the commands do not take.
printHelpcalled the walk flags "map / tokens only" whenpackanddiff
accept them too, filed--depthunder a three-command group while four commands
take it, and tolddiffit "also accepts" only eight of the sixteen flags it
registers, omitting--max-size,--depth,--no-gitignore,--hidden,
--output,--dry-runand--list. There is now one WALK FLAGS group naming
the four traversing commands plus a complete section per command, with no scope
note the code contradicts. -
The README's MCP tool table was missing
doctor.
doctorshipped in v0.1.8 but the table never gained its row, so a client
reading the README concluded that a failing pack could not be diagnosed from
inside the server — the exact casedoctorexists for. The prose beside it
called the analytic tools "three" when there are four.doctoris now listed
with itsformat?/top?arguments, thelist_modelsfootnote moved out of
the cell so the argument lists stay machine-readable, and thefitobject is
described whereformat: "json"andmodelmeet. The README's install
snippets also still pinnedv0.1.7and the Docker examples0.1.4. -
make smokecould destroy uncommittedREADME.mdedits.
The diff test dirtiesREADME.mdto exercisediff, then restored it with
git checkout -- README.md. That restores from the index, so anyone who ran
the smoke suite with uncommitted README work lost it without warning. It now
copies the file aside and copies it back, preserving the exact bytes that were
there before the run. The finding was self-inflicted: the MCP table edit was
applied, the suite was run, and the edits came back missing from the commit. -
Twenty-three smoke assertions failed silently.
scripts/smoke.shran underset -euo pipefail, but 23 assertions were bare
grepcalls: when one failed the script aborted with no message at all — a wall
of passing sections followed by silence, with no way to tell which check broke.
All of them now go throughfail, which prints a specific reason. The bug had
stayed hidden for a structural reason:failwas defined near the bottom of
the script, after the assertions it was meant to serve, so those sections could
not have used it. It now sits at the top. Wiring thedoctor --output
assertion up is what surfaced the-obug above, which had been a silent
no-op.
Added
-
Regression tests pin the documentation to the code.
internal/cli/help_test.gowalks the union of every flag against all six
commands and asserts that each advertised flag parses (exit 0) and each
non-advertised one is rejected by the parser (exit 2). Two further tests read
the realprintHelpoutput and check both directions: every documented flag
must be registered, and no section may document a flag the command rejects.
internal/mcp/readme_test.goparses the README's tool table and compares it
both ways against the schemastools()returns, so a tool added to or removed
from the server fails it, as does a required/optional mismatch. Both are
mutation-checked: deletingdoctor's-oregistration fails the help test
with exactlycmd doctor: -o accept (exit 2, want 0), and deleting the
doctorrow from the table fails the README test withthe table does not document doctor; the server advertises it. -
The
Rundispatcher and three CLI error branches now have tests.
internal/cli/cli_gaps_test.godrivescli.Run— the functionmain.go
actually calls — through itsdoctorcase, which was the one command never
dispatched by a test, so a typo in the case label would have shipped as
"unknown command" for a command the help text advertises. The same file adds
the near-miss check (Run(["docter"])must hit the unknown-command branch),
thetokens --modelOVERFLOW verdict with the reverse case proving the mark is
a property of the repository/model pair rather than of the fixture, and
diff --dry-run's "omitted by the budget" line with the converse case proving
it follows the cap rather than printing unconditionally.
TestDoctorRejectsExtraArgspreviously rejected only an unknown flag, which
made its name overclaim — flag parsing and positional-argument rejection are
two different branches with two different messages, and it now covers both and
asserts both. -
The fit-report selection and sorting contracts are pinned.
Tests now fix the order--sort tokens/--sort bytesproduce, which file
wins a tie, and that--toptruncates the text breakdown while the JSON
payload stays complete.
Test coverage
| package | v0.1.8 | v0.1.9 |
|---|---|---|
| cli | 97.6% | 99.4% |
| counter | 100% | 100% |
| doctor | 98.0% | 98.0% |
| format | 99.3% | 99.3% |
| gitutil | 100% | 100% |
| ignore | 98.0% | 98.0% |
| mcp | 97.1% | 97.3% |
| packer | 100% | 100% |
| repomap | 100% | 100% |
| version | 100% | 100% |
| walker | 94.4% | 94.4% |
423 tests, all passing, up from 389. Every remaining uncovered branch in the
suite is one that cannot be reached: a filepath.Abs failure that needs the
working directory deleted mid-call, a json.Marshal failure over values that
cannot fail to marshal, and outputWriter's os.Create failure, which calls
os.Exit(1). They are marked in comments rather than tested around. The suite
still asserts go.sum stays absent and go list -m all reports exactly one
module, so the binary remains dependency-free.
Installation
# Homebrew
brew tap la2278647-arch/tap https://github.com/la2278647-arch/homebrew-tap
brew install ctxpack
# Go
go install github.com/la2278647-arch/ctxpack@v0.1.9
# Windows PowerShell
irm https://raw.githubusercontent.com/la2278647-arch/ctxpack/main/install.ps1 | iex
# Linux/macOS
curl -fsSL https://raw.githubusercontent.com/la2278647-arch/ctxpack/main/install.sh | bash
# Direct download
# https://github.com/la2278647-arch/ctxpack/releases/tag/v0.1.9What's next
- GitHub Actions CI workflow (blocked on
workflowscope token) - Docker daemon testing of the multi-stage Dockerfile
- Model table expansion (blocked: context windows cannot be verified)
- Promotion posts (drafts in
docs/promote.md)
ctxpack v0.1.8
v0.1.8
The release that gives the MCP server a way to explain itself. A new doctor
tool answers the question an agent cannot otherwise ask, and the whole smoke
suite finally moved into one script that the CLI, the Makefile and CI all share.
Added
-
doctoris an MCP tool.
An agent that gotgit error: exit status 128fromdiff_repohad no way to
tell whether git was missing, on the wrong version, or whether the ref was
simply wrong — and the one diagnostic that answers that required apath,
which is exactly what the agent may be unable to name.doctortakes no path
at all: it reports the server's version, Go version, platform, git availability
and version, and the model registry broken down by vendor.toptruncates
only the text breakdown; theN models, M vendorstotal and the
format: "json"payload always stay complete, so a truncated answer cannot
understate the registry. It accepts justtextandjsonand refuses
anything else — a client cannot request a format it would silently get back
as text. -
scripts/smoke.sh: the smoke suite as one script.
It drives every command, all four output formats, the
--sort/--top/--format/--dry-run/--listflags,diffwith a
--ref A..Brange, a deletion across all four formats, and the MCP server over
stdio — against the source tree itself.make smokenow delegates to it, so
there is one copy instead of a Makefile recipe and a CI recipe that could drift
apart. The script finds the repository root from its own path, so it runs from
any working directory and accepts an explicit binary path as an optional first
argument. -
doctor, the file-selection flags, and all six MCP tools are in the smoke
suite.
doctorwas documented and unit-tested but never exercised end to end. Nor
were--include,--exclude,--max-size,--depth,--hidden,
--no-gitignore,map --csvormodels --vendor. The suite now asserts each
one's contract with relative counts rather than pinned numbers, so it keeps
passing as the repository grows:--depthmust shrink the file set,
--max-sizemust leave the count alone while collapsing the token total,
--includeand--excludemust each shrink it,--hiddenmust add files,
and--no-gitignorecan only keep or add. On the MCP side the suite asserts
thattools/listadvertises all six tools, that each is callable, and that
five failure modes are reported correctly.
Changed
-
doctormoved into a shared package.
The CLI'sdoctorcommand and the MCPdoctortool now both call
internal/doctorinstead of each implementing the checks. That is the same
"frontends share an engine" rule the packer and repomap packages already follow,
and it removes about a hundred lines of duplicated git probing and vendor
sorting frominternal/cli. The JSON keys the CLI has always emitted are
unchanged, so a script that parsesctxpack doctor --jsonkeeps working. -
--dry-runwrites its report to stderr, and the smoke suite asserts it.
The suite used to discard dry-run output with> /dev/null, which silently
failed to silence it — this codebase sends artifacts to stdout and status to
stderr, and a dry run produces status, not an artifact, so the redirect
captured nothing at all. The assertions now capture stderr and require the
report to be present, so the stream convention is pinned instead of tolerated. -
The CI smoke test calls
scripts/smoke.shinstead of inlining its steps.
The inlined copy had two bugs the script run surfaced: it grepped for"tree"
in MCP output, where the tool result arrives escaped as\"tree\"inside the
JSON-RPC envelope string, and it used> /dev/nullto silence dry-run output
that travels on stderr. -
The README MCP table was corrected.
It omittedpack_repo'smax_depth, and the introductory sentence implied
onlyrepo_map,count_tokensandlist_modelstake aformatwhen all six
tools do. The smoke suite now exercisesmax_depththrough the MCP interface
so this cannot quietly regress.
Test coverage
| package | v0.1.7 | v0.1.8 |
|---|---|---|
| cli | 96.6% | 97.6% |
| counter | 100% | 100% |
| doctor | — | 98.0% |
| format | 99.3% | 99.3% |
| gitutil | 100% | 100% |
| ignore | 98.0% | 98.0% |
| mcp | 97.4% | 97.1% |
| packer | 100% | 100% |
| repomap | 100% | 100% |
| version | 100% | 100% |
| walker | 94.4% | 94.4% |
389 tests, all passing. The suite still asserts go.sum stays absent and
go list -m all reports exactly one module, so the binary remains dependency-free.
Installation
# Homebrew
brew tap la2278647-arch/tap https://github.com/la2278647-arch/homebrew-tap
brew install ctxpack
# Go
go install github.com/la2278647-arch/ctxpack@v0.1.8
# Windows PowerShell
irm https://raw.githubusercontent.com/la2278647-arch/ctxpack/main/install.ps1 | iex
# Linux/macOS
curl -fsSL https://raw.githubusercontent.com/la2278647-arch/ctxpack/main/install.sh | bash
# Direct download
# https://github.com/la2278647-arch/ctxpack/releases/tag/v0.1.8What's next
- GitHub Actions CI workflow (blocked on
workflowscope token) - Docker daemon testing of the multi-stage Dockerfile
- Model table expansion (blocked: context windows cannot be verified)
- Promotion posts (drafts in
docs/promote.md)
ctxpack v0.1.7
v0.1.7
The release that teaches diff about history. diff now understands git
ranges and reports files that were deleted, and pack stops printing your
machine's absolute path into the bundle.
Added
-
diffranges (--ref A..B).
ctxpack diff --ref HEAD~5..HEADcompares two revisions as history. A range
never includes the working tree's untracked files, because those belong to
neither side of the range. A plain ref (--ref main) still diffs against the
working tree, so uncommitted changes remain included. The MCPdiff_repo
tool accepts the same range syntax for itsrefargument. -
diffreports deleted files.
A deletion has no content to pack, so before this release the bundle simply
never mentioned it — a removed file looked like it had never existed.diff
now lists removed paths in aDeletedsection: XML adds a<deleted>
element, Markdown a## Deletedheading, text a==== deleted ====block,
and JSON adeletedarray.--dry-runprints the count and each path. The
MCPdiff_repotool reports them the same way. Paths are reported by name
only, never content. -
examples/diff-demo: a reproducible diff snapshot.
A generatedctxpack diffoutput over a two-commit range containing a
modification, an addition and a deletion — the smallest example that shows
range syntax and the newDeletedsection together.make.shbuilds the
scratch repository in a temp directory and deletes it on exit, so the
committeddiff.xmlis byte-identical on any machine.
Changed
-
Bundles name the directory, not the machine.
packanddiffnow label the bundle with the walked directory's base name
(<root>ctxpack</root>) instead of its absolute path
(<root>D:\Users\alice\ctxpack</root>). The machine the bundle was built on
is not information a model needs, and an absolute path leaks the username of
whoever packed the repository. This matches whatmapalready did for its
root node;packanddiffhad diverged from it. The JSONrootfield
carries the same shortened value.If you parsed the JSON
rootfield and expected an absolute path, read it
from the file system instead — the bundle now names the directory. -
gitutil.DiffFilessplits deletions from changes.
ChangedFileskeeps its signature and behaviour, now returning only the
packable set; callers that need to report removals use the newDiffFiles,
which returns both lists.
Test coverage
| package | v0.1.6 | v0.1.7 |
|---|---|---|
| cli | 96.6% | 96.6% |
| counter | 100% | 100% |
| format | 99.1% | 99.3% |
| gitutil | 100% | 100% |
| ignore | 98.0% | 98.0% |
| mcp | 97.4% | 97.4% |
| packer | 100% | 100% |
| repomap | 100% | 100% |
| version | 100% | 100% |
| walker | 94.4% | 94.4% |
369 tests, all passing.
Installation
# Homebrew
brew tap la2278647-arch/tap https://github.com/la2278647-arch/homebrew-tap
brew install ctxpack
# Go
go install github.com/la2278647-arch/ctxpack@v0.1.7
# Windows PowerShell
irm https://raw.githubusercontent.com/la2278647-arch/ctxpack/main/install.ps1 | iex
# Linux/macOS
curl -fsSL https://raw.githubusercontent.com/la2278647-arch/ctxpack/main/install.sh | bash
# Direct download
# https://github.com/la2278647-arch/ctxpack/releases/tag/v0.1.7What's next
- GitHub Actions CI workflow (blocked on
workflowscope token) - Docker daemon testing of the multi-stage Dockerfile
- Model table expansion (blocked: context windows cannot be verified)
- Promotion posts (drafts in
docs/promote.md)