Skip to content

StarSync 2.2.1 - #5

Merged
NomadicDaddy merged 40 commits into
mainfrom
release/2.2.1
Aug 4, 2026
Merged

NomadicDaddy merged 40 commits into
mainfrom
release/2.2.1

Conversation

@NomadicDaddy

Copy link
Copy Markdown
Owner

Managed archive format 2, the programmatic API, node/npx support, and npm publication. See CHANGELOG.md.

NomadicDaddy and others added 30 commits July 29, 2026 12:20
An explicitly supplied empty or quoted-empty target path was silently
falling through to an implicit starred_repos directory, allowing a
command to inspect or modify an archive the caller never named. Now it is correctly reported as a usage error with exit code 2.

Usage error reports also preserve the requested --dry-run mode so
machine consumers receive consistent output shape.
…trol

A live sync of 284 starred repositories failed 15 checkouts. The causes were
three, none of them local:

- A fetch exits non-zero when the upstream moved a tag the archive already
  stores, even after every branch has advanced. The refresh now keeps the
  archived tag target, completes, and reports the retained tags.

- An upstream Git LFS store that no longer serves its objects failed the whole
  clone or refresh. The operation is retried once with GIT_LFS_SKIP_SMUDGE=1 so
  the checkout lands with its pointer files. The setting is never written to
  checkout config, per ADR 0005.

- A path this platform cannot represent in a working tree failed the clone, and
  on an older checkout showed up as a staged deletion that can never be
  resolved. Such paths are now excluded with sparse-checkout patterns, which
  survive a later fast-forward where skip-worktree bits did not, and the
  local-state guards in sync, verify, and migrate no longer read them as
  uncommitted work. Verify and migrate reach that conclusion without changing
  the checkout they inspect.

Each recovery applies at most once per operation, and a clone restarts from an
empty StarSync-owned staging directory so no partial checkout is published. A
failure matching no recovery surfaces its original error.

Fetch classification moves to remote-fetch.ts, recovery planning to
git-recovery.ts, and staged cloning to checkout-clone.ts to stay inside the
source-shape limits. git-exec.ts gains readStatusPaths, which reads porcelain
status untrimmed so a record whose index field is a space no longer shifts the
first path.

Verified: bun run smoke:qc passes 211 tests, and the live 302-checkout archive
now syncs 284 succeeded, 0 failed, 0 blocked.

Co-Authored-By: Claude Opus 5 <[email protected]>
- ADR 0009 explains why platform-unrepresentable paths are excluded with sparse
  checkout rather than skip-worktree bits, and why the guard must exclude before
  deciding whether a checkout is blocked.

- ADR 0002 gains the tag-clobber case: a rejection that only moves a tag the
  archive already stores is tolerated, while any other rejection or fatal error
  still fails the refresh.

- ADR 0005 gains the one-shot GIT_LFS_SKIP_SMUDGE retry and states that it is
  never written into checkout config.

- CONTEXT.md records that a path the host filesystem cannot represent is not
  local state, so it never makes a checkout a Blocked Checkout.

- README.md replaces the stale skip-worktree description, describes retained
  tags and the LFS fallback, and corrects the Scripts table.

Co-Authored-By: Claude Opus 5 <[email protected]>
Minor bump: the release adds functionality that did not exist before, namely
the retained-tag warning and the Git LFS pointer fallback, alongside the fixes.

package.json also restores start to `bun ./src/cli.ts`, which the
.aidd/deployment.md release probe and the README Scripts table both document.
The sync script keeps its explicit `sync` subcommand.

Verified: `bun run start -- --help` prints the six subcommands and exits 0.

Co-Authored-By: Claude Opus 5 <[email protected]>
Extract checkout inspection, duplicate filtering, and repository collision classification behind enforced source-shape boundaries.

Add focused real-Git regression coverage for invalid, duplicate, occupied, pending, retained, and mixed archive plans.
Snapshot and verify checkout metadata, restore it on failure, and compensate rename folder moves without overwriting occupied paths.

