Skip to content

Update base branch (#198)#220

Closed
cooper (czxtm) wants to merge 9 commits into
mainfrom
develop
Closed

Update base branch (#198)#220
cooper (czxtm) wants to merge 9 commits into
mainfrom
develop

Conversation

@czxtm
Copy link
Copy Markdown
Member

Summary

Test Plan

Docs

  • Docs updated (companion PR in darkmatter/nixmac-web: #___)
  • No docs update needed

cooper (czxtm) and others added 9 commits May 24, 2026 19:12
* chore(beads): nixmac-srn nightly release feature

* chore(beads): record PR #195 on nixmac-srn

* chore(beads): file nixmac-62s (TS build blocker) discovered triaging PR #195

* chore(beads): nixmac-srn shipping depends on nixmac-62s (TS build fix)

* fix(native): drop unused Plus and DropdownMenu imports (nixmac-62s)

Both imports were only referenced inside JSX comments, so tsc flagged
them (TS6133/TS6192) and broke the build check on main since bd658af.

The env.ts BooleanFromString errors mentioned in the issue do not
reproduce: apps/native resolves effect to 3.21.0 (transitive) which
still exports BooleanFromString. Only the root workspace pulls
effect@4.0.0-beta.62, but env.ts lives under apps/native.

Closes nixmac-62s.

* chore(beads): close nixmac-62s

* fix(native): migrate env.ts off Schema.BooleanFromString (effect 4.0)

The repo's bun.lock pins effect@4.0.0-beta.62 (no transitive effect@3.x).
4.0 removed Schema.BooleanFromString — which env.ts was using — so a
fresh `bun install --frozen-lockfile` (what CI does) produces a tree
where the import fails to compile. The earlier "doesn't reproduce
locally" diagnosis on nixmac-62s was misled by a stale symlink at
apps/native/node_modules/effect pointing into node_modules/.bun/effect@3.21.0/
left over from an older install run. Locally tsc resolved against the
stale 3.x version, where BooleanFromString still exists.

Migration:
- Replace `Schema.BooleanFromString` with
  `Schema.Literals(["true", "false"])` (4.0's plural array form; 3.x had
  variadic `Schema.Literal(...)` — these are not interchangeable).
- Coerce the validated string to `boolean | undefined` in code so the
  exported settings type matches the old BooleanFromString shape and
  downstream consumers (utils.ts:19's `!== true` check) don't need to
  change.
- Drop the auto-derived `Schema.Schema.Type<typeof Settings>` because
  the runtime shape we expose (with the string→bool coercion) differs
  from the decoded shape.

Strict parsing is preserved: any value other than "true"/"false" still
fails at decode time, same as the original.

Note: existing local installs with a stale apps/native/node_modules/effect
symlink will need `bun install` to refresh — the stale 3.x effect doesn't
have `Schema.Literals` (plural). One-time cost; matches CI from then on.

Refs nixmac-62s.

* chore(beads): file nixmac-rva (Storybook flake) + link as nixmac-srn blocker

* chore(beads): file nixmac-cmu (Rust dead_code) + link as nixmac-srn blocker

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* chore(beads): file nixmac-k8d (Monaco platform drift) + link as nixmac-srn blocker

* fix(beads): clean up stash-conflict markers in issues.jsonl

Previous commit 0895711 accidentally included unresolved 'Updated upstream
/ Stashed changes' markers from a botched git stash pop. Re-exporting via
bd export produces the correct merged state including nixmac-k8d as the
fourth nixmac-srn blocker.

* feat(ci): nightly develop→main release with minor version bump (#195)

* feat(ci): nightly develop→main release with minor version bump

Adds a GitHub Actions cron (09:00 UTC daily) that merges develop into
main and tags a vMAJ.(MIN+1).0 release. Exits silently when develop has
no new commits vs main.

The actual ship work is delegated to build.yaml's existing `tag` mode —
the nightly job just produces the merge commit and the tag, then atomically
pushes both. compute-version.sh gets a small defensive edit: when HEAD is
already tagged with a v* tag, `release` mode is demoted to `branch` so the
main-push event doesn't trigger a duplicate (patch-bumped) ship alongside
the tag-push event.

Prerequisites for the cron to push successfully:
- RELEASE_BOT_TOKEN secret (PAT with bypass), OR
- repo ruleset bypass for github-actions[bot] on main

Without either, `git push --atomic` fails on the protected main branch.
Workflow falls back to GITHUB_TOKEN so cron + script wiring can be tested
before bypass is granted.

Files:
- .github/workflows/nightly-release.yaml (new)
- ops/scripts/release/nightly-release.sh (new; supports DRY_RUN=1)
- ops/scripts/release/compute-version.sh (tag-aware release-mode skip)

* feat(ci): scope nightly release trigger to native build affecteds

Replace the simple "any commit on develop" trigger with the no-turbo
equivalent of `turbo run build --affected --filter=native`. Releases now
fire only when develop has changes inside the native workspace, its
transitive workspace deps (currently @nixmac/ui), or global build inputs
(root package.json, bun.lock, root tsconfig, Cargo.toml/lock).

This skips nights where develop only got CI/docs/release-script changes
so a minor version isn't burned on commits that wouldn't ship anything
different to users.

Adds ops/scripts/release/affected-paths.mjs which dynamically resolves
the affected path set by reading the root workspaces config and walking
workspace:* deps — no hardcoded list to maintain when new packages
appear.

Verified locally:
- Real diff (apps/native/*, Cargo.lock, etc.): release
- Synthetic diff (ops/, .github/, docs/, *.md): skip
- Synthetic diff (bun.lock only): release (global input)

* fix(ci): address Copilot review feedback on nightly-release

- next_minor_version: filter to stable vMAJ.MIN.PATCH only so disposable
  -test.N tags (used by build.yaml for signing rehearsals) can't pollute
  the bump base
- Remote tag existence check: use `git ls-remote --exit-code` with an
  exact ref pattern instead of `grep -q "${tag}"`, which would false-
  positive when a longer tag like v1.2.0-test.1 contains the candidate
  as a substring
- Docstring: align step 2 with actual behavior (logs a one-liner then
  exits 0, not strictly silent)
- Workflow: add concurrency group so a scheduled run + manual dispatch
  can't race on the same next-tag computation. cancel-in-progress=false
  to avoid aborting a half-completed merge+tag mid-flight

* docs(ci): align skip-message wording with affected-paths policy

Copilot follow-up: three places still described the skip condition as
"no new commits vs main" or "skip silently". The actual policy is the
affected-paths filter (no-turbo equivalent of
`turbo run build --affected --filter=native`), which can return false
even when develop has commits — they just don't touch the native build
graph.

- should_release docstring: "skip silently" → "skip (caller logs reason)"
- main() skip log: "develop has no new work" → "no changes affect the
  native build graph"
- workflow header: "no new commits vs main" → explanation of the
  affected-paths filter and what kinds of develop activity will no-op

No behavior change.

* fix(ci): nightly-release cwd-independence and ..→... range

Copilot follow-up. Two real bugs:

1. The script claimed cwd-independence via REPO_ROOT but only used it for
   the affected-paths.mjs invocation. Every git command and the
   `node -p require('./package.json')` fallback ran relative to the
   caller's cwd, so invoking the script from anywhere other than the
   repo root would fail. main() now `cd`s into REPO_ROOT before doing
   any work, which makes the cwd-independence claim actually true.

2. should_release used `git diff origin/main..origin/develop` (two-dot
   range), which is tip-to-tip. If main has a hotfix not on develop,
   two-dot treats it as a develop-side deletion and flags it as a
   change — falsely triggering a release every night until the hotfix
   gets merged back. Three-dot (`origin/main...origin/develop`) diffs
   from the merge-base, so only commits new on develop are counted.

Verified locally: running the script from /tmp now produces the same
dry-run plan as running from the repo root. Two-dot vs three-dot on
current origin/main vs origin/develop differs by one file, confirming
there is currently a hotfix-style commit on main that the old check
would have erroneously counted.

* docs/fix(ci): nightly-release token fallback + optional-env docstring

Copilot follow-up:

1. Workflow checkout's token fallback used `secrets.GITHUB_TOKEN` as the
   `||` second operand. While that *does* work in normal expression
   contexts (it's GitHub's documented way to reference the auto-injected
   token), the `github.token` context form is more reliable in fallback
   positions and `if:` evaluations. Switched to
   `secrets.RELEASE_BOT_TOKEN || github.token` for that defensive reason.

2. Header docstring claimed GIT_USER_NAME / GIT_USER_EMAIL were "Required
   env" but the code uses `if [[ -n "${VAR:-}" ]]` guards and silently
   skips git config when unset. They're actually optional CI overrides
   that fall back to the caller's existing git config — fine for local
   rehearsals, expected to be set in CI for bot-identity attribution.
   Updated the comment to match the actual code.

No behavior change.

* fix(ci): defensive Copilot follow-ups on nightly-release

1. DRY_RUN expression now gates on `github.event_name == 'workflow_dispatch'`
   before reading `inputs.dry_run`. The `inputs.*` context is only
   populated for dispatch events; gating ensures scheduled cron runs
   always get '0' regardless of how GitHub resolves missing-input refs.

2. compute-version.sh tag-skip regex now anchored with `$` so disposable
   `v0.22.0-test.N` tags (used for signing/notarization rehearsals)
   don't suppress legitimate `main`-push releases. Test tags don't ship
   (publish/R2/Linear steps in build.yaml skip them), so main-push must
   still bump+ship normally if such a tag happens to be at HEAD.
   Verified: `v1.2.3` matches the regex (correctly skips release mode),
   `v1.2.3-test.1` does not match (correctly does not suppress).

3. affected-paths.mjs now normalizes `package.json#workspaces` to handle
   both the npm/bun array form and the Yarn object form
   (`{ packages: [...] }`). nixmac uses the array form today; supporting
   both is cheap future-proofing if the repo ever switches package
   manager.

* docs/fix(ci): nightly-release docstring + unconditional fetch

Copilot follow-up:

1. Header step 4 said "Fast-forward / no-ff merge" but the implementation
   always uses `git merge --no-ff`. Updated the comment to match the
   actual behavior (always produces a merge commit so the release
   boundary stays visible in git log --first-parent).

2. `git fetch` was DRY_RUN-gated, but should_release and
   next_minor_version both query local refs (origin/main..origin/develop
   diff + `git tag --list` for the latest stable). On a stale checkout
   the dry-run could compute a wrong next version or false-positive
   "nothing to release". Unwrap the fetch from `run` so it always
   executes — fetch is read-only from the project's perspective (only
   updates local origin/* refs), so unconditional execution is safe and
   makes dry-run output reflect real remote state.

Verified: the unconditional fetch pulled a fresh v0.23.2 tag on this
run that the local checkout didn't have, validating the fix on its
first execution.

* fix(native): fix Chromatic Storybook

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix(native): env.ts — drop version-skewed Schema.Literal for plain String

PR #195 build broke at TS2554 ("Expected 1 arguments, but got 2") after
80a19c6 reverted NIX_INSTALLED_OVERRIDE from `Schema.Literals([...])` to
`Schema.Literal(...)` (variadic). The problem: `Schema.Literal`'s signature
is fundamentally version-skewed —

  effect 3.x:       `Literal<L>(...values: L)`     variadic, multi-value
  effect 4.0-beta:  `Literal<L>(value: L)`         single value only,
                    use `Literals([...])` for sets

So neither form source-compiles in both:

- `Schema.Literal("true", "false")` works in 3.x, fails 4.0 (this PR)
- `Schema.Literals(["true", "false"])` works in 4.0, fails 3.x (Chromatic)

The repo's lockfile pins effect 4.0-beta, so tsc sees that — but the
Chromatic/storybook test environment can resolve 3.x via workspace
symlink hoisting, which is why 80a19c6 picked the 3.x form to fix
Chromatic and broke the build instead.

Fix: validate with plain `Schema.String` (signature is identical across
versions) and coerce to boolean in code via
`raw.NIX_INSTALLED_OVERRIDE === "true" ? true : undefined`. The only
downstream consumer is `settings.NIX_INSTALLED_OVERRIDE !== true` in
widget/utils.ts, which treats any non-"true" value as functionally
false — so silent acceptance of unexpected strings is observationally
equivalent to coercing them to undefined. We lose schema-level
"must be 'true' or 'false'" strictness; we gain working CI on both
the build and Chromatic paths.

Verified against both effect@3.21.0 and effect@4.0.0-beta.62 symlinks
in isolation: no TS2554, no missing-Literals errors.

* fix(ci): nightly-release DRY_RUN final-message clarity

Copilot follow-up: the final `echo "Released ${tag}"` ran unconditionally,
so workflow_dispatch dry-runs printed "Released v0.24.0" even though the
merge/tag/push steps were only echoed. Now branches on DRY_RUN: prints
"Dry run complete — would have released ${tag}" in dry mode, "Released
${tag}" in real mode. Behavior preserved; just the operator-facing log
line distinguishes the two modes.

Did not touch the `local changed paths file path` declaration in
should_release — Copilots claim that `path` is unused is incorrect.
`path` is the inner loops read variable on line 85 and is used in the
path-matching comparisons on lines 87, 89, 91, and 92.

* fix(ci): nightly-release working-tree guard + setup-node pin

Copilot follow-up:

1. Add a clean-working-tree guard before the destructive `git reset --hard
   origin/${MAIN_BRANCH}`. Local accidental invocations would otherwise
   silently obliterate uncommitted work. CI runners start clean by
   construction so the guard never fires in CI; DRY_RUN=1 bypasses it
   since dry-mode does not mutate the tree. Error path prints
   `git status --short` so the operator can see what would have been lost.

2. Add an actions/setup-node@v6 step pinned to node-version: 20 (matching
   build.yaml's convention). The release script invokes node for
   affected-paths.mjs and the package.json version fallback in
   next_minor_version. Without an explicit pin the cron would depend on
   whatever node the ubuntu-latest runner image ships, which is not stable
   across image updates.

Verified: bash -n passes, dry-run still works, guard simulation triggers
correctly on dirty tree and stays out of the way in DRY_RUN=1.

---------

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…ms (#189)

* refactor: update prompt messages to clarify actions for untracked items

* refactor: fix a couple of snapshot prompts and re-update all snaps
* feat: show duration in terminal after evolution complete

* fix(evolution-telemetry): show duration in toast after evolution, in addition to in console

---------

Co-authored-by: Juan Pedro Bolívar Puente <raskolnikov@gnu.org>
… turn, implement framework for related optimizations (#180)

* feat(evolve): implement memory strategy for evolution messages and enhance message retention

* feat(logging): implement chat log recording for Ollama and OpenAI providers

* feat(evolve): enhance message retention strategy with deduplication and filtering logic; fix apparent bad merge in shared.ts

* feat(evolve): bypass all filtering in the default retention setting

* Use env guard consistently

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* feat(logging): put back completion log dir env var behavior

* fix(evolution): update message filtering logic to use indexed iteration (fix issue with think pruning) and improve retention strategy handling

* refactor(evolution): update filter_evolution_messages to return EvolutionMessage and fix a couple code review issues with how those are handled

* fix: update default memory strategy to None for unknown configurations

* refactor: update logging for evolution iterations and adjust test for unknown memory strategy

* feat: move format_duration_secs to utils and add new unit tests

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: cooper <1325802+czxtm@users.noreply.github.com>
* chore(beads): nixmac-srn nightly release feature

* chore(beads): record PR #195 on nixmac-srn

* chore(beads): file nixmac-62s (TS build blocker) discovered triaging PR #195

* chore(beads): nixmac-srn shipping depends on nixmac-62s (TS build fix)

* fix(native): drop unused Plus and DropdownMenu imports (nixmac-62s)

Both imports were only referenced inside JSX comments, so tsc flagged
them (TS6133/TS6192) and broke the build check on main since bd658af.

The env.ts BooleanFromString errors mentioned in the issue do not
reproduce: apps/native resolves effect to 3.21.0 (transitive) which
still exports BooleanFromString. Only the root workspace pulls
effect@4.0.0-beta.62, but env.ts lives under apps/native.

Closes nixmac-62s.

* chore(beads): close nixmac-62s

* fix(native): migrate env.ts off Schema.BooleanFromString (effect 4.0)

The repo's bun.lock pins effect@4.0.0-beta.62 (no transitive effect@3.x).
4.0 removed Schema.BooleanFromString — which env.ts was using — so a
fresh `bun install --frozen-lockfile` (what CI does) produces a tree
where the import fails to compile. The earlier "doesn't reproduce
locally" diagnosis on nixmac-62s was misled by a stale symlink at
apps/native/node_modules/effect pointing into node_modules/.bun/effect@3.21.0/
left over from an older install run. Locally tsc resolved against the
stale 3.x version, where BooleanFromString still exists.

Migration:
- Replace `Schema.BooleanFromString` with
  `Schema.Literals(["true", "false"])` (4.0's plural array form; 3.x had
  variadic `Schema.Literal(...)` — these are not interchangeable).
- Coerce the validated string to `boolean | undefined` in code so the
  exported settings type matches the old BooleanFromString shape and
  downstream consumers (utils.ts:19's `!== true` check) don't need to
  change.
- Drop the auto-derived `Schema.Schema.Type<typeof Settings>` because
  the runtime shape we expose (with the string→bool coercion) differs
  from the decoded shape.

Strict parsing is preserved: any value other than "true"/"false" still
fails at decode time, same as the original.

Note: existing local installs with a stale apps/native/node_modules/effect
symlink will need `bun install` to refresh — the stale 3.x effect doesn't
have `Schema.Literals` (plural). One-time cost; matches CI from then on.

Refs nixmac-62s.

* chore(beads): file nixmac-rva (Storybook flake) + link as nixmac-srn blocker

* chore(beads): file nixmac-cmu (Rust dead_code) + link as nixmac-srn blocker

* Raise log summarizer completion budget

Co-authored-by: cooper <czxtm@users.noreply.github.com>

* Fix prompt input API import after conflict merge

Co-authored-by: cooper <czxtm@users.noreply.github.com>

---------

Co-authored-by: Cooper Maruyama <me@cooperm.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: cooper <czxtm@users.noreply.github.com>
Co-authored-by: cooper <1325802+czxtm@users.noreply.github.com>
…sitory root (#184)

* fix: refactor config directory handling to support different git repository root

- Updated a lot of utility functions to accept and utilize the git repository root instead of the config directory.
- Renamed `format_config_dir_context` to `format_repo_view_context` for clarity.
- Adjusted file operations to ensure they respect the git repository structure, which is the new escape boundary.
- Implemented caching for the git repository root in the store.
- Updated tests to validate behavior with respect to the new repository structure.
- Prompt engineering to get the agent to send the correct paths more reliably, including a new format for the subtree snapshot that gets rid of the ascii art which the agent struggles more with.

* fix: AI code review comments

* fix: more code review comments

* fix: validate repo-relative path in git file diff reads

Agent-Logs-Url: https://github.com/darkmatter/nixmac/sessions/80ae992b-8909-4b1c-82fe-ce6da6602ce5

Co-authored-by: czxtm <1325802+czxtm@users.noreply.github.com>

* Use path operations for max depth calculation

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* fix: bad auto-merge

* fix: unnecessary debug log

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: czxtm <1325802+czxtm@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* fix: update hard-coded data for system defaults "track" feature

A lot of them were wrong/misleading to the agent.

Also improved the coverage of the nix-darwin docs.

* fix: correct attribute for sound feedback setting in system defaults

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: cooper <czxtm@users.noreply.github.com>
Copy link
Copy Markdown
Member Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

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.

4 participants