oh-my-space 0.10.0 → 0.11.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
@@ -104,6 +104,29 @@ When an AI coding agent works in a workspace, the main risk is operating in the
104
104
 
105
105
  These are **root-repository files under `oms/`, not submodule files**. The managed block is delimited by `<!-- OMS START -->` / `<!-- OMS END -->`; content outside the markers is preserved, and `oms agent uninstall` removes only that block (deleting the file if it becomes empty). The files are created but never staged, so you review and commit them yourself.
106
106
 
107
+ ## Workspace skills
108
+
109
+ `oms` publishes three installable agent skills that carry the workspace Git guardrail to sessions started anywhere in the workspace — including at the root, which the [`oms agent install`](#ai-agent-workflow) marker under `oms/` cannot reach. They are installed with the external Vercel Labs `skills` tool (`npx skills`):
110
+
111
+ ```bash
112
+ npx skills add divlook/oh-my-space # project scope: install at the workspace root
113
+ npx skills add divlook/oh-my-space -g # global scope: available in every workspace
114
+ npx skills add divlook/oh-my-space --skill oms-pointer # install one skill by name
115
+ npx skills add divlook/oh-my-space --list # list the available skills without installing
116
+ ```
117
+
118
+ Project scope is the default and recommended: these skills are only relevant in an `oms.yaml` workspace, so a project install keeps them out of unrelated repositories. `oms skills` prints these commands, and `oms skills --install` runs the project install for you, resolving to the workspace root first and forwarding extra arguments (`-g`, `--skill`, `--list`, `--copy`) straight through.
119
+
120
+ The three skills are named by the Git domain each manages:
121
+
122
+ | Skill | Use it when | What it does |
123
+ | --- | --- | --- |
124
+ | `oms-workspace` | Scope-ambiguous Git work in the workspace — committing from the root, a moved `oms status` pointer, a push, or adding/removing a repo with `oms sync`/`oms unsync`. | Establishes workspace state and root-versus-submodule scope before acting, and separates repo add/remove topology from recording a moved pointer. |
125
+ | `oms-pointer` | After `oms commit` or `oms pull` moves a submodule's commit. | Records the moved root pointer with `oms record`, so a submodule change is not left without a recorded pointer and the root pointer is not committed by mistake. |
126
+ | `oms-branch` | Starting or switching a branch inside a submodule. | Chooses `oms switch` (new local branch) versus `oms checkout` (track a remote branch) and avoids detached HEAD. |
127
+
128
+ Skill firing is best-effort — an agent loads a skill only when it judges the skill's description relevant — so the skills complement, rather than replace, `oms <command> --help` and the always-on marker block inside `oms/`. Each skill defers exact `oms status --json` field semantics to `oms status --help`, the version-matched authoritative source that ships with the installed CLI.
129
+
107
130
  ## Command reference
108
131
 
109
132
  `oms.yaml` declares each source repo with `alias`, a `remotes` mapping (which must include `origin`), and optional `branch` (the baseline).
@@ -123,6 +146,7 @@ When an AI coding agent works in a workspace, the main risk is operating in the
123
146
  | `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`. |
124
147
  | `oms unsync <alias>` / `--all` | workspace root | `git submodule deinit` + `git rm` for the alias; drops an empty `.gitmodules`. | Keeps the `oms.yaml` entry. Use `--force` to discard uncommitted changes. Removal topology is left unstaged by default; commit via the prompt or `--commit` (`chore(oms): remove ...`). |
125
148
  | `oms agent install` / `uninstall` | workspace root | Manages a marker-delimited OMS instruction block in `oms/AGENTS.md` and/or `oms/CLAUDE.md` (root-repo files). | `--target agents\|claude\|both` (omit to choose interactively). Does not stage files. See [AI agent workflow](#ai-agent-workflow). |
149
+ | `oms skills` | anywhere (`--install` resolves to root) | Prints the `npx skills add divlook/oh-my-space` commands (project scope and `-g` global) to install the workspace skills. | `--install` delegates to `npx skills add`, forwarding extra args (`-g`, `--skill <name>`, `--list`). Run outside a workspace without `-g`, it errors and points to the global install. See [Workspace skills](#workspace-skills). |
126
150
  | `oms update` | anywhere | Checks the npm registry and safely updates the installed `oms` CLI only when it detects a confident global install. | Use `--check` for a non-mutating check. Use `--yes` to skip the confirmation prompt for confident global updates. Project-local, temporary runner, development, and unknown installs print guidance only. |
127
151
 
128
152
  ## Updating the CLI
@@ -176,37 +200,11 @@ Rules:
176
200
 
177
201
  JSON schema: [`oms.schema.json`](./oms.schema.json) (also reachable at `https://raw.githubusercontent.com/divlook/oh-my-space/main/oms.schema.json` for YAML LSPs).
178
202
 
179
- ## Behavior changes
180
-
181
- The AI-submodule-workflow update scopes each command to a single Git boundary and makes root pointer commits explicit. If you have existing automation, note these changes:
182
-
183
- - **`oms push --commit` is removed** (and `oms push --record` is unsupported). It fails before pushing. Push the submodule branch, then record the root pointer separately:
184
-
185
- ```bash
186
- # before
187
- oms push api --commit
188
-
189
- # after
190
- oms push api # pushes the submodule branch only
191
- oms record api # commits the moved oms/api pointer in the parent
192
- ```
193
-
194
- - **`oms pull` and `oms push` no longer stage the root gitlink.** They synchronize only the submodule branch; the moved pointer shows up in `git status` and is committed with `oms record <alias>`.
195
-
196
- - **`oms sync` and `oms unsync` no longer leave the root index staged.** Topology changes (`.gitmodules` and `oms/<alias>`) stay in the working tree, unstaged. Create the topology commit through the interactive prompt or with `--commit`:
197
-
198
- ```bash
199
- # before: sync left .gitmodules + oms/api staged for you to commit
200
- oms sync api && git commit -m "add api"
201
-
202
- # after: topology is unstaged by default
203
- oms sync api --commit # creates chore(oms): add api submodule
204
- ```
205
-
206
203
  ## Migration guides
207
204
 
208
205
  Detailed migration steps are organized per version under [`docs/migrations/`](./docs/migrations/).
209
206
 
207
+ - [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
208
  - [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
209
  - [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
212
210
  - [0.3.x → 0.4.0](./docs/migrations/0.3.x-to-0.4.0.md) — renames `sources.yaml`/`sources/` to `oms.yaml`/`oms/`
@@ -1 +1 @@
1
- {"commit":"0cc84f79dc3659f53fd76a39f9e5ecbe33337651"}
1
+ {"commit":"c69910168d4bea81b7b02079ee868a5d99b3cf2d"}
package/dist/oms.js CHANGED
@@ -2014,14 +2014,16 @@ async function finalizeTopology(repoRoot, requested, kind, commit, allSucceeded)
2014
2014
  }
2015
2015
  const OMS_MARKER_START = "<!-- OMS START -->";
2016
2016
  const OMS_MARKER_END = "<!-- OMS END -->";
2017
- /** Concise, durable agent rules; detailed usage is deferred to CLI help. */
2017
+ /** Canonical scope-guardrail kernel, single-sourced into the marker block and each published SKILL.md. */
2018
+ const OMS_SCOPE_GUARDRAIL = `- Run \`oms status --json\` before Git work involving \`oms/\` to read root versus submodule state.
2019
+ - Treat each \`oms/<alias>/\` directory as a separate Git repository.
2020
+ - Use \`oms\` commands for scoped submodule workflows; do not guess root repository versus submodule Git scope.
2021
+ - Do not create root commits for existing submodule pointer updates unless the user explicitly runs \`oms record <alias>\`.`;
2022
+ /** Concise, durable agent rules; detailed usage is deferred to CLI help. The marker's own --help line stays outside the kernel constant. */
2018
2023
  const OMS_INSTRUCTION_BLOCK = `${OMS_MARKER_START}
2019
2024
  ## OMS Workspace Rules
2020
2025
 
2021
- - Run \`oms status --json\` before Git work involving \`oms/\` to read root versus submodule state.
2022
- - Treat each \`oms/<alias>/\` directory as a separate Git repository.
2023
- - Use \`oms\` commands for scoped submodule workflows; do not guess root repository versus submodule Git scope.
2024
- - Do not create root commits for existing submodule pointer updates unless the user explicitly runs \`oms record <alias>\`.
2026
+ ${OMS_SCOPE_GUARDRAIL}
2025
2027
  - Check \`oms --help\` and \`oms <command> --help\` for exact command usage.
2026
2028
  ${OMS_MARKER_END}`;
2027
2029
  function countOccurrences(haystack, needle) {
@@ -2171,6 +2173,45 @@ async function runAgentUninstall(options) {
2171
2173
  }
2172
2174
  return 0;
2173
2175
  }
2176
+ /** npx skills package identifier for the oms workspace skills. */
2177
+ const SKILLS_REPO = "divlook/oh-my-space";
2178
+ /** Extra args forwarded to "npx skills add", read from argv so flags pass through verbatim. */
2179
+ function skillsForwardedArgs() {
2180
+ // process.argv: [node, oms.js, "skills", ...rest]; drop the "--install" flag and forward the rest.
2181
+ return process.argv.slice(3).filter((arg) => arg !== "--install");
2182
+ }
2183
+ /** Print the install commands, or with --install delegate to "npx skills add" from the workspace root. */
2184
+ async function runSkills(install, extraArgs) {
2185
+ const projectCommand = `npx skills add ${SKILLS_REPO}`;
2186
+ const globalCommand = `${projectCommand} -g`;
2187
+ if (!install) {
2188
+ log.info("Install the oms workspace skills with the skills tool:");
2189
+ log.message(` ${projectCommand} # project scope (run at the workspace root)`);
2190
+ log.message(` ${globalCommand} # global scope (every workspace)`);
2191
+ log.message("Add --skill <name> to install one (oms-workspace, oms-pointer, oms-branch), or --list to list them.");
2192
+ return 0;
2193
+ }
2194
+ const wantsGlobal = extraArgs.includes("-g") || extraArgs.includes("--global");
2195
+ const workspaceRoot = findWorkspaceRoot();
2196
+ if (!workspaceRoot && !wantsGlobal) {
2197
+ log.error(`"oms skills --install" must run inside an ${MANIFEST_FILENAME} workspace. ` +
2198
+ `For a global install from anywhere, run: ${globalCommand}`);
2199
+ return 1;
2200
+ }
2201
+ const args = ["skills", "add", SKILLS_REPO, ...extraArgs];
2202
+ const npxBin = testEnv("OMS_NPX_BIN") ?? "npx";
2203
+ const result = spawnSync(npxBin, args, {
2204
+ stdio: "inherit",
2205
+ cwd: workspaceRoot ?? process.cwd(),
2206
+ shell: runtimePlatform() === "win32",
2207
+ });
2208
+ if (result.error || result.status === null) {
2209
+ log.error(`Could not run "${[npxBin, ...args].join(" ")}".`);
2210
+ log.message(`Install the skills manually: ${projectCommand}`);
2211
+ return 1;
2212
+ }
2213
+ return result.status;
2214
+ }
2174
2215
  const INIT_TEMPLATE = `# yaml-language-server: $schema=https://raw.githubusercontent.com/divlook/oh-my-space/main/oms.schema.json
2175
2216
  repos:
2176
2217
  - alias: example
@@ -2420,7 +2461,12 @@ async function exitWith(action) {
2420
2461
  const exitHelp = "\nExit codes: 0 ok | 1 usage/config error | 2 one or more git operations failed.";
2421
2462
  // Per-command help: each new or changed command states its purpose, scope boundary, and an example.
2422
2463
  const statusHelp = `
2423
- Machine-readable mode prints exactly one JSON object on stdout (schemaVersion, root, repos, pointers).
2464
+ Machine-readable mode prints exactly one JSON object on stdout. The schemaVersion 1 payload has seven
2465
+ top-level keys: schemaVersion, toolVersion, workspaceRoot, currentAlias, root, repos, and errors.
2466
+ Submodule pointer movement lives under root.submodulePointers, with moved, staged, split, and conflict
2467
+ arrays (not a top-level "pointers" key). Each repos[] entry summarizes one oms/<alias>/ submodule
2468
+ (alias, path, branch, head, pin, dirty, ahead/behind, error). Read the live --json output for exact
2469
+ per-field values.
2424
2470
  Examples:
2425
2471
  $ oms status --json # full workspace state for tools and agents
2426
2472
  $ oms status api --json # narrow the JSON to one alias
@@ -2477,6 +2523,18 @@ Removes the marker-delimited OMS block; a file left empty is deleted. Missing fi
2477
2523
  Example:
2478
2524
  $ oms agent uninstall --target both
2479
2525
  `;
2526
+ const skillsHelp = `
2527
+ Installs the oms workspace skills (oms-workspace, oms-pointer, oms-branch) via the external "skills" tool.
2528
+ Project scope (installed at the workspace root, discovered from the root and its subdirectories) is the
2529
+ default; -g installs globally for every workspace. With --install, oms resolves to the workspace root and
2530
+ delegates to "npx skills add", forwarding extra arguments (-g, --skill <name>, --list, --copy) straight
2531
+ through to the skills tool.
2532
+ Examples:
2533
+ $ oms skills # print the project and global install commands
2534
+ $ oms skills --install # install the skills project-scoped at the workspace root
2535
+ $ oms skills --install -g # install the skills globally
2536
+ $ oms skills --install --skill oms-branch # install one skill
2537
+ `;
2480
2538
  const commandNames = new Set([
2481
2539
  "init",
2482
2540
  "doctor",
@@ -2491,6 +2549,7 @@ const commandNames = new Set([
2491
2549
  "push",
2492
2550
  "unsync",
2493
2551
  "agent",
2552
+ "skills",
2494
2553
  "update",
2495
2554
  "help",
2496
2555
  ]);
@@ -2636,6 +2695,16 @@ agentCommand
2636
2695
  .action(async (options) => {
2637
2696
  await exitWith(runAgentUninstall(options));
2638
2697
  });
2698
+ program
2699
+ .command("skills")
2700
+ .description("Print the command to install the oms workspace skills, or run it with --install.")
2701
+ .option("--install", "delegate to \"npx skills add\" (forwards extra args such as -g, --skill, --list)")
2702
+ .allowUnknownOption()
2703
+ .argument("[args...]", "extra arguments forwarded to \"npx skills add\" with --install")
2704
+ .addHelpText("after", `${skillsHelp}${exitHelp}`)
2705
+ .action(async (_args, options) => {
2706
+ await exitWith(runSkills(Boolean(options.install), skillsForwardedArgs()));
2707
+ });
2639
2708
  program
2640
2709
  .command("update")
2641
2710
  .description("Check for and safely update the oms CLI. Only confident global installs are updated automatically.")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-space",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "Manage multi-repo workspaces with Git submodules.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/divlook/oh-my-space",