Add real-Git mutation-boundary, rollback, and durable-label agreement coverage.
Remove thirteen implementation-only export modifiers and two redundant lock re-exports.

Keep the package API unchanged and cover the narrowed boundaries through behavior and source-shape tests.
- Allow the real-Git copied archive journey up to 20 seconds on hosted Windows

- Preserve the default timeout for the rest of the test suite
Document each format-2 API-token responsibility while preserving the separate system Git credential boundary.
Assert local deployment metadata reflects the package-derived version, current tag gap, and format-2-safe rollback boundary.

Keep the assertion optional in clean CI checkouts where ignored AIDD metadata is intentionally absent.
Extract shared archive API contracts from the lock-owning facade.

Add a module-boundary regression and verify the focused graph with Madge.
- Reconcile existing checkout labels only after current or updated outcomes

- Add a subprocess-driven real-Git regression for blocked label changes

- Keep ignored AIDD feature metadata authoritative on disk
- exclude exact staging and damaged-backup directories from discovery and planning

- clean abandoned owned artifacts under the archive lock while preserving warnings

- cover failed backup cleanup and uncertain-name preservation with real Git tests
Resolve forced replacements by stable repository ID, keep source and canonical destination distinct, and reject duplicate identities or occupied destinations.

Cover owner, name, and casing renames plus preservation failures with real-Git process-boundary tests.
Detect exact pending folder casing and publish case-only renames through a safe intermediate path.

Cover owner-only, repository-only, and compensating rollback behavior with real Git fixtures.
Replace the production-module allowlist with full source inspection and exact per-metric baselines for existing outliers.

Add process-boundary coverage for a previously unlisted over-limit module.
- Redact authorization, bearer, generic key-value, and provider credential shapes

- Cover every required sanitizer form with focused tests
Sanitize structured report strings, progress, diagnostics, and unexpected errors.

Cover classic and fine-grained PATs in human and JSON CLI paths.
Validate modification guards from exact archive config without Git subprocesses.

Reuse archive and checkout inventories across rename apply and sync planning, with focused regression coverage.
Select the directly declared @types/bun package through the bun type-library name while keeping bun-types transitive.

Verified typecheck, lint, and formatting before commit.
- Enable the TypeScript parser project service

- Reject unbound method references at error severity

- Verify effective config, typecheck, lint, and formatting
Capture the ref-update stdin once and replay it into each guard, because a guard that reads it
would otherwise starve the next.

Add screenshot-guard.sh, which blocks a version-tag push whose screenshots/v<version>/ artifact
is missing or records a failed crawl.
Repoint bin, main, module, and types at node-target dist bundles with declarations emitted through
a dedicated tsconfig, so npx starsync and import 'starsync' both work without bun.

Move the bun-only install guard from preinstall to prepare. On preinstall it also ran for anyone
installing the published package, so npx died on a missing bun before reaching the CLI; prepare
never runs for an install from the registry. Chain the build into prepare so a clone or a git
dependency still has the entry points a gitignored dist/ would otherwise leave absent.

Drop private, declare the supported node floor, narrow files to the built output, and exercise
both bundles under node in release validation.
Record node and npx support, the prepare-guard move, and the post-2.0.0 rename, verification,
staging-isolation, and secret-redaction fixes.
A missing screenshots/ root now means the repo does not capture
screenshots (CLI, library) and passes silently. Previously, an
opted-in repo that forgot to capture for a version was treated the
same as an opted-out repo. The guard now correctly fails when the
root exists but the version directory is absent.
The table listed neither build:bundle nor build:types and still described build
as bundling the CLI alone. Adds every script, quotes the lint and format globs
verbatim, and notes that prepare and prepublishOnly are lifecycle hooks rather
than commands to run by hand.

