Dojang changelog
Version 0.3.0
To be released.
Command-line interface
-
Added
dojang mergefor divergent regular UTF-8 files on identity-copy routes. It runs a shell-free, machine-local three-way merge driver with owner-only inputs, explicit argument placeholders, an environment allowlist, and portable outcome codes from 1 through 255. Source, destination, and directory selectors,--driver,--driver-file,--dry-run, andpre-merge/post-mergehooks are supported. [[#48], [#75]] -
Merge publication is bound to the repository generation and the route policy observed for the conflict. Source, destination, and intermediate updates use identity-, content-, and mode-checked staging, and machine state is published only after one stable observation proves that all three replicas and their declared modes have converged. Concurrent edits, repository forgetting, recreation, and policy changes are checked before and after every replica replacement, so they leave a retryable conflict instead of accepting stale work. [[#48], [#75]]
-
Interrupted merge commits and state publication are recoverable on retry. Conditional replacement preserves the previous replica in a private sibling until publication is safe, while pending markers retain converged but unpublished work. Machine-state contents and their replacement directory entry reach stable storage before those markers are removed. New workspace directories and private markers are durably published before replica writes begin. Creation of the shared workspace ancestor is serialized across repositories, so a peer cannot use a visible directory before its durability barrier completes. Each marker authenticates the original and accepted contents of every replica, so any subset made durable by a crash can be recovered without replacing replicas that already contain the accepted contents and mode. Rejected baselines are removed without disturbing successful entries from the same transaction. [[#48], [#75]]
-
Failed, unresolved, and canceled workspaces remain available until recovery or
dojang forget. Workspace creation, scanning, marker updates, and cleanup are bound to pinned directory identities and validate complete ancestor chains, preventing replacement links from redirecting writes or removal outside machine-local state. Cleanup is serialized with repository lifecycle changes. [[#48], [#75]] -
Merge input changes and unreadable authoritative replicas are reported as conflicts. Invalid or unreadable successful driver output uses exit status 4, while workspace and replica write failures retain recovery data and use exit status 2. [[#48], [#75]]
-
Added
dojang init --from SOURCEto acquire, validate, enroll, and optionally apply an existing repository in one command. Local directories and.zip,.tar,.tar.gz, and.tgzarchives work without configuration. Machine-local external transports can run Git or another executable without a shell, with whole-argument source and destination placeholders and an explicit environment allowlist. Acquisition is staged beside the destination in an owner-only directory, rejects unsafe archive entries, including names that are reserved or invalid on Windows, and rejects paths that collide after case folding or Unicode normalization. It preserves recorded POSIX permissions where the destination filesystem supports them, requires an absent destination, and attempts to clean unpublished work after failure. Archive sources must resolve to regular files, so FIFOs and other special files are rejected without blocking. Unsupported permission metadata produces a warning without discarding the acquired contents. Stored permissions are restored while the repository is still private in staging, then an absent destination is published with one atomic no-replace directory rename. Existing paths, including empty directories and the current working directory, are rejected. If another process creates the destination first, publication fails without modifying that entry. Filesystems without an atomic no-replace rename are rejected rather than using an entry-by-entry fallback. External transport source and destination arguments and inherited environment values retain their native byte representation on POSIX. A dry run does not start an external transport and redacts its source argument, named credential argument values, and environment values, including sources whose native representation is not UTF-8. For local directory and archive sources, virtual publication preserves staged root and nested directory permissions so enrollment and apply previews match real execution. Directory sources and Unix ZIP archives reject FIFOs, sockets, devices, and other unsupported entry types before reading or extraction. Directory sources also reject paths that collide after case folding or Unicode normalization before copying begins. Directory source identities are pinned during validation, retained modes come from the same filesystem observations as their identities, regular files are checked through the same handles used to copy them, and the source tree membership and recorded entries are revalidated after copying. Concurrent additions, removals, replacements, type changes, and permission changes therefore stop publication. Archives changed while their bounded read is in progress are rejected with a retryable source-change error. ZIP directories marked with the DOS directory attribute are accepted even when their names omit a trailing slash. A destination nested inside its local directory source is rejected before staging is created. Standard tar archives whose first entry is./are accepted. A missing destination inherits the source root's permissions, including the target permissions when the directory source is a symbolic link. Permission restoration is verified after it is applied, so partial filesystem support produces the documented warning. POSIX reapplies mode0700after creating staging, so a restrictive umask cannot leave it unusable. Bootstrap rereads and parses the manifest under its final stored permissions before publication, rejecting archives that would make the published repository inaccessible. Explicit zero permission modes from Unix ZIP entries are retained instead of being treated as absent metadata. External transports run beneath an owner-only staging parent. Windows creates that parent with a protected, inheritable owner-only ACL and rejects filesystems that cannot enforce persistent ACLs. Archive input is limited to 16 MiB, expanded file contents to 64 MiB, entry counts to 10,000, paths to 4,096 characters, and path depth to 256 components, including bounded gzip decoding. Malformed PAX record lengths are rejected before conversion to a machine-sized integer. A relative WindowsAPPDATAtransport override falls back to the user's roaming application-data directory instead of resolving from the working directory. Broken Windows directory links retain their intrinsic link type, and interrupted publication widens restrictive staging before cleanup. Cleanup first moves the staging root to an operating-system-random quarantine path, checks the moved entry's recorded filesystem identity, and never recursively removes a concurrently created replacement. A failed restoration leaves the quarantine intact and reports its recovery path instead of silently hiding it. Directory traversal pins each opened directory and opens children without following links, so a transient directory-link replacement cannot redirect enumeration outside the source. An entry that vanishes after its name is enumerated is rejected as a concurrent source change instead of being silently omitted. Bootstrap also resolves and records the destination parent and its complete physical ancestor identity chain, revalidating the lexical target and that chain across preparation, acquisition, validation, and publication so an observed replacement aborts the operation. These boundary checks are not atomic with the following path mutation; cleanup and post-publication mismatches therefore warn that staging or a published copy may require manual removal. Noninteractive bootstrap requires both--no-interactiveand--yes. The selected bootstrap manifest must use a drive-less relative path inside the acquired repository without parent or symbolic-link components, and it must be a regular file no larger than 16 MiB. Staged validation parses bytes read through the validated handle, so a transport-created special file cannot block or redirect it. Manifest creation now writes complete bytes to a sibling temporary file before an atomic rename, while retaining ordinary creation permissions, so concurrent initialization and other readers cannot observe a partially written manifest. The rename never replaces a manifest created concurrently and rejects filesystems without an atomic no-replace primitive. On an unsupported filesystem, ordinarydojang initnow reports a file-write error and asks the user to move the repository before retrying. [[#47], [#74]] -
Added verified release installers for Linux and macOS on x86-64 and AArch64, and for Windows on x86-64. Installers download the release's SHA256SUMS file and reject an archive before installation when its checksum does not match. They can also leave the verified archive and checksums in an explicit directory without installing. Linux container images are built and tested with checksum-pinned official GHCup, GHC, and Stack artifacts for both architectures. After packaging each executable, the workflow extracts the final archive and checks its executable mode, version output, repository initialization, and status workflow. [[#47], [#74]]
-
Manifests can declare reusable sensitive-codec commands in
[codec-backends]. Each backend has a shell-free executable path, stable version, bounded timeout, and non-secret options. The new backend protocol types frame one JSON header line followed by the exact binary payload and accept only allowlisted structured failure categories. Codec errors preserve those categories without exposing backend diagnostics. Binary process requests and results redact their byte contents. [[#45], [#73]] -
Added the
encryptedcodec with reject reflection, the opt-inencrypted-re-addcodec with decrypt-after-encrypt validation, and thesecret-templatecodec with demand-drivensecret("backend", "item")lookups. These codecs require an explicitprivateorprivate-executableroute mode, publish new plaintext through owner-only temporary files, protect state snapshots, keep results command-scoped, suppress diff bodies, and remain offline during dry runs. File permissions are not encryption at rest. Backends run without arguments or inherited environment, and a timeout or interruption terminates the entire backend process group. Backends remain unavailable on Windows pending platform verification. [[#45], [#73]] -
Command execution now routes environment reads, platform detection, clocks, random identifiers, terminal checks, prompts, output, and child processes through explicit interpreters. Dry runs still accept interactive input but never start diff tools, editors, hooks, or other external programs. Hook processes are started while their repository state generation is validated, then awaited without holding the repository state lock so an explicitly allowed nested Dojang invocation cannot deadlock. If orchestration is interrupted after a hook starts, Dojang invokes the interpreter's cancellation action before propagating the interruption. [[#46], [#72]]
-
Detailed route branches can declare a byte-oriented
codec. The defaultidentitycodec preserves all existing behavior. Applying a route writes its rendered bytes through the intermediate snapshot, while status, diff, edit, and reflection use the same rendered source view. Registered codecs declare their inputs, dry-run behavior, cache scope, andidentity,reject, or validatedre-addreflection policy.--forcecannot bypass a codec's reflection policy. Codec diagnostics and plans redact source and rendered contents. The built-in diff reports non-UTF-8 rendered output as binary. File routes using a non-identity codec reject directory or symbolic-link destinations before changing repository files. Codec registration and configuration are validated even when the selected source is missing, before a forced operation can delete its destination. Before writing a buffered codec result, Dojang verifies that its authoritative input has not changed since evaluation. Cache-only dry runs reject codecs with external inputs before invoking their resolver. Codec failures use exit code 39. [[#43], [#70]] -
Added the built-in, deterministic
templatecodec. UTF-8 repository sources can use a pure Ginger/Jinja subset withvarsfor active manifest variables and case-insensitivefactsfor machine facts. Template variables never fall back to the process environment. Input dependencies are derived from each source so unrelated values do not invalidate its persistent cache; missing values fail only along the branch that executes. Diagnostics retain the missing input namespace and include source line and column while redacting contents; runtime-derived lookup keys are reported as<dynamic>, and invalid platform text identifies only the affected variable name. Partial Ginger arithmetic, formatting, and text-transformation operations are rejected before evaluation instead of terminating the process. Local bindings are validated in execution order and across every possible branch, and every valid Ginger script opener, including comment-prefixed forms, is rejected. Template reflection is rejected even with--force. [[#44], [#71]] -
Machine-state schema version 6 records only redacted codec metadata: the implementation name and version, configuration digest, cache key, and dependency fingerprints. Rendered bytes remain in the intermediate snapshot instead of being duplicated in state. A cached result is reused only when its deterministic key and recorded file fingerprint still match. Schema versions 1 through 5 remain readable. [[#43], [#70]]
-
Machine-state schema version 7 can record
updated-by = "merge"for a target whose source, destination, and intermediate snapshot converged through a three-way merge. Schema versions 1 through 6 remain readable. Earlier Dojang releases cannot read a state document after this version has rewritten it, even when no merge was performed. [[#48]] -
Detailed
[files]and[dirs]route branches can declare portable destination modes. The available modes areprivate(files0600, directories0700),executable(0755),private-executable(0700), andread-only(files0444, directories0555).dojang statusreports mode-only changes, whiledojang applyanddojang reflectrestore the declared mode even when the contents have not changed. Windows enforces onlyread-onlyand warns about other modes. Compact routes remain valid. Executable modes cannot be used for directory routes. [[#33], [#42], [#69]] -
A detailed route can set
kind = "symlink"to deploy a symbolic link whose target is the absolute path of the source in the repository.dojang applycreates missing links and repairs links after the checkout moves. It also recognizes a broken link whose target is already correct. An existing regular entry is a conflict unless--forceis used.dojang reflectrefuses deployment links, even with--force, and never follows a linked directory. Deployment links cannot declare a mode. On Windows, creating one requires Developer Mode or administrator privileges. [[#33], [#42], [#69]] -
Each destination entry is now owned by the route with the most specific destination. A broader directory route preserves entries owned by nested routes, and a deployed directory link forms a traversal boundary. Duplicate or aliased destinations, routes through deployment links, destinations that overlap the repository, and destinations that alias their own source are rejected before any files are changed. These configuration errors use exit code 38. [[#33], [#42], [#69]]
-
Added reusable, case-sensitive manifest variables in the
[vars]table. Values can be unconditional or selected by a moniker or environment predicate. Variables may reference one another in any declaration order, override inherited environment variables, and preserve an explicitly selected empty value. If no branch matches, lookup falls back to the inherited value. Reference cycles are reported before synchronization. Machine facts can select a variable branch but are not exposed as variable values. Manifest variables are configuration, not a place to store secrets. [[#33], [#40], [#68]] -
File routes, directory routes, and hook
working-directoryfields now use the same path-expression lookup. Relative hook working directories remain repository-relative. A literal dollar sign in a path expression must now be written as$$; existing hook working directories containing$must be updated. Values used by anon-changehook affect its fingerprint without being stored as plaintext. [[#33], [#40], [#68]] -
Manifests can distinguish machines with custom facts and the
fact.KEYpredicate syntax. Dojang also detects ahostnamefact. Fact names and values are case-insensitive, while the existing operating-system, architecture, and kernel predicates retain their behavior and specificity. Undefined facts warn and do not match, and declared facts cannot replace detected built-in facts. [[#33], [#41], [#67]] -
Put reusable, nonsecret machine values in the
[facts]table. Runningdojang initin an existing repository now enrolls the current machine and prompts for required facts. Noninteractive use can supply repeatable--fact KEY=VALUEoptions or reuse a TOML profile with--facts-file PATH. Repository-specific values override the shared profile, while-e/--env-fileremains a separate, higher-precedence simulation layer. Missing required values use exit code 22.dojang forgetremoves the repository's declared facts and profile association. Dry runs do not save enrollment. Facts may appear in diagnostics, state, and fingerprints, so they must not contain credentials. [[#33], [#41], [#67]] -
Machine-state schema version 5 records each route's declared kind and mode, using a deployment link's target as its fingerprint. Machine facts and shared-profile associations are also stored with the repository's state. Schema versions 1 through 4 remain readable. [[#33], [#40], [#41], [#42], [#67], [#68], [#69]]
-
Hooks can now run around the
apply,reflect,diff,status,edit, andunmanagecommands. Post-hooks run only after a successful command. Stable hook IDs supportonceand explicitly keyedon-changepolicies, with successful runs tracked for each repository and machine. Dry runs explain which hooks would run without starting them or updating history. Failed ignored hooks remain eligible for the next run. Hook processes receive the command, lifecycle event, repository, machine-state, platform, and selected-path context. [[#34], [#39], [#66]] -
Nested Dojang commands suppress hooks by default.
--allow-hook-recursionpermits one nested level but prevents a hook from re-entering itself in the same repository. Stateful hook runs are serialized, and forgetting then recreating a repository cannot let an old waiting or completed hook update the new state. [[#34], [#39], [#66]] -
Successful
dojang applyanddojang reflectoperations now record each managed destination and its last synchronized state. Partial failures update only entries that have already converged, and dry runs do not change these records. Route names that escape the source tree or normalize to the same path are rejected before synchronization. Path identity follows the host platform, including case-insensitive destination matching on Windows. [[#34], [#38], [#65]] -
dojang statusreports orphaned destinations when a route is removed, stops matching, changes definition, moves to another destination, or no longer produces a previously managed directory entry. It distinguishes unchanged, modified, and missing orphans without deleting them. Named pipes, sockets, devices, and other special entries are reported as modified without being read. [[#34], [#38], [#65]] -
Added
dojang unmanage --route ROUTE [DESTINATION ...]to discard orphan records and their unused snapshots without removing destination files. Modified destinations require--force.dojang forgetremoves only the selected repository's machine-local records, snapshots, and first-apply history; it leaves source and destination files alone. Interrupted cleanup can be retried, and other stateful commands wait until that cleanup is complete. [[#34], [#38], [#65]] -
Added versioned, repository-scoped machine state under the platform's user data directory. New repositories receive a stable
repository-id, and intermediate snapshots now default outside the worktree. Existing repositories must rundojang migrate, which copies and verifies the old .dojang/ snapshot before removing it and can resume an interrupted migration.--dry-rundoes not save migration work. Existing custom snapshots can be migrated in place with--intermediate-dir. [[#34], [#37], [#64]] -
Machine-state migration rejects snapshots that are missing, unowned, malformed, symlinked, or overlap protected paths. State and manifest replacement preserve native paths and POSIX modes, and corrupt or newer state files produce specific repair or upgrade guidance. Failed copy and cleanup work is journaled so that a retry cannot delete an unrelated or divergent directory. [[#34], [#37], [#64]]
-
The old ~/.dojang file no longer selects one global current repository. Dojang selects a repository automatically only when exactly one valid machine-state record points to its current checkout. Missing, reused, or ambiguous checkouts require
-r/--repository-dirinstead of falling back to another directory.dojang initanddojang migrateremain anchored to the current or explicitly selected directory, whiledojang env --ignore-env-filedoes not select a repository. First-apply history is tracked separately for each repository. [[#34], [#37], [#64]] -
Added detailed file and directory routes with ordered
monikeror inlinewhenconditions. Compact routes remain valid. Detailed routes can preserve repeated conditions, direct environment predicates, and null routes that the compact form cannot express without changing their meaning. [[#32], [#63]] -
dojang applyanddojang reflectnow inspect conflicts and destructive operations before executing one ordered reconciliation plan. A source-only change no longer blocksdojang reflect; only incompatible changes on both sides are conflicts. [[#28], [#31], [#62]] -
File and directory routes now use the same state observation and change calculation. Dojang detects symbolic links without following them, reports removed entries consistently, and compares equal-size regular files by content. [[#28], [#30], [#60]]
Haskell API
-
Added
MonadFileSystem.replaceFileIfSnapshot,MonadFileSystem.listDirectoryPinned, andwriteFileAtomicallyIfSnapshotfor content-, identity-, and mode-bound replacement of both the staged source and destination, mode staging, and non-recursive directory enumeration that cannot be redirected through a concurrent final-entry replacement. Filesystem-backed interpreters should override the new methods to provide their documented atomicity and pinning guarantees. [[#48], [#75]] -
Added
withMachineStateLockandwithRepositoryStateLockto serialize lifecycle work that observes absent state with concurrent machine-identity or repository-state creation. [[#48], [#75]] -
Added
CodecBackend, binary backend protocol framing, redacted binary process requests and results, and a timeout-aware command-effect boundary. Manifest writers reject backend declarations that the parser would reject. The six-argumentManifestpattern remains available for manifests without backends; usemanifestWithCodecBackendsorManifestWithCodecBackendsto preserve an explicit registry. [[#45], [#73]] -
Added effectful codec programs, backend runtime resolution, encrypted-file implementations, and demand-driven secret-template evaluation. Existing pure codec constructors remain source compatible.
CodecRuntime.resolveExternalInputnow returnsExternalInputFailure; embedding resolvers should useOpaqueExternalInputFailurefor untrusted details. Evaluations with declared backend inputs are command-scoped regardless of the implementation's cache setting, and captured inputs cannot be reflected through another codec definition. Effectful implementations are structurally command-scoped because backend request fingerprints do not attest to returned secret values. [[#45], [#73]] -
Added
MonadCommandEffect,MonadProcessControl, structured process and prompt requests, production and dry-run interpreters, and an exact scripted test interpreter.Appdelegates command effects to its selected interpreter, so embedding tests can replay complete commands without using host environment, clock, terminal, prompt, output, or process APIs. The scripted interpreter records process starts, waits, and cancellations separately, and rejects leaked processes.startAndAwaitAppProcessmasks the handoff from process startup to an interruptible wait and invokes the registered cancellation action on exceptional exits or application aborts.awaitProcessandcancelStartedProcessnow have fixed semantics over an opaqueStartedProcess.Appno longer has aMonadIOinstance: embedding code should add a dedicated effect, or useliftApponly at an interpreter or test boundary. Command exits now travel throughExceptT ExitCode; userunAppResultWithoutLogging,runAppResultWithLogging, orrunAppResultWithStderrLoggingto receive them as values. The older runners remain as compatibility adapters that throw the returned exit code. [[#46], [#72]] -
Added declarative codec types, deterministic cache keys, a controlled effect interpreter, typed redacted failures, and explicit runtime injection for apply, status, diff, edit, and reflect commands.
CodecImplementationtransformations are now pure rather than monadic; embedding applications must move filesystem, process, or secret lookup effects into the declared external-input resolver. Command-scoped evaluations are reused while the raw source remains stable. Forward and reverse transformations receive the validated route configuration. Their resolved inputs are frozen for re-add reflection, and manifest variables reach codecs as native operating-system bytes rather than a lossyTextconversion. Convergence publication rechecks the raw source.CodecEvaluationRequest.variablestherefore now usesMap Text ByteString. [[#43], [#70]] -
Added source-derived codec requirements and structured, source-positioned codec failures, plus
builtInCodecRuntimeand the built-in template codec specification and definition. The positionalCodecImplementationconstructor keeps its six arguments, while callbacks now returnCodecFailureandCodecRequirementsusesCodecInputSelection; replace input sets withrequiredCodecInputsornoCodecInputs. Embeddings can opt into source analysis withcodecImplementationWithSourceRequirements.codecRequirementsnow also accepts the raw source bytes. [[#44], [#71]] -
FileRoutebranches now carry aRouteTarget, which combines a path expression withRouteModeandRouteKind, instead of a bareFilePathExpression.RouteResultandManagedTargetexpose the selected metadata.MonadFileSystemcan observe portable modes and create symbolic links, and reconciliation plans include explicit mode, link, and ownership-preserving removal operations. [[#33], [#42], [#69]] -
Manifestnow has avariablesfield, andHook.workingDirectorychanged fromMaybe OsPathtoMaybe FilePathExpression. The existingmanifesthelper still creates a manifest with no variables; usemanifestWithVariablesto supply them.Context.variableGetternow reports provenance and warnings. [[#33], [#40], [#68]] -
Environmentnow stores custom facts inadditionalFacts. Code using the old three-argument constructor must callemptyEnvironmentor construct the four-field record. Record updates preserve custom facts. This source-incompatible change does not alter the CLI, manifest, environment-file, or machine-state formats. [[#33], [#41], [#67]] -
Manifest serialization now rejects invalid hook policy combinations and duplicate stateful IDs instead of writing a manifest that the parser would reject. Validated hook IDs remain abstract in the public API. [[#34], [#39], [#66]]
-
Manifest writing is total for detailed routes and uses the detailed form whenever the compact form would change condition semantics, priority, or multiplicity. [[#32], [#63]]
-
Added a pure, direction-aware reconciliation planner and a shared filesystem operation executor. Plans expose conflicts, skipped entries, and destructive operations before execution. [[#28], [#29], [#61]]
Version 0.2.1
Released on July 12, 2026.
-
Fixed a bug where
dojang reflectcrashed after deleting the intermediate copy when a managed file had been removed at its destination. Destination-side deletions are now reflected to the source and can also be selected by naming the deleted destination path explicitly. [[#24]] -
Fixed hook commands discarding the parent process environment. Hooks now inherit variables such as
PATHandHOME, while theDOJANG_*variables supplied by Dojang override any existing values. This allows hook commands and programs invoked by hook scripts to be found throughPATHas documented. [[#25]] -
Fixed
writeManifestsilently dropping file route predicates that could not be represented by a moniker or that collided after moniker resolution. It now returns aWriteError, andwriteManifestFileraises an I/O error, instead of writing an incomplete manifest. When multiple monikers represent the same predicate, the writer now selects the first name in a deterministic order. [[#26]]
Version 0.2.0
Released on January 19, 2026.
-
The
dojang initcommand now generates .gitignore if the source directory is a Git repository and the file does not exist yet. [[#16]] -
Fixed a bug that Dojang had not recognized
kernel.releasefield in a dojang-env.toml file unlike how it was documented and howdojang envcommand have behaved. [[#17]] -
Added disambiguation for ambiguous source paths in the
dojang reflectcommand. When multiple routes map to the same destination, Dojang now:- Auto-selects the route if only one source file exists
- Shows an interactive prompt with full source paths and
(exists)labels - Warns when multiple source files exist (potential configuration issue)
- Supports
DOJANG_AUTO_SELECTenvironment variable (first,error) - Accepts
--sourceoption to explicitly specify which source to use
[[#22]]
-
Added the
dojang editcommand which opens the source file of a target file in the user's editor and applies changes after editing. [[#21]]- Editor detection priority:
--editoroption →$VISUAL→$EDITOR→ platform default (notepadon Windows,vion POSIX) - Use
--no-applyflag to skip automatic apply after editing - Use
--forceflag to skip conflict warnings - Use
--sequentialflag to edit files one at a time - Use
--sourceoption orDOJANG_AUTO_SELECTto resolve ambiguous routes - Non-existent target paths create empty source files before editing (prompts for route selection if multiple routes match)
- Editor detection priority:
-
Added a registry file (~/.dojang) that stores the repository path. This allows the
dojang editcommand to work from any directory. [[#21]]- Created automatically during
dojang apply - If the registry points to a different repository, Dojang prompts to overwrite (in interactive mode) or overwrites silently (in non-interactive mode)
- Created automatically during
-
Enhanced
dojang reflectanddojang editcommands to support batch operations. [[#18]]- Without arguments, shows all changed files and prompts for confirmation before processing
- Use
--all/-aflag to process all changed files without prompting - Directory arguments process all changed files within the directory
- Ignored files are skipped by default with a warning; use
--forceto include them - Use
--include-unregistered/-uflag to include unregistered files found in destination directories (prompts for route selection in interactive mode;dojang reflectonly, not yet fordojang edit)
-
Added pre/post apply hooks that run custom scripts before and after the
dojang applycommand. [[#19]]pre-apply: Runs before every applypre-first-apply: Runs only on first apply (when ~/.dojang doesn't exist)post-first-apply: Runs only on first apply, after file syncpost-apply: Runs after every apply- Hooks support conditional execution via
whenfield using environment predicates - Use
ignore-failure = trueto continue even if a hook fails - In dry-run mode, hooks print “Would run hook: …” instead of executing
- Environment variables available to hooks:
DOJANG_REPOSITORY,DOJANG_MANIFEST,DOJANG_DRY_RUN,DOJANG_OS,DOJANG_ARCH
Version 0.1.0
Initial release. Released on November 26, 2023.