* feat: add wmill protection-rules pull/push CLI commands
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor: use directional keys for protection-rules pull --json diff
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address review — exit non-zero on failure, resolve override workspace key
- failure paths in pull/push now exit 1 so CI/scripts detect failed reconciles
- --override writes under the resolved workspace key (findWorkspaceByGitBranch),
not the raw branch, so gitBranch-mapped entries aren't left inert
- pull --replace clears a shadowing protectionRules override so top-level takes
effect (was an infinite pull --diff loop)
- push reports applied create/update/delete counts on partial failure and warns
loudly when an empty list would wipe all backend rules
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address review — dry-run pull --diff no longer writes; --promotion coherent
- pull --diff returns before the no-wmill.yaml bootstrap, so a dry run never
creates/mutates wmill.yaml
- pull --promotion now writes/clears the promotion target's promotionOverrides
(the same block getEffectiveSettings reads), instead of the current branch's
regular overrides — read and write are now coherent
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor: move protection rules to a per-workspace protection-rules.yaml
Replaces the wmill.yaml/SyncOptions integration (top-level + overrides +
promotionOverrides) with a dedicated protection-rules.yaml keyed by workspace
name. This removes the getEffectiveSettings layering that caused the override
shadowing / promotion-coherence / dry-run bugs entirely.
- protection-rules.yaml: { <workspace>: ProtectionRuleEntry[] }, keys must
match wmill.yaml 'workspaces' (source of truth for backend id/baseUrl/token)
- commands reduced to: pull/push [workspace] | --all, with --dry-run
- per-workspace auth resolved via tryResolveBranchWorkspace + setClient
- push remains a full reconcile (create/update/delete) with delete confirm,
empty-list wipe warning, partial-failure reporting, non-zero exit on failure
- conf.ts reverted to main; SyncOptions no longer carries protectionRules
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address review — honor explicit --base-url/--token in protection-rules
configureClientForWorkspace bypassed the credential precedence other commands
use: explicit --base-url/--token now work for stateless CI (no stored profile
or wmill.yaml baseUrl needed), and an explicit --token overrides a stored
profile's token. The backend workspace id still derives from the wmill.yaml
mapping (feature invariant).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address cubic review — consistent status on partial --all failure
cubic found that pull/push reported success:true while exiting non-zero on
partial --all failures, and that the push command description was missing from
the generated CLI docs.
- pull/push now report success:false + partialFailure:true (and exit 1) when
any --all workspace fails; success:true only on full success
- .description() calls use single string literals (not + concatenation) so
system_prompts/generate.py parses them; regenerated CLI docs
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: address review — --json-output must emit only JSON on stdout
Codex flagged that workspace resolution (tryResolveBranchWorkspace's log.info)
and push's empty-list delete warning print to stdout before the JSON payload,
breaking machine callers. Silence human logs via log.setSilent(true) as the
first action when --json-output is set (before readConfigFile / resolution);
log.error still goes to stderr.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>