Co-Authored-By: Claude Opus 5 <[email protected]>
NomadicDaddy and others added 10 commits August 3, 2026 13:22
The move off preinstall, the publishable manifest, the dist/ entry points, and
the node shebang were all hand-verified only. package-distribution.test.ts runs
require-bun.ts as a process under a spoofed npm user agent and again under a bun
one, and pins the manifest and tsconfig shape around it.

Also pins the release workflow's node step, which is the one automated defense
against a bun-only API reaching src, and rewrites the deployment-guide test that
pinned a tag inventory that had gone stale.

Co-Authored-By: Claude Opus 5 <[email protected]>
Prettier trailingComma moves from "es5" to "all", which reformats the
source, the scripts, and the tests. Adding a later argument or array
element is now a one-line diff instead of two, and this matches the
sibling repositories the shared hooks and license core come from.

No behavior changed.

Co-Authored-By: Claude Opus 5 <[email protected]>
leak-guard.sh scans the staged index diff for credential shapes and for
machine-local private literals, so a secret is caught before the commit
is written rather than at the remote boundary. leak-guard-setup.sh seeds
the tier-two pattern file at ~/.config/leak-guard/patterns, outside the
repository, and never overwrites an existing one.

check-leak-guard.sh self-tests the guard against a scratch repository.
Every leaky fixture is assembled at runtime by concatenation so no
literal the guard would flag is written into a tracked file.

All three are byte-identical with the aidd and spernakit copies. Nothing
runs them yet; the wiring follows.

Co-Authored-By: Claude Opus 5 <[email protected]>
generate-third-party-licenses.ts resolves the declared production
dependencies and the closure bun.lock locks beneath them, then writes
THIRD_PARTY_LICENSES.md and THIRD_PARTY_NOTICES.md. The summary records
which licenses are involved; the appendix reproduces each package's own
copyright line, license text, and NOTICE file, which is what MIT, BSD,
ISC and Apache-2.0 each require a redistributor to pass on.

It is the policy gate as well as the writer. A license family with no
reviewed notice text, a copyleft package with no recorded distribution
analysis, or a package it cannot locate on disk stops the run, because
the alternative is a document that reads as complete and is not.

The scope sections describe what StarSync actually distributes.
build:bundle passes --packages=external, so the published tarball
carries no third-party code and deliberately omits both documents: a
consumer's own resolver picks the versions it installs. bun run compile
is the opposite case and gets its own section, since it embeds the whole
closure plus the LGPL-linked Bun runtime.

check-license-core.ts and scripts/lib/license-core/ are the shared core,
synced from spernakit. The nested-version lookup in resolve.ts treated
a scope directory such as @octokit/ as a package directory, so under a
hoisted install it reported an installed package as missing; that fix
was made upstream and carried into every repository holding the core.

Co-Authored-By: Claude Opus 5 <[email protected]>
pre-commit runs the leak guard over the staged diff, then the static
checks, and adds check:licenses when bun.lock or package.json is staged.
It reads the staged file list into a variable rather than piping it:
under set -o pipefail a matching grep -q can close the pipe early, git
takes SIGPIPE, and the check is skipped on exactly the commits that
stage a dependency manifest. The hook is byte-identical with the aidd
and spernakit copies and depends only on the script names smoke:qc:fast,
check:licenses and check:leak-guard, so each repository is free to
implement them differently.

smoke:qc splits in two. smoke:qc:fast is the static subset with no
tests, which is what the hook runs; smoke:qc keeps everything and now
also runs the leak-guard self-test and both license checks. prepare
points core.hooksPath at .githooks/ and seeds the pattern file, so bun
install is what installs the hook.

@octokit/rest is pinned to an exact version. The attribution documents
are generated from the lockfile, so a caret range lets an install move
the closure away from what they describe.

Co-Authored-By: Claude Opus 5 <[email protected]>
Records the third-party attribution generator, the commit-time leak
guard, the smoke:qc split, and the screenshot-guard fix, and bumps the
manifest to match the new changelog section.

