oh-my-space 0.11.6 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,6 +13,10 @@ Declare external repositories in `oms.yaml` and sync them into `oms/<alias>/`. Y
13
13
  - You want to stay on a real branch during everyday submodule work instead of landing in a detached HEAD.
14
14
  - You want pointer changes to show up in `git status` so you can review them before committing.
15
15
 
16
+ ## Automation-first commands
17
+
18
+ OMS automates routine, deterministic preparation and bounded recovery whenever it can do so safely. It asks only when a choice depends on intent that cannot be inferred, such as creating missing root submodule topology. If safe completion or a useful degraded result is impossible, the error identifies the failed operation, the state that was preserved, and an actionable OMS command or bounded Git repair.
19
+
16
20
  ## Requirements
17
21
 
18
22
  - [Node.js](https://nodejs.org) `>=20.19.0` to run `oms`.
@@ -81,6 +85,50 @@ oms record api # commit the moved oms/api pointer in your
81
85
 
82
86
  Omit the alias or branch on `oms switch` and `oms checkout` to pick one interactively — synced submodules, and local or `origin/*` branches respectively.
83
87
 
88
+ ## Listing branches
89
+
90
+ `oms branch list [alias]` produces a current branch inventory for one declared submodule. Use an explicit alias, omit it to select the sole declaration automatically, or choose among multiple aliases interactively:
91
+
92
+ ```bash
93
+ oms branch list api
94
+ oms branch list
95
+ oms branch # choose list or delete interactively
96
+ ```
97
+
98
+ Before listing, OMS safely initializes an existing registered submodule when needed, reconciles every remote declared for that alias in `oms.yaml`, and runs `git fetch <remote> --prune` sequentially in manifest order. A failed fetch is retried once. If both attempts fail, cached refs remain visible as `stale`; a failed remote without usable refs is `unavailable`. These degraded states still exit 0 when local refs can be inspected. Extra local remotes are not fetched or included in the remote inventory, although an actual configured upstream on one of them remains visible for its local branch.
99
+
100
+ The output identifies the selected alias and detached HEAD when applicable, then prints:
101
+
102
+ - a `known`, `incomplete`, or `unknown` baseline summary, including reliable baseline names that have no matching local branch;
103
+ - a sorted LOCAL table with current/baseline flags, the exact configured upstream, and ahead/behind counts (`?` when an upstream is unavailable);
104
+ - a REMOTE table grouped in manifest order, with branch names sorted inside each `fresh`, `stale`, or `unavailable` remote.
105
+
106
+ When `branch` is omitted from `oms.yaml`, a successful origin fetch refreshes `origin/HEAD`; a failed refresh is reported as baseline uncertainty instead of blocking the inventory. Listing never switches, creates, deletes, merges, or pushes a branch, never changes or records a root gitlink, and never prints an `oms record` hint. An interactive user may explicitly delegate missing topology creation to `oms sync`; otherwise root topology remains unchanged. Exit 1 covers selection or safe-preparation refusal, and exit 2 covers automatic initialization or local-ref inspection failure. Run `oms branch list --help` for the authoritative behavior and examples.
107
+
108
+ ## Deleting a local branch
109
+
110
+ `oms branch delete [alias] [branch]` removes one **local** branch inside a single initialized submodule. It is deliberately narrow and safe:
111
+
112
+ ```bash
113
+ oms branch delete api feature/login # safe delete (git branch -d)
114
+ oms branch delete api feature/login --force # force delete (git branch -D)
115
+ oms branch delete # pick alias, then branch, interactively
116
+ oms branch # interactive list/delete action selector
117
+ ```
118
+
119
+ - **Local only.** It never deletes a remote branch or a remote-tracking ref, never fetches or pushes, and never stages or commits the root gitlink. A missing local branch whose name exists on `origin` is reported as local-only.
120
+ - **Protected branches.** The current branch and every resolved baseline are protected and cannot be deleted, even with `--force`. Baselines are the explicit `oms.yaml` `branch`, or the remote default (`origin/HEAD`) when `branch` is omitted, plus any branch recorded for the alias in a present, reliable `.gitmodules` version (working tree, index, or `HEAD`). Drift between these is reported and both are protected; a later `oms sync` reconciles the metadata. Unreadable, malformed, duplicate, or multi-valued baseline metadata fails closed with the offending source named.
121
+ - **Safe by default, one force retry.** A safe `git branch -d` is tried first. If Git rejects it (an unmerged branch) and the branch still exists, an interactive prompt offers a single force retry (default No); a non-interactive shell prints the exact `oms branch delete <alias> <branch> --force` command instead. Before every force deletion OMS prints the branch tip's full OID and a POSIX-shell-safe `git -C oms/<alias> branch <branch> <oid>` recreation command, and re-checks the OID so a branch that moved concurrently aborts (exit 2) rather than losing commits.
122
+ - **Preconditions.** Deletion is rejected while a merge/rebase/cherry-pick/revert/bisect/sequencer operation is in progress in the submodule, and for a detached HEAD unless it exactly matches the recorded root gitlink (which lets interrupted automatic initialization resume). Dirty submodule and root state do not block deletion. A registered-but-uninitialized alias named explicitly is initialized automatically (network access limited to that alias) and then revalidated.
123
+
124
+ ## Sync finalization and metadata reconciliation
125
+
126
+ `oms sync` finalizes topology and OMS-managed `.gitmodules` metadata through **one** decision, and reconciles that metadata from `oms.yaml`:
127
+
128
+ - **Authoritative manifest metadata.** For an initialized submodule, `oms.yaml` `remotes.origin` is authoritative: sync reconciles the local `origin` URL and the `.gitmodules` `url` to it, and writes an explicit `branch` (or removes the key when omitted). Sync validates the baseline after fetching — an explicit branch must exist on `origin`, and an omitted branch requires a resolvable `origin/HEAD` — and fails that alias otherwise **without** changing its metadata. Output names only the changed fields (`url`, `branch`), never URL values.
129
+ - **One finalization.** Reconciled metadata follows the same commit-or-unstage decision as topology: `--commit` (or the interactive default-Yes prompt) records topology and metadata together in one path-limited commit that also includes the complete current working-tree `oms.yaml`; without a commit, the changes are left unstaged.
130
+ - **Partial success and isolation.** A `--commit` that partially fails commits only the successful aliases through an owner-only temporary index, preserving unrelated staged paths, and exits non-zero with a summary. The temporary-index commit, a durable fsynced intent marker, and an atomically installed replacement index keep an interrupted commit recoverable: `sync`, `unsync`, and `record` run a shared recovery preflight that completes or safely blocks on leftover finalization state before mutating the root again.
131
+
84
132
  ## How `oms` uses Git submodules
85
133
 
86
134
  `oms` does not replace Git submodules. It adds a small command layer for the workflow details that make submodules awkward. Submodules already give you a reproducible pin (the parent records each source's exact commit), visibility (`git status` shows when a pointer moved), and history (the pointer travels with your commits). The friction is in everyday branch work, and that is what `oms` smooths over:
@@ -143,6 +191,8 @@ Skill firing is best-effort — an agent loads a skill only when it judges the s
143
191
  | `oms record [alias]` | workspace root or inside `oms/<alias>/` | Commits an existing root gitlink pointer update for one alias (`chore(oms): update <alias> submodule to <sha>`). | Root repo only, path-limited to `oms/<alias>`; refuses unrelated staged changes. Not for adds/removals — use `oms sync`/`oms unsync`. |
144
192
  | `oms switch [alias] [branch]` | workspace root | `git switch` to a LOCAL branch, creating it locally if it does not exist yet (no remote required). | `--from <ref>` sets the start point for a new branch. Omit alias/branch to pick interactively (or create a new branch). |
145
193
  | `oms checkout [alias] [branch]` | workspace root | `git fetch origin --prune`, then check out a REMOTE branch (`origin/*`) as a local tracking branch (or switch to an existing local counterpart). | Omit alias/branch to pick interactively. To create a brand-new local branch, use `oms switch`. |
194
+ | `oms branch list [alias]` | workspace root | Safely prepares one declared submodule, refreshes all declared remotes, and lists local and remote-tracking branches. | Shows baseline certainty, current/baseline flags, exact upstream divergence, detached HEAD, and per-remote `fresh`/`stale`/`unavailable` state. Never switches a branch or changes a root gitlink outside an explicitly accepted `oms sync`. |
195
+ | `oms branch delete [alias] [branch]` | workspace root | Deletes one LOCAL branch inside one initialized submodule with `git branch -d` (safe) or `-D` (`--force`). | Local only — never deletes a remote or remote-tracking ref, never touches the root gitlink. Protects the current branch and every resolved baseline (see below). Omit alias/branch to pick interactively; a registered-but-uninitialized alias is initialized first. Exit 0 on success, 1 on input/precondition errors, 2 on a declined/failed/concurrent deletion. |
146
196
  | `oms fetch ...` | workspace root | `git fetch <remote> --prune` in each submodule. | `--remote <name>` (repeatable) picks the remote(s); omit to choose interactively, defaults to `origin`. |
147
197
  | `oms pull ...` | workspace root | `git pull --ff-only <remote>` on each submodule's current branch. | Submodule branch only — never stages or commits the root gitlink. Rejects a dirty submodule; prints an `oms record <alias>` hint when the pointer moves. `--remote <name>` selects a single remote (defaults to `origin`). |
148
198
  | `oms push <alias>...` | workspace root | `git push <remote> <branch>` (creating the remote branch on first push). | Submodule branch only — never stages or commits the root gitlink. `--commit`/`--record` are unsupported; record the root pointer with `oms record <alias>`. `--remote <name>` (repeatable) picks the remote(s); upstream is set only for `origin`. |
@@ -206,6 +256,7 @@ JSON schema: [`oms.schema.json`](./oms.schema.json) (also reachable at `https://
206
256
 
207
257
  Detailed migration steps are organized per version under [`docs/migrations/`](./docs/migrations/).
208
258
 
259
+ - [0.11.x → 0.12.0](./docs/migrations/0.11.x-to-0.12.0.md) — adds `oms branch delete` and makes `oms sync` reconcile declarative `.gitmodules` metadata with stricter baseline validation and a durable finalization recovery preflight
209
260
  - [0.9.x → 0.10.0](./docs/migrations/0.9.x-to-0.10.0.md) — scopes each command to a single Git boundary and makes root pointer commits explicit via `oms record`
210
261
  - [0.7.x → 0.8.0](./docs/migrations/0.7.x-to-0.8.0.md) — splits `oms checkout` into `oms switch` (local branches) and `oms checkout` (remote branches)
211
262
  - [0.5.x → 0.6.0](./docs/migrations/0.5.x-to-0.6.0.md) — switches the data model from bare clone + worktrees back to git submodules
@@ -1 +1 @@
1
- {"commit":"0d3c13d83f032e684228796dd90e82cf8eb36575"}
1
+ {"commit":"be1d798a55c5e7fae0b33ef6057661a1ac25a5d7"}