@glrs-dev/cli 0.0.1 → 0.1.1

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.
Files changed (173) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +14 -15
  3. package/dist/chunk-3RG5ZIWI.js +10 -0
  4. package/dist/chunk-6RHN2EDH.js +93 -0
  5. package/dist/chunk-DEODG2LC.js +55 -0
  6. package/dist/chunk-FSAGM22T.js +17 -0
  7. package/dist/chunk-GQBZREK5.js +136 -0
  8. package/dist/chunk-HWMRY35D.js +139 -0
  9. package/dist/chunk-LMRDQ4GW.js +129 -0
  10. package/dist/chunk-NLPX2KOF.js +149 -0
  11. package/dist/chunk-P7PRH4I3.js +177 -0
  12. package/dist/chunk-VCN7RNLU.js +60 -0
  13. package/dist/chunk-VJFNIKQJ.js +120 -0
  14. package/dist/chunk-W37UX3U2.js +35 -0
  15. package/dist/chunk-YBCA3IP6.js +25 -0
  16. package/dist/chunk-YGNDPKIW.js +99 -0
  17. package/dist/cli.d.ts +1 -1
  18. package/dist/cli.js +89 -36
  19. package/dist/commands/cleanup.d.ts +19 -0
  20. package/dist/commands/cleanup.js +11 -0
  21. package/dist/commands/create.d.ts +17 -0
  22. package/dist/commands/create.js +12 -0
  23. package/dist/commands/delete.d.ts +17 -0
  24. package/dist/commands/delete.js +12 -0
  25. package/dist/commands/go.d.ts +4 -0
  26. package/dist/commands/go.js +11 -0
  27. package/dist/commands/list.d.ts +15 -0
  28. package/dist/commands/list.js +12 -0
  29. package/dist/commands/switch.d.ts +11 -0
  30. package/dist/commands/switch.js +12 -0
  31. package/dist/commands/types.d.ts +10 -0
  32. package/dist/commands/types.js +0 -0
  33. package/dist/index.d.ts +16 -19
  34. package/dist/index.js +4 -1
  35. package/dist/lib/config.d.ts +14 -0
  36. package/dist/lib/config.js +14 -0
  37. package/dist/lib/fmt.d.ts +12 -0
  38. package/dist/lib/fmt.js +25 -0
  39. package/dist/lib/git.d.ts +26 -0
  40. package/dist/lib/git.js +25 -0
  41. package/dist/lib/registry.d.ts +14 -0
  42. package/dist/lib/registry.js +13 -0
  43. package/dist/lib/select.d.ts +21 -0
  44. package/dist/lib/select.js +10 -0
  45. package/dist/lib/worktree.d.ts +35 -0
  46. package/dist/lib/worktree.js +17 -0
  47. package/dist/vendor/harness-opencode/dist/agents/prompts/agents-md-writer.md +89 -0
  48. package/dist/vendor/harness-opencode/dist/agents/prompts/architecture-advisor.md +46 -0
  49. package/dist/vendor/harness-opencode/dist/agents/prompts/build.md +93 -0
  50. package/dist/vendor/harness-opencode/dist/agents/prompts/code-searcher.md +54 -0
  51. package/dist/vendor/harness-opencode/dist/agents/prompts/docs-maintainer.md +128 -0
  52. package/dist/vendor/harness-opencode/dist/agents/prompts/gap-analyzer.md +44 -0
  53. package/dist/vendor/harness-opencode/dist/agents/prompts/lib-reader.md +39 -0
  54. package/dist/vendor/harness-opencode/dist/agents/prompts/pilot-builder.md +107 -0
  55. package/dist/vendor/harness-opencode/dist/agents/prompts/pilot-planner.md +153 -0
  56. package/dist/vendor/harness-opencode/dist/agents/prompts/plan-reviewer.md +49 -0
  57. package/dist/vendor/harness-opencode/dist/agents/prompts/plan.md +144 -0
  58. package/dist/vendor/harness-opencode/dist/agents/prompts/prime.md +374 -0
  59. package/dist/vendor/harness-opencode/dist/agents/prompts/qa-reviewer.md +68 -0
  60. package/dist/vendor/harness-opencode/dist/agents/prompts/qa-thorough.md +63 -0
  61. package/dist/vendor/harness-opencode/dist/agents/prompts/research.md +138 -0
  62. package/dist/vendor/harness-opencode/dist/agents/shared/index.ts +26 -0
  63. package/dist/vendor/harness-opencode/dist/agents/shared/workflow-mechanics.md +32 -0
  64. package/dist/vendor/harness-opencode/dist/bin/memory-mcp-launcher.sh +145 -0
  65. package/dist/vendor/harness-opencode/dist/bin/plan-check.sh +255 -0
  66. package/dist/vendor/harness-opencode/dist/chunk-VJUETC6A.js +205 -0
  67. package/dist/vendor/harness-opencode/dist/chunk-VVMP6QWS.js +731 -0
  68. package/dist/vendor/harness-opencode/dist/chunk-XCZ3NOXR.js +703 -0
  69. package/dist/vendor/harness-opencode/dist/cli.d.ts +1 -0
  70. package/dist/vendor/harness-opencode/dist/cli.js +5096 -0
  71. package/dist/vendor/harness-opencode/dist/commands/prompts/autopilot.md +96 -0
  72. package/dist/vendor/harness-opencode/dist/commands/prompts/costs.md +94 -0
  73. package/dist/vendor/harness-opencode/dist/commands/prompts/fresh.md +382 -0
  74. package/dist/vendor/harness-opencode/dist/commands/prompts/init-deep.md +196 -0
  75. package/dist/vendor/harness-opencode/dist/commands/prompts/research.md +27 -0
  76. package/dist/vendor/harness-opencode/dist/commands/prompts/review.md +96 -0
  77. package/dist/vendor/harness-opencode/dist/commands/prompts/ship.md +104 -0
  78. package/dist/vendor/harness-opencode/dist/index.d.ts +21 -0
  79. package/dist/vendor/harness-opencode/dist/index.js +2092 -0
  80. package/dist/vendor/harness-opencode/dist/install-4EYR56OR.js +9 -0
  81. package/dist/vendor/harness-opencode/dist/skills/agent-estimation/SKILL.md +159 -0
  82. package/dist/vendor/harness-opencode/dist/skills/paths.ts +18 -0
  83. package/dist/vendor/harness-opencode/dist/skills/pilot-planning/SKILL.md +49 -0
  84. package/dist/vendor/harness-opencode/dist/skills/pilot-planning/rules/dag-shape.md +47 -0
  85. package/dist/vendor/harness-opencode/dist/skills/pilot-planning/rules/decomposition.md +36 -0
  86. package/dist/vendor/harness-opencode/dist/skills/pilot-planning/rules/first-principles.md +29 -0
  87. package/dist/vendor/harness-opencode/dist/skills/pilot-planning/rules/milestones.md +57 -0
  88. package/dist/vendor/harness-opencode/dist/skills/pilot-planning/rules/self-review.md +46 -0
  89. package/dist/vendor/harness-opencode/dist/skills/pilot-planning/rules/task-context.md +47 -0
  90. package/dist/vendor/harness-opencode/dist/skills/pilot-planning/rules/touches-scope.md +47 -0
  91. package/dist/vendor/harness-opencode/dist/skills/pilot-planning/rules/verify-design.md +53 -0
  92. package/dist/vendor/harness-opencode/dist/skills/research/SKILL.md +350 -0
  93. package/dist/vendor/harness-opencode/dist/skills/research-auto/SKILL.md +283 -0
  94. package/dist/vendor/harness-opencode/dist/skills/research-local/SKILL.md +268 -0
  95. package/dist/vendor/harness-opencode/dist/skills/research-web/SKILL.md +119 -0
  96. package/dist/vendor/harness-opencode/dist/skills/review-plan/SKILL.md +32 -0
  97. package/dist/vendor/harness-opencode/dist/skills/vercel-composition-patterns/AGENTS.md +946 -0
  98. package/dist/vendor/harness-opencode/dist/skills/vercel-composition-patterns/README.md +60 -0
  99. package/dist/vendor/harness-opencode/dist/skills/vercel-composition-patterns/SKILL.md +89 -0
  100. package/dist/vendor/harness-opencode/dist/skills/vercel-composition-patterns/rules/architecture-avoid-boolean-props.md +100 -0
  101. package/dist/vendor/harness-opencode/dist/skills/vercel-composition-patterns/rules/architecture-compound-components.md +112 -0
  102. package/dist/vendor/harness-opencode/dist/skills/vercel-composition-patterns/rules/patterns-children-over-render-props.md +87 -0
  103. package/dist/vendor/harness-opencode/dist/skills/vercel-composition-patterns/rules/patterns-explicit-variants.md +100 -0
  104. package/dist/vendor/harness-opencode/dist/skills/vercel-composition-patterns/rules/react19-no-forwardref.md +42 -0
  105. package/dist/vendor/harness-opencode/dist/skills/vercel-composition-patterns/rules/state-context-interface.md +191 -0
  106. package/dist/vendor/harness-opencode/dist/skills/vercel-composition-patterns/rules/state-decouple-implementation.md +113 -0
  107. package/dist/vendor/harness-opencode/dist/skills/vercel-composition-patterns/rules/state-lift-state.md +125 -0
  108. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/AGENTS.md +2975 -0
  109. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/README.md +123 -0
  110. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/SKILL.md +137 -0
  111. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  112. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/advanced-init-once.md +42 -0
  113. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/advanced-use-latest.md +39 -0
  114. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/async-api-routes.md +38 -0
  115. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/async-defer-await.md +80 -0
  116. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/async-dependencies.md +51 -0
  117. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/async-parallel.md +28 -0
  118. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
  119. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +59 -0
  120. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
  121. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
  122. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
  123. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/bundle-preload.md +50 -0
  124. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
  125. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +71 -0
  126. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +48 -0
  127. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
  128. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +107 -0
  129. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
  130. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
  131. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
  132. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
  133. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/js-early-exit.md +50 -0
  134. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
  135. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/js-index-maps.md +37 -0
  136. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
  137. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
  138. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
  139. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
  140. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rendering-activity.md +26 -0
  141. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  142. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
  143. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
  144. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
  145. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
  146. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
  147. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
  148. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md +75 -0
  149. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
  150. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
  151. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
  152. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
  153. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
  154. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  155. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
  156. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rerender-memo.md +44 -0
  157. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
  158. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
  159. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
  160. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
  161. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
  162. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/server-auth-actions.md +96 -0
  163. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
  164. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/server-cache-react.md +76 -0
  165. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/server-dedup-props.md +65 -0
  166. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/server-hoist-static-io.md +142 -0
  167. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +83 -0
  168. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/server-serialization.md +38 -0
  169. package/dist/vendor/harness-opencode/dist/skills/web-design-guidelines/SKILL.md +39 -0
  170. package/dist/vendor/harness-opencode/package.json +11 -0
  171. package/package.json +20 -15
  172. package/LICENSE +0 -21
  173. package/dist/chunk-TU23AE2F.js +0 -69