The README Scripts table picks up the license and leak-guard commands,
and the License section now explains what the two attribution documents
cover, why neither ships inside the published tarball, and why they
still matter to anyone distributing the compile executable.

Co-Authored-By: Claude Opus 5 <[email protected]>
perfectionist/sort-sets rejects the set literal in the sibling
repositories that carry this same license core, so the shared file could
not pass lint where it came from. Ordering only; the entries skipped are
unchanged.

Co-Authored-By: Claude Opus 5 <[email protected]>
Enable the seven perfectionist rules aidd and spernakit enforce and this
repo did not: sort-array-includes, sort-heritage-clauses,
sort-intersection-types, sort-maps, sort-named-exports, sort-named-imports,
and sort-sets. The missing sort-sets is why a shared licence-core file could
pass lint here while failing it in the repo it is synced from.

Raise every perfectionist rule and consistent-type-imports from warn to
error to match; --max-warnings 0 already made those equivalent, so the gate
does not move. Pass --report-unused-disable-directives in lint and lint:fix
as both siblings do, and replace the deprecated tseslint.config entry point
with defineConfig from eslint/config.

sort-jsx-props stays out: there is no JSX here and the lint globs cover .ts
only, so it could never fire.

The 20 resulting violations are applied via lint:fix. All are import
specifier reorders, one intersection-type reorder, and the environment-key
set in src/lib/git-exec.ts, which is read only through .has() and does not
depend on its order.

Co-Authored-By: Claude Opus 5 <[email protected]>
`smoke:qc:fast` now runs a new `lint:fast` that passes ESLint's --cache, while
`smoke:qc` keeps running the plain uncached `lint`. That cache keys on each
file's own content, so with type-aware rules a type change in one file can
create a violation in another the cache then treats as unchanged and skips.
Keeping it out of the full gate means the authoritative run always sees
everything.

`smoke:qc` no longer delegates to `smoke:qc:fast` for its first four steps,
since doing so would have handed the full gate the cached lint.

Co-Authored-By: Claude Opus 5 <[email protected]>
Records the lint gate split, the perfectionist rule alignment with the
sibling repositories, and the sorted skipped-entries set in the shared
license core. All internal tooling, so a patch bump.

Co-Authored-By: Claude Opus 5 <[email protected]>
@NomadicDaddy
NomadicDaddy merged commit c33bd7e into main Aug 4, 2026
3 checks passed
@NomadicDaddy
NomadicDaddy deleted the release/2.2.1 branch August 4, 2026 00:36
NomadicDaddy added a commit that referenced this pull request Sep 10, 2026
* docs(release): cut 1.1.1 changelog and bump version

* fix(tooling): delete misleading .nvmrc file

- .nvmrc contained '24' implying Node.js v24 runtime; project uses Bun exclusively

- packageManager [email protected], only-allow bun preinstall hook, bun-types confirm Bun-only

- File was previously deleted in 3de0117 but re-added in 1d4ffb2 ('deps')

- Verified git ls-files no longer tracks nvmrc; README already documents Bun >= 1.3.14

- package-manager-enforcement feature.json step #5 guards against reintroduction

* fix(licensing): add LICENSE file for declared MIT license

- package.json declares "license": "MIT" and lists LICENSE in files array, but the file was missing

- Any published tarball would have omitted the required license text (MIT violation)

- Created LICENSE with full MIT text, copyright Copyright (c) 2026 NomadicDaddy (matches author field)

- Prevention guard added to package-manager-enforcement feature.json spec step 6

- Resolves audit finding: audit-licensing-1784089532-license-file-missing-despite-package-json-license-field-and-readme-claim

- bun run smoke:qc passes (typecheck + lint + format:check)

* feat(cli): add archive CLI command suite with subcommand dispatch

- Register sync, verify, migrate, dates, init, unlock as explicit subcommands

- Each subcommand has shared target-path parsing and per-command --help output

- Not-yet-shipped subcommands exit 1 with 'not available in this release'

- Add sync --dry-run (query stars, inspect archive, no git operations)

