@kaisers-io/refs 0.5.0 → 0.5.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.
- package/CHANGELOG.md +228 -0
- package/README.md +91 -0
- package/dist/refs.mjs +1 -1
- package/package.json +18 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.5.1] - 2026-07-30
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- The npm tarball now ships a package README (the npm page was empty) and this
|
|
15
|
+
`CHANGELOG.md` — the latter matters because the GitHub repository is private during the
|
|
16
|
+
current development phase, so the packaged copy is the only changelog users can see.
|
|
17
|
+
The release pipeline's tarball-content allowlist covers both, and a new guard fails the
|
|
18
|
+
release if the packaged changelog drifts from the repository one.
|
|
19
|
+
- Registry metadata in `package.json`: `keywords`, `homepage`, and `bugs`.
|
|
20
|
+
|
|
21
|
+
## [0.5.0] - 2026-07-30
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- Full Windows support: every command, the lock/steal machinery, sync/clone/remove with their
|
|
26
|
+
containment guards, and the read-only hook guards now behave on Windows exactly as on
|
|
27
|
+
macOS/Linux (Git for Windows required). CI runs the full test suite plus a PowerShell smoke
|
|
28
|
+
test — which exercises the npm-generated `.cmd` shims — on `windows-latest`.
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- Lock directory names no longer contain `:` (illegal in Windows file names; every locked
|
|
33
|
+
command failed with `EINVAL` there). Per-ref locks are now named `ref.<key>`; a stale
|
|
34
|
+
`ref:<key>` directory left by an older version is inert and can be deleted.
|
|
35
|
+
- The lock-steal pipeline treats Windows sharing-violation errors (`EPERM`/`EACCES`/`EBUSY` on
|
|
36
|
+
the tombstone rename or on re-creating a directory that is still delete-pending) as a lost
|
|
37
|
+
race and retries, instead of crashing.
|
|
38
|
+
- Workspace package paths are `/`-separated identifiers on every platform (they previously used
|
|
39
|
+
`\` on Windows, breaking sorting, deduplication, and stored config paths).
|
|
40
|
+
- Child-process cleanup also listens for `SIGBREAK`, so Ctrl-Break on Windows kills spawned
|
|
41
|
+
git/ssh children like Ctrl-C does.
|
|
42
|
+
|
|
43
|
+
## [0.4.0] - 2026-07-28
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
|
|
47
|
+
- Internal: whole-codebase clarity refactor — comments now explain behavior instead of project
|
|
48
|
+
history, inline lint exceptions cut from 75 to 20, `type` aliases replace interfaces
|
|
49
|
+
throughout, dead exports removed, and the workspace-detection logic is split into a pure,
|
|
50
|
+
directly-tested module. No CLI behavior change.
|
|
51
|
+
|
|
52
|
+
### Removed
|
|
53
|
+
|
|
54
|
+
- `refs search` and `refs range` (both added in 0.3.0). A dedicated efficiency benchmark
|
|
55
|
+
(18-task corpus built around the two commands, taught inline with worked `--json` examples and
|
|
56
|
+
provably on `PATH`) measured **0 / 324 adoption** — neither Opus 4.8 nor GPT-5.6 invoked either
|
|
57
|
+
command on a single task, including tasks constructed to favor them — while the condition
|
|
58
|
+
carrying the teaching cost _more_ (cost-weighted spend +19% over discipline, +41% over naive for
|
|
59
|
+
Claude). With the dependency source checked out, both commands compete head-to-head with the
|
|
60
|
+
agent's native `git grep` / `git log` / `git diff` and lose: they are redundant with skills the
|
|
61
|
+
agent already has on the very source refs provides. refs' core value — real, local source the
|
|
62
|
+
agent then reads and greps — is unchanged. The agent skill now routes source-search and version
|
|
63
|
+
questions to `resolve`/`sync`/`tag` plus read-only git on the checkout. The now-dead core helpers
|
|
64
|
+
(`git/grep`, `git/range`, `git/changelog`) were removed with them.
|
|
65
|
+
|
|
66
|
+
## [0.3.0] - 2026-07-23
|
|
67
|
+
|
|
68
|
+
### Added
|
|
69
|
+
|
|
70
|
+
- `refs range <ref> <old-version> <new-version>` — a bounded version-diff digest for
|
|
71
|
+
agent-driven "what changed between these versions" questions. Resolves both versions to git
|
|
72
|
+
tags (same `tag_format` inheritance as `refs tag`) and returns, in one call, the commit count,
|
|
73
|
+
the newest `--limit` (default 50) non-merge commit subjects, diff stats, changed paths (capped
|
|
74
|
+
at 200), and a changelog excerpt extracted at the new tag. `--package <name>` scopes the
|
|
75
|
+
diff/paths/changelog to that package's path while the commit log stays repo-wide. Every bounded
|
|
76
|
+
list carries an honest flag in `truncated`; the digest is a starting point, and the full history
|
|
77
|
+
stays available via plain git in the checkout.
|
|
78
|
+
- `refs search <ref> <pattern>` — bounded structured code search over a ref's checkout. Wraps
|
|
79
|
+
`git grep -z -n -I --extended-regexp` and returns `{path, line, snippet}` matches (trimmed,
|
|
80
|
+
capped at 200 chars), at most `--limit` (default 50), with `truncated: true` whenever more
|
|
81
|
+
exist. Vendored/generated paths (`dist`, `build`, `node_modules`, lockfiles, …) are excluded by
|
|
82
|
+
default and echoed in `excludes_applied`; `--no-default-excludes` turns them off. `--glob` takes
|
|
83
|
+
plain glob patterns (never raw git pathspec magic — leading `:` or root-escaping `..` are
|
|
84
|
+
rejected), and `--package` is a hard boundary that intersects with any `--glob` and refuses a
|
|
85
|
+
package directory resolving outside the checkout. No matches is a success, not an error.
|
|
86
|
+
|
|
87
|
+
### Changed
|
|
88
|
+
|
|
89
|
+
- Rewrote the agent skill's investigation playbook (`skills/refs/references/investigate.md`) as an
|
|
90
|
+
advisory guide built on the "hint, not gate" principle: four hard rules (read real source before
|
|
91
|
+
citing, treat digests as starting points, honour truncation flags, unmask decoy version tags)
|
|
92
|
+
plus recommended investigation funnels with explicit escape hatches, tuned by two real-world
|
|
93
|
+
field tests.
|
|
94
|
+
|
|
95
|
+
## [0.2.0] - 2026-07-07
|
|
96
|
+
|
|
97
|
+
### Added
|
|
98
|
+
|
|
99
|
+
- Onboarding flow for the agent skill (`skills/refs/references/onboarding.md`, triggered by
|
|
100
|
+
"onboard me" / "set up refs" / "what is refs"): health check via `refs doctor --json`, a
|
|
101
|
+
consented `refs init` where needed, the three core jobs explained with copyable example
|
|
102
|
+
prompts, and a first-ref suggestion drawn from the project's own dependency manifests.
|
|
103
|
+
- Install flow in the skill's capability gate: when the `refs` CLI is missing, the agent now
|
|
104
|
+
checks the Node version, asks the user for consent, installs `@kaisers-io/refs` from npm,
|
|
105
|
+
verifies with `refs --version`, and runs `refs doctor --json` automatically. A new
|
|
106
|
+
`compatibility` frontmatter field declares the CLI dependency.
|
|
107
|
+
|
|
108
|
+
### Changed
|
|
109
|
+
|
|
110
|
+
- All example content (docs, skill references, README, CLI help text) switched from next.js to
|
|
111
|
+
zod (`github.com/colinhacks/zod`) — every example validated against a real zod checkout via
|
|
112
|
+
refs itself.
|
|
113
|
+
- Development now requires pnpm 11 or newer (`engines.pnpm` at the workspace root); the
|
|
114
|
+
published CLI has no pnpm requirement.
|
|
115
|
+
- The user-facing supported Node range relaxed from `>=24.12 <25` to `>=24.12` (open-ended),
|
|
116
|
+
verified working on Node 25.9 and 26.4 (build, tests, stub, and source fallback). Development
|
|
117
|
+
stays pinned to Node 24.12 via `.node-version`; CI and the root `packageManager` field are
|
|
118
|
+
unchanged.
|
|
119
|
+
- `packages/cli/bin/refs.mjs` is now a committed, zero-dependency stub (not build output): it
|
|
120
|
+
checks the Node.js version, then loads and runs the tsdown bundle from `dist/refs.mjs`. If the
|
|
121
|
+
bundle is missing but sources and dependencies are present, it falls back to running the CLI
|
|
122
|
+
directly from TypeScript source via Node's native type stripping. It fails loudly with an
|
|
123
|
+
actionable message (exit 1) only if neither the bundle nor the source fallback can load. The
|
|
124
|
+
tsdown bundle itself moved from `bin/refs.mjs` to `dist/refs.mjs`, and remains gitignored build
|
|
125
|
+
output produced by `pnpm build`.
|
|
126
|
+
|
|
127
|
+
## [0.1.3] - 2026-07-05
|
|
128
|
+
|
|
129
|
+
### Added
|
|
130
|
+
|
|
131
|
+
- Plugin manifests for the Codex app/CLI (`.codex-plugin/plugin.json`) and Claude Code's
|
|
132
|
+
plugin marketplace (`.claude-plugin/plugin.json` + `marketplace.json`), plus a
|
|
133
|
+
`.agents/plugins/marketplace.json` mirror for Codex's own marketplace. A
|
|
134
|
+
`.agents/skills/refs` symlink to `skills/refs/` gives Codex repo-local
|
|
135
|
+
auto-discovery of the skill when run inside this checkout.
|
|
136
|
+
|
|
137
|
+
### Changed
|
|
138
|
+
|
|
139
|
+
- `packages/cli/bin/refs.mjs` (the built CLI bundle) is no longer committed to the repo — it's
|
|
140
|
+
build output, regenerated by `pnpm build` and gitignored. CI now proves the build is
|
|
141
|
+
deterministic (two consecutive builds byte-for-byte identical) instead of diffing a committed
|
|
142
|
+
copy, and the release pipeline passes the bundle built and guarded by the unprivileged `verify`
|
|
143
|
+
job to the minimal `publish` job as a workflow artifact, so `publish` still never installs
|
|
144
|
+
dependencies or runs a build while it holds the npm OIDC token.
|
|
145
|
+
- Updated the bundled `smol-toml` TOML parser/serializer from 1.6.1 to 1.7.0 (faster
|
|
146
|
+
single-pass string decoding; integers beyond the safe range now serialize as floats;
|
|
147
|
+
no breaking changes).
|
|
148
|
+
- `refs add <source> --description <text>` no longer reuses `<text>` as a fallback
|
|
149
|
+
description for detected packages that lack one. `<text>` is now only ever the
|
|
150
|
+
top-level ref description; if one or more detected packages have no manifest
|
|
151
|
+
description (including a single-package repo whose lone package has none, and a
|
|
152
|
+
package whose manifest carries an empty `"description": ""` — the `npm init -y`
|
|
153
|
+
scaffold), the one-shot fails (exit 3) naming every affected package and pointing at
|
|
154
|
+
the two-phase `--dry-run`/`--proposal` flow instead. Consequently, an `npm:<pkg>`
|
|
155
|
+
source without detected workspace packages can effectively never use the one-shot —
|
|
156
|
+
its single seeded package entry never carries a description — and always needs the
|
|
157
|
+
two-phase flow.
|
|
158
|
+
|
|
159
|
+
- Replaced the `execa` dependency with a small hand-rolled `node:child_process`-based
|
|
160
|
+
process runner. `git`/`ssh` invocations, timeouts, and error handling work as
|
|
161
|
+
before, with two minor observable differences: a command that fails to spawn at
|
|
162
|
+
all (e.g. `git` missing from `PATH`) now reports exit code 127 instead of 1, and
|
|
163
|
+
its OS error message (e.g. `spawn git ENOENT`) now lands on stderr — improving
|
|
164
|
+
`refs doctor`'s failure detail for a missing `git` binary. The published CLI
|
|
165
|
+
bundle is smaller as a result (`bin/refs.mjs`: 305,188 → 196,249 bytes raw,
|
|
166
|
+
89,740 → 55,864 bytes gzipped).
|
|
167
|
+
|
|
168
|
+
### Fixed
|
|
169
|
+
|
|
170
|
+
- `refs add --proposal` validation errors now name the offending key(s) for a
|
|
171
|
+
stray/unrecognized field in the proposal — top-level (e.g.
|
|
172
|
+
`unrecognized key(s) in proposal: "okay"`) and nested inside a package entry (e.g.
|
|
173
|
+
`unrecognized key(s) in proposal at packages.<name>: "bogus"`) — instead of a bare,
|
|
174
|
+
contextless `Invalid input`. Named-field validation errors (missing or wrong-typed
|
|
175
|
+
fields, including nested package fields like `packages.<name>.description`) are
|
|
176
|
+
unchanged.
|
|
177
|
+
|
|
178
|
+
## [0.1.2] - 2026-07-05
|
|
179
|
+
|
|
180
|
+
### Added
|
|
181
|
+
|
|
182
|
+
- `refs add` now emits progress lines on stderr while it works (`refs: resolving npm
|
|
183
|
+
package '…'…`, `refs: cloning …`, `refs: detecting workspace packages…`) in both
|
|
184
|
+
human and `--json` mode, so long clones no longer look like a hang. stdout is
|
|
185
|
+
unaffected and stays exactly the parseable envelope in `--json` mode.
|
|
186
|
+
|
|
187
|
+
### Fixed
|
|
188
|
+
|
|
189
|
+
- `refs add --proposal` now accepts the full `--json` envelope that
|
|
190
|
+
`refs add … --dry-run --json` prints, so the documented pipe workflow
|
|
191
|
+
(`refs add npm:x --dry-run --json > f.json` → edit → `refs add --proposal f.json`)
|
|
192
|
+
works without hand-stripping the `data` wrapper. Bare proposal documents keep
|
|
193
|
+
working unchanged.
|
|
194
|
+
- A proposal file containing a failed (`ok: false`) or malformed (no usable `data`
|
|
195
|
+
object) envelope now fails with a clear message instead of a field-by-field
|
|
196
|
+
validation dump.
|
|
197
|
+
|
|
198
|
+
## [0.1.1] - 2026-07-05
|
|
199
|
+
|
|
200
|
+
No user-facing changes. First tag-driven release, validating the OIDC
|
|
201
|
+
trusted-publishing pipeline end to end.
|
|
202
|
+
|
|
203
|
+
## [0.1.0] - 2026-07-05
|
|
204
|
+
|
|
205
|
+
### Added
|
|
206
|
+
|
|
207
|
+
- Initial release of the `refs` CLI: manage local, read-only checkouts of reference
|
|
208
|
+
repositories ("refs") for agents and humans — `init`, `add` (two-phase
|
|
209
|
+
proposal/finalize or one-shot `--description`), `list`, `show`, `resolve`, `sync`,
|
|
210
|
+
`edit`, `remove`, `migrate`, and `doctor`.
|
|
211
|
+
- npm-source resolution (`refs add npm:<package>`), workspace package detection
|
|
212
|
+
(npm/yarn/pnpm monorepos), tag-format detection, blobless clones with full-clone
|
|
213
|
+
fallback, and a configurable git transport (`https`/`ssh`).
|
|
214
|
+
- Machine-readable `--json` output with a stable `{ok, data, warnings}` /
|
|
215
|
+
`{ok, error}` envelope on every command, plus stable exit codes.
|
|
216
|
+
- Containment-guarded destructive operations, credential redaction in every
|
|
217
|
+
URL-carrying message, and read-only enforcement of managed checkouts via
|
|
218
|
+
installed git hooks.
|
|
219
|
+
- Agent skill (`skills/refs/`) documenting the investigate/add/maintain workflows.
|
|
220
|
+
|
|
221
|
+
[Unreleased]: https://github.com/kaisers-io/refs/compare/v0.4.0...HEAD
|
|
222
|
+
[0.4.0]: https://github.com/kaisers-io/refs/compare/v0.3.0...v0.4.0
|
|
223
|
+
[0.3.0]: https://github.com/kaisers-io/refs/compare/v0.2.0...v0.3.0
|
|
224
|
+
[0.2.0]: https://github.com/kaisers-io/refs/compare/v0.1.3...v0.2.0
|
|
225
|
+
[0.1.3]: https://github.com/kaisers-io/refs/compare/v0.1.2...v0.1.3
|
|
226
|
+
[0.1.2]: https://github.com/kaisers-io/refs/compare/v0.1.1...v0.1.2
|
|
227
|
+
[0.1.1]: https://github.com/kaisers-io/refs/compare/v0.1.0...v0.1.1
|
|
228
|
+
[0.1.0]: https://github.com/kaisers-io/refs/releases/tag/v0.1.0
|
package/README.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# @kaisers-io/refs
|
|
2
|
+
|
|
3
|
+
**Real source code for coding agents.**
|
|
4
|
+
|
|
5
|
+
`refs` manages arbitrary git repositories (GitHub, GitLab, self-hosted) as local, managed
|
|
6
|
+
read-only source-code references, so that coding agents answer questions about
|
|
7
|
+
dependencies and reference projects against **real source code** — never against a
|
|
8
|
+
minified `node_modules` bundle, never against stale training knowledge.
|
|
9
|
+
|
|
10
|
+
When your project depends on `zod`, you say "add zod as a ref"; `refs` resolves the npm
|
|
11
|
+
package to its git repository, clones it, detects its release-tag convention and monorepo
|
|
12
|
+
packages, and from then on any agent can answer "what changed between v4.0.0 and v4.1.0"
|
|
13
|
+
or "how does zod implement codecs" by reading the actual checkout.
|
|
14
|
+
|
|
15
|
+
npm is only a convenience resolver (`npm:zod`). Arbitrary git URLs work directly.
|
|
16
|
+
|
|
17
|
+
**Read-only is a workflow promise, not a security boundary.** Every checkout under
|
|
18
|
+
`sources/` is a managed reference, not a working copy: agents are instructed never to
|
|
19
|
+
edit, commit, or push inside one. `refs` installs git hooks that reject commits/pushes in
|
|
20
|
+
a checkout as a backstop, and `refs sync` self-heals a dirty checkout if something slips
|
|
21
|
+
through anyway — but this is discipline enforced by convention and tooling, not a sandbox.
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
Requirements: Node.js `>=24.12` and git. macOS, Linux, and Windows are fully supported —
|
|
26
|
+
every command, locking, sync, and the read-only guards behave the same on all three (on
|
|
27
|
+
Windows, use [Git for Windows](https://gitforwindows.org/)).
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm i -g @kaisers-io/refs
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Then verify the setup:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
refs --version
|
|
37
|
+
refs doctor
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Quickstart
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# 1. Seed the refs home directory, config, and git hooks guard.
|
|
44
|
+
refs init
|
|
45
|
+
|
|
46
|
+
# 2. Propose adding a ref — resolves npm:zod to its git repo, clones it, and writes
|
|
47
|
+
# a reviewable proposal. Nothing is added to config yet.
|
|
48
|
+
refs add npm:zod --dry-run
|
|
49
|
+
|
|
50
|
+
# 3. Review the proposal JSON, then finalize it, or use --description for a
|
|
51
|
+
# one-shot add:
|
|
52
|
+
refs add npm:zod --description "TypeScript-first schema validation" --json
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Every command accepts `--json` for a stable, machine-readable envelope and `--verbose`
|
|
56
|
+
for stack traces on error. Run `refs --help` or `refs <command> --help` — the CLI's own
|
|
57
|
+
help is the authoritative, always-current reference.
|
|
58
|
+
|
|
59
|
+
## Commands
|
|
60
|
+
|
|
61
|
+
| Command | What it does |
|
|
62
|
+
| -------------- | --------------------------------------------------------------------------------------- |
|
|
63
|
+
| `refs init` | Seed or migrate the refs home directory, its config, and the git hooks guard. |
|
|
64
|
+
| `refs add` | Add a git reference in two phases: propose (`--dry-run`), then finalize (`--proposal`). |
|
|
65
|
+
| `refs list` | List configured refs with their staleness/missing checkout status. |
|
|
66
|
+
| `refs show` | Show a configured ref: full entry, state, local path, and sample tags. |
|
|
67
|
+
| `refs sync` | Fetch (or re-clone, if the checkout is missing) configured refs — all by default. |
|
|
68
|
+
| `refs resolve` | Resolve a git url, npm package name, import path, or ref-key suffix to its ref/package. |
|
|
69
|
+
| `refs tag` | Resolve a version to its git tag, via the ref's (or a package's) `tag_format`. |
|
|
70
|
+
| `refs edit` | Edit one field of a global setting, a ref, or a package. |
|
|
71
|
+
| `refs remove` | Remove a configured ref: its config/state entry AND its checkout directory. |
|
|
72
|
+
| `refs doctor` | Run environment/integrity checks (git, node, config, hooks, checkouts, ssh). |
|
|
73
|
+
| `refs migrate` | Migrate the refs config to the current schema, seeding it if absent. |
|
|
74
|
+
|
|
75
|
+
## Agent skill
|
|
76
|
+
|
|
77
|
+
The CLI pairs with one thin, cross-agent skill (Claude Code and Codex) that routes agent
|
|
78
|
+
questions ("how does zod implement codecs") to the right checkout via `refs resolve
|
|
79
|
+
--json` and keeps things fresh with `refs sync`/`refs doctor`. `refs init` prints the
|
|
80
|
+
exact install command for your setup. The skill is distributed from the GitHub
|
|
81
|
+
repository, which is private during the current development phase — it opens up when
|
|
82
|
+
`refs` goes public.
|
|
83
|
+
|
|
84
|
+
## Changelog
|
|
85
|
+
|
|
86
|
+
`CHANGELOG.md` ships inside this package (npm's "Code" tab shows it) — the GitHub
|
|
87
|
+
repository is private during the current development phase.
|
|
88
|
+
|
|
89
|
+
## License
|
|
90
|
+
|
|
91
|
+
MIT
|
package/dist/refs.mjs
CHANGED
|
@@ -365,6 +365,6 @@ Expecting one of '${n.join(`', '`)}'`);return this._lifeCycleHooks[e]?this._life
|
|
|
365
365
|
- if the default executable name is not suitable, use the executableFile option to supply a custom name or path
|
|
366
366
|
- ${t?`searched for local subcommand relative to directory '${t}'`:`no directory for search for local subcommand, use .executableDir() to supply a custom directory`}`;throw Error(r)}_executeSubCommand(e,t){t=t.slice();let n=[`.js`,`.ts`,`.tsx`,`.mjs`,`.cjs`];function r(e,t){let r=p.resolve(e,t);if(le.existsSync(r))return r;if(n.includes(p.extname(t)))return;let i=n.find(e=>le.existsSync(`${r}${e}`));if(i)return`${r}${i}`}this._checkForMissingMandatoryOptions(),this._checkForConflictingOptions();let i=e._executableFile||`${this._name}-${e._name}`,a=this._executableDir||``;if(this._scriptPath){let e;try{e=le.realpathSync(this._scriptPath)}catch{e=this._scriptPath}a=p.resolve(p.dirname(e),a)}if(a){let t=r(a,i);if(!t&&!e._executableFile&&this._scriptPath){let n=p.basename(this._scriptPath,p.extname(this._scriptPath));n!==this._name&&(t=r(a,`${n}-${e._name}`))}i=t||i}let o=n.includes(p.extname(i)),s;h.platform===`win32`?(this._checkForMissingExecutable(i,a,e._name),t.unshift(i),t=Ld(h.execArgv).concat(t),s=ge.spawn(h.execPath,t,{stdio:`inherit`})):o?(t.unshift(i),t=Ld(h.execArgv).concat(t),s=ge.spawn(h.argv[0],t,{stdio:`inherit`})):s=ge.spawn(i,t,{stdio:`inherit`}),s.killed||[`SIGUSR1`,`SIGUSR2`,`SIGTERM`,`SIGINT`,`SIGHUP`].forEach(e=>{h.on(e,()=>{s.killed===!1&&s.exitCode===null&&s.kill(e)})});let c=this._exitCallback;s.on(`close`,e=>{e??=1,c?c(new Td(e,`commander.executeSubCommandAsync`,`(close)`)):h.exit(e)}),s.on(`error`,t=>{if(t.code===`ENOENT`)this._checkForMissingExecutable(i,a,e._name);else if(t.code===`EACCES`)throw Error(`'${i}' not executable`);if(!c)h.exit(1);else{let e=new Td(1,`commander.executeSubCommandAsync`,`(error)`);e.nestedError=t,c(e)}}),this.runningCommand=s}_dispatchSubcommand(e,t,n){let r=this._findCommand(e);r||this.help({error:!0}),r._prepareForParse();let i;return i=this._chainOrCallSubCommandHook(i,r,`preSubcommand`),i=this._chainOrCall(i,()=>{if(r._executableHandler)this._executeSubCommand(r,t.concat(n));else return r._parseCommand(t,n)}),i}_dispatchHelpCommand(e){e||this.help();let t=this._findCommand(e);return t&&!t._executableHandler&&t.help(),this._dispatchSubcommand(e,[],[this._getHelpOption()?.long??this._getHelpOption()?.short??`--help`])}_checkNumberOfArguments(){this.registeredArguments.forEach((e,t)=>{e.required&&this.args[t]==null&&this.missingArgument(e.name())}),!(this.registeredArguments.length>0&&this.registeredArguments[this.registeredArguments.length-1].variadic)&&this.args.length>this.registeredArguments.length&&this._excessArguments(this.args)}_processArguments(){let e=(e,t,n)=>{let r=t;if(t!==null&&e.parseArg){let i=`error: command-argument value '${t}' is invalid for argument '${e.name()}'.`;r=this._callParseArg(e,t,n,i)}return r};this._checkNumberOfArguments();let t=[];this.registeredArguments.forEach((n,r)=>{let i=n.defaultValue;n.variadic?r<this.args.length?(i=this.args.slice(r),n.parseArg&&(i=i.reduce((t,r)=>e(n,r,t),n.defaultValue))):i===void 0&&(i=[]):r<this.args.length&&(i=this.args[r],n.parseArg&&(i=e(n,i,n.defaultValue))),t[r]=i}),this.processedArgs=t}_chainOrCall(e,t){return e?.then&&typeof e.then==`function`?e.then(()=>t()):t()}_chainOrCallHooks(e,t){let n=e,r=[];return this._getCommandAndAncestors().reverse().filter(e=>e._lifeCycleHooks[t]!==void 0).forEach(e=>{e._lifeCycleHooks[t].forEach(t=>{r.push({hookedCommand:e,callback:t})})}),t===`postAction`&&r.reverse(),r.forEach(e=>{n=this._chainOrCall(n,()=>e.callback(e.hookedCommand,this))}),n}_chainOrCallSubCommandHook(e,t,n){let r=e;return this._lifeCycleHooks[n]!==void 0&&this._lifeCycleHooks[n].forEach(e=>{r=this._chainOrCall(r,()=>e(this,t))}),r}_parseCommand(e,t){let n=this.parseOptions(t);if(this._parseOptionsEnv(),this._parseOptionsImplied(),e=e.concat(n.operands),t=n.unknown,this.args=e.concat(t),e&&this._findCommand(e[0]))return this._dispatchSubcommand(e[0],e.slice(1),t);if(this._getHelpCommand()&&e[0]===this._getHelpCommand().name())return this._dispatchHelpCommand(e[1]);if(this._defaultCommandName)return this._outputHelpIfRequested(t),this._dispatchSubcommand(this._defaultCommandName,e,t);this.commands.length&&this.args.length===0&&!this._actionHandler&&!this._defaultCommandName&&this.help({error:!0}),this._outputHelpIfRequested(n.unknown),this._checkForMissingMandatoryOptions(),this._checkForConflictingOptions();let r=()=>{n.unknown.length>0&&this.unknownOption(n.unknown[0])},i=`command:${this.name()}`;if(this._actionHandler){r(),this._processArguments();let n;return n=this._chainOrCallHooks(n,`preAction`),n=this._chainOrCall(n,()=>this._actionHandler(this.processedArgs)),this.parent&&(n=this._chainOrCall(n,()=>{this.parent.emit(i,e,t)})),n=this._chainOrCallHooks(n,`postAction`),n}if(this.parent?.listenerCount(i))r(),this._processArguments(),this.parent.emit(i,e,t);else if(e.length){if(this._findCommand(`*`))return this._dispatchSubcommand(`*`,e,t);this.listenerCount(`command:*`)?this.emit(`command:*`,e,t):this.commands.length?this.unknownCommand():(r(),this._processArguments())}else this.commands.length?(r(),this.help({error:!0})):(r(),this._processArguments())}_findCommand(e){if(e)return this.commands.find(t=>t._name===e||t._aliases.includes(e))}_findOption(e){return this.options.find(t=>t.is(e))}_checkForMissingMandatoryOptions(){this._getCommandAndAncestors().forEach(e=>{e.options.forEach(t=>{t.mandatory&&e.getOptionValue(t.attributeName())===void 0&&e.missingMandatoryOptionValue(t)})})}_checkForConflictingLocalOptions(){let e=this.options.filter(e=>{let t=e.attributeName();return this.getOptionValue(t)!==void 0&&this.getOptionValueSource(t)!=="default"});e.filter(e=>e.conflictsWith.length>0).forEach(t=>{let n=e.find(e=>t.conflictsWith.includes(e.attributeName()));n&&this._conflictingOption(t,n)})}_checkForConflictingOptions(){this._getCommandAndAncestors().forEach(e=>{e._checkForConflictingLocalOptions()})}parseOptions(e){let t=[],n=[],r=t;function i(e){return e.length>1&&e[0]===`-`}let a=e=>/^-(\d+|\d*\.\d+)(e[+-]?\d+)?$/.test(e)?!this._getCommandAndAncestors().some(e=>e.options.map(e=>e.short).some(e=>/^-\d$/.test(e))):!1,o=null,s=null,c=0;for(;c<e.length||s;){let l=s??e[c++];if(s=null,l===`--`){r===n&&r.push(l),r.push(...e.slice(c));break}if(o&&(!i(l)||a(l))){this.emit(`option:${o.name()}`,l);continue}if(o=null,i(l)){let t=this._findOption(l);if(t){if(t.required){let n=e[c++];n===void 0&&this.optionMissingArgument(t),this.emit(`option:${t.name()}`,n)}else if(t.optional){let n=null;c<e.length&&(!i(e[c])||a(e[c]))&&(n=e[c++]),this.emit(`option:${t.name()}`,n)}else this.emit(`option:${t.name()}`);o=t.variadic?t:null;continue}}if(l.length>2&&l[0]===`-`&&l[1]!==`-`){let e=this._findOption(`-${l[1]}`);if(e){e.required||e.optional&&this._combineFlagAndOptionalValue?this.emit(`option:${e.name()}`,l.slice(2)):(this.emit(`option:${e.name()}`),s=`-${l.slice(2)}`);continue}}if(/^--[^=]+=/.test(l)){let e=l.indexOf(`=`),t=this._findOption(l.slice(0,e));if(t&&(t.required||t.optional)){this.emit(`option:${t.name()}`,l.slice(e+1));continue}}if(r===t&&i(l)&&!(this.commands.length===0&&a(l))&&(r=n),(this._enablePositionalOptions||this._passThroughOptions)&&t.length===0&&n.length===0){if(this._findCommand(l)){t.push(l),n.push(...e.slice(c));break}else if(this._getHelpCommand()&&l===this._getHelpCommand().name()){t.push(l,...e.slice(c));break}else if(this._defaultCommandName){n.push(l,...e.slice(c));break}}if(this._passThroughOptions){r.push(l,...e.slice(c));break}r.push(l)}return{operands:t,unknown:n}}opts(){if(this._storeOptionsAsProperties){let e={},t=this.options.length;for(let n=0;n<t;n++){let t=this.options[n].attributeName();e[t]=t===this._versionOptionName?this._version:this[t]}return e}return this._optionValues}optsWithGlobals(){return this._getCommandAndAncestors().reduce((e,t)=>Object.assign(e,t.opts()),{})}error(e,t){this._outputConfiguration.outputError(`${e}\n`,this._outputConfiguration.writeErr),typeof this._showHelpAfterError==`string`?this._outputConfiguration.writeErr(`${this._showHelpAfterError}\n`):this._showHelpAfterError&&(this._outputConfiguration.writeErr(`
|
|
367
367
|
`),this.outputHelp({error:!0}));let n=t||{},r=n.exitCode||1,i=n.code||`commander.error`;this._exit(r,i,e)}_parseOptionsEnv(){this.options.forEach(e=>{if(e.envVar&&e.envVar in h.env){let t=e.attributeName();(this.getOptionValue(t)===void 0||[`default`,`config`,`env`].includes(this.getOptionValueSource(t)))&&(e.required||e.optional?this.emit(`optionEnv:${e.name()}`,h.env[e.envVar]):this.emit(`optionEnv:${e.name()}`))}})}_parseOptionsImplied(){let e=new jd(this.options),t=e=>this.getOptionValue(e)!==void 0&&![`default`,`implied`].includes(this.getOptionValueSource(e));this.options.filter(n=>n.implied!==void 0&&t(n.attributeName())&&e.valueFromOption(this.getOptionValue(n.attributeName()),n)).forEach(e=>{Object.keys(e.implied).filter(e=>!t(e)).forEach(t=>{this.setOptionValueWithSource(t,e.implied[t],`implied`)})})}missingArgument(e){let t=`error: missing required argument '${e}'`;this.error(t,{code:`commander.missingArgument`})}optionMissingArgument(e){let t=`error: option '${e.flags}' argument missing`;this.error(t,{code:`commander.optionMissingArgument`})}missingMandatoryOptionValue(e){let t=`error: required option '${e.flags}' not specified`;this.error(t,{code:`commander.missingMandatoryOptionValue`})}_conflictingOption(e,t){let n=e=>{let t=e.attributeName(),n=this.getOptionValue(t),r=this.options.find(e=>e.negate&&t===e.attributeName()),i=this.options.find(e=>!e.negate&&t===e.attributeName());return r&&(r.presetArg===void 0&&n===!1||r.presetArg!==void 0&&n===r.presetArg)?r:i||e},r=e=>{let t=n(e),r=t.attributeName();return this.getOptionValueSource(r)===`env`?`environment variable '${t.envVar}'`:`option '${t.flags}'`},i=`error: ${r(e)} cannot be used with ${r(t)}`;this.error(i,{code:`commander.conflictingOption`})}unknownOption(e){if(this._allowUnknownOption)return;let t=``;if(e.startsWith(`--`)&&this._showSuggestionAfterError){let n=[],r=this;do{let e=r.createHelp().visibleOptions(r).filter(e=>e.long).map(e=>e.long);n=n.concat(e),r=r.parent}while(r&&!r._enablePositionalOptions);t=Fd(e,n)}let n=`error: unknown option '${e}'${t}`;this.error(n,{code:`commander.unknownOption`})}_excessArguments(e){if(this._allowExcessArguments)return;let t=this.registeredArguments.length,n=t===1?``:`s`,r=e.length,i=`error: too many arguments${this.parent?` for '${this.name()}'`:``}. Expected ${t} argument${n} but got ${r}: ${e.join(`, `)}.`;this.error(i,{code:`commander.excessArguments`})}unknownCommand(){let e=this.args[0],t=``;if(this._showSuggestionAfterError){let n=[];this.createHelp().visibleCommands(this).forEach(e=>{n.push(e.name()),e.alias()&&n.push(e.alias())}),t=Fd(e,n)}let n=`error: unknown command '${e}'${t}`;this.error(n,{code:`commander.unknownCommand`})}version(e,t,n){if(e===void 0)return this._version;this._version=e,t||=`-V, --version`,n||=`output the version number`;let r=this.createOption(t,n);return this._versionOptionName=r.attributeName(),this._registerOption(r),this.on(`option:`+r.name(),()=>{this._outputConfiguration.writeOut(`${e}\n`),this._exit(0,`commander.version`,e)}),this}description(e,t){return e===void 0&&t===void 0?this._description:(this._description=e,t&&(this._argsDescription=t),this)}summary(e){return e===void 0?this._summary:(this._summary=e,this)}alias(e){if(e===void 0)return this._aliases[0];let t=this;if(this.commands.length!==0&&this.commands[this.commands.length-1]._executableHandler&&(t=this.commands[this.commands.length-1]),e===t._name)throw Error(`Command alias can't be the same as its name`);let n=this.parent?._findCommand(e);if(n){let t=[n.name()].concat(n.aliases()).join(`|`);throw Error(`cannot add alias '${e}' to command '${this.name()}' as already have command '${t}'`)}return t._aliases.push(e),this}aliases(e){return e===void 0?this._aliases:(e.forEach(e=>this.alias(e)),this)}usage(e){if(e===void 0){if(this._usage)return this._usage;let e=this.registeredArguments.map(e=>Od(e));return[].concat(this.options.length||this._helpOption!==null?`[options]`:[],this.commands.length?`[command]`:[],this.registeredArguments.length?e:[]).join(` `)}return this._usage=e,this}name(e){return e===void 0?this._name:(this._name=e,this)}helpGroup(e){return e===void 0?this._helpGroupHeading??``:(this._helpGroupHeading=e,this)}commandsGroup(e){return e===void 0?this._defaultCommandGroup??``:(this._defaultCommandGroup=e,this)}optionsGroup(e){return e===void 0?this._defaultOptionGroup??``:(this._defaultOptionGroup=e,this)}_initOptionGroup(e){this._defaultOptionGroup&&!e.helpGroupHeading&&e.helpGroup(this._defaultOptionGroup)}_initCommandGroup(e){this._defaultCommandGroup&&!e.helpGroup()&&e.helpGroup(this._defaultCommandGroup)}nameFromFilename(e){return this._name=p.basename(e,p.extname(e)),this}executableDir(e){return e===void 0?this._executableDir:(this._executableDir=e,this)}helpInformation(e){let t=this.createHelp(),n=this._getOutputContext(e);t.prepareContext({error:n.error,helpWidth:n.helpWidth,outputHasColors:n.hasColors});let r=t.formatHelp(this,t);return n.hasColors?r:this._outputConfiguration.stripColor(r)}_getOutputContext(e){e||={};let t=!!e.error,n,r,i;return t?(n=e=>this._outputConfiguration.writeErr(e),r=this._outputConfiguration.getErrHasColors(),i=this._outputConfiguration.getErrHelpWidth()):(n=e=>this._outputConfiguration.writeOut(e),r=this._outputConfiguration.getOutHasColors(),i=this._outputConfiguration.getOutHelpWidth()),{error:t,write:e=>(r||(e=this._outputConfiguration.stripColor(e)),n(e)),hasColors:r,helpWidth:i}}outputHelp(e){let t;typeof e==`function`&&(t=e,e=void 0);let n=this._getOutputContext(e),r={error:n.error,write:n.write,command:this};this._getCommandAndAncestors().reverse().forEach(e=>e.emit(`beforeAllHelp`,r)),this.emit(`beforeHelp`,r);let i=this.helpInformation({error:n.error});if(t&&(i=t(i),typeof i!=`string`&&!Buffer.isBuffer(i)))throw Error(`outputHelp callback must return a string or a Buffer`);n.write(i),this._getHelpOption()?.long&&this.emit(this._getHelpOption().long),this.emit(`afterHelp`,r),this._getCommandAndAncestors().forEach(e=>e.emit(`afterAllHelp`,r))}helpOption(e,t){return typeof e==`boolean`?(e?(this._helpOption===null&&(this._helpOption=void 0),this._defaultOptionGroup&&this._initOptionGroup(this._getHelpOption())):this._helpOption=null,this):(this._helpOption=this.createOption(e??`-h, --help`,t??`display help for command`),(e||t)&&this._initOptionGroup(this._helpOption),this)}_getHelpOption(){return this._helpOption===void 0&&this.helpOption(void 0,void 0),this._helpOption}addHelpOption(e){return this._helpOption=e,this._initOptionGroup(e),this}help(e){this.outputHelp(e);let t=Number(h.exitCode??0);t===0&&e&&typeof e!=`function`&&e.error&&(t=1),this._exit(t,`commander.help`,`(outputHelp)`)}addHelpText(e,t){let n=[`beforeAll`,`before`,`after`,`afterAll`];if(!n.includes(e))throw Error(`Unexpected value for position to addHelpText.
|
|
368
|
-
Expecting one of '${n.join(`', '`)}'`);let r=`${e}Help`;return this.on(r,e=>{let n;n=typeof t==`function`?t({error:e.error,command:e.command}):t,n&&e.write(`${n}\n`)}),this}_outputHelpIfRequested(e){let t=this._getHelpOption();t&&e.find(e=>t.is(e))&&(this.outputHelp(),this._exit(0,`commander.helpDisplayed`,`(outputHelp)`))}};function Ld(e){return e.map(e=>{if(!e.startsWith(`--inspect`))return e;let t,n=`127.0.0.1`,r=`9229`,i;return(i=e.match(/^(--inspect(-brk)?)$/))===null?(i=e.match(/^(--inspect(-brk|-port)?)=([^:]+)$/))===null?(i=e.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/))!==null&&(t=i[1],n=i[3],r=i[4]):(t=i[1],/^\d+$/.test(i[3])?r=i[3]:n=i[3]):t=i[1],t&&r!==`0`?`${t}=${n}:${parseInt(r)+1}`:e})}function Rd(){if(h.env.NO_COLOR||h.env.FORCE_COLOR===`0`||h.env.FORCE_COLOR===`false`)return!1;if(h.env.FORCE_COLOR||h.env.CLICOLOR_FORCE!==void 0)return!0}new Id;const zd=[],Bd=e=>Array.isArray(e)?e:[e],Vd=e=>e===void 0?zd:[e],Hd=e=>e instanceof Error?e.message:String(e),Z=e=>{let t=e.optsWithGlobals();return{json:t.json===!0,verbose:t.verbose===!0}},Q=(e,t,n,r,i)=>{if(t.json){let t={data:r,ok:!0,warnings:i??zd};e.out(JSON.stringify(t));return}for(let t of Bd(n))e.out(t);for(let t of i??zd)e.errLine(`refs: warning: ${t}`)},Ud=(e,t,n)=>{if(t.json){let t={error:{code:n.code,message:n.message},ok:!1};e.out(JSON.stringify(t));return}e.errLine(`refs: ${n.message}`)},Wd=(e,t)=>{e.errLine(`refs: ${t}`)},$=(e,t,n)=>async()=>{try{await n()}catch(n){let r=xe(n,{verbose:t.verbose});Ud(e,t,r),process.exitCode=r.exitCode}};var Gd=`0.5.0`;const Kd=async e=>{let t=await e.runner.run(`git`,[`--version`]);return t.exitCode===0?{detail:t.stdout.trim(),name:`git`,status:`ok`}:{detail:t.stderr.trim()||`git --version exited with code ${t.exitCode}`,name:`git`,status:`fail`}},qd=/^v(?<major>\d+)\.(?<minor>\d+)/u,Jd=e=>{let t=qd.exec(e),n=t?.groups?.major,r=t?.groups?.minor;if(n!==void 0&&r!==void 0)return{major:Number(n),minor:Number(r)}},Yd=e=>e===void 0?!1:e.major>24||e.major===24&&e.minor>=12,Xd=e=>{let{nodeVersion:t}=e;return Yd(Jd(t))?{detail:t,name:`node`,status:`ok`}:{detail:`${t} does not satisfy the required range >=24.12`,name:`node`,status:`fail`}},Zd=()=>cs.parse({meta:{cli_version:`0.0.0`,schema_version:1},refs:{},settings:{}}),Qd=async e=>{try{return{config:await W(e)}}catch(e){return{config:Zd(),errorMessage:Hd(e)}}},$d=e=>e===void 0?{detail:`config is present and matches the current schema`,name:`config`,status:`ok`}:{detail:e,name:`config`,status:`fail`},ef=[`.claude`,`skills`,`refs`,`SKILL.md`],tf=[`.codex`,`skills`,`refs`,`SKILL.md`],nf=e=>e===void 0?[]:[m(e,...ef),m(e,...tf)],rf=async t=>{try{return await e(t),!0}catch{return!1}},af=async e=>{let t=nf(e.env.HOME);return(await Promise.all(t.map(e=>rf(e)))).some(Boolean)?{detail:`the refs skill is installed`,name:`skill`,status:`ok`}:{detail:`refs skill not found — install it: npx skills add kaisers-io/refs`,name:`skill`,status:`warn`}},of=(e,t)=>Object.keys(t.refs).map(t=>({dest:U(e,z.parse(t)),key:t})).filter(e=>G(e.dest)),sf=[`pre-commit`,`pre-push`],cf=async(t,r)=>{try{return await e(m(t.hooksDir,r),n.X_OK),!0}catch{return!1}},lf=async e=>{let t=await Promise.all(sf.map(t=>cf(e,t)));return sf.filter((e,n)=>!t[n])},uf=async(e,t,n)=>{let r=await e.runner.run(`git`,[`config`,`--local`,`--get`,`core.hooksPath`],{cwd:n});return r.exitCode===0&&r.stdout.trim()===t.hooksDir},df=e=>e.missingHooks.length>0?{detail:`${e.missingHooks.map(e=>`hooks/${e}`).join(`, `)} missing or not executable — run: refs init`,name:`hooks-guard`,status:`fail`}:e.badKeys.length>0?{detail:`core.hooksPath not set for: ${e.badKeys.join(`, `)} — run: refs init`,name:`hooks-guard`,status:`fail`}:{detail:`${sf.map(e=>`hooks/${e}`).join(`, `)} present; ${e.checkoutCount} checkout(s) guarded`,name:`hooks-guard`,status:`ok`},ff=async(e,t,n)=>{let r=of(t,n),[i,a]=await Promise.all([lf(t),Promise.all(r.map(n=>uf(e,t,n.dest)))]),o=r.filter((e,t)=>!a[t]).map(e=>e.key);return df({badKeys:o,checkoutCount:r.length,missingHooks:i})},pf=async(e,t)=>{let n=await e.runner.run(`git`,[`status`,`--porcelain`],{cwd:t.dest});return n.exitCode===0?{broken:!1,detail:``,dirty:n.stdout.trim()!==``,key:t.key}:{broken:!0,detail:n.stderr.trim(),dirty:!1,key:t.key}},mf=e=>{let t=e.filter(e=>e.broken);if(t.length>0)return{detail:t.map(e=>`${e.key}: git status failed — ${e.detail}`).join(`; `),name:`dirty-checkouts`,status:`fail`};let n=e.filter(e=>e.dirty).map(e=>e.key);return n.length===0?{detail:`no local changes in any checkout`,name:`dirty-checkouts`,status:`ok`}:{detail:`local changes will be discarded on next sync: ${n.join(`, `)}`,name:`dirty-checkouts`,status:`warn`}},hf=async(e,t,n)=>{let r=of(t,n),i=await Promise.all(r.map(t=>pf(e,t)));return mf(i)},gf=async e=>{try{return await X(e)}catch{return Uu.parse({})}},_f=async e=>{try{return(await s(e,{withFileTypes:!0})).filter(e=>e.isDirectory()).map(e=>e.name)}catch(e){if(V(e))return[];throw e}},vf=async(e,t)=>{if(G(e))return[[...t]];let n=await _f(e);return(await Promise.all(n.map(n=>vf(m(e,n),[...t,n])))).flat()},yf=(e,t,n)=>{let r=e.refs[t]?.pending_proposal_at;return r!==void 0&&n-Date.parse(r)<864e5},bf=(e,t,n)=>yf(t,e.key,n)?`${e.key}: pending add`:`${e.key}: orphan — remove with: rm -rf ${e.dest}`,xf=(e,t)=>({dest:m(e.sourcesDir,...t),key:t.join(`/`)}),Sf=async(e,t,n)=>{let r=(await vf(e.sourcesDir,[])).map(t=>xf(e,t)).filter(e=>!Object.hasOwn(t.refs,e.key));if(r.length===0)return{detail:`no orphaned checkouts under sources/`,name:`orphans`,status:`ok`};let i=Date.now();return{detail:r.map(e=>bf(e,n,i)).join(`; `),name:`orphans`,status:`warn`}},Cf=/^(?<user>[^/\s@]+)@(?<host>[^:/\s]+):/u,wf=e=>e===``?{}:{user:e},Tf=e=>e===``?{}:{port:e},Ef=e=>{try{let t=new URL(e);return t.protocol===`ssh:`?{host:t.hostname,...wf(t.username),...Tf(t.port)}:void 0}catch{return}},Df=e=>{let t=Cf.exec(e),n=t?.groups?.host;return n===void 0?Ef(e):{host:n,user:t?.groups?.user??`git`}},Of=e=>e.port===void 0?e.host:`${e.host}:${e.port}`,kf=e=>e.user===void 0?Of(e):`${e.user}@${Of(e)}`,Af=e=>{let t=Object.values(e.refs).map(e=>Df(e.url)).filter(e=>e!==void 0),n=new Map;for(let e of t)n.set(kf(e),e);return[...n.values()].toSorted((e,t)=>kf(e).localeCompare(kf(t)))},jf=/Permission denied/u,Mf=[/Could not resolve hostname/u,/Connection refused/u,/Host key verification failed/u,/timed out/u],Nf=e=>e.user===void 0?e.host:`${e.user}@${e.host}`,Pf=e=>{let t=[`-o`,`ConnectTimeout=5`,`-o`,`BatchMode=yes`],n=Nf(e);return e.port===void 0?[...t,`-T`,n]:[...t,`-p`,e.port,`-T`,n]},Ff=async(e,t,n)=>{let r=kf(t),i=await e.runner.run(`ssh`,Pf(t),{timeoutMs:n});return i.timedOut===!0?{host:r,outcome:`timeout`}:jf.test(i.stderr)?{host:r,outcome:`denied`}:Mf.some(e=>e.test(i.stderr))?{detail:i.stderr.trim(),host:r,outcome:`connection-warn`}:{host:r,outcome:`ok`}},If=(e,t)=>{let n=e.filter(e=>e.outcome===`timeout`).map(e=>e.host);if(n.length!==0)return{detail:`ssh probe timed out after ${t/1e3}s: ${n.join(`, `)}`,name:`ssh-auth`,status:`fail`}},Lf=e=>{let t=e.filter(e=>e.outcome===`denied`).map(e=>e.host);if(t.length!==0)return{detail:`ssh permission denied for: ${t.join(`, `)}`,name:`ssh-auth`,status:`fail`}},Rf=e=>{let t=e.filter(e=>e.outcome===`connection-warn`);if(t.length!==0)return{detail:`ssh connection issue, treated as warn: ${t.map(e=>`${e.host} (${e.detail??``})`).join(`; `)}`,name:`ssh-auth`,status:`warn`}},zf=e=>({detail:`ssh auth ok for: ${e.map(e=>e.host).join(`, `)}`,name:`ssh-auth`,status:`ok`}),Bf=(e,t)=>If(e,t)??Lf(e)??Rf(e)??zf(e),Vf=async(e,t,n)=>{let r=Af(t);if(r.length===0)return;let i=n?.timeoutMs??1e4,a=await Promise.all(r.map(t=>Ff(e,t,i)));return Bf(a,i)},Hf=async e=>{try{return await e.run()}catch(t){return{detail:`check crashed: ${Hd(t)}`,name:e.name,status:`fail`}}},Uf=async e=>{let[t,...n]=e;if(t===void 0)return[];let r=await Hf(t),i=await Uf(n);return r===void 0?i:[r,...i]},Wf=e=>{let{configLoad:t,ctx:n,home:r,state:i}=e;return[{name:`git`,run:()=>Kd(n)},{name:`node`,run:()=>Promise.resolve(Xd(n))},{name:`config`,run:()=>Promise.resolve($d(t.errorMessage))},{name:`hooks-guard`,run:()=>ff(n,r,t.config)},{name:`dirty-checkouts`,run:()=>hf(n,r,t.config)},{name:`orphans`,run:()=>Sf(r,t.config,i)},{name:`skill`,run:()=>af(n)},{name:`ssh-auth`,run:()=>Vf(n,t.config)}]},Gf=async e=>{let t=H(e.env),n=await Qd(t),r=await gf(t);return Uf(Wf({configLoad:n,ctx:e,home:t,state:r}))},Kf={fail:`FAIL`,ok:`OK`,warn:`WARN`},qf=e=>e.map(e=>`[${Kf[e.status]}] ${e.name}: ${e.detail}`),Jf=e=>e.some(e=>e.status===`fail`),Yf=(e,t)=>{e.command(`doctor`).description(`Run environment/integrity checks (git, node, config, hooks, checkouts, ssh).`).action((e,n)=>{let r=Z(n);return $(t,r,async()=>{let e=await Gf(t);Q(t,r,qf(e),{checks:e}),Jf(e)&&(process.exitCode=g.UNEXPECTED)})()})},Xf=async e=>{let t=H(e.env),n=await J(t,`home`,()=>lc(t,Gd));return n===`migrated`?{backup:Vs(t),result:n}:{backup:null,result:n}},Zf=e=>e.result===`migrated`&&e.backup!==null?`config migrated (backup: ${te(e.backup)})`:e.result===`seeded`?`config seeded`:`config up to date`,Qf=(e,t)=>{e.command(`migrate`).description(`Migrate the refs config to the current schema, seeding it if absent.`).action((e,n)=>{let r=Z(n);return $(t,r,async()=>{let e=await Xf(t);Q(t,r,Zf(e),e)})()})},$f=(e,t,n)=>e===void 0||n-Date.parse(e)>t,ep=(e,t,n)=>{let r=e.state.refs[t],i=Qo(Y(`sync_ttl`,n,e.settings));return{clone_mode:Y(`clone_mode`,n,e.settings),description:n.description,key:t,missing:!G(U(e.home,z.parse(t))),packages:Object.keys(n.packages??{}).toSorted(),stale:$f(r?.last_fetched_at,i,e.now)}},tp=e=>{let t={home:e.home,now:e.now,settings:e.config.settings,state:e.state};return Object.entries(e.config.refs).map(([e,n])=>ep(t,e,n)).toSorted((e,t)=>e.key.localeCompare(t.key))},np=async e=>{let t=H(e.env),n=await W(t),r=await X(t);return tp({config:n,home:t,now:Date.now(),state:r})},rp=e=>{let t=[];return e.stale&&t.push(`[stale]`),e.missing&&t.push(`[missing]`),t.length===0?``:` ${t.join(` `)}`},ip=e=>e.length===0?[`no refs configured — run: refs add <source>`]:e.map(e=>`${e.key} ${e.description}${rp(e)}`),ap=e=>e.split(`/`),op=(e,t)=>{let n=ap(e);if(t.length>n.length)return!1;let r=n.length-t.length;return t.every((e,t)=>e===n[r+t])},sp=(e,t)=>{if(Object.hasOwn(e.refs,t))return z.parse(t);let n=ap(t),r=Object.keys(e.refs).filter(e=>op(e,n)).toSorted(),[i]=r;if(i===void 0)throw v(`no ref matches '${t}'`);if(r.length>1)throw y(`'${t}' matches more than one ref: ${r.join(`, `)}`);return z.parse(i)},cp=(e,t)=>{e.command(`list`).description(`List configured refs with their staleness/missing checkout status.`).action((e,n)=>{let r=Z(n);return $(t,r,async()=>{let e=await np(t);Q(t,r,ip(e),e)})()})},lp=e=>`ref.${e.replaceAll(`/`,`_`)}`,up=e=>e.REFS_ALLOW_FILE_URLS===`1`,dp=(e,t)=>{let n=dl(t,{allowFileUrls:up(e.env)});return{cloneUrl:n.cloneUrl,key:n.key}},fp=async(e,t)=>{if(t===``)throw y(`refs add npm: requires a package name, e.g. npm:left-pad`);Wd(e,`resolving npm package '${t}'…`);let n=await hu(e.fetcher,t),r={cloneUrl:n.cloneUrl,key:n.key,npmPkgName:t};return n.directory!==void 0&&(r.npmDirectory=n.directory),r},pp=(e,t)=>t.startsWith(`npm:`)?fp(e,t.slice(4)):Promise.resolve(dp(e,t)),mp=(e,t)=>{if(e.npmPkgName===void 0)return e;let n=Y(`git_transport`,void 0,t);return{...e,cloneUrl:Cl(e.cloneUrl,n)}},hp=e=>`ref '${e}' already exists — use refs edit or refs remove`,gp=(e,t)=>{if(e.refs[t]!==void 0)throw ye(hp(t))},_p=async e=>{try{return await s(e,{withFileTypes:!0})}catch(e){if(V(e))return;throw e}},vp=e=>e.filter(e=>e.isDirectory()).map(e=>e.name),yp=async(e,t)=>{let n=await _p(e);if(n===void 0)return{kind:`stop`};let r=vp(n);if(r.includes(t))return{kind:`continue`,nextDir:m(e,t)};let i=r.find(e=>e.toLowerCase()===t.toLowerCase());return i===void 0?{kind:`stop`}:{kind:`collision`,name:i}},bp=async(e,t,n)=>{let[r,...i]=t;if(r===void 0)return;let a=await yp(e,r);if(a.kind!==`stop`)return a.kind===`collision`?[...n,a.name].join(`/`):bp(a.nextDir,i,[...n,r])},xp=[],Sp=async(e,t)=>{let n=await bp(e.sourcesDir,t.split(`/`),xp);if(n!==void 0)throw ye(`checkout path for '${t}' collides case-insensitively with existing '${n}'`)},Cp=async e=>{try{return await i(e),!0}catch(e){if(V(e))return!1;throw e}},wp=async e=>{try{return await s(e)}catch(e){if(V(e))return;throw e}},Tp=async e=>{try{return(await i(e)).isDirectory()}catch(e){if(V(e))return;throw e}},Ep=async e=>{let t=await wp(e);if(t===void 0)return!0;if(t.length>0)return!1;try{await d(e)}catch(e){if(!V(e))throw e}return!0},Dp=async e=>{let t=await Tp(e);return t===void 0?!0:t?Ep(e):!1},Op=async(e,t)=>{t!==e.sourcesDir&&await Dp(t)&&await Op(e,ne(t))},kp=async(e,t)=>await Cp(t)?(Gs(e,t),await u(t,{force:!0,recursive:!0}),await Op(e,ne(t)),{removedCheckout:!0}):{removedCheckout:!1,warning:`checkout was already missing`},Ap=(e,t)=>Object.fromEntries(Object.entries(e).filter(([e])=>e!==t)),jp=async(e,t)=>{let n=await W(e);await $s(e,{...n,refs:Ap(n.refs,t)});let r=await X(e);await Ku(e,{...r,refs:Ap(r.refs,t)})},Mp=async(e,t)=>{let n=H(e.env),r=sp(await W(n),t),i=U(n,r),{removedCheckout:a,warning:o}=await J(n,lp(r),()=>kp(n,i));return await J(n,`home`,()=>jp(n,r)),{data:{key:r,removed_checkout:a},warnings:Vd(o)}},Np=e=>e.removed_checkout?[`removed ${e.key} (checkout deleted)`]:[`removed ${e.key} (checkout was already missing)`],Pp=(e,t)=>{e.command(`remove`).description(`Remove a configured ref: its config/state entry AND its checkout directory.`).argument(`<ref>`,`full ref key or a unique suffix, e.g. zod`).action((e,n,r)=>{let i=Z(r);return $(t,i,async()=>{let{data:n,warnings:r}=await Mp(t,e);Q(t,i,Np(n),n,r)})()})},Fp=(e,t)=>{let n=e.refs[t];if(n===void 0)throw Error(`internal: matched ref key '${t}' is missing from config.refs`);return n},Ip=(e,t)=>{if(!G(e))throw v(`checkout for '${t}' is missing — run: refs sync ${t}`)},Lp=(e,t,n)=>{let r=e.packages?.[n];if(r===void 0)throw v(`no package '${n}' registered on ref '${t}'`);return r},Rp=e=>`no ref matches '${e}' — run refs list, or add it: refs add <url>`,zp=/^[a-z][a-z0-9+.-]*:\/\//iu,Bp=/^git@[^:/\s]+:[^\s]+$/u,Vp=e=>zp.test(e)||Bp.test(e),Hp=(e,t)=>{try{return dl(e,t)}catch{if(Vp(e))throw b(`query looks like a git url but is not a supported form — check the url (credentials are never accepted) or run: refs resolve <package|ref-suffix>`);return}},Up=(e,t,n)=>{let r=Hp(t,n);if(r!==void 0){if(Object.hasOwn(e.refs,r.key))return{key:r.key};throw v(Rp(t))}},Wp=(e,t)=>{let n=[];for(let r of Object.keys(e.refs).toSorted()){let i=e.refs[r]?.packages?.[t];i!==void 0&&n.push({entry:i,key:z.parse(r)})}return n},Gp=(e,t)=>`package '${e}' is registered by more than one ref: ${t.join(`, `)} — use the full ref key`,Kp=(e,t)=>{let n=Wp(e,t),[r]=n;if(r!==void 0){if(n.length>1)throw y(Gp(t,n.map(e=>e.key)));return r}},qp=(e,t)=>{let n=t.split(`/`);for(let t=n.length-1;t>=1;--t){let r=n.slice(0,t).join(`/`),i=Kp(e,r);if(i!==void 0)return{...i,name:r}}},Jp=(e,t)=>{try{return sp(e,t)}catch(e){throw e instanceof _&&e.code===`not_found`?v(Rp(t)):e}},Yp=(e,t,n)=>{let r=Up(e,t,n);if(r!==void 0)return r;let i=Kp(e,t);if(i!==void 0)return{key:i.key,packageMatch:{...i,name:t}};let a=qp(e,t);return a===void 0?{key:Jp(e,t)}:{key:a.key,packageMatch:a}},Xp=(e,t)=>{if(e.packageMatch===void 0)return null;let{entry:n,name:r}=e.packageMatch;return{local_path:m(t,n.path),name:r,path:n.path}},Zp=async(e,t)=>{let n=H(e.env),r=await W(n),i=Yp(r,t,{allowFileUrls:up(e.env)}),a=Fp(r,i.key),o=await X(n),s=U(n,i.key),c=Qo(Y(`sync_ttl`,a,r.settings));return{key:i.key,local_path:s,missing:!G(s),package:Xp(i,s),stale:$f(o.refs[i.key]?.last_fetched_at,c,Date.now())}},Qp=e=>{let t=[e.key,`local_path: ${e.local_path}`];return e.package!==null&&t.push(`package: ${e.package.name}`,`local_path: ${e.package.local_path}`),t},$p=(e,t)=>{e.command(`resolve`).description(`Resolve a git url, npm package name, import path, or ref-key suffix to its ref/package.`).argument(`<query>`,`git url, npm package name, import path, or unique ref-key suffix`).action((e,n,r)=>{let i=Z(r);return $(t,i,async()=>{let n=await Zp(t,e);Q(t,i,Qp(n),n)})()})},em={},tm=async(e,t)=>{if(!G(t))return{tags:[]};try{return{tags:await kc(e.runner,t,5)}}catch(e){return{tags:[],warning:`could not list tags: ${Hd(e)}`}}},nm=async(e,t)=>{let n=H(e.env),r=await W(n),i=sp(r,t),a=Fp(r,i),o=await X(n),s=U(n,i),{tags:c,warning:l}=await tm(e,s);return{data:{...a,key:i,local_path:s,sample_tags:c,state:o.refs[i]??em},warnings:Vd(l)}},rm=e=>{let t=[`${e.key} ${e.description}`,`url: ${e.url}`,`local_path: ${e.local_path}`];return e.sample_tags.length>0&&t.push(`tags: ${e.sample_tags.join(`, `)}`),t},im=(e,t)=>{e.command(`show`).description(`Show a configured ref: full entry, state, local path, and sample tags.`).argument(`<ref>`,`full ref key or a unique suffix, e.g. zod`).action((e,n,r)=>{let i=Z(r);return $(t,i,async()=>{let{data:n,warnings:r}=await nm(t,e);Q(t,i,rm(n),n,r)})()})},am=(e,t)=>{let n={head_sha:t.headSha,last_fetched_at:new Date().toISOString()},r=t.effectiveCloneMode??e?.effective_clone_mode;return r!==void 0&&(n.effective_clone_mode=r),n},om=async(e,t,n)=>{let r=await W(e),i=r.refs[t];i!==void 0&&(r.refs[t]={...i,default_branch:n},await $s(e,r))},sm=(e,t,n)=>J(e,`home`,async()=>{n.branchRenamedTo!==void 0&&await om(e,t,n.branchRenamedTo);let r=await X(e);r.refs[t]=am(r.refs[t],n),await Ku(e,r)}),cm=async(e,t,n)=>{try{await J(e,`home`,async()=>{let r=await X(e);r.refs[t]={...r.refs[t],last_error:n},await Ku(e,r)})}catch{}},lm=e=>{let t=0,n=[];return{acquire:()=>{if(t<e)return t+=1,Promise.resolve();let{promise:r,resolve:i}=Promise.withResolvers();return n.push(()=>{t+=1,i()}),r},release:()=>{--t;let e=n.shift();e!==void 0&&e()}}},um=async(e,t)=>{await e.acquire();try{return await t()}finally{e.release()}},dm=(e,t,n)=>`checkout at ${e} points at '${q(t)}' — expected '${q(n)}'; remove the checkout directory or run refs remove before retrying`,fm=e=>e.exitCode===0?e.stdout.trim():`(no origin remote)`,pm=(e,t)=>{try{return dl(e,{allowFileUrls:t}).key}catch{return}},mm=async(e,t)=>{let n=await e.run(`git`,[`remote`,`get-url`,`origin`],{cwd:t.dest}),r=fm(n),i=pm(t.expectedUrl,t.allowFileUrls),a=pm(r,t.allowFileUrls);if(i===void 0||a!==i)throw ye(dm(t.dest,r,t.expectedUrl))},hm=e=>`checkout at ${e} exists but is not refs-managed — remove it (rm -rf ${e}) and retry`,gm=async(e,t)=>{let n=await e.run(`git`,[`config`,`--local`,`core.hooksPath`],{cwd:t.dest});if(n.exitCode!==0||n.stdout.trim()!==t.hooksDir)throw ye(hm(t.dest))},_m=async(e,t)=>{await a(ne(t.dest),{recursive:!0}),Wd(e,`cloning ${q(t.cloneUrl)} into ${t.dest}…`);let n=await bc(e.runner,t);return n.warning===void 0?{effectiveMode:n.effectiveMode}:{effectiveMode:n.effectiveMode,warning:n.warning}},vm=async(e,t)=>(Gs(t.home,t.dest),G(t.dest)?(await mm(e.runner,{allowFileUrls:t.allowFileUrls,dest:t.dest,expectedUrl:t.cloneUrl}),await gm(e.runner,{dest:t.dest,hooksDir:t.hooksDir}),{}):_m(e,t)),ym=(e,t)=>`checkout for '${e}' at ${t} is missing or corrupt (git rev-parse HEAD failed) — run: refs remove ${e}, then refs add <source> --dry-run again`,bm=(e,t,n)=>`checkout for '${e}' at ${t} has a HEAD sha refs cannot store yet (${n.length} hex chars, expected 40) — only SHA-1 repositories are supported for now; \`--object-format=sha256\` repositories are not yet supported`,xm=async(e,t)=>{await mm(e,t),await gm(e,{dest:t.dest,hooksDir:t.hooksDir});let n=await e.run(`git`,[`rev-parse`,`HEAD`],{cwd:t.dest});if(n.exitCode!==0)throw b(ym(t.key,t.dest));let r=n.stdout.trim();if(!Hu.shape.head_sha.safeParse(r).success)throw b(bm(t.key,t.dest,r));return r},Sm=(e,t,n)=>`sync produced a HEAD sha for '${e}' at ${t} that refs cannot store yet (${n.length} hex chars) — only SHA-1 repositories are supported for now`,Cm=(e,t,n)=>{if(!Hu.shape.head_sha.safeParse(n).success)throw b(Sm(e,t,n));return n},wm=(e,t,n)=>{let r={effectiveCloneMode:t.effectiveMode,headSha:n.headSha,status:`cloned`};return n.actualBranch!==e.ref.default_branch&&(r.branchRenamedTo=n.actualBranch),t.warning!==void 0&&(r.warning=t.warning),r},Tm=async(e,t,n)=>{await a(ne(n),{recursive:!0});let r=Y(`clone_mode`,t.ref,t.settings),i=await bc(e.runner,{cloneUrl:t.ref.url,dest:n,hooksDir:t.home.hooksDir,mode:r}),o=await Sc(e.runner,n),s=await xm(e.runner,{allowFileUrls:up(e.env),dest:n,expectedUrl:t.ref.url,hooksDir:t.home.hooksDir,key:t.key});return wm(t,i,{actualBranch:o,headSha:s})},Em=async(e,t,n)=>{await gm(e.runner,{dest:n,hooksDir:t.home.hooksDir}),await mm(e.runner,{allowFileUrls:up(e.env),dest:n,expectedUrl:t.ref.url});let r=await Oc(e.runner,{defaultBranch:t.ref.default_branch,dir:n}),i={headSha:Cm(t.key,n,r.newSha),status:r.status};return r.branchRenamedTo!==void 0&&(i.branchRenamedTo=r.branchRenamedTo),r.warning!==void 0&&(i.warning=r.warning),i},Dm=(e,t)=>J(t.home,lp(t.key),()=>{let n=U(t.home,t.key);return Gs(t.home,n),G(n)?Em(e,t,n):Tm(e,t,n)}),Om=e=>{let t=[];e.branchRenamedTo!==void 0&&t.push(`default branch renamed to ${e.branchRenamedTo}`),e.warning!==void 0&&t.push(e.warning);let[n]=t;if(n!==void 0)return t.join(` | `)},km=(e,t)=>{let n={key:e,status:t.status},r=Om(t);return r!==void 0&&(n.warning=r),n},Am=async(e,t)=>{try{let n=await Dm(e,t);return await sm(t.home,t.key,n),km(t.key,n)}catch(e){let n=Hd(e);return await cm(t.home,t.key,n),{error:n,key:t.key,status:`failed`}}},jm=(e,t)=>e.status===`rejected`?{error:Hd(e.reason),key:t,status:`failed`}:e.value,Mm=async(e,t)=>{let n=lm(4);return(await Promise.allSettled(t.map(t=>um(n,()=>Am(e,t))))).map((e,n)=>{let r=t[n];if(r===void 0)throw Error(`internal: sync target at index ${n} is missing`);return jm(e,r.key)})},Nm=(e,t,n)=>({home:e,key:n,ref:Fp(t,n),settings:t.settings}),Pm=(e,t,n)=>n.length===0?Object.keys(t.refs).toSorted().map(n=>Nm(e,t,z.parse(n))):n.map(n=>Nm(e,t,sp(t,n))),Fm=(e,t,n)=>{let r=Date.now();return t.filter(t=>{let i=Qo(Y(`sync_ttl`,t.ref,t.settings)),a=$f(n.refs[t.key]?.last_fetched_at,i,r),o=!G(U(e,t.key));return a||o})},Im=async(e,t,n)=>{if(!n)return t;let r=await X(e);return Fm(e,t,r)},Lm=async(e,t)=>{let n=H(e.env),r=await W(n),i=Pm(n,r,t.refs),a=await Mm(e,await Im(n,i,t.staleOnly));return{failedCount:a.filter(e=>e.status===`failed`).length,results:a}},Rm=[`updated`,`fresh`,`cloned`,`restored`,`failed`],zm={cloned:`Cloned`,failed:`Failed`,fresh:`Fresh`,restored:`Restored`,updated:`Updated`},Bm=e=>{let t={cloned:[],failed:[],fresh:[],restored:[],updated:[]};for(let n of e)t[n.status].push(n);return t},Vm=e=>e.status===`failed`?` ${e.key}: ${e.error??`unknown error`}`:e.warning===void 0?` ${e.key}`:` ${e.key} (${e.warning})`,Hm=e=>{let t=Bm(e),n=[Rm.map(e=>`${zm[e]} (${t[e].length})`).join(` / `)];for(let e of Rm)for(let r of t[e])n.push(Vm(r));return n},Um=(e,t)=>({refs:e,staleOnly:t.staleOnly===!0}),Wm=(e,t)=>{e.command(`sync`).description(`Fetch (or re-clone, if the checkout is missing) configured refs — all by default.`).argument(`[refs...]`,`ref keys or unique suffixes to sync (default: every configured ref)`).option(`--stale-only`,`skip refs whose last sync is still within their ref's sync_ttl`).action((e,n,r)=>{let i=Z(r);return $(t,i,async()=>{let r=await Lm(t,Um(e,n));Q(t,i,Hm(r.results),{results:r.results}),r.failedCount>0&&(process.exitCode=g.UNEXPECTED)})()})},Gm=(e,t,n)=>n===void 0?e.tag_format:Lp(e,t,n).tag_format??e.tag_format,Km=async(e,t)=>{let n=H(e.env),r=await W(n),i=sp(r,t.query),a=Fp(r,i),o=Gm(a,i,t.opts.packageName),s=U(n,i);Ip(s,i);let c=await Wc(e.runner,s,o,t.version);return{key:i,ref_path:`refs/tags/${c}`,tag:c,version:t.version}},qm=e=>[`${e.key}@${e.version} -> ${e.tag}`],Jm=e=>{let t={};return e.package!==void 0&&(t.packageName=e.package),t},Ym=[Yf,Qf,Pp,$p,im,Wm,(e,t)=>{e.command(`tag`).description(`Resolve a version to its git tag, via the ref's (or a package's) tag_format.`).argument(`<ref>`,`full ref key or a unique suffix, e.g. zod`).argument(`<version>`,`version to resolve, e.g. 4.1.0`).option(`--package <name>`,`resolve against this package's tag_format instead of the ref's`).action((e,n,r,i)=>{let a=Z(i);return $(t,a,async()=>{let i=await Km(t,{opts:Jm(r),query:e,version:n});Q(t,a,qm(i),i)})()})}],Xm=e=>e.description===void 0?{path:e.path}:{description:e.description,path:e.path},Zm=(e,t,n)=>e.length>0?Object.fromEntries(e.map(e=>[e.name,Xm(e)])):n===void 0?{}:{[n]:{path:t??`.`}},Qm=e=>{let t=e.description??``;return e.tag_format===void 0?{description:t,path:e.path}:{description:t,path:e.path,tag_format:e.tag_format}},$m=e=>{let t=Object.entries(e);if(t.length!==0)return Object.fromEntries(t.map(([e,t])=>[e,Qm(t)]))},eh=e=>e.description===void 0||e.description===``,th=e=>Object.entries(e).filter(([,e])=>eh(e)).map(([e])=>e).toSorted(),nh=e=>{let t=th(e);if(t.length!==0)throw b(`packages without a detected description: ${t.join(`, `)} — run the two-phase flow instead: refs add <source> --dry-run --json > proposal.json, fill in the package descriptions, then refs add --proposal proposal.json`)},rh=e=>{if(Object.keys(e).length!==0)return e},ih=e=>{if(e===null)throw b(`tag_format_candidate must be set to a valid tag format (containing '{version}') before finalizing — edit the proposal and provide one, or add the ref manually`);return e},ah=e=>e.packages===void 0?{default_branch:e.default_branch,description:e.description,tag_format:e.tag_format,url:e.url}:{default_branch:e.default_branch,description:e.description,packages:e.packages,tag_format:e.tag_format,url:e.url},oh=async(e,t,n)=>{let r=await Sc(e.runner,t),i=Hc(await kc(e.runner,t));return Wd(e,`detecting workspace packages…`),{defaultBranch:r,packages:Zm(await Sd(t),n.npmDirectory,n.npmPkgName),tagFormatCandidate:i}},sh=(e,t)=>J(t.home,lp(t.resolved.key),async()=>{let n=await vm(e,{allowFileUrls:up(e.env),cloneUrl:t.resolved.cloneUrl,dest:t.dest,home:t.home,hooksDir:t.home.hooksDir,mode:t.cloneMode}),r={fields:await oh(e,t.dest,t.resolved)};return n.effectiveMode!==void 0&&(r.effectiveMode=n.effectiveMode),n.warning!==void 0&&(r.warning=n.warning),r}),ch=e=>{let t={default_branch:e.cloneResult.fields.defaultBranch,description:``,key:e.resolved.key,packages:e.cloneResult.fields.packages,tag_format_candidate:e.cloneResult.fields.tagFormatCandidate,url:e.resolved.cloneUrl},n={dest:e.dest,proposal:t};return e.cloneResult.effectiveMode!==void 0&&(n.effectiveCloneMode=e.cloneResult.effectiveMode),e.cloneResult.warning!==void 0&&(n.warning=e.cloneResult.warning),n},lh=async(e,t)=>{let n=H(e.env),r=await W(n),i=mp(await pp(e,t),r.settings);gp(r,i.key),await Sp(n,i.key);let a=U(n,i.key),o=Y(`clone_mode`,void 0,r.settings),s=await sh(e,{cloneMode:o,dest:a,home:n,resolved:i});return ch({cloneResult:s,dest:a,resolved:i})},uh=(e,t,n)=>J(e,`home`,async()=>{gp(await W(e),t);let r=await X(e),i=r.refs[t],a=n??i?.effective_clone_mode,o={...i,pending_proposal_at:new Date().toISOString()};a!==void 0&&(o.effective_clone_mode=a),r.refs[t]=o,await Ku(e,r)}),dh=(e,t)=>{let n=cs.safeParse(e);if(!n.success)throw b(O(n.error));let r=Uu.safeParse(t);if(!r.success)throw b(O(r.error));return{config:n.data,state:r.data}},fh=async(e,t)=>{let n=await W(e.home);gp(n,e.ref.key);let r=ah(e.ref);n.refs[e.ref.key]=r;let i=await X(e.home);return i.refs[e.ref.key]={effective_clone_mode:e.effectiveCloneMode??i.refs[e.ref.key]?.effective_clone_mode??Y(`clone_mode`,void 0,n.settings),head_sha:t,last_fetched_at:new Date().toISOString()},{...dh(n,i),entry:r}},ph=async(e,t)=>{let n=up(e.env),r=await J(t.home,lp(t.ref.key),()=>(Gs(t.home,t.dest),xm(e.runner,{allowFileUrls:n,dest:t.dest,expectedUrl:t.ref.url,hooksDir:t.home.hooksDir,key:t.ref.key})));return J(t.home,`home`,async()=>{let{config:e,entry:n,state:i}=await fh(t,r);return await Ku(t.home,i),await $s(t.home,e),{entry:n,key:t.ref.key}})},mh=(e,t)=>t===`-`?e.readStdin():o(t,`utf8`),hh=e=>{try{return JSON.parse(e)}catch(e){throw b(`invalid JSON in proposal: ${Hd(e)}`)}},gh=e=>typeof e==`object`&&!!e&&!Array.isArray(e),_h=e=>gh(e)&&`ok`in e&&!(`key`in e),vh=e=>{if(!_h(e))return e;if(e.ok===!1)throw b(`proposal file contains a failed refs envelope (ok is false) — re-run the dry-run`);if(gh(e.data))return e.data;throw b(`proposal file is a refs envelope without a usable data object — re-run the dry-run`)},yh=e=>e.code===`unrecognized_keys`,bh=e=>e.path.length===0,xh=(e,t)=>{let n=t.toSorted().map(e=>`"${e}"`).join(`, `);return e===``?`✖ unrecognized key(s) in proposal: ${n}`:`✖ unrecognized key(s) in proposal at ${e}: ${n}`},Sh=e=>{let t=new Map;for(let n of e){let e=lt(n.path);t.set(e,[...t.get(e)??[],...n.keys])}return[...t.entries()].toSorted(([e],[t])=>e.localeCompare(t)).map(([e,t])=>xh(e,t))},Ch=e=>`✖ invalid proposal: ${e.message}`,wh=e=>{let t=e.issues.filter(e=>yh(e)),n=e.issues.filter(e=>!yh(e)),r=n.filter(e=>bh(e));if(t.length===0&&r.length===0)return O(e);let i=n.filter(e=>!bh(e)),a=[...Sh(t),...r.map(e=>Ch(e))];return i.length>0&&a.push(O({issues:i})),a.join(`
|
|
368
|
+
Expecting one of '${n.join(`', '`)}'`);let r=`${e}Help`;return this.on(r,e=>{let n;n=typeof t==`function`?t({error:e.error,command:e.command}):t,n&&e.write(`${n}\n`)}),this}_outputHelpIfRequested(e){let t=this._getHelpOption();t&&e.find(e=>t.is(e))&&(this.outputHelp(),this._exit(0,`commander.helpDisplayed`,`(outputHelp)`))}};function Ld(e){return e.map(e=>{if(!e.startsWith(`--inspect`))return e;let t,n=`127.0.0.1`,r=`9229`,i;return(i=e.match(/^(--inspect(-brk)?)$/))===null?(i=e.match(/^(--inspect(-brk|-port)?)=([^:]+)$/))===null?(i=e.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/))!==null&&(t=i[1],n=i[3],r=i[4]):(t=i[1],/^\d+$/.test(i[3])?r=i[3]:n=i[3]):t=i[1],t&&r!==`0`?`${t}=${n}:${parseInt(r)+1}`:e})}function Rd(){if(h.env.NO_COLOR||h.env.FORCE_COLOR===`0`||h.env.FORCE_COLOR===`false`)return!1;if(h.env.FORCE_COLOR||h.env.CLICOLOR_FORCE!==void 0)return!0}new Id;const zd=[],Bd=e=>Array.isArray(e)?e:[e],Vd=e=>e===void 0?zd:[e],Hd=e=>e instanceof Error?e.message:String(e),Z=e=>{let t=e.optsWithGlobals();return{json:t.json===!0,verbose:t.verbose===!0}},Q=(e,t,n,r,i)=>{if(t.json){let t={data:r,ok:!0,warnings:i??zd};e.out(JSON.stringify(t));return}for(let t of Bd(n))e.out(t);for(let t of i??zd)e.errLine(`refs: warning: ${t}`)},Ud=(e,t,n)=>{if(t.json){let t={error:{code:n.code,message:n.message},ok:!1};e.out(JSON.stringify(t));return}e.errLine(`refs: ${n.message}`)},Wd=(e,t)=>{e.errLine(`refs: ${t}`)},$=(e,t,n)=>async()=>{try{await n()}catch(n){let r=xe(n,{verbose:t.verbose});Ud(e,t,r),process.exitCode=r.exitCode}};var Gd=`0.5.1`;const Kd=async e=>{let t=await e.runner.run(`git`,[`--version`]);return t.exitCode===0?{detail:t.stdout.trim(),name:`git`,status:`ok`}:{detail:t.stderr.trim()||`git --version exited with code ${t.exitCode}`,name:`git`,status:`fail`}},qd=/^v(?<major>\d+)\.(?<minor>\d+)/u,Jd=e=>{let t=qd.exec(e),n=t?.groups?.major,r=t?.groups?.minor;if(n!==void 0&&r!==void 0)return{major:Number(n),minor:Number(r)}},Yd=e=>e===void 0?!1:e.major>24||e.major===24&&e.minor>=12,Xd=e=>{let{nodeVersion:t}=e;return Yd(Jd(t))?{detail:t,name:`node`,status:`ok`}:{detail:`${t} does not satisfy the required range >=24.12`,name:`node`,status:`fail`}},Zd=()=>cs.parse({meta:{cli_version:`0.0.0`,schema_version:1},refs:{},settings:{}}),Qd=async e=>{try{return{config:await W(e)}}catch(e){return{config:Zd(),errorMessage:Hd(e)}}},$d=e=>e===void 0?{detail:`config is present and matches the current schema`,name:`config`,status:`ok`}:{detail:e,name:`config`,status:`fail`},ef=[`.claude`,`skills`,`refs`,`SKILL.md`],tf=[`.codex`,`skills`,`refs`,`SKILL.md`],nf=e=>e===void 0?[]:[m(e,...ef),m(e,...tf)],rf=async t=>{try{return await e(t),!0}catch{return!1}},af=async e=>{let t=nf(e.env.HOME);return(await Promise.all(t.map(e=>rf(e)))).some(Boolean)?{detail:`the refs skill is installed`,name:`skill`,status:`ok`}:{detail:`refs skill not found — install it: npx skills add kaisers-io/refs`,name:`skill`,status:`warn`}},of=(e,t)=>Object.keys(t.refs).map(t=>({dest:U(e,z.parse(t)),key:t})).filter(e=>G(e.dest)),sf=[`pre-commit`,`pre-push`],cf=async(t,r)=>{try{return await e(m(t.hooksDir,r),n.X_OK),!0}catch{return!1}},lf=async e=>{let t=await Promise.all(sf.map(t=>cf(e,t)));return sf.filter((e,n)=>!t[n])},uf=async(e,t,n)=>{let r=await e.runner.run(`git`,[`config`,`--local`,`--get`,`core.hooksPath`],{cwd:n});return r.exitCode===0&&r.stdout.trim()===t.hooksDir},df=e=>e.missingHooks.length>0?{detail:`${e.missingHooks.map(e=>`hooks/${e}`).join(`, `)} missing or not executable — run: refs init`,name:`hooks-guard`,status:`fail`}:e.badKeys.length>0?{detail:`core.hooksPath not set for: ${e.badKeys.join(`, `)} — run: refs init`,name:`hooks-guard`,status:`fail`}:{detail:`${sf.map(e=>`hooks/${e}`).join(`, `)} present; ${e.checkoutCount} checkout(s) guarded`,name:`hooks-guard`,status:`ok`},ff=async(e,t,n)=>{let r=of(t,n),[i,a]=await Promise.all([lf(t),Promise.all(r.map(n=>uf(e,t,n.dest)))]),o=r.filter((e,t)=>!a[t]).map(e=>e.key);return df({badKeys:o,checkoutCount:r.length,missingHooks:i})},pf=async(e,t)=>{let n=await e.runner.run(`git`,[`status`,`--porcelain`],{cwd:t.dest});return n.exitCode===0?{broken:!1,detail:``,dirty:n.stdout.trim()!==``,key:t.key}:{broken:!0,detail:n.stderr.trim(),dirty:!1,key:t.key}},mf=e=>{let t=e.filter(e=>e.broken);if(t.length>0)return{detail:t.map(e=>`${e.key}: git status failed — ${e.detail}`).join(`; `),name:`dirty-checkouts`,status:`fail`};let n=e.filter(e=>e.dirty).map(e=>e.key);return n.length===0?{detail:`no local changes in any checkout`,name:`dirty-checkouts`,status:`ok`}:{detail:`local changes will be discarded on next sync: ${n.join(`, `)}`,name:`dirty-checkouts`,status:`warn`}},hf=async(e,t,n)=>{let r=of(t,n),i=await Promise.all(r.map(t=>pf(e,t)));return mf(i)},gf=async e=>{try{return await X(e)}catch{return Uu.parse({})}},_f=async e=>{try{return(await s(e,{withFileTypes:!0})).filter(e=>e.isDirectory()).map(e=>e.name)}catch(e){if(V(e))return[];throw e}},vf=async(e,t)=>{if(G(e))return[[...t]];let n=await _f(e);return(await Promise.all(n.map(n=>vf(m(e,n),[...t,n])))).flat()},yf=(e,t,n)=>{let r=e.refs[t]?.pending_proposal_at;return r!==void 0&&n-Date.parse(r)<864e5},bf=(e,t,n)=>yf(t,e.key,n)?`${e.key}: pending add`:`${e.key}: orphan — remove with: rm -rf ${e.dest}`,xf=(e,t)=>({dest:m(e.sourcesDir,...t),key:t.join(`/`)}),Sf=async(e,t,n)=>{let r=(await vf(e.sourcesDir,[])).map(t=>xf(e,t)).filter(e=>!Object.hasOwn(t.refs,e.key));if(r.length===0)return{detail:`no orphaned checkouts under sources/`,name:`orphans`,status:`ok`};let i=Date.now();return{detail:r.map(e=>bf(e,n,i)).join(`; `),name:`orphans`,status:`warn`}},Cf=/^(?<user>[^/\s@]+)@(?<host>[^:/\s]+):/u,wf=e=>e===``?{}:{user:e},Tf=e=>e===``?{}:{port:e},Ef=e=>{try{let t=new URL(e);return t.protocol===`ssh:`?{host:t.hostname,...wf(t.username),...Tf(t.port)}:void 0}catch{return}},Df=e=>{let t=Cf.exec(e),n=t?.groups?.host;return n===void 0?Ef(e):{host:n,user:t?.groups?.user??`git`}},Of=e=>e.port===void 0?e.host:`${e.host}:${e.port}`,kf=e=>e.user===void 0?Of(e):`${e.user}@${Of(e)}`,Af=e=>{let t=Object.values(e.refs).map(e=>Df(e.url)).filter(e=>e!==void 0),n=new Map;for(let e of t)n.set(kf(e),e);return[...n.values()].toSorted((e,t)=>kf(e).localeCompare(kf(t)))},jf=/Permission denied/u,Mf=[/Could not resolve hostname/u,/Connection refused/u,/Host key verification failed/u,/timed out/u],Nf=e=>e.user===void 0?e.host:`${e.user}@${e.host}`,Pf=e=>{let t=[`-o`,`ConnectTimeout=5`,`-o`,`BatchMode=yes`],n=Nf(e);return e.port===void 0?[...t,`-T`,n]:[...t,`-p`,e.port,`-T`,n]},Ff=async(e,t,n)=>{let r=kf(t),i=await e.runner.run(`ssh`,Pf(t),{timeoutMs:n});return i.timedOut===!0?{host:r,outcome:`timeout`}:jf.test(i.stderr)?{host:r,outcome:`denied`}:Mf.some(e=>e.test(i.stderr))?{detail:i.stderr.trim(),host:r,outcome:`connection-warn`}:{host:r,outcome:`ok`}},If=(e,t)=>{let n=e.filter(e=>e.outcome===`timeout`).map(e=>e.host);if(n.length!==0)return{detail:`ssh probe timed out after ${t/1e3}s: ${n.join(`, `)}`,name:`ssh-auth`,status:`fail`}},Lf=e=>{let t=e.filter(e=>e.outcome===`denied`).map(e=>e.host);if(t.length!==0)return{detail:`ssh permission denied for: ${t.join(`, `)}`,name:`ssh-auth`,status:`fail`}},Rf=e=>{let t=e.filter(e=>e.outcome===`connection-warn`);if(t.length!==0)return{detail:`ssh connection issue, treated as warn: ${t.map(e=>`${e.host} (${e.detail??``})`).join(`; `)}`,name:`ssh-auth`,status:`warn`}},zf=e=>({detail:`ssh auth ok for: ${e.map(e=>e.host).join(`, `)}`,name:`ssh-auth`,status:`ok`}),Bf=(e,t)=>If(e,t)??Lf(e)??Rf(e)??zf(e),Vf=async(e,t,n)=>{let r=Af(t);if(r.length===0)return;let i=n?.timeoutMs??1e4,a=await Promise.all(r.map(t=>Ff(e,t,i)));return Bf(a,i)},Hf=async e=>{try{return await e.run()}catch(t){return{detail:`check crashed: ${Hd(t)}`,name:e.name,status:`fail`}}},Uf=async e=>{let[t,...n]=e;if(t===void 0)return[];let r=await Hf(t),i=await Uf(n);return r===void 0?i:[r,...i]},Wf=e=>{let{configLoad:t,ctx:n,home:r,state:i}=e;return[{name:`git`,run:()=>Kd(n)},{name:`node`,run:()=>Promise.resolve(Xd(n))},{name:`config`,run:()=>Promise.resolve($d(t.errorMessage))},{name:`hooks-guard`,run:()=>ff(n,r,t.config)},{name:`dirty-checkouts`,run:()=>hf(n,r,t.config)},{name:`orphans`,run:()=>Sf(r,t.config,i)},{name:`skill`,run:()=>af(n)},{name:`ssh-auth`,run:()=>Vf(n,t.config)}]},Gf=async e=>{let t=H(e.env),n=await Qd(t),r=await gf(t);return Uf(Wf({configLoad:n,ctx:e,home:t,state:r}))},Kf={fail:`FAIL`,ok:`OK`,warn:`WARN`},qf=e=>e.map(e=>`[${Kf[e.status]}] ${e.name}: ${e.detail}`),Jf=e=>e.some(e=>e.status===`fail`),Yf=(e,t)=>{e.command(`doctor`).description(`Run environment/integrity checks (git, node, config, hooks, checkouts, ssh).`).action((e,n)=>{let r=Z(n);return $(t,r,async()=>{let e=await Gf(t);Q(t,r,qf(e),{checks:e}),Jf(e)&&(process.exitCode=g.UNEXPECTED)})()})},Xf=async e=>{let t=H(e.env),n=await J(t,`home`,()=>lc(t,Gd));return n===`migrated`?{backup:Vs(t),result:n}:{backup:null,result:n}},Zf=e=>e.result===`migrated`&&e.backup!==null?`config migrated (backup: ${te(e.backup)})`:e.result===`seeded`?`config seeded`:`config up to date`,Qf=(e,t)=>{e.command(`migrate`).description(`Migrate the refs config to the current schema, seeding it if absent.`).action((e,n)=>{let r=Z(n);return $(t,r,async()=>{let e=await Xf(t);Q(t,r,Zf(e),e)})()})},$f=(e,t,n)=>e===void 0||n-Date.parse(e)>t,ep=(e,t,n)=>{let r=e.state.refs[t],i=Qo(Y(`sync_ttl`,n,e.settings));return{clone_mode:Y(`clone_mode`,n,e.settings),description:n.description,key:t,missing:!G(U(e.home,z.parse(t))),packages:Object.keys(n.packages??{}).toSorted(),stale:$f(r?.last_fetched_at,i,e.now)}},tp=e=>{let t={home:e.home,now:e.now,settings:e.config.settings,state:e.state};return Object.entries(e.config.refs).map(([e,n])=>ep(t,e,n)).toSorted((e,t)=>e.key.localeCompare(t.key))},np=async e=>{let t=H(e.env),n=await W(t),r=await X(t);return tp({config:n,home:t,now:Date.now(),state:r})},rp=e=>{let t=[];return e.stale&&t.push(`[stale]`),e.missing&&t.push(`[missing]`),t.length===0?``:` ${t.join(` `)}`},ip=e=>e.length===0?[`no refs configured — run: refs add <source>`]:e.map(e=>`${e.key} ${e.description}${rp(e)}`),ap=e=>e.split(`/`),op=(e,t)=>{let n=ap(e);if(t.length>n.length)return!1;let r=n.length-t.length;return t.every((e,t)=>e===n[r+t])},sp=(e,t)=>{if(Object.hasOwn(e.refs,t))return z.parse(t);let n=ap(t),r=Object.keys(e.refs).filter(e=>op(e,n)).toSorted(),[i]=r;if(i===void 0)throw v(`no ref matches '${t}'`);if(r.length>1)throw y(`'${t}' matches more than one ref: ${r.join(`, `)}`);return z.parse(i)},cp=(e,t)=>{e.command(`list`).description(`List configured refs with their staleness/missing checkout status.`).action((e,n)=>{let r=Z(n);return $(t,r,async()=>{let e=await np(t);Q(t,r,ip(e),e)})()})},lp=e=>`ref.${e.replaceAll(`/`,`_`)}`,up=e=>e.REFS_ALLOW_FILE_URLS===`1`,dp=(e,t)=>{let n=dl(t,{allowFileUrls:up(e.env)});return{cloneUrl:n.cloneUrl,key:n.key}},fp=async(e,t)=>{if(t===``)throw y(`refs add npm: requires a package name, e.g. npm:left-pad`);Wd(e,`resolving npm package '${t}'…`);let n=await hu(e.fetcher,t),r={cloneUrl:n.cloneUrl,key:n.key,npmPkgName:t};return n.directory!==void 0&&(r.npmDirectory=n.directory),r},pp=(e,t)=>t.startsWith(`npm:`)?fp(e,t.slice(4)):Promise.resolve(dp(e,t)),mp=(e,t)=>{if(e.npmPkgName===void 0)return e;let n=Y(`git_transport`,void 0,t);return{...e,cloneUrl:Cl(e.cloneUrl,n)}},hp=e=>`ref '${e}' already exists — use refs edit or refs remove`,gp=(e,t)=>{if(e.refs[t]!==void 0)throw ye(hp(t))},_p=async e=>{try{return await s(e,{withFileTypes:!0})}catch(e){if(V(e))return;throw e}},vp=e=>e.filter(e=>e.isDirectory()).map(e=>e.name),yp=async(e,t)=>{let n=await _p(e);if(n===void 0)return{kind:`stop`};let r=vp(n);if(r.includes(t))return{kind:`continue`,nextDir:m(e,t)};let i=r.find(e=>e.toLowerCase()===t.toLowerCase());return i===void 0?{kind:`stop`}:{kind:`collision`,name:i}},bp=async(e,t,n)=>{let[r,...i]=t;if(r===void 0)return;let a=await yp(e,r);if(a.kind!==`stop`)return a.kind===`collision`?[...n,a.name].join(`/`):bp(a.nextDir,i,[...n,r])},xp=[],Sp=async(e,t)=>{let n=await bp(e.sourcesDir,t.split(`/`),xp);if(n!==void 0)throw ye(`checkout path for '${t}' collides case-insensitively with existing '${n}'`)},Cp=async e=>{try{return await i(e),!0}catch(e){if(V(e))return!1;throw e}},wp=async e=>{try{return await s(e)}catch(e){if(V(e))return;throw e}},Tp=async e=>{try{return(await i(e)).isDirectory()}catch(e){if(V(e))return;throw e}},Ep=async e=>{let t=await wp(e);if(t===void 0)return!0;if(t.length>0)return!1;try{await d(e)}catch(e){if(!V(e))throw e}return!0},Dp=async e=>{let t=await Tp(e);return t===void 0?!0:t?Ep(e):!1},Op=async(e,t)=>{t!==e.sourcesDir&&await Dp(t)&&await Op(e,ne(t))},kp=async(e,t)=>await Cp(t)?(Gs(e,t),await u(t,{force:!0,recursive:!0}),await Op(e,ne(t)),{removedCheckout:!0}):{removedCheckout:!1,warning:`checkout was already missing`},Ap=(e,t)=>Object.fromEntries(Object.entries(e).filter(([e])=>e!==t)),jp=async(e,t)=>{let n=await W(e);await $s(e,{...n,refs:Ap(n.refs,t)});let r=await X(e);await Ku(e,{...r,refs:Ap(r.refs,t)})},Mp=async(e,t)=>{let n=H(e.env),r=sp(await W(n),t),i=U(n,r),{removedCheckout:a,warning:o}=await J(n,lp(r),()=>kp(n,i));return await J(n,`home`,()=>jp(n,r)),{data:{key:r,removed_checkout:a},warnings:Vd(o)}},Np=e=>e.removed_checkout?[`removed ${e.key} (checkout deleted)`]:[`removed ${e.key} (checkout was already missing)`],Pp=(e,t)=>{e.command(`remove`).description(`Remove a configured ref: its config/state entry AND its checkout directory.`).argument(`<ref>`,`full ref key or a unique suffix, e.g. zod`).action((e,n,r)=>{let i=Z(r);return $(t,i,async()=>{let{data:n,warnings:r}=await Mp(t,e);Q(t,i,Np(n),n,r)})()})},Fp=(e,t)=>{let n=e.refs[t];if(n===void 0)throw Error(`internal: matched ref key '${t}' is missing from config.refs`);return n},Ip=(e,t)=>{if(!G(e))throw v(`checkout for '${t}' is missing — run: refs sync ${t}`)},Lp=(e,t,n)=>{let r=e.packages?.[n];if(r===void 0)throw v(`no package '${n}' registered on ref '${t}'`);return r},Rp=e=>`no ref matches '${e}' — run refs list, or add it: refs add <url>`,zp=/^[a-z][a-z0-9+.-]*:\/\//iu,Bp=/^git@[^:/\s]+:[^\s]+$/u,Vp=e=>zp.test(e)||Bp.test(e),Hp=(e,t)=>{try{return dl(e,t)}catch{if(Vp(e))throw b(`query looks like a git url but is not a supported form — check the url (credentials are never accepted) or run: refs resolve <package|ref-suffix>`);return}},Up=(e,t,n)=>{let r=Hp(t,n);if(r!==void 0){if(Object.hasOwn(e.refs,r.key))return{key:r.key};throw v(Rp(t))}},Wp=(e,t)=>{let n=[];for(let r of Object.keys(e.refs).toSorted()){let i=e.refs[r]?.packages?.[t];i!==void 0&&n.push({entry:i,key:z.parse(r)})}return n},Gp=(e,t)=>`package '${e}' is registered by more than one ref: ${t.join(`, `)} — use the full ref key`,Kp=(e,t)=>{let n=Wp(e,t),[r]=n;if(r!==void 0){if(n.length>1)throw y(Gp(t,n.map(e=>e.key)));return r}},qp=(e,t)=>{let n=t.split(`/`);for(let t=n.length-1;t>=1;--t){let r=n.slice(0,t).join(`/`),i=Kp(e,r);if(i!==void 0)return{...i,name:r}}},Jp=(e,t)=>{try{return sp(e,t)}catch(e){throw e instanceof _&&e.code===`not_found`?v(Rp(t)):e}},Yp=(e,t,n)=>{let r=Up(e,t,n);if(r!==void 0)return r;let i=Kp(e,t);if(i!==void 0)return{key:i.key,packageMatch:{...i,name:t}};let a=qp(e,t);return a===void 0?{key:Jp(e,t)}:{key:a.key,packageMatch:a}},Xp=(e,t)=>{if(e.packageMatch===void 0)return null;let{entry:n,name:r}=e.packageMatch;return{local_path:m(t,n.path),name:r,path:n.path}},Zp=async(e,t)=>{let n=H(e.env),r=await W(n),i=Yp(r,t,{allowFileUrls:up(e.env)}),a=Fp(r,i.key),o=await X(n),s=U(n,i.key),c=Qo(Y(`sync_ttl`,a,r.settings));return{key:i.key,local_path:s,missing:!G(s),package:Xp(i,s),stale:$f(o.refs[i.key]?.last_fetched_at,c,Date.now())}},Qp=e=>{let t=[e.key,`local_path: ${e.local_path}`];return e.package!==null&&t.push(`package: ${e.package.name}`,`local_path: ${e.package.local_path}`),t},$p=(e,t)=>{e.command(`resolve`).description(`Resolve a git url, npm package name, import path, or ref-key suffix to its ref/package.`).argument(`<query>`,`git url, npm package name, import path, or unique ref-key suffix`).action((e,n,r)=>{let i=Z(r);return $(t,i,async()=>{let n=await Zp(t,e);Q(t,i,Qp(n),n)})()})},em={},tm=async(e,t)=>{if(!G(t))return{tags:[]};try{return{tags:await kc(e.runner,t,5)}}catch(e){return{tags:[],warning:`could not list tags: ${Hd(e)}`}}},nm=async(e,t)=>{let n=H(e.env),r=await W(n),i=sp(r,t),a=Fp(r,i),o=await X(n),s=U(n,i),{tags:c,warning:l}=await tm(e,s);return{data:{...a,key:i,local_path:s,sample_tags:c,state:o.refs[i]??em},warnings:Vd(l)}},rm=e=>{let t=[`${e.key} ${e.description}`,`url: ${e.url}`,`local_path: ${e.local_path}`];return e.sample_tags.length>0&&t.push(`tags: ${e.sample_tags.join(`, `)}`),t},im=(e,t)=>{e.command(`show`).description(`Show a configured ref: full entry, state, local path, and sample tags.`).argument(`<ref>`,`full ref key or a unique suffix, e.g. zod`).action((e,n,r)=>{let i=Z(r);return $(t,i,async()=>{let{data:n,warnings:r}=await nm(t,e);Q(t,i,rm(n),n,r)})()})},am=(e,t)=>{let n={head_sha:t.headSha,last_fetched_at:new Date().toISOString()},r=t.effectiveCloneMode??e?.effective_clone_mode;return r!==void 0&&(n.effective_clone_mode=r),n},om=async(e,t,n)=>{let r=await W(e),i=r.refs[t];i!==void 0&&(r.refs[t]={...i,default_branch:n},await $s(e,r))},sm=(e,t,n)=>J(e,`home`,async()=>{n.branchRenamedTo!==void 0&&await om(e,t,n.branchRenamedTo);let r=await X(e);r.refs[t]=am(r.refs[t],n),await Ku(e,r)}),cm=async(e,t,n)=>{try{await J(e,`home`,async()=>{let r=await X(e);r.refs[t]={...r.refs[t],last_error:n},await Ku(e,r)})}catch{}},lm=e=>{let t=0,n=[];return{acquire:()=>{if(t<e)return t+=1,Promise.resolve();let{promise:r,resolve:i}=Promise.withResolvers();return n.push(()=>{t+=1,i()}),r},release:()=>{--t;let e=n.shift();e!==void 0&&e()}}},um=async(e,t)=>{await e.acquire();try{return await t()}finally{e.release()}},dm=(e,t,n)=>`checkout at ${e} points at '${q(t)}' — expected '${q(n)}'; remove the checkout directory or run refs remove before retrying`,fm=e=>e.exitCode===0?e.stdout.trim():`(no origin remote)`,pm=(e,t)=>{try{return dl(e,{allowFileUrls:t}).key}catch{return}},mm=async(e,t)=>{let n=await e.run(`git`,[`remote`,`get-url`,`origin`],{cwd:t.dest}),r=fm(n),i=pm(t.expectedUrl,t.allowFileUrls),a=pm(r,t.allowFileUrls);if(i===void 0||a!==i)throw ye(dm(t.dest,r,t.expectedUrl))},hm=e=>`checkout at ${e} exists but is not refs-managed — remove it (rm -rf ${e}) and retry`,gm=async(e,t)=>{let n=await e.run(`git`,[`config`,`--local`,`core.hooksPath`],{cwd:t.dest});if(n.exitCode!==0||n.stdout.trim()!==t.hooksDir)throw ye(hm(t.dest))},_m=async(e,t)=>{await a(ne(t.dest),{recursive:!0}),Wd(e,`cloning ${q(t.cloneUrl)} into ${t.dest}…`);let n=await bc(e.runner,t);return n.warning===void 0?{effectiveMode:n.effectiveMode}:{effectiveMode:n.effectiveMode,warning:n.warning}},vm=async(e,t)=>(Gs(t.home,t.dest),G(t.dest)?(await mm(e.runner,{allowFileUrls:t.allowFileUrls,dest:t.dest,expectedUrl:t.cloneUrl}),await gm(e.runner,{dest:t.dest,hooksDir:t.hooksDir}),{}):_m(e,t)),ym=(e,t)=>`checkout for '${e}' at ${t} is missing or corrupt (git rev-parse HEAD failed) — run: refs remove ${e}, then refs add <source> --dry-run again`,bm=(e,t,n)=>`checkout for '${e}' at ${t} has a HEAD sha refs cannot store yet (${n.length} hex chars, expected 40) — only SHA-1 repositories are supported for now; \`--object-format=sha256\` repositories are not yet supported`,xm=async(e,t)=>{await mm(e,t),await gm(e,{dest:t.dest,hooksDir:t.hooksDir});let n=await e.run(`git`,[`rev-parse`,`HEAD`],{cwd:t.dest});if(n.exitCode!==0)throw b(ym(t.key,t.dest));let r=n.stdout.trim();if(!Hu.shape.head_sha.safeParse(r).success)throw b(bm(t.key,t.dest,r));return r},Sm=(e,t,n)=>`sync produced a HEAD sha for '${e}' at ${t} that refs cannot store yet (${n.length} hex chars) — only SHA-1 repositories are supported for now`,Cm=(e,t,n)=>{if(!Hu.shape.head_sha.safeParse(n).success)throw b(Sm(e,t,n));return n},wm=(e,t,n)=>{let r={effectiveCloneMode:t.effectiveMode,headSha:n.headSha,status:`cloned`};return n.actualBranch!==e.ref.default_branch&&(r.branchRenamedTo=n.actualBranch),t.warning!==void 0&&(r.warning=t.warning),r},Tm=async(e,t,n)=>{await a(ne(n),{recursive:!0});let r=Y(`clone_mode`,t.ref,t.settings),i=await bc(e.runner,{cloneUrl:t.ref.url,dest:n,hooksDir:t.home.hooksDir,mode:r}),o=await Sc(e.runner,n),s=await xm(e.runner,{allowFileUrls:up(e.env),dest:n,expectedUrl:t.ref.url,hooksDir:t.home.hooksDir,key:t.key});return wm(t,i,{actualBranch:o,headSha:s})},Em=async(e,t,n)=>{await gm(e.runner,{dest:n,hooksDir:t.home.hooksDir}),await mm(e.runner,{allowFileUrls:up(e.env),dest:n,expectedUrl:t.ref.url});let r=await Oc(e.runner,{defaultBranch:t.ref.default_branch,dir:n}),i={headSha:Cm(t.key,n,r.newSha),status:r.status};return r.branchRenamedTo!==void 0&&(i.branchRenamedTo=r.branchRenamedTo),r.warning!==void 0&&(i.warning=r.warning),i},Dm=(e,t)=>J(t.home,lp(t.key),()=>{let n=U(t.home,t.key);return Gs(t.home,n),G(n)?Em(e,t,n):Tm(e,t,n)}),Om=e=>{let t=[];e.branchRenamedTo!==void 0&&t.push(`default branch renamed to ${e.branchRenamedTo}`),e.warning!==void 0&&t.push(e.warning);let[n]=t;if(n!==void 0)return t.join(` | `)},km=(e,t)=>{let n={key:e,status:t.status},r=Om(t);return r!==void 0&&(n.warning=r),n},Am=async(e,t)=>{try{let n=await Dm(e,t);return await sm(t.home,t.key,n),km(t.key,n)}catch(e){let n=Hd(e);return await cm(t.home,t.key,n),{error:n,key:t.key,status:`failed`}}},jm=(e,t)=>e.status===`rejected`?{error:Hd(e.reason),key:t,status:`failed`}:e.value,Mm=async(e,t)=>{let n=lm(4);return(await Promise.allSettled(t.map(t=>um(n,()=>Am(e,t))))).map((e,n)=>{let r=t[n];if(r===void 0)throw Error(`internal: sync target at index ${n} is missing`);return jm(e,r.key)})},Nm=(e,t,n)=>({home:e,key:n,ref:Fp(t,n),settings:t.settings}),Pm=(e,t,n)=>n.length===0?Object.keys(t.refs).toSorted().map(n=>Nm(e,t,z.parse(n))):n.map(n=>Nm(e,t,sp(t,n))),Fm=(e,t,n)=>{let r=Date.now();return t.filter(t=>{let i=Qo(Y(`sync_ttl`,t.ref,t.settings)),a=$f(n.refs[t.key]?.last_fetched_at,i,r),o=!G(U(e,t.key));return a||o})},Im=async(e,t,n)=>{if(!n)return t;let r=await X(e);return Fm(e,t,r)},Lm=async(e,t)=>{let n=H(e.env),r=await W(n),i=Pm(n,r,t.refs),a=await Mm(e,await Im(n,i,t.staleOnly));return{failedCount:a.filter(e=>e.status===`failed`).length,results:a}},Rm=[`updated`,`fresh`,`cloned`,`restored`,`failed`],zm={cloned:`Cloned`,failed:`Failed`,fresh:`Fresh`,restored:`Restored`,updated:`Updated`},Bm=e=>{let t={cloned:[],failed:[],fresh:[],restored:[],updated:[]};for(let n of e)t[n.status].push(n);return t},Vm=e=>e.status===`failed`?` ${e.key}: ${e.error??`unknown error`}`:e.warning===void 0?` ${e.key}`:` ${e.key} (${e.warning})`,Hm=e=>{let t=Bm(e),n=[Rm.map(e=>`${zm[e]} (${t[e].length})`).join(` / `)];for(let e of Rm)for(let r of t[e])n.push(Vm(r));return n},Um=(e,t)=>({refs:e,staleOnly:t.staleOnly===!0}),Wm=(e,t)=>{e.command(`sync`).description(`Fetch (or re-clone, if the checkout is missing) configured refs — all by default.`).argument(`[refs...]`,`ref keys or unique suffixes to sync (default: every configured ref)`).option(`--stale-only`,`skip refs whose last sync is still within their ref's sync_ttl`).action((e,n,r)=>{let i=Z(r);return $(t,i,async()=>{let r=await Lm(t,Um(e,n));Q(t,i,Hm(r.results),{results:r.results}),r.failedCount>0&&(process.exitCode=g.UNEXPECTED)})()})},Gm=(e,t,n)=>n===void 0?e.tag_format:Lp(e,t,n).tag_format??e.tag_format,Km=async(e,t)=>{let n=H(e.env),r=await W(n),i=sp(r,t.query),a=Fp(r,i),o=Gm(a,i,t.opts.packageName),s=U(n,i);Ip(s,i);let c=await Wc(e.runner,s,o,t.version);return{key:i,ref_path:`refs/tags/${c}`,tag:c,version:t.version}},qm=e=>[`${e.key}@${e.version} -> ${e.tag}`],Jm=e=>{let t={};return e.package!==void 0&&(t.packageName=e.package),t},Ym=[Yf,Qf,Pp,$p,im,Wm,(e,t)=>{e.command(`tag`).description(`Resolve a version to its git tag, via the ref's (or a package's) tag_format.`).argument(`<ref>`,`full ref key or a unique suffix, e.g. zod`).argument(`<version>`,`version to resolve, e.g. 4.1.0`).option(`--package <name>`,`resolve against this package's tag_format instead of the ref's`).action((e,n,r,i)=>{let a=Z(i);return $(t,a,async()=>{let i=await Km(t,{opts:Jm(r),query:e,version:n});Q(t,a,qm(i),i)})()})}],Xm=e=>e.description===void 0?{path:e.path}:{description:e.description,path:e.path},Zm=(e,t,n)=>e.length>0?Object.fromEntries(e.map(e=>[e.name,Xm(e)])):n===void 0?{}:{[n]:{path:t??`.`}},Qm=e=>{let t=e.description??``;return e.tag_format===void 0?{description:t,path:e.path}:{description:t,path:e.path,tag_format:e.tag_format}},$m=e=>{let t=Object.entries(e);if(t.length!==0)return Object.fromEntries(t.map(([e,t])=>[e,Qm(t)]))},eh=e=>e.description===void 0||e.description===``,th=e=>Object.entries(e).filter(([,e])=>eh(e)).map(([e])=>e).toSorted(),nh=e=>{let t=th(e);if(t.length!==0)throw b(`packages without a detected description: ${t.join(`, `)} — run the two-phase flow instead: refs add <source> --dry-run --json > proposal.json, fill in the package descriptions, then refs add --proposal proposal.json`)},rh=e=>{if(Object.keys(e).length!==0)return e},ih=e=>{if(e===null)throw b(`tag_format_candidate must be set to a valid tag format (containing '{version}') before finalizing — edit the proposal and provide one, or add the ref manually`);return e},ah=e=>e.packages===void 0?{default_branch:e.default_branch,description:e.description,tag_format:e.tag_format,url:e.url}:{default_branch:e.default_branch,description:e.description,packages:e.packages,tag_format:e.tag_format,url:e.url},oh=async(e,t,n)=>{let r=await Sc(e.runner,t),i=Hc(await kc(e.runner,t));return Wd(e,`detecting workspace packages…`),{defaultBranch:r,packages:Zm(await Sd(t),n.npmDirectory,n.npmPkgName),tagFormatCandidate:i}},sh=(e,t)=>J(t.home,lp(t.resolved.key),async()=>{let n=await vm(e,{allowFileUrls:up(e.env),cloneUrl:t.resolved.cloneUrl,dest:t.dest,home:t.home,hooksDir:t.home.hooksDir,mode:t.cloneMode}),r={fields:await oh(e,t.dest,t.resolved)};return n.effectiveMode!==void 0&&(r.effectiveMode=n.effectiveMode),n.warning!==void 0&&(r.warning=n.warning),r}),ch=e=>{let t={default_branch:e.cloneResult.fields.defaultBranch,description:``,key:e.resolved.key,packages:e.cloneResult.fields.packages,tag_format_candidate:e.cloneResult.fields.tagFormatCandidate,url:e.resolved.cloneUrl},n={dest:e.dest,proposal:t};return e.cloneResult.effectiveMode!==void 0&&(n.effectiveCloneMode=e.cloneResult.effectiveMode),e.cloneResult.warning!==void 0&&(n.warning=e.cloneResult.warning),n},lh=async(e,t)=>{let n=H(e.env),r=await W(n),i=mp(await pp(e,t),r.settings);gp(r,i.key),await Sp(n,i.key);let a=U(n,i.key),o=Y(`clone_mode`,void 0,r.settings),s=await sh(e,{cloneMode:o,dest:a,home:n,resolved:i});return ch({cloneResult:s,dest:a,resolved:i})},uh=(e,t,n)=>J(e,`home`,async()=>{gp(await W(e),t);let r=await X(e),i=r.refs[t],a=n??i?.effective_clone_mode,o={...i,pending_proposal_at:new Date().toISOString()};a!==void 0&&(o.effective_clone_mode=a),r.refs[t]=o,await Ku(e,r)}),dh=(e,t)=>{let n=cs.safeParse(e);if(!n.success)throw b(O(n.error));let r=Uu.safeParse(t);if(!r.success)throw b(O(r.error));return{config:n.data,state:r.data}},fh=async(e,t)=>{let n=await W(e.home);gp(n,e.ref.key);let r=ah(e.ref);n.refs[e.ref.key]=r;let i=await X(e.home);return i.refs[e.ref.key]={effective_clone_mode:e.effectiveCloneMode??i.refs[e.ref.key]?.effective_clone_mode??Y(`clone_mode`,void 0,n.settings),head_sha:t,last_fetched_at:new Date().toISOString()},{...dh(n,i),entry:r}},ph=async(e,t)=>{let n=up(e.env),r=await J(t.home,lp(t.ref.key),()=>(Gs(t.home,t.dest),xm(e.runner,{allowFileUrls:n,dest:t.dest,expectedUrl:t.ref.url,hooksDir:t.home.hooksDir,key:t.ref.key})));return J(t.home,`home`,async()=>{let{config:e,entry:n,state:i}=await fh(t,r);return await Ku(t.home,i),await $s(t.home,e),{entry:n,key:t.ref.key}})},mh=(e,t)=>t===`-`?e.readStdin():o(t,`utf8`),hh=e=>{try{return JSON.parse(e)}catch(e){throw b(`invalid JSON in proposal: ${Hd(e)}`)}},gh=e=>typeof e==`object`&&!!e&&!Array.isArray(e),_h=e=>gh(e)&&`ok`in e&&!(`key`in e),vh=e=>{if(!_h(e))return e;if(e.ok===!1)throw b(`proposal file contains a failed refs envelope (ok is false) — re-run the dry-run`);if(gh(e.data))return e.data;throw b(`proposal file is a refs envelope without a usable data object — re-run the dry-run`)},yh=e=>e.code===`unrecognized_keys`,bh=e=>e.path.length===0,xh=(e,t)=>{let n=t.toSorted().map(e=>`"${e}"`).join(`, `);return e===``?`✖ unrecognized key(s) in proposal: ${n}`:`✖ unrecognized key(s) in proposal at ${e}: ${n}`},Sh=e=>{let t=new Map;for(let n of e){let e=lt(n.path);t.set(e,[...t.get(e)??[],...n.keys])}return[...t.entries()].toSorted(([e],[t])=>e.localeCompare(t)).map(([e,t])=>xh(e,t))},Ch=e=>`✖ invalid proposal: ${e.message}`,wh=e=>{let t=e.issues.filter(e=>yh(e)),n=e.issues.filter(e=>!yh(e)),r=n.filter(e=>bh(e));if(t.length===0&&r.length===0)return O(e);let i=n.filter(e=>!bh(e)),a=[...Sh(t),...r.map(e=>Ch(e))];return i.length>0&&a.push(O({issues:i})),a.join(`
|
|
369
369
|
`)},Th=e=>{let t=Vu.safeParse(e);if(!t.success)throw b(wh(t.error));return t.data},Eh=async(e,t)=>{let n=await mh(e,t);return Th(vh(hh(n)))},Dh=(e,t)=>[`refs add: dry-run proposal ready for '${e}' (checkout: ${t})`,`next: review the proposal, then run refs add --proposal <file> to finalize`],Oh=async(e,t)=>{let n=await lh(e,t);await uh(H(e.env),n.proposal.key,n.effectiveCloneMode);let r=Vd(n.warning);return{data:n.proposal,human:Dh(n.proposal.key,n.dest),warnings:r}},kh=e=>[`refs add: '${e}' added to config`],Ah=e=>{let t={default_branch:e.default_branch,description:e.description,key:e.key,tag_format:ih(e.tag_format_candidate),url:e.url},n=rh(e.packages);return n!==void 0&&(t.packages=n),t},jh=async(e,t)=>{let n=await Eh(e,t),r=H(e.env),i=U(r,n.key);if(!G(i))throw v(`no checkout found at ${i} — run: refs add <source> --dry-run first`);let{entry:a,key:o}=await ph(e,{dest:i,home:r,ref:Ah(n)});return{data:{entry:a,key:o},human:kh(o),warnings:[]}},Mh=(e,t)=>{nh(e.proposal.packages);let n={default_branch:e.proposal.default_branch,description:t,key:e.proposal.key,tag_format:ih(e.proposal.tag_format_candidate),url:e.proposal.url},r=$m(e.proposal.packages);return r!==void 0&&(n.packages=r),n},Nh=async(e,t,n)=>{let r=await lh(e,t),i=H(e.env),a=Mh(r,n),o={dest:r.dest,home:i,ref:a};r.effectiveCloneMode!==void 0&&(o.effectiveCloneMode=r.effectiveCloneMode);let{entry:s,key:c}=await ph(e,o),l=Vd(r.warning);return{data:{entry:s,key:c},human:kh(c),warnings:l}},Ph=e=>{let t=[e.dryRun,e.proposal!==void 0,e.description!==void 0].filter(Boolean).length;if(t>1)throw y(`refs add: use only one of --dry-run, --proposal, or --description`);if(t===0)throw y(`refs add needs --dry-run, --proposal, or --description`)},Fh=e=>{if(e===void 0||e===``)throw y(`refs add requires <source> (a git url or npm:<package>)`);return e},Ih=(e,t)=>(Ph(t),t.proposal===void 0?t.description===void 0?Oh(e,Fh(t.source)):Nh(e,Fh(t.source),t.description):jh(e,t.proposal)),Lh=(e,t)=>{let n={dryRun:t.dryRun===!0};return e!==void 0&&(n.source=e),t.proposal!==void 0&&(n.proposal=t.proposal),t.description!==void 0&&(n.description=t.description),n},Rh=(e,t)=>{e.command(`add`).description(`Add a git reference in two phases: propose (--dry-run), then finalize (--proposal).`).argument(`[source]`,`git url or npm:<package> (omit when finalizing with --proposal)`).option(`--dry-run`,`resolve and clone the source, writing a reviewable proposal`).option(`--proposal <file>`,`finalize from a completed proposal JSON file (- for stdin)`).option(`--description <text>`,`one-shot: dry-run then finalize immediately with this description`).action((e,n,r)=>{let i=Z(r);return $(t,i,async()=>{let r=await Ih(t,Lh(e,n));Q(t,i,r.human,r.data,r.warnings)})()})},zh=e=>e===void 0?null:e,Bh=()=>Object.keys(os.shape).toSorted().join(`, `),Vh=e=>`unknown package field '${e}' — valid fields: ${Bh()}`,Hh=e=>Object.hasOwn(os.shape,e),Uh=(e,t,n)=>{if(!Hh(t))throw y(Vh(t));let r=e[t],i=os.safeParse({...e,[t]:n});if(!i.success)throw b(O(i.error));return{field:t,newValue:i.data[t],oldValue:r,updated:i.data}},Wh=async e=>{let t=Lp(e.entry,e.key,e.packageName),n=Uh(t,e.field,e.value),r={...e.entry,packages:{...e.entry.packages,[e.packageName]:n.updated}};return await $s(e.home,{...e.config,refs:{...e.config.refs,[e.key]:r}}),{field:n.field,key:e.key,new:zh(n.newValue),old:zh(n.oldValue)}},Gh=`packages`,Kh=()=>Object.keys(ss.shape).filter(e=>e!==Gh).toSorted().join(`, `),qh=e=>`unknown ref field '${e}' — valid fields: ${Kh()}`,Jh=e=>Object.hasOwn(ss.shape,e),Yh=(e,t,n)=>`failed to rewrite git remote at ${e} to '${q(t)}': ${n.trim()}`,Xh=async(e,t)=>{if(Gs(t.home,t.dest),!G(t.dest))return;let n=await e.runner.run(`git`,[`remote`,`set-url`,`origin`,t.cloneUrl],{cwd:t.dest});if(n.exitCode!==0)throw b(Yh(t.dest,t.cloneUrl,n.stderr))},Zh=async(e,t)=>{let n=dl(t.value,{allowFileUrls:up(e.env)});if(n.key!==t.key)throw b(`new url derives a different key — remove and re-add instead`);let r=U(t.home,t.key);return await Xh(e,{cloneUrl:n.cloneUrl,dest:r,home:t.home}),{...t.entry,url:n.cloneUrl}},Qh=(e,t,n)=>{let r={...e,[t]:n},i=ss.safeParse(r);if(!i.success)throw b(O(i.error));return i.data},$h=(e,t)=>t.field===`url`?Zh(e,{entry:t.entry,home:t.home,key:t.key,value:t.value}):Promise.resolve(Qh(t.entry,t.field,t.value)),eg=async(e,t)=>{let{field:n}=t;if(n===Gh)throw y(`use --package <name> <field> <value>`);if(!Jh(n))throw y(qh(n));let r=t.entry[n],i=await $h(e,{entry:t.entry,field:n,home:t.home,key:t.key,value:t.value});return{new:i[n],old:r,updated:i}},tg=(e,t)=>{let n=H(e.env),{field:r,opts:i,query:a,value:o}=t;return J(n,`home`,async()=>{let t=await W(n),s=sp(t,a),c=Fp(t,s);if(i.packageName!==void 0)return Wh({config:t,entry:c,field:r,home:n,key:s,packageName:i.packageName,value:o});let l=await eg(e,{entry:c,field:r,home:n,key:s,value:o});return await $s(n,{...t,refs:{...t.refs,[s]:l.updated}}),{field:r,key:s,new:zh(l.new),old:zh(l.old)}})},ng=`settings`,rg=[],ig=()=>Object.keys(is.shape).toSorted().join(`, `),ag=e=>`unknown setting '${e}' — valid settings: ${ig()}`,og=e=>Object.hasOwn(is.shape,e),sg=e=>`note: 'settings' addressed the global settings, not ${e} — use the full ref key to edit that ref`,cg=e=>{try{let t=sp(e,ng);return[sg(`ref '${t}'`)]}catch(e){if(e instanceof _&&e.code===`usage`)return[sg("one of several matching refs — see `refs list`")];if(e instanceof _&&e.code===`not_found`)return rg;throw e}},lg=e=>({data:{field:e.key,key:ng,new:zh(e.parsed[e.key]),old:zh(e.old)},warnings:cg(e.config)}),ug=(e,t)=>{let n=H(e.env);return J(n,`home`,async()=>{let e=await W(n);if(!og(t.key))throw y(ag(t.key));let r=e.settings[t.key],i={...e.settings,[t.key]:t.value},a=is.safeParse(i);if(!a.success)throw b(O(a.error));return await $s(n,{...e,settings:a.data}),lg({config:e,key:t.key,old:r,parsed:a.data})})},dg=[],fg=e=>{let t={};return e.package!==void 0&&(t.packageName=e.package),t},pg=async(e,t)=>{if(t.first===`settings`){if(t.opts.packageName!==void 0)throw y(`--package is not valid with 'refs edit settings ...' — it only applies to ref/package edits`);return ug(e,{key:t.second,value:t.value})}return{data:await tg(e,{field:t.second,opts:t.opts,query:t.first,value:t.value}),warnings:dg}},mg=e=>e==null?`(unset)`:String(e),hg=e=>[`${e.key}: ${e.field} '${mg(e.old)}' -> '${mg(e.new)}'`],gg=(e,t)=>{e.command(`edit`).description(`Edit one field: 'refs edit settings <key> <value>' for a global setting, or 'refs edit <ref> <field> <value> [--package <name>]' for a ref or package field.`).argument(`<ref-or-settings>`,`a ref key/unique suffix, or the literal 'settings'`).argument(`<field-or-key>`,`field to edit (or, in settings mode, the setting key)`).argument(`<value>`,`the new value`).option(`--package <name>`,`edit this package's field instead of a top-level ref field`).action((e,n,r,i,a)=>{let o=Z(a);return $(t,o,async()=>{let{data:a,warnings:s}=await pg(t,{first:e,opts:fg(i),second:n,value:r});Q(t,o,hg(a),a,s)})()})},_g=`Install the agent skill: npx skills add kaisers-io/refs (private phase: npx skills add <path-to-this-repo> --skill refs)`,vg=async e=>{await a(e.root,{recursive:!0}),await a(e.sourcesDir,{recursive:!0}),await a(e.locksDir,{recursive:!0}),await a(e.hooksDir,{recursive:!0})},yg=async e=>{let t=H(e.env);return await vg(t),{config:await J(t,`home`,async()=>{let e=await lc(t,Gd);return await Mc(t),e}),home:t.root,skill_hint:_g}},bg=[(e,t)=>{e.command(`init`).description(`Seed or migrate the refs home directory, its config, and the git hooks guard.`).action((e,n)=>{let r=Z(n);return $(t,r,async()=>{let e=await yg(t);Q(t,r,[`refs home: ${e.home} (${e.config})`,_g],e)})()})},Rh,gg,cp,...Ym],xg=(e,t)=>{for(let n of bg)n(e,t)},Sg=[``,`Examples:`,` $ refs list --json`,` $ refs sync --stale-only --json`,` $ refs resolve zod/mini --json`,``,`Every command accepts --json for structured output and --verbose for stack traces on error.`].join(`
|
|
370
370
|
`),Cg=new Set([`commander.help`,`commander.helpDisplayed`,`commander.version`]),wg=`--json`,Tg=`--verbose`,Eg=/\n$/u,Dg=/^error: /u,Og=e=>e.replace(Dg,``),kg=(e,t)=>{for(let n of e){if(n===`--`)return!1;if(n===t)return!0}return!1},Ag=e=>kg(e,wg),jg=e=>kg(e,Tg),Mg=(e,t,n)=>n&&t!==void 0?`${e}\n${t}`:e,Ng=e=>{let t=new Id().name(`refs`).description(`Manage git-based reference checkouts shared across a workspace.`).version(Gd).option(wg,`emit machine-readable JSON on stdout instead of human-readable text`).option(Tg,`include stack traces in error output`).allowExcessArguments(!1).exitOverride().configureOutput({outputError:()=>{},writeErr:t=>{e.errLine(t.replace(Eg,``))},writeOut:t=>{e.out(t.replace(Eg,``))}});return t.addHelpText(`after`,Sg),xg(t,e),t},Pg=()=>{process.exitCode=g.OK},Fg=(e,t,n)=>{Ud(e,t,{code:`usage`,message:Mg(Og(n.message),n.stack,t.verbose)}),process.exitCode=g.USAGE},Ig=(e,t,n)=>{if(Cg.has(n.code)){Pg();return}Fg(e,t,n)},Lg=(e,t,n)=>{let r=xe(n,{verbose:t.verbose});Ud(e,t,r),process.exitCode=r.exitCode},Rg=async(e,t,n)=>{let r={json:Ag(n),verbose:jg(n)};try{await t.parseAsync(n)}catch(t){if(t instanceof Td){Ig(e,r,t);return}Lg(e,r,t)}},zg=(e,t)=>Rg(e,Ng(e),t);import.meta.main&&await zg(wd(),process.argv);export{Ng as buildProgram,Z as cliOptsOf,Q as emit,Ud as emitError,Hd as errorMessageOf,Wd as progress,wd as realContext,xg as registerCommands,zg as run,Rg as runProgram,Vd as warningsFor,$ as wrapAction};
|
package/package.json
CHANGED
|
@@ -1,7 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kaisers-io/refs",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "Managed read-only git checkouts of reference repositories for coding agents.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ai",
|
|
7
|
+
"checkout",
|
|
8
|
+
"claude-code",
|
|
9
|
+
"cli",
|
|
10
|
+
"codex",
|
|
11
|
+
"coding-agents",
|
|
12
|
+
"git",
|
|
13
|
+
"monorepo",
|
|
14
|
+
"references",
|
|
15
|
+
"source-code"
|
|
16
|
+
],
|
|
17
|
+
"homepage": "https://github.com/kaisers-io/refs#readme",
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/kaisers-io/refs/issues"
|
|
20
|
+
},
|
|
5
21
|
"license": "MIT",
|
|
6
22
|
"repository": {
|
|
7
23
|
"type": "git",
|
|
@@ -11,6 +27,7 @@
|
|
|
11
27
|
"refs": "./bin/refs.mjs"
|
|
12
28
|
},
|
|
13
29
|
"files": [
|
|
30
|
+
"CHANGELOG.md",
|
|
14
31
|
"bin",
|
|
15
32
|
"dist"
|
|
16
33
|
],
|