package/CHANGELOG.md CHANGED
@@ -1,5 +1,55 @@
1
1
  # @glrs-dev/cli
2
2
 
3
+ ## 0.1.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [`050f4b9`](https://github.com/iceglober/glrs/commit/050f4b9bf2304dd5fb5031c38e7fe247b68ead07) Thanks [@iceglober](https://github.com/iceglober)! - **Rename `@glrs-dev/harness-opencode` → `@glrs-dev/harness-plugin-opencode` and republish.**
8
+
9
+ ## Why
10
+
11
+ OpenCode resolves plugins by npm-installing them into `~/.cache/opencode/packages/<plugin>@<version>/` at plugin-load time. The previous plan — marking `@glrs-dev/harness-opencode` as `private: true` and vendoring it only into `@glrs-dev/cli` — broke OpenCode's plugin loader because the package wasn't published on npm, causing `ETARGET: No matching version found for @glrs-dev/harness-opencode@1.0.0`.
12
+
13
+ The fix: publish the plugin under a new name (`@glrs-dev/harness-plugin-opencode`) so OpenCode can resolve it normally. The old name stays deprecated at its last published version (`0.16.2`).
14
+
15
+ ## What changed
16
+
17
+ - `packages/harness-opencode/package.json`: renamed from `@glrs-dev/harness-opencode` to `@glrs-dev/harness-plugin-opencode`, `private: true` removed, `publishConfig.access: public` + `provenance: true` added, version reset to `0.1.0` (fresh name on npm).
18
+ - The `install` / `uninstall` / `doctor` flows now write the new name to `opencode.json`'s plugin array.
19
+ - `@glrs-dev/cli` still bundles a vendored copy of the plugin for standalone subprocess dispatch (`glrs oc`), but the npm-resolved copy is what OpenCode's plugin runtime loads.
20
+ - Bin names unchanged — `harness-opencode` and `glrs-oc` still work.
21
+
22
+ ## Migration for existing users
23
+
24
+ Re-run `glrs oc install` to update your `opencode.json` plugin array from `@glrs-dev/harness-opencode` to `@glrs-dev/harness-plugin-opencode`. The old entry will be replaced; no data loss.
25
+
26
+ ## 0.1.0
27
+
28
+ ### Minor Changes
29
+
30
+ - [`37da38d`](https://github.com/iceglober/glrs/commit/37da38d0c0ffebf6758ef696644be3c79203eb4d) Thanks [@iceglober](https://github.com/iceglober)! - **First release of `@glrs-dev/cli` as the unified entry point for the @glrs-dev ecosystem.**
31
+
32
+ ## What's included
33
+
34
+ - `glrs oc <args>` — dispatches to a vendored copy of `@glrs-dev/harness-opencode` (the OpenCode agent harness). The harness-opencode bin is bundled inside this tarball at `dist/vendor/harness-opencode/`; no separate install needed.
35
+ - `glrs wt <args>` — worktree management (create, list, switch, delete, cleanup). Stores worktrees under `~/.glorious/worktrees/<repo>/<name>/`.
36
+
37
+ ## Install
38
+
39
+ ```bash
40
+ npm i -g @glrs-dev/cli
41
+ ```
42
+
43
+ Requires Bun >= 1.2.0 on PATH — the CLI and the vendored harness use Bun-native APIs (`bun:sqlite`, `Bun.spawn`).
44
+
45
+ ## Migration
46
+
47
+ - `@glrs-dev/harness-opencode` on npm is being deprecated. Its final published version (`0.16.2` or later) should be the last. Users should migrate to `glrs oc <args>`.
48
+ - `@glrs-dev/agentic` has been removed from the repo. Its worktree-management commands live natively under `glrs wt`.
49
+ - `@glrs-dev/assume` remains a separate, standalone package — install it independently if you need the SSO credential manager.
50
+
51
+ - [`b3ff224`](https://github.com/iceglober/glrs/commit/b3ff2249da36abb6669588ddf08d57c2d3b00464) Thanks [@iceglober](https://github.com/iceglober)! - Add `@research` agent and four bundled research skills (`research`, `research-web`, `research-local`, `research-auto`) to the vendored harness-opencode. `@research` is an Opus-class, `mode: all` orchestrator that decomposes research queries into parallel workstreams, dispatches per-workstream sub-agents using one of the four skills (multi-round umbrella, local codebase, web, or autonomous `.lab/` experimentation), reviews findings for gaps, iterates, and synthesizes. The existing `/research` slash command is rewritten as a thin delegator to `@research`; PRIME's subagent-reference recap gains an `@research` entry so its task-tool picker surfaces the agent alongside `@plan`, `@build`, `@code-searcher`, `@qa-reviewer`, etc.
52
+
3
53
  ## 0.0.1
4
54
 
5
55
  ### Patch Changes
package/README.md CHANGED
@@ -1,35 +1,34 @@
1
1
  # `@glrs-dev/cli`
2
2
 
3
- Unified CLI for the [@glrs-dev](https://www.npmjs.com/org/glrs-dev) ecosystem. One binary, three subcommands:
3
+ Unified CLI for the [@glrs-dev](https://www.npmjs.com/org/glrs-dev) ecosystem. One binary, two subcommands:
4
4
 
5
5
  ```bash
6
6
  npm i -g @glrs-dev/cli
7
7
  ```
8
8
 
9
9
  ```bash
10
- glrs oc install # → harness-opencode install
11
- glrs agentic wt new feature # gs-agentic wt new feature
12
- glrs assume login aws # gs-assume login aws
10
+ glrs oc install # → OpenCode harness install
11
+ glrs wt new feature # create a worktree
12
+ glrs wt list # list worktrees across repos
13
+ glrs wt switch # interactive picker
13
14
  ```
14
15
 
15
- Each subtool still ships its own direct bin — `harness-opencode`, `gs-agentic` / `gsag`, `gs-assume` / `gsa` — if you prefer typing those. The dispatcher exists to give new users one install command and one entry point to remember.
16
+ Requires [Bun](https://bun.sh) on PATH at runtime.
16
17
 
17
- ## How it works
18
+ The `harness-opencode` bin remains available directly for power users who prefer the untagged entry point.
18
19
 
19
- The `glrs` binary is a thin dispatcher. It:
20
+ ## How it works
20
21
 
21
- 1. Reads the first positional arg as the subcommand (`oc`, `agentic`, `assume`)
22
- 2. Resolves the underlying binary via `require.resolve(<package>/package.json)` → reads the `bin` field
23
- 3. Spawns the binary with the remaining argv forwarded, inheriting stdio
24
- 4. Exits with the child's exit code
22
+ The `glrs` binary has two subcommands:
25
23
 
26
- For the `assume` subcommand, the dispatcher imports `@glrs-dev/assume`'s exported `getBinaryPath()` directly and execs the prebuilt Rust binary skipping the TS shim middle-layer for interactive credential operations.
24
+ - **`glrs oc <args>`** dispatches to [`@glrs-dev/harness-plugin-opencode`](../harness-opencode/) (bundled as a dependency). Resolves the bin via `require.resolve(<package>/package.json)` reads the `bin` field spawns with argv forwarded.
25
+ - **`glrs wt <args>`** — worktree management, handled natively. Commands: `new`, `list`, `switch`, `delete`, `cleanup`. Worktrees are stored in `~/.glorious/worktrees/<repo>/<name>/`.
27
26
 
28
27
  ## Philosophy
29
28
 
30
- - **Don't duplicate CLI logic.** Every flag, every subcommand, every option lives in the underlying tool. The dispatcher adds no behavior.
31
- - **Don't fragment muscle memory.** `harness-opencode` / `gsag` / `gsa` keep working forever. `glrs` is additive, not a replacement.
32
- - **One install, one thing to remember.** For new users in the @glrs-dev ecosystem, `npm i -g @glrs-dev/cli` gets them everything.
29
+ - **Don't duplicate CLI logic.** `glrs oc` is a thin spawn wrapper around `harness-opencode`.
30
+ - **One install, one thing to remember** for the harness + worktree workflow.
31
+ - **Separate concerns stay separate.** The SSO credential tool [`@glrs-dev/assume`](../assume/) is a standalone Rust binary installed separately.
33
32
 
34
33
  ## Docs
35
34
 
@@ -0,0 +1,10 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ export {
9
+ __require
10
+ };
@@ -0,0 +1,93 @@
1
+ import {
2
+ go
3
+ } from "./chunk-DEODG2LC.js";
4
+ import {
5
+ currentBranchIn,
6
+ gitInSafe,
7
+ gitRoot,
8
+ gitSafe,
9
+ listWorktrees
10
+ } from "./chunk-LMRDQ4GW.js";
11
+ import {
12
+ loadRegistry
13
+ } from "./chunk-VCN7RNLU.js";
14
+ import {
15
+ bold,
16
+ dim
17
+ } from "./chunk-YBCA3IP6.js";
18
+
19
+ // src/commands/list.ts
20
+ import * as path from "path";
21
+ import { command, flag } from "cmd-ts";
22
+ var list = command({
23
+ name: "list",
24
+ aliases: ["ls"],
25
+ description: "List all worktrees across repos",
26
+ args: {
27
+ interactive: flag({
28
+ long: "interactive",
29
+ short: "i",
30
+ description: "Interactively pick a worktree to switch into (same as `wt switch`)."
31
+ })
32
+ },
33
+ handler: async ({ interactive }) => {
34
+ if (interactive) {
35
+ await go();
36
+ return;
37
+ }
38
+ const entries = loadRegistry();
39
+ if (entries.length === 0) {
40
+ if (gitSafe("rev-parse", "--git-dir")) {
41
+ showLocalWorktrees();
42
+ return;
43
+ }
44
+ console.log(
45
+ dim("No worktrees registered. Create one with: glrs wt new")
46
+ );
47
+ return;
48
+ }
49
+ const byRepo = /* @__PURE__ */ new Map();
50
+ for (const entry of entries) {
51
+ const list2 = byRepo.get(entry.repo) ?? [];
52
+ list2.push(entry);
53
+ byRepo.set(entry.repo, list2);
54
+ }
55
+ for (const [repo, repoEntries] of byRepo) {
56
+ console.log(`
57
+ ${bold(repo)} ${dim(repoEntries[0].repoPath)}`);
58
+ for (const entry of repoEntries) {
59
+ const current = currentBranchIn(entry.wtPath);
60
+ const branchCol = current && current !== entry.branch ? `${entry.branch} ${dim(`\u2192 ${current}`)}` : current ?? entry.branch;
61
+ const commit = gitInSafe(entry.wtPath, "rev-parse", "--short", "HEAD") ?? dim("?");
62
+ console.log(
63
+ ` ${pad(branchCol, 45)} ${pad(commit, 10)} ${dim(entry.wtPath)}`
64
+ );
65
+ }
66
+ }
67
+ console.log();
68
+ }
69
+ });
70
+ function showLocalWorktrees() {
71
+ const entries = listWorktrees();
72
+ const root = gitRoot();
73
+ console.log(bold(pad("NAME", 40) + pad("BRANCH", 30) + "COMMIT"));
74
+ console.log(pad("\u2500\u2500\u2500\u2500", 40) + pad("\u2500\u2500\u2500\u2500\u2500\u2500", 30) + "\u2500\u2500\u2500\u2500\u2500\u2500");
75
+ for (const entry of entries) {
76
+ let displayName = path.basename(entry.path);
77
+ if (entry.path === root) {
78
+ displayName += ` ${dim("(main)")}`;
79
+ }
80
+ const branch = entry.branch ? entry.branch.replace("refs/heads/", "") : "(detached)";
81
+ const shortCommit = entry.commit.slice(0, 7);
82
+ console.log(pad(displayName, 40) + pad(branch, 30) + shortCommit);
83
+ }
84
+ }
85
+ function pad(s, width) {
86
+ const visible = s.replace(/\x1b\[[0-9;]*m/g, "");
87
+ const padding = Math.max(0, width - visible.length);
88
+ return s + " ".repeat(padding);
89
+ }
90
+
91
+ export {
92
+ list
93
+ };
@@ -0,0 +1,55 @@
1
+ import {
2
+ select
3
+ } from "./chunk-P7PRH4I3.js";
4
+ import {
5
+ currentBranchIn,
6
+ spawnShell
7
+ } from "./chunk-LMRDQ4GW.js";
8
+ import {
9
+ loadRegistry
10
+ } from "./chunk-VCN7RNLU.js";
11
+ import {
12
+ bold,
13
+ dim,
14
+ info,
15
+ warn
16
+ } from "./chunk-YBCA3IP6.js";
17
+
18
+ // src/commands/go.ts
19
+ async function go() {
20
+ const entries = loadRegistry();
21
+ if (entries.length === 0) {
22
+ warn(
23
+ "no worktrees registered \u2014 create one with: glrs wt new"
24
+ );
25
+ return;
26
+ }
27
+ const byRepo = /* @__PURE__ */ new Map();
28
+ for (const entry of entries) {
29
+ const list = byRepo.get(entry.repo) ?? [];
30
+ list.push(entry);
31
+ byRepo.set(entry.repo, list);
32
+ }
33
+ const groups = [];
34
+ for (const [repo, repoEntries] of byRepo) {
35
+ groups.push({
36
+ title: repo,
37
+ choices: repoEntries.map((e) => {
38
+ const current = currentBranchIn(e.wtPath);
39
+ const label = current && current !== e.branch ? `${e.branch} ${dim(`\u2192 ${current}`)}` : e.branch;
40
+ return { label, value: e, hint: e.wtPath };
41
+ })
42
+ });
43
+ }
44
+ const selected = await select({
45
+ message: "Select a worktree",
46
+ groups
47
+ });
48
+ if (!selected) return;
49
+ info(`opening shell in ${bold(selected.branch)}...`);
50
+ spawnShell(selected.wtPath);
51
+ }
52
+
53
+ export {
54
+ go
55
+ };
@@ -0,0 +1,17 @@
1
+ import {
2
+ go
3
+ } from "./chunk-DEODG2LC.js";
4
+
5
+ // src/commands/switch.ts
6
+ import { command } from "cmd-ts";
7
+ var switchCmd = command({
8
+ name: "switch",
9
+ aliases: ["sw"],
10
+ description: "Interactive worktree picker \u2014 select a worktree to open a shell in",
11
+ args: {},
12
+ handler: go
13
+ });
14
+
15
+ export {
16
+ switchCmd
17
+ };
@@ -0,0 +1,136 @@
1
+ import {
2
+ createWorktree
3
+ } from "./chunk-VJFNIKQJ.js";
4
+ import {
5
+ spawnShell
6
+ } from "./chunk-LMRDQ4GW.js";
7
+ import {
8
+ loadRegistry
9
+ } from "./chunk-VCN7RNLU.js";
10
+ import {
11
+ info
12
+ } from "./chunk-YBCA3IP6.js";
13
+ import {
14
+ __require
15
+ } from "./chunk-3RG5ZIWI.js";
16
+
17
+ // src/commands/create.ts
18
+ import { command, positional, option, optional, string } from "cmd-ts";
19
+ import * as path from "path";
20
+ import * as os from "os";
21
+ var INDEX_DIR = path.join(os.homedir(), ".glorious");
22
+ var INDEX_FILE = path.join(INDEX_DIR, "repos.json");
23
+ function existsSync(filePath) {
24
+ return Bun.file(filePath).existsSync();
25
+ }
26
+ function readTextSync(filePath) {
27
+ try {
28
+ return Bun.file(filePath).textSync();
29
+ } catch {
30
+ return null;
31
+ }
32
+ }
33
+ function loadRepoIndex() {
34
+ if (!existsSync(INDEX_FILE)) return {};
35
+ try {
36
+ const raw = readTextSync(INDEX_FILE);
37
+ if (!raw) return {};
38
+ return JSON.parse(raw);
39
+ } catch {
40
+ return {};
41
+ }
42
+ }
43
+ function lookupRepo(name) {
44
+ return loadRepoIndex()[name] ?? null;
45
+ }
46
+ function scanRoots() {
47
+ return ["~/repos", "~/code", "~/src"].map((p) => p.replace("~", os.homedir())).filter((p) => existsSync(p));
48
+ }
49
+ function findRepoByScan(name, maxDepth = 4) {
50
+ const skip = /* @__PURE__ */ new Set(["node_modules", "target", "dist", "vendor"]);
51
+ for (const root of scanRoots()) {
52
+ const hit = walk(root, name, skip, maxDepth, 0);
53
+ if (hit) return hit;
54
+ }
55
+ return null;
56
+ }
57
+ function walk(dir, name, skip, maxDepth, depth) {
58
+ if (depth > maxDepth) return null;
59
+ if (path.basename(dir) === name && existsSync(path.join(dir, ".git"))) {
60
+ return dir;
61
+ }
62
+ let children;
63
+ try {
64
+ children = __require("fs").readdirSync(dir);
65
+ } catch {
66
+ return null;
67
+ }
68
+ if (existsSync(path.join(dir, ".git"))) return null;
69
+ for (const child of children) {
70
+ if (skip.has(child) || child.startsWith(".")) continue;
71
+ const full = path.join(dir, child);
72
+ let stat;
73
+ try {
74
+ stat = __require("fs").statSync(full);
75
+ } catch {
76
+ continue;
77
+ }
78
+ if (!stat.isDirectory()) continue;
79
+ const found = walk(full, name, skip, maxDepth, depth + 1);
80
+ if (found) return found;
81
+ }
82
+ return null;
83
+ }
84
+ function resolveRepoPath(repo) {
85
+ if (!repo) return void 0;
86
+ const wt = loadRegistry().find((e) => e.repo === repo);
87
+ if (wt) {
88
+ if (!existsSync(wt.repoPath)) {
89
+ throw new Error(
90
+ `Registered repo '${repo}' points to ${wt.repoPath}, which no longer exists.`
91
+ );
92
+ }
93
+ return wt.repoPath;
94
+ }
95
+ const indexed = lookupRepo(repo);
96
+ if (indexed) return indexed;
97
+ const scanned = findRepoByScan(repo);
98
+ if (scanned) return scanned;
99
+ throw new Error(
100
+ `No repo named '${repo}' found.
101
+ Looked in worktree registry, ~/.glorious/repos.json, and scan roots.
102
+ Fix: run 'glrs wt new' from inside the repo once.`
103
+ );
104
+ }
105
+ var create = command({
106
+ name: "new",
107
+ aliases: ["create"],
108
+ description: "Create a worktree from the latest origin default branch. Name is auto-generated.",
109
+ args: {
110
+ repo: positional({
111
+ type: optional(string),
112
+ displayName: "repo",
113
+ description: "Optional repo name. Required when running outside a git repo; looked up in the worktree registry, the repo index, or under repo.scan-roots."
114
+ }),
115
+ from: option({
116
+ type: optional(string),
117
+ long: "from",
118
+ description: "Base branch override (default: remote default branch). Rare \u2014 prefer default."
119
+ })
120
+ },
121
+ handler: ({ repo, from }) => {
122
+ const repoPath = resolveRepoPath(repo);
123
+ const { wtPath } = createWorktree({ from, repoPath, repo });
124
+ console.log(`
125
+ cd ${wtPath}
126
+ `);
127
+ if (process.stdin.isTTY) {
128
+ info("spawning shell in worktree (exit to return)...");
129
+ spawnShell(wtPath);
130
+ }
131
+ }
132
+ });
133
+
134
+ export {
135
+ create
136
+ };
@@ -0,0 +1,139 @@
1
+ import {
2
+ isProtected
3
+ } from "./chunk-W37UX3U2.js";
4
+ import {
5
+ defaultBranch,
6
+ git,
7
+ gitInSafe,
8
+ gitRoot,
9
+ gitSafe,
10
+ listWorktrees
11
+ } from "./chunk-LMRDQ4GW.js";
12
+ import {
13
+ unregisterWorktree
14
+ } from "./chunk-VCN7RNLU.js";
15
+ import {
16
+ bold,
17
+ dim,
18
+ info,
19
+ ok,
20
+ red,
21
+ warn
22
+ } from "./chunk-YBCA3IP6.js";
23
+
24
+ // src/commands/cleanup.ts
25
+ import * as readline from "readline";
26
+ import { command, option, flag, optional, string } from "cmd-ts";
27
+ var cleanup = command({
28
+ name: "cleanup",
29
+ description: "Delete worktrees whose branches are merged or stale",
30
+ args: {
31
+ base: option({
32
+ type: optional(string),
33
+ long: "base",
34
+ description: "Base branch to check against (default: auto-detect)"
35
+ }),
36
+ dryRun: flag({
37
+ long: "dry-run",
38
+ description: "Show candidates without deleting"
39
+ }),
40
+ yes: flag({ long: "yes", short: "y", description: "Skip confirmation" })
41
+ },
42
+ handler: async ({ base: baseOpt, dryRun, yes }) => {
43
+ const base = baseOpt ?? defaultBranch();
44
+ info(`checking worktrees against ${bold(base)}...`);
45
+ gitSafe("fetch", "origin", base, "--quiet");
46
+ const entries = listWorktrees();
47
+ const root = gitRoot();
48
+ const candidates = [];
49
+ for (const entry of entries) {
50
+ if (entry.path === root) continue;
51
+ const branch = entry.branch?.replace("refs/heads/", "");
52
+ if (!branch) continue;
53
+ if (isProtected(branch)) continue;
54
+ const merged = gitSafe(
55
+ "merge-base",
56
+ "--is-ancestor",
57
+ entry.branch,
58
+ `origin/${base}`
59
+ ) !== null;
60
+ const remoteDeleted = gitSafe(
61
+ "show-ref",
62
+ "--verify",
63
+ "--quiet",
64
+ `refs/remotes/origin/${branch}`
65
+ ) === null;
66
+ if (!merged && !remoteDeleted) continue;
67
+ const status = gitInSafe(entry.path, "status", "--porcelain");
68
+ if (status === null || status !== "") {
69
+ if (status !== null && status !== "") {
70
+ warn(`skipping ${branch} -- has uncommitted changes`);
71
+ }
72
+ continue;
73
+ }
74
+ if (!remoteDeleted) {
75
+ const unpushed = gitInSafe(
76
+ entry.path,
77
+ "log",
78
+ "--oneline",
79
+ `origin/${base}..HEAD`
80
+ );
81
+ const count = unpushed ? unpushed.split("\n").filter(Boolean).length : 0;
82
+ if (count > 0) {
83
+ warn(`skipping ${branch} -- has ${count} unpushed commit(s)`);
84
+ continue;
85
+ }
86
+ }
87
+ candidates.push({ path: entry.path, branch });
88
+ }
89
+ if (candidates.length === 0) {
90
+ ok("no worktrees to clean up");
91
+ return;
92
+ }
93
+ console.log(`
94
+ ${bold("Candidates for cleanup:")}`);
95
+ for (const c of candidates) {
96
+ console.log(` ${red("\u2715")} ${c.branch} ${dim(`(${c.path})`)}`);
97
+ }
98
+ console.log();
99
+ if (dryRun) {
100
+ info("dry run -- no worktrees deleted");
101
+ return;
102
+ }
103
+ if (!yes) {
104
+ const confirmed = await confirm(
105
+ `Delete ${candidates.length} worktree(s)? [y/N] `
106
+ );
107
+ if (!confirmed) {
108
+ info("aborted");
109
+ return;
110
+ }
111
+ }
112
+ for (const c of candidates) {
113
+ try {
114
+ git("worktree", "remove", c.path);
115
+ gitSafe("branch", "-d", c.branch);
116
+ unregisterWorktree(c.path);
117
+ ok(`deleted ${c.branch}`);
118
+ } catch {
119
+ warn(`failed to delete ${c.branch}`);
120
+ }
121
+ }
122
+ }
123
+ });
124
+ function confirm(prompt) {
125
+ const rl = readline.createInterface({
126
+ input: process.stdin,
127
+ output: process.stdout
128
+ });
129
+ return new Promise((resolve) => {
130
+ rl.question(prompt, (answer) => {
131
+ rl.close();
132
+ resolve(/^[Yy]$/.test(answer.trim()));
133
+ });
134
+ });
135
+ }
136
+
137
+ export {
138
+ cleanup
139
+ };
@@ -0,0 +1,129 @@
1
+ // src/lib/git.ts
2
+ import * as path from "path";
3
+ function git(...args) {
4
+ const result = Bun.spawnSync(["git", ...args], {
5
+ stdout: "pipe",
6
+ stderr: "pipe"
7
+ });
8
+ if (!result.success) {
9
+ const err = new TextDecoder().decode(result.stderr);
10
+ throw new Error(err || `git ${args.join(" ")} failed`);
11
+ }
12
+ return new TextDecoder().decode(result.stdout).trim();
13
+ }
14
+ function gitSafe(...args) {
15
+ const result = Bun.spawnSync(["git", ...args], {
16
+ stdout: "pipe",
17
+ stderr: "ignore"
18
+ });
19
+ if (!result.success) return null;
20
+ return new TextDecoder().decode(result.stdout).trim();
21
+ }
22
+ function gitIn(cwd, ...args) {
23
+ const result = Bun.spawnSync(["git", ...args], {
24
+ cwd,
25
+ stdout: "pipe",
26
+ stderr: "pipe"
27
+ });
28
+ if (!result.success) {
29
+ const err = new TextDecoder().decode(result.stderr);
30
+ throw new Error(err || `git ${args.join(" ")} failed in ${cwd}`);
31
+ }
32
+ return new TextDecoder().decode(result.stdout).trim();
33
+ }
34
+ function gitInSafe(cwd, ...args) {
35
+ const result = Bun.spawnSync(["git", ...args], {
36
+ cwd,
37
+ stdout: "pipe",
38
+ stderr: "ignore"
39
+ });
40
+ if (!result.success) return null;
41
+ return new TextDecoder().decode(result.stdout).trim();
42
+ }
43
+ function spawnShell(cwd) {
44
+ const shell = process.env.SHELL || "bash";
45
+ Bun.spawnSync([shell], {
46
+ cwd,
47
+ stdin: "inherit",
48
+ stdout: "inherit",
49
+ stderr: "inherit"
50
+ });
51
+ }
52
+ function gitRoot() {
53
+ const commonDir = git("rev-parse", "--git-common-dir");
54
+ if (!path.isAbsolute(commonDir)) {
55
+ return git("rev-parse", "--show-toplevel");
56
+ }
57
+ return path.dirname(commonDir);
58
+ }
59
+ function defaultBranch() {
60
+ return defaultBranchIn(process.cwd());
61
+ }
62
+ function defaultBranchIn(repoPath) {
63
+ const ref = gitInSafe(repoPath, "symbolic-ref", "refs/remotes/origin/HEAD");
64
+ if (ref) return ref.replace("refs/remotes/origin/", "");
65
+ for (const name of ["main", "master"]) {
66
+ if (gitInSafe(
67
+ repoPath,
68
+ "show-ref",
69
+ "--verify",
70
+ `refs/remotes/origin/${name}`
71
+ ) !== null) {
72
+ return name;
73
+ }
74
+ }
75
+ for (const name of ["main", "master"]) {
76
+ if (gitInSafe(repoPath, "show-ref", "--verify", `refs/heads/${name}`) !== null) {
77
+ return name;
78
+ }
79
+ }
80
+ throw new Error(
81
+ "Cannot detect default branch. Set it with: git remote set-head origin <branch>"
82
+ );
83
+ }
84
+ function currentBranchIn(wtPath) {
85
+ const out = gitInSafe(wtPath, "branch", "--show-current");
86
+ return out && out.length > 0 ? out : null;
87
+ }
88
+ function listWorktrees() {
89
+ const raw = git("worktree", "list", "--porcelain");
90
+ const entries = [];
91
+ let current = {};
92
+ for (const line of raw.split("\n")) {
93
+ if (line === "") {
94
+ if (current.path) {
95
+ entries.push({
96
+ path: current.path,
97
+ commit: current.commit ?? "",
98
+ branch: current.branch ?? null
99
+ });
100
+ }
101
+ current = {};
102
+ continue;
103
+ }
104
+ if (line.startsWith("worktree ")) current.path = line.slice(9);
105
+ else if (line.startsWith("HEAD ")) current.commit = line.slice(5);
106
+ else if (line.startsWith("branch ")) current.branch = line.slice(7);
107
+ }
108
+ if (current.path) {
109
+ entries.push({
110
+ path: current.path,
111
+ commit: current.commit ?? "",
112
+ branch: current.branch ?? null
113
+ });
114
+ }
115
+ return entries;
116
+ }
117
+
118
+ export {
119
+ git,
120
+ gitSafe,
121
+ gitIn,
122
+ gitInSafe,
123
+ spawnShell,
124
+ gitRoot,
125
+ defaultBranch,
126
+ defaultBranchIn,
127
+ currentBranchIn,
128
+ listWorktrees
129
+ };