- Add migrate --apply flag handling (deferred to 2.0)

- Route dates through extracted dates-command module

- Keep bare starsync and set-folder-dates as deprecated aliases with warnings

- Warn when starred_repos fallback path is used

- Add SUBCOMMANDS const and isSubcommand type guard to cli-utils

- New files: help-text.ts, subcommands.ts, dates-command.ts

- 19 new tests (41 total), smoke:qc + build pass

* feat(security): separate API auth from Git transport, add secret safety

- New src/lib/secret-safety.ts: URL credential detection, token redaction, GitHub.com host validation, Git auth error detection, credential guidance

- cloneOrPull: validates repository origins as GitHub.com before any git operation

- Git runs non-interactively (GIT_TERMINAL_PROMPT=0, core.askPass=) with auth failure guidance

- Remote URLs and error messages sanitized — embedded credentials stripped before output

- GitHub PAT patterns (ghp_…, github_pat_…) redacted from error messages

- Updated .env.example and README with authentication model documentation

- 25 new tests (66 total, all pass); smoke:qc, build pass

- Updated .aidd/features/git-authentication-and-secret-safety/feature.json: passes true, status completed

* docs(readme): correct glob scopes in script table for lint, format, and format:check

- Changed lint from eslint "**/*.ts" to eslint "src/**/*.ts"

- Changed format from prettier --write "**/*.ts" "*.json" to prettier --write "src/**/*.ts"

- Changed format:check from prettier --check "**/*.ts" "*.json" to prettier --check "src/**/*.ts"

- All three entries now match package.json verbatim

- Resolves audit finding audit-documentation-1784089535

* fix(licensing): add private:true to package.json to prevent accidental publish

- Added "private": true to package.json top-level

- Verified bun publish refuses with 'attempted to publish a private package'

- Updated package-manager-enforcement feature spec step #7 (prevention guard)

- Marked audit-licensing-1784089532-private-true finding as resolved

* fix(config): remove duplicate .claude/ and dist/ entries from .gitignore

- Removed second occurrence of .claude/ and dist/ from .gitignore

- Verified: sort .gitignore | uniq -d returns empty; git check-ignore confirms all paths still ignored

- Added prevention step #8 to gitignore-and-environment-protection feature.json

* fix(qc): remove redundant @typescript-eslint/eslint-plugin and parser devDeps

- The typescript-eslint meta-package (8.64.0) bundles both transitively

- Neither standalone package is imported in eslint.config.js or any source

- Verified: smoke:qc, lint, 66 tests, build all pass

- Added prevention step #8 to eslint-code-style-enforcement feature.json

* fix(qc): widen lint and format globs to cover scripts/ and test/ directories

- Widened lint, lint:fix, format, and format:check in package.json from src/**/*.ts to include scripts/**/*.ts and test/**/*.ts

- Fixed perfectionist/sort-imports error in test/index.test.ts (type import before value import with blank-line separation)

- Updated README.md Scripts table to reflect expanded glob scopes

- Prettier auto-fixed quotes in scripts/set-folder-dates.ts

Audit finding: audit-qc-pipeline-1784153818 (Critical)

* fix(qc): include bun test in smoke:qc quality gate

- Added && bun test to smoke:qc script in package.json so pre-commit gate includes unit tests

- Updated README.md Scripts table: smoke:qc now documents typecheck, lint, format check, test

- Updated .aidd/ spec.md, assertions.md, CHANGELOG.md, and build-and-compile-pipeline feature.json (prevention step #9)

- Verified: bun run smoke:qc passes (typecheck + lint + format:check + bun test, 66 tests)

* feat(sync): replace sequential pull loop with bounded concurrency refresh pool

- New src/lib/refresh.ts: bounded-concurrency pool (default 4, range 1-8) with per-repo progress (Syncing N/Total), safe refresh (fetch --tags --no-prune, ff-only when clean, block divergent/dirty), clone with transient retry, and graceful interruption (first SIGINT stops scheduling, second terminates)

- New src/lib/git-exec.ts: async execFile wrapper (no shell injection) with isTransientGitError classifier (auth/not-found/divergence/integrity never retried)

- New src/lib/api-retry.ts: withApiRetry retries 5xx/429 up to 2 times honoring retry-after/x-ratelimit-reset; 401/403/404/422 fail immediately

- Updated src/index.ts: --concurrency flag, runSyncPool/processRepository replaces sequential cloneOrPull loop, retained checkout tracking, detailed outcome summary (Added/Updated/Current/Blocked/Skipped/Retained/Failed)

- Updated src/lib/help-text.ts: --concurrency documentation in sync help

- Updated test/index.test.ts: 26 new tests for refresh pipeline, concurrency parsing, git-exec classification, api-retry (92 total, all pass)

* feat(cli): add structured command reporting

Add schema-versioned JSON output and shared human reporting across all subcommands.

Separate checkout lifecycle, pending rename, run outcome, and finding severity while preserving interruption and exit-code semantics.

Document the contract and verify with 104 tests, production build, and real CLI stream checks.

* feat(migration): add legacy archive preview

Implement read-only identity and rename planning for legacy archives.

Classify all 289 live checkouts without modifying archive metadata.

* feat(verify): add read-only archive verification

Verify legacy and managed archives locally for Git integrity, owner and checkout identity metadata, safe origins, blocked state, duplicate identities, and pending renames.

Add schema-versioned CLI reporting, interruption handling, read-only process-boundary tests, documentation, changelog, and completed archive-verification metadata.

* feat(api): add programmatic archive operations

Expose explicit Bun archive operations with structured reports, progress callbacks, and AbortSignal cancellation.

Delegate CLI commands to the library API, deprecate low-level exports, remove the Node engine declaration, and verify with 122 tests plus bundle and standalone builds.

* chore(git): hide .aidd metadata and guard against publishing it

This repo has a published remote, so its .aidd/ blueprint must never reach
GitHub: git history is retroactive and a push cannot be undone. Anchor the
ignore rule to the repo root (.aidd/ also matched nested directories) and keep
prettier out of it entirely — aidd owns the format of what it writes.

The pre-push guard blocks a push carrying .aidd history: a clean tip says
nothing about the commits behind it.

* chore: groom to workspace TS standards (config-only)

- package.json: pin eslint 10.7.0 (was ^10.6.0), typescript 6.0.3 (was ^6.0.3),
  only-allow 1.2.2 (was ^1.2.2); add --max-warnings 0 to lint and lint:fix scripts
- tsconfig.json: add allowSyntheticDefaultImports, erasableSyntaxOnly,
  noImplicitReturns, noUncheckedSideEffectImports
- eslint.config.js and .prettierrc already conform to standard (no change)
- AGENTS.md left untouched

Gate results (all pass, no surfaced errors):
- typecheck: pass
- lint: pass (0 warnings, --max-warnings 0)
- format:check: pass

* chore(tooling): replace only-allow Bun guard

* docs(release): cut 1.2.0 changelog and bump version

* feat(archive): initialize managed archives

- authenticate and persist exact archive owner metadata

- require explicit targets and enforce owner and format guards

- cover initialization and non-destructive failure paths

* feat(archive): lock archive operations

- serialize archive inspection and mutation with portable ownership metadata

- reclaim only confirmed-dead local locks and add risk-reported forced unlock

- route CLI, programmatic API, and deprecated dates entrypoint through locking

- cover Windows, macOS, Linux, stale, live, uncertain, and forced cases

* feat(archive): migrate managed checkout identities

- match and persist stable GitHub repository identities during sync

- apply resumable collision-safe canonical checkout migrations

- verify migration behavior through real Git process boundaries

* feat(archive): manage checkout archive dates

- derive Archive Dates from every reachable local Git reference

- normalize dates after sync and through the unified CLI and API

- add real-Git coverage and remove the standalone compatibility alias

* feat(sync): stage new checkout publication

- Clone and validate new managed checkouts before atomic publication

- Preserve occupied destinations and clean only owned staging directories

- Add isolated real-Git and focused retry, collision, and redaction coverage

* feat(release): add cross-platform validation gates

- run locked Bun quality, build, and compile checks on Windows, macOS, and Linux

- validate a representative copied archive offline and guard the opt-in live smoke target

- cover repository URL casing, suffix, SSH, trailing slash, and Unicode normalization

* docs(release): cut 1.3.0 changelog and bump version

* refactor(core): remove unreachable utilities

- Remove the unused synchronous archive lock wrapper

- Remove the unused aggregate subcommand help lookup

- Preserve directly consumed async locking and help exports

* ci(release): pin third-party actions

- Pin checkout v6 and setup-bun v2 to reviewed full commit SHAs

- Enforce immutable references and release-tag comments in release validation tests

* ci(release): bound validation runs

- Cancel superseded workflow runs within the same pull request or ref.

- Bound each platform job to 20 minutes and enforce the workflow contract in tests.

* test(release): expose cross-platform report failures

Make failed release-boundary assertions print their full reports so platform-specific findings remain actionable in CI.

* test(release): expose cross-platform report failures

Make failed release-boundary assertions print their full reports so platform-specific findings remain actionable in CI.

* docs(archive): reconcile managed archive documentation

- align README with the six live commands, explicit targets, staged publication, and the local Bun guard

- record explicit targeting and the command-level API as accepted implemented decisions

- keep ignored AIDD contracts and completion metadata authoritative on disk

* refactor(cli): remove public index dependency

- Move sync parser state into dependency-neutral CLI utilities

- Preserve parser and help compatibility through public re-exports

- Add regression coverage for dispatch imports and sync help

* fix(sync): isolate invalid managed checkouts

- Continue valid starred and retained checkout planning after identity scan failures

- Aggregate blocked and successful outcomes with exit code 1

- Cover normal, dry-run, and retained mixed archives

* fix(sync): follow remote default branch

- carry GitHub default_branch through managed sync planning

- switch or create the validated default branch before fast-forwarding

- cover clean, renamed, missing, dirty, divergent, and invalid branch states with real Git

* refactor(archive): enforce workflow source boundaries

- Split archive API, migration, verification, dates, and refresh coordinators behind stable facades

- Add source-shape enforcement and facade characterization coverage

- Document the check:max-lines quality gate

* fix(security): isolate git subprocess environments

- Add one allowlisted environment builder for every Git process boundary

- Prevent parent and override secrets from reaching Git helpers, hooks, or filters

- Cover async and synchronous boundaries with platform-variable retention tests

* chore(tooling): align formatter and lint pins

- Pin Prettier 3.9.6 and typescript-eslint 8.65.0 to the live workspace baseline.

- Regenerate the Bun lockfile and verify frozen install, typecheck, lint, formatting, tests, and build.

* chore(tooling): lint javascript configuration

- Add isolated ESLint coverage for eslint.config.js

- Enumerate tooling and TypeScript lint targets explicitly

- Keep ignored AIDD completion metadata validated locally

* feat(githooks): add screenshot artifact guard to pre-push hook

Block pushing version tags whose screenshot directory is missing or
incomplete. Releases v3.25.0–v3.28.2 shipped without visual records
because nothing enforced the artifact. The guard checks for directory
existence, a minimum PNG count, and a successful crawl-result.json
stamp when present.

Refactor the pre-push wrapper to capture stdin once and replay it into
each guard, since only the first consumer would otherwise see the ref
updates.

* feat(verify): add forced checkout recovery

* docs(release): cut 1.4.0 changelog and bump version

* fix(sync): stream live checkout progress

* docs(release): cut 1.4.1 changelog and bump version

* chore: add local deployment command

* test: make Git environment assertion cross-platform

---------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant